Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

[package]
name = "kite_sql"
version = "0.2.0"
version = "0.2.1"
edition = "2021"
build = "build.rs"
authors = ["Kould <kould2333@gmail.com>", "Xwg <loloxwg@gmail.com>"]
description = "SQL as a Function for Rust"
documentation = "https://docs.rs/kite_sql/latest/kite_sql/"
Expand All @@ -28,6 +29,7 @@ default = ["macros", "rocksdb"]
macros = []
orm = []
rocksdb = ["dep:rocksdb"]
unsafe_txdb_checkpoint = ["rocksdb", "dep:librocksdb-sys"]
lmdb = ["dep:lmdb", "dep:lmdb-sys"]
net = ["rocksdb", "dep:pgwire", "dep:async-trait", "dep:clap", "dep:env_logger", "dep:futures", "dep:log", "dep:tokio"]
pprof = ["pprof/criterion", "pprof/flamegraph"]
Expand Down Expand Up @@ -86,6 +88,7 @@ sqlite = { version = "0.34" }

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
rocksdb = { version = "0.23", optional = true }
librocksdb-sys = { version = "0.17.1", optional = true }
lmdb = { version = "0.8.0", optional = true }
lmdb-sys = { version = "0.8.0", optional = true }

Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,15 @@ fn main() -> Result<(), DatabaseError> {
- `build_lmdb()` opens a persistent LMDB-backed database.
- `build_in_memory()` opens an in-memory database for tests, examples, and temporary workloads.
- `build_optimistic()` is available on native targets when you specifically want optimistic transactions on top of RocksDB.
- `Database::checkpoint(path)` creates a local consistent snapshot when the selected storage backend supports it.
- Cargo features:
- `rocksdb` is enabled by default
- `lmdb` is optional
- `unsafe_txdb_checkpoint` enables experimental checkpoint support for RocksDB `TransactionDB`
- `cargo check --no-default-features --features lmdb` builds an LMDB-only native configuration

On native targets, `LMDB` shines when reads dominate, while `RocksDB` is usually the stronger choice when writes do.
Checkpoint support and feature-gating details are documented in [docs/features.md](docs/features.md).

👉**more examples**
- [hello_world](examples/hello_world.rs)
Expand Down
93 changes: 93 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use std::env;
use std::fs;
use std::path::Path;

const SUPPORTED_ROCKSDB_VERSION: &str = "0.23.0";
const SUPPORTED_LIBROCKSDB_SYS_VERSION: &str = "0.17.1+9.9.3";

fn main() {
println!("cargo:rerun-if-changed=Cargo.lock");
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_UNSAFE_TXDB_CHECKPOINT");

if env::var_os("CARGO_FEATURE_UNSAFE_TXDB_CHECKPOINT").is_none() {
return;
}

let lock_path = Path::new("Cargo.lock");
let lock_contents = fs::read_to_string(lock_path)
.unwrap_or_else(|err| panic!("failed to read {}: {err}", lock_path.display()));

ensure_locked_version(
&lock_contents,
"rocksdb",
SUPPORTED_ROCKSDB_VERSION,
"unsafe_txdb_checkpoint",
);
ensure_locked_version(
&lock_contents,
"librocksdb-sys",
SUPPORTED_LIBROCKSDB_SYS_VERSION,
"unsafe_txdb_checkpoint",
);
}

fn ensure_locked_version(
lock_contents: &str,
expected_name: &str,
expected_version: &str,
feature_name: &str,
) {
let found_version = find_locked_version(lock_contents, expected_name);

match found_version.as_deref() {
Some(version) if version == expected_version => {}
Some(version) => panic!(
"feature `{feature_name}` only supports `{expected_name} = {expected_version}`, found `{expected_name} = {version}` in Cargo.lock; disable the feature or re-validate the implementation"
),
None => panic!(
"feature `{feature_name}` requires `{expected_name} = {expected_version}` in Cargo.lock, but `{expected_name}` was not found"
),
}
}

fn find_locked_version(lock_contents: &str, expected_name: &str) -> Option<String> {
let mut current_name = None;
let mut current_version = None;

for line in lock_contents.lines() {
let line = line.trim();
if line == "[[package]]" {
if current_name.as_deref() == Some(expected_name) {
return current_version;
}
current_name = None;
current_version = None;
continue;
}

if let Some(value) = extract_toml_string(line, "name") {
current_name = Some(value.to_string());
continue;
}

if let Some(value) = extract_toml_string(line, "version") {
current_version = Some(value.to_string());
}
}

if current_name.as_deref() == Some(expected_name) {
current_version
} else {
None
}
}

fn extract_toml_string<'a>(line: &'a str, key: &str) -> Option<&'a str> {
let prefix = match key {
"name" => "name = \"",
"version" => "version = \"",
_ => return None,
};
let rest = line.strip_prefix(prefix)?;
rest.strip_suffix('"')
}
29 changes: 29 additions & 0 deletions docs/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,35 @@ let kite_sql = DataBaseBuilder::path("./data")
- Pessimistic (Default)
- Optimistic

### Checkpoint
KiteSQL exposes checkpoint as a storage capability rather than a full backup workflow. A checkpoint only creates a consistent local snapshot directory; compressing, uploading, retaining, and pruning backups should stay in application code.

Support matrix:
- `build_optimistic()` supports `Database::checkpoint(...)` through RocksDB's safe checkpoint API.
- `build_rocksdb()` requires Cargo feature `unsafe_txdb_checkpoint` because upstream `rocksdb` does not currently expose a safe `TransactionDB` checkpoint API.
- `build_lmdb()` and `build_in_memory()` do not currently expose checkpoint support.

Opt in for `TransactionDB` checkpoint support:
```bash
cargo check --features unsafe_txdb_checkpoint
```

Minimal usage:
```rust
use kite_sql::db::DataBaseBuilder;
use kite_sql::errors::DatabaseError;

fn main() -> Result<(), DatabaseError> {
let database = DataBaseBuilder::path("./data").build_rocksdb()?;

database.checkpoint("./backup/checkpoint-2026-03-29")?;

Ok(())
}
```

If `unsafe_txdb_checkpoint` is not enabled, `build_rocksdb()` returns an explicit error instead of attempting the experimental implementation.

### Field options
- [not] null
- unique
Expand Down
Loading
Loading