lithos 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7741f8dffd9dd5d4d0f710b18fca0a7b1a0d574e893d60c9f5735c36a93954d6
4
+ data.tar.gz: 6d4eb49a96a6cb44a97587f997905cc77c4e93bd4c33f64579db48754180b7d8
5
+ SHA512:
6
+ metadata.gz: 6d24765cfbfdc9d6394eacd84081eeba1891f9f8423d2c3665cb7270e417e0cfe4d3e147b79e97607cc1ed6c56d96894805c13a88db2957de37fe350401f60bb
7
+ data.tar.gz: 4af63db49e563dc16b3411f44a238b86174336b532f1caa6ab478c8e7d68b8282e3ec8d291eeba821177bdda0d0ab654eeaca2a61b4eaf4d735797d40d244883
data/CHANGELOG.md ADDED
@@ -0,0 +1,28 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format is based on
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
5
+ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.1.0] - 2026-05-30
10
+
11
+ ### Added
12
+ - `Lithos.open(path, sync:, memtable_bytes:)` with block (auto-close) and
13
+ non-block forms; `#close`, `#closed?`, `#path`.
14
+ - `#put`/`#[]=`, `#get`/`#[]`, `#delete`, `#key?` (+ `include?`/`has_key?`),
15
+ `#fetch` (with default/block, raises `KeyError`).
16
+ - Ordered iteration: `#each`, `#each_key`, `#scan(gte:/gt:/lte:/lt:)`,
17
+ `#range(from, to)`; `Enumerable` mixed in; `#size`/`#length`, `#empty?`, `#to_h`.
18
+ - `#flush` (seal the memtable into an SSTable) and `#compact` (merge SSTables,
19
+ dropping shadowed keys and tombstones).
20
+ - LSM engine: CRC32 write-ahead log (durable per write in sync mode), sorted
21
+ memtable, immutable memory-mapped SSTables with bloom filters + sparse index,
22
+ atomically-published MANIFEST catalog, crash recovery via WAL replay (torn /
23
+ bad-CRC tail discarded), and an exclusive single-writer directory lock.
24
+ - Arbitrary binary keys and values (embedded NULs); lexicographic unsigned-byte
25
+ key ordering.
26
+
27
+ [Unreleased]: https://github.com/main-path/lithos/compare/v0.1.0...HEAD
28
+ [0.1.0]: https://github.com/main-path/lithos/releases/tag/v0.1.0
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ned
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,101 @@
1
+ # lithos
2
+
3
+ **A small embedded, ordered, crash-safe key-value store for Ruby — no external database.**
4
+
5
+ `lithos` is a from-scratch storage engine: a **log-structured merge (LSM) tree**,
6
+ the same design behind LevelDB/RocksDB, written as a native Ruby extension with
7
+ **zero external dependency**. You get:
8
+
9
+ - **Durable writes** — every `put`/`delete` is appended to a CRC-checked
10
+ write-ahead log and `fsync`'d before it returns (in the default `sync:` mode).
11
+ - **Crash recovery** — on open, the WAL is replayed; a torn or corrupted tail is
12
+ detected and discarded.
13
+ - **Ordered keys** — keys are stored sorted (unsigned-byte order), so you get
14
+ `each`, `each_key`, and range `scan`s for free.
15
+ - **Binary safe** — keys and values are arbitrary byte strings (embedded NULs OK).
16
+
17
+ The niche it fills: every other ordered + crash-safe Ruby KV store is a binding
18
+ to an external C/C++ library (LMDB/LevelDB/RocksDB) that's a pain to build on a
19
+ native-MSVC Windows Ruby. `lithos` is self-contained and builds with
20
+ [`vcvars`](https://rubygems.org/gems/vcvars) — no prebuilt database needed.
21
+
22
+ ## Requirements
23
+
24
+ - **Windows** with a native **MSVC (mswin)** Ruby. Not supported on MinGW/UCRT.
25
+ - Visual Studio 2017+ / Build Tools with the **Desktop development with C++** workload.
26
+
27
+ ## Install
28
+
29
+ ```sh
30
+ gem install lithos
31
+ ```
32
+
33
+ ## Usage
34
+
35
+ ```ruby
36
+ require "lithos"
37
+
38
+ Lithos.open("data/mydb") do |db|
39
+ db["alpha"] = "one"
40
+ db.put("beta", "two")
41
+ db.put("\x00raw\xff", "binary ok") # arbitrary binary keys + values
42
+
43
+ db["alpha"] # => "one"
44
+ db["missing"] # => nil
45
+ db.key?("beta") # => true
46
+ db.fetch("nope", "default") # => "default" (or raises KeyError)
47
+ db.delete("beta") # => true (existed)
48
+
49
+ # ordered iteration (ascending unsigned-byte key order)
50
+ db.each { |k, v| puts "#{k}=#{v}" }
51
+ db.each_key { |k| puts k }
52
+
53
+ # ordered range scans
54
+ db.scan(gte: "a", lt: "m") { |k, v| ... } # gt/lt exclusive, gte/lte inclusive
55
+ db.range("a", "m") { |k, v| ... } # half-open [a, m)
56
+ db.scan(gte: "a").to_a # Enumerator without a block
57
+
58
+ db.size # live key count
59
+ db.flush # seal the memtable into an SSTable
60
+ db.compact # merge SSTables, dropping shadowed keys + tombstones
61
+ end # closed automatically (flush + fsync)
62
+ ```
63
+
64
+ Open without a block when you want to manage the lifetime yourself:
65
+
66
+ ```ruby
67
+ db = Lithos.open("data/mydb", sync: true)
68
+ db["k"] = "v"
69
+ db.close
70
+ ```
71
+
72
+ Data persists across reopens, and survives a crash (process kill, power loss at
73
+ the OS-flush boundary): reopening replays the WAL and discards any partial tail.
74
+
75
+ ## How it works
76
+
77
+ ```
78
+ put/delete ──> WAL (append + CRC + fsync) ──> memtable (sorted std::map)
79
+ │ (size threshold)
80
+
81
+ SSTable (immutable, mmap'd:
82
+ sorted data + bloom + sparse index)
83
+ get ──> memtable ──> SSTables newest→oldest (bloom-filtered)
84
+ compact ──> k-way merge of all SSTables ──> one SSTable (drops tombstones)
85
+ ```
86
+
87
+ The set of live SSTables + the active WAL is recorded in a `MANIFEST` that is
88
+ rewritten atomically (temp file + `FlushFileBuffers` + atomic rename), so the
89
+ on-disk catalog is never observed half-updated.
90
+
91
+ ## Notes
92
+
93
+ - **Durability vs speed:** `sync: true` (default) `fsync`s every write. For bulk
94
+ loads, `Lithos.open(path, sync: false)` skips per-write `fsync` (call `#flush`
95
+ or `#close` to make data durable) — faster, but a crash can lose recent writes.
96
+ - **Single writer:** a store takes an exclusive directory lock on open; it is not
97
+ safe to share one store across threads (give each thread its own, or use a Mutex).
98
+
99
+ ## License
100
+
101
+ [MIT](LICENSE.txt).
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # extconf.rb for the lithos LSM key-value store extension.
4
+
5
+ require "mkmf"
6
+
7
+ unless RbConfig::CONFIG["target_os"] =~ /mswin/
8
+ abort <<~MSG
9
+ lithos requires a native Windows MSVC (mswin) Ruby — its storage engine uses
10
+ Win32 file APIs (memory-mapped SSTables, FlushFileBuffers, atomic rename) and
11
+ is built with cl.exe. Your Ruby is "#{RbConfig['arch']}".
12
+ MSG
13
+ end
14
+
15
+ # C++ engine (std::map/std::string/std::vector/std::priority_queue) — needs C++ exceptions.
16
+ $CXXFLAGS << " -EHsc"
17
+
18
+ # kernel32 (file APIs / mapping) is linked by default; no extra import libs needed.
19
+
20
+ create_makefile("lithos/lithos")