void TruncateSegments()

in src/device/file_system_disk.h [350:411]


  void TruncateSegments(uint64_t new_begin_segment, GcState::truncate_callback_t caller_callback) {
    class Context : public IAsyncContext {
     public:
      Context(bundle_t* files_, uint64_t new_begin_segment_,
              GcState::truncate_callback_t caller_callback_)
        : files{ files_ }
        , new_begin_segment{ new_begin_segment_ }
        , caller_callback{ caller_callback_ } {
      }
      /// The deep-copy constructor.
      Context(const Context& other)
        : files{ other.files }
        , new_begin_segment{ other.new_begin_segment }
        , caller_callback{ other.caller_callback } {
      }
     protected:
      Status DeepCopy_Internal(IAsyncContext*& context_copy) final {
        return IAsyncContext::DeepCopy_Internal(*this, context_copy);
      }
     public:
      bundle_t* files;
      uint64_t new_begin_segment;
      GcState::truncate_callback_t caller_callback;
    };

    auto callback = [](IAsyncContext* ctxt) {
      CallbackContext<Context> context{ ctxt };
      for(uint64_t idx = context->files->begin_segment; idx < context->new_begin_segment; ++idx) {
        file_t& file = context->files->file(idx);
        file.Close();
        file.Delete();
      }
      std::free(context->files);
      if(context->caller_callback) {
        context->caller_callback(context->new_begin_segment * kSegmentSize);
      }
    };

    // Only one thread can modify the list of files at a given time.
    std::lock_guard<std::mutex> lock{ mutex_ };
    bundle_t* files = files_.load();
    assert(files);
    if(files->begin_segment >= new_begin_segment) {
      // Segments have already been truncated.
      if(caller_callback) {
        caller_callback(files->begin_segment * kSegmentSize);
      }
      return;
    }

    // Make a copy of the list, excluding the files to be truncated.
    void* buffer = std::malloc(bundle_t::size(files->end_segment - new_begin_segment));
    bundle_t* new_files = new(buffer) bundle_t{ handler_, new_begin_segment, files->end_segment,
        *files };
    files_.store(new_files);
    // Delete the old list only after all threads have finished looking at it.
    Context context{ files, new_begin_segment, caller_callback };
    IAsyncContext* context_copy;
    Status result = context.DeepCopy(context_copy);
    assert(result == Status::Ok);
    epoch_->BumpCurrentEpoch(callback, context_copy);
  }