|
15 | 15 | #include <limits> |
16 | 16 | #include <list> |
17 | 17 | #include <map> |
| 18 | +#include <memory> |
| 19 | +#include <optional> |
18 | 20 | #include <set> |
19 | 21 | #include <string> |
20 | 22 | #include <unordered_map> |
@@ -2810,7 +2812,68 @@ class DBImpl : public DB { |
2810 | 2812 | size_t GetWalPreallocateBlockSize(uint64_t write_buffer_size) const; |
2811 | 2813 | Env::WriteLifeTimeHint CalculateWALWriteHint() { return Env::WLTH_SHORT; } |
2812 | 2814 |
|
2813 | | - IOStatus CreateWAL(const WriteOptions& write_options, uint64_t log_file_num, |
| 2815 | + // Returns true when async WAL precreation is enabled and compatible with the |
| 2816 | + // active WAL strategy. WAL recycling already avoids file creation latency, so |
| 2817 | + // precreation is disabled when recycle_log_file_num is non-zero. |
| 2818 | + bool AsyncWALPrecreateEnabled() const; |
| 2819 | + |
| 2820 | + // A WAL file that has a reserved file number and may have an opened writer, |
| 2821 | + // but has not been added to DBImpl's in-memory logical WAL tracking lists |
| 2822 | + // (logs_ and alive_wal_files_). |
| 2823 | + struct UnpublishedWAL { |
| 2824 | + uint64_t log_number = 0; |
| 2825 | + std::unique_ptr<log::Writer> writer; |
| 2826 | + |
| 2827 | + UnpublishedWAL() = default; |
| 2828 | + UnpublishedWAL(const UnpublishedWAL&) = delete; |
| 2829 | + UnpublishedWAL& operator=(const UnpublishedWAL&) = delete; |
| 2830 | + |
| 2831 | + UnpublishedWAL(UnpublishedWAL&& other) noexcept { |
| 2832 | + *this = std::move(other); |
| 2833 | + } |
| 2834 | + UnpublishedWAL& operator=(UnpublishedWAL&& other) noexcept { |
| 2835 | + if (this != &other) { |
| 2836 | + log_number = other.log_number; |
| 2837 | + writer = std::move(other.writer); |
| 2838 | + other.Reset(); |
| 2839 | + } |
| 2840 | + return *this; |
| 2841 | + } |
| 2842 | + |
| 2843 | + void Reset() { |
| 2844 | + log_number = 0; |
| 2845 | + writer.reset(); |
| 2846 | + } |
| 2847 | + }; |
| 2848 | + |
| 2849 | + // Reserves the next WAL file number and schedules a HIGH-priority background |
| 2850 | + // task to precreate that WAL file. A precreated WAL is not a logical WAL |
| 2851 | + // until a foreground WAL rotation consumes it. |
| 2852 | + void MaybeScheduleAsyncWALPrecreate(size_t preallocate_block_size); |
| 2853 | + |
| 2854 | + // Background task for opening the reserved future WAL and publishing the |
| 2855 | + // result under mutex_. |
| 2856 | + static void BGWorkAsyncWALPrecreate(void* arg); |
| 2857 | + |
| 2858 | + // Waits for an in-flight async WAL precreation and returns a prepared WAL if |
| 2859 | + // one is available. If precreation failed, returns an empty WAL and lets the |
| 2860 | + // foreground rotation create the WAL synchronously. Caller must hold mutex_. |
| 2861 | + UnpublishedWAL WaitForAsyncWALPrecreate(); |
| 2862 | + |
| 2863 | + // Opens and preallocates a WAL writer without writing logical WAL records. |
| 2864 | + // Used by async WAL precreation and by synchronous WAL creation. |
| 2865 | + IOStatus CreateWALWriter(const DBOptions& db_options, uint64_t log_file_num, |
| 2866 | + uint64_t recycle_log_number, |
| 2867 | + size_t preallocate_block_size, |
| 2868 | + UnpublishedWAL* new_wal); |
| 2869 | + |
| 2870 | + // Starts an opened WAL file by writing the initial records required before it |
| 2871 | + // can be installed as the current WAL for foreground writes. |
| 2872 | + IOStatus StartWALFile(const WriteOptions& write_options, |
| 2873 | + const PredecessorWALInfo& predecessor_wal_info, |
| 2874 | + log::Writer* new_log); |
| 2875 | + IOStatus CreateWAL(const DBOptions& db_options, |
| 2876 | + const WriteOptions& write_options, uint64_t log_file_num, |
2814 | 2877 | uint64_t recycle_log_number, size_t preallocate_block_size, |
2815 | 2878 | const PredecessorWALInfo& predecessor_wal_info, |
2816 | 2879 | log::Writer** new_log); |
@@ -3306,6 +3369,28 @@ class DBImpl : public DB { |
3306 | 3369 | AsyncFileOpenState bg_async_file_open_state_ = |
3307 | 3370 | AsyncFileOpenState::kNotScheduled; |
3308 | 3371 |
|
| 3372 | + // State machine for the single async WAL precreation slot protected by |
| 3373 | + // mutex_. Background precreation failure returns to kNotScheduled; foreground |
| 3374 | + // rotation handles it the same as no prepared WAL and creates one |
| 3375 | + // synchronously. kScheduled owns a reserved file number; kReady owns an |
| 3376 | + // opened writer that has not been started or added to logical WAL tracking. |
| 3377 | + enum class AsyncWALPrecreateState : uint8_t { |
| 3378 | + kNotScheduled = 0, // No WAL precreate work is in-flight or ready. |
| 3379 | + kScheduled, // Background task owns creation of the reserved WAL. |
| 3380 | + kReady, // Reserved WAL writer is open but not logically live. |
| 3381 | + }; |
| 3382 | + |
| 3383 | + // Protected by mutex_. Tracks at most one background precreated WAL. A |
| 3384 | + // precreated WAL is only reserved empty storage until SwitchMemtable() |
| 3385 | + // consumes it and installs it in DBImpl's in-memory logical WAL tracking |
| 3386 | + // lists (logs_ and alive_wal_files_). |
| 3387 | + AsyncWALPrecreateState async_wal_precreate_state_ = |
| 3388 | + AsyncWALPrecreateState::kNotScheduled; |
| 3389 | + |
| 3390 | + // Reserved in-flight/ready precreated WAL. The writer is populated only while |
| 3391 | + // state is kReady. |
| 3392 | + UnpublishedWAL async_wal_precreate_wal_; |
| 3393 | + |
3309 | 3394 | std::deque<ManualCompactionState*> manual_compaction_dequeue_; |
3310 | 3395 |
|
3311 | 3396 | // shall we disable deletion of obsolete files |
|
0 commit comments