Preview JEP-349-branch
authoregahlin
Fri, 17 May 2019 16:02:27 +0200
branchJEP-349-branch
changeset 57360 5d043a159d5c
parent 57359 4cab5edc2950
child 57361 53dccc90a5be
Preview
src/hotspot/share/gc/z/zTracer.cpp
src/hotspot/share/jfr/dcmd/jfrDcmds.cpp
src/hotspot/share/jfr/dcmd/jfrDcmds.hpp
src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp
src/hotspot/share/jfr/jfr.cpp
src/hotspot/share/jfr/jfr.hpp
src/hotspot/share/jfr/jni/jfrJavaSupport.cpp
src/hotspot/share/jfr/jni/jfrJavaSupport.hpp
src/hotspot/share/jfr/jni/jfrJniMethod.cpp
src/hotspot/share/jfr/jni/jfrJniMethod.hpp
src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp
src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp
src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp
src/hotspot/share/jfr/metadata/jfrSerializer.hpp
src/hotspot/share/jfr/metadata/metadata.xml
src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp
src/hotspot/share/jfr/periodic/jfrPeriodic.cpp
src/hotspot/share/jfr/periodic/jfrThreadCPULoadEvent.cpp
src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp
src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.hpp
src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.cpp
src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp
src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrThreadGroup.cpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.cpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetWriter.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdBits.inline.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp
src/hotspot/share/jfr/recorder/repository/jfrChunkWriter.cpp
src/hotspot/share/jfr/recorder/repository/jfrChunkWriter.hpp
src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp
src/hotspot/share/jfr/recorder/repository/jfrRepository.cpp
src/hotspot/share/jfr/recorder/repository/jfrRepository.hpp
src/hotspot/share/jfr/recorder/service/jfrPostBox.cpp
src/hotspot/share/jfr/recorder/service/jfrPostBox.hpp
src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp
src/hotspot/share/jfr/recorder/service/jfrRecorderService.hpp
src/hotspot/share/jfr/recorder/service/jfrRecorderThread.cpp
src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp
src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.cpp
src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.hpp
src/hotspot/share/jfr/recorder/storage/jfrBuffer.cpp
src/hotspot/share/jfr/recorder/storage/jfrBuffer.hpp
src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.inline.hpp
src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp
src/hotspot/share/jfr/recorder/storage/jfrStorage.hpp
src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.hpp
src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.inline.hpp
src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp
src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.hpp
src/hotspot/share/jfr/recorder/stringpool/jfrStringPoolBuffer.cpp
src/hotspot/share/jfr/support/jfrKlassExtension.hpp
src/hotspot/share/jfr/support/jfrThreadLocal.cpp
src/hotspot/share/jfr/support/jfrThreadLocal.hpp
src/hotspot/share/jfr/utilities/jfrIterator.hpp
src/hotspot/share/jfr/utilities/jfrLogTagSets.hpp
src/hotspot/share/jfr/utilities/jfrTypes.hpp
src/hotspot/share/jfr/writers/jfrJavaEventWriter.hpp
src/hotspot/share/jfr/writers/jfrStorageAdapter.hpp
src/hotspot/share/jfr/writers/jfrWriterHost.inline.hpp
src/hotspot/share/logging/logTag.hpp
src/hotspot/share/runtime/thread.cpp
src/jdk.jfr/share/classes/jdk/jfr/Recording.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/ChunkParser.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/ConstantMap.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/EventParser.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/LongMap.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/ObjectFactory.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/ParserFactory.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingFile.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/TimeConverter.java
src/jdk.jfr/share/classes/jdk/jfr/events/ActiveRecordingEvent.java
src/jdk.jfr/share/classes/jdk/jfr/internal/EventWriter.java
src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java
src/jdk.jfr/share/classes/jdk/jfr/internal/LogTag.java
src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataDescriptor.java
src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataReader.java
src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java
src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataWriter.java
src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformEventType.java
src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecorder.java
src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java
src/jdk.jfr/share/classes/jdk/jfr/internal/Repository.java
src/jdk.jfr/share/classes/jdk/jfr/internal/RepositoryChunk.java
src/jdk.jfr/share/classes/jdk/jfr/internal/RequestEngine.java
src/jdk.jfr/share/classes/jdk/jfr/internal/SecuritySupport.java
src/jdk.jfr/share/classes/jdk/jfr/internal/Utils.java
src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java
src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RecordingInput.java
src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RecordingInternals.java
src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java
src/jdk.jfr/share/conf/jfr/default.jfc
src/jdk.jfr/share/conf/jfr/profile.jfc
test/hotspot/gtest/jfr/test_networkUtilization.cpp
test/hotspot/gtest/jfr/test_threadCpuLoad.cpp
test/jdk/jdk/jfr/api/consumer/TestReadTwice.java
test/jdk/jdk/jfr/api/consumer/TestRecordingFile.java
test/jdk/jdk/jfr/api/consumer/TestRecordingInternals.java
test/lib/jdk/test/lib/jfr/EventNames.java
--- a/src/hotspot/share/gc/z/zTracer.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/gc/z/zTracer.cpp	Fri May 17 16:02:27 2019 +0200
@@ -58,11 +58,9 @@
 
 static void register_jfr_type_serializers() {
   JfrSerializer::register_serializer(TYPE_ZSTATISTICSCOUNTERTYPE,
-                                     false /* require_safepoint */,
                                      true /* permit_cache */,
                                      new ZStatisticsCounterTypeConstant());
   JfrSerializer::register_serializer(TYPE_ZSTATISTICSSAMPLERTYPE,
-                                     false /* require_safepoint */,
                                      true /* permit_cache */,
                                      new ZStatisticsSamplerTypeConstant());
 }
--- a/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp	Fri May 17 16:02:27 2019 +0200
@@ -349,6 +349,7 @@
   _filename("filename", "Resulting recording filename, e.g. \\\"" JFR_FILENAME_EXAMPLE "\\\"", "STRING", false),
   _maxage("maxage", "Maximum time to keep recorded data (on disk) in (s)econds, (m)inutes, (h)ours, or (d)ays, e.g. 60m, or 0 for no limit", "NANOTIME", false, "0"),
   _maxsize("maxsize", "Maximum amount of bytes to keep (on disk) in (k)B, (M)B or (G)B, e.g. 500M, or 0 for no limit", "MEMORY SIZE", false, "0"),
+  _flush("flush", "Maximum time before flushing buffers, measuare in (s)econds, e.g. 4 s, or 0 for flushing when a recording ends", "NANOTIME", false, "0"),
   _dump_on_exit("dumponexit", "Dump running recording when JVM shuts down", "BOOLEAN", false),
   _path_to_gc_roots("path-to-gc-roots", "Collect path to GC roots", "BOOLEAN", false, "false") {
   _dcmdparser.add_dcmd_option(&_name);
@@ -359,6 +360,7 @@
   _dcmdparser.add_dcmd_option(&_filename);
   _dcmdparser.add_dcmd_option(&_maxage);
   _dcmdparser.add_dcmd_option(&_maxsize);
+  _dcmdparser.add_dcmd_option(&_flush);
   _dcmdparser.add_dcmd_option(&_dump_on_exit);
   _dcmdparser.add_dcmd_option(&_path_to_gc_roots);
 };
@@ -411,6 +413,10 @@
     maxsize = JfrJavaSupport::new_java_lang_Long(_maxsize.value()._size, CHECK);
   }
 
+  jobject flush = NULL;
+  if (_flush.is_set()) {
+    flush = JfrJavaSupport::new_java_lang_Long(_flush.value()._nanotime, CHECK);
+  }
   jobject duration = NULL;
   if (_duration.is_set()) {
     duration = JfrJavaSupport::new_java_lang_Long(_duration.value()._nanotime, CHECK);
@@ -458,7 +464,7 @@
   static const char method[] = "execute";
   static const char signature[] = "(Ljava/lang/String;[Ljava/lang/String;Ljava/lang/Long;"
     "Ljava/lang/Long;Ljava/lang/Boolean;Ljava/lang/String;"
-    "Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Boolean;Ljava/lang/Boolean;)Ljava/lang/String;";
+    "Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Boolean;Ljava/lang/Boolean;)Ljava/lang/String;";
 
   JfrJavaArguments execute_args(&result, klass, method, signature, CHECK);
   execute_args.set_receiver(h_dcmd_instance);
@@ -472,6 +478,7 @@
   execute_args.push_jobject(filename);
   execute_args.push_jobject(maxage);
   execute_args.push_jobject(maxsize);
+  execute_args.push_jobject(flush);
   execute_args.push_jobject(dump_on_exit);
   execute_args.push_jobject(path_to_gc_roots);
 
--- a/src/hotspot/share/jfr/dcmd/jfrDcmds.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/dcmd/jfrDcmds.hpp	Fri May 17 16:02:27 2019 +0200
@@ -90,6 +90,7 @@
   DCmdArgument<char*> _filename;
   DCmdArgument<NanoTimeArgument> _maxage;
   DCmdArgument<MemorySizeArgument> _maxsize;
+  DCmdArgument<NanoTimeArgument> _flush;
   DCmdArgument<bool> _dump_on_exit;
   DCmdArgument<bool> _path_to_gc_roots;
 
--- a/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp	Fri May 17 16:02:27 2019 +0200
@@ -44,7 +44,6 @@
 #include "memory/allocation.inline.hpp"
 #include "memory/resourceArea.hpp"
 #include "oops/array.hpp"
-#include "oops/constantPool.hpp"
 #include "oops/instanceKlass.hpp"
 #include "oops/method.hpp"
 #include "prims/jvmtiRedefineClasses.hpp"
--- a/src/hotspot/share/jfr/jfr.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/jfr.cpp	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -71,6 +71,18 @@
   JfrThreadLocal::on_exit(t);
 }
 
+void Jfr::exclude_thread(Thread* t) {
+  JfrThreadLocal::exclude(t);
+}
+
+void Jfr::include_thread(Thread* t) {
+  JfrThreadLocal::include(t);
+}
+
+bool Jfr::is_excluded(Thread* t) {
+  return t != NULL && t->jfr_thread_local()->is_excluded();
+}
+
 void Jfr::on_java_thread_dismantle(JavaThread* jt) {
   if (JfrRecorder::is_recording()) {
     JfrCheckpointManager::write_thread_checkpoint(jt);
--- a/src/hotspot/share/jfr/jfr.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/jfr.hpp	Fri May 17 16:02:27 2019 +0200
@@ -48,6 +48,9 @@
   static void on_unloading_classes();
   static void on_thread_start(Thread* thread);
   static void on_thread_exit(Thread* thread);
+  static void exclude_thread(Thread* thread);
+  static bool is_excluded(Thread* thread);
+  static void include_thread(Thread* thread);
   static void on_java_thread_dismantle(JavaThread* jt);
   static void on_vm_shutdown(bool exception_handler = false);
   static bool on_flight_recorder_option(const JavaVMOption** option, char* delimiter);
--- a/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp	Fri May 17 16:02:27 2019 +0200
@@ -23,7 +23,6 @@
  */
 
 #include "precompiled.hpp"
-#include "jni.h"
 #include "classfile/javaClasses.inline.hpp"
 #include "classfile/modules.hpp"
 #include "classfile/symbolTable.hpp"
@@ -42,9 +41,11 @@
 #include "runtime/fieldDescriptor.inline.hpp"
 #include "runtime/java.hpp"
 #include "runtime/jniHandles.inline.hpp"
+#include "runtime/semaphore.inline.hpp"
 #include "runtime/synchronizer.hpp"
 #include "runtime/thread.inline.hpp"
 #include "runtime/threadSMR.hpp"
+#include "utilities/growableArray.hpp"
 
 #ifdef ASSERT
 void JfrJavaSupport::check_java_thread_in_vm(Thread* t) {
@@ -58,6 +59,12 @@
   assert(t->is_Java_thread(), "invariant");
   assert(((JavaThread*)t)->thread_state() == _thread_in_native, "invariant");
 }
+
+static void check_new_unstarted_java_thread(Thread* t) {
+  assert(t != NULL, "invariant");
+  assert(t->is_Java_thread(), "invariant");
+  assert(((JavaThread*)t)->thread_state() == _thread_new, "invariant");
+}
 #endif
 
 /*
@@ -93,6 +100,21 @@
   JNIHandles::destroy_global(handle);
 }
 
+jweak JfrJavaSupport::global_weak_jni_handle(const oop obj, Thread* t) {
+  DEBUG_ONLY(check_java_thread_in_vm(t));
+  HandleMark hm(t);
+  return JNIHandles::make_weak_global(Handle(t, obj));
+}
+
+jweak JfrJavaSupport::global_weak_jni_handle(const jobject handle, Thread* t) {
+  const oop obj = JNIHandles::resolve(handle);
+  return obj == NULL ? NULL : global_weak_jni_handle(obj, t);
+}
+
+void JfrJavaSupport::destroy_global_weak_jni_handle(jweak handle) {
+  JNIHandles::destroy_weak_global(handle);
+}
+
 oop JfrJavaSupport::resolve_non_null(jobject obj) {
   return JNIHandles::resolve_non_null(obj);
 }
@@ -603,9 +625,149 @@
   return true;
 }
 
-jlong JfrJavaSupport::jfr_thread_id(jobject target_thread) {
+class ThreadExclusionListAccess : public StackObj {
+ private:
+  static Semaphore _mutex_semaphore;
+ public:
+  ThreadExclusionListAccess() { _mutex_semaphore.wait(); }
+  ~ThreadExclusionListAccess() { _mutex_semaphore.signal(); }
+};
+
+Semaphore ThreadExclusionListAccess::_mutex_semaphore(1);
+static GrowableArray<jweak>* exclusion_list = NULL;
+
+static bool equals(const jweak excluded_thread, Handle target_thread) {
+  return JfrJavaSupport::resolve_non_null(excluded_thread) == target_thread();
+}
+
+static int find_exclusion_thread_idx(Handle thread) {
+  if (exclusion_list != NULL) {
+    for (int i = 0; i < exclusion_list->length(); ++i) {
+      if (equals(exclusion_list->at(i), thread)) {
+        return i;
+      }
+    }
+  }
+  return -1;
+}
+
+static Handle as_handle(jobject thread) {
+  return Handle(Thread::current(), JfrJavaSupport::resolve_non_null(thread));
+}
+
+static bool thread_is_not_excluded(Handle thread) {
+  return -1 == find_exclusion_thread_idx(thread);
+}
+
+static bool thread_is_not_excluded(jobject thread) {
+  return thread_is_not_excluded(as_handle(thread));
+}
+
+static bool is_thread_excluded(jobject thread) {
+  return !thread_is_not_excluded(thread);
+}
+
+#ifdef ASSERT
+static bool is_thread_excluded(Handle thread) {
+  return !thread_is_not_excluded(thread);
+}
+#endif // ASSERT
+
+static int add_thread_to_exclusion_list(jobject thread) {
+  ThreadExclusionListAccess lock;
+  if (exclusion_list == NULL) {
+    exclusion_list = new (ResourceObj::C_HEAP, mtTracing) GrowableArray<jweak>(10, true, mtTracing);
+  }
+  assert(exclusion_list != NULL, "invariant");
+  assert(thread_is_not_excluded(thread), "invariant");
+  jweak ref = JfrJavaSupport::global_weak_jni_handle(thread, Thread::current());
+  const int idx = exclusion_list->append(ref);
+  assert(is_thread_excluded(thread), "invariant");
+  return idx;
+}
+
+static void remove_thread_from_exclusion_list(Handle thread) {
+  assert(exclusion_list != NULL, "invariant");
+  assert(is_thread_excluded(thread), "invariant");
+  assert(exclusion_list != NULL, "invariant");
+  const int idx = find_exclusion_thread_idx(thread);
+  assert(idx >= 0, "invariant");
+  assert(idx < exclusion_list->length(), "invariant");
+  JfrJavaSupport::destroy_global_weak_jni_handle(exclusion_list->at(idx));
+  exclusion_list->delete_at(idx);
+  assert(thread_is_not_excluded(thread), "invariant");
+  if (0 == exclusion_list->length()) {
+    delete exclusion_list;
+    exclusion_list = NULL;
+  }
+}
+
+static void remove_thread_from_exclusion_list(jobject thread) {
+  ThreadExclusionListAccess lock;
+  remove_thread_from_exclusion_list(as_handle(thread));
+}
+
+// includes removal
+static bool check_exclusion_state_on_thread_start(JavaThread* jt) {
+  Handle h_obj(jt, jt->threadObj());
+  ThreadExclusionListAccess lock;
+  if (thread_is_not_excluded(h_obj)) {
+    return false;
+  }
+  remove_thread_from_exclusion_list(h_obj);
+  return true;
+}
+
+jlong JfrJavaSupport::jfr_thread_id(jobject thread) {
   ThreadsListHandle tlh;
   JavaThread* native_thread = NULL;
-  (void)tlh.cv_internal_thread_to_JavaThread(target_thread, &native_thread, NULL);
+  (void)tlh.cv_internal_thread_to_JavaThread(thread, &native_thread, NULL);
   return native_thread != NULL ? JFR_THREAD_ID(native_thread) : 0;
 }
+
+void JfrJavaSupport::exclude(jobject thread) {
+  HandleMark hm;
+  ThreadsListHandle tlh;
+  JavaThread* native_thread = NULL;
+  (void)tlh.cv_internal_thread_to_JavaThread(thread, &native_thread, NULL);
+  if (native_thread != NULL) {
+    JfrThreadLocal::exclude(native_thread);
+  } else {
+    // not started yet, track the thread oop
+    add_thread_to_exclusion_list(thread);
+  }
+}
+
+void JfrJavaSupport::include(jobject thread) {
+  HandleMark hm;
+  ThreadsListHandle tlh;
+  JavaThread* native_thread = NULL;
+  (void)tlh.cv_internal_thread_to_JavaThread(thread, &native_thread, NULL);
+  if (native_thread != NULL) {
+    JfrThreadLocal::include(native_thread);
+  } else {
+    // not started yet, untrack the thread oop
+    remove_thread_from_exclusion_list(thread);
+  }
+}
+
+bool JfrJavaSupport::is_excluded(jobject thread) {
+  HandleMark hm;
+  ThreadsListHandle tlh;
+  JavaThread* native_thread = NULL;
+  (void)tlh.cv_internal_thread_to_JavaThread(thread, &native_thread, NULL);
+  return native_thread != NULL ? native_thread->jfr_thread_local()->is_excluded() : is_thread_excluded(thread);
+}
+
+void JfrJavaSupport::on_thread_start(Thread* t) {
+  assert(t != NULL, "invariant");
+  assert(Thread::current() == t, "invariant");
+  if (!t->is_Java_thread()) {
+    return;
+  }
+  DEBUG_ONLY(check_new_unstarted_java_thread(t);)
+  HandleMark hm;
+  if (check_exclusion_state_on_thread_start((JavaThread*)t)) {
+    JfrThreadLocal::exclude(t);
+  }
+}
--- a/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp	Fri May 17 16:02:27 2019 +0200
@@ -29,18 +29,21 @@
 #include "utilities/exceptions.hpp"
 
 class Klass;
-class JavaThread;
 class outputStream;
 
 class JfrJavaSupport : public AllStatic {
  public:
   static jobject local_jni_handle(const oop obj, Thread* t);
   static jobject local_jni_handle(const jobject handle, Thread* t);
-  static void destroy_local_jni_handle(const jobject handle);
+  static void destroy_local_jni_handle(jobject handle);
 
   static jobject global_jni_handle(const oop obj, Thread* t);
   static jobject global_jni_handle(const jobject handle, Thread* t);
-  static void destroy_global_jni_handle(const jobject handle);
+  static void destroy_global_jni_handle(jobject handle);
+
+  static jweak global_weak_jni_handle(const oop obj, Thread* t);
+  static jweak global_weak_jni_handle(const jobject handle, Thread* t);
+  static void destroy_global_weak_jni_handle(jweak handle);
 
   static oop resolve_non_null(jobject obj);
   static void notify_all(jobject obj, TRAPS);
@@ -85,7 +88,11 @@
   static bool is_jdk_jfr_module_available();
   static bool is_jdk_jfr_module_available(outputStream* stream, TRAPS);
 
-  static jlong jfr_thread_id(jobject target_thread);
+  static jlong jfr_thread_id(jobject thread);
+  static void exclude(jobject thread);
+  static void include(jobject thread);
+  static bool is_excluded(jobject thread);
+  static void on_thread_start(Thread* t);
 
   // critical
   static void abort(jstring errorMsg, TRAPS);
--- a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp	Fri May 17 16:02:27 2019 +0200
@@ -284,6 +284,10 @@
   return JfrJavaEventWriter::flush(writer, used_size, requested_size, thread);
 JVM_END
 
+JVM_ENTRY_NO_ENV(void, jfr_flush(JNIEnv* env, jobject jvm, jboolean include_metadata, jshort flush_counter))
+  JfrRepository::flush(include_metadata == JNI_TRUE, thread);
+JVM_END
+
 JVM_ENTRY_NO_ENV(void, jfr_set_repository_location(JNIEnv* env, jobject repo, jstring location))
   return JfrRepository::set_path(location, thread);
 JVM_END
@@ -311,3 +315,20 @@
 JVM_ENTRY_NO_ENV(void, jfr_emit_old_object_samples(JNIEnv* env, jobject jvm, jlong cutoff_ticks, jboolean emit_all))
   LeakProfiler::emit_events(cutoff_ticks, emit_all == JNI_TRUE);
 JVM_END
+
+JVM_ENTRY_NO_ENV(void, jfr_exclude_thread(JNIEnv* env, jobject jvm, jobject t))
+  JfrJavaSupport::exclude(t);
+JVM_END
+
+JVM_ENTRY_NO_ENV(void, jfr_include_thread(JNIEnv* env, jobject jvm, jobject t))
+  JfrJavaSupport::include(t);
+JVM_END
+
+JVM_ENTRY_NO_ENV(jboolean, jfr_is_thread_excluded(JNIEnv* env, jobject jvm, jobject t))
+  return JfrJavaSupport::is_excluded(t);
+JVM_END
+
+JVM_ENTRY_NO_ENV(jlong, jfr_chunk_start_nanos(JNIEnv* env, jobject jvm))
+  return JfrRepository::current_chunk_start_nanos();
+JVM_END
+
--- a/src/hotspot/share/jfr/jni/jfrJniMethod.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/jni/jfrJniMethod.hpp	Fri May 17 16:02:27 2019 +0200
@@ -113,6 +113,7 @@
 
 jboolean JNICALL jfr_event_writer_flush(JNIEnv* env, jclass cls, jobject writer, jint used_size, jint requested_size);
 
+void JNICALL jfr_flush(JNIEnv* env, jobject jvm, jboolean include_metadata, jshort flush_counter);
 void JNICALL jfr_abort(JNIEnv* env, jobject jvm, jstring errorMsg);
 
 jlong JNICALL jfr_get_epoch_address(JNIEnv* env, jobject jvm);
@@ -131,6 +132,13 @@
 
 jboolean JNICALL jfr_should_rotate_disk(JNIEnv* env, jobject jvm);
 
+void JNICALL jfr_exclude_thread(JNIEnv* env, jobject jvm, jobject t);
+
+void JNICALL jfr_include_thread(JNIEnv* env, jobject jvm, jobject t);
+
+jboolean JNICALL jfr_is_thread_excluded(JNIEnv* env, jobject jvm, jobject t);
+
+jlong JNICALL jfr_chunk_start_nanos(JNIEnv* env, jobject jvm);
 
 #ifdef __cplusplus
 }
--- a/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -70,6 +70,7 @@
       (char*)"getEventWriter", (char*)"()Ljava/lang/Object;", (void*)jfr_get_event_writer,
       (char*)"newEventWriter", (char*)"()Ljdk/jfr/internal/EventWriter;", (void*)jfr_new_event_writer,
       (char*)"flush", (char*)"(Ljdk/jfr/internal/EventWriter;II)Z", (void*)jfr_event_writer_flush,
+      (char*)"flush", (char*)"(ZS)V", (void*)jfr_flush,
       (char*)"setRepositoryLocation", (char*)"(Ljava/lang/String;)V", (void*)jfr_set_repository_location,
       (char*)"abort", (char*)"(Ljava/lang/String;)V", (void*)jfr_abort,
       (char*)"getEpochAddress", (char*)"()J",(void*)jfr_get_epoch_address,
@@ -79,7 +80,11 @@
       (char*)"getUnloadedEventClassCount", (char*)"()J", (void*)jfr_get_unloaded_event_classes_count,
       (char*)"setCutoff", (char*)"(JJ)Z", (void*)jfr_set_cutoff,
       (char*)"emitOldObjectSamples", (char*)"(JZ)V", (void*)jfr_emit_old_object_samples,
-      (char*)"shouldRotateDisk", (char*)"()Z", (void*)jfr_should_rotate_disk
+      (char*)"shouldRotateDisk", (char*)"()Z", (void*)jfr_should_rotate_disk,
+      (char*)"exclude", (char*)"(Ljava/lang/Thread;)V", (void*)jfr_exclude_thread,
+      (char*)"include", (char*)"(Ljava/lang/Thread;)V", (void*)jfr_include_thread,
+      (char*)"isExcluded", (char*)"(Ljava/lang/Thread;)Z", (void*)jfr_is_thread_excluded,
+      (char*)"getChunkStartNanos", (char*)"()J", (void*)jfr_chunk_start_nanos
     };
 
     const size_t method_array_length = sizeof(method) / sizeof(JNINativeMethod);
--- a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp	Fri May 17 16:02:27 2019 +0200
@@ -230,8 +230,8 @@
   assert(thread != NULL, "invariant");
   static bool types_registered = false;
   if (!types_registered) {
-    JfrSerializer::register_serializer(TYPE_OLDOBJECTROOTSYSTEM, false, true, new RootSystemType());
-    JfrSerializer::register_serializer(TYPE_OLDOBJECTROOTTYPE, false, true, new RootType());
+    JfrSerializer::register_serializer(TYPE_OLDOBJECTROOTSYSTEM, true, new RootSystemType());
+    JfrSerializer::register_serializer(TYPE_OLDOBJECTROOTTYPE, true, new RootType());
     types_registered = true;
   }
   const ObjectSampler* const object_sampler = LeakProfiler::object_sampler();
--- a/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp	Fri May 17 16:02:27 2019 +0200
@@ -29,6 +29,7 @@
 #include "gc/shared/strongRootsScope.hpp"
 #include "jfr/leakprofiler/utilities/unifiedOop.hpp"
 #include "jfr/leakprofiler/checkpoint/rootResolver.hpp"
+#include "jfr/utilities/jfrThreadIterator.hpp"
 #include "memory/iterator.hpp"
 #include "memory/universe.hpp"
 #include "oops/klass.hpp"
@@ -37,7 +38,6 @@
 #include "prims/jvmtiThreadState.hpp"
 #include "runtime/frame.inline.hpp"
 #include "runtime/mutexLocker.hpp"
-#include "runtime/threadSMR.inline.hpp"
 #include "runtime/vframe_hp.hpp"
 #include "services/management.hpp"
 #include "utilities/growableArray.hpp"
@@ -277,8 +277,9 @@
  public:
   ReferenceToThreadRootClosure(RootCallback& callback) :_callback(callback), _complete(false) {
     assert_locked_or_safepoint(Threads_lock);
-    for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) {
-      if (do_thread_roots(jt)) {
+    JfrJavaThreadIterator iter;
+    while (iter.has_next()) {
+      if (do_thread_roots(iter.next())) {
         return;
       }
     }
--- a/src/hotspot/share/jfr/metadata/jfrSerializer.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/metadata/jfrSerializer.hpp	Fri May 17 16:02:27 2019 +0200
@@ -70,8 +70,9 @@
 class JfrSerializer : public CHeapObj<mtTracing> {
  public:
   virtual ~JfrSerializer() {}
-  static bool register_serializer(JfrTypeId id, bool require_safepoint, bool permit_cache, JfrSerializer* serializer);
-  virtual void serialize(JfrCheckpointWriter& writer) = 0;
+  static bool register_serializer(JfrTypeId id, bool permit_cache, JfrSerializer* serializer);
+  virtual void serialize(JfrCheckpointWriter& writer) {}
+  virtual void on_rotation() {}
 };
 
 /*
--- a/src/hotspot/share/jfr/metadata/metadata.xml	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/metadata/metadata.xml	Fri May 17 16:02:27 2019 +0200
@@ -983,6 +983,42 @@
     <Field type="ulong" name="value" label="Value" />
   </Event>
 
+  <Event name="Flush" category="Flight Recorder" label="Flush" thread="false">
+    <Field type="ulong" name="flushId" label="Flush Identifier" relation="FlushId" />
+    <Field type="ulong" name="elements" label="Elements Written" />
+    <Field type="ulong" contentType="bytes" name="size" label="Size Written" />
+  </Event>
+
+  <Event name="FlushStorage" category="Flight Recorder" label="Flush Storage" thread="false">
+    <Field type="ulong" name="flushId" label="Flush Identifier" relation="FlushId" />
+    <Field type="ulong" name="elements" label="Elements Written" />
+    <Field type="ulong" contentType="bytes" name="size" label="Size Written" />
+  </Event>
+
+  <Event name="FlushStacktrace" category="Flight Recorder" label="Flush Stacktrace" thread="false">
+    <Field type="ulong" name="flushId" label="Flush Identifier" relation="FlushId" />
+    <Field type="ulong" name="elements" label="Elements Written" />
+    <Field type="ulong" contentType="bytes" name="size" label="Size Written" />
+  </Event>
+
+  <Event name="FlushStringPool" category="Flight Recorder" label="Flush String Pool" thread="false">
+    <Field type="ulong" name="flushId" label="Flush Identifier" relation="FlushId" />
+    <Field type="ulong" name="elements" label="Elements Written" />
+    <Field type="ulong" contentType="bytes" name="size" label="Size Written" />
+  </Event>
+
+  <Event name="FlushMetadata" category="Flight Recorder" label="Flush Metadata" thread="false">
+    <Field type="ulong" name="flushId" label="Flush Identifier" relation="FlushId" />
+    <Field type="ulong" name="elements" label="Elements Written" />
+    <Field type="ulong" contentType="bytes" name="size" label="Size Written" />
+  </Event>
+
+  <Event name="FlushTypeSet" category="Flight Recorder" label="Flush Type Set" thread="false">
+    <Field type="ulong" name="flushId" label="Flush Identifier" relation="FlushId" />
+    <Field type="ulong" name="elements" label="Elements Written" />
+    <Field type="ulong" contentType="bytes" name="size" label="Size Written" />
+  </Event>
+
   <Type name="ZStatisticsCounterType" label="Z Statistics Counter">
     <Field type="string" name="counter" label="Counter" />
   </Type>
@@ -1168,6 +1204,7 @@
   <Relation name="GcId"/>
   <Relation name="CompileId" />
   <Relation name="SweepId"/>
+  <Relation name="FlushId"/>
  
   <XmlType name="Package" parameterType="const PackageEntry*" fieldType="const PackageEntry*"/> 
   <XmlType name="Class" javaType="java.lang.Class" parameterType="const Klass*" fieldType="const Klass*"/> 
--- a/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -40,6 +40,7 @@
   uint64_t bytes_in;
   uint64_t bytes_out;
   bool in_use;
+  bool written;
 };
 
 static GrowableArray<InterfaceEntry>* _interfaces = NULL;
@@ -72,6 +73,7 @@
   entry.bytes_in = iface->get_bytes_in();
   entry.bytes_out = iface->get_bytes_out();
   entry.in_use = false;
+  entry.written = false;
   return _interfaces->at(_interfaces->append(entry));
 }
 
@@ -117,17 +119,17 @@
   return ret_val != FUNCTIONALITY_NOT_IMPLEMENTED;
 }
 
-class JfrNetworkInterfaceName : public JfrSerializer {
- public:
-  void serialize(JfrCheckpointWriter& writer) {
+static void write_interface_types(JfrCheckpointWriter& writer) {
     assert(_interfaces != NULL, "invariant");
+  writer.write_type(TYPE_NETWORKINTERFACENAME);
     const JfrCheckpointContext ctx = writer.context();
     const intptr_t count_offset = writer.reserve(sizeof(u4)); // Don't know how many yet
     int active_interfaces = 0;
     for (int i = 0; i < _interfaces->length(); ++i) {
       InterfaceEntry& entry = _interfaces->at(i);
-      if (entry.in_use) {
+    if (entry.in_use && !entry.written) {
         entry.in_use = false;
+        entry.written = true;
         writer.write_key(entry.id);
         writer.write(entry.name);
         ++active_interfaces;
@@ -140,12 +142,19 @@
     }
     writer.write_count(active_interfaces, count_offset);
   }
+class JfrNetworkInterfaceName : public JfrSerializer {
+ public:
+   void on_rotation() {
+     for (int i = 0; i < _interfaces->length(); ++i) {
+       InterfaceEntry& entry = _interfaces->at(i);
+       entry.written = false;
+     }
+   }
 };
 
 static bool register_network_interface_name_serializer() {
   assert(_interfaces != NULL, "invariant");
   return JfrSerializer::register_serializer(TYPE_NETWORKINTERFACENAME,
-                                            false, // require safepoint
                                             false, // disallow caching; we want a callback every rotation
                                             new JfrNetworkInterfaceName());
 }
@@ -161,6 +170,7 @@
   const JfrTicks cur_time = JfrTicks::now();
   const JfrTickspan interval = last_sample_instant == 0 ? cur_time - cur_time : cur_time - last_sample_instant;
   last_sample_instant = cur_time;
+  bool write_type = false;
   for (NetworkInterface *cur = network_interfaces; cur != NULL; cur = cur->next()) {
     InterfaceEntry& entry = get_entry(cur);
     if (interval.value() > 0) {
@@ -177,6 +187,9 @@
         event.set_readRate(8 * read_rate);
         event.set_writeRate(8 * write_rate);
         event.commit();
+        if (!entry.written) {
+          write_type = true;
+        }
       }
       // update existing entry with new values
       entry.bytes_in = current_bytes_in;
@@ -184,6 +197,10 @@
     }
   }
 
+  if (write_type) {
+    JfrCheckpointWriter writer(false, true, Thread::current());
+    write_interface_types(writer);
+  }
   static bool is_serializer_registered = false;
   if (!is_serializer_registered) {
     is_serializer_registered = register_network_interface_name_serializer();
--- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp	Fri May 17 16:02:27 2019 +0200
@@ -45,6 +45,7 @@
 #include "jfr/periodic/jfrNetworkUtilization.hpp"
 #include "jfr/recorder/jfrRecorder.hpp"
 #include "jfr/support/jfrThreadId.hpp"
+#include "jfr/utilities/jfrThreadIterator.hpp"
 #include "jfr/utilities/jfrTime.hpp"
 #include "jfrfiles/jfrPeriodic.hpp"
 #include "logging/log.hpp"
@@ -57,7 +58,6 @@
 #include "runtime/os.hpp"
 #include "runtime/os_perf.hpp"
 #include "runtime/thread.inline.hpp"
-#include "runtime/threadSMR.hpp"
 #include "runtime/sweeper.hpp"
 #include "runtime/vmThread.hpp"
 #include "services/classLoadingService.hpp"
@@ -416,10 +416,13 @@
   GrowableArray<jlong> allocated(initial_size);
   GrowableArray<traceid> thread_ids(initial_size);
   JfrTicks time_stamp = JfrTicks::now();
+
   {
-    // Collect allocation statistics while holding threads lock
-    MutexLocker ml(Threads_lock);
-    for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) {
+    JfrJavaThreadIterator iter;
+    while (iter.has_next()) {
+      JavaThread* const jt = iter.next();
+      assert(jt != NULL, "invariant");
+
       allocated.append(jt->cooked_allocated_bytes());
       thread_ids.append(JFR_THREAD_ID(jt));
     }
--- a/src/hotspot/share/jfr/periodic/jfrThreadCPULoadEvent.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/periodic/jfrThreadCPULoadEvent.cpp	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,11 +28,10 @@
 #include "jfr/periodic/jfrThreadCPULoadEvent.hpp"
 #include "jfr/support/jfrThreadId.hpp"
 #include "jfr/support/jfrThreadLocal.hpp"
+#include "jfr/utilities/jfrThreadIterator.hpp"
 #include "jfr/utilities/jfrTime.hpp"
 #include "utilities/globalDefinitions.hpp"
 #include "runtime/os.hpp"
-#include "runtime/thread.inline.hpp"
-#include "runtime/threadSMR.inline.hpp"
 
 jlong JfrThreadCPULoadEvent::get_wallclock_time() {
   return os::javaTimeNanos();
@@ -115,8 +114,12 @@
   JfrTicks event_time = JfrTicks::now();
   jlong cur_wallclock_time = JfrThreadCPULoadEvent::get_wallclock_time();
 
-  JavaThreadIteratorWithHandle jtiwh;
-  while (JavaThread* jt = jtiwh.next()) {
+  JfrJavaThreadIterator iter;
+  int number_of_threads = 0;
+  while (iter.has_next()) {
+    JavaThread* const jt = iter.next();
+    assert(jt != NULL, "invariant");
+    ++number_of_threads;
     EventThreadCPULoad event(UNTIMED);
     if (JfrThreadCPULoadEvent::update_event(event, jt, cur_wallclock_time, processor_count)) {
       event.set_starttime(event_time);
@@ -129,7 +132,7 @@
       event.commit();
     }
   }
-  log_trace(jfr)("Measured CPU usage for %d threads in %.3f milliseconds", jtiwh.length(),
+  log_trace(jfr)("Measured CPU usage for %d threads in %.3f milliseconds", number_of_threads,
     (double)(JfrTicks::now() - event_time).milliseconds());
   // Restore this thread's thread id
   periodic_thread_tl->set_thread_id(periodic_thread_id);
--- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,9 +34,13 @@
 #include "jfr/recorder/storage/jfrStorageUtils.inline.hpp"
 #include "jfr/recorder/repository/jfrChunkWriter.hpp"
 #include "jfr/utilities/jfrBigEndian.hpp"
+#include "jfr/utilities/jfrIterator.hpp"
+#include "jfr/utilities/jfrThreadIterator.hpp"
 #include "jfr/utilities/jfrTypes.hpp"
+#include "jfr/writers/jfrJavaEventWriter.hpp"
 #include "logging/log.hpp"
 #include "memory/resourceArea.hpp"
+#include "runtime/handles.inline.hpp"
 #include "runtime/mutexLocker.hpp"
 #include "runtime/orderAccess.hpp"
 #include "runtime/os.inline.hpp"
@@ -136,6 +140,8 @@
 
 void JfrCheckpointManager::register_full(BufferPtr t, Thread* thread) {
   // nothing here at the moment
+  assert(t != NULL, "invariant");
+  assert(t->acquired_by(thread), "invariant");
   assert(t->retired(), "invariant");
 }
 
@@ -271,15 +277,15 @@
 
 static size_t write_checkpoint_event(JfrChunkWriter& cw, const u1* data) {
   assert(data != NULL, "invariant");
-  const intptr_t previous_checkpoint_event = cw.previous_checkpoint_offset();
-  const intptr_t event_begin = cw.current_offset();
-  const intptr_t offset_to_previous_checkpoint_event = 0 == previous_checkpoint_event ? 0 : previous_checkpoint_event - event_begin;
-  const jlong total_checkpoint_size = total_size(data);
-  write_checkpoint_header(cw, offset_to_previous_checkpoint_event, data);
+  const int64_t last_checkpoint_event = cw.last_checkpoint_offset();
+  const int64_t event_begin = cw.current_offset();
+  const int64_t offset_to_last_checkpoint_event = 0 == last_checkpoint_event ? 0 : last_checkpoint_event - event_begin;
+  const int64_t total_checkpoint_size = total_size(data);
+  write_checkpoint_header(cw, offset_to_last_checkpoint_event, data);
   write_checkpoint_content(cw, data, total_checkpoint_size - sizeof(JfrCheckpointEntry));
-  const jlong checkpoint_event_size = cw.current_offset() - event_begin;
+  const int64_t checkpoint_event_size = cw.current_offset() - event_begin;
   cw.write_padded_at_offset<u4>(checkpoint_event_size, event_begin);
-  cw.set_previous_checkpoint_offset(event_begin);
+  cw.set_last_checkpoint_offset(event_begin);
   return (size_t)total_checkpoint_size;
 }
 
@@ -336,8 +342,36 @@
   return processed;
 }
 
+typedef StopOnEmptyIterator<JfrDoublyLinkedList<JfrBuffer> > EmptyIterator;
+
+template <typename Processor>
+static void process_transition_mspace(Processor& processor, JfrCheckpointMspace* mspace) {
+  assert(mspace->is_full_empty(), "invariant");
+  process_free_list_iterator_control<Processor, JfrCheckpointMspace, EmptyIterator>(processor, mspace, forward);
+}
+
+size_t JfrCheckpointManager::flush() {
+  WriteOperation wo(_chunkwriter);
+  MutexedWriteOperation mwo(wo);
+  process_transition_mspace(mwo, _epoch_transition_mspace);
+  assert(_free_list_mspace->is_full_empty(), "invariant");
+  process_free_list(mwo, _free_list_mspace);
+  return wo.processed();
+}
+
+size_t JfrCheckpointManager::write_constants() {
+  write_types();
+  return flush();
+}
+
 size_t JfrCheckpointManager::write_epoch_transition_mspace() {
-  return write_mspace_exclusive(_epoch_transition_mspace, _chunkwriter);
+  Thread* const thread = Thread::current();
+  WriteOperation wo(_chunkwriter);
+  MutexedWriteOperation mwo(wo);
+  CheckpointReleaseOperation cro(_epoch_transition_mspace, thread, false);
+  CheckpointWriteOperation cpwo(&mwo, &cro);
+  process_transition_mspace(cpwo, _epoch_transition_mspace);
+  return wo.processed();
 }
 
 typedef DiscardOp<DefaultDiscarder<JfrBuffer> > DiscardOperation;
@@ -346,20 +380,38 @@
   process_free_list(discarder, _free_list_mspace);
   process_free_list(discarder, _epoch_transition_mspace);
   synchronize_epoch();
-  return discarder.processed();
+  return discarder.elements();
 }
 
 size_t JfrCheckpointManager::write_types() {
+  ResourceMark rm;
+  HandleMark hm;
   JfrCheckpointWriter writer(false, true, Thread::current());
   JfrTypeManager::write_types(writer);
   return writer.used_size();
 }
 
-size_t JfrCheckpointManager::write_safepoint_types() {
-  // this is also a "flushpoint"
-  JfrCheckpointWriter writer(true, true, Thread::current());
-  JfrTypeManager::write_safepoint_types(writer);
-  return writer.used_size();
+class JfrNotifyClosure : public ThreadClosure {
+ public:
+  void do_thread(Thread* t) {
+    assert(t != NULL, "invariant");
+    assert(t->is_Java_thread(), "invariant");
+    assert_locked_or_safepoint(Threads_lock);
+    JfrJavaEventWriter::notify((JavaThread*)t);
+  }
+};
+
+void JfrCheckpointManager::notify_threads() {
+  assert(SafepointSynchronize::is_at_safepoint(), "invariant");
+  JfrNotifyClosure tc;
+  JfrJavaThreadIterator iter;
+  while (iter.has_next()) {
+    tc.do_thread(iter.next());
+  }
+}
+
+void JfrCheckpointManager::notify_types_on_rotation() {
+  JfrTypeManager::notify_types_on_rotation();
 }
 
 void JfrCheckpointManager::write_type_set() {
@@ -371,10 +423,16 @@
   JfrTypeManager::write_type_set_for_unloaded_classes();
 }
 
-void JfrCheckpointManager::create_thread_checkpoint(JavaThread* jt) {
-  JfrTypeManager::create_thread_checkpoint(jt);
+size_t JfrCheckpointManager::flush_type_set() {
+  const size_t elements = JfrTypeManager::flush_type_set();
+  flush();
+  return elements;
 }
 
-void JfrCheckpointManager::write_thread_checkpoint(JavaThread* jt) {
-  JfrTypeManager::write_thread_checkpoint(jt);
+void JfrCheckpointManager::create_thread_checkpoint(Thread* t) {
+  JfrTypeManager::create_thread_checkpoint(t);
 }
+
+void JfrCheckpointManager::write_thread_checkpoint(Thread* t) {
+  JfrTypeManager::write_thread_checkpoint(t);
+}
--- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.hpp	Fri May 17 16:02:27 2019 +0200
@@ -73,13 +73,17 @@
 
   size_t clear();
   size_t write();
+  size_t write_constants();
+  size_t flush();
   size_t write_epoch_transition_mspace();
   size_t write_types();
-  size_t write_safepoint_types();
+  size_t write_metadata_event();
   void write_type_set();
   void shift_epoch();
   void synchronize_epoch();
   bool use_epoch_transition_mspace(const Thread* t) const;
+  void notify_threads();
+  void notify_types_on_rotation();
 
   JfrCheckpointManager(JfrChunkWriter& cw);
   ~JfrCheckpointManager();
@@ -91,9 +95,10 @@
 
  public:
   void register_service_thread(const Thread* t);
+  size_t flush_type_set();
   static void write_type_set_for_unloaded_classes();
-  static void create_thread_checkpoint(JavaThread* jt);
-  static void write_thread_checkpoint(JavaThread* jt);
+  static void create_thread_checkpoint(Thread* t);
+  static void write_thread_checkpoint(Thread* t);
 
   friend class JfrRecorder;
   friend class JfrRecorderService;
--- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.cpp	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -156,6 +156,7 @@
   this->seek(ctx.offset);
   set_count(ctx.count);
 }
+
 bool JfrCheckpointWriter::has_data() const {
   return this->used_size() > sizeof(JfrCheckpointEntry);
 }
--- a/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,19 +29,11 @@
 #include "oops/klass.inline.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/typeArrayOop.inline.hpp"
-#include "runtime/semaphore.hpp"
 #include "runtime/thread.inline.hpp"
 
 static jbyteArray _metadata_blob = NULL;
-static Semaphore metadata_mutex_semaphore(1);
-
-void JfrMetadataEvent::lock() {
-  metadata_mutex_semaphore.wait();
-}
-
-void JfrMetadataEvent::unlock() {
-  metadata_mutex_semaphore.signal();
-}
+static u8 metadata_id = 0;
+static u8 last_written_metadata_id = 0;
 
 static void write_metadata_blob(JfrChunkWriter& chunkwriter, jbyteArray metadata_blob) {
   if (metadata_blob != NULL) {
@@ -56,34 +48,38 @@
   }
 }
 
-// the semaphore is assumed to be locked  (was locked previous safepoint)
-size_t JfrMetadataEvent::write(JfrChunkWriter& chunkwriter, jlong metadata_offset) {
+void JfrMetadataEvent::write(JfrChunkWriter& chunkwriter) {
   assert(chunkwriter.is_valid(), "invariant");
+  const jlong metadata_offset = chunkwriter.current_offset();
   assert(chunkwriter.current_offset() == metadata_offset, "invariant");
+
+  if (last_written_metadata_id == metadata_id && chunkwriter.has_metadata()) {
+    return;
+  }
+
   // header
   chunkwriter.reserve(sizeof(u4));
   chunkwriter.write<u8>(EVENT_METADATA); // ID 0
   // time data
   chunkwriter.write(JfrTicks::now());
   chunkwriter.write((u8)0); // duration
-  chunkwriter.write((u8)0); // metadata id
+  chunkwriter.write(metadata_id); // metadata id
   write_metadata_blob(chunkwriter, _metadata_blob); // payload
-  unlock(); // open up for java to provide updated metadata
+  last_written_metadata_id = metadata_id;
   // fill in size of metadata descriptor event
   const jlong size_written = chunkwriter.current_offset() - metadata_offset;
   chunkwriter.write_padded_at_offset((u4)size_written, metadata_offset);
-  return size_written;
+  chunkwriter.set_last_metadata_offset(metadata_offset);
 }
 
 void JfrMetadataEvent::update(jbyteArray metadata) {
   JavaThread* thread = (JavaThread*)Thread::current();
   assert(thread->is_Java_thread(), "invariant");
   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread));
-  lock();
   if (_metadata_blob != NULL) {
     JfrJavaSupport::destroy_global_jni_handle(_metadata_blob);
   }
   const oop new_desc_oop = JfrJavaSupport::resolve_non_null(metadata);
   _metadata_blob = new_desc_oop != NULL ? (jbyteArray)JfrJavaSupport::global_jni_handle(new_desc_oop, thread) : NULL;
-  unlock();
+  ++metadata_id;
 }
--- a/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.hpp	Fri May 17 16:02:27 2019 +0200
@@ -37,9 +37,7 @@
 //
 class JfrMetadataEvent : AllStatic {
  public:
-  static void lock();
-  static void unlock();
-  static size_t write(JfrChunkWriter& writer, jlong metadata_offset);
+  static void write(JfrChunkWriter& writer);
   static void update(jbyteArray metadata);
 };
 
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrThreadGroup.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrThreadGroup.cpp	Fri May 17 16:02:27 2019 +0200
@@ -25,7 +25,6 @@
 #include "precompiled.hpp"
 #include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
 #include "jfr/recorder/checkpoint/types/jfrThreadGroup.hpp"
-#include "jfr/utilities/jfrResourceManager.hpp"
 #include "jfr/utilities/jfrTypes.hpp"
 #include "runtime/handles.inline.hpp"
 #include "runtime/jniHandles.inline.hpp"
@@ -33,6 +32,8 @@
 #include "runtime/semaphore.hpp"
 #include "utilities/growableArray.hpp"
 
+static const int initial_array_size = 30;
+
 class ThreadGroupExclusiveAccess : public StackObj {
  private:
   static Semaphore _mutex_semaphore;
@@ -257,12 +258,10 @@
   }
 }
 
-JfrThreadGroup::JfrThreadGroup() : _list(NULL) {
-  _list = new (ResourceObj::C_HEAP, mtTracing) GrowableArray<JfrThreadGroupEntry*>(30, true);
-}
+JfrThreadGroup::JfrThreadGroup() :
+  _list(new (ResourceObj::C_HEAP, mtTracing) GrowableArray<JfrThreadGroupEntry*>(initial_array_size, true, mtTracing)) {}
 
 JfrThreadGroup::~JfrThreadGroup() {
-  assert(SafepointSynchronize::is_at_safepoint(), "invariant");
   if (_list != NULL) {
     for (int i = 0; i < _list->length(); i++) {
       JfrThreadGroupEntry* e = _list->at(i);
@@ -281,14 +280,11 @@
 }
 
 traceid JfrThreadGroup::thread_group_id(const JavaThread* jt, Thread* current) {
-  ResourceMark rm(current);
-  HandleMark hm(current);
   JfrThreadGroupsHelper helper(jt, current);
   return helper.is_valid() ? thread_group_id_internal(helper) : 0;
 }
 
 traceid JfrThreadGroup::thread_group_id(JavaThread* const jt) {
-  assert(!JfrStream_lock->owned_by_self(), "holding stream lock but should not hold it here");
   return thread_group_id(jt, jt);
 }
 
@@ -396,9 +392,7 @@
   ThreadGroupExclusiveAccess lock;
   JfrThreadGroup* tg_instance = instance();
   assert(tg_instance != NULL, "invariant");
-  ResourceManager<JfrThreadGroup> tg_handle(tg_instance);
-  set_instance(NULL);
-  tg_handle->write_thread_group_entries(writer);
+  tg_instance->write_thread_group_entries(writer);
 }
 
 // for writing a particular thread group
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -39,7 +39,7 @@
 #include "jfr/recorder/checkpoint/types/jfrThreadState.hpp"
 #include "jfr/recorder/checkpoint/types/jfrTypeSet.hpp"
 #include "jfr/support/jfrThreadLocal.hpp"
-#include "jfr/writers/jfrJavaEventWriter.hpp"
+#include "jfr/utilities/jfrThreadIterator.hpp"
 #include "memory/metaspaceGCThresholdUpdater.hpp"
 #include "memory/referenceType.hpp"
 #include "memory/universe.hpp"
@@ -93,12 +93,10 @@
 // Requires a ResourceMark for get_thread_name/as_utf8
 void JfrCheckpointThreadClosure::do_thread(Thread* t) {
   assert(t != NULL, "invariant");
-  assert_locked_or_safepoint(Threads_lock);
   const JfrThreadLocal* const tl = t->jfr_thread_local();
   assert(tl != NULL, "invariant");
-  if (tl->is_dead()) {
-    return;
-  }
+  assert(!tl->is_dead(), "invariant");
+  assert(!tl->is_excluded(), "invariant");
   ++_count;
   _writer.write_key(tl->thread_id());
   _writer.write(t->name());
@@ -110,7 +108,6 @@
     _writer.write(java_lang_Thread::thread_id(jt->threadObj()));
     _writer.write(JfrThreadGroup::thread_group_id(jt, _curthread));
     // since we are iterating threads during a safepoint, also issue notification
-    JfrJavaEventWriter::notify(jt);
     return;
   }
   _writer.write((const char*)NULL); // java name
@@ -119,13 +116,18 @@
 }
 
 void JfrThreadConstantSet::serialize(JfrCheckpointWriter& writer) {
-  assert(SafepointSynchronize::is_at_safepoint(), "invariant");
   JfrCheckpointThreadClosure tc(writer);
-  Threads::threads_do(&tc);
+  JfrJavaThreadIterator javathreads;
+  while (javathreads.has_next()) {
+    tc.do_thread(javathreads.next());
+  }
+  JfrNonJavaThreadIterator nonjavathreads;
+  while (nonjavathreads.has_next()) {
+    tc.do_thread(nonjavathreads.next());
+  }
 }
 
 void JfrThreadGroupConstant::serialize(JfrCheckpointWriter& writer) {
-  assert(SafepointSynchronize::is_at_safepoint(), "invariant");
   JfrThreadGroup::serialize(writer);
 }
 
@@ -298,16 +300,23 @@
 
 class TypeSetSerialization {
  private:
+  size_t _elements;
   bool _class_unload;
+  bool _flushpoint;
  public:
-  explicit TypeSetSerialization(bool class_unload) : _class_unload(class_unload) {}
+  explicit TypeSetSerialization(bool class_unload, bool flushpoint) : _elements(0), _class_unload(class_unload), _flushpoint(flushpoint) {}
   void write(JfrCheckpointWriter& writer, JfrCheckpointWriter* leakp_writer) {
-    JfrTypeSet::serialize(&writer, leakp_writer, _class_unload);
+    MutexLocker cld_lock(SafepointSynchronize::is_at_safepoint() ? NULL : ClassLoaderDataGraph_lock);
+    MutexLocker lock(SafepointSynchronize::is_at_safepoint() ? NULL : Module_lock);
+    _elements = JfrTypeSet::serialize(&writer, leakp_writer, _class_unload, _flushpoint);
+  }
+  size_t elements() const {
+    return _elements;
   }
 };
 
 void ClassUnloadTypeSet::serialize(JfrCheckpointWriter& writer) {
-  TypeSetSerialization type_set(true);
+  TypeSetSerialization type_set(true, false);
   if (LeakProfiler::is_running()) {
     JfrCheckpointWriter leakp_writer(false, true, Thread::current());
     type_set.write(writer, &leakp_writer);
@@ -317,8 +326,19 @@
   type_set.write(writer, NULL);
 };
 
+void FlushTypeSet::serialize(JfrCheckpointWriter& writer) {
+  assert(!SafepointSynchronize::is_at_safepoint(), "invariant");
+  TypeSetSerialization type_set(false, true);
+  type_set.write(writer, NULL);
+  _elements = type_set.elements();
+}
+
+size_t FlushTypeSet::elements() const {
+  return _elements;
+}
+
 void TypeSet::serialize(JfrCheckpointWriter& writer) {
-  TypeSetSerialization type_set(false);
+  TypeSetSerialization type_set(false, false);
   if (LeakProfiler::is_suspended()) {
     JfrCheckpointWriter leakp_writer(false, true, Thread::current());
     type_set.write(writer, &leakp_writer);
@@ -335,20 +355,23 @@
 void JfrThreadConstant::serialize(JfrCheckpointWriter& writer) {
   assert(_thread != NULL, "invariant");
   assert(_thread == Thread::current(), "invariant");
-  assert(_thread->is_Java_thread(), "invariant");
-  assert(!_thread->jfr_thread_local()->has_thread_checkpoint(), "invariant");
   ResourceMark rm(_thread);
-  const oop threadObj = _thread->threadObj();
-  assert(threadObj != NULL, "invariant");
-  const u8 java_lang_thread_id = java_lang_Thread::thread_id(threadObj);
+  HandleMark hm(_thread);
   const char* const thread_name = _thread->name();
-  const traceid thread_group_id = JfrThreadGroup::thread_group_id(_thread);
   writer.write_count(1);
   writer.write_key(_thread->jfr_thread_local()->thread_id());
   writer.write(thread_name);
   writer.write((traceid)_thread->osthread()->thread_id());
-  writer.write(thread_name);
-  writer.write(java_lang_thread_id);
-  writer.write(thread_group_id);
-  JfrThreadGroup::serialize(&writer, thread_group_id);
+  if (_thread->is_Java_thread()) {
+    JavaThread* const jt = (JavaThread*)_thread;
+    writer.write(jt->name());
+    writer.write(java_lang_Thread::thread_id(jt->threadObj()));
+    const traceid thread_group_id = JfrThreadGroup::thread_group_id(jt, jt);
+    writer.write(thread_group_id);
+    JfrThreadGroup::serialize(&writer, thread_group_id);
+    return;
+  }
+  writer.write((const char*)NULL); // java name
+  writer.write((traceid)0); // java thread id
+  writer.write((traceid)0); // java thread group
 }
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.hpp	Fri May 17 16:02:27 2019 +0200
@@ -42,6 +42,12 @@
   void serialize(JfrCheckpointWriter& writer);
 };
 
+class FlushTypeSet : public JfrSerializer {
+ size_t _elements;
+ public:
+  void serialize(JfrCheckpointWriter& writer);
+  size_t elements() const;
+};
 class FlagValueOriginConstant : public JfrSerializer {
  public:
   void serialize(JfrCheckpointWriter& writer);
@@ -129,9 +135,9 @@
 
 class JfrThreadConstant : public JfrSerializer {
  private:
-  JavaThread* _thread;
+  Thread* _thread;
  public:
-  JfrThreadConstant(JavaThread* jt) : _thread(jt) {}
+  JfrThreadConstant(Thread* t) : _thread(t) {}
   void serialize(JfrCheckpointWriter& writer);
 };
 
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.cpp	Fri May 17 16:02:27 2019 +0200
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "jfr/jfr.hpp"
 #include "jfr/metadata/jfrSerializer.hpp"
 #include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
 #include "jfr/recorder/checkpoint/types/jfrType.hpp"
@@ -72,6 +73,8 @@
   }
 
   void invoke(JfrCheckpointWriter& writer) const;
+
+  void on_rotation() const;
 };
 
 void JfrSerializerRegistration::invoke(JfrCheckpointWriter& writer) const {
@@ -96,6 +99,10 @@
   }
 }
 
+void  JfrSerializerRegistration::on_rotation() const {
+  _serializer->on_rotation();
+}
+
 class SerializerRegistrationGuard : public StackObj {
  private:
   static Semaphore _mutex_semaphore;
@@ -113,7 +120,6 @@
 typedef JfrDoublyLinkedList<JfrSerializerRegistration> List;
 typedef StopOnNullIterator<const List> Iterator;
 static List types;
-static List safepoint_types;
 
 void JfrTypeManager::clear() {
   SerializerRegistrationGuard guard;
@@ -124,12 +130,6 @@
     assert(registration != NULL, "invariant");
     delete registration;
   }
-  Iterator sp_type_iter(safepoint_types);
-  while (sp_type_iter.has_next()) {
-    registration = safepoint_types.remove(sp_type_iter.next());
-    assert(registration != NULL, "invariant");
-    delete registration;
-  }
 }
 
 void JfrTypeManager::write_types(JfrCheckpointWriter& writer) {
@@ -139,54 +139,53 @@
   }
 }
 
-void JfrTypeManager::write_safepoint_types(JfrCheckpointWriter& writer) {
-  assert(SafepointSynchronize::is_at_safepoint(), "invariant");
-  const Iterator iter(safepoint_types);
+void JfrTypeManager::notify_types_on_rotation() {
+  const Iterator iter(types);
   while (iter.has_next()) {
-    iter.next()->invoke(writer);
+    iter.next()->on_rotation();
   }
 }
 
 void JfrTypeManager::write_type_set() {
   // can safepoint here because of Module_lock
-  MutexLocker cld_lock(SafepointSynchronize::is_at_safepoint() ? NULL : ClassLoaderDataGraph_lock);
-  MutexLocker lock(SafepointSynchronize::is_at_safepoint() ? NULL : Module_lock);
-
+  assert(!SafepointSynchronize::is_at_safepoint(), "invariant");
   JfrCheckpointWriter writer(true, true, Thread::current());
   TypeSet set;
   set.serialize(writer);
 }
 
 void JfrTypeManager::write_type_set_for_unloaded_classes() {
-  assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
+  assert(SafepointSynchronize::is_at_safepoint(), "invariant");
   JfrCheckpointWriter writer(false, true, Thread::current());
   ClassUnloadTypeSet class_unload_set;
   class_unload_set.serialize(writer);
 }
 
-void JfrTypeManager::create_thread_checkpoint(JavaThread* jt) {
-  assert(jt != NULL, "invariant");
-  JfrThreadConstant type_thread(jt);
-  JfrCheckpointWriter writer(false, true, jt);
+size_t JfrTypeManager::flush_type_set() {
+  assert(!SafepointSynchronize::is_at_safepoint(), "invariant");
+  JfrCheckpointWriter writer(true, true, Thread::current());
+  FlushTypeSet flush;
+  flush.serialize(writer);
+  return flush.elements();
+}
+
+void JfrTypeManager::create_thread_checkpoint(Thread* t) {
+  assert(t != NULL, "invariant");
+  JfrThreadConstant type_thread(t);
+  JfrCheckpointWriter writer(false, true, t);
   writer.write_type(TYPE_THREAD);
   type_thread.serialize(writer);
   // create and install a checkpoint blob
-  jt->jfr_thread_local()->set_thread_checkpoint(writer.checkpoint_blob());
-  assert(jt->jfr_thread_local()->has_thread_checkpoint(), "invariant");
+  t->jfr_thread_local()->set_thread_checkpoint(writer.checkpoint_blob());
+  assert(t->jfr_thread_local()->has_thread_checkpoint(), "invariant");
 }
 
-void JfrTypeManager::write_thread_checkpoint(JavaThread* jt) {
-  assert(jt != NULL, "JavaThread is NULL!");
-  ResourceMark rm(jt);
-  if (jt->jfr_thread_local()->has_thread_checkpoint()) {
-    JfrCheckpointWriter writer(false, false, jt);
-    jt->jfr_thread_local()->thread_checkpoint()->write(writer);
-  } else {
-    JfrThreadConstant type_thread(jt);
-    JfrCheckpointWriter writer(false, true, jt);
-    writer.write_type(TYPE_THREAD);
-    type_thread.serialize(writer);
-  }
+void JfrTypeManager::write_thread_checkpoint(Thread* t) {
+  assert(t != NULL, "invariant");
+  JfrThreadConstant type_thread(t);
+  JfrCheckpointWriter writer(false, true, t);
+  writer.write_type(TYPE_THREAD);
+  type_thread.serialize(writer);
 }
 
 #ifdef ASSERT
@@ -198,22 +197,21 @@
 }
 #endif
 
-static bool register_type(JfrTypeId id, bool require_safepoint, bool permit_cache, JfrSerializer* serializer) {
+static bool register_type(JfrTypeId id, bool permit_cache, JfrSerializer* serializer) {
   assert(serializer != NULL, "invariant");
   JfrSerializerRegistration* const registration = new JfrSerializerRegistration(id, permit_cache, serializer);
   if (registration == NULL) {
     delete serializer;
     return false;
   }
-  if (require_safepoint) {
-    assert(!safepoint_types.in_list(registration), "invariant");
-    DEBUG_ONLY(assert_not_registered_twice(id, safepoint_types);)
-    safepoint_types.prepend(registration);
-  } else {
-    assert(!types.in_list(registration), "invariant");
-    DEBUG_ONLY(assert_not_registered_twice(id, types);)
-    types.prepend(registration);
+
+  assert(!types.in_list(registration), "invariant");
+  DEBUG_ONLY(assert_not_registered_twice(id, types);)
+  if (Jfr::is_recording()) {
+    JfrCheckpointWriter writer(false, true, Thread::current());
+    registration->invoke(writer);
   }
+  types.prepend(registration);
   return true;
 }
 
@@ -221,31 +219,30 @@
   SerializerRegistrationGuard guard;
 
   // register non-safepointing type serialization
-  register_type(TYPE_FLAGVALUEORIGIN, false, true, new FlagValueOriginConstant());
-  register_type(TYPE_INFLATECAUSE, false, true, new MonitorInflateCauseConstant());
-  register_type(TYPE_GCCAUSE, false, true, new GCCauseConstant());
-  register_type(TYPE_GCNAME, false, true, new GCNameConstant());
-  register_type(TYPE_GCWHEN, false, true, new GCWhenConstant());
-  register_type(TYPE_G1HEAPREGIONTYPE, false, true, new G1HeapRegionTypeConstant());
-  register_type(TYPE_GCTHRESHOLDUPDATER, false, true, new GCThresholdUpdaterConstant());
-  register_type(TYPE_METADATATYPE, false, true, new MetadataTypeConstant());
-  register_type(TYPE_METASPACEOBJECTTYPE, false, true, new MetaspaceObjectTypeConstant());
-  register_type(TYPE_G1YCTYPE, false, true, new G1YCTypeConstant());
-  register_type(TYPE_REFERENCETYPE, false, true, new ReferenceTypeConstant());
-  register_type(TYPE_NARROWOOPMODE, false, true, new NarrowOopModeConstant());
-  register_type(TYPE_COMPILERPHASETYPE, false, true, new CompilerPhaseTypeConstant());
-  register_type(TYPE_CODEBLOBTYPE, false, true, new CodeBlobTypeConstant());
-  register_type(TYPE_VMOPERATIONTYPE, false, true, new VMOperationTypeConstant());
-  register_type(TYPE_THREADSTATE, false, true, new ThreadStateConstant());
+  register_type(TYPE_THREADGROUP, false, new JfrThreadGroupConstant());
+  register_type(TYPE_THREAD, false, new JfrThreadConstantSet());
+  register_type(TYPE_FLAGVALUEORIGIN, true, new FlagValueOriginConstant());
+  register_type(TYPE_INFLATECAUSE, true, new MonitorInflateCauseConstant());
+  register_type(TYPE_GCCAUSE, true, new GCCauseConstant());
+  register_type(TYPE_GCNAME, true, new GCNameConstant());
+  register_type(TYPE_GCWHEN, true, new GCWhenConstant());
+  register_type(TYPE_G1HEAPREGIONTYPE, true, new G1HeapRegionTypeConstant());
+  register_type(TYPE_GCTHRESHOLDUPDATER, true, new GCThresholdUpdaterConstant());
+  register_type(TYPE_METADATATYPE, true, new MetadataTypeConstant());
+  register_type(TYPE_METASPACEOBJECTTYPE, true, new MetaspaceObjectTypeConstant());
+  register_type(TYPE_G1YCTYPE, true, new G1YCTypeConstant());
+  register_type(TYPE_REFERENCETYPE, true, new ReferenceTypeConstant());
+  register_type(TYPE_NARROWOOPMODE, true, new NarrowOopModeConstant());
+  register_type(TYPE_COMPILERPHASETYPE, true, new CompilerPhaseTypeConstant());
+  register_type(TYPE_CODEBLOBTYPE, true, new CodeBlobTypeConstant());
+  register_type(TYPE_VMOPERATIONTYPE, true, new VMOperationTypeConstant());
+  register_type(TYPE_THREADSTATE, true, new ThreadStateConstant());
 
-  // register safepointing type serialization
-  register_type(TYPE_THREADGROUP, true, false, new JfrThreadGroupConstant());
-  register_type(TYPE_THREAD, true, false, new JfrThreadConstantSet());
   return true;
 }
 
 // implementation for the static registration function exposed in the JfrSerializer api
-bool JfrSerializer::register_serializer(JfrTypeId id, bool require_safepoint, bool permit_cache, JfrSerializer* serializer) {
+bool JfrSerializer::register_serializer(JfrTypeId id, bool permit_cache, JfrSerializer* serializer) {
   SerializerRegistrationGuard guard;
-  return register_type(id, require_safepoint, permit_cache, serializer);
+  return register_type(id, permit_cache, serializer);
 }
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.hpp	Fri May 17 16:02:27 2019 +0200
@@ -34,11 +34,12 @@
   static bool initialize();
   static void clear();
   static void write_types(JfrCheckpointWriter& writer);
-  static void write_safepoint_types(JfrCheckpointWriter& writer);
+  static void notify_types_on_rotation();
   static void write_type_set();
   static void write_type_set_for_unloaded_classes();
-  static void create_thread_checkpoint(JavaThread* jt);
-  static void write_thread_checkpoint(JavaThread* jt);
+  static size_t flush_type_set();
+  static void create_thread_checkpoint(Thread* t);
+  static void write_thread_checkpoint(Thread* t);
 };
 
 #endif // SHARE_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPEMANAGER_HPP
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -80,35 +80,35 @@
   return cld->is_unsafe_anonymous() ? 0 : TRACE_ID(cld);
 }
 
-static void tag_leakp_klass_artifacts(KlassPtr k, bool class_unload) {
+static void tag_leakp_klass_artifacts(KlassPtr k, bool current_epoch) {
   assert(k != NULL, "invariant");
   PkgPtr pkg = k->package();
   if (pkg != NULL) {
-    tag_leakp_artifact(pkg, class_unload);
+    tag_leakp_artifact(pkg, current_epoch);
     ModPtr module = pkg->module();
     if (module != NULL) {
-      tag_leakp_artifact(module, class_unload);
+      tag_leakp_artifact(module, current_epoch);
     }
   }
   CldPtr cld = k->class_loader_data();
   assert(cld != NULL, "invariant");
   if (!cld->is_unsafe_anonymous()) {
-    tag_leakp_artifact(cld, class_unload);
+    tag_leakp_artifact(cld, current_epoch);
   }
 }
 
 class TagLeakpKlassArtifact {
-  bool _class_unload;
+  bool _current_epoch;
  public:
-  TagLeakpKlassArtifact(bool class_unload) : _class_unload(class_unload) {}
+  TagLeakpKlassArtifact(bool current_epoch) : _current_epoch(current_epoch) {}
   bool operator()(KlassPtr klass) {
-    if (_class_unload) {
+    if (_current_epoch) {
       if (LEAKP_USED_THIS_EPOCH(klass)) {
-        tag_leakp_klass_artifacts(klass, _class_unload);
+        tag_leakp_klass_artifacts(klass, _current_epoch);
       }
     } else {
       if (LEAKP_USED_PREV_EPOCH(klass)) {
-        tag_leakp_klass_artifacts(klass, _class_unload);
+        tag_leakp_klass_artifacts(klass, _current_epoch);
       }
     }
     return true;
@@ -123,11 +123,10 @@
  * The weird naming is an effort to decrease the risk of name clashes.
  */
 
-int write__artifact__klass(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* k) {
+int write__artifact__klass(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, KlassPtr klass) {
   assert(writer != NULL, "invariant");
   assert(artifacts != NULL, "invariant");
-  assert(k != NULL, "invariant");
-  KlassPtr klass = (KlassPtr)k;
+  assert(klass != NULL, "invariant");
   traceid pkg_id = 0;
   KlassPtr theklass = klass;
   if (theklass->is_objArray_klass()) {
@@ -149,17 +148,33 @@
   return 1;
 }
 
+int write__artifact__klass__leakp(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* k) {
+  assert(k != NULL, "invariant");
+  KlassPtr klass = (KlassPtr)k;
+  return write__artifact__klass(writer, artifacts, klass);
+}
+
+int write__artifact__klass__serialize(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* k) {
+  assert(k != NULL, "invariant");
+  KlassPtr klass = (KlassPtr)k;
+  int result = write__artifact__klass(writer, artifacts, klass);
+  if (IS_NOT_SERIALIZED(klass)) {
+    SET_SERIALIZED(klass);
+  }
+  assert(IS_SERIALIZED(klass), "invariant");
+  return result;
+}
+
 typedef LeakPredicate<KlassPtr> LeakKlassPredicate;
-typedef JfrPredicatedArtifactWriterImplHost<KlassPtr, LeakKlassPredicate, write__artifact__klass> LeakKlassWriterImpl;
+typedef SerializePredicate<KlassPtr> KlassPredicate;
+typedef JfrPredicatedArtifactWriterImplHost<KlassPtr, LeakKlassPredicate, write__artifact__klass__leakp> LeakKlassWriterImpl;
 typedef JfrArtifactWriterHost<LeakKlassWriterImpl, TYPE_CLASS> LeakKlassWriter;
-typedef JfrArtifactWriterImplHost<KlassPtr, write__artifact__klass> KlassWriterImpl;
+typedef JfrPredicatedArtifactWriterImplHost<KlassPtr, KlassPredicate, write__artifact__klass__serialize> KlassWriterImpl;
 typedef JfrArtifactWriterHost<KlassWriterImpl, TYPE_CLASS> KlassWriter;
 
-int write__artifact__method(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* m) {
+int write__artifact__method(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, MethodPtr method) {
   assert(writer != NULL, "invariant");
   assert(artifacts != NULL, "invariant");
-  assert(m != NULL, "invariant");
-  MethodPtr method = (MethodPtr)m;
   const traceid method_name_symbol_id = artifacts->mark(method->name());
   assert(method_name_symbol_id > 0, "invariant");
   const traceid method_sig_symbol_id = artifacts->mark(method->signature());
@@ -176,14 +191,33 @@
   return 1;
 }
 
-typedef JfrArtifactWriterImplHost<MethodPtr, write__artifact__method> MethodWriterImplTarget;
+int write__artifact__method__leakp(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* m) {
+  assert(m != NULL, "invariant");
+  MethodPtr method = (MethodPtr)m;
+  return write__artifact__method(writer, artifacts, method);
+}
+
+int write__artifact__method__serialize(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* m) {
+  assert(m != NULL, "invariant");
+  MethodPtr method = (MethodPtr)m;
+  int result = write__artifact__method(writer, artifacts, method);
+  if (METHOD_NOT_SERIALIZED(method)) {
+    SET_METHOD_SERIALIZED(method);
+  }
+  assert(IS_METHOD_SERIALIZED(method), "invariant");
+  return result;
+}
+
+typedef JfrArtifactWriterImplHost<MethodPtr, write__artifact__method__leakp> LeakpMethodWriterImplTarget;
+typedef JfrArtifactWriterHost<LeakpMethodWriterImplTarget, TYPE_METHOD> LeakpMethodWriterImpl;
+typedef SerializePredicate<MethodPtr> MethodPredicate;
+typedef JfrPredicatedArtifactWriterImplHost<MethodPtr, MethodPredicate, write__artifact__method__serialize> MethodWriterImplTarget;
 typedef JfrArtifactWriterHost<MethodWriterImplTarget, TYPE_METHOD> MethodWriterImpl;
 
-int write__artifact__package(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* p) {
+int write__artifact__package(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, PkgPtr pkg) {
   assert(writer != NULL, "invariant");
   assert(artifacts != NULL, "invariant");
-  assert(p != NULL, "invariant");
-  PkgPtr pkg = (PkgPtr)p;
+  assert(pkg != NULL, "invariant");
   Symbol* const pkg_name = pkg->name();
   const traceid package_name_symbol_id = pkg_name != NULL ? artifacts->mark(pkg_name) : 0;
   assert(package_name_symbol_id > 0, "invariant");
@@ -194,17 +228,34 @@
   return 1;
 }
 
+int write__artifact__package__leakp(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* p) {
+  assert(p != NULL, "invariant");
+  PkgPtr pkg = (PkgPtr)p;
+  return write__artifact__package(writer, artifacts, pkg);
+}
+
+int write__artifact__package__serialize(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* p) {
+  assert(p != NULL, "invariant");
+  PkgPtr pkg = (PkgPtr)p;
+  int result = write__artifact__package(writer, artifacts, pkg);
+  if (IS_NOT_SERIALIZED(pkg)) {
+    SET_SERIALIZED(pkg);
+  }
+  assert(IS_SERIALIZED(pkg), "invariant");
+  return result;
+}
+
 typedef LeakPredicate<PkgPtr> LeakPackagePredicate;
-int _compare_pkg_ptr_(PkgPtr const& lhs, PkgPtr const& rhs) { return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0; }
-typedef UniquePredicate<PkgPtr, _compare_pkg_ptr_> PackagePredicate;
-typedef JfrPredicatedArtifactWriterImplHost<PkgPtr, LeakPackagePredicate, write__artifact__package> LeakPackageWriterImpl;
-typedef JfrPredicatedArtifactWriterImplHost<PkgPtr, PackagePredicate, write__artifact__package> PackageWriterImpl;
+//int _compare_pkg_ptr_(PkgPtr const& lhs, PkgPtr const& rhs) { return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0; }
+//typedef UniquePredicate<PkgPtr, _compare_pkg_ptr_> PackagePredicate;
+typedef SerializePredicate<PkgPtr> PackagePredicate;
+typedef JfrPredicatedArtifactWriterImplHost<PkgPtr, LeakPackagePredicate, write__artifact__package__leakp> LeakPackageWriterImpl;
+typedef JfrPredicatedArtifactWriterImplHost<PkgPtr, PackagePredicate, write__artifact__package__serialize> PackageWriterImpl;
 typedef JfrArtifactWriterHost<LeakPackageWriterImpl, TYPE_PACKAGE> LeakPackageWriter;
 typedef JfrArtifactWriterHost<PackageWriterImpl, TYPE_PACKAGE> PackageWriter;
 
-int write__artifact__module(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* m) {
-  assert( m != NULL, "invariant");
-  ModPtr entry = (ModPtr)m;
+int write__artifact__module(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, ModPtr entry) {
+  assert(entry != NULL, "invariant");
   Symbol* const module_name = entry->name();
   const traceid module_name_symbol_id = module_name != NULL ? artifacts->mark(module_name) : 0;
   Symbol* const module_version = entry->version();
@@ -219,17 +270,41 @@
   return 1;
 }
 
+int write__artifact__module__leakp(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* m) {
+  assert(m != NULL, "invariant");
+  ModPtr entry = (ModPtr)m;
+  return write__artifact__module(writer, artifacts, entry);
+}
+
+int write__artifact__module__serialize(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* m) {
+  assert(m != NULL, "invariant");
+  ModPtr entry = (ModPtr)m;
+  int result = write__artifact__module(writer, artifacts, entry);
+  CldPtr cld = entry->loader_data();
+  assert(cld != NULL, "invariant");
+  if (IS_NOT_SERIALIZED(cld)) {
+    if (!cld->is_unsafe_anonymous()) {
+      SET_USED_PREV_EPOCH(cld);
+    }
+  }
+  if (IS_NOT_SERIALIZED(entry)) {
+    SET_SERIALIZED(entry);
+  }
+  assert(IS_SERIALIZED(entry), "invariant");
+  return result;
+}
+
 typedef LeakPredicate<ModPtr> LeakModulePredicate;
-int _compare_mod_ptr_(ModPtr const& lhs, ModPtr const& rhs) { return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0; }
-typedef UniquePredicate<ModPtr, _compare_mod_ptr_> ModulePredicate;
-typedef JfrPredicatedArtifactWriterImplHost<ModPtr, LeakModulePredicate, write__artifact__module> LeakModuleWriterImpl;
-typedef JfrPredicatedArtifactWriterImplHost<ModPtr, ModulePredicate, write__artifact__module> ModuleWriterImpl;
+//int _compare_mod_ptr_(ModPtr const& lhs, ModPtr const& rhs) { return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0; }
+//typedef UniquePredicate<ModPtr, _compare_mod_ptr_> ModulePredicate;
+typedef SerializePredicate<ModPtr> ModulePredicate;
+typedef JfrPredicatedArtifactWriterImplHost<ModPtr, LeakModulePredicate, write__artifact__module__leakp> LeakModuleWriterImpl;
+typedef JfrPredicatedArtifactWriterImplHost<ModPtr, ModulePredicate, write__artifact__module__serialize> ModuleWriterImpl;
 typedef JfrArtifactWriterHost<LeakModuleWriterImpl, TYPE_MODULE> LeakModuleWriter;
 typedef JfrArtifactWriterHost<ModuleWriterImpl, TYPE_MODULE> ModuleWriter;
 
-int write__artifact__classloader(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* c) {
-  assert(c != NULL, "invariant");
-  CldPtr cld = (CldPtr)c;
+int write__artifact__classloader(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, CldPtr cld) {
+  assert(cld != NULL, "invariant");
   assert(!cld->is_unsafe_anonymous(), "invariant");
   const traceid cld_id = TRACE_ID(cld);
   // class loader type
@@ -250,18 +325,40 @@
   return 1;
 }
 
-typedef LeakPredicate<CldPtr> LeakCldPredicate;
-int _compare_cld_ptr_(CldPtr const& lhs, CldPtr const& rhs) { return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0; }
-typedef UniquePredicate<CldPtr, _compare_cld_ptr_> CldPredicate;
-typedef JfrPredicatedArtifactWriterImplHost<CldPtr, LeakCldPredicate, write__artifact__classloader> LeakCldWriterImpl;
-typedef JfrPredicatedArtifactWriterImplHost<CldPtr, CldPredicate, write__artifact__classloader> CldWriterImpl;
+int write__artifact__classloader__leakp(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* c) {
+  assert(c != NULL, "invariant");
+  CldPtr cld = (CldPtr)c;
+  int result = write__artifact__classloader(writer, artifacts, cld);
+  if (IS_NOT_LEAKP_SERIALIZED(cld)) {
+    SET_LEAKP_SERIALIZED(cld);
+  }
+  assert(IS_LEAKP_SERIALIZED(cld), "invariant");
+  return result;
+}
+
+int write__artifact__classloader__serialize(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* c) {
+  assert(c != NULL, "invariant");
+  CldPtr cld = (CldPtr)c;
+  int result = write__artifact__classloader(writer, artifacts, cld);
+  if (IS_NOT_SERIALIZED(cld)) {
+    SET_SERIALIZED(cld);
+  }
+  assert(IS_SERIALIZED(cld), "invariant");
+  return result;
+}
+
+typedef LeakSerializePredicate<CldPtr> LeakCldPredicate;
+//int _compare_cld_ptr_(CldPtr const& lhs, CldPtr const& rhs) { return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0; }
+//typedef UniquePredicate<CldPtr, _compare_cld_ptr_> CldPredicate;
+typedef SerializePredicate<CldPtr> CldPredicate;
+typedef JfrPredicatedArtifactWriterImplHost<CldPtr, LeakCldPredicate, write__artifact__classloader__leakp> LeakCldWriterImpl;
+typedef JfrPredicatedArtifactWriterImplHost<CldPtr, CldPredicate, write__artifact__classloader__serialize> CldWriterImpl;
 typedef JfrArtifactWriterHost<LeakCldWriterImpl, TYPE_CLASSLOADER> LeakCldWriter;
 typedef JfrArtifactWriterHost<CldWriterImpl, TYPE_CLASSLOADER> CldWriter;
 
 typedef const JfrSymbolId::SymbolEntry* SymbolEntryPtr;
 
-static int write__artifact__symbol__entry__(JfrCheckpointWriter* writer,
-                                            SymbolEntryPtr entry) {
+static int write__artifact__symbol__entry__(JfrCheckpointWriter* writer, SymbolEntryPtr entry) {
   assert(writer != NULL, "invariant");
   assert(entry != NULL, "invariant");
   ResourceMark rm;
@@ -336,12 +433,12 @@
   typedef KlassPtr Type;
   KlassSymbolWriterImpl(JfrCheckpointWriter* writer,
                         JfrArtifactSet* artifacts,
-                        bool class_unload) : _writer(writer),
+                        bool current_epoch) : _writer(writer),
                                              _artifacts(artifacts),
-                                             _predicate(class_unload),
-                                             _method_used_predicate(class_unload),
-                                             _method_flag_predicate(class_unload),
-                                             _unique_predicate(class_unload) {}
+                                             _predicate(current_epoch),
+                                             _method_used_predicate(current_epoch),
+                                             _method_flag_predicate(current_epoch),
+                                             _unique_predicate(current_epoch) {}
 
   int operator()(KlassPtr klass) {
     assert(klass != NULL, "invariant");
@@ -392,8 +489,7 @@
   assert(pkg_name != NULL, "invariant");
   SymbolEntryPtr package_symbol = this->_artifacts->map_symbol(pkg_name);
   assert(package_symbol != NULL, "invariant");
-  return _unique_predicate(package_symbol->id()) ?
-    write__artifact__symbol__entry__(this->_writer, package_symbol) : 0;
+  return _unique_predicate(package_symbol->id()) ? write__artifact__symbol__entry__(this->_writer, package_symbol) : 0;
 }
 
 template <template <typename> class Predicate>
@@ -495,9 +591,7 @@
   MethodUsedPredicate<false> _method_used_predicate;
 
  public:
-  ClearKlassAndMethods(bool class_unload) : _clear_klass_tag_bits(class_unload),
-                                            _clear_method_flag(class_unload),
-                                            _method_used_predicate(class_unload) {}
+  ClearKlassAndMethods(bool current_epoch) : _method_used_predicate(current_epoch) {}
   bool operator()(KlassPtr klass) {
     if (_method_used_predicate(klass)) {
       const InstanceKlass* ik = InstanceKlass::cast(klass);
@@ -544,16 +638,17 @@
 void JfrTypeSet::write_klass_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer) {
   assert(!_artifacts->has_klass_entries(), "invariant");
   KlassArtifactRegistrator reg(_artifacts);
-  KlassWriter kw(writer, _artifacts, _class_unload);
+  KlassWriter kw(writer, _artifacts, current_epoch());
   KlassWriterRegistration kwr(&kw, &reg);
   if (leakp_writer == NULL) {
     KlassCallback callback(&kwr);
     _subsystem_callback = &callback;
     do_klasses();
+    _artifacts->tally(kw);
     return;
   }
-  TagLeakpKlassArtifact tagging(_class_unload);
-  LeakKlassWriter lkw(leakp_writer, _artifacts, _class_unload);
+  TagLeakpKlassArtifact tagging(current_epoch());
+  LeakKlassWriter lkw(leakp_writer, _artifacts, current_epoch());
   LeakpKlassArtifactTagging lpkat(&tagging, &lkw);
   CompositeKlassWriter ckw(&lpkat, &kw);
   CompositeKlassWriterRegistration ckwr(&ckw, &reg);
@@ -567,12 +662,18 @@
                          ClearArtifact<PkgPtr> > PackageWriterWithClear;
 
 typedef CompositeFunctor<PkgPtr,
+                         PackageWriter,
+                         UnTagArtifact<PkgPtr> > PackageWriterWithUnTag;
+typedef CompositeFunctor<PkgPtr,
                          LeakPackageWriter,
                          PackageWriter> CompositePackageWriter;
 
 typedef CompositeFunctor<PkgPtr,
                          CompositePackageWriter,
                          ClearArtifact<PkgPtr> > CompositePackageWriterWithClear;
+typedef CompositeFunctor<PkgPtr,
+                         CompositePackageWriter,
+                         UnTagArtifact<PkgPtr> > CompositePackageWriterWithUnTag;
 
 class PackageFieldSelector {
  public:
@@ -587,11 +688,33 @@
                              PackageWriterWithClear> KlassPackageWriterWithClear;
 
 typedef KlassToFieldEnvelope<PackageFieldSelector,
+                             PackageWriterWithUnTag> KlassPackageWriterWithUnTag;
+typedef KlassToFieldEnvelope<PackageFieldSelector, PackageWriter> KlassPackageWriter;
+typedef KlassToFieldEnvelope<PackageFieldSelector, CompositePackageWriter> KlassCompositePackageWriter;
+typedef KlassToFieldEnvelope<PackageFieldSelector,
                              CompositePackageWriterWithClear> KlassCompositePackageWriterWithClear;
 
+typedef KlassToFieldEnvelope<PackageFieldSelector,
+                             CompositePackageWriterWithUnTag> KlassCompositePackageWriterWithUnTag;
 typedef JfrArtifactCallbackHost<PkgPtr, PackageWriterWithClear> PackageCallback;
 typedef JfrArtifactCallbackHost<PkgPtr, CompositePackageWriterWithClear> CompositePackageCallback;
 
+static void write_package_constants_current_epoch(JfrArtifactSet* artifacts, JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer) {
+  assert(artifacts != NULL, "invariant");
+  assert(artifacts->has_klass_entries(), "invariant");
+  PackageWriter pw(writer, artifacts, true);
+  if (leakp_writer == NULL) {
+    KlassPackageWriter kpw(&pw);
+    artifacts->iterate_klasses(kpw);
+    artifacts->tally(pw);
+  } else {
+    LeakPackageWriter lpw(leakp_writer, artifacts, true);
+    CompositePackageWriter cpw(&lpw, &pw);
+    KlassCompositePackageWriter kcpw(&cpw);
+    artifacts->iterate_klasses(kcpw);
+  }
+}
+
 /*
  * Composite operation
  *
@@ -602,22 +725,30 @@
  */
 void JfrTypeSet::write_package_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer) {
   assert(_artifacts->has_klass_entries(), "invariant");
-  ClearArtifact<PkgPtr> clear(_class_unload);
-  PackageWriter pw(writer, _artifacts, _class_unload);
+  if (current_epoch()) {
+    write_package_constants_current_epoch(_artifacts, writer, leakp_writer);
+    return;
+  }
+  assert(is_rotating(), "invariant");
+  PackageWriter pw(writer, _artifacts, false);
+  ClearArtifact<PkgPtr> clear;
+  UnTagArtifact<PkgPtr> untag;
   if (leakp_writer == NULL) {
+    PackageWriterWithUnTag kpw(&pw, &untag);
+    KlassPackageWriterWithUnTag kpwwut(&kpw);
+    _artifacts->iterate_klasses(kpwwut);
     PackageWriterWithClear pwwc(&pw, &clear);
-    KlassPackageWriterWithClear kpwwc(&pwwc);
-    _artifacts->iterate_klasses(kpwwc);
     PackageCallback callback(&pwwc);
     _subsystem_callback = &callback;
     do_packages();
     return;
   }
-  LeakPackageWriter lpw(leakp_writer, _artifacts, _class_unload);
+  LeakPackageWriter lpw(leakp_writer, _artifacts, false);
   CompositePackageWriter cpw(&lpw, &pw);
+  CompositePackageWriterWithUnTag cpwwut(&cpw, &untag);
+  KlassCompositePackageWriterWithUnTag kcpw(&cpwwut);
+  _artifacts->iterate_klasses(kcpw);
   CompositePackageWriterWithClear cpwwc(&cpw, &clear);
-  KlassCompositePackageWriterWithClear ckpw(&cpwwc);
-  _artifacts->iterate_klasses(ckpw);
   CompositePackageCallback callback(&cpwwc);
   _subsystem_callback = &callback;
   do_packages();
@@ -628,12 +759,18 @@
                          ClearArtifact<ModPtr> > ModuleWriterWithClear;
 
 typedef CompositeFunctor<ModPtr,
+                         ModuleWriter,
+                         UnTagArtifact<ModPtr> > ModuleWriterWithUnTag;
+typedef CompositeFunctor<ModPtr,
                          LeakModuleWriter,
                          ModuleWriter> CompositeModuleWriter;
 
 typedef CompositeFunctor<ModPtr,
                          CompositeModuleWriter,
                          ClearArtifact<ModPtr> > CompositeModuleWriterWithClear;
+typedef CompositeFunctor<ModPtr,
+                         CompositeModuleWriter,
+                         UnTagArtifact<ModPtr> > CompositeModuleWriterWithUnTag;
 
 typedef JfrArtifactCallbackHost<ModPtr, ModuleWriterWithClear> ModuleCallback;
 typedef JfrArtifactCallbackHost<ModPtr, CompositeModuleWriterWithClear> CompositeModuleCallback;
@@ -652,8 +789,31 @@
                              ModuleWriterWithClear> KlassModuleWriterWithClear;
 
 typedef KlassToFieldEnvelope<ModuleFieldSelector,
+                             ModuleWriterWithUnTag> KlassModuleWriterWithUnTag;
+typedef KlassToFieldEnvelope<ModuleFieldSelector, ModuleWriter> KlassModuleWriter;
+typedef KlassToFieldEnvelope<ModuleFieldSelector,  CompositeModuleWriter> KlassCompositeModuleWriter;
+typedef KlassToFieldEnvelope<ModuleFieldSelector,
                              CompositeModuleWriterWithClear> KlassCompositeModuleWriterWithClear;
 
+typedef KlassToFieldEnvelope<ModuleFieldSelector,
+                             CompositeModuleWriterWithUnTag> KlassCompositeModuleWriterWithUnTag;
+
+static void write_module_constants_current_epoch(JfrArtifactSet* artifacts, JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer) {
+  assert(artifacts != NULL, "invariant");
+  assert(artifacts->has_klass_entries(), "invariant");
+  ModuleWriter mw(writer, artifacts, true);
+  if (leakp_writer == NULL) {
+    KlassModuleWriter kmw(&mw);
+    artifacts->iterate_klasses(kmw);
+    artifacts->tally(mw);
+  } else {
+    LeakModuleWriter lmw(leakp_writer, artifacts, true);
+    CompositeModuleWriter cmw(&lmw, &mw);
+    KlassCompositeModuleWriter kcmw(&cmw);
+    artifacts->iterate_klasses(kcmw);
+  }
+}
+
 /*
  * Composite operation
  *
@@ -663,30 +823,40 @@
  */
 void JfrTypeSet::write_module_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer) {
   assert(_artifacts->has_klass_entries(), "invariant");
-  ClearArtifact<ModPtr> clear(_class_unload);
-  ModuleWriter mw(writer, _artifacts, _class_unload);
+  if (current_epoch()) {
+    write_module_constants_current_epoch(_artifacts, writer, leakp_writer);
+    return;
+  }
+  assert(is_rotating(), "invariant");
+  ClearArtifact<ModPtr> clear;
+  UnTagArtifact<ModPtr> untag;
+  ModuleWriter mw(writer, _artifacts, false);
   if (leakp_writer == NULL) {
+    ModuleWriterWithUnTag kpw(&mw, &untag);
+    KlassModuleWriterWithUnTag kmwwut(&kpw);
+    _artifacts->iterate_klasses(kmwwut);
     ModuleWriterWithClear mwwc(&mw, &clear);
-    KlassModuleWriterWithClear kmwwc(&mwwc);
-    _artifacts->iterate_klasses(kmwwc);
     ModuleCallback callback(&mwwc);
     _subsystem_callback = &callback;
     do_modules();
     return;
   }
-  LeakModuleWriter lmw(leakp_writer, _artifacts, _class_unload);
+  LeakModuleWriter lmw(leakp_writer, _artifacts, false);
   CompositeModuleWriter cmw(&lmw, &mw);
+  CompositeModuleWriterWithUnTag cmwwut(&cmw, &untag);
+  KlassCompositeModuleWriterWithUnTag kcmw(&cmwwut);
+  _artifacts->iterate_klasses(kcmw);
   CompositeModuleWriterWithClear cmwwc(&cmw, &clear);
-  KlassCompositeModuleWriterWithClear kmwwc(&cmwwc);
-  _artifacts->iterate_klasses(kmwwc);
   CompositeModuleCallback callback(&cmwwc);
   _subsystem_callback = &callback;
   do_modules();
 }
 
 typedef CompositeFunctor<CldPtr, CldWriter, ClearArtifact<CldPtr> > CldWriterWithClear;
+typedef CompositeFunctor<CldPtr, CldWriter, UnTagArtifact<CldPtr> > CldWriterWithUnTag;
 typedef CompositeFunctor<CldPtr, LeakCldWriter, CldWriter> CompositeCldWriter;
 typedef CompositeFunctor<CldPtr, CompositeCldWriter, ClearArtifact<CldPtr> > CompositeCldWriterWithClear;
+typedef CompositeFunctor<CldPtr, CompositeCldWriter, UnTagArtifact<CldPtr> > CompositeCldWriterWithUnTag;
 typedef JfrArtifactCallbackHost<CldPtr, CldWriterWithClear> CldCallback;
 typedef JfrArtifactCallbackHost<CldPtr, CompositeCldWriterWithClear> CompositeCldCallback;
 
@@ -700,8 +870,28 @@
   }
 };
 
+typedef KlassToFieldEnvelope<CldFieldSelector, CldWriter> KlassCldWriter;
 typedef KlassToFieldEnvelope<CldFieldSelector, CldWriterWithClear> KlassCldWriterWithClear;
+typedef KlassToFieldEnvelope<CldFieldSelector, CldWriterWithUnTag> KlassCldWriterWithUnTag;
+typedef KlassToFieldEnvelope<CldFieldSelector, CompositeCldWriter> KlassCompositeCldWriter;
 typedef KlassToFieldEnvelope<CldFieldSelector, CompositeCldWriterWithClear> KlassCompositeCldWriterWithClear;
+typedef KlassToFieldEnvelope<CldFieldSelector, CompositeCldWriterWithUnTag> KlassCompositeCldWriterWithUnTag;
+
+static void write_class_loader_constants_current_epoch(JfrArtifactSet* artifacts, JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer) {
+  assert(artifacts != NULL, "invariant");
+  assert(artifacts->has_klass_entries(), "invariant");
+  CldWriter cldw(writer, artifacts, true);
+  if (leakp_writer == NULL) {
+    KlassCldWriter kcw(&cldw);
+    artifacts->iterate_klasses(kcw);
+    artifacts->tally(cldw);
+  } else {
+    LeakCldWriter lcldw(leakp_writer, artifacts, true);
+    CompositeCldWriter ccldw(&lcldw, &cldw);
+    KlassCompositeCldWriter kccldw(&ccldw);
+    artifacts->iterate_klasses(kccldw);
+  }
+}
 
 /*
  * Composite operation
@@ -712,22 +902,30 @@
  */
 void JfrTypeSet::write_class_loader_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer) {
   assert(_artifacts->has_klass_entries(), "invariant");
-  ClearArtifact<CldPtr> clear(_class_unload);
-  CldWriter cldw(writer, _artifacts, _class_unload);
+  if (current_epoch()) {
+    write_class_loader_constants_current_epoch(_artifacts, writer, leakp_writer);
+    return;
+  }
+  assert(is_rotating(), "invariant");
+  ClearArtifact<CldPtr> clear;
+  UnTagArtifact<CldPtr> untag;
+  CldWriter cldw(writer, _artifacts, false);
   if (leakp_writer == NULL) {
+    CldWriterWithUnTag cldwut(&cldw, &untag);
+    KlassCldWriterWithUnTag kcldwut(&cldwut);
+    _artifacts->iterate_klasses(kcldwut);
     CldWriterWithClear cldwwc(&cldw, &clear);
-    KlassCldWriterWithClear kcldwwc(&cldwwc);
-    _artifacts->iterate_klasses(kcldwwc);
     CldCallback callback(&cldwwc);
     _subsystem_callback = &callback;
     do_class_loaders();
     return;
   }
-  LeakCldWriter lcldw(leakp_writer, _artifacts, _class_unload);
+  LeakCldWriter lcldw(leakp_writer, _artifacts, false);
   CompositeCldWriter ccldw(&lcldw, &cldw);
+  CompositeCldWriterWithUnTag cldwwut(&ccldw, &untag);
+  KlassCompositeCldWriterWithUnTag kccldw(&cldwwut);
+  _artifacts->iterate_klasses(kccldw);
   CompositeCldWriterWithClear ccldwwc(&ccldw, &clear);
-  KlassCompositeCldWriterWithClear kcclwwc(&ccldwwc);
-  _artifacts->iterate_klasses(kcclwwc);
   CompositeCldCallback callback(&ccldwwc);
   _subsystem_callback = &callback;
   do_class_loaders();
@@ -743,11 +941,11 @@
  public:
   MethodIteratorHost(JfrCheckpointWriter* writer,
                      JfrArtifactSet* artifacts,
-                     bool class_unload,
+                     bool current_epoch,
                      bool skip_header = false) :
-    _method_functor(writer, artifacts, class_unload, skip_header),
-    _method_used_predicate(class_unload),
-    _method_flag_predicate(class_unload) {}
+    _method_functor(writer, artifacts, current_epoch, skip_header),
+    _method_used_predicate(current_epoch),
+    _method_flag_predicate(current_epoch) {}
 
   bool operator()(KlassPtr klass) {
     if (_method_used_predicate(klass)) {
@@ -768,7 +966,7 @@
   void add(int count) { _method_functor.add(count); }
 };
 
-typedef MethodIteratorHost<true /*leakp */,  MethodWriterImpl> LeakMethodWriter;
+typedef MethodIteratorHost<true /*leakp */,  LeakpMethodWriterImpl> LeakMethodWriter;
 typedef MethodIteratorHost<false, MethodWriterImpl> MethodWriter;
 typedef CompositeFunctor<KlassPtr, LeakMethodWriter, MethodWriter> CompositeMethodWriter;
 
@@ -780,39 +978,56 @@
  */
 void JfrTypeSet::write_method_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer) {
   assert(_artifacts->has_klass_entries(), "invariant");
-  MethodWriter mw(writer, _artifacts, _class_unload);
+  MethodWriter mw(writer, _artifacts, is_not_rotating());
   if (leakp_writer == NULL) {
     _artifacts->iterate_klasses(mw);
+    _artifacts->tally(mw);
     return;
   }
-  LeakMethodWriter lpmw(leakp_writer, _artifacts, _class_unload);
+  LeakMethodWriter lpmw(leakp_writer, _artifacts, is_not_rotating());
   CompositeMethodWriter cmw(&lpmw, &mw);
   _artifacts->iterate_klasses(cmw);
 }
-static void write_symbols_leakp(JfrCheckpointWriter* leakp_writer, JfrArtifactSet* artifacts, bool class_unload) {
+
+static void write_symbols_leakp(JfrCheckpointWriter* leakp_writer, JfrArtifactSet* artifacts, bool current_epoch) {
   assert(leakp_writer != NULL, "invariant");
   assert(artifacts != NULL, "invariant");
-  LeakKlassSymbolWriter lpksw(leakp_writer, artifacts, class_unload);
+  LeakKlassSymbolWriter lpksw(leakp_writer, artifacts, current_epoch);
   artifacts->iterate_klasses(lpksw);
 }
-static void write_symbols(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer, JfrArtifactSet* artifacts, bool class_unload) {
+
+static void write_symbols(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer, JfrArtifactSet* artifacts, bool current_epoch) {
   assert(writer != NULL, "invariant");
   assert(artifacts != NULL, "invariant");
   if (leakp_writer != NULL) {
-    write_symbols_leakp(leakp_writer, artifacts, class_unload);
+    write_symbols_leakp(leakp_writer, artifacts, current_epoch);
   }
   // iterate all registered symbols
-  SymbolEntryWriter symbol_writer(writer, artifacts, class_unload);
+  SymbolEntryWriter symbol_writer(writer, artifacts, current_epoch);
   artifacts->iterate_symbols(symbol_writer);
-  CStringEntryWriter cstring_writer(writer, artifacts, class_unload, true); // skip header
+  CStringEntryWriter cstring_writer(writer, artifacts, current_epoch, true); // skip header
   artifacts->iterate_cstrings(cstring_writer);
   symbol_writer.add(cstring_writer.count());
+  artifacts->tally(symbol_writer);
 }
 
 bool JfrTypeSet::_class_unload = false;
+bool JfrTypeSet::_flushpoint = false;
 JfrArtifactSet* JfrTypeSet::_artifacts = NULL;
 JfrArtifactClosure* JfrTypeSet::_subsystem_callback = NULL;
 
+bool JfrTypeSet::is_rotating() {
+  return !(_class_unload || _flushpoint);
+}
+
+bool JfrTypeSet::is_not_rotating() {
+  return !is_rotating();
+}
+
+bool JfrTypeSet::current_epoch() {
+  return is_not_rotating();
+}
+
 void JfrTypeSet::write_symbol_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer) {
   assert(writer != NULL, "invariant");
   assert(_artifacts->has_klass_entries(), "invariant");
@@ -838,12 +1053,23 @@
 void JfrTypeSet::do_klass(Klass* klass) {
   assert(klass != NULL, "invariant");
   assert(_subsystem_callback != NULL, "invariant");
-  if (USED_PREV_EPOCH(klass)) { // includes leakp subset
-    _subsystem_callback->do_artifact(klass);
-    return;
+  if (_flushpoint) {
+    if (USED_THIS_EPOCH(klass)) {
+      _subsystem_callback->do_artifact(klass);
+      return;
+    }
+  } else {
+    if (USED_PREV_EPOCH(klass)) { // includes leakp subset
+      _subsystem_callback->do_artifact(klass);
+      return;
+    }
   }
   if (klass->is_subclass_of(SystemDictionary::ClassLoader_klass()) || klass == SystemDictionary::Object_klass()) {
-    SET_LEAKP_USED_PREV_EPOCH(klass); // tag leakp "safe byte" for subset inclusion
+    if (_flushpoint) {
+      SET_LEAKP_USED_THIS_EPOCH(klass);
+    } else {
+      SET_LEAKP_USED_PREV_EPOCH(klass); // tag leakp "safe byte" for subset inclusion
+    }
     _subsystem_callback->do_artifact(klass);
   }
 }
@@ -856,19 +1082,35 @@
   ClassLoaderDataGraph::classes_do(&do_klass);
 }
 
-void JfrTypeSet::do_unloaded_package(PackageEntry* entry) {
-  assert(entry != NULL, "invariant");
-  assert(_subsystem_callback != NULL, "invariant");
-  if (ANY_USED_THIS_EPOCH(entry)) { // includes leakp subset
-    _subsystem_callback->do_artifact(entry);
+template <typename T>
+static void do_current_epoch_artifact(JfrArtifactClosure* callback, T* value) {
+  assert(callback != NULL, "invariant");
+  assert(value != NULL, "invariant");
+  if (ANY_USED_THIS_EPOCH(value)) { // includes leakp subset
+    callback->do_artifact(value);
   }
 }
 
+template <typename T>
+static void do_previous_epoch_artifact(JfrArtifactClosure* callback, T* value) {
+  assert(callback != NULL, "invariant");
+  assert(value != NULL, "invariant");
+  if (ANY_USED_PREV_EPOCH(value)) { // includes leakp subset
+    callback->do_artifact(value);
+    assert(IS_NOT_SERIALIZED(value), "invariant");
+    return;
+  }
+  if (IS_SERIALIZED(value)) {
+    UNSERIALIZE(value);
+  }
+  assert(IS_NOT_SERIALIZED(value), "invariant");
+}
+void JfrTypeSet::do_unloaded_package(PackageEntry* entry) {
+  do_current_epoch_artifact(_subsystem_callback, entry);
+}
+
 void JfrTypeSet::do_package(PackageEntry* entry) {
-  assert(_subsystem_callback != NULL, "invariant");
-  if (ANY_USED_PREV_EPOCH(entry)) { // includes leakp subset
-    _subsystem_callback->do_artifact(entry);
-  }
+  do_previous_epoch_artifact(_subsystem_callback, entry);
 }
 
 void JfrTypeSet::do_packages() {
@@ -878,19 +1120,13 @@
   }
   ClassLoaderDataGraph::packages_do(&do_package);
 }
+
 void JfrTypeSet::do_unloaded_module(ModuleEntry* entry) {
-  assert(entry != NULL, "invariant");
-  assert(_subsystem_callback != NULL, "invariant");
-  if (ANY_USED_THIS_EPOCH(entry)) { // includes leakp subset
-    _subsystem_callback->do_artifact(entry);
-  }
+  do_current_epoch_artifact(_subsystem_callback, entry);
 }
 
 void JfrTypeSet::do_module(ModuleEntry* entry) {
-  assert(_subsystem_callback != NULL, "invariant");
-  if (ANY_USED_PREV_EPOCH(entry)) { // includes leakp subset
-    _subsystem_callback->do_artifact(entry);
-  }
+  do_previous_epoch_artifact(_subsystem_callback, entry);
 }
 
 void JfrTypeSet::do_modules() {
@@ -902,17 +1138,11 @@
 }
 
 void JfrTypeSet::do_unloaded_class_loader_data(ClassLoaderData* cld) {
-  assert(_subsystem_callback != NULL, "invariant");
-  if (ANY_USED_THIS_EPOCH(cld)) { // includes leakp subset
-    _subsystem_callback->do_artifact(cld);
-  }
+  do_current_epoch_artifact(_subsystem_callback, cld);
 }
 
 void JfrTypeSet::do_class_loader_data(ClassLoaderData* cld) {
-  assert(_subsystem_callback != NULL, "invariant");
-  if (ANY_USED_PREV_EPOCH(cld)) { // includes leakp subset
-    _subsystem_callback->do_artifact(cld);
-  }
+  do_previous_epoch_artifact(_subsystem_callback, cld);
 }
 
 class CLDCallback : public CLDClosure {
@@ -921,7 +1151,7 @@
  public:
   CLDCallback(bool class_unload) : _class_unload(class_unload) {}
   void do_cld(ClassLoaderData* cld) {
-     assert(cld != NULL, "invariant");
+    assert(cld != NULL, "invariant");
     if (cld->is_unsafe_anonymous()) {
       return;
     }
@@ -942,47 +1172,48 @@
   ClassLoaderDataGraph::loaded_cld_do(&cld_cb);
 }
 
-static void clear_artifacts(JfrArtifactSet* artifacts,
-                            bool class_unload) {
+static void clear_artifacts(JfrArtifactSet* artifacts, bool current_epoch) {
   assert(artifacts != NULL, "invariant");
   assert(artifacts->has_klass_entries(), "invariant");
 
   // untag
-  ClearKlassAndMethods clear(class_unload);
+  ClearKlassAndMethods clear(current_epoch);
   artifacts->iterate_klasses(clear);
-  artifacts->clear();
 }
 
 /**
  * Write all "tagged" (in-use) constant artifacts and their dependencies.
  */
-void JfrTypeSet::serialize(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer, bool class_unload) {
+size_t JfrTypeSet::serialize(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer, bool class_unload, bool flushpoint) {
   assert(writer != NULL, "invariant");
   ResourceMark rm;
   // initialization begin
   _class_unload = class_unload;
+  _flushpoint = flushpoint;
   ++checkpoint_id;
   if (_artifacts == NULL) {
-    _artifacts = new JfrArtifactSet(class_unload);
-    _subsystem_callback = NULL;
+    _artifacts = new JfrArtifactSet(current_epoch());
   } else {
-    _artifacts->initialize(class_unload);
-    _subsystem_callback = NULL;
+    _artifacts->initialize(current_epoch());
   }
   assert(_artifacts != NULL, "invariant");
   assert(!_artifacts->has_klass_entries(), "invariant");
-  assert(_subsystem_callback == NULL, "invariant");
   // initialization complete
 
   // write order is important because an individual write step
   // might tag an artifact to be written in a subsequent step
   write_klass_constants(writer, leakp_writer);
-  if (_artifacts->has_klass_entries()) {
-    write_package_constants(writer, leakp_writer);
-    write_module_constants(writer, leakp_writer);
-    write_class_loader_constants(writer, leakp_writer);
-    write_method_constants(writer, leakp_writer);
-    write_symbol_constants(writer, leakp_writer);
+  if (!_artifacts->has_klass_entries()) {
+    return 0;
+  }
+  write_package_constants(writer, leakp_writer);
+  write_module_constants(writer, leakp_writer);
+  write_class_loader_constants(writer, leakp_writer);
+  write_method_constants(writer, leakp_writer);
+  write_symbol_constants(writer, leakp_writer);
+  const size_t total_count = _artifacts->total_count();
+  if (!flushpoint) {
     clear_artifacts(_artifacts, class_unload);
   }
+  return total_count;
 }
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.hpp	Fri May 17 16:02:27 2019 +0200
@@ -44,6 +44,10 @@
   static JfrArtifactSet* _artifacts;
   static JfrArtifactClosure* _subsystem_callback;
   static bool _class_unload;
+  static bool _flushpoint;
+  static bool is_rotating();
+  static bool is_not_rotating();
+  static bool current_epoch();
 
   static void do_klass(Klass* k);
   static void do_unloaded_klass(Klass* k);
@@ -67,7 +71,7 @@
   static void write_class_loader_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer);
   static void write_method_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer);
   static void write_symbol_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer);
-  static void serialize(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer, bool class_unload);
+  static size_t serialize(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer, bool class_unload, bool flushpoint);
 };
 
 #endif // SHARE_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESET_HPP
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -196,20 +196,22 @@
   return (uintptr_t)const_cast<Symbol*>(sym)->identity_hash();
 }
 
-JfrArtifactSet::JfrArtifactSet(bool class_unload) : _symbol_id(new JfrSymbolId()),
-                                                    _klass_list(NULL),
-                                                    _class_unload(class_unload) {
-  initialize(class_unload);
+JfrArtifactSet::JfrArtifactSet(bool current_epoch) : _symbol_id(new JfrSymbolId()),
+                                                     _klass_list(NULL),
+                                                     _total_count(0),
+                                                     _current_epoch(current_epoch) {
+  initialize(current_epoch);
   assert(_klass_list != NULL, "invariant");
 }
 
 static const size_t initial_class_list_size = 200;
-void JfrArtifactSet::initialize(bool class_unload) {
+void JfrArtifactSet::initialize(bool current_epoch) {
   assert(_symbol_id != NULL, "invariant");
   _symbol_id->initialize();
   assert(!_symbol_id->has_entries(), "invariant");
   _symbol_id->mark(BOOTSTRAP_LOADER_NAME, 0); // pre-load "bootstrap"
-  _class_unload = class_unload;
+  _total_count = 0;
+  _current_epoch = current_epoch;
   // resource allocation
   _klass_list = new GrowableArray<const Klass*>(initial_class_list_size, false, mtTracing);
 }
@@ -269,3 +271,8 @@
   assert(_klass_list->find(k) == -1, "invariant");
   _klass_list->append(k);
 }
+
+size_t JfrArtifactSet::total_count() const {
+  return _total_count;
+}
+
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp	Fri May 17 16:02:27 2019 +0200
@@ -76,9 +76,9 @@
 };
 
 template <typename T>
-void tag_leakp_artifact(T const& value, bool class_unload) {
+void tag_leakp_artifact(T const& value, bool current_epoch) {
   assert(value != NULL, "invariant");
-  if (class_unload) {
+  if (current_epoch) {
     SET_LEAKP_USED_THIS_EPOCH(value);
     assert(LEAKP_USED_THIS_EPOCH(value), "invariant");
   } else {
@@ -89,11 +89,11 @@
 
 template <typename T>
 class LeakpClearArtifact {
-  bool _class_unload;
+  bool _current_epoch;
  public:
-  LeakpClearArtifact(bool class_unload) : _class_unload(class_unload) {}
+  LeakpClearArtifact(bool current_epoch) : _current_epoch(current_epoch) {}
   bool operator()(T const& value) {
-    if (_class_unload) {
+    if (_current_epoch) {
       if (LEAKP_USED_THIS_EPOCH(value)) {
         LEAKP_UNUSE_THIS_EPOCH(value);
       }
@@ -107,50 +107,65 @@
 };
 
 template <typename T>
+class UnTagArtifact {
+ public:
+  UnTagArtifact() {}
+  bool operator()(T const& value) {
+    if (LEAKP_USED_PREV_EPOCH(value)) {
+      LEAKP_UNUSE_PREV_EPOCH(value);
+    }
+    if (USED_PREV_EPOCH(value)) {
+      UNUSE_PREV_EPOCH(value);
+    }
+    return true;
+  }
+};
+
+template <typename T>
 class ClearArtifact {
-  bool _class_unload;
  public:
-  ClearArtifact(bool class_unload) : _class_unload(class_unload) {}
   bool operator()(T const& value) {
-    if (_class_unload) {
-      if (LEAKP_USED_THIS_EPOCH(value)) {
-        LEAKP_UNUSE_THIS_EPOCH(value);
-      }
-      if (USED_THIS_EPOCH(value)) {
-        UNUSE_THIS_EPOCH(value);
-      }
-      if (METHOD_USED_THIS_EPOCH(value)) {
-        UNUSE_METHOD_THIS_EPOCH(value);
-      }
-    } else {
-      if (LEAKP_USED_PREV_EPOCH(value)) {
-        LEAKP_UNUSE_PREV_EPOCH(value);
-      }
-      if (USED_PREV_EPOCH(value)) {
-        UNUSE_PREV_EPOCH(value);
-      }
-      if (METHOD_USED_PREV_EPOCH(value)) {
-        UNUSE_METHOD_PREV_EPOCH(value);
-      }
+    if (LEAKP_USED_PREV_EPOCH(value)) {
+      LEAKP_UNUSE_PREV_EPOCH(value);
+    }
+    if (USED_PREV_EPOCH(value)) {
+      UNUSE_PREV_EPOCH(value);
+    }
+    if (IS_SERIALIZED(value)) {
+      UNSERIALIZE(value);
     }
+    assert(IS_NOT_SERIALIZED(value), "invariant");
+    return true;
+  }
+};
+
+template <>
+class ClearArtifact<const Klass*> {
+ public:
+  bool operator()(const Klass* klass) {
+    if (LEAKP_USED_PREV_EPOCH(klass)) {
+      LEAKP_UNUSE_PREV_EPOCH(klass);
+    }
+    if (USED_PREV_EPOCH(klass)) {
+      UNUSE_PREV_EPOCH(klass);
+    }
+    if (METHOD_USED_PREV_EPOCH(klass)) {
+      UNUSE_METHOD_PREV_EPOCH(klass);
+    }
+    if (IS_SERIALIZED(klass)) {
+      UNSERIALIZE(klass);
+    }
+    assert(IS_NOT_SERIALIZED(klass), "invariant");
     return true;
   }
 };
 
 template <>
 class ClearArtifact<const Method*> {
-  bool _class_unload;
  public:
-  ClearArtifact(bool class_unload) : _class_unload(class_unload) {}
   bool operator()(const Method* method) {
-    if (_class_unload) {
-      if (METHOD_FLAG_USED_THIS_EPOCH(method)) {
-        CLEAR_METHOD_FLAG_USED_THIS_EPOCH(method);
-      }
-    } else {
-      if (METHOD_FLAG_USED_PREV_EPOCH(method)) {
-        CLEAR_METHOD_FLAG_USED_PREV_EPOCH(method);
-      }
+    if (METHOD_FLAG_USED_PREV_EPOCH(method)) {
+      CLEAR_METHOD_FLAG_USED_PREV_EPOCH(method);
     }
     return true;
   }
@@ -158,21 +173,53 @@
 
 template <typename T>
 class LeakPredicate {
-  bool _class_unload;
+  bool _current_epoch;
  public:
-  LeakPredicate(bool class_unload) : _class_unload(class_unload) {}
+  LeakPredicate(bool current_epoch) : _current_epoch(current_epoch) {}
   bool operator()(T const& value) {
-    return _class_unload ? LEAKP_USED_THIS_EPOCH(value) : LEAKP_USED_PREV_EPOCH(value);
+    return _current_epoch ? LEAKP_USED_THIS_EPOCH(value) : LEAKP_USED_PREV_EPOCH(value);
+  }
+};
+
+template <typename T>
+class LeakSerializePredicate {
+  LeakPredicate<T> _leak_predicate;
+ public:
+  LeakSerializePredicate(bool current_epoch) : _leak_predicate(current_epoch) {}
+  bool operator()(T const& value) {
+    return IS_NOT_LEAKP_SERIALIZED(value) && _leak_predicate(value);
   }
 };
 
 template <typename T>
 class UsedPredicate {
-  bool _class_unload;
+  bool _current_epoch;
+ public:
+  UsedPredicate(bool current_epoch) : _current_epoch(current_epoch) {}
+  bool operator()(T const& value) {
+    return _current_epoch ? USED_THIS_EPOCH(value) : USED_PREV_EPOCH(value);
+  }
+};
+
+template <typename T>
+class SerializePredicate {
+  bool _current_epoch;
  public:
-  UsedPredicate(bool class_unload) : _class_unload(class_unload) {}
+  SerializePredicate(bool current_epoch) : _current_epoch(current_epoch) {}
   bool operator()(T const& value) {
-    return _class_unload ? USED_THIS_EPOCH(value) : USED_PREV_EPOCH(value);
+    assert(value != NULL, "invariant");
+    return IS_NOT_SERIALIZED(value);
+  }
+};
+
+template <>
+class SerializePredicate<const Method*> {
+  bool _current_epoch;
+public:
+  SerializePredicate(bool current_epoch) : _current_epoch(current_epoch) {}
+  bool operator()(const Method* method) {
+    assert(method != NULL, "invariant");
+    return METHOD_NOT_SERIALIZED(method);
   }
 };
 
@@ -194,22 +241,22 @@
 };
 
 class MethodFlagPredicate {
-  bool _class_unload;
+  bool _current_epoch;
  public:
-  MethodFlagPredicate(bool class_unload) : _class_unload(class_unload) {}
+  MethodFlagPredicate(bool current_epoch) : _current_epoch(current_epoch) {}
   bool operator()(const Method* method) {
-    return _class_unload ? METHOD_FLAG_USED_THIS_EPOCH(method) : METHOD_FLAG_USED_PREV_EPOCH(method);
+    return _current_epoch ? METHOD_FLAG_USED_THIS_EPOCH(method) : METHOD_FLAG_USED_PREV_EPOCH(method);
   }
 };
 
 template <bool leakp>
 class MethodUsedPredicate {
-  bool _class_unload;
+  bool _current_epoch;
  public:
-  MethodUsedPredicate(bool class_unload) : _class_unload(class_unload) {}
+  MethodUsedPredicate(bool current_epoch) : _current_epoch(current_epoch) {}
   bool operator()(const Klass* klass) {
     assert(ANY_USED(klass), "invariant");
-    if (_class_unload) {
+    if (_current_epoch) {
       return leakp ? LEAKP_METHOD_USED_THIS_EPOCH(klass) : METHOD_USED_THIS_EPOCH(klass);
     }
     return leakp ? LEAKP_METHOD_USED_PREV_EPOCH(klass) : METHOD_USED_PREV_EPOCH(klass);
@@ -313,14 +360,15 @@
  private:
   JfrSymbolId* _symbol_id;
   GrowableArray<const Klass*>* _klass_list;
-  bool _class_unload;
+  size_t _total_count;
+  bool _current_epoch;
 
  public:
-  JfrArtifactSet(bool class_unload);
+  JfrArtifactSet(bool current_epoch);
   ~JfrArtifactSet();
 
   // caller needs ResourceMark
-  void initialize(bool class_unload);
+  void initialize(bool current_epoch);
   void clear();
 
   traceid mark(const Symbol* sym, uintptr_t hash);
@@ -334,7 +382,9 @@
   const JfrSymbolId::CStringEntry* map_cstring(uintptr_t hash) const;
 
   bool has_klass_entries() const;
+  bool current_epoch() const { return _current_epoch; }
   int entries() const;
+  size_t total_count() const;
   void register_klass(const Klass* k);
 
   template <typename Functor>
@@ -355,6 +405,12 @@
   void iterate_cstrings(T& functor) {
     _symbol_id->iterate_cstrings(functor);
   }
+
+  template <typename Writer>
+  void tally(Writer& writer) {
+    _total_count += writer.count();
+  }
+
 };
 
 class KlassArtifactRegistrator {
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetWriter.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetWriter.hpp	Fri May 17 16:02:27 2019 +0200
@@ -41,8 +41,8 @@
  public:
   JfrArtifactWriterHost(JfrCheckpointWriter* writer,
                         JfrArtifactSet* artifacts,
-                        bool class_unload,
-                        bool skip_header = false) : _impl(writer, artifacts, class_unload),
+                        bool current_epoch,
+                        bool skip_header = false) : _impl(writer, artifacts, current_epoch),
                                                     _writer(writer),
                                                     _ctx(writer->context()),
                                                     _count(0),
@@ -82,11 +82,11 @@
  private:
   JfrCheckpointWriter* _writer;
   JfrArtifactSet* _artifacts;
-  bool _class_unload;
+  bool _current_epoch;
  public:
   typedef T Type;
-  JfrArtifactWriterImplHost(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, bool class_unload) :
-    _writer(writer), _artifacts(artifacts), _class_unload(class_unload) {}
+  JfrArtifactWriterImplHost(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, bool current_epoch) :
+    _writer(writer), _artifacts(artifacts), _current_epoch(current_epoch) {}
   int operator()(T const& value) {
     return op(this->_writer, this->_artifacts, value);
   }
@@ -98,8 +98,8 @@
   Predicate _predicate;
   typedef JfrArtifactWriterImplHost<T, op> Parent;
  public:
-  JfrPredicatedArtifactWriterImplHost(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, bool class_unload) :
-    Parent(writer, artifacts, class_unload), _predicate(class_unload) {}
+  JfrPredicatedArtifactWriterImplHost(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, bool current_epoch) :
+    Parent(writer, artifacts, current_epoch), _predicate(current_epoch) {}
   int operator()(T const& value) {
     return _predicate(value) ? Parent::operator()(value) : 0;
   }
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdBits.inline.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdBits.inline.hpp	Fri May 17 16:02:27 2019 +0200
@@ -40,17 +40,11 @@
 
 inline void set_bits(jbyte bits, jbyte* const dest) {
   assert(dest != NULL, "invariant");
-  const jbyte current = OrderAccess::load_acquire(dest);
+  const jbyte current = *dest;
   if (bits != (current & bits)) {
-    *dest |= bits;
-  }
-}
+    *dest = current | bits;
 
-inline void set_mask(jbyte mask, jbyte* const dest) {
-  assert(dest != NULL, "invariant");
-  const jbyte current = OrderAccess::load_acquire(dest);
-  if (mask != (current & mask)) {
-    *dest &= mask;
+    OrderAccess::storestore();
   }
 }
 
@@ -82,6 +76,27 @@
   } while (true);
 }
 
+inline void set_mask(jbyte mask, jbyte* const dest) {
+  assert(dest != NULL, "invariant");
+  const jbyte current = *dest;
+  if (mask != (current & mask)) {
+    *dest = current & mask;
+    OrderAccess::storestore();
+  }
+}
+inline void set_mask_cas(jbyte mask, jbyte* const dest) {
+  assert(dest != NULL, "invariant");
+  do {
+    const jbyte current = OrderAccess::load_acquire(dest);
+    if (mask == (current & mask)) {
+      return;
+    }
+    const jbyte new_value = current & mask;
+    if (Atomic::cmpxchg(new_value, dest, current) == current) {
+      return;
+    }
+  } while (true);
+}
 inline void set_traceid_bits(jbyte bits, traceid* dest) {
   set_bits(bits, ((jbyte*)dest) + low_offset);
 }
@@ -103,7 +118,7 @@
 }
 
 inline void set_leakp_traceid_mask(jbyte mask, traceid* dest) {
-  set_mask(mask, ((jbyte*)dest) + leakp_offset);
+  set_mask_cas(mask, ((jbyte*)dest) + leakp_offset);
 }
 
 #endif // SHARE_JFR_RECORDER_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDBITS_INLINE_HPP
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp	Fri May 17 16:02:27 2019 +0200
@@ -32,12 +32,19 @@
 #define METHOD_USED_BIT (USED_BIT << 2)
 #define EPOCH_1_SHIFT 0
 #define EPOCH_2_SHIFT 1
+#define SERIALIZED_SHIFT 2
+#define LEAKP_SERIALIZED_SHIFT 3
 #define LEAKP_SHIFT 8
 
 #define USED_EPOCH_1_BIT (USED_BIT << EPOCH_1_SHIFT)
 #define USED_EPOCH_2_BIT (USED_BIT << EPOCH_2_SHIFT)
 #define LEAKP_USED_EPOCH_1_BIT (USED_EPOCH_1_BIT << LEAKP_SHIFT)
 #define LEAKP_USED_EPOCH_2_BIT (USED_EPOCH_2_BIT << LEAKP_SHIFT)
+#define SERIALIZED_BIT (USED_BIT << SERIALIZED_SHIFT)
+#define SERIALIZED_TEST_BIT (SERIALIZED_BIT << LEAKP_SHIFT)
+#define LEAKP_SERIALIZED_BIT (USED_BIT << LEAKP_SERIALIZED_SHIFT)
+#define LEAKP_SERIALIZED_TEST_BIT (LEAKP_SERIALIZED_BIT << LEAKP_SHIFT)
+#define METHOD_LEAKP_SERIALIZED_BIT ((USED_BIT << LEAKP_SERIALIZED_SHIFT))
 #define METHOD_USED_EPOCH_1_BIT (METHOD_USED_BIT << EPOCH_1_SHIFT)
 #define METHOD_USED_EPOCH_2_BIT (METHOD_USED_BIT << EPOCH_2_SHIFT)
 #define METHOD_AND_CLASS_IN_USE_BITS (METHOD_USED_BIT | USED_BIT)
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp	Fri May 17 16:02:27 2019 +0200
@@ -48,17 +48,24 @@
 // #define JDK_JFR_EVENT_SUBKLASS  16
 // #define JDK_JFR_EVENT_KLASS     32
 // #define EVENT_HOST_KLASS        64
+// #define EVENT_RESERVED          128
 
 #define IS_JDK_JFR_EVENT_SUBKLASS(ptr) (((ptr)->trace_id() & (JDK_JFR_EVENT_SUBKLASS)) != 0)
 
+#define IS_SERIALIZED(ptr)        (((ptr)->trace_id() & (SERIALIZED_TEST_BIT)) != 0)
+#define IS_NOT_SERIALIZED(ptr)    (!IS_SERIALIZED(ptr))
+#define IS_LEAKP_SERIALIZED(ptr)  (((ptr)->trace_id() & (LEAKP_SERIALIZED_TEST_BIT)) != 0)
+#define IS_NOT_LEAKP_SERIALIZED(ptr) (!IS_LEAKP_SERIALIZED(ptr))
 #define ANY_USED_BITS (USED_EPOCH_2_BIT         | \
                        USED_EPOCH_1_BIT         | \
                        METHOD_USED_EPOCH_2_BIT  | \
                        METHOD_USED_EPOCH_1_BIT  | \
+                       LEAKP_USED_EPOCH_1_BIT    | \
                        LEAKP_USED_EPOCH_2_BIT   | \
-                       LEAKP_USED_EPOCH_1_BIT)
+                       SERIALIZED_TEST_BIT       | \
+                       LEAKP_SERIALIZED_TEST_BIT)
 
-#define TRACE_ID_META_BITS (EVENT_HOST_KLASS | JDK_JFR_EVENT_KLASS | JDK_JFR_EVENT_SUBKLASS | ANY_USED_BITS)
+#define TRACE_ID_META_BITS (EVENT_RESERVED | EVENT_HOST_KLASS | JDK_JFR_EVENT_KLASS | JDK_JFR_EVENT_SUBKLASS | ANY_USED_BITS)
 
 #define ANY_EVENT                       (EVENT_HOST_KLASS | JDK_JFR_EVENT_KLASS | JDK_JFR_EVENT_SUBKLASS)
 #define IS_JDK_JFR_EVENT_KLASS(ptr)     (((ptr)->trace_id() & JDK_JFR_EVENT_KLASS) != 0)
@@ -76,13 +83,17 @@
 #define TRACE_ID_MASKED_PTR(ptr)        (TRACE_ID_MASKED((ptr)->trace_id()))
 #define TRACE_ID_RAW(ptr)               ((ptr)->trace_id())
 #define TRACE_ID(ptr)                   (TRACE_ID_MASKED_PTR(ptr) >> TRACE_ID_SHIFT)
-#define METHOD_ID(kls, meth)            (TRACE_ID_MASKED_PTR(kls) | (meth)->method_idnum())
+#define METHOD_ID(kls, meth)            (TRACE_ID_MASKED_PTR(kls) | (meth)->orig_method_idnum())
 #define SET_TAG(ptr, tag)               (set_traceid_bits(tag, (ptr)->trace_id_addr()))
-#define SET_LEAKP_TAG(ptr, tag)         (set_leakp_traceid_bits(tag, (ptr)->trace_id_addr()))
 #define SET_TAG_CAS(ptr, tag)           (set_traceid_bits_cas(tag, (ptr)->trace_id_addr()))
 #define SET_LEAKP_TAG_CAS(ptr, tag)     (set_leakp_traceid_bits_cas(tag, (ptr)->trace_id_addr()))
+#define SET_LEAKP_TAG(ptr, tag)         (SET_LEAKP_TAG_CAS(ptr, tag))
 
+#define SET_SERIALIZED(ptr)             (set_leakp_traceid_bits_cas((jbyte)SERIALIZED_BIT, (ptr)->trace_id_addr()))
+#define SET_LEAKP_SERIALIZED(ptr)       (set_leakp_traceid_bits_cas((jbyte)LEAKP_SERIALIZED_BIT, (ptr)->trace_id_addr()))
+#define UNSERIALIZE_MASK                (~(SERIALIZED_BIT | LEAKP_SERIALIZED_BIT))
 #define IN_USE_THIS_EPOCH_BIT           (JfrTraceIdEpoch::in_use_this_epoch_bit())
+#define IN_USE_THIS_EPOCH_UNSERIALIZED_BIT (IN_USE_THIS_EPOCH_BIT | SERIALIZED_TEST_BIT)
 #define IN_USE_PREV_EPOCH_BIT           (JfrTraceIdEpoch::in_use_prev_epoch_bit())
 #define LEAKP_IN_USE_THIS_EPOCH_BIT     (JfrTraceIdEpoch::leakp_in_use_this_epoch_bit())
 #define LEAKP_IN_USE_PREV_EPOCH_BIT     (JfrTraceIdEpoch::leakp_in_use_prev_epoch_bit())
@@ -107,13 +118,15 @@
 
 #define SET_USED_THIS_EPOCH(ptr)        (SET_TAG(ptr, IN_USE_THIS_EPOCH_BIT))
 #define SET_USED_PREV_EPOCH(ptr)        (SET_TAG_CAS(ptr, IN_USE_PREV_EPOCH_BIT))
-#define SET_LEAKP_USED_THIS_EPOCH(ptr)  (SET_LEAKP_TAG(ptr, IN_USE_THIS_EPOCH_BIT))
-#define SET_LEAKP_USED_PREV_EPOCH(ptr)  (SET_LEAKP_TAG(ptr, IN_USE_PREV_EPOCH_BIT))
+#define SET_LEAKP_USED_THIS_EPOCH(ptr)  (SET_LEAKP_TAG_CAS(ptr, IN_USE_THIS_EPOCH_BIT))
+#define SET_LEAKP_USED_PREV_EPOCH(ptr)  (SET_LEAKP_TAG_CAS(ptr, IN_USE_PREV_EPOCH_BIT))
 #define SET_METHOD_AND_CLASS_USED_THIS_EPOCH(kls) (SET_TAG(kls, METHOD_AND_CLASS_IN_USE_THIS_EPOCH_BITS))
 
 #define USED_THIS_EPOCH(ptr)            (((ptr)->trace_id() & IN_USE_THIS_EPOCH_BIT) != 0)
+#define USED_THIS_EPOCH_UNSERIALIZED(ptr) ((USED_THIS_EPOCH(ptr)) && (IS_NOT_SERIALIZED(ptr)))
 #define NOT_USED_THIS_EPOCH(ptr)        (!USED_THIS_EPOCH(ptr))
 #define USED_PREV_EPOCH(ptr)            (((ptr)->trace_id() & IN_USE_PREV_EPOCH_BIT) != 0)
+#define USED_PREV_EPOCH_UNSERIALIZED(ptr) ((USED_PREV_EPOCH(ptr)) && (IS_NOT_SERIALIZED(ptr)))
 #define NOT_USED_PREV_EPOCH(ptr)        (!USED_PREV_EPOCH(ptr))
 #define USED_ANY_EPOCH(ptr)             (((ptr)->trace_id() & (USED_EPOCH_2_BIT | USED_EPOCH_1_BIT)) != 0)
 #define NOT_USED_ANY_EPOCH(ptr)         (!USED_ANY_EPOCH(ptr))
@@ -126,8 +139,10 @@
 #define LEAKP_NOT_USED_ANY_EPOCH(ptr)   (!LEAKP_USED_ANY_EPOCH(ptr))
 
 #define ANY_USED_THIS_EPOCH(ptr)        (((ptr)->trace_id() & (LEAKP_IN_USE_THIS_EPOCH_BIT | IN_USE_THIS_EPOCH_BIT)) != 0)
+#define ANY_USED_THIS_EPOCH_UNSERIALIZED(ptr) ((ANY_USED_THIS_EPOCH(ptr)) && (IS_NOT_SERIALIZED(ptr)))
 #define ANY_NOT_USED_THIS_EPOCH(ptr)    (!ANY_USED_THIS_EPOCH(ptr))
 #define ANY_USED_PREV_EPOCH(ptr)        (((ptr)->trace_id() & (LEAKP_IN_USE_PREV_EPOCH_BIT | IN_USE_PREV_EPOCH_BIT)) != 0)
+#define ANY_USED_PREV_EPOCH_UNSERIALIZED(ptr) ((ANY_USED_PREV_EPOCH(ptr)) && (IS_NOT_SERIALIZED(ptr)))
 #define ANY_NOT_USED_PREV_EPOCH(ptr)    (!ANY_USED_PREV_EPOCH(ptr))
 
 #define METHOD_USED_THIS_EPOCH(kls)     (((kls)->trace_id() & METHOD_IN_USE_THIS_EPOCH_BIT) != 0)
@@ -166,6 +181,7 @@
 #define LEAKP_UNUSE_METHOD_THIS_EPOCH(kls) (set_leakp_traceid_mask(UNUSE_METHOD_THIS_EPOCH_MASK, (kls)->trace_id_addr()))
 #define LEAKP_UNUSE_METHOD_PREV_EPOCH(kls) (set_leakp_traceid_mask(UNUSE_METHOD_PREV_EPOCH_MASK, (kls)->trace_id_addr()))
 
+#define UNSERIALIZE(ptr)                (set_leakp_traceid_mask(UNSERIALIZE_MASK, (ptr)->trace_id_addr()))
 #define ANY_USED(ptr)                   (((ptr)->trace_id() & ANY_USED_BITS) != 0)
 #define ANY_NOT_USED(ptr)               (!ANY_USED(ptr))
 
@@ -174,14 +190,22 @@
 #define UNUSE_METHOD_AND_CLASS_PREV_EPOCH(kls) (set_traceid_mask(UNUSE_METHOD_AND_CLASS_PREV_EPOCH_MASK, (kls)->trace_id_addr()))
 #define LEAKP_UNUSE_METHODS_AND_CLASS_PREV_EPOCH(kls) (set_leakp_traceid_mask(UNUSE_METHOD_AND_CLASS_PREV_EPOCH_MASK, (kls)->trace_id_addr()))
 
+#define IS_METHOD_SERIALIZED(m)              ((m)->is_trace_flag_set((jbyte)SERIALIZED_BIT))
+#define METHOD_NOT_SERIALIZED(m)             (!IS_METHOD_SERIALIZED(m))
+#define SET_METHOD_SERIALIZED(m)             (set_bits_cas((jbyte)SERIALIZED_BIT, (m)->trace_flags_addr()))
+#define UNSERIALIZE_METHOD(m)                (clear_bits_cas((jbyte)SERIALIZED_BIT, (m)->trace_flags_addr()))
+#define IS_LEAKP_METHOD_SERIALIZED(m)        ((m)->is_trace_flag_set((jbyte)LEAKP_SERIALIZED_BIT))
+#define METHOD_NOT_LEAKP_SERIALIZED(m)       (!IS_LEAKP_METHOD_SERIALIZED(m))
+#define SET_LEAKP_METHOD_SERIALIZED(m)       (set_bits_cas((jbyte)LEAKP_SERIALIZED_BIT, (m)->trace_flags_addr()))
+#define UNSERIALIZE_LEAKP_METHOD(m)          (clear_bits_cas((jbyte)LEAKP_SERIALIZED_BIT, (m)->trace_flags_addr()))
 #define METHOD_FLAG_USED_THIS_EPOCH(m)       ((m)->is_trace_flag_set((jbyte)JfrTraceIdEpoch::in_use_this_epoch_bit()))
 #define METHOD_FLAG_NOT_USED_THIS_EPOCH(m)   (!METHOD_FLAG_USED_THIS_EPOCH(m))
-#define SET_METHOD_FLAG_USED_THIS_EPOCH(m)   ((m)->set_trace_flag((jbyte)JfrTraceIdEpoch::in_use_this_epoch_bit()))
+#define SET_METHOD_FLAG_USED_THIS_EPOCH(m)   (set_bits_cas((jbyte)JfrTraceIdEpoch::in_use_this_epoch_bit(), (m)->trace_flags_addr()))
 #define METHOD_FLAG_USED_PREV_EPOCH(m)       ((m)->is_trace_flag_set((jbyte)JfrTraceIdEpoch::in_use_prev_epoch_bit()))
 #define METHOD_FLAG_NOT_USED_PREV_EPOCH(m)   (!METHOD_FLAG_USED_PREV_EPOCH(m))
 #define METHOD_FLAG_USED_ANY_EPOCH(m)        ((METHOD_FLAG_USED_THIS_EPOCH(m) || METHOD_FLAG_USED_PREV_EPOCH(m)) != 0)
 #define METHOD_FLAG_NOT_USED_ANY_EPOCH(m)    ((METHOD_FLAG_NOT_USED_THIS_EPOCH(m) && METHOD_FLAG_NOT_USED_PREV_EPOCH(m)) != 0)
-#define CLEAR_METHOD_FLAG_USED_THIS_EPOCH(m) (clear_bits_cas((jbyte)JfrTraceIdEpoch::in_use_this_epoch_bit(), (m)->trace_flags_addr()))
-#define CLEAR_METHOD_FLAG_USED_PREV_EPOCH(m) (clear_bits_cas((jbyte)JfrTraceIdEpoch::in_use_prev_epoch_bit(), (m)->trace_flags_addr()))
+#define CLEAR_METHOD_FLAG_USED_THIS_EPOCH(m) (clear_bits_cas((jbyte)JfrTraceIdEpoch::in_use_this_epoch_bit() | SERIALIZED_BIT, (m)->trace_flags_addr()))
+#define CLEAR_METHOD_FLAG_USED_PREV_EPOCH(m) (clear_bits_cas((jbyte)JfrTraceIdEpoch::in_use_prev_epoch_bit() | SERIALIZED_BIT, (m)->trace_flags_addr()))
 
 #endif // SHARE_JFR_RECORDER_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDMACROS_HPP
--- a/src/hotspot/share/jfr/recorder/repository/jfrChunkWriter.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/repository/jfrChunkWriter.cpp	Fri May 17 16:02:27 2019 +0200
@@ -23,10 +23,11 @@
  */
 
 #include "precompiled.hpp"
-#include "jfr/recorder/repository/jfrChunkState.hpp"
+#include "jfr/recorder/repository/jfrChunk.hpp"
 #include "jfr/recorder/repository/jfrChunkWriter.hpp"
 #include "jfr/recorder/service/jfrOptionSet.hpp"
 #include "jfr/utilities/jfrTime.hpp"
+#include "jfr/utilities/jfrTimeConverter.hpp"
 #include "jfr/utilities/jfrTypes.hpp"
 #include "runtime/mutexLocker.hpp"
 #include "runtime/os.hpp"
@@ -34,85 +35,245 @@
 
 static const u2 JFR_VERSION_MAJOR = 2;
 static const u2 JFR_VERSION_MINOR = 0;
-static const size_t MAGIC_LEN = 4;
-static const size_t FILEHEADER_SLOT_SIZE = 8;
-static const size_t CHUNK_SIZE_OFFSET = 8;
-
-JfrChunkWriter::JfrChunkWriter() : JfrChunkWriterBase(NULL), _chunkstate(NULL) {}
 
-bool JfrChunkWriter::initialize() {
-  assert(_chunkstate == NULL, "invariant");
-  _chunkstate = new JfrChunkState();
-  return _chunkstate != NULL;
-}
+static const int64_t MAGIC_OFFSET = 0;
+static const int64_t MAGIC_LEN = 4;
+static const int64_t VERSION_OFFSET = MAGIC_LEN;
+static const int64_t SIZE_OFFSET = 8;
+static const int64_t SLOT_SIZE = 8;
+static const int64_t CHECKPOINT_OFFSET = SIZE_OFFSET + SLOT_SIZE;
+static const int64_t METADATA_OFFSET = CHECKPOINT_OFFSET + SLOT_SIZE;
+static const int64_t START_NANOS_OFFSET = METADATA_OFFSET + SLOT_SIZE;
+static const int64_t DURATION_NANOS_OFFSET = START_NANOS_OFFSET + SLOT_SIZE;
+static const int64_t START_TICKS_OFFSET = DURATION_NANOS_OFFSET + SLOT_SIZE;
+static const int64_t CPU_FREQUENCY_OFFSET = START_TICKS_OFFSET + SLOT_SIZE;
+static const int64_t GENERATION_OFFSET = CPU_FREQUENCY_OFFSET + SLOT_SIZE;
+static const int64_t CAPABILITY_OFFSET = GENERATION_OFFSET + 2;
+static const int64_t HEADER_SIZE = CAPABILITY_OFFSET + 2;
+static const int64_t RESERVE_SIZE = GENERATION_OFFSET - (4 * SIZE_OFFSET);
+static const int64_t VOLATILE_FIELD_SIZE = SLOT_SIZE * 2;
+
+static const u1 COMPLETE = 0;
+static const u1 GUARD = 0xff;
+static const u1 PAD = 0;
+static const size_t GENERATION_SIZE = sizeof(u2);
+static const size_t HEAD_BUFFER_SIZE = HEADER_SIZE + SLOT_SIZE;
+
+typedef NoOwnershipAdapter JfrHeadBuffer; // stack local array as buffer
+typedef StreamWriterHost<JfrHeadBuffer, StackObj> JfrBufferedHeadWriter;
+typedef WriterHost<BigEndianEncoder, BigEndianEncoder, JfrBufferedHeadWriter> JfrHeadWriterBase;
+
+static uint8_t head_buffer[HEAD_BUFFER_SIZE] = {0};
 
 static fio_fd open_chunk(const char* path) {
-  assert(JfrStream_lock->owned_by_self(), "invariant");
   return path != NULL ? os::open(path, O_CREAT | O_RDWR, S_IREAD | S_IWRITE) : invalid_fd;
 }
 
-bool JfrChunkWriter::open() {
-  assert(_chunkstate != NULL, "invariant");
-  JfrChunkWriterBase::reset(open_chunk(_chunkstate->path()));
-  const bool is_open = this->has_valid_fd();
-  if (is_open) {
-    this->bytes("FLR", MAGIC_LEN);
-    this->be_write((u2)JFR_VERSION_MAJOR);
-    this->be_write((u2)JFR_VERSION_MINOR);
-    this->reserve(6 * FILEHEADER_SLOT_SIZE);
-    // u8 chunk_size
-    // u8 initial checkpoint offset
-    // u8 metadata section offset
-    // u8 chunk start nanos
-    // u8 chunk duration nanos
-    // u8 chunk start ticks
-    this->be_write(JfrTime::frequency());
+class JfrChunkHeadWriter : public StackObj {
+  friend class JfrChunkWriter;
+ private:
+  JfrChunkWriter* _writer;
+  JfrChunk* _chunk;
+
+  void write_magic() {
+    assert(MAGIC_OFFSET == _writer->current_offset(), "invariant");
+    _writer->bytes("FLR", MAGIC_LEN);
+  }
+
+  void write_version() {
+    assert(VERSION_OFFSET == _writer->current_offset(), "invariant");
+    _writer->be_write((u2)JFR_VERSION_MAJOR);
+    _writer->be_write((u2)JFR_VERSION_MINOR);
+  }
+
+  void write_size(int64_t size) {
+    assert(SIZE_OFFSET == _writer->current_offset(), "invariant");
+    _writer->be_write(size);
+  }
+
+  void write_checkpoint() {
+    assert(CHECKPOINT_OFFSET == _writer->current_offset(), "invariant");
+    _writer->be_write(_chunk->last_checkpoint_offset());
+  }
+
+  void write_metadata() {
+    assert(METADATA_OFFSET == _writer->current_offset(), "invariant");
+    _writer->be_write(_chunk->last_metadata_offset());
+  }
+
+  void write_time(bool finalize) {
+    assert(_writer->is_valid(), "invariant");
+    assert(_chunk != NULL, "invariant");
+    assert(START_NANOS_OFFSET == _writer->current_offset(), "invariant");
+    if (finalize) {
+      _writer->be_write(_chunk->previous_start_nanos());
+      _writer->be_write(_chunk->last_chunk_duration());
+      _writer->be_write(_chunk->previous_start_ticks());
+      return;
+    }
+    _writer->be_write(_chunk->start_nanos());
+    _writer->be_write(_chunk->duration());
+    _writer->be_write(_chunk->start_ticks());
+  }
+
+  void write_cpu_frequency() {
+    assert(CPU_FREQUENCY_OFFSET == _writer->current_offset(), "invariant");
+    static const jlong frequency = JfrTime::frequency();
+    _writer->be_write(frequency);
+  }
+
+  void write_capabilities() {
+    assert(CAPABILITY_OFFSET == _writer->current_offset(), "invariant");
     // chunk capabilities, CompressedIntegers etc
-    this->be_write((u4)JfrOptionSet::compressed_integers() ? 1 : 0);
-    _chunkstate->reset();
+    static bool compressed_integers = JfrOptionSet::compressed_integers();
+    _writer->be_write(compressed_integers ? (u2)1 : (u2)0);
+  }
+
+  void write_generation(bool finalize) {
+    assert(GENERATION_OFFSET == _writer->current_offset(), "invariant");
+    _writer->be_write(finalize ? COMPLETE : _chunk->generation());
+    _writer->be_write(PAD);
+  }
+
+  void write_guard() {
+    assert(GENERATION_OFFSET == _writer->current_offset(), "invariant");
+    _writer->be_write(GUARD);
+    _writer->be_write(PAD);
+  }
+
+  void write_guard_flush() {
+    assert(GENERATION_OFFSET == _writer->current_offset(), "invariant");
+    write_guard();
+    _writer->flush();
   }
-  return is_open;
+
+  void initialize() {
+    assert(_writer->is_valid(), "invariant");
+    assert(_chunk != NULL, "invariant");
+    assert(0 == _writer->current_offset(), "invariant");
+    write_magic();
+    write_version();
+    write_size(HEADER_SIZE);
+    write_checkpoint();
+    write_metadata();
+    write_time(false);
+    write_cpu_frequency();
+    write_generation(false);
+    write_capabilities();
+    assert(HEADER_SIZE == _writer->current_offset(), "invariant");
+    _writer->flush();
+  }
+
+  void flush(int64_t size, bool finalize) {
+    assert(_writer->is_valid(), "invariant");
+    assert(_chunk != NULL, "invariant");
+    assert(SIZE_OFFSET == _writer->current_offset(), "invariant");
+    write_size(size);
+    write_checkpoint();
+    write_metadata();
+    write_time(finalize);
+    write_cpu_frequency();
+    write_generation(finalize);
+    // no need to write capabilities
+    _writer->seek(size); // implicit flush
+  }
+
+  JfrChunkHeadWriter(JfrChunkWriter* writer, int64_t offset) : _writer(writer), _chunk(writer->_chunk) {
+    assert(_writer != NULL, "invariant");
+    assert(_writer->is_valid(), "invariant");
+    assert(_chunk != NULL, "invariant");
+    if (0 == _writer->current_offset()) {
+      assert(HEADER_SIZE == offset, "invariant");
+      initialize();
+    } else {
+      _writer->seek(GENERATION_OFFSET);
+      write_guard();
+      _writer->seek(offset);
+    }
+    assert(offset == _writer->current_offset(), "invariant");
+  }
+};
+
+JfrChunkWriter::JfrChunkWriter() : JfrChunkWriterBase(NULL), _chunk(new JfrChunk()) {}
+
+JfrChunkWriter::~JfrChunkWriter() {
+  assert(_chunk != NULL, "invariant");
+  delete _chunk;
 }
 
-size_t JfrChunkWriter::close(int64_t metadata_offset) {
-  write_header(metadata_offset);
-  this->flush();
-  this->close_fd();
-  return (size_t)size_written();
+void JfrChunkWriter::set_path(const char* path) {
+  assert(_chunk != NULL, "invariant");
+  _chunk->set_path(path);
+}
+
+void JfrChunkWriter::time_stamp_chunk_now() {
+  assert(_chunk != NULL, "invariant");
+  _chunk->update_time_to_now();
 }
 
-void JfrChunkWriter::write_header(int64_t metadata_offset) {
-  assert(this->is_valid(), "invariant");
-  // Chunk size
-  this->write_be_at_offset(size_written(), CHUNK_SIZE_OFFSET);
-  // initial checkpoint event offset
-  this->write_be_at_offset(_chunkstate->previous_checkpoint_offset(), CHUNK_SIZE_OFFSET + (1 * FILEHEADER_SLOT_SIZE));
-  // metadata event offset
-  this->write_be_at_offset(metadata_offset, CHUNK_SIZE_OFFSET + (2 * FILEHEADER_SLOT_SIZE));
-  // start of chunk in nanos since epoch
-  this->write_be_at_offset(_chunkstate->previous_start_nanos(), CHUNK_SIZE_OFFSET + (3 * FILEHEADER_SLOT_SIZE));
-  // duration of chunk in nanos
-  this->write_be_at_offset(_chunkstate->last_chunk_duration(), CHUNK_SIZE_OFFSET + (4 * FILEHEADER_SLOT_SIZE));
-  // start of chunk in ticks
-  this->write_be_at_offset(_chunkstate->previous_start_ticks(), CHUNK_SIZE_OFFSET + (5 * FILEHEADER_SLOT_SIZE));
-}
-
-void JfrChunkWriter::set_chunk_path(const char* chunk_path) {
-  _chunkstate->set_path(chunk_path);
+int64_t JfrChunkWriter::flushpoint(bool finalize) {
+  assert(_chunk != NULL, "invariant");
+  const int64_t sz_written = size_written();
+  if (!finalize) {
+    _chunk->update();
+  }
+  JfrChunkHeadWriter head(this, SIZE_OFFSET);
+  head.flush(sz_written, finalize);
+  return sz_written;
 }
 
 int64_t JfrChunkWriter::size_written() const {
   return this->is_valid() ? this->current_offset() : 0;
 }
 
-int64_t JfrChunkWriter::previous_checkpoint_offset() const {
-  return _chunkstate->previous_checkpoint_offset();
+int64_t JfrChunkWriter::last_checkpoint_offset() const {
+  assert(_chunk != NULL, "invariant");
+  return _chunk->last_checkpoint_offset();
+}
+
+int64_t JfrChunkWriter::current_chunk_start_nanos() const {
+  assert(_chunk != NULL, "invariant");
+  return this->is_valid() ? _chunk->start_nanos() : invalid_time;
+}
+
+void JfrChunkWriter::set_last_checkpoint_offset(int64_t offset) {
+  assert(_chunk != NULL, "invariant");
+  _chunk->set_last_checkpoint_offset(offset);
+}
+
+bool JfrChunkWriter::is_initial_flushpoint_for_chunk() const {
+  assert(_chunk != NULL, "invariant");
+  assert(_chunk->is_started(), "invariant");
+  assert(!_chunk->is_finished(), "invariant");
+  return _chunk->is_initial_flush();
 }
 
-void JfrChunkWriter::set_previous_checkpoint_offset(int64_t offset) {
-  _chunkstate->set_previous_checkpoint_offset(offset);
+void JfrChunkWriter::set_last_metadata_offset(int64_t offset) {
+  assert(_chunk != NULL, "invariant");
+  _chunk->set_last_metadata_offset(offset);
+}
+
+bool JfrChunkWriter::has_metadata() const {
+  assert(_chunk != NULL, "invariant");
+  return _chunk->has_metadata();
 }
 
-void JfrChunkWriter::time_stamp_chunk_now() {
-  _chunkstate->update_time_to_now();
+bool JfrChunkWriter::open() {
+  assert(_chunk != NULL, "invariant");
+  JfrChunkWriterBase::reset(open_chunk(_chunk->path()));
+  const bool is_open = this->has_valid_fd();
+  if (is_open) {
+    assert(0 == this->current_offset(), "invariant");
+    _chunk->reset();
+    JfrChunkHeadWriter head(this, HEADER_SIZE);
+  }
+  return is_open;
 }
+
+int64_t JfrChunkWriter::close() {
+  assert(this->has_valid_fd(), "invariant");
+  const int64_t size_written = flushpoint(true);
+  this->close_fd();
+  assert(!this->is_valid(), "invariant");
+  return size_written;
+}
--- a/src/hotspot/share/jfr/recorder/repository/jfrChunkWriter.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/repository/jfrChunkWriter.hpp	Fri May 17 16:02:27 2019 +0200
@@ -29,28 +29,34 @@
 #include "jfr/writers/jfrStreamWriterHost.inline.hpp"
 #include "jfr/writers/jfrWriterHost.inline.hpp"
 
-typedef MallocAdapter<M> JfrStreamBuffer; // 1 mb buffered writes
-typedef StreamWriterHost<JfrStreamBuffer, JfrCHeapObj> JfrBufferedStreamWriter;
-typedef WriterHost<BigEndianEncoder, CompressedIntegerEncoder, JfrBufferedStreamWriter> JfrChunkWriterBase;
+typedef MallocAdapter<M> JfrChunkBuffer; // 1 mb buffered writes
+typedef StreamWriterHost<JfrChunkBuffer, JfrCHeapObj> JfrBufferedChunkWriter;
+typedef WriterHost<BigEndianEncoder, CompressedIntegerEncoder, JfrBufferedChunkWriter> JfrChunkWriterBase;
 
-class JfrChunkState;
+class JfrChunk;
+class JfrChunkHeadWriter;
 
 class JfrChunkWriter : public JfrChunkWriterBase {
+  friend class JfrChunkHeadWriter;
   friend class JfrRepository;
  private:
-  JfrChunkState* _chunkstate;
-
+  JfrChunk* _chunk;
+  void set_path(const char* path);
+  int64_t flushpoint(bool finalize);
   bool open();
-  size_t close(int64_t metadata_offset);
-  void write_header(int64_t metadata_offset);
-  void set_chunk_path(const char* chunk_path);
+  int64_t close();
+  int64_t current_chunk_start_nanos() const;
 
  public:
   JfrChunkWriter();
-  bool initialize();
+  ~JfrChunkWriter();
+
   int64_t size_written() const;
-  int64_t previous_checkpoint_offset() const;
-  void set_previous_checkpoint_offset(int64_t offset);
+  int64_t last_checkpoint_offset() const;
+  void set_last_checkpoint_offset(int64_t offset);
+  void set_last_metadata_offset(int64_t offset);
+  bool is_initial_flushpoint_for_chunk() const;
+  bool has_metadata() const;
   void time_stamp_chunk_now();
 };
 
--- a/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp	Fri May 17 16:02:27 2019 +0200
@@ -248,7 +248,6 @@
 }
 
 static const char* create_emergency_dump_path() {
-  assert(JfrStream_lock->owned_by_self(), "invariant");
   char* buffer = NEW_RESOURCE_ARRAY_RETURN_NULL(char, JVM_MAXPATHLEN);
   if (NULL == buffer) {
     return NULL;
@@ -291,7 +290,6 @@
 // Caller needs ResourceMark
 static const char* create_emergency_chunk_path(const char* repository_path) {
   assert(repository_path != NULL, "invariant");
-  assert(JfrStream_lock->owned_by_self(), "invariant");
   const size_t repository_path_len = strlen(repository_path);
   // date time
   char date_time_buffer[32] = { 0 };
@@ -312,7 +310,6 @@
 }
 
 static fio_fd emergency_dump_file_descriptor() {
-  assert(JfrStream_lock->owned_by_self(), "invariant");
   ResourceMark rm;
   const char* const emergency_dump_path = create_emergency_dump_path();
   return emergency_dump_path != NULL ? open_exclusivly(emergency_dump_path) : invalid_fd;
@@ -325,7 +322,7 @@
 void JfrEmergencyDump::on_vm_error(const char* repository_path) {
   assert(repository_path != NULL, "invariant");
   ResourceMark rm;
-  MutexLocker stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag);
+
   const fio_fd emergency_fd = emergency_dump_file_descriptor();
   if (emergency_fd != invalid_fd) {
     RepositoryIterator iterator(repository_path, strlen(repository_path));
@@ -409,10 +406,6 @@
     JfrBuffer_lock->unlock();
   }
 
-  if (JfrStream_lock->owned_by_self()) {
-    JfrStream_lock->unlock();
-  }
-
   if (JfrStacktrace_lock->owned_by_self()) {
     JfrStacktrace_lock->unlock();
   }
--- a/src/hotspot/share/jfr/recorder/repository/jfrRepository.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/repository/jfrRepository.cpp	Fri May 17 16:02:27 2019 +0200
@@ -26,13 +26,14 @@
 #include "jfr/jfr.hpp"
 #include "jfr/jni/jfrJavaSupport.hpp"
 #include "jfr/recorder/jfrRecorder.hpp"
-#include "jfr/recorder/repository/jfrChunkState.hpp"
 #include "jfr/recorder/repository/jfrChunkWriter.hpp"
 #include "jfr/recorder/repository/jfrEmergencyDump.hpp"
 #include "jfr/recorder/repository/jfrRepository.hpp"
 #include "jfr/recorder/service/jfrPostBox.hpp"
+#include "logging/log.hpp"
 #include "memory/resourceArea.hpp"
 #include "runtime/mutex.hpp"
+#include "runtime/os.hpp"
 #include "runtime/thread.inline.hpp"
 
 static JfrRepository* _instance = NULL;
@@ -43,11 +44,6 @@
 
 static JfrChunkWriter* _chunkwriter = NULL;
 
-static bool initialize_chunkwriter() {
-  assert(_chunkwriter == NULL, "invariant");
-  _chunkwriter = new JfrChunkWriter();
-  return _chunkwriter != NULL && _chunkwriter->initialize();
-}
 
 JfrChunkWriter& JfrRepository::chunkwriter() {
   return *_chunkwriter;
@@ -56,7 +52,9 @@
 JfrRepository::JfrRepository(JfrPostBox& post_box) : _path(NULL), _post_box(post_box) {}
 
 bool JfrRepository::initialize() {
-  return initialize_chunkwriter();
+  assert(_chunkwriter == NULL, "invariant");
+  _chunkwriter = new JfrChunkWriter();
+  return _chunkwriter != NULL;
 }
 
 JfrRepository::~JfrRepository() {
@@ -84,7 +82,7 @@
 }
 
 void JfrRepository::on_vm_error() {
-  assert(!JfrStream_lock->owned_by_self(), "invariant");
+
   if (_path == NULL) {
     // completed already
     return;
@@ -107,15 +105,19 @@
   return true;
 }
 
-void JfrRepository::set_chunk_path(const char* path) {
-  assert(JfrStream_lock->owned_by_self(), "invariant");
-  chunkwriter().set_chunk_path(path);
+void JfrRepository::notify_on_new_chunk_path() {
+  if (Jfr::is_recording()) {
+    // rotations are synchronous, block until rotation completes
+    instance()._post_box.post(MSG_ROTATE);
+  }
 }
 
-void JfrRepository::notify_on_new_chunk_path() {
-  if (Jfr::is_recording()) {
-    instance()._post_box.post(MSG_ROTATE);
-  }
+void JfrRepository::set_chunk_path(const char* path) {
+  chunkwriter().set_path(path);
+}
+
+jlong JfrRepository::current_chunk_start_nanos() {
+  return chunkwriter().current_chunk_start_nanos();
 }
 
 /**
@@ -134,14 +136,11 @@
   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt));
   ResourceMark rm(jt);
   const char* const canonical_chunk_path = JfrJavaSupport::c_str(path, jt);
-  {
-    MutexLocker stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag);
-    if (NULL == canonical_chunk_path && !_chunkwriter->is_valid()) {
-      // new output is NULL and current output is NULL
-      return;
-    }
-    instance().set_chunk_path(canonical_chunk_path);
+  if (NULL == canonical_chunk_path && !_chunkwriter->is_valid()) {
+    // new output is NULL and current output is NULL
+    return;
   }
+  instance().set_chunk_path(canonical_chunk_path);
   notify_on_new_chunk_path();
 }
 
@@ -155,14 +154,26 @@
 }
 
 bool JfrRepository::open_chunk(bool vm_error /* false */) {
-  assert(JfrStream_lock->owned_by_self(), "invariant");
   if (vm_error) {
     ResourceMark rm;
-    _chunkwriter->set_chunk_path(JfrEmergencyDump::build_dump_path(_path));
+    _chunkwriter->set_path(JfrEmergencyDump::build_dump_path(_path));
   }
   return _chunkwriter->open();
 }
 
-size_t JfrRepository::close_chunk(int64_t metadata_offset) {
-  return _chunkwriter->close(metadata_offset);
+size_t JfrRepository::close_chunk() {
+  return _chunkwriter->close();
 }
+
+void JfrRepository::flush(bool metadata, JavaThread* jt) {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt));
+  assert(Jfr::is_recording(), "invariant");
+  if (!_chunkwriter->is_valid()) {
+    return;
+  }
+  instance()._post_box.post((metadata || _chunkwriter->is_initial_flushpoint_for_chunk()) ? MSG_FLUSHPOINT_METADATA : MSG_FLUSHPOINT);
+}
+
+size_t JfrRepository::flush_chunk() {
+  return _chunkwriter->flushpoint(false);
+}
--- a/src/hotspot/share/jfr/recorder/repository/jfrRepository.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/repository/jfrRepository.hpp	Fri May 17 16:02:27 2019 +0200
@@ -55,8 +55,10 @@
   bool set_path(const char* path);
   void set_chunk_path(const char* path);
   bool open_chunk(bool vm_error = false);
-  size_t close_chunk(int64_t metadata_offset);
+  size_t close_chunk();
+  size_t flush_chunk();
   void on_vm_error();
+
   static void notify_on_new_chunk_path();
   static JfrChunkWriter& chunkwriter();
 
@@ -68,6 +70,8 @@
  public:
   static void set_path(jstring location, JavaThread* jt);
   static void set_chunk_path(jstring path, JavaThread* jt);
+  static void flush(bool metadata, JavaThread* jt);
+  static jlong current_chunk_start_nanos();
 };
 
 #endif // SHARE_JFR_RECORDER_REPOSITORY_JFRREPOSITORY_HPP
--- a/src/hotspot/share/jfr/recorder/service/jfrPostBox.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/service/jfrPostBox.cpp	Fri May 17 16:02:27 2019 +0200
@@ -33,7 +33,9 @@
                              (MSGBIT(MSG_STOP))   |          \
                              (MSGBIT(MSG_START))  |          \
                              (MSGBIT(MSG_CLONE_IN_MEMORY)) | \
-                             (MSGBIT(MSG_VM_ERROR))          \
+                             (MSGBIT(MSG_VM_ERROR))        | \
+                             (MSGBIT(MSG_FLUSHPOINT))      | \
+                             (MSGBIT(MSG_FLUSHPOINT_METADATA)) \
                            )
 
 static JfrPostBox* _instance = NULL;
--- a/src/hotspot/share/jfr/recorder/service/jfrPostBox.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/service/jfrPostBox.hpp	Fri May 17 16:02:27 2019 +0200
@@ -41,6 +41,8 @@
   MSG_SHUTDOWN,
   MSG_VM_ERROR,
   MSG_DEADBUFFER,
+  MSG_FLUSHPOINT,
+  MSG_FLUSHPOINT_METADATA,
   MSG_NO_OF_MSGS
 };
 
--- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp	Fri May 17 16:02:27 2019 +0200
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "jfrfiles/jfrEventClasses.hpp"
 #include "jfr/jni/jfrJavaSupport.hpp"
 #include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp"
 #include "jfr/recorder/jfrRecorder.hpp"
@@ -75,6 +76,9 @@
 static const int rotation_try_limit = 1000;
 static const int rotation_retry_sleep_millis = 10;
 
+// incremented on each flushpoint
+static u8 flushpoint_id = 0;
+
 class RotationLock : public StackObj {
  private:
   Thread* const _thread;
@@ -130,70 +134,171 @@
   bool not_acquired() const { return !_acquired; }
 };
 
+template <typename E, typename Instance, size_t(Instance::*func)()>
+class ServiceFunctor {
+ private:
+  Instance& _instance;
+  u4 _elements;
+ public:
+  typedef E EventType;
+  ServiceFunctor(Instance& instance) : _instance(instance), _elements(0) {}
+  bool process() {
+    _elements = (u4)(_instance.*func)();
+    return true;
+  }
+  u4 elements() const { return _elements; }
+};
+
+template <typename ContentFunctor>
+class WriteSubsystem : public StackObj {
+ protected:
+  const JfrTicks _start_time;
+  JfrTicks _end_time;
+  JfrChunkWriter& _cw;
+  ContentFunctor& _content_functor;
+  const int64_t _start_offset;
+ public:
+  typedef typename ContentFunctor::EventType EventType;
+
+  WriteSubsystem(JfrChunkWriter& cw, ContentFunctor& functor) :
+    _start_time(JfrTicks::now()),
+    _end_time(),
+    _cw(cw),
+    _content_functor(functor),
+    _start_offset(_cw.current_offset()) {
+    assert(_cw.is_valid(), "invariant");
+  }
+
+  bool process() {
+    // invocation
+    _content_functor.process();
+    _end_time = JfrTicks::now();
+    return 0 != _content_functor.elements();
+  }
+
+  const JfrTicks& start_time() const {
+    return _start_time;
+  }
+
+  const JfrTicks& end_time() const {
+    return _end_time;
+  }
+
+  int64_t start_offset() const {
+    return _start_offset;
+  }
+
+  int64_t end_offset() const {
+    return current_offset();
+  }
+
+  int64_t current_offset() const {
+    return _cw.current_offset();
+  }
+
+  u4 elements() const {
+    return (u4) _content_functor.elements();
+  }
+
+  u4 size() const {
+    return (u4)(end_offset() - start_offset());
+  }
+
+  static bool is_event_enabled() {
+    return EventType::is_enabled();
+  }
+
+  static u8 event_id() {
+    return EventType::eventId;
+  }
+
+  void write_elements(int64_t offset) {
+    _cw.write_padded_at_offset<u4>(elements(), offset);
+  }
+
+  void write_size() {
+    _cw.write_padded_at_offset<u4>(size(), start_offset());
+  }
+
+  void set_last_checkpoint() {
+    _cw.set_last_checkpoint_offset(start_offset());
+  }
+
+  void rewind() {
+    _cw.seek(start_offset());
+  }
+
+};
+
 static int64_t write_checkpoint_event_prologue(JfrChunkWriter& cw, u8 type_id) {
-  const int64_t prev_cp_offset = cw.previous_checkpoint_offset();
-  const int64_t prev_cp_relative_offset = 0 == prev_cp_offset ? 0 : prev_cp_offset - cw.current_offset();
+  const int64_t last_cp_offset = cw.last_checkpoint_offset();
+  const int64_t last_cp_relative_offset = 0 == last_cp_offset ? 0 : last_cp_offset - cw.current_offset();
   cw.reserve(sizeof(u4));
   cw.write<u8>(EVENT_CHECKPOINT);
   cw.write(JfrTicks::now());
-  cw.write((int64_t)0);
-  cw.write(prev_cp_relative_offset); // write previous checkpoint offset delta
+  cw.write<int64_t>((int64_t)0);
+  cw.write(last_cp_relative_offset); // write last checkpoint offset delta
   cw.write<bool>(false); // flushpoint
-  cw.write((u4)1); // nof types in this checkpoint
-  cw.write(type_id);
+  cw.write<u4>((u4)1); // nof types in this checkpoint
+  cw.write<u8>(type_id);
   const int64_t number_of_elements_offset = cw.current_offset();
   cw.reserve(sizeof(u4));
   return number_of_elements_offset;
 }
 
 template <typename ContentFunctor>
-class WriteCheckpointEvent : public StackObj {
+class WriteSubsystemCheckpointEvent : public WriteSubsystem<ContentFunctor> {
  private:
-  JfrChunkWriter& _cw;
-  u8 _type_id;
-  ContentFunctor& _content_functor;
+  const u8 _type_id;
  public:
-  WriteCheckpointEvent(JfrChunkWriter& cw, u8 type_id, ContentFunctor& functor) :
-    _cw(cw),
-    _type_id(type_id),
-    _content_functor(functor) {
-    assert(_cw.is_valid(), "invariant");
-  }
+  WriteSubsystemCheckpointEvent(JfrChunkWriter& cw, ContentFunctor& functor, u8 type_id) :
+    WriteSubsystem<ContentFunctor>(cw, functor), _type_id(type_id) {}
+
   bool process() {
-    // current_cp_offset is also offset for the event size header field
-    const int64_t current_cp_offset = _cw.current_offset();
-    const int64_t num_elements_offset = write_checkpoint_event_prologue(_cw, _type_id);
-    // invocation
-    _content_functor.process();
-    const u4 number_of_elements = (u4)_content_functor.processed();
-    if (number_of_elements == 0) {
+    const int64_t num_elements_offset = write_checkpoint_event_prologue(this->_cw, _type_id);
+    if (!WriteSubsystem<ContentFunctor>::process()) {
       // nothing to do, rewind writer to start
-      _cw.seek(current_cp_offset);
-      return true;
+      this->rewind();
+      assert(this->current_offset() == this->start_offset(), "invariant");
+      return false;
     }
-    assert(number_of_elements > 0, "invariant");
-    assert(_cw.current_offset() > num_elements_offset, "invariant");
-    _cw.write_padded_at_offset<u4>(number_of_elements, num_elements_offset);
-    _cw.write_padded_at_offset<u4>((u4)_cw.current_offset() - current_cp_offset, current_cp_offset);
-    // update writer with last checkpoint position
-    _cw.set_previous_checkpoint_offset(current_cp_offset);
+    assert(this->elements() > 0, "invariant");
+    assert(this->current_offset() > num_elements_offset, "invariant");
+    this->write_elements(num_elements_offset);
+    this->write_size();
+    this->set_last_checkpoint();
     return true;
   }
 };
 
-template <typename Instance, size_t(Instance::*func)()>
-class ServiceFunctor {
- private:
-  Instance& _instance;
-  size_t _processed;
- public:
-  ServiceFunctor(Instance& instance) : _instance(instance), _processed(0) {}
-  bool process() {
-    _processed = (_instance.*func)();
-    return true;
+template <typename Functor>
+static void write_flush_event(Functor& f) {
+  if (!Functor::is_event_enabled()) {
+    return;
   }
-  size_t processed() const { return _processed; }
-};
+  typename Functor::EventType e(UNTIMED);
+  e.set_starttime(f.start_time());
+  e.set_endtime(f.end_time());
+  e.set_flushId(flushpoint_id);
+  e.set_elements(f.elements());
+  e.set_size(f.size());
+  e.commit();
+}
+
+template <typename Functor>
+static u4 invoke(Functor& f) {
+  f.process();
+  return f.elements();
+}
+
+template <typename Functor>
+static u4 invoke_with_flush_event(Functor& f) {
+  const u4 elements = invoke(f);
+  if (elements != 0) {
+    write_flush_event(f);
+  }
+  return elements;
+}
 
 template <typename Instance, void(Instance::*func)()>
 class JfrVMOperation : public VM_Operation {
@@ -206,22 +311,36 @@
   Mode evaluation_mode() const { return _safepoint; } // default
 };
 
-class WriteStackTraceRepository : public StackObj {
+class FlushStackTraceRepository : public StackObj {
  private:
   JfrStackTraceRepository& _repo;
   JfrChunkWriter& _cw;
-  size_t _elements_processed;
+  size_t _elements;
   bool _clear;
 
  public:
-  WriteStackTraceRepository(JfrStackTraceRepository& repo, JfrChunkWriter& cw, bool clear) :
-    _repo(repo), _cw(cw), _elements_processed(0), _clear(clear) {}
+  typedef EventFlushStacktrace EventType;
+  FlushStackTraceRepository(JfrStackTraceRepository& repo, JfrChunkWriter& cw, bool clear) :
+    _repo(repo), _cw(cw), _elements(0), _clear(clear) {}
   bool process() {
-    _elements_processed = _repo.write(_cw, _clear);
+    _elements = _repo.write(_cw, _clear);
     return true;
   }
-  size_t processed() const { return _elements_processed; }
-  void reset() { _elements_processed = 0; }
+  size_t elements() const { return _elements; }
+  void reset() { _elements = 0; }
+};
+
+class FlushMetadataEvent : public StackObj {
+ private:
+  JfrChunkWriter& _cw;
+ public:
+  typedef EventFlushMetadata EventType;
+  FlushMetadataEvent(JfrChunkWriter& cw) : _cw(cw) {}
+  bool process() {
+    JfrMetadataEvent::write(_cw);
+    return true;
+  }
+  size_t elements() const { return 1; }
 };
 
 static bool recording = false;
@@ -318,8 +437,7 @@
   if (msgs & (MSGBIT(MSG_STOP))) {
     stop();
   }
-  // action determined by chunkwriter state
-  if (!_chunkwriter.is_valid()) {
+  if (!_storage.control().to_disk()) {
     in_memory_rotation();
     return;
   }
@@ -338,22 +456,17 @@
 }
 
 void JfrRecorderService::open_new_chunk(bool vm_error) {
-  assert(!_chunkwriter.is_valid(), "invariant");
-  assert(!JfrStream_lock->owned_by_self(), "invariant");
   JfrChunkRotation::on_rotation();
-  MutexLocker stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag);
-  if (!_repository.open_chunk(vm_error)) {
-    assert(!_chunkwriter.is_valid(), "invariant");
-    _storage.control().set_to_disk(false);
-    return;
+  const bool valid_chunk = _repository.open_chunk(vm_error);
+  _storage.control().set_to_disk(valid_chunk);
+  if (valid_chunk) {
+    _checkpoint_manager.write_constants();
   }
-  assert(_chunkwriter.is_valid(), "invariant");
-  _storage.control().set_to_disk(true);
 }
 
 void JfrRecorderService::in_memory_rotation() {
-  assert(!_chunkwriter.is_valid(), "invariant");
   // currently running an in-memory recording
+  assert(!_storage.control().to_disk(), "invariant");
   open_new_chunk();
   if (_chunkwriter.is_valid()) {
     // dump all in-memory buffer data to the newly created chunk
@@ -362,8 +475,6 @@
 }
 
 void JfrRecorderService::serialize_storage_from_in_memory_recording() {
-  assert(!JfrStream_lock->owned_by_self(), "not holding stream lock!");
-  MutexLocker stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag);
   _storage.write();
 }
 
@@ -375,7 +486,6 @@
 void JfrRecorderService::finalize_current_chunk() {
   assert(_chunkwriter.is_valid(), "invariant");
   write();
-  assert(!_chunkwriter.is_valid(), "invariant");
 }
 
 void JfrRecorderService::write() {
@@ -386,48 +496,160 @@
   post_safepoint_write();
 }
 
-typedef ServiceFunctor<JfrStringPool, &JfrStringPool::write> WriteStringPool;
-typedef ServiceFunctor<JfrStringPool, &JfrStringPool::write_at_safepoint> WriteStringPoolSafepoint;
-typedef WriteCheckpointEvent<WriteStackTraceRepository> WriteStackTraceCheckpoint;
-typedef WriteCheckpointEvent<WriteStringPool> WriteStringPoolCheckpoint;
-typedef WriteCheckpointEvent<WriteStringPoolSafepoint> WriteStringPoolCheckpointSafepoint;
+typedef ServiceFunctor<EventFlushStringPool, JfrStringPool, &JfrStringPool::write> FlushStringPoolFunctor;
+typedef ServiceFunctor<EventFlushStringPool, JfrStringPool, &JfrStringPool::write_at_safepoint> FlushStringPoolSafepointFunctor;
+typedef WriteSubsystemCheckpointEvent<FlushStackTraceRepository> FlushStackTraceCheckpoint;
+typedef WriteSubsystemCheckpointEvent<FlushStringPoolFunctor> FlushStringPoolCheckpoint;
+typedef WriteSubsystemCheckpointEvent<FlushStringPoolSafepointFunctor> FlushStringPoolCheckpointSafepoint;
+
+static u4 flush_stacktrace(JfrStackTraceRepository& stack_trace_repo, JfrChunkWriter& chunkwriter, bool clear) {
+  FlushStackTraceRepository flush_stacktrace_repo(stack_trace_repo, chunkwriter, clear);
+  FlushStackTraceCheckpoint flush_stack_trace_checkpoint(chunkwriter, flush_stacktrace_repo, TYPE_STACKTRACE);
+  return invoke_with_flush_event(flush_stack_trace_checkpoint);
+}
+
+static u4 flush_stacktrace(JfrStackTraceRepository& stack_trace_repo, JfrChunkWriter& chunkwriter) {
+  return flush_stacktrace(stack_trace_repo, chunkwriter, false);
+}
+
+static u4 flush_stacktrace_checkpoint(JfrStackTraceRepository& stack_trace_repo, JfrChunkWriter& chunkwriter, bool clear) {
+  FlushStackTraceRepository flush_stacktrace_repo(stack_trace_repo, chunkwriter, clear);
+  FlushStackTraceCheckpoint flush_stack_trace_checkpoint(chunkwriter, flush_stacktrace_repo, TYPE_STACKTRACE);
+  return invoke(flush_stack_trace_checkpoint);
+}
+
+static u4 flush_stringpool(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) {
+  FlushStringPoolFunctor flush_string_pool(string_pool);
+  FlushStringPoolCheckpoint flush_string_pool_checkpoint(chunkwriter, flush_string_pool, TYPE_STRING);
+  return invoke_with_flush_event(flush_string_pool_checkpoint);
+}
 
-static void write_stacktrace_checkpoint(JfrStackTraceRepository& stack_trace_repo, JfrChunkWriter& chunkwriter, bool clear) {
-  WriteStackTraceRepository write_stacktrace_repo(stack_trace_repo, chunkwriter, clear);
-  WriteStackTraceCheckpoint write_stack_trace_checkpoint(chunkwriter, TYPE_STACKTRACE, write_stacktrace_repo);
-  write_stack_trace_checkpoint.process();
+static u4 flush_stringpool_checkpoint(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) {
+  FlushStringPoolFunctor flush_string_pool(string_pool);
+  FlushStringPoolCheckpoint flush_string_pool_checkpoint(chunkwriter, flush_string_pool, TYPE_STRING);
+  return invoke(flush_string_pool_checkpoint);
+}
+
+static u4 flush_stringpool_checkpoint_safepoint(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) {
+  FlushStringPoolSafepointFunctor flush_string_pool(string_pool);
+  FlushStringPoolCheckpointSafepoint flush_string_pool_checkpoint(chunkwriter, flush_string_pool, TYPE_STRING);
+  return invoke(flush_string_pool_checkpoint);
+}
+
+typedef ServiceFunctor<EventFlushTypeSet, JfrCheckpointManager, &JfrCheckpointManager::flush_type_set> FlushTypeSetFunctor;
+typedef WriteSubsystem<FlushTypeSetFunctor> FlushTypeSet;
+
+static u4 flush_typeset(JfrCheckpointManager& checkpoint_manager, JfrChunkWriter& chunkwriter) {
+  FlushTypeSetFunctor flush_type_set(checkpoint_manager);
+  FlushTypeSet fts(chunkwriter, flush_type_set);
+  return invoke_with_flush_event(fts);
+}
+
+typedef WriteSubsystem<FlushMetadataEvent> FlushMetadata;
+
+static u4 flush_metadata_event(JfrChunkWriter& chunkwriter) {
+  assert(chunkwriter.is_valid(), "invariant");
+  FlushMetadataEvent fme(chunkwriter);
+  FlushMetadata fm(chunkwriter, fme);
+  return invoke_with_flush_event(fm);
+}
+
+static u4 flush_metadata_event_checkpoint(JfrChunkWriter& chunkwriter) {
+  assert(chunkwriter.is_valid(), "invariant");
+  FlushMetadataEvent wme(chunkwriter);
+  FlushMetadata wm(chunkwriter, wme);
+  return invoke(wm);
 }
 
-static void write_stringpool_checkpoint(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) {
-  WriteStringPool write_string_pool(string_pool);
-  WriteStringPoolCheckpoint write_string_pool_checkpoint(chunkwriter, TYPE_STRING, write_string_pool);
-  write_string_pool_checkpoint.process();
+static JfrBuffer* thread_local_buffer() {
+  return Thread::current()->jfr_thread_local()->native_buffer();
+}
+
+static void reset_buffer(JfrBuffer* buffer) {
+  assert(buffer != NULL, "invariant");
+  assert(buffer == thread_local_buffer(), "invariant");
+  buffer->set_pos(const_cast<u1*>(buffer->top()));
+  assert(buffer->empty(), "invariant");
+}
+
+static void reset_thread_local_buffer() {
+  reset_buffer(thread_local_buffer());
+}
+
+static void write_thread_local_buffer(JfrChunkWriter& chunkwriter) {
+  JfrBuffer * const buffer = thread_local_buffer();
+  assert(buffer != NULL, "invariant");
+  if (!buffer->empty()) {
+    chunkwriter.write_unbuffered(buffer->top(), buffer->pos() - buffer->top());
+    reset_buffer(buffer);
+  }
+  assert(buffer->empty(), "invariant");
+}
+
+typedef ServiceFunctor<EventFlushStorage, JfrStorage, &JfrStorage::write> FlushStorageFunctor;
+typedef WriteSubsystem<FlushStorageFunctor> FlushStorage;
+
+static size_t flush_storage(JfrStorage& storage, JfrChunkWriter& chunkwriter) {
+  assert(chunkwriter.is_valid(), "invariant");
+  FlushStorageFunctor fsf(storage);
+  FlushStorage fs(chunkwriter, fsf);
+  return invoke_with_flush_event(fs);
 }
 
-static void write_stringpool_checkpoint_safepoint(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) {
-  WriteStringPoolSafepoint write_string_pool(string_pool);
-  WriteStringPoolCheckpointSafepoint write_string_pool_checkpoint(chunkwriter, TYPE_STRING, write_string_pool);
-  write_string_pool_checkpoint.process();
+typedef ServiceFunctor<EventFlush, JfrRecorderService, &JfrRecorderService::flush> FlushFunctor;
+typedef WriteSubsystem<FlushFunctor> Flush;
+
+static bool write_metadata_in_flushpoint = false;
+
+size_t JfrRecorderService::flush() {
+  size_t total_elements = 0;
+  if (write_metadata_in_flushpoint) {
+    total_elements = flush_metadata_event(_chunkwriter);
+  }
+  const size_t storage_elements = flush_storage(_storage, _chunkwriter);
+  if (0 == storage_elements) {
+    return total_elements;
+  }
+  total_elements += storage_elements;
+  total_elements += flush_stacktrace(_stack_trace_repository, _chunkwriter);
+  if (_string_pool.modified()) {
+    total_elements += flush_stringpool(_string_pool, _chunkwriter);
+  }
+  total_elements += flush_typeset(_checkpoint_manager, _chunkwriter);
+  return total_elements;
+}
+
+void JfrRecorderService::flush(int msgs) {
+  assert(_chunkwriter.is_valid(), "invariant");
+  ResourceMark rm;
+  HandleMark hm;
+  reset_thread_local_buffer();
+  ++flushpoint_id;
+  write_metadata_in_flushpoint = (msgs & MSGBIT(MSG_FLUSHPOINT_METADATA));
+  FlushFunctor flushpoint(*this);
+  Flush fl(_chunkwriter, flushpoint);
+  invoke_with_flush_event(fl);
+  write_thread_local_buffer(_chunkwriter);
+  _repository.flush_chunk();
 }
 
 //
 // pre-safepoint write sequence
 //
-//  lock stream lock ->
-//    write non-safepoint dependent types ->
-//      write checkpoint epoch transition list->
-//        write stack trace checkpoint ->
-//          write string pool checkpoint ->
-//            write storage ->
-//              release stream lock
+//  write checkpoint epoch transition list->
+//    write stack trace checkpoint ->
+//      write string pool checkpoint ->
+//        notify about pending rotation ->
+//          write storage
 //
 void JfrRecorderService::pre_safepoint_write() {
-  MutexLocker stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag);
   assert(_chunkwriter.is_valid(), "invariant");
-  _checkpoint_manager.write_types();
   _checkpoint_manager.write_epoch_transition_mspace();
-  write_stacktrace_checkpoint(_stack_trace_repository, _chunkwriter, false);
-  write_stringpool_checkpoint(_string_pool, _chunkwriter);
+  flush_stacktrace_checkpoint(_stack_trace_repository, _chunkwriter, false);
+  if (_string_pool.modified()) {
+    flush_stringpool_checkpoint(_string_pool, _chunkwriter);
+  }
+  _checkpoint_manager.notify_types_on_rotation();
   _storage.write();
 }
 
@@ -444,47 +666,34 @@
 //
 // safepoint write sequence
 //
-//   lock stream lock ->
-//     write object sample stacktraces ->
-//       write stacktrace repository ->
-//         write string pool ->
-//           write safepoint dependent types ->
-//             write storage ->
-//                 shift_epoch ->
-//                   update time ->
-//                     lock metadata descriptor ->
-//                       release stream lock
+// write object sample stacktraces ->
+//   write stacktrace repository ->
+//     write string pool ->
+//       write storage ->
+//         notify java threads ->
+//           shift_epoch ->
+//             update time
 //
 void JfrRecorderService::safepoint_write() {
   assert(SafepointSynchronize::is_at_safepoint(), "invariant");
-  MutexLocker stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag);
   write_object_sample_stacktrace(_stack_trace_repository);
-  write_stacktrace_checkpoint(_stack_trace_repository, _chunkwriter, true);
-  write_stringpool_checkpoint_safepoint(_string_pool, _chunkwriter);
-  _checkpoint_manager.write_safepoint_types();
+  flush_stacktrace_checkpoint(_stack_trace_repository, _chunkwriter, true);
+  if (_string_pool.modified()) {
+    flush_stringpool_checkpoint_safepoint(_string_pool, _chunkwriter);
+  }
   _storage.write_at_safepoint();
+  _checkpoint_manager.notify_threads();
   _checkpoint_manager.shift_epoch();
   _chunkwriter.time_stamp_chunk_now();
-  JfrMetadataEvent::lock();
-}
-
-static int64_t write_metadata_event(JfrChunkWriter& chunkwriter) {
-  assert(chunkwriter.is_valid(), "invariant");
-  const int64_t metadata_offset = chunkwriter.current_offset();
-  JfrMetadataEvent::write(chunkwriter, metadata_offset);
-  return metadata_offset;
 }
 
 //
 // post-safepoint write sequence
 //
-//  lock stream lock ->
-//    write type set ->
-//      write checkpoints ->
-//        write metadata event ->
-//          write chunk header ->
-//            close chunk fd ->
-//              release stream lock
+//  write type set ->
+//    write checkpoints ->
+//      write metadata event ->
+//        close chunk
 //
 void JfrRecorderService::post_safepoint_write() {
   assert(_chunkwriter.is_valid(), "invariant");
@@ -493,12 +702,11 @@
   // already tagged artifacts for the previous epoch. We can accomplish this concurrently
   // with threads now tagging artifacts in relation to the new, now updated, epoch and remain outside of a safepoint.
   _checkpoint_manager.write_type_set();
-  MutexLocker stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag);
   // serialize any outstanding checkpoint memory
   _checkpoint_manager.write();
   // serialize the metadata descriptor event and close out the chunk
-  _repository.close_chunk(write_metadata_event(_chunkwriter));
-  assert(!_chunkwriter.is_valid(), "invariant");
+  flush_metadata_event_checkpoint(_chunkwriter);
+  _repository.close_chunk();
 }
 
 void JfrRecorderService::vm_error_rotation() {
@@ -512,7 +720,6 @@
 void JfrRecorderService::finalize_current_chunk_on_vm_error() {
   assert(_chunkwriter.is_valid(), "invariant");
   pre_safepoint_write();
-  JfrMetadataEvent::lock();
   // Do not attempt safepoint dependent operations during emergency dump.
   // Optimistically write tagged artifacts.
   _checkpoint_manager.shift_epoch();
@@ -520,13 +727,10 @@
   // update time
   _chunkwriter.time_stamp_chunk_now();
   post_safepoint_write();
-  assert(!_chunkwriter.is_valid(), "invariant");
 }
 
 void JfrRecorderService::process_full_buffers() {
   if (_chunkwriter.is_valid()) {
-    assert(!JfrStream_lock->owned_by_self(), "invariant");
-    MutexLocker stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag);
     _storage.write_full();
   }
 }
--- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.hpp	Fri May 17 16:02:27 2019 +0200
@@ -68,10 +68,12 @@
   JfrRecorderService();
   void start();
   void rotate(int msgs);
+  void flush(int msgs);
   void process_full_buffers();
   void scavenge();
   void evaluate_chunk_size_for_rotation();
   static bool is_recording();
+  size_t flush();
 };
 
 #endif // SHARE_JFR_RECORDER_SERVICE_JFRRECORDERSERVICE_HPP
--- a/src/hotspot/share/jfr/recorder/service/jfrRecorderThread.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderThread.cpp	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,7 @@
 #include "classfile/javaClasses.hpp"
 #include "classfile/symbolTable.hpp"
 #include "classfile/systemDictionary.hpp"
+#include "jfr/jfr.hpp"
 #include "jfr/jni/jfrJavaSupport.hpp"
 #include "jfr/recorder/jfrRecorder.hpp"
 #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
@@ -64,7 +65,6 @@
   if (allocation_failed) {
     JfrJavaSupport::throw_out_of_memory_error("Unable to create native recording thread for JFR", CHECK_NULL);
   }
-
   Thread::start(new_thread);
   return new_thread;
 }
@@ -98,8 +98,9 @@
   instanceHandle h_thread_oop(THREAD, (instanceOop)result.get_jobject());
   assert(h_thread_oop.not_null(), "invariant");
   // attempt thread start
-  const Thread* const t = start_thread(h_thread_oop, recorderthread_entry,THREAD);
+  Thread* const t = start_thread(h_thread_oop, recorderthread_entry, THREAD);
   if (!HAS_PENDING_EXCEPTION) {
+    Jfr::exclude_thread(t);
     cp_manager->register_service_thread(t);
     return true;
   }
--- a/src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp	Fri May 17 16:02:27 2019 +0200
@@ -40,6 +40,7 @@
   #define START (msgs & (MSGBIT(MSG_START)))
   #define SHUTDOWN (msgs & MSGBIT(MSG_SHUTDOWN))
   #define ROTATE (msgs & (MSGBIT(MSG_ROTATE)|MSGBIT(MSG_STOP)))
+  #define FLUSHPOINT (msgs & (MSGBIT(MSG_FLUSHPOINT)|MSGBIT(MSG_FLUSHPOINT_METADATA)))
   #define PROCESS_FULL_BUFFERS (msgs & (MSGBIT(MSG_ROTATE)|MSGBIT(MSG_STOP)|MSGBIT(MSG_FULLBUFFER)))
   #define SCAVENGE (msgs & (MSGBIT(MSG_DEADBUFFER)))
 
@@ -72,6 +73,8 @@
         service.start();
       } else if (ROTATE) {
         service.rotate(msgs);
+      } else if (FLUSHPOINT) {
+        service.flush(msgs);
       }
       JfrMsg_lock->lock();
       post_box.notify_waiters();
@@ -90,6 +93,7 @@
   #undef START
   #undef SHUTDOWN
   #undef ROTATE
+  #undef FLUSHPOINT
   #undef PROCESS_FULL_BUFFERS
   #undef SCAVENGE
 }
--- a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.cpp	Fri May 17 16:02:27 2019 +0200
@@ -119,7 +119,7 @@
 };
 
 bool JfrStackTraceRepository::initialize() {
-  return JfrSerializer::register_serializer(TYPE_FRAMETYPE, false, true, new JfrFrameType());
+  return JfrSerializer::register_serializer(TYPE_FRAMETYPE, true, new JfrFrameType());
 }
 
 size_t JfrStackTraceRepository::clear() {
@@ -196,7 +196,7 @@
     *hash = tl->cached_stack_trace_hash();
     return tl->cached_stack_trace_id();
   }
-  if (!thread->is_Java_thread() || thread->is_hidden_from_external_view()) {
+  if (!thread->is_Java_thread() || thread->is_hidden_from_external_view() || tl->is_excluded()) {
     return 0;
   }
   JfrStackFrame* frames = tl->stackframes();
@@ -367,7 +367,6 @@
   assert(_method, "no method pointer");
   assert(_line == 0, "already have linenumber");
   _line = _method->line_number_from_bci(_bci);
-  _method = NULL;
 }
 
 void JfrStackTrace::set_frame(u4 frame_pos, JfrStackFrame& frame) {
@@ -446,7 +445,7 @@
     const int lineno = method->line_number_from_bci(bci);
     // Can we determine if it's inlined?
     _hash = (_hash << 2) + (unsigned int)(((size_t)mid >> 2) + (bci << 4) + type);
-    _frames[count] = JfrStackFrame(mid, bci, type, lineno);
+    _frames[count] = JfrStackFrame(method, mid, bci, type, lineno);
     st.samples_next();
     count++;
   }
--- a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.hpp	Fri May 17 16:02:27 2019 +0200
@@ -53,8 +53,8 @@
 
   JfrStackFrame(const traceid& id, int bci, int type, const Method* method) :
     _method(method), _methodid(id), _line(0), _bci(bci), _type(type) {}
-  JfrStackFrame(const traceid& id, int bci, int type, int lineno) :
-    _method(NULL), _methodid(id), _line(lineno), _bci(bci), _type(type) {}
+  JfrStackFrame(const Method* method, const traceid& id, int bci, int type, int lineno) :
+    _method(method), _methodid(id), _line(lineno), _bci(bci), _type(type) {}
   bool equals(const JfrStackFrame& rhs) const;
   void write(JfrChunkWriter& cw) const;
   void write(JfrCheckpointWriter& cpw) const;
--- a/src/hotspot/share/jfr/recorder/storage/jfrBuffer.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/storage/jfrBuffer.cpp	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -54,10 +54,18 @@
   return true;
 }
 
-void JfrBuffer::reinitialize() {
+void JfrBuffer::reinitialize(bool exclusion /* false */) {
   assert(!lease(), "invariant");
   assert(!transient(), "invariant");
   set_pos(start());
+  if (exclusion != excluded()) {
+    // update
+    if (exclusion) {
+      set_excluded();
+    } else {
+      clear_excluded();
+    }
+  }
   clear_retired();
   set_top(start());
 }
@@ -136,6 +144,14 @@
   _identity = NULL;
 }
 
+bool JfrBuffer::acquired_by(const void* id) const {
+  return identity() == id;
+}
+
+bool JfrBuffer::acquired_by_self() const {
+  return acquired_by(Thread::current());
+}
+
 #ifdef ASSERT
 static bool validate_to(const JfrBuffer* const to, size_t size) {
   assert(to != NULL, "invariant");
@@ -153,10 +169,6 @@
   assert(t->top() + size <= t->pos(), "invariant");
   return true;
 }
-
-bool JfrBuffer::acquired_by_self() const {
-  return identity() == Thread::current();
-}
 #endif // ASSERT
 
 void JfrBuffer::move(JfrBuffer* const to, size_t size) {
@@ -183,11 +195,11 @@
   set_concurrent_top(start());
 }
 
-// flags
 enum FLAG {
   RETIRED = 1,
   TRANSIENT = 2,
-  LEASE = 4
+  LEASE = 4,
+  EXCLUDED = 8
 };
 
 bool JfrBuffer::transient() const {
@@ -222,6 +234,22 @@
   assert(!lease(), "invariant");
 }
 
+bool JfrBuffer::excluded() const {
+  return (u1)EXCLUDED == (_flags & (u1)EXCLUDED);
+}
+
+void JfrBuffer::set_excluded() {
+  _flags |= (u1)EXCLUDED;
+  assert(excluded(), "invariant");
+}
+
+void JfrBuffer::clear_excluded() {
+  if (excluded()) {
+    _flags ^= (u1)EXCLUDED;
+  }
+  assert(!excluded(), "invariant");
+}
+
 static u2 load_acquire_flags(const u2* const flags) {
   return OrderAccess::load_acquire(flags);
 }
--- a/src/hotspot/share/jfr/recorder/storage/jfrBuffer.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/storage/jfrBuffer.hpp	Fri May 17 16:02:27 2019 +0200
@@ -57,12 +57,11 @@
   u4 _size;
 
   const u1* stable_top() const;
-  void clear_flags();
 
  public:
   JfrBuffer();
   bool initialize(size_t header_size, size_t size, const void* id = NULL);
-  void reinitialize();
+  void reinitialize(bool exclusion = false);
   void concurrent_reinitialization();
   size_t discard();
   JfrBuffer* next() const {
@@ -150,6 +149,8 @@
 
   void acquire(const void* id);
   bool try_acquire(const void* id);
+  bool acquired_by(const void* id) const;
+  bool acquired_by_self() const;
   void release();
 
   void move(JfrBuffer* const to, size_t size);
@@ -167,7 +168,10 @@
   void set_retired();
   void clear_retired();
 
-  debug_only(bool acquired_by_self() const;)
+  bool excluded() const;
+  void set_excluded();
+  void clear_excluded();
+
 };
 
 class JfrAgeNode : public JfrBuffer {
--- a/src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.inline.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.inline.hpp	Fri May 17 16:02:27 2019 +0200
@@ -104,6 +104,7 @@
   }
   assert(t->empty(), "invariant");
   assert(!t->retired(), "invariant");
+  assert(!t->excluded(), "invariant");
   assert(t->identity() == NULL, "invariant");
   if (!should_populate_cache()) {
     remove_free(t);
@@ -346,19 +347,19 @@
 template <typename Mspace>
 inline bool ReleaseOp<Mspace>::process(typename Mspace::Type* t) {
   assert(t != NULL, "invariant");
-  if (t->retired() || t->try_acquire(_thread)) {
-    if (t->transient()) {
-      if (_release_full) {
-        mspace_release_full_critical(t, _mspace);
-      } else {
-        mspace_release_free_critical(t, _mspace);
-      }
-      return true;
+  // assumes some means of exclusive access to t
+  if (t->transient()) {
+    if (_release_full) {
+      mspace_release_full_critical(t, _mspace);
+    } else {
+      mspace_release_free_critical(t, _mspace);
     }
-    t->reinitialize();
-    assert(t->empty(), "invariant");
-    t->release(); // publish
+    return true;
   }
+  t->reinitialize();
+  assert(t->empty(), "invariant");
+  assert(!t->retired(), "invariant");
+  t->release(); // publish
   return true;
 }
 
--- a/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp	Fri May 17 16:02:27 2019 +0200
@@ -26,6 +26,7 @@
 #include "jfr/jfrEvents.hpp"
 #include "jfr/jni/jfrJavaSupport.hpp"
 #include "jfr/recorder/jfrRecorder.hpp"
+#include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
 #include "jfr/recorder/repository/jfrChunkWriter.hpp"
 #include "jfr/recorder/service/jfrOptionSet.hpp"
 #include "jfr/recorder/service/jfrPostBox.hpp"
@@ -253,6 +254,18 @@
     assert(buffer->empty(), "invariant");
     return true;
   }
+
+  if (buffer->excluded()) {
+    const bool thread_is_excluded = thread->jfr_thread_local()->is_excluded();
+    buffer->reinitialize(thread_is_excluded);
+    assert(buffer->empty(), "invariant");
+    if (!thread_is_excluded) {
+      // state change from exclusion to inclusion requires a thread checkpoint
+      JfrCheckpointManager::write_thread_checkpoint(thread);
+    }
+    return true;
+  }
+
   BufferPtr const promotion_buffer = get_promotion_buffer(unflushed_size, _global_mspace, *this, promotion_retry, thread);
   if (promotion_buffer == NULL) {
     write_data_loss(buffer, thread);
@@ -339,9 +352,9 @@
 void JfrStorage::register_full(BufferPtr buffer, Thread* thread) {
   assert(buffer != NULL, "invariant");
   assert(buffer->retired(), "invariant");
+  assert(buffer->acquired_by(thread), "invariant");
   if (!full_buffer_registration(buffer, _age_mspace, control(), thread)) {
     handle_registration_failure(buffer);
-    buffer->release();
   }
   if (control().should_post_buffer_full_message()) {
     _post_box.post(MSG_FULLBUFFER);
@@ -376,8 +389,8 @@
     }
   }
   assert(buffer->empty(), "invariant");
+  assert(buffer->identity() != NULL, "invariant");
   control().increment_dead();
-  buffer->release();
   buffer->set_retired();
 }
 
@@ -465,6 +478,7 @@
   assert(t != NULL, "invariant");
   assert(cur != NULL, "invariant");
   assert(cur->lease(), "invariant");
+  assert(!cur->excluded(), "invariant");
   assert(cur_pos != NULL, "invariant");
   assert(native ? t->jfr_thread_local()->native_buffer() == cur : t->jfr_thread_local()->java_buffer() == cur, "invariant");
   assert(t->jfr_thread_local()->shelved_buffer() != NULL, "invariant");
@@ -491,6 +505,9 @@
   // the case for stable thread local buffers; it is not the case for large buffers.
   if (!cur->empty()) {
     flush_regular_buffer(cur, t);
+    if (cur->excluded()) {
+      return cur;
+    }
   }
   assert(t->jfr_thread_local()->shelved_buffer() == NULL, "invariant");
   if (cur->free_size() >= req) {
@@ -582,13 +599,13 @@
 typedef ConcurrentWriteOpExcludeRetired<WriteOperation> ThreadLocalConcurrentWriteOperation;
 
 size_t JfrStorage::write() {
-  const size_t full_size_processed = write_full();
+  const size_t full_elements = write_full();
   WriteOperation wo(_chunkwriter);
   ThreadLocalConcurrentWriteOperation tlwo(wo);
   process_full_list(tlwo, _thread_local_mspace);
   ConcurrentWriteOperation cwo(wo);
   process_free_list(cwo, _global_mspace);
-  return full_size_processed + wo.processed();
+  return full_elements + wo.elements();
 }
 
 size_t JfrStorage::write_at_safepoint() {
@@ -600,7 +617,7 @@
   process_full_list(writer, _transient_mspace);
   assert(_global_mspace->is_full_empty(), "invariant");
   process_free_list(writer, _global_mspace);
-  return wo.processed();
+  return wo.elements();
 }
 
 typedef DiscardOp<DefaultDiscarder<JfrStorage::Buffer> > DiscardOperation;
@@ -608,14 +625,14 @@
 typedef CompositeOperation<MutexedWriteOperation, ReleaseOperation> FullOperation;
 
 size_t JfrStorage::clear() {
-  const size_t full_size_processed = clear_full();
+  const size_t full_elements = clear_full();
   DiscardOperation discarder(concurrent); // concurrent discard mode
   process_full_list(discarder, _thread_local_mspace);
   assert(_transient_mspace->is_free_empty(), "invariant");
   process_full_list(discarder, _transient_mspace);
   assert(_global_mspace->is_full_empty(), "invariant");
   process_free_list(discarder, _global_mspace);
-  return full_size_processed + discarder.processed();
+  return full_elements + discarder.elements();
 }
 
 static void insert_free_age_nodes(JfrStorageAgeMspace* age_mspace, JfrAgeNode* head, JfrAgeNode* tail, size_t count) {
@@ -687,10 +704,9 @@
 
 static void log(size_t count, size_t amount, bool clear = false) {
   if (log_is_enabled(Debug, jfr, system)) {
-    if (count > 0) {
+    assert(count > 0, "invariant");
       log_debug(jfr, system)("%s " SIZE_FORMAT " full buffer(s) of " SIZE_FORMAT" B of data%s",
         clear ? "Discarded" : "Wrote", count, amount, clear ? "." : " to chunk.");
-    }
   }
 }
 
@@ -706,15 +722,25 @@
   ReleaseOperation ro(_transient_mspace, thread);
   FullOperation cmd(&writer, &ro);
   const size_t count = process_full(cmd, control(), _age_mspace);
-  log(count, writer.processed());
-  return writer.processed();
+  if (0 == count) {
+    assert(0 == writer.elements(), "invariant");
+    return 0;
+  }
+  const size_t size = writer.size();
+  log(count, size);
+  return count;
 }
 
 size_t JfrStorage::clear_full() {
   DiscardOperation discarder(mutexed); // a retired buffer implies mutexed access
   const size_t count = process_full(discarder, control(), _age_mspace);
-  log(count, discarder.processed(), true);
-  return discarder.processed();
+  if (0 == count) {
+    assert(0 == discarder.elements(), "invariant");
+    return 0;
+  }
+  const size_t size = discarder.size();
+  log(count, size, true);
+  return count;
 }
 
 static void scavenge_log(size_t count, size_t amount, size_t current) {
@@ -738,13 +764,18 @@
   Scavenger(JfrStorageControl& control, Mspace* mspace) : _control(control), _mspace(mspace), _count(0), _amount(0) {}
   bool process(Type* t) {
     if (t->retired()) {
+      assert(t->identity() != NULL, "invariant");
+      assert(t->empty(), "invariant");
       assert(!t->transient(), "invariant");
       assert(!t->lease(), "invariant");
-      assert(t->empty(), "invariant");
-      assert(t->identity() == NULL, "invariant");
       ++_count;
       _amount += t->total_size();
+      if (t->excluded()) {
+        t->clear_excluded();
+      }
+      assert(!t->excluded(), "invariant");
       t->clear_retired();
+      t->release();
       _control.decrement_dead();
       mspace_release_full_critical(t, _mspace);
     }
@@ -761,6 +792,11 @@
   }
   Scavenger<JfrThreadLocalMspace> scavenger(ctrl, _thread_local_mspace);
   process_full_list(scavenger, _thread_local_mspace);
-  scavenge_log(scavenger.processed(), scavenger.amount(), ctrl.dead_count());
-  return scavenger.processed();
+  const size_t count = scavenger.processed();
+  if (0 == count) {
+    assert(0 == scavenger.amount(), "invariant");
+    return 0;
+  }
+  scavenge_log(count, scavenger.amount(), ctrl.dead_count());
+  return count;
 }
--- a/src/hotspot/share/jfr/recorder/storage/jfrStorage.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/storage/jfrStorage.hpp	Fri May 17 16:02:27 2019 +0200
@@ -68,7 +68,6 @@
 
   size_t clear();
   size_t clear_full();
-  size_t write();
   size_t write_full();
   size_t write_at_safepoint();
   size_t scavenge();
@@ -89,6 +88,8 @@
   void discard_oldest(Thread* t);
   static JfrStorageControl& control();
 
+  size_t write();
+
   friend class JfrRecorder;
   friend class JfrRecorderService;
   template <typename, template <typename> class, typename>
--- a/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.hpp	Fri May 17 16:02:27 2019 +0200
@@ -44,8 +44,11 @@
   bool process(Type* t = NULL) {
     return _next == NULL ? _op->process(t) : _op->process(t) && _next->process(t);
   }
-  size_t processed() const {
-    return _next == NULL ? _op->processed() : _op->processed() + _next->processed();
+  size_t elements() const {
+    return _next == NULL ? _op->elements() : _op->elements() + _next->elements();
+  }
+  size_t size() const {
+    return _next == NULL ? _op->size() : _op->size() + _next->size();
   }
 };
 
@@ -53,23 +56,27 @@
 class UnBufferedWriteToChunk {
  private:
   JfrChunkWriter& _writer;
-  size_t _processed;
+  size_t _elements;
+  size_t _size;
  public:
   typedef T Type;
-  UnBufferedWriteToChunk(JfrChunkWriter& writer) : _writer(writer), _processed(0) {}
+  UnBufferedWriteToChunk(JfrChunkWriter& writer) : _writer(writer), _elements(0), _size(0) {}
   bool write(Type* t, const u1* data, size_t size);
-  size_t processed() { return _processed; }
+  size_t elements() const { return _elements; }
+  size_t size() const { return _size; }
 };
 
 template <typename T>
 class DefaultDiscarder {
  private:
-  size_t _processed;
+  size_t _elements;
+  size_t _size;
  public:
   typedef T Type;
-  DefaultDiscarder() : _processed() {}
+  DefaultDiscarder() : _elements(0), _size(0) {}
   bool discard(Type* t, const u1* data, size_t size);
-  size_t processed() const { return _processed; }
+  size_t elements() const { return _elements; }
+  size_t size() const { return _size; }
 };
 
 template <typename Operation>
@@ -80,7 +87,8 @@
   typedef typename Operation::Type Type;
   ConcurrentWriteOp(Operation& operation) : _operation(operation) {}
   bool process(Type* t);
-  size_t processed() const { return _operation.processed(); }
+  size_t elements() const { return _operation.elements(); }
+  size_t size() const { return _operation.size(); }
 };
 
 template <typename Operation>
@@ -89,10 +97,10 @@
   typedef typename Operation::Type Type;
   ConcurrentWriteOpExcludeRetired(Operation& operation) : ConcurrentWriteOp<Operation>(operation) {}
   bool process(Type* t);
-  size_t processed() const { return ConcurrentWriteOp<Operation>::processed(); }
+  size_t elements() const { return ConcurrentWriteOp<Operation>::elements();}
+  size_t size() const { return ConcurrentWriteOp<Operation>::size(); }
 };
 
-
 template <typename Operation>
 class MutexedWriteOp {
  private:
@@ -101,7 +109,17 @@
   typedef typename Operation::Type Type;
   MutexedWriteOp(Operation& operation) : _operation(operation) {}
   bool process(Type* t);
-  size_t processed() const { return _operation.processed(); }
+  size_t elements() const { return _operation.elements(); }
+  size_t size() const { return _operation.size(); }
+};
+
+template <typename Operation>
+class ExclusiveOp : public MutexedWriteOp<Operation> {
+ public:
+  typedef typename Operation::Type Type;
+  ExclusiveOp(Operation& operation) : MutexedWriteOp<Operation>(operation) {}
+  bool process(Type* t);
+  size_t size() const { return MutexedWriteOp<Operation>::size(); }
 };
 
 enum jfr_operation_mode {
@@ -118,7 +136,8 @@
   typedef typename Operation::Type Type;
   DiscardOp(jfr_operation_mode mode = concurrent) : _operation(), _mode(mode) {}
   bool process(Type* t);
-  size_t processed() const { return _operation.processed(); }
+  size_t elements() const { return _operation.elements(); }
+  size_t size() const { return _operation.size(); }
 };
 
 #endif // SHARE_JFR_RECORDER_STORAGE_JFRSTORAGEUTILS_HPP
--- a/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.inline.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.inline.hpp	Fri May 17 16:02:27 2019 +0200
@@ -26,17 +26,20 @@
 #define SHARE_JFR_RECORDER_STORAGE_JFRSTORAGEUTILS_INLINE_HPP
 
 #include "jfr/recorder/storage/jfrStorageUtils.hpp"
+#include "runtime/thread.inline.hpp"
 
 template <typename T>
 inline bool UnBufferedWriteToChunk<T>::write(T* t, const u1* data, size_t size) {
   _writer.write_unbuffered(data, size);
-  _processed += size;
+  ++_elements;
+  _size += size;
   return true;
 }
 
 template <typename T>
 inline bool DefaultDiscarder<T>::discard(T* t, const u1* data, size_t size) {
-  _processed += size;
+  ++_elements;
+  _size += size;
   return true;
 }
 
@@ -44,7 +47,7 @@
 inline bool ConcurrentWriteOp<Operation>::process(typename Operation::Type* t) {
   const u1* const current_top = t->concurrent_top();
   const size_t unflushed_size = t->pos() - current_top;
-  if (unflushed_size == 0) {
+  if (unflushed_size == 0 || t->excluded()) {
     t->set_concurrent_top(current_top);
     return true;
   }
@@ -67,7 +70,7 @@
   assert(t != NULL, "invariant");
   const u1* const current_top = t->top();
   const size_t unflushed_size = t->pos() - current_top;
-  if (unflushed_size == 0) {
+  if (unflushed_size == 0 || t->excluded()) {
     return true;
   }
   const bool result = _operation.write(t, current_top, unflushed_size);
@@ -75,6 +78,28 @@
   return result;
 }
 
+template <typename Type>
+static void retired_sensitive_acquire(Type* t) {
+  assert(t != NULL, "invariant");
+  if (t->retired()) {
+    return;
+  }
+  Thread* const thread = Thread::current();
+  while (!t->try_acquire(thread)) {
+    if (t->retired()) {
+      return;
+    }
+  }
+}
+
+template <typename Operation>
+inline bool ExclusiveOp<Operation>::process(typename Operation::Type* t) {
+  retired_sensitive_acquire(t);
+  assert(t->acquired_by_self() || t->retired(), "invariant");
+  // User is required to ensure proper release of the acquisition
+  return MutexedWriteOp<Operation>::process(t);
+}
+
 template <typename Operation>
 inline bool DiscardOp<Operation>::process(typename Operation::Type* t) {
   assert(t != NULL, "invariant");
--- a/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,7 +33,6 @@
 #include "jfr/recorder/stringpool/jfrStringPoolWriter.hpp"
 #include "jfr/utilities/jfrTypes.hpp"
 #include "logging/log.hpp"
-#include "runtime/atomic.hpp"
 #include "runtime/mutexLocker.hpp"
 #include "runtime/orderAccess.hpp"
 #include "runtime/safepoint.hpp"
@@ -42,12 +41,32 @@
 typedef JfrStringPool::Buffer* BufferPtr;
 
 static JfrStringPool* _instance = NULL;
+static uint64_t store_generation = 0;
+static uint64_t serialized_generation = 0;
 
+inline void set_value(uint64_t value, uint64_t* const dest) {
+  assert(dest != NULL, "invariant");
+  const uint64_t current = OrderAccess::load_acquire(dest);
+  if (value != current) {
+    OrderAccess::release_store(dest, value);
+  }
+}
+static void inc_store_generation() {
+  set_value(OrderAccess::load_acquire(&serialized_generation) + 1, &store_generation);
+}
+static void set_serialized_generation() {
+  set_value(OrderAccess::load_acquire(&store_generation), &serialized_generation);
+}
+bool JfrStringPool::modified() {
+  return serialized_generation != OrderAccess::load_acquire(&store_generation);
+}
 JfrStringPool& JfrStringPool::instance() {
   return *_instance;
 }
 
 JfrStringPool* JfrStringPool::create(JfrChunkWriter& cw) {
+  store_generation = 0;
+  serialized_generation = 0;
   assert(_instance == NULL, "invariant");
   _instance = new JfrStringPool(cw);
   return _instance;
@@ -136,97 +155,83 @@
     writer.write(id);
     writer.write(string);
     writer.inc_nof_strings();
+    inc_store_generation();
   }
   return current_epoch;
 }
 
-class StringPoolWriteOp  {
+template <template <typename> class Operation>
+class StringPoolOp {
  public:
   typedef JfrStringPoolBuffer Type;
  private:
-  UnBufferedWriteToChunk<Type> _writer;
+  Operation<Type> _op;
   Thread* _thread;
   size_t _strings_processed;
  public:
-  StringPoolWriteOp(JfrChunkWriter& writer, Thread* thread) : _writer(writer), _thread(thread), _strings_processed(0) {}
+  StringPoolOp() : _op(), _thread(Thread::current()), _strings_processed(0) {}
+  StringPoolOp(JfrChunkWriter& writer, Thread* thread) : _op(writer), _thread(thread), _strings_processed(0) {}
   bool write(Type* buffer, const u1* data, size_t size) {
-    buffer->acquire(_thread); // blocking
+    assert(buffer->acquired_by(_thread) || buffer->retired(), "invariant");
     const uint64_t nof_strings_used = buffer->string_count();
     assert(nof_strings_used > 0, "invariant");
     buffer->set_string_top(buffer->string_top() + nof_strings_used);
     // "size processed" for string pool buffers is the number of processed string elements
     _strings_processed += nof_strings_used;
-    const bool ret = _writer.write(buffer, data, size);
-    buffer->release();
-    return ret;
+    return _op.write(buffer, data, size);
   }
   size_t processed() { return _strings_processed; }
 };
 
-typedef StringPoolWriteOp WriteOperation;
-typedef ConcurrentWriteOp<WriteOperation> ConcurrentWriteOperation;
+template <typename Type>
+class StringPoolDiscarderStub {
+ public:
+  bool write(Type* buffer, const u1* data, size_t size) {
+    // stub only, discard happens at higher level
+    return true;
+  }
+};
+
+typedef StringPoolOp<UnBufferedWriteToChunk> WriteOperation;
+typedef StringPoolOp<StringPoolDiscarderStub> DiscardOperation;
+typedef ExclusiveOp<WriteOperation> ExclusiveWriteOperation;
+typedef ExclusiveOp<DiscardOperation> ExclusiveDiscardOperation;
+typedef ReleaseOp<JfrStringPoolMspace> StringPoolReleaseOperation;
+typedef CompositeOperation<ExclusiveWriteOperation, StringPoolReleaseOperation> StringPoolWriteOperation;
+typedef CompositeOperation<ExclusiveDiscardOperation, StringPoolReleaseOperation> StringPoolDiscardOperation;
 
 size_t JfrStringPool::write() {
+  set_serialized_generation();
   Thread* const thread = Thread::current();
   WriteOperation wo(_chunkwriter, thread);
-  ConcurrentWriteOperation cwo(wo);
-  assert(_free_list_mspace->is_full_empty(), "invariant");
-  process_free_list(cwo, _free_list_mspace);
-  return wo.processed();
-}
-
-typedef MutexedWriteOp<WriteOperation> MutexedWriteOperation;
-typedef ReleaseOp<JfrStringPoolMspace> StringPoolReleaseOperation;
-typedef CompositeOperation<MutexedWriteOperation, StringPoolReleaseOperation> StringPoolWriteOperation;
-
-size_t JfrStringPool::write_at_safepoint() {
-  assert(SafepointSynchronize::is_at_safepoint(), "invariant");
-  Thread* const thread = Thread::current();
-  WriteOperation wo(_chunkwriter, thread);
-  MutexedWriteOperation mwo(wo);
+  ExclusiveWriteOperation ewo(wo);
   StringPoolReleaseOperation spro(_free_list_mspace, thread, false);
-  StringPoolWriteOperation spwo(&mwo, &spro);
+  StringPoolWriteOperation spwo(&ewo, &spro);
   assert(_free_list_mspace->is_full_empty(), "invariant");
   process_free_list(spwo, _free_list_mspace);
   return wo.processed();
 }
 
-class StringPoolBufferDiscarder {
- private:
-  Thread* _thread;
-  size_t _processed;
- public:
-  typedef JfrStringPoolBuffer Type;
-  StringPoolBufferDiscarder() : _thread(Thread::current()), _processed(0) {}
-  bool process(Type* buffer) {
-    buffer->acquire(_thread); // serialized access
-    const u1* const current_top = buffer->top();
-    const size_t unflushed_size = buffer->pos() - current_top;
-    if (unflushed_size == 0) {
-      assert(buffer->string_count() == 0, "invariant");
-      buffer->release();
-      return true;
-    }
-    buffer->set_top(current_top + unflushed_size);
-    const uint64_t nof_strings_used = buffer->string_count();
-    buffer->set_string_top(buffer->string_top() + nof_strings_used);
-    // "size processed" for string pool buffers is the number of string elements
-    _processed += (size_t)nof_strings_used;
-    buffer->release();
-    return true;
-  }
-  size_t processed() const { return _processed; }
-};
+size_t JfrStringPool::write_at_safepoint() {
+  assert(SafepointSynchronize::is_at_safepoint(), "invariant");
+  return write();
+}
 
 size_t JfrStringPool::clear() {
-  StringPoolBufferDiscarder discard_operation;
+  set_serialized_generation();
+  DiscardOperation discard_operation;
+  ExclusiveDiscardOperation edo(discard_operation);
+  StringPoolReleaseOperation spro(_free_list_mspace, Thread::current(), false);
+  StringPoolDiscardOperation spdo(&edo, &spro);
   assert(_free_list_mspace->is_full_empty(), "invariant");
-  process_free_list(discard_operation, _free_list_mspace);
+  process_free_list(spdo, _free_list_mspace);
   return discard_operation.processed();
 }
 
 void JfrStringPool::register_full(BufferPtr t, Thread* thread) {
   // nothing here at the moment
+  assert(t != NULL, "invariant");
+  assert(t->acquired_by(thread), "invariant");
   assert(t->retired(), "invariant");
 }
 
--- a/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.hpp	Fri May 17 16:02:27 2019 +0200
@@ -71,6 +71,7 @@
   static JfrStringPool* create(JfrChunkWriter& cw);
   bool initialize();
   static void destroy();
+  static bool modified();
 
   friend class JfrRecorder;
   friend class JfrRecorderService;
--- a/src/hotspot/share/jfr/recorder/stringpool/jfrStringPoolBuffer.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/stringpool/jfrStringPoolBuffer.cpp	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,11 +29,9 @@
 
 void JfrStringPoolBuffer::reinitialize() {
   assert(acquired_by_self() || retired(), "invariant");
-  concurrent_top();
-  set_pos((start()));
   set_string_pos(0);
   set_string_top(0);
-  set_concurrent_top(start());
+  JfrBuffer::reinitialize();
 }
 
 uint64_t JfrStringPoolBuffer::string_pos() const {
@@ -57,7 +55,7 @@
 }
 
 void JfrStringPoolBuffer::increment(uint64_t value) {
-  assert(acquired_by_self() || retired(), "invariant");
+  assert(acquired_by_self(), "invariant");
   ++_string_count_pos;
 }
 
--- a/src/hotspot/share/jfr/support/jfrKlassExtension.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/support/jfrKlassExtension.hpp	Fri May 17 16:02:27 2019 +0200
@@ -36,6 +36,7 @@
 #define JDK_JFR_EVENT_SUBKLASS 16
 #define JDK_JFR_EVENT_KLASS    32
 #define EVENT_HOST_KLASS       64
+#define EVENT_RESERVED         128
 #define IS_EVENT_KLASS(ptr) (((ptr)->trace_id() & (JDK_JFR_EVENT_KLASS | JDK_JFR_EVENT_SUBKLASS)) != 0)
 #define ON_KLASS_CREATION(k, p, t) if (IS_EVENT_KLASS(k)) JfrEventClassTransformer::on_klass_creation(k, p, t)
 
--- a/src/hotspot/share/jfr/support/jfrThreadLocal.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/support/jfrThreadLocal.cpp	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -55,6 +55,7 @@
   _stack_trace_hash(0),
   _stackdepth(0),
   _entering_suspend_flag(0),
+  _excluded(false),
   _dead(false) {}
 
 u8 JfrThreadLocal::add_data_lost(u8 value) {
@@ -84,9 +85,13 @@
 void JfrThreadLocal::on_start(Thread* t) {
   assert(t != NULL, "invariant");
   assert(Thread::current() == t, "invariant");
+  JfrJavaSupport::on_thread_start(t);
   if (JfrRecorder::is_recording()) {
-    if (t->is_Java_thread()) {
-      send_java_thread_start_event((JavaThread*)t);
+    if (!t->jfr_thread_local()->is_excluded()) {
+      JfrCheckpointManager::write_thread_checkpoint(t);
+      if (t->is_Java_thread()) {
+        send_java_thread_start_event((JavaThread*)t);
+      }
     }
   }
 }
@@ -107,20 +112,22 @@
   assert(Thread::current() == t, "invariant");
   assert(!tl->is_dead(), "invariant");
   assert(tl->shelved_buffer() == NULL, "invariant");
+  tl->_dead = true;
+  if (tl->has_java_event_writer()) {
+    assert(t->is_Java_thread(), "invariant");
+    const jobject event_writer = tl->java_event_writer();
+    tl->set_java_event_writer(NULL);
+    JfrJavaSupport::destroy_global_jni_handle(event_writer);
+  }
   if (tl->has_native_buffer()) {
     JfrStorage::release_thread_local(tl->native_buffer(), t);
   }
   if (tl->has_java_buffer()) {
     JfrStorage::release_thread_local(tl->java_buffer(), t);
   }
-  if (tl->has_java_event_writer()) {
-    assert(t->is_Java_thread(), "invariant");
-    JfrJavaSupport::destroy_global_jni_handle(tl->java_event_writer());
-  }
   if (tl->_stackframes != NULL) {
     FREE_C_HEAP_ARRAY(JfrStackFrame, tl->_stackframes);
   }
-  tl->_dead = true;
 }
 
 void JfrThreadLocal::on_exit(Thread* t) {
@@ -128,23 +135,31 @@
   JfrThreadLocal * const tl = t->jfr_thread_local();
   assert(!tl->is_dead(), "invariant");
   if (JfrRecorder::is_recording()) {
-    if (t->is_Java_thread()) {
+    if (t->is_Java_thread() && !tl->is_excluded()) {
       send_java_thread_end_events(tl->thread_id(), (JavaThread*)t);
     }
   }
   release(tl, Thread::current()); // because it could be that Thread::current() != t
 }
 
+static JfrBuffer* acquire_buffer(bool excluded) {
+  JfrBuffer* const buffer = JfrStorage::acquire_thread_local(Thread::current());
+  if (buffer != NULL && excluded) {
+    buffer->set_excluded();
+  }
+  return buffer;
+}
+
 JfrBuffer* JfrThreadLocal::install_native_buffer() const {
   assert(!has_native_buffer(), "invariant");
-  _native_buffer = JfrStorage::acquire_thread_local(Thread::current());
+  _native_buffer = acquire_buffer(_excluded);
   return _native_buffer;
 }
 
 JfrBuffer* JfrThreadLocal::install_java_buffer() const {
   assert(!has_java_buffer(), "invariant");
   assert(!has_java_event_writer(), "invariant");
-  _java_buffer = JfrStorage::acquire_thread_local(Thread::current());
+  _java_buffer = acquire_buffer(_excluded);
   return _java_buffer;
 }
 
@@ -163,3 +178,13 @@
 ByteSize JfrThreadLocal::java_event_writer_offset() {
   return in_ByteSize(offset_of(JfrThreadLocal, _java_event_writer));
 }
+
+void JfrThreadLocal::exclude(Thread* t) {
+  assert(t != NULL, "invariant");
+  t->jfr_thread_local()->_excluded = true;
+}
+
+void JfrThreadLocal::include(Thread* t) {
+  assert(t != NULL, "invariant");
+  t->jfr_thread_local()->_excluded = false;
+}
--- a/src/hotspot/share/jfr/support/jfrThreadLocal.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/support/jfrThreadLocal.hpp	Fri May 17 16:02:27 2019 +0200
@@ -50,6 +50,7 @@
   unsigned int _stack_trace_hash;
   mutable u4 _stackdepth;
   volatile jint _entering_suspend_flag;
+  bool _excluded;
   bool _dead;
 
   JfrBuffer* install_native_buffer() const;
@@ -205,6 +206,10 @@
     _trace_id = id;
   }
 
+  bool is_excluded() const {
+    return _excluded;
+  }
+
   bool is_dead() const {
     return _dead;
   }
@@ -215,6 +220,8 @@
 
   static void on_start(Thread* t);
   static void on_exit(Thread* t);
+  static void exclude(Thread* t);
+  static void include(Thread* t);
 
   // Code generation
   static ByteSize trace_id_offset();
--- a/src/hotspot/share/jfr/utilities/jfrIterator.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/utilities/jfrIterator.hpp	Fri May 17 16:02:27 2019 +0200
@@ -40,6 +40,14 @@
   }
 };
 
+template <typename Node>
+class StopOnEmptyCondition : public AllStatic {
+public:
+  static bool has_next(const Node* node) {
+    return node != NULL && !node->empty();
+  }
+};
+
 template <typename List, template <typename> class ContinuationPredicate>
 class Navigator {
  public:
@@ -83,6 +91,12 @@
   NavigatorStopOnNull(List& list, jfr_iter_direction direction = forward) : Navigator<List, StopOnNullCondition>(list, direction) {}
 };
 
+template <typename List>
+class NavigatorStopOnEmpty : public Navigator<List, StopOnEmptyCondition> {
+public:
+  NavigatorStopOnEmpty(List& list, jfr_iter_direction direction = forward) : Navigator<List, StopOnEmptyCondition>(list, direction) {}
+};
+
 template<typename List, template <typename> class Navigator, typename AP = StackObj>
 class IteratorHost : public AP {
  private:
@@ -104,4 +118,10 @@
   StopOnNullIterator(List& list, jfr_iter_direction direction = forward) : IteratorHost<List, NavigatorStopOnNull, AP>(list, direction) {}
 };
 
+template<typename List, typename AP = StackObj>
+class StopOnEmptyIterator : public IteratorHost<List, NavigatorStopOnEmpty, AP> {
+public:
+  StopOnEmptyIterator(List& list, jfr_iter_direction direction = forward) : IteratorHost<List, NavigatorStopOnEmpty, AP>(list, direction) {}
+};
+
 #endif // SHARE_JFR_UTILITIES_JFRITERATOR_HPP
--- a/src/hotspot/share/jfr/utilities/jfrLogTagSets.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/utilities/jfrLogTagSets.hpp	Fri May 17 16:02:27 2019 +0200
@@ -53,6 +53,7 @@
   JFR_LOG_TAG(jfr, system, bytecode) \
   JFR_LOG_TAG(jfr, system, parser) \
   JFR_LOG_TAG(jfr, system, metadata) \
+  JFR_LOG_TAG(jfr, system, streaming) \
   JFR_LOG_TAG(jfr, metadata) \
   JFR_LOG_TAG(jfr, event) \
   JFR_LOG_TAG(jfr, setting) \
--- a/src/hotspot/share/jfr/utilities/jfrTypes.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/utilities/jfrTypes.hpp	Fri May 17 16:02:27 2019 +0200
@@ -33,6 +33,7 @@
 typedef int fio_fd;
 const int invalid_fd = -1;
 const jlong invalid_offset = -1;
+const int64_t invalid_time = -1;
 const u4 STACK_DEPTH_DEFAULT = 64;
 const u4 MIN_STACK_DEPTH = 1;
 const u4 MAX_STACK_DEPTH = 2048;
--- a/src/hotspot/share/jfr/writers/jfrJavaEventWriter.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/writers/jfrJavaEventWriter.hpp	Fri May 17 16:02:27 2019 +0200
@@ -32,7 +32,7 @@
 class Thread;
 
 class JfrJavaEventWriter : AllStatic {
-  friend class JfrCheckpointThreadClosure;
+  friend class JfrNotifyClosure;
   friend class JfrJavaEventWriterNotifyOperation;
   friend class JfrJavaEventWriterNotificationClosure;
  private:
--- a/src/hotspot/share/jfr/writers/jfrStorageAdapter.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/writers/jfrStorageAdapter.hpp	Fri May 17 16:02:27 2019 +0200
@@ -82,7 +82,7 @@
     assert(_thread != NULL, "invariant");
     Flush f(_storage, used, requested, _thread);
     _storage = f.result();
-    return _storage != NULL;
+    return _storage != NULL && !_storage->excluded();
   }
 
   void release() {
@@ -236,7 +236,8 @@
   void release() {}
   bool flush(size_t used, size_t requested) {
     // don't flush/expand a buffer that is not our own
-    return false;
+    _pos = _start;
+    return true;
   }
 };
 
--- a/src/hotspot/share/jfr/writers/jfrWriterHost.inline.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/writers/jfrWriterHost.inline.hpp	Fri May 17 16:02:27 2019 +0200
@@ -170,7 +170,7 @@
   }
   if (this->available_size() < requested + size_safety_cushion) {
     if (!this->accommodate(this->used_size(), requested + size_safety_cushion)) {
-      this->cancel();
+      assert(!this->is_valid(), "invariant");
       return NULL;
     }
   }
--- a/src/hotspot/share/logging/logTag.hpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/logging/logTag.hpp	Fri May 17 16:02:27 2019 +0200
@@ -147,6 +147,7 @@
   LOG_TAG(startuptime) \
   LOG_TAG(state) \
   LOG_TAG(stats) \
+  LOG_TAG(streaming) \
   LOG_TAG(stringdedup) \
   LOG_TAG(stringtable) \
   LOG_TAG(symboltable) \
--- a/src/hotspot/share/runtime/thread.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/runtime/thread.cpp	Fri May 17 16:02:27 2019 +0200
@@ -3075,17 +3075,6 @@
 // if vm exit occurs during initialization). These cases can all be accounted
 // for such that this method never returns NULL.
 const char* JavaThread::get_thread_name() const {
-#ifdef ASSERT
-  // early safepoints can hit while current thread does not yet have TLS
-  if (!SafepointSynchronize::is_at_safepoint()) {
-    Thread *cur = Thread::current();
-    if (!(cur->is_Java_thread() && cur == this)) {
-      // Current JavaThreads are allowed to get their own name without
-      // the Threads_lock.
-      assert_locked_or_safepoint(Threads_lock);
-    }
-  }
-#endif // ASSERT
   return get_thread_name_string();
 }
 
--- a/src/jdk.jfr/share/classes/jdk/jfr/Recording.java	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/Recording.java	Fri May 17 16:02:27 2019 +0200
@@ -414,6 +414,32 @@
     }
 
     /**
+     * Determines how often events are made available for streaming.
+     *
+     * @param interval the interval at which events are made available for streaming.
+     *
+     * @throws IllegalArgumentException if <code>interval</code> is negative
+     *
+     * @throws IllegalStateException if the recording is in the {@code CLOSED} state
+     */
+    public void setFlushInterval(Duration interval) {
+        Objects.nonNull(interval);
+        if (interval.isNegative()) {
+            throw new IllegalArgumentException("Stream interval can't be negative");
+        }
+        internal.setFlushInterval(interval);
+    }
+
+    /**
+     * Returns how often events are made available for streaming purposes.
+     *
+     * @return the desired stream interval, or {@code null} if no interval has been set
+     */
+    public Duration getFlushInterval() {
+        return internal.getFlushInterval();
+    }
+
+    /**
      * Determines how far back data is kept in the disk repository.
      * <p>
      * To control the amount of recording data stored on disk, the maximum length of
--- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/ChunkParser.java	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/ChunkParser.java	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,7 @@
 import java.io.IOException;
 import java.util.Collection;
 import java.util.List;
+import java.util.StringJoiner;
 
 import jdk.jfr.EventType;
 import jdk.jfr.internal.LogLevel;
@@ -35,7 +36,9 @@
 import jdk.jfr.internal.Logger;
 import jdk.jfr.internal.MetadataDescriptor;
 import jdk.jfr.internal.Type;
+import jdk.jfr.internal.Utils;
 import jdk.jfr.internal.consumer.ChunkHeader;
+import jdk.jfr.internal.consumer.Parser;
 import jdk.jfr.internal.consumer.RecordingInput;
 
 /**
@@ -45,38 +48,127 @@
 final class ChunkParser {
     private static final long CONSTANT_POOL_TYPE_ID = 1;
     private final RecordingInput input;
-    private final LongMap<Parser> parsers;
     private final ChunkHeader chunkHeader;
-    private final long absoluteChunkEnd;
     private final MetadataDescriptor metadata;
-    private final LongMap<Type> typeMap;
     private final TimeConverter timeConverter;
+    private final MetadataDescriptor previousMetadata;
+    private final long pollInterval;
+    private final LongMap<ConstantLookup> constantLookups;
+
+    private LongMap<Type> typeMap;
+    private LongMap<Parser> parsers;
+    private boolean chunkFinished;
+    private InternalEventFilter eventFilter = InternalEventFilter.ACCEPT_ALL;
 
     public ChunkParser(RecordingInput input) throws IOException {
-        this(new ChunkHeader(input));
+        this(new ChunkHeader(input), null, 500);
     }
 
-    private ChunkParser(ChunkHeader header) throws IOException {
+    private ChunkParser(ChunkHeader header, ChunkParser previous, long pollInterval) throws IOException {
         this.input = header.getInput();
         this.chunkHeader = header;
-        this.metadata = header.readMetadata();
-        this.absoluteChunkEnd = header.getEnd();
+        if (previous == null) {
+            this.pollInterval = 500;
+            this.constantLookups = new LongMap<>();
+            this.previousMetadata = null;
+        } else {
+            this.constantLookups = previous.constantLookups;
+            this.previousMetadata = previous.metadata;
+            this.pollInterval = previous.pollInterval;
+        }
+        this.metadata = header.readMetadata(previousMetadata);
         this.timeConverter = new TimeConverter(chunkHeader, metadata.getGMTOffset());
-
-        ParserFactory factory = new ParserFactory(metadata, timeConverter);
-        LongMap<ConstantMap> constantPools = factory.getConstantPools();
-        parsers = factory.getParsers();
-        typeMap = factory.getTypeMap();
-
-        fillConstantPools(parsers, constantPools);
-        constantPools.forEach(ConstantMap::setIsResolving);
-        constantPools.forEach(ConstantMap::resolve);
-        constantPools.forEach(ConstantMap::setResolved);
+        if (metadata != previousMetadata) {
+            ParserFactory factory = new ParserFactory(metadata, constantLookups, timeConverter);
+            parsers = factory.getParsers();
+            typeMap = factory.getTypeMap();
+        } else {
+            parsers = previous.parsers;
+            typeMap = previous.typeMap;
+        }
+        constantLookups.forEach(c -> c.newPool());
+        fillConstantPools(0);
+        constantLookups.forEach(c -> c.getLatestPool().setResolving());
+        constantLookups.forEach(c -> c.getLatestPool().resolve());
+        constantLookups.forEach(c -> c.getLatestPool().setResolved());
 
         input.position(chunkHeader.getEventStart());
     }
 
+    public void setParserFilter(InternalEventFilter filter) {
+    // Disable low level filter, since it doesn't work
+    // when a psrser is shared
+    //    this.eventFilter = filter;
+    //    updateParserFilters();
+    }
+
+    public InternalEventFilter getEventFilter() {
+        return this.eventFilter;
+    }
+
+    private void updateParserFilters() {
+        parsers.forEach(p -> {
+            if (p instanceof EventParser) {
+                EventParser ep = (EventParser) p;
+                long threshold = eventFilter.getThreshold(ep.getEventType().getName());
+                if (threshold >= 0) {
+                    ep.setEnabled(true);
+                    ep.setThreshold(timeConverter.convertDurationNanos(threshold));
+                } else {
+                    ep.setThreshold(-1L);
+                }
+            }
+        });
+    }
+
+    /**
+     * Reads an event and returns null when segment or chunk ends.
+     */
+    public RecordedEvent readStreamingEvent(boolean awaitNewEvents) throws IOException {
+        long absoluteChunkEnd = chunkHeader.getEnd();
+        while (true) {
+            RecordedEvent event = readEvent();
+            if (event != null) {
+                return event;
+            }
+            if (!awaitNewEvents) {
+                return null;
+            }
+            long lastValid = absoluteChunkEnd;
+            long metadataPoistion = chunkHeader.getMetataPosition();
+            long contantPosition = chunkHeader.getConstantPoolPosition();
+            chunkFinished = awaitUpdatedHeader(absoluteChunkEnd);
+            if (chunkFinished) {
+                Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "At chunk end");
+                return null;
+            }
+            absoluteChunkEnd = chunkHeader.getEnd();
+            // Read metadata and constant pools for the next segment
+            if (chunkHeader.getMetataPosition() != metadataPoistion) {
+                Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Found new metadata in chunk. Rebuilding types and parsers");
+                MetadataDescriptor metadata = chunkHeader.readMetadata(previousMetadata);
+                ParserFactory factory = new ParserFactory(metadata, constantLookups, timeConverter);
+                parsers = factory.getParsers();
+                typeMap = factory.getTypeMap();
+                updateParserFilters();
+            }
+            if (contantPosition != chunkHeader.getConstantPoolPosition()) {
+                Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Found new constant pool data. Filling up pools with new values");
+                constantLookups.forEach(c -> c.getLatestPool().setAllResolved(false));
+                fillConstantPools(contantPosition + chunkHeader.getAbsoluteChunkStart());
+                constantLookups.forEach(c -> c.getLatestPool().setResolving());
+                constantLookups.forEach(c -> c.getLatestPool().resolve());
+                constantLookups.forEach(c -> c.getLatestPool().setResolved());
+            }
+            input.position(lastValid);
+        }
+    }
+
+    /**
+     * Reads an event and returns null when the chunk ends
+     */
     public RecordedEvent readEvent() throws IOException {
+        long absoluteChunkEnd = chunkHeader.getEnd();
         while (input.position() < absoluteChunkEnd) {
             long pos = input.position();
             int size = input.readInt();
@@ -84,10 +176,16 @@
                 throw new IOException("Event can't have zero size");
             }
             long typeId = input.readLong();
-            if (typeId > CONSTANT_POOL_TYPE_ID) { // also skips metadata (id=0)
-                Parser ep = parsers.get(typeId);
-                if (ep instanceof EventParser) {
-                    return (RecordedEvent) ep.parse(input);
+            // Skip metadata and constant pool events (id = 0, id = 1)
+            if (typeId > CONSTANT_POOL_TYPE_ID) {
+                Parser p = parsers.get(typeId);
+                if (p instanceof EventParser) {
+                    EventParser ep = (EventParser) p;
+                    RecordedEvent event = ep.parse(input);
+                    if (event != null) {
+                        input.position(pos + size);
+                        return event;
+                    }
                 }
             }
             input.position(pos + size);
@@ -95,62 +193,132 @@
         return null;
     }
 
-    private void fillConstantPools(LongMap<Parser> typeParser, LongMap<ConstantMap> constantPools) throws IOException {
-        long nextCP = chunkHeader.getAbsoluteChunkStart();
-        long deltaToNext = chunkHeader.getConstantPoolPosition();
-        while (deltaToNext != 0) {
-            nextCP += deltaToNext;
-            input.position(nextCP);
-            final long position = nextCP;
+    private boolean awaitUpdatedHeader(long absoluteChunkEnd) throws IOException {
+        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Waiting for more data (streaming). Read so far: " + chunkHeader.getChunkSize() + " bytes");
+        while (true) {
+            chunkHeader.refresh();
+            if (absoluteChunkEnd != chunkHeader.getEnd()) {
+                return false;
+            }
+            if (chunkHeader.isFinished()) {
+                return true;
+            }
+            Utils.takeNap(pollInterval);
+        }
+    }
+
+    private void fillConstantPools(long abortCP) throws IOException {
+        long thisCP = chunkHeader.getConstantPoolPosition() + chunkHeader.getAbsoluteChunkStart();
+        long lastCP = -1;
+        long delta = -1;
+        boolean log = Logger.shouldLog(LogTag.JFR_SYSTEM_PARSER, LogLevel.TRACE);
+        while (thisCP != abortCP && delta != 0) {
+            input.position(thisCP);
+            lastCP = thisCP;
             int size = input.readInt(); // size
             long typeId = input.readLong();
             if (typeId != CONSTANT_POOL_TYPE_ID) {
-                throw new IOException("Expected check point event (id = 1) at position " + nextCP + ", but found type id = " + typeId);
+                throw new IOException("Expected check point event (id = 1) at position " + lastCP + ", but found type id = " + typeId);
             }
             input.readLong(); // timestamp
             input.readLong(); // duration
-            deltaToNext = input.readLong();
-            final long delta = deltaToNext;
+            delta = input.readLong();
+            thisCP += delta;
             boolean flush = input.readBoolean();
             int poolCount = input.readInt();
+            final long logLastCP = lastCP;
+            final long logDelta = delta;
             Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.TRACE, () -> {
-                return "New constant pool: startPosition=" + position + ", size=" + size + ", deltaToNext=" + delta + ", flush=" + flush + ", poolCount=" + poolCount;
+                return "New constant pool: startPosition=" + logLastCP + ", size=" + size + ", deltaToNext=" + logDelta + ", flush=" + flush + ", poolCount=" + poolCount;
             });
-
             for (int i = 0; i < poolCount; i++) {
                 long id = input.readLong(); // type id
-                ConstantMap pool = constantPools.get(id);
+                ConstantLookup lookup = constantLookups.get(id);
                 Type type = typeMap.get(id);
-                if (pool == null) {
+                if (lookup == null) {
                     Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Found constant pool(" + id + ") that is never used");
                     if (type == null) {
-                        throw new IOException("Error parsing constant pool type " + getName(id) + " at position " + input.position() + " at check point between [" + nextCP + ", " + nextCP + size + "]");
+                        throw new IOException(
+                                "Error parsing constant pool type " + getName(id) + " at position " + input.position() + " at check point between [" + lastCP + ", " + lastCP + size + "]");
                     }
-                    pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type.getName());
-                    constantPools.put(type.getId(), pool);
+                    ConstantMap pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type.getName());
+                    constantLookups.put(type.getId(), new ConstantLookup(pool, type));
                 }
-                Parser parser = typeParser.get(id);
+                Parser parser = parsers.get(id);
                 if (parser == null) {
                     throw new IOException("Could not find constant pool type with id = " + id);
                 }
                 try {
                     int count = input.readInt();
-                    Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.TRACE, () -> "Constant: " + getName(id) + "[" + count + "]");
+                    if (count == 0) {
+                        throw new InternalError("Pool " + type.getName() + " must contain at least one element ");
+                    }
+                    if (log) {
+                        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.TRACE, "Constant Pool " + i + ": " + type.getName());
+                    }
                     for (int j = 0; j < count; j++) {
                         long key = input.readLong();
-                        Object value = parser.parse(input);
-                        pool.put(key, value);
+//                      Object resolved = lookup.getCurrent(key);
+// Disable cache        Object resolved = lookup.getResolved(key);
+//                      if (resolved == null) {
+                            Object v = parser.parse(input);
+                            logConstant(key, v, false);
+                            lookup.getLatestPool().put(key, v);
+//                        } else {
+//                            parser.skip(input);
+//                            logConstant(key, resolved, true);
+// Disable cache            lookup.getLatestPool().putResolved(key, resolved);
+//                        }
                     }
                 } catch (Exception e) {
-                    throw new IOException("Error parsing constant pool type " + getName(id) + " at position " + input.position() + " at check point between [" + nextCP + ", " + nextCP + size + "]", e);
+                    throw new IOException("Error parsing constant pool type " + getName(id) + " at position " + input.position() + " at check point between [" + lastCP + ", " + lastCP + size + "]",
+                            e);
                 }
             }
-            if (input.position() != nextCP + size) {
+            if (input.position() != lastCP + size) {
                 throw new IOException("Size of check point event doesn't match content");
             }
         }
     }
 
+    private void logConstant(long key, Object v, boolean preresolved) {
+        if (!Logger.shouldLog(LogTag.JFR_SYSTEM_PARSER, LogLevel.TRACE)) {
+            return;
+        }
+        String valueText;
+        if (v.getClass().isArray()) {
+            Object[] array = (Object[]) v;
+            StringJoiner sj = new StringJoiner(", ", "{", "}");
+            for (int i = 0; i < array.length; i++) {
+                sj.add(textify(array[i]));
+            }
+            valueText = sj.toString();
+        } else {
+            valueText = textify(v);
+        }
+        String suffix  = preresolved ? " (presolved)" :"";
+        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.TRACE, "Constant: " + key + " = " + valueText + suffix);
+    }
+
+    private String textify(Object o) {
+        if (o == null) { // should not happen
+            return "null";
+        }
+        if (o instanceof String) {
+            return "\"" + String.valueOf(o) + "\"";
+        }
+        if (o instanceof RecordedObject) {
+            return o.getClass().getName();
+        }
+        if (o.getClass().isArray()) {
+            Object[] array = (Object[]) o;
+            if (array.length > 0) {
+                return textify(array[0]) + "[]"; // can it be recursive?
+            }
+        }
+        return String.valueOf(o);
+    }
+
     private String getName(long id) {
         Type type = typeMap.get(id);
         return type == null ? ("unknown(" + id + ")") : type.getName();
@@ -164,11 +332,15 @@
         return metadata.getEventTypes();
     }
 
-    public boolean isLastChunk() {
+    public boolean isLastChunk() throws IOException {
         return chunkHeader.isLastChunk();
     }
 
     public ChunkParser nextChunkParser() throws IOException {
-        return new ChunkParser(chunkHeader.nextHeader());
+        return new ChunkParser(chunkHeader.nextHeader(), this, pollInterval);
+    }
+
+    public boolean isChunkFinished() {
+        return chunkFinished;
     }
 }
--- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/ConstantMap.java	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/ConstantMap.java	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,9 +25,6 @@
 
 package jdk.jfr.consumer;
 
-import java.util.ArrayList;
-import java.util.List;
-
 /**
  * Holds mapping between a set of keys and their corresponding object.
  *
@@ -35,6 +32,15 @@
  * {@link ObjectFactory} can be supplied which will instantiate a typed object.
  */
 final class ConstantMap {
+
+    private static final int RESOLUTION_FINISHED = 0;
+    private static final int RESOLUTION_STARTED = 1;
+    public static final ConstantMap EMPTY = new ConstantMap();
+
+    // A temporary placeholder, so objects can
+    // reference themselves (directly, or indirectly),
+    // when making a transition from numeric id references
+    // to normal Java references.
     private final static class Reference {
         private final long key;
         private final ConstantMap pool;
@@ -47,18 +53,28 @@
         Object resolve() {
             return pool.get(key);
         }
+
+        public String toString() {
+            return "ref: " + pool.name + "[" + key + "]";
+        }
     }
 
-    private final ObjectFactory<?> factory;
+    final ObjectFactory<?> factory;
+    final String name;
+
     private final LongMap<Object> objects;
 
-    private LongMap<Boolean> isResolving;
+    private boolean resolving;
     private boolean allResolved;
-    private String name;
+
+    private ConstantMap() {
+        this(null, "<empty>");
+        allResolved = true;
+    }
 
     ConstantMap(ObjectFactory<?> factory, String name) {
         this.name = name;
-        this.objects = new LongMap<>();
+        this.objects = new LongMap<>(2);
         this.factory = factory;
     }
 
@@ -68,26 +84,42 @@
             return objects.get(id);
         }
         // referenced from a pool, deal with this later
-        if (isResolving == null) {
+        if (!resolving) {
             return new Reference(this, id);
         }
 
-        Boolean beingResolved = isResolving.get(id);
+        // should always have a value
+        Object value = objects.get(id);
+        if (value == null) {
+            // unless is 0 which is used to represent null
+            if (id == 0) {
+                return null;
+            }
+            throw new InternalError("Missing object id=" + id + " in pool " + name + ". All ids should reference object");
+        }
 
-        // we are resolved (but not the whole pool)
-        if (Boolean.FALSE.equals(beingResolved)) {
-            return objects.get(id);
+        // id is resolved (but not the whole pool)
+        if (objects.isSetId(id, RESOLUTION_FINISHED)) {
+            return value;
         }
 
         // resolving ourself, abort to avoid infinite recursion
-        if (Boolean.TRUE.equals(beingResolved)) {
+        if (objects.isSetId(id, RESOLUTION_STARTED)) {
             return null;
         }
 
-        // resolve me!
-        isResolving.put(id, Boolean.TRUE);
-        Object resolved = resolve(objects.get(id));
-        isResolving.put(id, Boolean.FALSE);
+        // mark id as STARTED if we should
+        // come back during object resolution
+        objects.setId(id, RESOLUTION_STARTED);
+
+        // resolve object!
+        Object resolved = resolve(value);
+
+        // mark id as FINISHED
+        objects.setId(id, RESOLUTION_FINISHED);
+
+        // if a factory exists, convert to RecordedThread.
+        // RecordedClass etc. and store back results
         if (factory != null) {
             Object factorized = factory.createObject(id, resolved);
             objects.put(id, factorized);
@@ -105,7 +137,8 @@
         if (o != null && o.getClass().isArray()) {
             final Object[] array = (Object[]) o;
             for (int i = 0; i < array.length; i++) {
-                array[i] = resolve(array[i]);
+                Object element = array[i];
+                array[i] = resolve(element);
             }
             return array;
         }
@@ -113,27 +146,44 @@
     }
 
     public void resolve() {
-        List<Long> keyList = new ArrayList<>();
-        objects.keys().forEachRemaining(keyList::add);
-        for (Long l : keyList) {
-            get(l);
-        }
+        objects.forEachKey(k -> get(k));
     }
 
     public void put(long key, Object value) {
         objects.put(key, value);
     }
 
-    public void setIsResolving() {
-        isResolving = new LongMap<>();
+    public void setResolving() {
+        resolving = true;
+        allResolved = false;
     }
 
     public void setResolved() {
         allResolved = true;
-        isResolving = null; // pool finished, release memory
+        resolving = false;
     }
 
     public String getName() {
         return name;
     }
+
+    public Object getResolved(long id) {
+        return objects.get(id);
+    }
+
+    public void putResolved(long id, Object object) {
+        objects.setId(id, RESOLUTION_FINISHED);
+        objects.put(id, object);
+    }
+
+    public void setAllResolved(boolean allResolved) {
+        this.allResolved = allResolved;
+    }
+
+    public boolean isResolved(long id) {
+        if (objects.hasKey(id)) {
+            return objects.isSetId(id, RESOLUTION_FINISHED);
+        }
+        return false;
+    }
 }
--- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventParser.java	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventParser.java	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,7 @@
 
 import jdk.jfr.EventType;
 import jdk.jfr.ValueDescriptor;
+import jdk.jfr.internal.consumer.Parser;
 import jdk.jfr.internal.consumer.RecordingInput;
 
 /**
@@ -44,29 +45,68 @@
     private final TimeConverter timeConverter;
     private final boolean hasDuration;
     private final List<ValueDescriptor> valueDescriptors;
+    private final int startIndex;
+    private long thresholdTicks = -1;
+    private boolean enabled = true;
 
     EventParser(TimeConverter timeConverter, EventType type, Parser[] parsers) {
         this.timeConverter = timeConverter;
         this.parsers = parsers;
         this.eventType = type;
         this.hasDuration = type.getField(FIELD_DURATION) != null;
+        this.startIndex = hasDuration ? 2 : 1;
         this.valueDescriptors = type.getFields();
     }
 
+    public EventType getEventType() {
+        return eventType;
+    }
+
+    public void setThreshold(long thresholdTicks) {
+        this.thresholdTicks = thresholdTicks;
+    }
+
+    public void setEnabled(boolean enabled) {
+        this.enabled = enabled;
+    }
+
+    public boolean isEnabled() {
+        return this.enabled;
+    }
+
+    public RecordedEvent parse(RecordingInput input) throws IOException {
+        if (enabled) {
+            long startTicks = input.readLong();
+            long durationTicks = 0;
+            if (hasDuration) {
+                durationTicks = input.readLong();
+                if (durationTicks < thresholdTicks) {
+                    return null;
+                }
+            }
+            Object[] values = new Object[parsers.length];
+            for (int i = startIndex; i < parsers.length; i++) {
+                values[i] = parsers[i].parse(input);
+            }
+            values[0] = startTicks;
+            if (hasDuration) {
+                values[1] = Long.valueOf(durationTicks);
+            }
+            long startTime = timeConverter.convertTimestamp(startTicks);
+            if (hasDuration) {
+                long endTime = timeConverter.convertTimestamp(startTicks + durationTicks);
+                return new RecordedEvent(eventType, valueDescriptors, values, startTime, endTime, timeConverter);
+            } else {
+                return new RecordedEvent(eventType, valueDescriptors, values, startTime, startTime, timeConverter);
+            }
+        }
+        return null;
+
+    }
+
     @Override
-    public Object parse(RecordingInput input) throws IOException {
-        Object[] values = new Object[parsers.length];
-        for (int i = 0; i < parsers.length; i++) {
-            values[i] = parsers[i].parse(input);
-        }
-        Long startTicks = (Long) values[0];
-        long startTime = timeConverter.convertTimestamp(startTicks);
-        if (hasDuration) {
-            long durationTicks = (Long) values[1];
-            long endTime = timeConverter.convertTimestamp(startTicks + durationTicks);
-            return new RecordedEvent(eventType, valueDescriptors, values, startTime, endTime, timeConverter);
-        } else {
-            return new RecordedEvent(eventType, valueDescriptors, values, startTime, startTime, timeConverter);
-        }
+    public void skip(RecordingInput input) throws IOException {
+        throw new InternalError("Should not call this method. More efficent to read event size and skip ahead");
     }
+
 }
--- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/LongMap.java	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/LongMap.java	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,37 +25,232 @@
 
 package jdk.jfr.consumer;
 
-import java.util.HashMap;
-import java.util.Iterator;
+import java.util.BitSet;
+import java.util.function.Consumer;
+import java.util.function.LongConsumer;
+
+@SuppressWarnings("unchecked")
+final class LongMap<T> {
+    private static final int MAXIMUM_CAPACITY = 1 << 30;
+    private static final long[] EMPTY_KEYS = new long[0];
+    private static final Object[] EMPTY_OBJECTS = new Object[0];
+    private static final int DEFAULT_SIZE = 32;
+    private static final Object NULL_OBJECT = new Object();
+
+    private final int bitCount;
+    private BitSet bitSet;
+    private long[] keys = EMPTY_KEYS;
+    private T[] objects = (T[]) EMPTY_OBJECTS;
+    private int count;
+    private int shift;
+
+    public LongMap() {
+        this.bitCount = 0;
+    }
+
+    public LongMap(int markBits) {
+        this.bitCount = markBits;
+        this.bitSet = new BitSet();
+    }
+
+    // Should be 2^n
+    private void initialize(int capacity) {
+        keys = new long[capacity];
+        objects = (T[]) new Object[capacity];
+        shift = 64 - (31 - Integer.numberOfLeadingZeros(capacity));
+    }
+
+    public void claimBits() {
+        // flip last bit back and forth to make bitset expand to max size
+        int lastBit = bitSetIndex(objects.length - 1, bitCount -1);
+        bitSet.flip(lastBit);
+        bitSet.flip(lastBit);
+    }
 
-/**
- * Commonly used data structure for looking up objects given an id (long value)
- *
- * TODO: Implement without using Map and Long objects, to minimize allocation
- *
- * @param <T>
- */
-final class LongMap<T> implements Iterable<T> {
-    private final HashMap<Long, T> map;
+    public void setId(long id, int bitIndex) {
+        int bitSetIndex = bitSetIndex(tableIndexOf(id), bitIndex);
+        bitSet.set(bitSetIndex, true);
+    }
+
+    public void clearId(long id, int bitIndex) {
+        int bitSetIndex = bitSetIndex(tableIndexOf(id), bitIndex);
+        bitSet.set(bitSetIndex, false);
+    }
+
+    public boolean isSetId(long id, int bitIndex) {
+        int bitSetIndex = bitSetIndex(tableIndexOf(id), bitIndex);
+        return bitSet.get(bitSetIndex);
+    }
+
+    private int bitSetIndex(int tableIndex, int bitIndex) {
+        return bitCount * tableIndex + bitIndex;
+    }
 
-    LongMap() {
-        map = new HashMap<>(101);
+    private int tableIndexOf(long id) {
+        int index = index(id);
+        while (true) {
+            if (objects[index] == null) {
+                throw new InternalError("Unknown id");
+            }
+            if (keys[index] == id) {
+                return index;
+            }
+            index++;
+            if (index == keys.length) {
+                index = 0;
+            }
+        }
+    }
+
+    public boolean hasKey(long id) {
+        int index = index(id);
+        while (true) {
+            if (objects[index] == null) {
+               return false;
+            }
+            if (keys[index] == id) {
+                return true;
+            }
+            index++;
+            if (index == keys.length) {
+                index = 0;
+            }
+        }
     }
 
-    void put(long id, T object) {
-        map.put(id, object);
-    }
-
-    T get(long id) {
-        return map.get(id);
+    public void expand(int size) {
+        int l = 4 * size / 3;
+        if (l <= keys.length) {
+            return;
+        }
+        int n = tableSizeFor(l);
+        LongMap<T> temp = new LongMap<>(bitCount);
+        temp.initialize(n);
+        // Optimization, avoid growing while copying bits
+        if (bitCount > 0 && !bitSet.isEmpty()) {
+           temp.claimBits();
+           claimBits();
+        }
+        for (int tIndex = 0; tIndex < keys.length; tIndex++) {
+            T o = objects[tIndex];
+            if (o != null) {
+                long key = keys[tIndex];
+                temp.put(key, o);
+                if (bitCount != 0) {
+                    for (int bIndex = 0; bIndex < bitCount; bIndex++) {
+                        boolean bitValue = isSetId(key, bIndex);
+                        if (bitValue) {
+                            temp.setId(key, bIndex);
+                        }
+                    }
+                }
+            }
+        }
+        keys = temp.keys;
+        objects = temp.objects;
+        shift = temp.shift;
+        bitSet = temp.bitSet;
     }
 
-    @Override
-    public Iterator<T> iterator() {
-        return map.values().iterator();
+    public void put(long id, T object) {
+        if (keys == EMPTY_KEYS) {
+            // Lazy initialization
+            initialize(DEFAULT_SIZE);
+        }
+        if (count > 3 * keys.length / 4) {
+            expand(2 * keys.length);
+        }
+        if (object == null) {
+            object = (T) NULL_OBJECT;
+        }
+
+        int index = index(id);
+        // probe for empty slot
+        while (true) {
+            if (objects[index] == null) {
+                keys[index] = id;
+                objects[index] = object;
+                count++;
+                return;
+            }
+            // if it already exists, replace
+            if (keys[index] == id) {
+                objects[index] = object;
+                return;
+            }
+            index++;
+            if (index == keys.length) {
+                index = 0;
+            }
+        }
+    }
+    public T getAt(int tableIndex) {
+        T o =  objects[tableIndex];
+        return o == NULL_OBJECT ? null : o;
     }
 
-    Iterator<Long> keys() {
-        return map.keySet().iterator();
+    public T get(long id) {
+        if (keys == EMPTY_KEYS) {
+            return null;
+        }
+        int index = index(id);
+        while (true) {
+            if (objects[index] == null) {
+                return null;
+            }
+            if (keys[index] == id) {
+                return getAt(index);
+            }
+            index++;
+            if (index == keys.length) {
+                index = 0;
+            }
+        }
+    }
+
+    private int index(long id) {
+//      int hash = (int) (id ^ (id >>> 32));
+//      return hash & (keys.length - 1);
+        return (int) ((id * -7046029254386353131L) >>> shift);
+    }
+
+    // Copied from HashMap::tableSizeFor
+    private static final int tableSizeFor(int cap) {
+        int n = -1 >>> Integer.numberOfLeadingZeros(cap - 1);
+        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
+    }
+
+    public void forEachKey(LongConsumer keyTraverser) {
+        for (int i = 0; i < keys.length; i++) {
+            if (objects[i] != null) {
+                keyTraverser.accept(keys[i]);
+            }
+        }
+    }
+
+    public void forEach(Consumer<T> consumer) {
+        for (int i = 0; i < keys.length; i++) {
+            T o = objects[i];
+            if (o != null) {
+                consumer.accept(o);
+            }
+        }
+    }
+
+    public int size() {
+        return count;
+    }
+
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < objects.length; i++) {
+            sb.append(i);
+            sb.append(": id=");
+            sb.append(keys[i]);
+            sb.append(" ");
+            sb.append(objects[i]);
+            sb.append("\n");
+        }
+        return sb.toString();
     }
 }
--- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/ObjectFactory.java	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/ObjectFactory.java	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -78,7 +78,7 @@
         if (value instanceof Object[]) {
             return createTyped(valueDescriptors, id, (Object[]) value);
         }
-        throw new InternalError("Object factory must have struct type");
+        throw new InternalError("Object factory must have struct type. Type was " + value.getClass().getName());
     }
 
     abstract T createTyped(List<ValueDescriptor> valueDescriptors, long id, Object[] values);
--- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/ParserFactory.java	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/ParserFactory.java	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,13 +28,13 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Objects;
 
 import jdk.jfr.EventType;
 import jdk.jfr.ValueDescriptor;
 import jdk.jfr.internal.MetadataDescriptor;
 import jdk.jfr.internal.PrivateAccess;
 import jdk.jfr.internal.Type;
+import jdk.jfr.internal.consumer.Parser;
 import jdk.jfr.internal.consumer.RecordingInput;
 
 /**
@@ -44,19 +44,21 @@
     private final LongMap<Parser> parsers = new LongMap<>();
     private final TimeConverter timeConverter;
     private final LongMap<Type> types = new LongMap<>();
-    private final LongMap<ConstantMap> constantPools;
+    private final LongMap<ConstantLookup> constantLookups;
 
-    public ParserFactory(MetadataDescriptor metadata, TimeConverter timeConverter) throws IOException {
-        this.constantPools = new LongMap<>();
+    public ParserFactory(MetadataDescriptor metadata, LongMap<ConstantLookup> constantLookups, TimeConverter timeConverter) throws IOException {
+        this.constantLookups = constantLookups;
         this.timeConverter = timeConverter;
         for (Type t : metadata.getTypes()) {
             types.put(t.getId(), t);
         }
-        for (Type t : types) {
+        List<Type> typeList = new ArrayList<>();
+        types.forEach(typeList::add);
+        for (Type t : typeList) {
             if (!t.getFields().isEmpty()) { // Avoid primitives
-                CompositeParser cp = createCompositeParser(t);
+                CompositeParser cp = createCompositeParser(t, false);
                 if (t.isSimpleType()) { // Reduce to nested parser
-                   parsers.put(t.getId(), cp.parsers[0]);
+                    parsers.put(t.getId(), cp.parsers[0]);
                 }
 
             }
@@ -71,10 +73,6 @@
         return parsers;
     }
 
-    public LongMap<ConstantMap> getConstantPools() {
-        return constantPools;
-    }
-
     public LongMap<Type> getTypeMap() {
         return types;
     }
@@ -82,17 +80,17 @@
     private EventParser createEventParser(EventType eventType) throws IOException {
         List<Parser> parsers = new ArrayList<Parser>();
         for (ValueDescriptor f : eventType.getFields()) {
-            parsers.add(createParser(f));
+            parsers.add(createParser(f, true));
         }
         return new EventParser(timeConverter, eventType, parsers.toArray(new Parser[0]));
     }
 
-    private Parser createParser(ValueDescriptor v) throws IOException {
+    private Parser createParser(ValueDescriptor v, boolean event) throws IOException {
         boolean constantPool = PrivateAccess.getInstance().isConstantPool(v);
         if (v.isArray()) {
             Type valueType = PrivateAccess.getInstance().getType(v);
             ValueDescriptor element = PrivateAccess.getInstance().newValueDescriptor(v.getName(), valueType, v.getAnnotationElements(), 0, constantPool, null);
-            return new ArrayParser(createParser(element));
+            return new ArrayParser(createParser(element, event));
         }
         long id = v.getTypeId();
         Type type = types.get(id);
@@ -100,25 +98,29 @@
             throw new IOException("Type '" + v.getTypeName() + "' is not defined");
         }
         if (constantPool) {
-            ConstantMap pool = constantPools.get(id);
-            if (pool == null) {
-                pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type.getName());
-                constantPools.put(id, pool);
+            ConstantLookup lookup = constantLookups.get(id);
+            if (lookup == null) {
+                ConstantMap pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type.getName());
+                lookup = new ConstantLookup(pool, type);
+                constantLookups.put(id, lookup);
             }
-            return new ConstantMapValueParser(pool);
+            if (event) {
+                return new EventValueConstantParser(lookup);
+            }
+            return new ConstantValueParser(lookup);
         }
         Parser parser = parsers.get(id);
         if (parser == null) {
             if (!v.getFields().isEmpty()) {
-                return createCompositeParser(type);
+                return createCompositeParser(type, event);
             } else {
-                return registerParserType(type, createPrimitiveParser(type));
+                return registerParserType(type, createPrimitiveParser(type, constantPool));
             }
         }
         return parser;
     }
 
-    private Parser createPrimitiveParser(Type type) throws IOException {
+    private Parser createPrimitiveParser(Type type, boolean event) throws IOException {
         switch (type.getName()) {
         case "int":
             return new IntegerParser();
@@ -138,8 +140,9 @@
             return new ByteParser();
         case "java.lang.String":
             ConstantMap pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type.getName());
-            constantPools.put(type.getId(), pool);
-            return new StringParser(pool);
+            ConstantLookup lookup = new ConstantLookup(pool, type);
+            constantLookups.put(type.getId(), lookup);
+            return new StringParser(lookup, event);
         default:
             throw new IOException("Unknown primitive type " + type.getName());
         }
@@ -155,7 +158,7 @@
         return parser;
     }
 
-    private CompositeParser createCompositeParser(Type type) throws IOException {
+    private CompositeParser createCompositeParser(Type type, boolean event) throws IOException {
         List<ValueDescriptor> vds = type.getFields();
         Parser[] parsers = new Parser[vds.size()];
         CompositeParser composite = new CompositeParser(parsers);
@@ -164,7 +167,7 @@
 
         int index = 0;
         for (ValueDescriptor vd : vds) {
-            parsers[index++] = createParser(vd);
+            parsers[index++] = createParser(vd, event);
         }
         return composite;
     }
@@ -174,6 +177,11 @@
         public Object parse(RecordingInput input) throws IOException {
             return input.readBoolean() ? Boolean.TRUE : Boolean.FALSE;
         }
+
+        @Override
+        public void skip(RecordingInput input) throws IOException {
+            input.skipBytes(1);
+        }
     }
 
     private static final class ByteParser extends Parser {
@@ -181,19 +189,50 @@
         public Object parse(RecordingInput input) throws IOException {
             return Byte.valueOf(input.readByte());
         }
+
+        @Override
+        public void skip(RecordingInput input) throws IOException {
+            input.skipBytes(1);
+        }
     }
 
     private static final class LongParser extends Parser {
+        private Object lastLongObject = Long.valueOf(0);
+        private long last = 0;
+
         @Override
         public Object parse(RecordingInput input) throws IOException {
-            return Long.valueOf(input.readLong());
+            long l = input.readLong();
+            if (l != last) {
+                last = l;
+                lastLongObject = Long.valueOf(l);
+            }
+            return lastLongObject;
+        }
+
+        @Override
+        public void skip(RecordingInput input) throws IOException {
+            input.readLong();
         }
     }
 
     private static final class IntegerParser extends Parser {
+        private Integer lastIntegergObject = Integer.valueOf(0);
+        private int last = 0;
+
         @Override
         public Object parse(RecordingInput input) throws IOException {
-            return Integer.valueOf(input.readInt());
+            int i = input.readInt();
+            if (i != last) {
+                last = i;
+                lastIntegergObject = Integer.valueOf(i);
+            }
+            return lastIntegergObject;
+        }
+
+        @Override
+        public void skip(RecordingInput input) throws IOException {
+            input.readInt();
         }
     }
 
@@ -202,6 +241,11 @@
         public Object parse(RecordingInput input) throws IOException {
             return Short.valueOf(input.readShort());
         }
+
+        @Override
+        public void skip(RecordingInput input) throws IOException {
+            input.readShort();
+        }
     }
 
     private static final class CharacterParser extends Parser {
@@ -209,6 +253,11 @@
         public Object parse(RecordingInput input) throws IOException {
             return Character.valueOf(input.readChar());
         }
+
+        @Override
+        public void skip(RecordingInput input) throws IOException {
+            input.readChar();
+        }
     }
 
     private static final class FloatParser extends Parser {
@@ -216,6 +265,11 @@
         public Object parse(RecordingInput input) throws IOException {
             return Float.valueOf(input.readFloat());
         }
+
+        @Override
+        public void skip(RecordingInput input) throws IOException {
+            input.skipBytes(Float.SIZE);
+        }
     }
 
     private static final class DoubleParser extends Parser {
@@ -223,33 +277,10 @@
         public Object parse(RecordingInput input) throws IOException {
             return Double.valueOf(input.readDouble());
         }
-    }
-
-    private static final class StringParser extends Parser {
-        private final ConstantMap stringConstantMap;
-        private String last;
-
-        StringParser(ConstantMap stringConstantMap) {
-            this.stringConstantMap = stringConstantMap;
-        }
 
         @Override
-        public Object parse(RecordingInput input) throws IOException {
-            String s = parseEncodedString(input);
-            if (!Objects.equals(s, last)) {
-                last = s;
-            }
-            return last;
-        }
-
-        private String parseEncodedString(RecordingInput input) throws IOException {
-            byte encoding = input.readByte();
-            if (encoding == RecordingInput.STRING_ENCODING_CONSTANT_POOL) {
-                long id = input.readLong();
-                return (String) stringConstantMap.get(id);
-            } else {
-                return input.readEncodedString(encoding);
-            }
+        public void skip(RecordingInput input) throws IOException {
+            input.skipBytes(Double.SIZE);
         }
     }
 
@@ -269,9 +300,17 @@
             }
             return array;
         }
+
+        @Override
+        public void skip(RecordingInput input) throws IOException {
+            final int size = input.readInt();
+            for (int i = 0; i < size; i++) {
+                elementParser.skip(input);
+            }
+        }
     }
 
-    private final static class CompositeParser extends Parser {
+    final static class CompositeParser extends Parser {
         private final Parser[] parsers;
 
         public CompositeParser(Parser[] valueParsers) {
@@ -286,18 +325,54 @@
             }
             return values;
         }
+
+        @Override
+        public void skip(RecordingInput input) throws IOException {
+            for (int i = 0; i < parsers.length; i++) {
+                parsers[i].skip(input);
+            }
+        }
     }
 
-    private static final class ConstantMapValueParser extends Parser {
-        private final ConstantMap pool;
-
-        ConstantMapValueParser(ConstantMap pool) {
-            this.pool = pool;
+    public static final class EventValueConstantParser extends Parser {
+        private final ConstantLookup lookup;
+        private Object lastValue = 0;
+        private long lastKey = -1;
+        EventValueConstantParser(ConstantLookup lookup) {
+            this.lookup = lookup;
         }
 
         @Override
         public Object parse(RecordingInput input) throws IOException {
-            return pool.get(input.readLong());
+            long key = input.readLong();
+            if (key == lastKey) {
+                return lastValue;
+            }
+            lastKey = key;
+            lastValue = lookup.getCurrentResolved(key);
+            return lastValue;
+        }
+
+        @Override
+        public void skip(RecordingInput input) throws IOException {
+            input.readLong();
+        }
+    }
+
+    public static final class ConstantValueParser extends Parser {
+        private final ConstantLookup lookup;
+        ConstantValueParser(ConstantLookup lookup) {
+            this.lookup = lookup;
+        }
+
+        @Override
+        public Object parse(RecordingInput input) throws IOException {
+            return lookup.getCurrent(input.readLong());
+        }
+
+        @Override
+        public void skip(RecordingInput input) throws IOException {
+            input.readLong();
         }
     }
 }
--- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,11 +25,13 @@
 
 package jdk.jfr.consumer;
 
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.time.Duration;
 import java.time.Instant;
 import java.time.OffsetDateTime;
+import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 
@@ -37,6 +39,9 @@
 import jdk.jfr.Timestamp;
 import jdk.jfr.ValueDescriptor;
 import jdk.jfr.internal.PrivateAccess;
+import jdk.jfr.internal.Type;
+import jdk.jfr.internal.consumer.Parser;
+import jdk.jfr.internal.consumer.RecordingInternals;
 import jdk.jfr.internal.tool.PrettyWriter;
 
 /**
@@ -51,6 +56,33 @@
  */
 public class RecordedObject {
 
+    static{
+        RecordingInternals.INSTANCE = new RecordingInternals() {
+            public List<Type> readTypes(RecordingFile file) throws IOException {
+                return file.readTypes();
+            }
+
+            public boolean isLastEventInChunk(RecordingFile file) {
+                return file.isLastEventInChunk;
+            }
+
+            @Override
+            public Object getOffsetDataTime(RecordedObject event, String name) {
+                return event.getOffsetDateTime(name);
+            }
+
+            @Override
+            public void sort(List<RecordedEvent> events) {
+               Collections.sort(events, (e1, e2) -> Long.compare(e1.endTime, e2.endTime));
+            }
+
+            @Override
+            public Parser newStringParser() {
+                return new StringParser(null, false);
+            }
+        };
+    }
+
     private final static class UnsignedValue {
         private final Object o;
 
--- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingFile.java	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingFile.java	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,6 @@
 import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 
@@ -41,7 +40,6 @@
 import jdk.jfr.internal.Type;
 import jdk.jfr.internal.consumer.ChunkHeader;
 import jdk.jfr.internal.consumer.RecordingInput;
-import jdk.jfr.internal.consumer.RecordingInternals;
 
 /**
  * A recording file.
@@ -62,29 +60,8 @@
  * @since 9
  */
 public final class RecordingFile implements Closeable {
-    static{
-        RecordingInternals.INSTANCE = new RecordingInternals() {
-            public List<Type> readTypes(RecordingFile file) throws IOException {
-                return file.readTypes();
-            }
 
-            public boolean isLastEventInChunk(RecordingFile file) {
-                return file.isLastEventInChunk;
-            }
-
-            @Override
-            public Object getOffsetDataTime(RecordedObject event, String name) {
-                return event.getOffsetDateTime(name);
-            }
-
-            @Override
-            public void sort(List<RecordedEvent> events) {
-               Collections.sort(events, (e1, e2) -> Long.compare(e1.endTime, e2.endTime));
-            }
-        };
-    }
-
-    private boolean isLastEventInChunk;
+    boolean isLastEventInChunk;
     private final File file;
     private RecordingInput input;
     private ChunkParser chunkParser;
@@ -154,14 +131,15 @@
      */
     public List<EventType> readEventTypes() throws IOException {
         ensureOpen();
+        MetadataDescriptor previous = null;
         List<EventType> types = new ArrayList<>();
         HashSet<Long> foundIds = new HashSet<>();
         try (RecordingInput ri = new RecordingInput(file)) {
             ChunkHeader ch = new ChunkHeader(ri);
-            aggregateEventTypeForChunk(ch, types, foundIds);
+            aggregateEventTypeForChunk(ch, null, types, foundIds);
             while (!ch.isLastChunk()) {
                 ch = ch.nextHeader();
-                aggregateEventTypeForChunk(ch, types, foundIds);
+                previous = aggregateEventTypeForChunk(ch, previous, types, foundIds);
             }
         }
         return types;
@@ -169,37 +147,41 @@
 
     List<Type> readTypes() throws IOException  {
         ensureOpen();
+        MetadataDescriptor previous = null;
         List<Type> types = new ArrayList<>();
         HashSet<Long> foundIds = new HashSet<>();
         try (RecordingInput ri = new RecordingInput(file)) {
             ChunkHeader ch = new ChunkHeader(ri);
-            aggregateTypeForChunk(ch, types, foundIds);
+            ch.awaitFinished();
+            aggregateTypeForChunk(ch, null, types, foundIds);
             while (!ch.isLastChunk()) {
                 ch = ch.nextHeader();
-                aggregateTypeForChunk(ch, types, foundIds);
+                previous = aggregateTypeForChunk(ch, previous, types, foundIds);
             }
         }
         return types;
     }
 
-    private void aggregateTypeForChunk(ChunkHeader ch, List<Type> types, HashSet<Long> foundIds) throws IOException {
-        MetadataDescriptor m = ch.readMetadata();
+    private MetadataDescriptor aggregateTypeForChunk(ChunkHeader ch, MetadataDescriptor previous, List<Type> types, HashSet<Long> foundIds) throws IOException {
+        MetadataDescriptor m = ch.readMetadata(previous);
         for (Type t : m.getTypes()) {
             if (!foundIds.contains(t.getId())) {
                 types.add(t);
                 foundIds.add(t.getId());
             }
         }
+        return m;
     }
 
-    private static void aggregateEventTypeForChunk(ChunkHeader ch, List<EventType> types, HashSet<Long> foundIds) throws IOException {
-        MetadataDescriptor m = ch.readMetadata();
+    private static MetadataDescriptor aggregateEventTypeForChunk(ChunkHeader ch,  MetadataDescriptor previous, List<EventType> types, HashSet<Long> foundIds) throws IOException {
+        MetadataDescriptor m = ch.readMetadata(previous);
         for (EventType t : m.getEventTypes()) {
             if (!foundIds.contains(t.getId())) {
                 types.add(t);
                 foundIds.add(t.getId());
             }
         }
+        return m;
     }
 
     /**
@@ -246,6 +228,11 @@
         }
     }
 
+    // package protected
+    File getFile() {
+        return file;
+    }
+
     // either sets next to an event or sets eof to true
     private void findNext() throws IOException {
         while (nextEvent == null) {
@@ -266,4 +253,6 @@
             throw new IOException("Stream Closed");
         }
     }
+
+
 }
--- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/TimeConverter.java	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/TimeConverter.java	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -69,4 +69,8 @@
     public ZoneOffset getZoneOffset() {
         return zoneOffet;
     }
+
+    public long convertDurationNanos(long durationNanos) {
+        return (long) (durationNanos * divisor);
+    }
 }
--- a/src/jdk.jfr/share/classes/jdk/jfr/events/ActiveRecordingEvent.java	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/events/ActiveRecordingEvent.java	Fri May 17 16:02:27 2019 +0200
@@ -53,6 +53,10 @@
     @Timespan(Timespan.MILLISECONDS)
     public long maxAge;
 
+    @Label("Flush Interval")
+    @Timespan(Timespan.MILLISECONDS)
+    public long flushInterval;
+
     @Label("Max Size")
     @DataAmount
     public long maxSize;
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventWriter.java	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventWriter.java	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,7 @@
 package jdk.jfr.internal;
 
 import jdk.internal.misc.Unsafe;
-import jdk.jfr.internal.consumer.RecordingInput;
+import jdk.jfr.internal.consumer.StringEncoding;
 
 /**
  * Class must reside in a package with package restriction.
@@ -115,18 +115,18 @@
 
     public void putString(String s, StringPool pool) {
         if (s == null) {
-            putByte(RecordingInput.STRING_ENCODING_NULL);
+            putByte(StringEncoding.STRING_ENCODING_NULL);
             return;
         }
         int length = s.length();
         if (length == 0) {
-            putByte(RecordingInput.STRING_ENCODING_EMPTY_STRING);
+            putByte(StringEncoding.STRING_ENCODING_EMPTY_STRING);
             return;
         }
         if (length > StringPool.MIN_LIMIT && length < StringPool.MAX_LIMIT) {
             long l = StringPool.addString(s);
             if (l > 0) {
-                putByte(RecordingInput.STRING_ENCODING_CONSTANT_POOL);
+                putByte(StringEncoding.STRING_ENCODING_CONSTANT_POOL);
                 putLong(l);
                 return;
             }
@@ -138,7 +138,7 @@
     private void putStringValue(String s) {
         int length = s.length();
         if (isValidForSize(1 + 5 + 3 * length)) {
-            putUncheckedByte(RecordingInput.STRING_ENCODING_CHAR_ARRAY); // 1 byte
+            putUncheckedByte(StringEncoding.STRING_ENCODING_CHAR_ARRAY); // 1 byte
             putUncheckedInt(length); // max 5 bytes
             for (int i = 0; i < length; i++) {
                 putUncheckedChar(s.charAt(i)); // max 3 bytes
@@ -197,11 +197,7 @@
         if (currentPosition + requestedSize > maxPosition) {
             flushOnEnd = flush(usedSize(), requestedSize);
             // retry
-            if (currentPosition + requestedSize > maxPosition) {
-                Logger.log(LogTag.JFR_SYSTEM,
-                           LogLevel.WARN, () ->
-                               "Unable to commit. Requested size " + requestedSize + " too large");
-                valid = false;
+            if (!valid) {
                 return false;
             }
         }
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -270,7 +270,6 @@
      *
      * @param file the file where data should be written, or null if it should
      *        not be copied out (in memory).
-     *
      * @throws IOException
      */
     public native void setOutput(String file);
@@ -460,6 +459,20 @@
     public static native boolean flush(EventWriter writer, int uncommittedSize, int requestedSize);
 
     /**
+     * Flushes all thread buffers to disk and the constant pool data needed to read
+     * them.
+     * <p>
+     * When the method returns, the chunk header should be updated with valid
+     * pointers to the metadata event, last check point event, correct file size and
+     * the generation id.
+     *
+     * @param includeMetadata {@code true} if metadata event should be written, {@code false}
+     *        otherwise
+     * @param flushCounter the (flushCounter + 1= should be written to the chunk header, by default the
+     *        value in the chunk header should be {@code 1} and set {@code 0} once the chunk is complete.
+     */
+    public native void flush(boolean includeMetadata, short flushCounter);
+    /**
      * Sets the location of the disk repository, to be used at an emergency
      * dump.
      *
@@ -523,4 +536,30 @@
      * @return if it is time to perform a chunk rotation
      */
     public native boolean shouldRotateDisk();
+
+    /**
+     * Exclude a thread from the jfr system
+     *
+     */
+    public native void exclude(Thread thread);
+
+    /**
+     * Include a thread back into the jfr system
+     *
+     */
+    public native void include(Thread thread);
+
+    /**
+     * Test if a thread ius currently excluded from the jfr system.
+     *
+     * @return is thread currently excluded
+     */
+    public native boolean isExcluded(Thread thread);
+
+    /**
+     * Get the start time in nanos from the header of the current chunk
+     *
+     *@return start time of the recording in nanos, -1 in case of in-memory
+     */
+    public native long getChunkStartNanos();
 }
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/LogTag.java	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/LogTag.java	Fri May 17 16:02:27 2019 +0200
@@ -63,21 +63,25 @@
      */
     JFR_SYSTEM_METADATA(6),
     /**
+     *  Covers streaming (for Hotspot developers)
+     */
+    JFR_SYSTEM_STREAMING(7),
+    /**
      *  Covers metadata for Java user (for Hotspot developers)
      */
-    JFR_METADATA(7),
+    JFR_METADATA(8),
     /**
      * Covers events (for users of the JDK)
      */
-    JFR_EVENT(8),
+    JFR_EVENT(9),
     /**
      * Covers setting (for users of the JDK)
      */
-    JFR_SETTING(9),
+    JFR_SETTING(10),
     /**
      * Covers usage of jcmd with JFR
      */
-    JFR_DCMD(10);
+    JFR_DCMD(11);
 
     /* set from native side */
     volatile int tagSetLevel = 100; // prevent logging if JVM log system has not been initialized
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataDescriptor.java	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataDescriptor.java	Fri May 17 16:02:27 2019 +0200
@@ -25,7 +25,6 @@
 
 package jdk.jfr.internal;
 
-import java.io.DataInput;
 import java.io.DataOutput;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -35,6 +34,7 @@
 import java.util.TimeZone;
 
 import jdk.jfr.EventType;
+import jdk.jfr.internal.consumer.RecordingInput;
 
 /**
  * Metadata about a chunk
@@ -214,6 +214,7 @@
     long gmtOffset;
     String locale;
     Element root;
+    public long metadataId;
 
     // package private
     MetadataDescriptor() {
@@ -252,7 +253,7 @@
         return locale;
     }
 
-    public static MetadataDescriptor read(DataInput input) throws IOException {
+    public static MetadataDescriptor read(RecordingInput input) throws IOException {
         MetadataReader r = new MetadataReader(input);
         return r.getDescriptor();
     }
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataReader.java	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataReader.java	Fri May 17 16:02:27 2019 +0200
@@ -49,6 +49,9 @@
 import jdk.jfr.SettingDescriptor;
 import jdk.jfr.ValueDescriptor;
 import jdk.jfr.internal.MetadataDescriptor.Element;
+import jdk.jfr.internal.consumer.Parser;
+import jdk.jfr.internal.consumer.RecordingInput;
+import jdk.jfr.internal.consumer.RecordingInternals;
 
 /**
  * Parses metadata.
@@ -61,12 +64,13 @@
     private final MetadataDescriptor descriptor;
     private final Map<Long, Type> types = new HashMap<>();
 
-    public MetadataReader(DataInput input) throws IOException {
+    public MetadataReader(RecordingInput input) throws IOException {
         this.input = input;
         int size = input.readInt();
         this.pool = new ArrayList<>(size);
+        Parser p = RecordingInternals.instance().newStringParser();
         for (int i = 0; i < size; i++) {
-            this.pool.add(input.readUTF());
+            this.pool.add((String) p.parse(input));
         }
         descriptor = new MetadataDescriptor();
         Element root = createElement();
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -61,6 +61,8 @@
     private boolean staleMetadata = true;
     private boolean unregistered;
     private long lastUnloaded = -1;
+    private boolean flushMetadata;
+    private short flushCounter = 0;
 
     public MetadataRepository() {
         initializeJVMEventTypes();
@@ -142,6 +144,7 @@
         typeLibrary.addType(handler.getPlatformEventType());
         if (jvm.isRecording()) {
             storeDescriptorInJVM(); // needed for emergency dump
+            flushMetadata = true;
             settingsManager.setEventControl(handler.getEventControl());
             settingsManager.updateRetransform(Collections.singletonList((eventClass)));
         } else {
@@ -255,12 +258,12 @@
         staleMetadata = true;
     }
 
-    // Lock around setOutput ensures that other threads dosn't
-    // emit event after setOutput and unregister the event class, before a call
+    // Lock around setOutput ensures that other threads don't
+    // emit events after setOutput and unregister the event class, before a call
     // to storeDescriptorInJVM
-    synchronized void setOutput(String filename) {
+    synchronized void setOutput(String filename) {
         jvm.setOutput(filename);
-
+        flushMetadata = false;
         unregisterUnloaded();
         if (unregistered) {
             staleMetadata = typeLibrary.clearUnregistered();
@@ -269,6 +272,7 @@
         if (staleMetadata) {
             storeDescriptorInJVM();
         }
+        flushCounter = 0;
     }
 
     private void unregisterUnloaded() {
@@ -307,4 +311,11 @@
         throw new InternalError("Mirror class must have annotation " + MirrorEvent.class.getName());
     }
 
+    public synchronized void flush() {
+        jvm.flush(flushMetadata || flushCounter == 0, ++flushCounter);
+        if (flushCounter == Short.MAX_VALUE) {
+            flushCounter = 0;
+        }
+        this.flushMetadata = false;
+    }
 }
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataWriter.java	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataWriter.java	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -53,7 +53,7 @@
 import jdk.jfr.ValueDescriptor;
 import jdk.jfr.internal.MetadataDescriptor.Attribute;
 import jdk.jfr.internal.MetadataDescriptor.Element;
-import jdk.jfr.internal.consumer.RecordingInput;
+import jdk.jfr.internal.consumer.StringEncoding;
 
 /**
  * Class responsible for converting a list of types into a format that can be
@@ -94,10 +94,10 @@
 
     private void writeString(DataOutput out, String s) throws IOException {
         if (s == null ) {
-            out.writeByte(RecordingInput.STRING_ENCODING_NULL);
+            out.writeByte(StringEncoding.STRING_ENCODING_NULL);
             return;
         }
-        out.writeByte(RecordingInput.STRING_ENCODING_CHAR_ARRAY); // encoding UTF-16
+        out.writeByte(StringEncoding.STRING_ENCODING_CHAR_ARRAY); // encoding UTF-16
         int length = s.length();
         writeInt(out, length);
             for (int i = 0; i < length; i++) {
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformEventType.java	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformEventType.java	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -69,7 +69,7 @@
         super(name, Type.SUPER_TYPE_EVENT, id);
         this.dynamicSettings = dynamicSettings;
         this.isJVM = Type.isDefinedByJVM(id);
-        this.isMethodSampling = name.equals(Type.EVENT_NAME_PREFIX + "ExecutionSample") || name.equals(Type.EVENT_NAME_PREFIX + "NativeMethodSample");
+        this.isMethodSampling = isJVM && (name.equals(Type.EVENT_NAME_PREFIX + "ExecutionSample") || name.equals(Type.EVENT_NAME_PREFIX + "NativeMethodSample"));
         this.isJDK = isJDK;
         this.stackTraceOffset = stackTraceOffset(name, isJDK);
     }
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecorder.java	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecorder.java	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,7 +31,6 @@
 import static jdk.jfr.internal.LogTag.JFR;
 import static jdk.jfr.internal.LogTag.JFR_SYSTEM;
 
-import java.io.IOException;
 import java.security.AccessControlContext;
 import java.security.AccessController;
 import java.time.Duration;
@@ -96,6 +95,7 @@
             Thread t = SecuritySupport.createThreadWitNoPermissions("Permissionless thread", ()-> {
                 result.add(new Timer("JFR Recording Scheduler", true));
             });
+            jvm.exclude(t);
             t.start();
             t.join();
             return result.get(0);
@@ -204,7 +204,7 @@
         repository.clear();
     }
 
-    synchronized void start(PlatformRecording recording) {
+    synchronized long start(PlatformRecording recording) {
         // State can only be NEW or DELAYED because of previous checks
         Instant now = Instant.now();
         recording.setStartTime(now);
@@ -215,14 +215,17 @@
         }
         boolean toDisk = recording.isToDisk();
         boolean beginPhysical = true;
+        long streamInterval = recording.getStreamIntervalMillis();
         for (PlatformRecording s : getRecordings()) {
             if (s.getState() == RecordingState.RUNNING) {
                 beginPhysical = false;
                 if (s.isToDisk()) {
                     toDisk = true;
                 }
+                streamInterval = Math.min(streamInterval, s.getStreamIntervalMillis());
             }
         }
+        long startNanos = -1;
         if (beginPhysical) {
             RepositoryChunk newChunk = null;
             if (toDisk) {
@@ -232,7 +235,8 @@
                 MetadataRepository.getInstance().setOutput(null);
             }
             currentChunk = newChunk;
-            jvm.beginRecording_();
+            jvm.beginRecording_();
+            startNanos = jvm.getChunkStartNanos();
             recording.setState(RecordingState.RUNNING);
             updateSettings();
             writeMetaEvents();
@@ -241,7 +245,8 @@
             if (toDisk) {
                 newChunk = repository.newChunk(now);
                 RequestEngine.doChunkEnd();
-                MetadataRepository.getInstance().setOutput(newChunk.getUnfishedFile().toString());
+                MetadataRepository.getInstance().setOutput(newChunk.getUnfishedFile().toString());
+                startNanos = jvm.getChunkStartNanos();
             }
             recording.setState(RecordingState.RUNNING);
             updateSettings();
@@ -251,8 +256,12 @@
             }
             currentChunk = newChunk;
         }
+        if (toDisk) {
+            RequestEngine.setFlushInterval(streamInterval);
+        }
+        RequestEngine.doChunkBegin();
 
-        RequestEngine.doChunkBegin();
+        return startNanos;
     }
 
     synchronized void stop(PlatformRecording recording) {
@@ -267,6 +276,7 @@
         Instant now = Instant.now();
         boolean toDisk = false;
         boolean endPhysical = true;
+        long streamInterval = Long.MAX_VALUE;
         for (PlatformRecording s : getRecordings()) {
             RecordingState rs = s.getState();
             if (s != recording && RecordingState.RUNNING == rs) {
@@ -274,6 +284,7 @@
                 if (s.isToDisk()) {
                     toDisk = true;
                 }
+                streamInterval = Math.min(streamInterval, s.getStreamIntervalMillis());
             }
         }
         OldObjectSample.emit(recording);
@@ -309,6 +320,13 @@
             currentChunk = newChunk;
             RequestEngine.doChunkBegin();
         }
+
+        if (toDisk) {
+            RequestEngine.setFlushInterval(streamInterval);
+        } else {
+            RequestEngine.setFlushInterval(Long.MAX_VALUE);
+        }
+
         recording.setState(RecordingState.STOPPED);
     }
 
@@ -395,6 +413,7 @@
                 r.appendChunk(chunk);
             }
         }
+        FilePurger.purge();
     }
 
     private void writeMetaEvents() {
@@ -415,6 +434,8 @@
                     event.maxSize = size == null ? Long.MAX_VALUE : size;
                     Instant start = r.getStartTime();
                     event.recordingStart = start == null ? Long.MAX_VALUE : start.toEpochMilli();
+                    Duration fi = r.getFlushInterval();
+                    event.flushInterval = fi == null ? Long.MAX_VALUE : fi.toMillis();
                     event.commit();
                 }
             }
@@ -448,7 +469,7 @@
                 JVM.FILE_DELTA_CHANGE.wait(duration < 10 ? 10 : duration);
             }
         } catch (InterruptedException e) {
-            e.printStackTrace();
+            // Ignore
         }
     }
 
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -84,6 +84,7 @@
     private TimerTask startTask;
     private AccessControlContext noDestinationDumpOnExitAccessControlContext;
     private boolean shuoldWriteActiveRecordingEvent = true;
+    private Duration flushInterval;
 
     PlatformRecording(PlatformRecorder recorder, long id) {
         // Typically the access control context is taken
@@ -98,9 +99,10 @@
         this.name = String.valueOf(id);
     }
 
-    public void start() {
+    public long start() {
         RecordingState oldState;
         RecordingState newState;
+        long startNanos = -1;
         synchronized (recorder) {
             oldState = getState();
             if (!Utils.isBefore(state, RecordingState.RUNNING)) {
@@ -111,7 +113,7 @@
                 startTask = null;
                 startTime = null;
             }
-            recorder.start(this);
+            startNanos = recorder.start(this);
             Logger.log(LogTag.JFR, LogLevel.INFO, () -> {
                 // Only print non-default values so it easy to see
                 // which options were added
@@ -143,6 +145,8 @@
             newState = getState();
         }
         notifyIfStateChanged(oldState, newState);
+
+        return startNanos;
     }
 
     public boolean stop(String reason) {
@@ -775,4 +779,28 @@
     public SafePath getDumpOnExitDirectory()  {
         return this.dumpOnExitDirectory;
     }
+
+    public void setFlushInterval(Duration interval) {
+        synchronized (recorder) {
+            if (getState() == RecordingState.CLOSED) {
+                throw new IllegalStateException("Can't set stream interval when recording is closed");
+            }
+            this.flushInterval = interval;
+        }
+    }
+
+    public Duration getFlushInterval() {
+        synchronized (recorder) {
+            return flushInterval;
+        }
+    }
+
+    public long getStreamIntervalMillis() {
+        synchronized (recorder) {
+            if (flushInterval != null) {
+                return flushInterval.toMillis();
+            }
+            return Long.MAX_VALUE;
+        }
+    }
 }
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/Repository.java	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/Repository.java	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -43,6 +43,7 @@
 
     public final static DateTimeFormatter REPO_DATE_FORMAT = DateTimeFormatter
             .ofPattern("yyyy_MM_dd_HH_mm_ss");
+    private static final String JFR_REPOSITORY_LOCATION_PROPERTY = "jdk.jfr.repository";
 
     private final Set<SafePath> cleanupDirectories = new HashSet<>();
     private SafePath baseLocation;
@@ -55,7 +56,7 @@
         return instance;
     }
 
-    public synchronized void setBasePath(SafePath baseLocation) throws Exception {
+    public synchronized void setBasePath(SafePath baseLocation) throws IOException  {
         // Probe to see if repository can be created, needed for fail fast
         // during JVM startup or JFR.configure
         this.repository = createRepository(baseLocation);
@@ -69,7 +70,7 @@
         this.baseLocation = baseLocation;
     }
 
-    synchronized void ensureRepository() throws Exception {
+    public synchronized void ensureRepository() throws IOException {
         if (baseLocation == null) {
             setBasePath(SecuritySupport.JAVA_IO_TMPDIR);
         }
@@ -91,7 +92,7 @@
         }
     }
 
-    private static SafePath createRepository(SafePath basePath) throws Exception {
+    private static SafePath createRepository(SafePath basePath) throws IOException {
         SafePath canonicalBaseRepositoryPath = createRealBasePath(basePath);
         SafePath f = null;
 
@@ -108,13 +109,14 @@
         }
 
         if (i == MAX_REPO_CREATION_RETRIES) {
-            throw new Exception("Unable to create JFR repository directory using base location (" + basePath + ")");
+            throw new IOException("Unable to create JFR repository directory using base location (" + basePath + ")");
         }
         SafePath canonicalRepositoryPath = SecuritySupport.toRealPath(f);
+        SecuritySupport.setProperty(JFR_REPOSITORY_LOCATION_PROPERTY, canonicalRepositoryPath.toString());
         return canonicalRepositoryPath;
     }
 
-    private static SafePath createRealBasePath(SafePath safePath) throws Exception {
+    private static SafePath createRealBasePath(SafePath safePath) throws IOException {
         if (SecuritySupport.exists(safePath)) {
             if (!SecuritySupport.isWritable(safePath)) {
                 throw new IOException("JFR repository directory (" + safePath.toString() + ") exists, but isn't writable");
@@ -154,7 +156,7 @@
                 SecuritySupport.clearDirectory(p);
                 Logger.log(LogTag.JFR, LogLevel.INFO, "Removed repository " + p);
             } catch (IOException e) {
-                Logger.log(LogTag.JFR, LogLevel.ERROR, "Repository " + p + " could not be removed at shutdown: " + e.getMessage());
+                Logger.log(LogTag.JFR, LogLevel.INFO, "Repository " + p + " could not be removed at shutdown: " + e.getMessage());
             }
         }
     }
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/RepositoryChunk.java	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/RepositoryChunk.java	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -63,10 +63,10 @@
                 LocalDateTime.ofInstant(startTime, z.getZone()));
         this.startTime = startTime;
         this.repositoryPath = path;
-        this.unFinishedFile = findFileName(repositoryPath, fileName, ".part");
+        this.unFinishedFile = findFileName(repositoryPath, fileName, ".jfr");
         this.file = findFileName(repositoryPath, fileName, ".jfr");
         this.unFinishedRAF = SecuritySupport.createRandomAccessFile(unFinishedFile);
-        SecuritySupport.touch(file);
+ //       SecuritySupport.touch(file);
     }
 
     private static SafePath findFileName(SafePath directory, String name, String extension) throws Exception {
@@ -105,8 +105,6 @@
     private static long finish(SafePath unFinishedFile, SafePath file) throws IOException {
         Objects.requireNonNull(unFinishedFile);
         Objects.requireNonNull(file);
-        SecuritySupport.delete(file);
-        SecuritySupport.moveReplace(unFinishedFile, file);
         return SecuritySupport.getFileSize(file);
     }
 
@@ -123,9 +121,11 @@
             SecuritySupport.delete(f);
             Logger.log(LogTag.JFR, LogLevel.DEBUG, () -> "Repository chunk " + f + " deleted");
         } catch (IOException e) {
-            Logger.log(LogTag.JFR, LogLevel.ERROR, ()  -> "Repository chunk " + f + " could not be deleted: " + e.getMessage());
+            // Probably happens because file is being streamed
+            // on Windows where files in use can't be removed.
+            Logger.log(LogTag.JFR, LogLevel.DEBUG, ()  -> "Repository chunk " + f + " could not be deleted: " + e.getMessage());
             if (f != null) {
-                SecuritySupport.deleteOnExit(f);
+                FilePurger.add(f);
             }
         }
     }
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/RequestEngine.java	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/RequestEngine.java	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,6 +30,7 @@
 import java.security.PrivilegedAction;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.CopyOnWriteArrayList;
@@ -96,6 +97,8 @@
 
     private final static List<RequestHook> entries = new CopyOnWriteArrayList<>();
     private static long lastTimeMillis;
+    private static long flushInterval = Long.MAX_VALUE;
+    private static long streamDelta;
 
     public static void addHook(AccessControlContext acc, PlatformEventType type, Runnable hook) {
         Objects.requireNonNull(acc);
@@ -209,7 +212,9 @@
             lastTimeMillis = now;
             return 0;
         }
-        for (RequestHook he : entries) {
+        Iterator<RequestHook> hookIterator = entries.iterator();
+        while(hookIterator.hasNext()) {
+            RequestHook he = hookIterator.next();
             long left = 0;
             PlatformEventType es = he.type;
             // Not enabled, skip.
@@ -228,7 +233,6 @@
                 // for wait > period
                 r_delta = 0;
                 he.execute();
-                ;
             }
 
             // calculate time left
@@ -250,7 +254,36 @@
                 min = left;
             }
         }
+        // Flush should happen after all periodic events has been emitted
+        // Repeat of the above algorithm, but using the stream interval.
+        if (flushInterval != Long.MAX_VALUE) {
+            long r_period = flushInterval;
+            long r_delta = streamDelta;
+            r_delta += delta;
+            if (r_delta >= r_period) {
+                r_delta = 0;
+                MetadataRepository.getInstance().flush();
+            }
+            long left = (r_period - r_delta);
+            if (left < 0) {
+                left = 0;
+            }
+            streamDelta = r_delta;
+            if (min == 0 || left < min) {
+                min = left;
+            }
+        }
+
         lastTimeMillis = now;
         return min;
     }
+
+    public static void setFlushInterval(long interval) {
+        flushInterval = interval;
+        if (interval < flushInterval) {
+            synchronized (JVM.FILE_DELTA_CHANGE) {
+                JVM.FILE_DELTA_CHANGE.notifyAll();
+            }
+        }
+    }
 }
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/SecuritySupport.java	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/SecuritySupport.java	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -290,6 +290,10 @@
         doPrivileged(() ->  MetadataRepository.getInstance().registerMirror(eventClass), new FlightRecorderPermission(Utils.REGISTER_EVENT));
     }
 
+    public static void setProperty(String propertyName, String value) {
+        doPrivileged(() -> System.setProperty(propertyName, value), new PropertyPermission(propertyName, "write"));
+    }
+
     static boolean getBooleanProperty(String propertyName) {
         return doPrivilegedWithReturn(() -> Boolean.getBoolean(propertyName), new PropertyPermission(propertyName, "read"));
     }
@@ -330,7 +334,7 @@
         doPriviligedIO(() -> Files.walkFileTree(safePath.toPath(), new DirectoryCleaner()));
     }
 
-    static SafePath toRealPath(SafePath safePath) throws Exception {
+    static SafePath toRealPath(SafePath safePath) throws IOException {
         return new SafePath(doPrivilegedIOWithReturn(() -> safePath.toPath().toRealPath()));
     }
 
@@ -408,7 +412,7 @@
     }
 
     static Class<?> defineClass(Class<?> lookupClass, byte[] bytes) {
-        return AccessController.doPrivileged(new PrivilegedAction<>() {
+        return AccessController.doPrivileged(new PrivilegedAction<Class<?>>() {
             @Override
             public Class<?> run() {
                 try {
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/Utils.java	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/Utils.java	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -595,4 +595,10 @@
         String idText = recording == null ? "" :  "-id-" + Long.toString(recording.getId());
         return "hotspot-" + "pid-" + pid + idText + "-" + date + ".jfr";
     }
+    public static void takeNap(long millis) {
+        try {
+            Thread.sleep(millis);
+        } catch (InterruptedException e) {
+        }
+    }
 }
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,48 +25,61 @@
 
 package jdk.jfr.internal.consumer;
 
-import java.io.DataInput;
 import java.io.IOException;
 
 import jdk.jfr.internal.LogLevel;
 import jdk.jfr.internal.LogTag;
 import jdk.jfr.internal.Logger;
 import jdk.jfr.internal.MetadataDescriptor;
+import jdk.jfr.internal.Utils;
 
 public final class ChunkHeader {
+    public static final long HEADER_SIZE = 68;
+    public static final byte MARKED_FOR_DELETION = (byte) 255;
+    private static final byte UPDATING_CHUNK_HEADER = (byte) 255;
+    private static final long CHUNK_SIZE_POSITION = 8;
+    private static final long DURATION_NANOS_POSITION = 40;
+    private static final long FILE_STATE_POSITION = 64;
     private static final long METADATA_TYPE_ID = 0;
     private static final byte[] FILE_MAGIC = { 'F', 'L', 'R', '\0' };
 
     private final short major;
     private final short minor;
-    private final long chunkSize;
     private final long chunkStartTicks;
     private final long ticksPerSecond;
     private final long chunkStartNanos;
-    private final long metadataPosition;
- //   private final long absoluteInitialConstantPoolPosition;
-    private final long absoluteChunkEnd;
-    private final long absoluteEventStart;
     private final long absoluteChunkStart;
-    private final boolean lastChunk;
     private final RecordingInput input;
-    private final long durationNanos;
     private final long id;
+    private long absoluteEventStart;
+    private long chunkSize;
     private long constantPoolPosition;
+    private long metadataPosition;
+    private long durationNanos;
+    private long absoluteChunkEnd;
+    private boolean isFinished;
+    private boolean finished;
 
     public ChunkHeader(RecordingInput input) throws IOException {
         this(input, 0, 0);
     }
 
     private ChunkHeader(RecordingInput input, long absoluteChunkStart, long id) throws IOException {
+        this.absoluteChunkStart = absoluteChunkStart;
+        this.absoluteEventStart = absoluteChunkStart + HEADER_SIZE;
+        if (input.getFileSize() < HEADER_SIZE) {
+            throw new IOException("Not a complete Chunk header");
+        }
+        input.setValidSize(absoluteChunkStart + HEADER_SIZE);
         input.position(absoluteChunkStart);
         if (input.position() >= input.size()) {
-            throw new IOException("Chunk contains no data");
+           throw new IOException("Chunk contains no data");
         }
         verifyMagic(input);
         this.input = input;
         this.id = id;
-        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk " + id);
+        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: " + id);
+        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: file=" + input.getFilename());
         Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: startPosition=" + absoluteChunkStart);
         major = input.readRawShort();
         Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: major=" + major);
@@ -75,11 +88,11 @@
         if (major != 1 && major != 2) {
             throw new IOException("File version " + major + "." + minor + ". Only Flight Recorder files of version 1.x and 2.x can be read by this JDK.");
         }
-        chunkSize = input.readRawLong();
+        input.readRawLong(); // chunk size
         Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: chunkSize=" + chunkSize);
-        this.constantPoolPosition = input.readRawLong();
+        input.readRawLong(); // constant pool position
         Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: constantPoolPosition=" + constantPoolPosition);
-        metadataPosition = input.readRawLong();
+        input.readRawLong(); // metadata position
         Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: metadataPosition=" + metadataPosition);
         chunkStartNanos = input.readRawLong(); // nanos since epoch
         Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: startNanos=" + chunkStartNanos);
@@ -91,21 +104,97 @@
         Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: ticksPerSecond=" + ticksPerSecond);
         input.readRawInt(); // features, not used
 
-        // set up boundaries
-        this.absoluteChunkStart = absoluteChunkStart;
-        absoluteChunkEnd = absoluteChunkStart + chunkSize;
-        lastChunk = input.size() == absoluteChunkEnd;
-        absoluteEventStart = input.position();
+        refresh();
+        input.position(absoluteEventStart);
+    }
+    public void refresh() throws IOException {
+        while (true) {
+            byte fileState1;
+            input.positionPhysical(absoluteChunkStart + FILE_STATE_POSITION);
+            while ((fileState1 = input.readPhysicalByte()) == UPDATING_CHUNK_HEADER) {
+                Utils.takeNap(3);
+                input.positionPhysical(absoluteChunkStart + FILE_STATE_POSITION);
+            }
+            input.positionPhysical(absoluteChunkStart + CHUNK_SIZE_POSITION);
+            long chunkSize = input.readPhysicalLong();
+            long constantPoolPosition = input.readPhysicalLong();
+            long metadataPosition = input.readPhysicalLong();
+            input.positionPhysical(absoluteChunkStart + DURATION_NANOS_POSITION);
+            long durationNanos = input.readPhysicalLong();
+            input.positionPhysical(absoluteChunkStart + FILE_STATE_POSITION);
+            byte fileState2 =  input.readPhysicalByte();
+            if (fileState1 == fileState2) { // valid header
+                finished = fileState1 == 0;
+                if (constantPoolPosition != 0 && metadataPosition != 0) {
+                    Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Setting input size to " + (absoluteChunkStart + chunkSize));
+                    if (finished) {
+                        // This assumes that the whole recording
+                        // is finished if the first chunk is.
+                        // This is a limitation we may want to
+                        // remove, but greatly improves performance as
+                        // data can be read across chunk boundaries
+                        // of multi-chunk files and only once.
+                        input.setValidSize(input.getFileSize());
+                    } else {
+                        input.setValidSize(absoluteChunkStart + chunkSize);
+                    }
+                    this.chunkSize = chunkSize;
+                    Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: chunkSize=" + chunkSize);
+                    this.constantPoolPosition = constantPoolPosition;
+                    Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: constantPoolPosition=" + constantPoolPosition);
+                    this.metadataPosition = metadataPosition;
+                    Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: metadataPosition=" + metadataPosition);
+                    this.durationNanos = durationNanos;
+                    Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: durationNanos =" + durationNanos);
+                    isFinished = fileState2 == 0;
+                    Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: generation=" + fileState2);
+                    Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: finished=" + isFinished);
+                    Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: fileSize=" + input.size());
+                    absoluteChunkEnd = absoluteChunkStart + chunkSize;
+                    return;
+                }
+            }
+        }
+    }
 
-        // read metadata
-        input.position(absoluteEventStart);
+    public void awaitFinished() throws IOException {
+        if (finished) {
+            return;
+        }
+        long pos = input.position();
+        try {
+            input.positionPhysical(absoluteChunkStart + FILE_STATE_POSITION);
+            while (true) {
+                byte filestate = input.readPhysicalByte();
+                if (filestate ==0) {
+                    finished = true;
+                    return;
+                }
+                Utils.takeNap(3);
+            }
+        } finally {
+            input.position(pos);
+        }
+    }
+
+    public boolean isLastChunk() throws IOException {
+        awaitFinished();
+        // streaming files only have one chunk
+        return input.getFileSize() == absoluteChunkEnd;
+   }
+
+    public boolean isFinished() throws IOException {
+        return isFinished;
     }
 
     public ChunkHeader nextHeader() throws IOException {
         return new ChunkHeader(input, absoluteChunkEnd, id + 1);
     }
+    public MetadataDescriptor readMetadata() throws IOException {
+        return readMetadata(null);
+    }
 
-    public MetadataDescriptor readMetadata() throws IOException {
+    public MetadataDescriptor readMetadata(MetadataDescriptor previous) throws IOException {
         input.position(absoluteChunkStart + metadataPosition);
         input.readInt(); // size
         long id = input.readLong(); // event type id
@@ -115,15 +204,15 @@
         input.readLong(); // start time
         input.readLong(); // duration
         long metadataId = input.readLong();
-        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.TRACE, "Metadata id=" + metadataId);
-        // No need to read if metadataId == lastMetadataId, but we
-        // do it for verification purposes.
-        return MetadataDescriptor.read(input);
+        if (previous != null && metadataId == previous.metadataId) {
+            return previous;
+        }
+        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.TRACE, "New metadata id = " + metadataId);
+        MetadataDescriptor m =  MetadataDescriptor.read(input);
+        m.metadataId = metadataId;
+        return m;
     }
 
-    public boolean isLastChunk() {
-        return lastChunk;
-    }
 
     public short getMajor() {
         return major;
@@ -137,13 +226,22 @@
         return absoluteChunkStart;
     }
 
+    public long getAbsoluteEventStart() {
+        return absoluteEventStart;
+    }
     public long getConstantPoolPosition() {
         return constantPoolPosition;
     }
 
+    public long getMetataPosition() {
+        return metadataPosition;
+    }
     public long getStartTicks() {
         return chunkStartTicks;
     }
+    public long getChunkSize() {
+        return chunkSize;
+    }
 
     public double getTicksPerSecond() {
         return ticksPerSecond;
@@ -169,7 +267,7 @@
         return input;
     }
 
-    private static void verifyMagic(DataInput input) throws IOException {
+    private static void verifyMagic(RecordingInput input) throws IOException {
         for (byte c : FILE_MAGIC) {
             if (input.readByte() != c) {
                 throw new IOException("Not a Flight Recorder file");
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RecordingInput.java	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RecordingInput.java	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,36 +30,28 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.RandomAccessFile;
-import java.nio.charset.Charset;
 
 public final class RecordingInput implements DataInput, AutoCloseable {
 
-    public static final byte STRING_ENCODING_NULL = 0;
-    public static final byte STRING_ENCODING_EMPTY_STRING = 1;
-    public static final byte STRING_ENCODING_CONSTANT_POOL = 2;
-    public static final byte STRING_ENCODING_UTF8_BYTE_ARRAY = 3;
-    public static final byte STRING_ENCODING_CHAR_ARRAY = 4;
-    public static final byte STRING_ENCODING_LATIN1_BYTE_ARRAY = 5;
 
     private final static int DEFAULT_BLOCK_SIZE = 16 * 1024 * 1024;
-    private final static Charset UTF8 = Charset.forName("UTF-8");
-    private final static Charset LATIN1 = Charset.forName("ISO-8859-1");
 
     private static final class Block {
         private byte[] bytes = new byte[0];
         private long blockPosition;
-
+        private int size;
         boolean contains(long position) {
-            return position >= blockPosition && position < blockPosition + bytes.length;
+            return position >= blockPosition && position < blockPosition + size;
         }
 
         public void read(RandomAccessFile file, int amount) throws IOException {
             blockPosition = file.getFilePointer();
             // reuse byte array, if possible
-            if (amount != bytes.length) {
+            if (amount > bytes.length) {
                 bytes = new byte[amount];
             }
-            file.readFully(bytes);
+            this.size = amount;
+            file.readFully(bytes, 0 , amount);
         }
 
         public byte get(long position) {
@@ -68,24 +60,34 @@
     }
 
     private final RandomAccessFile file;
-    private final long size;
+    private final String filename;
     private Block currentBlock = new Block();
     private Block previousBlock = new Block();
     private long position;
     private final int blockSize;
+    private long size = -1; // Fail fast if setSize(...) has not been called before parsing
 
-    private RecordingInput(File f, int blockSize) throws IOException {
-        this.size = f.length();
+    public RecordingInput(File f, int blockSize) throws IOException {
         this.blockSize = blockSize;
+        this.filename = f.getAbsolutePath().toString();
         this.file = new RandomAccessFile(f, "r");
-        if (size < 8) {
-            throw new IOException("Not a valid Flight Recorder file. File length is only " + size + " bytes.");
+        if (f.length() < 8) {
+            throw new IOException("Not a valid Flight Recorder file. File length is only " + f.length() + " bytes.");
         }
     }
 
     public RecordingInput(File f) throws IOException {
         this(f, DEFAULT_BLOCK_SIZE);
     }
+    public void positionPhysical(long position) throws IOException {
+        file.seek(position);
+    }
+    public final byte readPhysicalByte() throws IOException {
+        return file.readByte();
+    }
+    public long readPhysicalLong() throws IOException {
+        return file.readLong();
+    }
 
     @Override
     public final byte readByte() throws IOException {
@@ -150,20 +152,20 @@
         return ((b7 & 0xFFL)) + ((b6 & 0xFFL) << 8) + ((b5 & 0xFFL) << 16) + ((b4 & 0xFFL) << 24) + ((b3 & 0xFFL) << 32) + ((b2 & 0xFFL) << 40) + ((b1 & 0xFFL) << 48) + (((long) b0) << 56);
     }
 
-    public final long position() throws IOException {
+    public final long position() {
         return position;
     }
 
     public final void position(long newPosition) throws IOException {
         if (!currentBlock.contains(newPosition)) {
             if (!previousBlock.contains(newPosition)) {
-                if (newPosition > size()) {
-                    throw new EOFException("Trying to read at " + newPosition + ", but file is only " + size() + " bytes.");
+                if (newPosition > size) {
+                    throw new EOFException("Trying to read at " + newPosition + ", but file is only " + size + " bytes.");
                 }
                 long blockStart = trimToFileSize(calculateBlockStart(newPosition));
                 file.seek(blockStart);
                 // trim amount to file size
-                long amount = Math.min(size() - blockStart, blockSize);
+                long amount = Math.min(size - blockStart, blockSize);
                 previousBlock.read(file, (int) amount);
             }
             // swap previous and current
@@ -191,7 +193,7 @@
         return newPosition - blockSize / 2;
     }
 
-    public final long size() throws IOException {
+    public final long size() {
         return size;
     }
 
@@ -245,34 +247,7 @@
     // 4, means ""
     @Override
     public String readUTF() throws IOException {
-        return readEncodedString(readByte());
-    }
-
-    public String readEncodedString(byte encoding) throws IOException {
-        if (encoding == STRING_ENCODING_NULL) {
-            return null;
-        }
-        if (encoding == STRING_ENCODING_EMPTY_STRING) {
-            return "";
-        }
-        int size = readInt();
-        if (encoding == STRING_ENCODING_CHAR_ARRAY) {
-            char[] c = new char[size];
-            for (int i = 0; i < size; i++) {
-                c[i] = readChar();
-            }
-            return new String(c);
-        }
-        byte[] bytes = new byte[size];
-        readFully(bytes); // TODO: optimize, check size, and copy only if needed
-        if (encoding == STRING_ENCODING_UTF8_BYTE_ARRAY) {
-            return new String(bytes, UTF8);
-        }
-
-        if (encoding == STRING_ENCODING_LATIN1_BYTE_ARRAY) {
-            return new String(bytes, LATIN1);
-        }
-        throw new IOException("Unknown string encoding " + encoding);
+        throw new UnsupportedOperationException("Use StringParser");
     }
 
     @Override
@@ -336,4 +311,19 @@
         int b8 = readByte(); // read last byte raw
         return ret + (((long) (b8 & 0XFF)) << 56);
     }
+
+    public void setValidSize(long size) {
+        if (size > this.size) {
+            this.size = size;
+        }
+    }
+
+    public long getFileSize() throws IOException {
+        return file.length();
+    }
+
+    public String getFilename() {
+        return filename;
+    }
+
 }
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RecordingInternals.java	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RecordingInternals.java	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,6 +34,19 @@
 
 public abstract class RecordingInternals {
 
+    public static RecordingInternals instance() {
+        if (INSTANCE == null) {
+            // Force initialization
+            try {
+                Class<?> c = RecordedObject.class;
+                Class.forName(c.getName(), true, c.getClassLoader());
+            } catch (ClassNotFoundException e) {
+                new InternalError("shuld not happen");
+            }
+        }
+        return INSTANCE;
+    }
+
     public static RecordingInternals INSTANCE;
 
     public abstract boolean isLastEventInChunk(RecordingFile file);
@@ -44,4 +57,5 @@
 
     public abstract void sort(List<RecordedEvent> events);
 
+    public abstract Parser newStringParser();
 }
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java	Fri May 17 16:02:27 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -80,7 +80,7 @@
      * @throws DCmdException if recording could not be started
      */
     @SuppressWarnings("resource")
-    public String execute(String name, String[] settings, Long delay, Long duration, Boolean disk, String path, Long maxAge, Long maxSize, Boolean dumpOnExit, Boolean pathToGcRoots) throws DCmdException {
+    public String execute(String name, String[] settings, Long delay, Long duration, Boolean disk, String path, Long maxAge, Long maxSize, Long flush, Boolean dumpOnExit, Boolean pathToGcRoots) throws DCmdException {
         if (Logger.shouldLog(LogTag.JFR_DCMD, LogLevel.DEBUG)) {
             Logger.log(LogTag.JFR_DCMD, LogLevel.DEBUG, "Executing DCmdStart: name=" + name +
                     ", settings=" + Arrays.asList(settings) +
@@ -89,6 +89,7 @@
                     ", disk=" + disk+
                     ", filename=" + path +
                     ", maxage=" + maxAge +
+                    ", flush=" + flush +
                     ", maxsize=" + maxSize +
                     ", dumponexit =" + dumpOnExit +
                     ", path-to-gc-roots=" + pathToGcRoots);
@@ -131,6 +132,12 @@
             }
         }
 
+        if (flush != null) {
+            if (Boolean.FALSE.equals(disk)) {
+                throw new DCmdException("Flush can only be set for recordings that are to disk.");
+            }
+        }
+
         if (!FlightRecorder.isInitialized() && delay == null) {
             initializeWithForcedInstrumentation(s);
         }
@@ -143,6 +150,7 @@
         if (disk != null) {
             recording.setToDisk(disk.booleanValue());
         }
+
         recording.setSettings(s);
         SafePath safePath = null;
 
@@ -172,6 +180,10 @@
             recording.setMaxAge(Duration.ofNanos(maxAge));
         }
 
+        if (flush != null) {
+            recording.setFlushInterval(Duration.ofNanos(flush));
+        }
+
         if (maxSize != null) {
             recording.setMaxSize(maxSize);
         }
--- a/src/jdk.jfr/share/conf/jfr/default.jfc	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/conf/jfr/default.jfc	Fri May 17 16:02:27 2019 +0200
@@ -661,6 +661,36 @@
       <setting name="enabled">true</setting>
     </event>
 
+    <event name="jdk.Flush">
+      <setting name="enabled">true</setting>
+      <setting name="threshold">0 ns</setting>
+    </event>
+
+    <event name="jdk.FlushStorage">
+      <setting name="enabled">true</setting>
+      <setting name="threshold">0 ns</setting>
+    </event>
+
+    <event name="jdk.FlushStacktrace">
+      <setting name="enabled">true</setting>
+      <setting name="threshold">0 ns</setting>
+    </event>
+
+    <event name="jdk.FlushStringPool">
+      <setting name="enabled">true</setting>
+      <setting name="threshold">0 ns</setting>
+    </event>
+
+    <event name="jdk.FlushMetadata">
+      <setting name="enabled">true</setting>
+      <setting name="threshold">0 ns</setting>
+    </event>
+
+    <event name="jdk.FlushTypeSet">
+      <setting name="enabled">true</setting>
+      <setting name="threshold">0 ns</setting>
+    </event>
+
     <event name="jdk.DataLoss">
       <setting name="enabled">true</setting>
     </event>
--- a/src/jdk.jfr/share/conf/jfr/profile.jfc	Fri May 17 15:53:21 2019 +0200
+++ b/src/jdk.jfr/share/conf/jfr/profile.jfc	Fri May 17 16:02:27 2019 +0200
@@ -661,6 +661,36 @@
       <setting name="enabled">true</setting>
     </event>
 
+    <event name="jdk.Flush">
+      <setting name="enabled">true</setting>
+      <setting name="threshold">0 ns</setting>
+    </event>
+
+    <event name="jdk.FlushStorage">
+      <setting name="enabled">true</setting>
+      <setting name="threshold">0 ns</setting>
+    </event>
+
+    <event name="jdk.FlushStacktrace">
+      <setting name="enabled">true</setting>
+      <setting name="threshold">0 ns</setting>
+    </event>
+
+    <event name="jdk.FlushStringPool">
+      <setting name="enabled">true</setting>
+      <setting name="threshold">0 ns</setting>
+    </event>
+
+    <event name="jdk.FlushMetadata">
+      <setting name="enabled">true</setting>
+      <setting name="threshold">0 ns</setting>
+    </event>
+
+    <event name="jdk.FlushTypeSet">
+      <setting name="enabled">true</setting>
+      <setting name="threshold">0 ns</setting>
+    </event>
+
     <event name="jdk.DataLoss">
       <setting name="enabled">true</setting>
     </event>
--- a/test/hotspot/gtest/jfr/test_networkUtilization.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/test/hotspot/gtest/jfr/test_networkUtilization.cpp	Fri May 17 16:02:27 2019 +0200
@@ -78,6 +78,9 @@
     void write_key(traceid id) {
       current = id;
     }
+    void write_type(JfrTypeId id) {}
+    MockJfrCheckpointWriter() {}
+    MockJfrCheckpointWriter(bool dummy1, bool dummy2, void* dummy3) {}
     void write(const char* data) {
       ids[current] = data;
     }
@@ -89,12 +92,12 @@
   public:
     static MockJfrSerializer* current;
 
-    static bool register_serializer(JfrTypeId id, bool require_safepoint, bool permit_cache, MockJfrSerializer* serializer) {
+    static bool register_serializer(JfrTypeId id, bool permit_cache, MockJfrSerializer* serializer) {
       current = serializer;
       return true;
     }
 
-    virtual void serialize(MockJfrCheckpointWriter& writer) = 0;
+    virtual void serialize(MockJfrCheckpointWriter& writer) {}
   };
 
   MockJfrSerializer* MockJfrSerializer::current;
--- a/test/hotspot/gtest/jfr/test_threadCpuLoad.cpp	Fri May 17 15:53:21 2019 +0200
+++ b/test/hotspot/gtest/jfr/test_threadCpuLoad.cpp	Fri May 17 16:02:27 2019 +0200
@@ -36,11 +36,10 @@
 #include "jfr/jfrEvents.hpp"
 #include "jfr/support/jfrThreadId.hpp"
 #include "jfr/support/jfrThreadLocal.hpp"
+#include "jfr/utilities/jfrThreadIterator.hpp"
 #include "jfr/utilities/jfrTime.hpp"
 #include "utilities/globalDefinitions.hpp"
 #include "runtime/os.hpp"
-#include "runtime/thread.inline.hpp"
-#include "runtime/threadSMR.inline.hpp"
 
 #include "unittest.hpp"
 
@@ -81,11 +80,18 @@
     MockJavaThread() : ::JavaThread() {}
   };
 
-  class MockJavaThreadIteratorWithHandle
+  class MockJfrJavaThreadIterator
   {
   public:
     MockJavaThread* next() { return NULL; }
-    int length() { return 0; }
+    bool has_next() const { return false; }
+  };
+
+  class MockJfrJavaThreadIteratorAdapter
+  {
+  public:
+    MockJavaThread* next() { return NULL; }
+    bool has_next() const { return false; }
   };
 
 // Reincluding source files in the anonymous namespace unfortunately seems to
@@ -97,7 +103,8 @@
 #define os MockOs
 #define EventThreadCPULoad MockEventThreadCPULoad
 #define JavaThread MockJavaThread
-#define JavaThreadIteratorWithHandle MockJavaThreadIteratorWithHandle
+#define JfrJavaThreadIterator MockJfrJavaThreadIterator
+#define JfrJavaThreadIteratorAdapter MockJfrJavaThreadIteratorAdapter
 
 #include "jfr/periodic/jfrThreadCPULoadEvent.hpp"
 #include "jfr/periodic/jfrThreadCPULoadEvent.cpp"
@@ -105,7 +112,8 @@
 #undef os
 #undef EventThreadCPULoad
 #undef JavaThread
-#undef JavaThreadIteratorWithHandle
+#define JfrJavaThreadIterator MockJfrJavaThreadIterator
+#define JfrJavaThreadIteratorAdapter MockJfrJavaThreadIteratorAdapter
 
 } // anonymous namespace
 
--- a/test/jdk/jdk/jfr/api/consumer/TestReadTwice.java	Fri May 17 15:53:21 2019 +0200
+++ b/test/jdk/jdk/jfr/api/consumer/TestReadTwice.java	Fri May 17 16:02:27 2019 +0200
@@ -26,7 +26,6 @@
 package jdk.jfr.api.consumer;
 
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.util.LinkedList;
 import java.util.List;
 
--- a/test/jdk/jdk/jfr/api/consumer/TestRecordingFile.java	Fri May 17 15:53:21 2019 +0200
+++ b/test/jdk/jdk/jfr/api/consumer/TestRecordingFile.java	Fri May 17 16:02:27 2019 +0200
@@ -55,7 +55,7 @@
  * @key jfr
  * @requires vm.hasJFR
  * @library /test/lib
- * @run main/othervm jdk.jfr.api.consumer.TestRecordingFile
+ * @run main/othervm -Xlog:jfr*=info jdk.jfr.api.consumer.TestRecordingFile
  */
 public class TestRecordingFile {
 
@@ -210,12 +210,12 @@
            assertHasEventType(types, "Event2");
            assertMissingEventType(types, "Event3");
        }
-       try (RecordingFile f = new RecordingFile(twoEventTypes)) {
+       try (RecordingFile f = new RecordingFile(threeEventTypes)) {
            List<EventType> types = f.readEventTypes();
            assertUniqueEventTypes(types);
            assertHasEventType(types, "Event1");
            assertHasEventType(types, "Event2");
-           assertMissingEventType(types, "Event3");
+           assertHasEventType(types, "Event3");
        }
 
     }
--- a/test/jdk/jdk/jfr/api/consumer/TestRecordingInternals.java	Fri May 17 15:53:21 2019 +0200
+++ b/test/jdk/jdk/jfr/api/consumer/TestRecordingInternals.java	Fri May 17 16:02:27 2019 +0200
@@ -60,6 +60,7 @@
                 Asserts.assertEquals(id.toString(), rt.getThreadGroup().getName(), "Thread group name should match id");
                 Asserts.assertEquals(id, Integer.valueOf(i), "Chunks out of order");
                 i++;
+                System.out.println(i + " OK ");
             }
         }
     }
--- a/test/lib/jdk/test/lib/jfr/EventNames.java	Fri May 17 15:53:21 2019 +0200
+++ b/test/lib/jdk/test/lib/jfr/EventNames.java	Fri May 17 16:02:27 2019 +0200
@@ -187,6 +187,12 @@
     public final static String CPUTimeStampCounter = PREFIX + "CPUTimeStampCounter";
     public final static String ActiveRecording = PREFIX + "ActiveRecording";
     public final static String ActiveSetting = PREFIX + "ActiveSetting";
+    public static final String Flush = PREFIX + "Flush";
+    public static final String FlushStringPool = PREFIX + "FlushStringPool";
+    public static final String FlushStacktrace = PREFIX + "FlushStacktrace";
+    public static final String FlushStorage = PREFIX + "FlushStorage";
+    public static final String FlushMetadata = PREFIX + "FlushMetadata";
+    public static final String FlushTypeSet = PREFIX + "FlushTypeSet";
 
     public static boolean isGcEvent(EventType et) {
         return et.getCategoryNames().contains(GC_CATEGORY);