rocksolid 3.0.0

An ergonomic, high-level RocksDB wrapper for Rust. Features CF-aware optimistic & pessimistic transactions, advanced routing for merge operators and compaction filters, performance tuning profiles, batching, TTL values, and DAO macros.
Documentation
# 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`.