src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp
branchJEP-349-branch
changeset 57360 5d043a159d5c
parent 54623 1126f0607c70
child 57870 00860d9caf4d
--- 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();
   }
 }