Add experimental external log file API#14728
Conversation
✅ clang-tidy: No findings on changed linesCompleted in 497.4s. |
Claude Code Review - OBSOLETESuperseded by a newer AI review. Expand to see the original review.✅ Claude Code ReviewAuto-triggered after CI passed — reviewing commit 48c271d SummaryThis PR adds a well-structured external log file management system for RocksDB-managed High-severity findings (5):
Full review (click to expand)Findings🔴 HIGHH1. Checksum generator state lost on MANIFEST write failure —
|
| Context | Executes? | Assumptions hold? | Action needed? |
|---|---|---|---|
| ReadOnly DB | Yes (read ops) | Yes — CheckDBMutable() blocks writes |
Safe |
| Secondary Instance | Needs verification | Unknown | Verify behavior |
| WritePreparedTxnDB | Yes (independent) | Yes — no txn interaction | Safe |
| BackupEngine | Yes (via GetLiveFiles) | NO — files included but unsupported | H2 |
| Checkpoint | Yes (via GetLiveFilesStorageInfo) | Partially — M3 for unsealed | Fix trim_to_size |
| FIFO/Universal compaction | No interaction | N/A | Safe |
Positive Observations
- Clean state machine design: unsealed→sealed lifecycle with immutability well-enforced in
ExternalLogFileSet::AddFile(). - Comprehensive decode validation with clear error messages and corruption detection.
- Proper
pending_outputsintegration prevents file number reuse after crashes. - Good error path cleanup via
cleanup_active_writerlambda pattern. - TEST_SYNC_POINT hooks at key lifecycle points enable thorough concurrency testing.
- Rate-limited deletion via
DeleteSchedulerfollows established patterns.
ℹ️ About this response
Generated by Claude Code.
Review methodology: claude_md/code_review.md
Limitations:
- Claude may miss context from files not in the diff
- Large PRs may be truncated
- Always apply human judgment to AI suggestions
Commands:
/claude-review [context]— Request a code review/claude-query <question>— Ask about the PR or codebase
48c271d to
5c3ac5f
Compare
Codex Code Review - OBSOLETESuperseded by a newer AI review. Expand to see the original review.🟡 Codex Code ReviewAuto-triggered after CI passed — reviewing commit 5c3ac5f ❌ Codex review failed before producing findings. ℹ️ About this responseGenerated by Codex CLI. Limitations:
Commands:
|
5c3ac5f to
f3e43ae
Compare
Summary: Implement the experimental ExternalLogFileManager API and RocksDB integration for MANIFEST-tracked application byte streams. This folds the public API header and implementation into one diff for easier export to GitHub. What this adds: - Public API surface: ExternalLogFileManager, ExternalLogFileReader, ExternalLogFileWriter, ExternalLogFileOptions, IngestExternalLogFileOptions, ExternalLogFileInfo, reader visibility options, checksum verification options, reopen recovery options, and seal options. - DB integration: DB::NewExternalLogFileManager() and StackableDB forwarding. - MANIFEST integration: external-log metadata encoding/decoding, VersionEdit records, VersionSet tracking, recovery handling, manifest roll preservation, and file-number reservation/protection. - File enumeration integration: external log files participate in live-file/storage-info paths where supported, including FileStorageInfo fields and kExternalLogFile type support. - Docs and release note for the experimental feature. Public API contract: - Purpose: external log files are MANIFEST-tracked byte streams for application data. They let an application keep a consistent view of RocksDB state plus related application files without storing those bytes as keys or values, and they allow efficient sequential file read/write through the configured RocksDB FileSystem. - External log files are not RocksDB WALs, SSTs, or record containers. RocksDB does not replay their bytes into memtables, assign sequence numbers to their contents, define record boundaries, or interpret application data. - Each file has an application-provided name used by ListExternalLogFiles(), OpenExternalLogFileForRead(), ReopenExternalLogFile(), VerifyExternalLogFileChecksum(), DeleteExternalLogFile(), and DeleteExternalLogFiles(). The name is both the public lookup key and the physical path persisted in MANIFEST; there is no separate public path field. - In kDBRelativePath mode, the name is the DB-relative physical path. Absolute paths, backslash separators, empty components, . components, .. components, and names that collide with RocksDB-managed filenames are rejected. - In kExternalPath mode, the name is an explicit physical path. Absolute names are used as-is. Relative names are resolved against the DB directory and may include .. components. This keeps outside-DB tracking explicit through path_type without requiring a second application-provided path string. Reopen/restore require the application to recreate the same external path names before opening the DB. - CreateExternalLogFile() creates an unsealed file at the resolved physical path and registers it in MANIFEST at creation time. Sync() makes bytes durable in the FileSystem but does not update MANIFEST size/checksum metadata. Seal() records the final logical size and checksum metadata in MANIFEST and makes the file immutable. - ReopenExternalLogFile() is the recovery path for an unsealed file. If the physical file is longer than the MANIFEST durable prefix, the application chooses the recovered append point; RocksDB can recompute rolling checksum state when a checksum factory is configured. - IngestExternalLogFile() and IngestExternalLogFiles() register prebuilt immutable files as sealed external log files. If source_path already equals the resolved destination path, RocksDB validates and registers the existing file in place; otherwise it copies, moves, links, or link-or-copies according to the ingestion mode. Multi-file ingest commits all MANIFEST additions atomically after the physical transfers complete. RocksDB does not infer application record boundaries. - Readers see the committed logical prefix. For unsealed files with an active writer, snapshot readers capture the writer-visible size at open time and follow readers can observe later successful appends. For closed unsealed files without an active writer, readers expose the MANIFEST durable prefix until the application reopens, recovers, and seals the file. - DeleteExternalLogFile() removes one MANIFEST entry and deletes the physical file named by the MANIFEST entry. DeleteExternalLogFiles() removes multiple MANIFEST entries with one edit and then deletes the physical files. Both APIs reject duplicate names and return Busy without changing MANIFEST if any requested file has an active reader, writer, verifier, or physical-size listing reference. After a successful MANIFEST edit, RocksDB attempts every physical delete and ignores NotFound results. - DeleteExternalLogFile() and DeleteExternalLogFiles() are the only RocksDB APIs that delete explicit outside-DB external log files. Obsolete-file scanning does not discover or delete those paths indirectly; the MANIFEST entry is the authority. The delete path uses RocksDB rate-limited unaccounted purge machinery when configured, and directory sync/trash behavior uses each physical file's parent directory. - DestroyDB() does not delete explicit external-path files outside the DB directory. Applications must use DeleteExternalLogFile(), DeleteExternalLogFiles(), or their own cleanup for those files. - Checkpoint returns NotSupported while any external log file is registered, rather than silently creating a checkpoint with missing application files. - BackupEngine returns NotSupported while any external log file is registered and BackupEngine cannot preserve it. Applications using backup/restore must preserve the external files separately and recreate the same paths before opening the restored DB. - DB::GetLiveFiles() returns NotSupported for kExternalPath files because that API can only report DB-relative names. DB::GetLiveFilesStorageInfo() can report directory/filename metadata for external log files. - Thread safety: RocksDB synchronizes internal metadata, reference counts, and individual writer handles. A single writer handle serializes its mutating calls for append position, checksum state, file I/O, and closed/sealed state. RocksDB permits multiple unsealed files to be active concurrently, with at most one active writer per file. Applications must keep handles alive while in use and synchronize higher-level lifecycle decisions and record-boundary protocols. Test Plan: Public RocksDB checkout: ASSERT_STATUS_CHECKED=1 TEST_UINT128_COMPAT=1 ROCKSDB_MODIFY_NPHASH=1 LIB_MODE=static OPT="-DROCKSDB_USE_STD_SEMAPHORES -DROCKSDB_NAMESPACE=alternative_rocksdb_ns" make -j"$(nproc)" external_log_file_test ASSERT_STATUS_CHECKED=1 TEST_UINT128_COMPAT=1 ROCKSDB_MODIFY_NPHASH=1 LIB_MODE=static OPT="-DROCKSDB_USE_STD_SEMAPHORES -DROCKSDB_NAMESPACE=alternative_rocksdb_ns" ./external_log_file_test PATH=/usr/bin:$PATH make check-sources a/b/fbsource checkout: buck2 test --flagfile fbcode//mode/dev fbcode//rocksdb/src:external_log_file_test fbcode//rocksdb/src:external_log_file_test_fbcode Result: external_log_file_test ran 42 tests and passed. The command ended with an unrelated build failure in fbcode//warm_storage/client/prod:ws_file_api_lib due missing privacy/data_access_policies/zone/ZoneReclassification.h before the fbcode variant could run.
f3e43ae to
a0a4073
Compare
🟡 Codex Code ReviewAuto-triggered after CI passed — reviewing commit a0a4073 ❌ Codex review failed before producing findings. ℹ️ About this responseGenerated by Codex CLI. Limitations:
Commands:
|
✅ Claude Code ReviewAuto-triggered after CI passed — reviewing commit a0a4073 SummaryThis PR adds a substantial new feature (~5800 lines) introducing High-severity findings (3):
The full review with all 15 findings (3 HIGH, 7 MEDIUM, 5 LOW), cross-component analysis table, and positive observations has been written to ℹ️ About this responseGenerated by Claude Code. Limitations:
Commands:
|
Implement the experimental ExternalLogFileManager API and RocksDB integration for MANIFEST-tracked application byte streams. This folds the public API header and implementation into one diff for easier export to GitHub.
What this adds:
Public API contract: