This package provides a Gerbil LevelDB driver using libleveldb.
You need to have libleveldb installed in your system.
$ sudo apt install libleveldb-dev
Install homebrew (if not already done):
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
then install leveldb:
$ brew install leveldb
On ARM64 architectures (M1...) Homebrew installs its bits in /opt/homebrew. For some reason leveldb does not provide support for pkg-config. macOS users on ARM need to export CPPFLAGS and LDFLAGS for the compiler to find leveldb headers and library.
$ arch ## arm64
$ export CPPFLAGS=-I/opt/homebrew/include
$ export LDFLAGS=-L/opt/homebrew/lib
To install the package in your $GERBIL_PATH (~/.gerbil by default):
$ gerbil pkg install github.com/mighty-gerbils/gerbil-leveldbBuild the library:
$ ./build.ss
# or
$ make buildRun tests:
$ make testThe functional test (test/functional-test.ss) exercises all features including:
- Version query
- Options with all parameters (including
max-file-size:andenv:) - Environment creation
- Basic put/get/delete operations
- Write batches and batch append
- Snapshots with point-in-time reads
- Iterators and
in-leveldbiteration - Database properties
- Approximate size queries
- Compaction, repair, and destroy
To use bindings from this package:
(import :clan/db/leveldb)(import :clan/db/leveldb)
;; Open a database (creates if it doesn't exist)
(def db (leveldb-open "/path/to/mydb"))
;; Put a key-value pair
(leveldb-put db "mykey" "myvalue")
;; Get a value (returns u8vector or #f if not found)
(def val (leveldb-get db "mykey"))
(when val (displayln (bytes->string val)))
;; Delete a key
(leveldb-delete db "mykey")
;; Close the database
(leveldb-close db)(leveldb-open name [opts]) -> leveldbOpens a LevelDB database at the specified path. Creates the database if it doesn't exist (by default).
name: Path to the database directory (string)opts: Optional options object created withleveldb-options
(leveldb-close db) -> voidCloses the database and releases resources.
(leveldb-put db key val [opts]) -> voidStores a key-value pair in the database.
key: Key as string or u8vectorval: Value as string or u8vectoropts: Optional write options
(leveldb-get db key [opts]) -> u8vector | #fRetrieves a value by key. Returns #f if the key doesn't exist.
(leveldb-delete db key [opts]) -> voidDeletes a key from the database.
(leveldb-key? db key [opts]) -> booleanChecks if a key exists in the database.
Write batches allow atomic updates of multiple keys.
(leveldb-writebatch) -> writebatchCreates a new write batch.
(leveldb-writebatch-put batch key val) -> voidAdds a put operation to the batch.
(leveldb-writebatch-delete batch key) -> voidAdds a delete operation to the batch.
(leveldb-writebatch-append dest src) -> voidAppends all operations from src batch to dest batch. Useful for composing batches.
(def wb1 (leveldb-writebatch))
(def wb2 (leveldb-writebatch))
(leveldb-writebatch-put wb1 "a" "1")
(leveldb-writebatch-put wb2 "b" "2")
(leveldb-writebatch-append wb1 wb2) ;; wb1 now has both operations
(leveldb-write db wb1)(leveldb-writebatch-clear batch) -> voidClears all operations from a write batch.
(leveldb-write db batch [opts]) -> voidAtomically applies all operations in the batch to the database.
Snapshots provide a consistent read-only view of the database at a point in time.
(leveldb-snapshot db) -> snapshotCreates a snapshot of the current database state.
(leveldb-snapshot-release db snapshot) -> voidReleases a snapshot when no longer needed.
;; Create snapshot
(leveldb-put db "key" "value1")
(def snap (leveldb-snapshot db))
;; Modify after snapshot
(leveldb-put db "key" "value2")
;; Read current value
(leveldb-get db "key") ;; => "value2"
;; Read from snapshot
(def snap-opts (leveldb-read-options snapshot: snap))
(leveldb-get db "key" snap-opts) ;; => "value1"
;; Release when done
(leveldb-snapshot-release db snap)Iterators allow sequential scanning of key-value pairs.
(leveldb-iterator db [opts]) -> iteratorCreates an iterator for the database.
(leveldb-iterator-close iter) -> voidCloses the iterator.
(leveldb-iterator-valid? iter) -> booleanReturns #t if the iterator is positioned at a valid entry.
(leveldb-iterator-seek-first iter) -> void
(leveldb-iterator-seek-last iter) -> voidPositions the iterator at the first or last entry.
(leveldb-iterator-seek iter key) -> voidPositions the iterator at the first entry with key >= key.
(leveldb-iterator-next iter) -> void
(leveldb-iterator-prev iter) -> voidMoves to the next or previous entry.
(leveldb-iterator-key iter) -> u8vector
(leveldb-iterator-value iter) -> u8vectorReturns the key or value at the current position.
(in-leveldb db [start] [limit]) -> iterator
(in-leveldb-keys db [start] [limit]) -> iteratorCreates iterators compatible with Gerbil's for loops.
;; Iterate over all key-value pairs
(for ((values key val) (in-leveldb db))
(displayln (bytes->string key) " = " (bytes->string val)))
;; Iterate over keys only
(for (key (in-leveldb-keys db))
(displayln (bytes->string key)))
;; With range
(for ((values key val) (in-leveldb db "a" "z"))
...)(leveldb-property db name) -> string | #fReturns a database property value. Available properties include:
"leveldb.stats"- Multi-line statistics"leveldb.sstables"- SSTable information"leveldb.approximate-memory-usage"- Memory usage estimate
(displayln (leveldb-property db "leveldb.stats"))(leveldb-approximate-size db start-key end-key) -> integerReturns the approximate size in bytes of the data in the given key range.
(leveldb-approximate-size db "a" "z") ;; size of keys from "a" to "z"(leveldb-compact-range db start-key end-key) -> voidCompacts the underlying storage for the given key range.
(leveldb-destroy-db name [opts]) -> voidDestroys (deletes) a database and all its files.
(leveldb-repair-db name [opts]) -> voidAttempts to repair a corrupted database.
(leveldb-options keyword-args ...) -> optionsCreates database options. Keyword arguments:
| Keyword | Type | Default | Description |
|---|---|---|---|
create-if-missing: |
boolean | #t |
Create database if it doesn't exist |
error-if-exists: |
boolean | #f |
Error if database already exists |
paranoid-checks: |
boolean | #f |
Enable paranoid consistency checks |
compression: |
boolean | #t |
Enable Snappy compression |
write-buffer-size: |
integer | — | Write buffer size in bytes |
max-open-files: |
integer | — | Maximum number of open files |
block-size: |
integer | — | Block size in bytes |
block-restart-interval: |
integer | — | Block restart interval |
max-file-size: |
integer | — | Maximum file size in bytes |
lru-cache-capacity: |
integer | — | LRU cache size in bytes |
bloom-filter-bits: |
integer | — | Bloom filter bits per key |
env: |
env | — | Custom environment (for testing) |
(def opts (leveldb-options
write-buffer-size: 67108864 ;; 64MB
max-open-files: 1000
bloom-filter-bits: 10
max-file-size: 2097152)) ;; 2MB
(def db (leveldb-open "/path/to/db" opts))(leveldb-default-options) -> optionsReturns the default options (cached, reusable).
(leveldb-read-options keyword-args ...) -> read-optionsCreates read options. Keyword arguments:
| Keyword | Type | Default | Description |
|---|---|---|---|
verify-checksums: |
boolean | #f |
Verify checksums on read |
fill-cache: |
boolean | #f |
Fill cache on read |
snapshot: |
snapshot | — | Read from a snapshot |
(leveldb-write-options keyword-args ...) -> write-optionsCreates write options. Keyword arguments:
| Keyword | Type | Default | Description |
|---|---|---|---|
sync: |
boolean | #f |
Sync writes to disk |
(leveldb-default-env) -> envReturns the default environment. Can be passed to leveldb-options with env:.
(leveldb-env-test-directory env) -> stringReturns a path to a temporary test directory.
(leveldb-version) -> (values major minor)Returns the LevelDB library version as two values.
(defvalues (major minor) (leveldb-version))
(displayln "LevelDB " major "." minor) ;; e.g., "LevelDB 1.23"All operations may raise LevelDBError on failure.
(leveldb-error? obj) -> booleanPredicate for LevelDB errors.
(with-catch
(lambda (e)
(when (leveldb-error? e)
(displayln "LevelDB error: " (error-message e))))
(lambda ()
(leveldb-open "/nonexistent/path")))The following LevelDB C API features are not exposed due to FFI callback complexity:
- Custom comparators (
leveldb_comparator_create) - Custom filter policies (
leveldb_filterpolicy_create) - Write batch iteration (
leveldb_writebatch_iterate) - Custom environments and loggers
For custom key ordering, design your keys to sort correctly with the default byte-ordering comparator (e.g., use zero-padded numbers).
© 2017-2023 The Gerbil Core Team and contributors; License: LGPLv2.1 and Apache 2.0
Originally written by vyzo.