Back to Rocksdb

Write APIs and WriteBatch

docs/components/write_flow/01_write_apis.md

11.8.15.6 KB
Original Source

Write APIs and WriteBatch

Files: db/db_impl/db_impl_write.cc, include/rocksdb/write_batch.h, db/write_batch.cc, include/rocksdb/options.h

Entry Points

RocksDB provides multiple write operations, all ultimately funneling through DBImpl::WriteImpl():

APIValueTypeDescription
Put(key, value)kTypeValueInsert or overwrite key
Delete(key)kTypeDeletionTombstone covering all older versions
SingleDelete(key)kTypeSingleDeletionTombstone pairing with exactly one Put
DeleteRange(start, end)kTypeRangeDeletionTombstone covering [start, end)
Merge(key, operand)kTypeMergeApply merge operator to key
PutEntity(key, columns)kTypeWideColumnEntityWide-column insert
TimedPut(key, value, write_unix_time)kTypeValuePreferredSeqnoPut with explicit write time for compaction
Write(WriteBatch)MixedAtomic batch of operations

All single-operation APIs construct a WriteBatch internally and call DB::Write(), which dispatches to DBImpl::WriteImpl(). The Merge operation additionally validates that a merge operator is configured via ColumnFamilyOptions::merge_operator (see include/rocksdb/advanced_options.h).

WriteBatch Binary Format

A WriteBatch serializes multiple operations into a single binary buffer (the rep_ field), ensuring atomicity: all operations succeed or all fail together.

Header (12 bytes):

OffsetSizeFieldDescription
08sequencePlaceholder; filled by write leader before WAL append
84countNumber of operations in the batch

Per-operation encoding (variable length, repeated):

FieldEncodingDescription
taguint8ValueType identifier
cf_idvarint32Column family ID (only for CF-prefixed op tags)
keyvarint32 length + bytesUser key
valuevarint32 length + bytesValue (for Put/Merge/PutEntity ops)

Important: The sequence number field in the header is initialized to 0. The write group leader stamps the assigned sequence into the merged batch header via WriteBatchInternal::SetSequence() before appending the record to the WAL. Individual writer sequence assignments for memtable insertion happen after the WAL write completes.

WriteBatch Key Fields

The WriteBatch class (see include/rocksdb/write_batch.h) tracks several metadata fields:

FieldTypePurpose
rep_std::stringBinary buffer containing header + operations
content_flags_atomic<uint32_t>Bitmask of operation types present (enables fast checks like HasDeleteRange())
prot_info_unique_ptr<ProtectionInfo>Optional per-entry checksums (8 bytes per key when enabled)
save_points_unique_ptr<SavePoints>Rollback snapshots for transaction support

The content_flags_ field enables O(1) queries like HasMerge() and HasDeleteRange() without scanning the batch contents. These flags are set during operation insertion and checked during write path validation.

WriteOptions Validation

Before entering the write path, DBImpl::WriteImpl() validates the request. The following per-write option combinations are rejected:

ConditionReason
sync && disableWALCannot sync without a WAL
HasDeleteRange() && row_cacheDeleteRange invalidation not supported with row cache
disableWAL && recycle_log_file_num > 0Recycled WAL corruption detection requires sequential sequences
protection_bytes_per_key not 0 or 8Only two protection levels supported
rate_limiter_priority not IO_TOTAL or IO_USERImplementation constraint

The disableWAL && recycle_log_file_num check has an exception: WritePreparedTxnDB uses disableWAL internally for split writes (WAL-only prepare + memtable-only commit), which is allowed when two_write_queues && disable_memtable.

DBOptions Incompatibility Checks

These immutable DBOptions conflicts are also checked at runtime in WriteImpl():

ConditionReason
two_write_queues && enable_pipelined_writeIncompatible write modes
unordered_write && enable_pipelined_writeIncompatible write modes
seq_per_batch && enable_pipelined_writePipelined write does not support seq_per_batch

Low-Priority Write Throttling

When WriteOptions::low_pri is set and compaction pressure exists (WriteController::NeedSpeedupCompaction() returns true), the write is rate-limited via WriteController::low_pri_rate_limiter() before entering the main write path. This rate limiter is separate from the main write delay mechanism and allows low-priority writes to make slow progress even under compaction pressure.

For two-phase commit (2PC), commit and rollback batches are exempt from low-priority throttling to avoid blocking transaction completion.

Write Path Dispatch

After validation, WriteImpl() dispatches to one of four write modes based on configuration:

  1. Two-queue WAL-only (two_write_queues_ && disable_memtable): Routes to WriteImplWALOnly() via the non-memtable write thread
  2. Unordered write (unordered_write): WAL write via WriteImplWALOnly(), then independent memtable insert via UnorderedWriteMemtable()
  3. Pipelined write (enable_pipelined_write): Routes to PipelinedWriteImpl() with overlapping WAL and memtable phases
  4. Normal batched write (default): Single-threaded WAL + memtable within the write group

See Write Modes for detailed descriptions of each mode.