fix(table): return error instead of fatalpanic when opening a corrupt sst (#2333) **Description** Fixes [#2201](https://github.com/dgraph-io/badger/issues/2201) `db.Open()` crashes with a `runtime.fatalpanic` when an SSTable's footer is corrupted (e.g. zeroed), instead of returning an error. Looking at the stack trace of issue description, it looks like following could be the reason for runtime termination, An SST footer is laid out as `[index][indexLen][checksum][checksumLen]`, with the two lengths stored as 4-byte big-endian values. When the footer is zeroed, `checksumLen` and `indexLen` both read as `0`, so we read empty checksum and index bytes. The empty protobuf checksum unmarshals to `Sum = 0`, and the CRC32C of an empty index is also `0`, so the `0 == 0` verification passes. The code then parses the empty index as flatbuffers and reads an out-of-bounds offset into a slice, which panics. `initBiggestAndSmallest` catches that panic, collects debug info, then deliberately re-panics — and that re-panic escapes the table-loading goroutine in `newLevelsController` (which has no `recover()`), so the runtime terminates the process. Changes: - `table/table.go`: `initBiggestAndSmallest` returns an error (instead of re-panicking) after collecting debug info, and `initIndex` validates the footer's `checksumLen`/`indexLen`, rejecting `<= 0` (an empty checksum/index false-passes the `0 == 0` checksum check and then panics parsing empty flatbuffers) and `>= tableSize` (the length can't describe a region as large as the whole file — it would make the footer's read offset negative and slice out of bounds). - `levels.go`: added a `recover()` in the table-loading goroutine as a safety net for any panic that still escapes the table package. **Checklist** - [x] Code compiles correctly and linting passes locally - [x] Tests added for new functionality, or regression tests for bug fixes added as applicable --------- Co-authored-by: Matthew McNeely <matthew.mcneely@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
BadgerDB is an embeddable, persistent and fast key-value (KV) database written in pure Go. It is the underlying database for Dgraph, a fast, distributed graph database. It's meant to be a performant alternative to non-Go-based key-value stores like RocksDB.
Badger is stable and is being used to serve data sets worth hundreds of terabytes. Badger supports concurrent ACID transactions with serializable snapshot isolation (SSI) guarantees. A Jepsen-style bank test runs nightly for 8h, with --race flag and ensures the maintenance of transactional guarantees. Badger has also been tested to work with filesystem level anomalies, to ensure persistence and consistency. Badger is being used by a number of projects which includes Dgraph, Jaeger Tracing, UsenetExpress, and many more.
The list of projects using Badger can be found here.
Please consult the Changelog for more detailed information on releases.
Note: Badger is built with go 1.23 and we refrain from bumping this version to minimize downstream effects of those using Badger in applications built with older versions of Go.
To start using Badger, install Go 1.23 or above. Badger v3 and above needs go modules. From your project, run the following command
go get github.com/dgraph-io/badger/v4
This will retrieve the library.
Badger provides a CLI tool which can perform certain operations like offline backup/restore. To install the Badger CLI, retrieve the repository and checkout the desired version. Then run
cd badger go install .
This will install the badger command line utility into your $GOBIN path.
Badger Documentation is available at https://badger.dgraph.io
Badger was written with these design goals in mind:
Badger’s design is based on a paper titled WiscKey: Separating Keys from Values in SSD-conscious Storage.
| Feature | Badger | RocksDB | BoltDB |
|---|---|---|---|
| Design | LSM tree with value log | LSM tree only | B+ tree |
| High Read throughput | Yes | No | Yes |
| High Write throughput | Yes | Yes | No |
| Designed for SSDs | Yes (with latest research 1) | Not specifically 2 | No |
| Embeddable | Yes | Yes | Yes |
| Sorted KV access | Yes | Yes | Yes |
| Pure Go (no Cgo) | Yes | No | Yes |
| Transactions | Yes, ACID, concurrent with SSI3 | Yes (but non-ACID) | Yes, ACID |
| Snapshots | Yes | Yes | Yes |
| TTL support | Yes | Yes | No |
| 3D access (key-value-version) | Yes4 | No | No |
1 The WISCKEY paper (on which Badger is based) saw big wins with separating values from keys, significantly reducing the write amplification compared to a typical LSM tree.
2 RocksDB is an SSD optimized version of LevelDB, which was designed specifically for rotating disks. As such RocksDB‘s design isn’t aimed at SSDs.
3 SSI: Serializable Snapshot Isolation. For more details, see the blog post Concurrent ACID Transactions in Badger
4 Badger provides direct access to value versions via its Iterator API. Users can also specify how many versions to keep per key via Options.
We have run comprehensive benchmarks against RocksDB, Bolt and LMDB. The benchmarking code, and the detailed logs for the benchmarks can be found in the badger-bench repo. More explanation, including graphs can be found the blog posts (linked above).
Below is a list of known projects that use Badger:
badger.Iterator, simplifying from-to, and prefix mechanics.If you are using Badger in a project please send a pull request to add it to the list.
Badger uses OS-specific implementations for directory locking and fsync operations. On POSIX-compliant systems (Linux, macOS, BSD), these work as expected.
For non-POSIX platforms, be aware of potential limitations:
| Platform | File | Notes |
|---|---|---|
| AIX | dir_aix.go | Directory fsync not supported; durability on crash may be affected |
| Windows | dir_windows.go | Uses different locking mechanism |
| Plan9 | dir_plan9.go | No file locking support |
| WASM/JS | dir_other.go | No file locking support |
If you encounter issues on these platforms, review the corresponding dir_*.go source file for implementation details.
If you're interested in contributing to Badger see CONTRIBUTING.