# Migrating to RockSolid 3.0
RockSolid 3.0 swaps its backing crate from `rocksdb` 0.24 to [`rust-rocksdb`](https://github.com/zaidoon1/rust-rocksdb) 0.51, moving the bundled engine from RocksDB 10.4.2 to 11.1.2. `CHANGELOG.md` records what changed; this document is what you have to do about it.
The good news first: **the dependency is aliased back to the name `rocksdb`, so `use rocksolid::rocksdb::...` and every RockSolid signature naming a RocksDB type are unchanged.** If your crate reaches RocksDB only through that re-export, the migration is a version bump and a rebuild.
## Every consumer
### 1. Bump the requirement
```toml
rocksolid = { version = "3", features = [ ... ] } # keep your existing feature list
```
Nothing picks 3.0 up automatically, which is intentional. Each repo upgrades deliberately.
### 2. Check your toolchain
* **Rust 1.91.0 or newer.** Dev machines are likely fine; the thing to audit is CI images and any `rust-toolchain.toml`.
* **A C++20 compiler**: GCC >= 11, Clang >= 10, or Visual Studio >= 2019. This is a RocksDB requirement since 10.7.0 and applies to the build host. Update Dockerfiles and build images.
### 3. Drop any direct `rocksdb` dependency
This is the one change that is not optional and not detected until link time. `rust-librocksdb-sys` and `librocksdb-sys` both declare `links = "rocksdb"`, and Cargo refuses a dependency graph containing both. If your `Cargo.toml` has its own `rocksdb` entry alongside `rocksolid`, remove it and route the imports through the re-export:
```rust
use rocksolid::rocksdb; // then rocksdb::Direction::Forward, etc.
use rocksolid::rocksdb::compaction_filter::Decision;
use rocksolid::types::{MergeOperands, MergeOperandsIter}; // already re-exported by RockSolid
```
If you genuinely need a build feature RockSolid does not forward, depend on `rust-rocksdb` (not `rocksdb`) at the same version RockSolid uses. Because it is the same package, Cargo unifies it and the types stay identical.
### 4. Re-check your route patterns
`matchit` moved from 0.8 to 0.9. It is part of RockSolid's public API (`matchit::Params` in every route handler, re-exported as `rocksolid::matchit`), so the bump reaches you.
Pattern syntax is unchanged: `{name}` for a named parameter, `{*name}` for a catch-all, which must be the final segment. What changed is that 0.9 tightened the conflict rules and rejects ambiguous pattern sets at insert time, so `add_route` may now return an error where 0.8 accepted the same set. Catch-all parameters are specifically treated as conflicting with suffixed route parameters (`/{*rest}` versus `/{x}suffix`).
If you are still on the pre-0.8 syntax (`*any`, `:name`), those have not been valid for some time and are silently treated as literal path segments, meaning the route never matches. Convert them to `{*any}` and `{name}`.
### 5. Expect a slower first build
RocksDB 11.1.2 compiles from source. The previously built `librocksdb-sys 0.17.3+10.4.2` artifacts are not reused. To link a prebuilt library instead, set `ROCKSDB_LIB_DIR` and `ROCKSDB_INCLUDE_DIR`. Note that a static `librocksdb.a` requires every compression library it was built against to be present at link time, so a fully featured system library generally needs RockSolid's `full` feature set to link.
## Operational notes
These are inherited from the RocksDB 10.4.2 to 11.1.2 jump, not from RockSolid itself.
* **Watch memory in staging before promoting.** The default block cache changed from LRUCache to HyperClockCache (RocksDB 10.7.0), and it applies to every RockSolid store since none set `block_cache` explicitly. Upstream's own note is that this "could expose previously hidden memory or resource leaks". Compare `rocksdb.block-cache-usage` and `rocksdb.estimate-table-readers-mem` under steady load, and pay particular attention if you use the `LatestValue` or `RealTime` profiles, which pin index and filter blocks in cache.
* **Rollback reaches RockSolid 2.7.0 and no further, and is untested.** New SST files use `format_version=7`, readable by RocksDB 10.4.0 and later, and 2.7.0 wraps 10.4.2, so the path should work. That rests on RocksDB's documented format support rather than an observed round-trip, so prove it against a copy of your data before you need it in anger. Releases pinned to `rocksdb` 0.22 (RocksDB 8.10.0) definitely cannot read what 3.0 writes.
* **Do not enable `separate_key_value_in_data_block`** through the `custom_options_db_and_cf` or `Tunable::inner` escape hatch. It is new in RocksDB 11.0.0 and every earlier RocksDB rejects files written with it, which closes the rollback door permanently.
* **Startup replay behavior may differ.** `enforce_write_buffer_manager_during_recovery` now defaults to `true`, so services using the `MemorySaver` or `RealTime` profiles may see different timing on a database with a large pinned WAL. The WAL hygiene rules in `ROCKSDB_OPERATIONS.md` are otherwise unchanged.
* **A database that has been silently limping may now fail at open.** SST file size validation always runs at DB open as of RocksDB 10.5.0. With paranoid checks on, a wrong-sized file fails the open; with them off, the affected column family is quarantined while healthy ones stay usable.
## Verifying your existing database
Your own production database is the real test, and opening it is the first thing to do after bumping. **Work on a copy**, since step 4 writes.
1. Copy a representative database, ideally a checkpoint rather than a live directory. `grep format_version <dbdir>/OPTIONS-*` should report `6`.
2. Open the copy under 3.0. Confirm the open succeeds and `list_cf` returns the CF set you expect. This is where a comparator or merge-operator name mismatch would surface: RocksDB records both in the CF's OPTIONS file and refuses to open a CF whose recorded name differs from the one supplied at open time.
3. Check reads: point lookups return the expected values, merge results are unchanged, comparator CFs iterate in the same order, and compaction filters still fire after a forced flush and `compact_range_cf`.
4. Write and flush, then re-check `format_version`. It should now report `7`, confirming new SSTs are on the new format.
5. If the rollback path matters to you, reopen that directory under your pre-upgrade build. Both engines cannot coexist in one dependency graph, so this needs a second checkout or git worktree at the old commit. This step is untested upstream, so it is worth doing once if you intend to rely on it.
## Build feature reference
`default` is `["multi-threaded-cf", "lz4", "bindgen-runtime"]`.
| Feature | Purpose |
| --- | --- |
| `multi-threaded-cf` | Retained for source compatibility; now forwarded unconditionally and a no-op |
| `lz4`, `snappy`, `zstd`, `zlib`, `bzip2` | Compression codecs |
| `bindgen-runtime` | Locate `libclang` at runtime (default) |
| `bindgen-static` | Link `libclang` statically; requires `default-features = false` |
| `jemalloc`, `io-uring`, `mt_static`, `lto`, `rtti`, `malloc-usable-size`, `zstd-static-linking-only` | Pass-throughs to `rust-rocksdb` |
| `natlex_sort`, `nat_sort` | Natural-order comparators |
| `base62`, `test-utils` | RockSolid utilities |
`bindgen-runtime` and `bindgen-static` are mutually exclusive; enabling both panics `clang-sys`'s build script. **`--all-features` is therefore not a supported build.** Use `--features full`, and pass `--exclude-features bindgen-static` to `cargo hack --feature-powerset`.