package snkv

  1. Overview
  2. Docs

doc/README.html

SNKV OCaml Bindings

License

OCaml FFI bindings and high-level API for SNKV, a persistent, ACID-compliant key-value store built on SQLite's B-tree engine.

Features

  • Full SNKV API coverage: All C library functions available through OCaml bindings
  • Two-level API: Low-level direct bindings and high-level OCaml-style API with algebraic types
  • Column families: Logical namespaces for data organization
  • TTL support: Time-to-live with automatic expiration
  • Encryption: Password-based authenticated encryption (XChaCha20-Poly1305)
  • Transactions: ACID-compliant transactions with read/write modes
  • Iterators: Forward, reverse, and prefix-based iteration
  • Statistics: Runtime performance and usage metrics

Requirements

  • OCaml 5.0+ (tested with 5.4.1)
  • Dune 3.21+
  • C compiler (GCC or Clang)
  • SQLite development headers (included in SNKV amalgamation)

Installation

From OPAM (recommended)

opam install snkv

From Source

git clone https://codeberg.org/tomaszb/snkv-ocaml.git
cd snkv-ocaml
dune build
dune install

For Development

git clone https://codeberg.org/tomaszb/snkv-ocaml.git
cd snkv-ocaml
opam pin add snkv .

Quick Start

Using the High-Level API (Recommended)

open Kv

(* Open an in-memory database *)
let db = open_exn () in

(* Basic operations *)
let () = put db ~key:"hello" ~value:"world" |> Result.get_ok in
let value = get db ~key:"hello" |> Result.get_ok in
print_endline value;  (* "world" *)

(* TTL operations *)
let now = TTL.now_ms () in
let () = TTL.put db ~key:"temp" ~value:"data" ~expire_ms:(Int64.add now 5000L) 
  |> Result.get_ok in

(* Column families *)
let cf = CF.create db "mycf" |> Result.get_ok in
let () = CF.put cf ~key:"foo" ~value:"bar" |> Result.get_ok in

(* Transactions *)
let () = Txn.with_transaction db Txn.Write (fun () ->
  put db ~key:"tx1" ~value:"val1"
) |> Result.get_ok in

close db

Using the Low-Level API

open Snkv

(* Direct C bindings *)
let db = open_ () in
put db ~key:"hello" ~value:"world";
let value = get db ~key:"hello" in
print_endline value;
close db

Documentation

Comprehensive API documentation is available:

You can also generate API documentation locally:

dune build @doc
# Open _build/default/_doc/_html/index.html

Examples

The project includes a complete example demonstrating all features:

dune exec snkv

This runs the example program in bin/main.ml which covers:

  • Basic key-value operations
  • Column family management
  • Iterator usage with higher-order functions
  • TTL operations with expiration
  • Transaction handling
  • Statistics collection
  • Encryption API (create, re-encrypt, remove)

Project Structure

snkv-ocaml/
├── lib/
│   ├── snkv.ml[i]      # Low-level C FFI bindings
│   ├── snkv_api.ml[i]  # High-level OCaml API
│   └── snkv_stubs.c    # C implementation
├── bin/
│   └── main.ml         # Example program
├── test/
│   └── test_snkv.ml    # Test suite
├── doc/                # Documentation
└── dune-project        # Build configuration

Testing

Run the test suite:

dune runtest

Or run specific tests:

dune exec test/test_snkv.exe

Error Handling

The high-level API uses OCaml's result type:

match Kv.put db ~key:"test" ~value:"data" with
| Ok () -> print_endline "Success"
| Error e -> Printf.printf "Error: %s\n" (Kv.error_to_string e)

Error codes are mapped to algebraic types:

  • Ok - Success
  • Error - Generic error
  • Busy - Database locked by another connection
  • NotFound - Key or column family not found
  • AuthFailed - Wrong password or corrupted encrypted store
  • Corrupt - Database file is malformed
  • etc.

Encryption Support

SNKV supports password-based authenticated encryption:

(* Create encrypted store *)
let db = Encryption.open_exn ~filename:"secure.db" ~password:"secret" in

(* Check encryption status *)
let encrypted = Encryption.is_encrypted db in

(* Re-encrypt with new password *)
Encryption.reencrypt db ~password:"newsecret" |> Result.get_ok;

(* Remove encryption *)
Encryption.remove_encryption db |> Result.get_ok;

Performance

The bindings have minimal overhead:

  • Direct C function calls through FFI
  • Zero-copy for key/value data where possible

License

This project is licensed under the Apache License 2.0 - see the LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request on Codeberg.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Support

Acknowledgments

  • SNKV - The underlying C key-value store
  • SQLite - The embedded database engine