Skip to main content

rust_rocksdb/
file_checksum.rs

1//! Whole file checksums recorded in the manifest.
2//!
3//! With a checksum generator factory installed, RocksDB hashes every SST file
4//! as it writes it and stores the digest and the generator's name in the
5//! manifest alongside the file entry. Everything that claims to verify file
6//! checksums reads those manifest entries:
7//!
8//! * `DB::VerifyFileChecksums` rehashes every live SST and blob file and
9//!   compares against the manifest.
10//! * Backup reuses the recorded digest instead of hashing the source file
11//!   again, and checks the copy against it.
12//! * Ingestion with
13//!   [`IngestExternalFileOptions::set_verify_file_checksum`](crate::IngestExternalFileOptions::set_verify_file_checksum)
14//!   checks the digest that came with the incoming file.
15//!
16//! `file_checksum_gen_factory` defaults to null, and none of that works without
17//! it. `VerifyFileChecksums` refuses to run at all and returns
18//! `InvalidArgument`, and backup goes back to hashing files itself.
19//!
20//! Turning the factory on does not backfill. Files already on disk carry no
21//! digest, verification skips them one by one without complaining, and they
22//! only pick one up when a compaction rewrites them.
23//!
24//! This is separate from the per block checksum that
25//! [`BlockBasedOptions::set_checksum_type`](crate::BlockBasedOptions::set_checksum_type)
26//! controls. Block checksums are stored inside the SST and verified on every
27//! read, so readers detect block corruption whether or not a file checksum
28//! exists. A file checksum covers the whole file in one digest, which is what
29//! makes it useful for copying and moving files around, and useless for
30//! locating corruption inside one.
31//!
32//! The generator's name surfaces in this crate as
33//! [`LiveFileStorageInfoEntry::file_checksum_func_name`](crate::metadata::LiveFileStorageInfoEntry::file_checksum_func_name).
34//! The digest itself is deliberately not exposed: the only C accessor returns it
35//! as a NUL-terminated string with no length, and a digest can contain a zero
36//! byte, so the value would be silently truncated.
37
38use std::ptr::NonNull;
39
40use crate::ffi;
41
42/// A factory RocksDB asks for a checksum generator each time it creates an SST
43/// file.
44///
45/// Install one with
46/// [`Options::set_file_checksum_gen_factory`](crate::Options::set_file_checksum_gen_factory).
47/// The setter copies the underlying `shared_ptr`, so a factory can be installed
48/// on any number of `Options` and dropped as soon as the last call returns.
49pub struct FileChecksumGenFactory {
50    inner: NonNull<ffi::rocksdb_file_checksum_gen_factory_t>,
51}
52
53impl FileChecksumGenFactory {
54    /// The built in CRC32C generator, recorded in the manifest under the name
55    /// `FileChecksumCrc32c`.
56    ///
57    /// Upstream notes that this digest is big endian and unmasked, unlike the
58    /// other CRC32C values RocksDB computes, which makes it comparable with
59    /// CRC32C implementations outside RocksDB.
60    ///
61    /// Wraps `GetFileChecksumGenCrc32cFactory`.
62    #[must_use]
63    pub fn crc32c() -> Self {
64        let inner = unsafe { ffi::rocksdb_file_checksum_gen_crc32c_factory_create() };
65        Self {
66            inner: NonNull::new(inner)
67                .expect("rocksdb_file_checksum_gen_crc32c_factory_create returned null"),
68        }
69    }
70
71    pub(crate) fn as_ptr(&self) -> *mut ffi::rocksdb_file_checksum_gen_factory_t {
72        self.inner.as_ptr()
73    }
74}
75
76impl Drop for FileChecksumGenFactory {
77    fn drop(&mut self) {
78        unsafe {
79            ffi::rocksdb_file_checksum_gen_factory_destroy(self.inner.as_ptr());
80        }
81    }
82}
83
84// `rocksdb_file_checksum_gen_factory_t` is a
85// `std::shared_ptr<FileChecksumGenFactory>` and nothing else (c.cc:498).
86// Destroying the handle only drops that one reference, and the only other
87// operation this crate performs on it is the refcount bump in
88// `rocksdb_options_set_file_checksum_gen_factory` (c.cc:6067), which is atomic.
89// So the handle carries no thread affinity, and concurrent reads through
90// `&FileChecksumGenFactory` cannot race.
91unsafe impl Send for FileChecksumGenFactory {}
92unsafe impl Sync for FileChecksumGenFactory {}