#pragma once #include #include #include #include namespace xrpl { /** Keeps track of which ledgers haven't been fully saved. During the ledger building process this collection will keep track of those ledgers that are being built but have not yet been completely written. */ class PendingSaves { private: std::mutex mutable mutex_; std::map map_; std::condition_variable await_; public: /** Start working on a ledger This is called prior to updating the SQLite indexes. @return 'true' if work should be done */ bool startWork(LedgerIndex seq) { std::scoped_lock const lock(mutex_); auto it = map_.find(seq); if ((it == map_.end()) || it->second) { // Work done or another thread is doing it return false; } it->second = true; return true; } /** Finish working on a ledger This is called after updating the SQLite indexes. The tracking of the work in progress is removed and threads awaiting completion are notified. */ void finishWork(LedgerIndex seq) { std::scoped_lock const lock(mutex_); map_.erase(seq); await_.notify_all(); } /** Return `true` if a ledger is in the progress of being saved. */ bool pending(LedgerIndex seq) { std::scoped_lock const lock(mutex_); return map_.contains(seq); } /** Check if a ledger should be dispatched Called to determine whether work should be done or dispatched. If work is already in progress and the call is synchronous, wait for work to be completed. @return 'true' if work should be done or dispatched */ bool shouldWork(LedgerIndex seq, bool isSynchronous) { std::unique_lock lock(mutex_); do { auto it = map_.find(seq); if (it == map_.end()) { map_.emplace(seq, false); return true; } if (!isSynchronous) { // Already dispatched return false; } if (!it->second) { // Scheduled, but not dispatched return true; } // Already in progress, just need to wait await_.wait(lock); } while (true); } /** Get a snapshot of the pending saves Each entry in the returned map corresponds to a ledger that is in progress or dispatched. The boolean indicates whether work is currently in progress. */ std::map getSnapshot() const { std::scoped_lock const lock(mutex_); return map_; } }; } // namespace xrpl