foldlitedb 0.1.0__tar.gz
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.
- foldlitedb-0.1.0/DESIGN.md +190 -0
- foldlitedb-0.1.0/LICENSE +21 -0
- foldlitedb-0.1.0/PKG-INFO +239 -0
- foldlitedb-0.1.0/README.md +218 -0
- foldlitedb-0.1.0/docs/api.html +197 -0
- foldlitedb-0.1.0/docs/concepts.html +79 -0
- foldlitedb-0.1.0/docs/index.html +67 -0
- foldlitedb-0.1.0/docs/layout.html +40 -0
- foldlitedb-0.1.0/docs/pages.json +8 -0
- foldlitedb-0.1.0/docs/playground.html +67 -0
- foldlitedb-0.1.0/docs/portable.html +225 -0
- foldlitedb-0.1.0/docs/releasing.html +35 -0
- foldlitedb-0.1.0/docs/static/favicon.svg +1 -0
- foldlitedb-0.1.0/docs/static/playground.css +2 -0
- foldlitedb-0.1.0/docs/static/playground.js +132 -0
- foldlitedb-0.1.0/docs/static/site.js +83 -0
- foldlitedb-0.1.0/docs/static/styles.css +6 -0
- foldlitedb-0.1.0/examples/catalogue.py +76 -0
- foldlitedb-0.1.0/examples/portable_metrics.py +37 -0
- foldlitedb-0.1.0/examples/telemetry.py +119 -0
- foldlitedb-0.1.0/native/Cargo.lock +752 -0
- foldlitedb-0.1.0/native/Cargo.toml +7 -0
- foldlitedb-0.1.0/native/engine/Cargo.toml +21 -0
- foldlitedb-0.1.0/native/engine/src/lib.rs +940 -0
- foldlitedb-0.1.0/native/engine/src/runtime.rs +201 -0
- foldlitedb-0.1.0/native/engine/src/storage.rs +440 -0
- foldlitedb-0.1.0/native/engine/tests/native_storage.rs +405 -0
- foldlitedb-0.1.0/native/engine/tests/portable.rs +527 -0
- foldlitedb-0.1.0/native/engine/tests/ux.rs +339 -0
- foldlitedb-0.1.0/native/licenses/wasmi/LICENSE-APACHE +201 -0
- foldlitedb-0.1.0/native/licenses/wasmi/LICENSE-MIT +25 -0
- foldlitedb-0.1.0/native/licenses/wasmi/SOURCES.txt +4 -0
- foldlitedb-0.1.0/native/licenses/wasmparser/LICENSE-APACHE +201 -0
- foldlitedb-0.1.0/native/licenses/wasmparser/LICENSE-Apache-2.0_WITH_LLVM-exception +220 -0
- foldlitedb-0.1.0/native/licenses/wasmparser/LICENSE-MIT +23 -0
- foldlitedb-0.1.0/native/licenses/wasmparser/SOURCES.txt +5 -0
- foldlitedb-0.1.0/native/python/Cargo.toml +18 -0
- foldlitedb-0.1.0/native/python/src/lib.rs +44 -0
- foldlitedb-0.1.0/pyproject.toml +47 -0
- foldlitedb-0.1.0/scripts/benchmark_database.py +153 -0
- foldlitedb-0.1.0/scripts/build_docs.py +105 -0
- foldlitedb-0.1.0/scripts/build_native_notices.py +78 -0
- foldlitedb-0.1.0/scripts/check_docs.py +154 -0
- foldlitedb-0.1.0/scripts/publish_docs.py +148 -0
- foldlitedb-0.1.0/src/foldlitedb/NATIVE_THIRD_PARTY_LICENSES.txt +11822 -0
- foldlitedb-0.1.0/src/foldlitedb/__init__.py +25 -0
- foldlitedb-0.1.0/src/foldlitedb/database.py +305 -0
- foldlitedb-0.1.0/src/foldlitedb/fileio.py +162 -0
- foldlitedb-0.1.0/src/foldlitedb/portable.py +7 -0
- foldlitedb-0.1.0/src/foldlitedb/portable_assets/THIRD_PARTY_LICENSES.txt +407 -0
- foldlitedb-0.1.0/src/foldlitedb/portable_assets/catalogue.json +12 -0
- foldlitedb-0.1.0/src/foldlitedb/portable_assets/catalogue.wasm +0 -0
- foldlitedb-0.1.0/src/foldlitedb/portable_assets/client.js +97 -0
- foldlitedb-0.1.0/src/foldlitedb/portable_assets/errors.js +40 -0
- foldlitedb-0.1.0/src/foldlitedb/portable_assets/host.js +201 -0
- foldlitedb-0.1.0/src/foldlitedb/portable_assets/metrics.json +12 -0
- foldlitedb-0.1.0/src/foldlitedb/portable_assets/metrics.wasm +0 -0
- foldlitedb-0.1.0/src/foldlitedb/portable_assets/worker.js +206 -0
- foldlitedb-0.1.0/src/foldlitedb/projection.py +70 -0
- foldlitedb-0.1.0/src/foldlitedb/streaming.py +135 -0
- foldlitedb-0.1.0/src/foldlitedb/streams.py +139 -0
- foldlitedb-0.1.0/src/foldlitedb/types.py +85 -0
- foldlitedb-0.1.0/tests/browser/test_portable_browser.py +350 -0
- foldlitedb-0.1.0/tests/test_add.py +117 -0
- foldlitedb-0.1.0/tests/test_convenience_api.py +103 -0
- foldlitedb-0.1.0/tests/test_database.py +206 -0
- foldlitedb-0.1.0/tests/test_docs_publishing.py +54 -0
- foldlitedb-0.1.0/tests/test_fileio.py +41 -0
- foldlitedb-0.1.0/tests/test_native_cache.py +156 -0
- foldlitedb-0.1.0/tests/test_portable.py +14 -0
- foldlitedb-0.1.0/tests/test_streaming.py +40 -0
- foldlitedb-0.1.0/tests/test_streams.py +103 -0
- foldlitedb-0.1.0/tests/test_ux.py +182 -0
- foldlitedb-0.1.0/views/.gitignore +2 -0
- foldlitedb-0.1.0/views/README.md +191 -0
- foldlitedb-0.1.0/views/assembly/examples/catalogue.ts +69 -0
- foldlitedb-0.1.0/views/assembly/examples/metrics.ts +83 -0
- foldlitedb-0.1.0/views/assembly/sdk/index.ts +195 -0
- foldlitedb-0.1.0/views/assembly/sdk/number.ts +168 -0
- foldlitedb-0.1.0/views/assembly/sdk/parse.ts +88 -0
- foldlitedb-0.1.0/views/package-lock.json +87 -0
- foldlitedb-0.1.0/views/package.json +20 -0
- foldlitedb-0.1.0/views/scripts/build-view.mjs +77 -0
- foldlitedb-0.1.0/views/scripts/build.mjs +53 -0
- foldlitedb-0.1.0/views/scripts/inspect-view.mjs +30 -0
- foldlitedb-0.1.0/views/scripts/view-build.mjs +60 -0
- foldlitedb-0.1.0/views/test/custom-build.test.mjs +136 -0
- foldlitedb-0.1.0/views/test/modules.test.mjs +224 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# Foldlite DB design
|
|
2
|
+
|
|
3
|
+
Foldlite DB derives live views from immutable documents. Its computation model is
|
|
4
|
+
inspired by CouchDB: map each document into keyed contributions, then reduce each
|
|
5
|
+
key. Its persistence model is a Rust append-only document log with a disposable
|
|
6
|
+
cache. Python exposes that engine directly. One compiled WebAssembly module
|
|
7
|
+
contains the full map and reducer, and runs unchanged in the native host and a
|
|
8
|
+
browser worker.
|
|
9
|
+
|
|
10
|
+
## Separate facts from derived state
|
|
11
|
+
|
|
12
|
+
The document log is the persistent source for this engine. Accepted documents are
|
|
13
|
+
immutable. An identical replay is a no-op; conflicting reuse of an identity or
|
|
14
|
+
source position is an error. Changes in a domain are new documents, rather than
|
|
15
|
+
mutations of old observations.
|
|
16
|
+
|
|
17
|
+
Document indexes, source checkpoints, group states, finalized results, and change
|
|
18
|
+
history are derived from those facts and the exact view module. They can be
|
|
19
|
+
reconstructed. A cache is useful only while its dependencies can be verified:
|
|
20
|
+
format version, document-log identity, committed prefix and digest, and compiled
|
|
21
|
+
module digest. Missing, corrupt, or incompatible cache data cannot silently
|
|
22
|
+
become authoritative.
|
|
23
|
+
|
|
24
|
+
Applications must back up the document log and computation artifacts, or retain
|
|
25
|
+
an external authoritative document stream with stable identities and order.
|
|
26
|
+
Deleting a cache is safe; deleting the only copy of the log is data loss. A
|
|
27
|
+
reference version is insufficient to reproduce a lost reference snapshot; any
|
|
28
|
+
reference data needed by a deterministic view must remain reproducible.
|
|
29
|
+
|
|
30
|
+
## Native durability
|
|
31
|
+
|
|
32
|
+
`native/engine` owns storage and Wasm execution. The path passed to `Database`
|
|
33
|
+
is a log file; `.cache` and `.lock` siblings hold an optional cache checkpoint and
|
|
34
|
+
an operating-system lock. One active owner may open a persistent log. `:memory:`
|
|
35
|
+
uses the same computation without persistent files or durable acknowledgements.
|
|
36
|
+
|
|
37
|
+
The log has an identity and checksummed, hash-linked frames containing accepted
|
|
38
|
+
document batches. The source format does not contain a view-module dependency.
|
|
39
|
+
An ingestion operation validates identities, source order, limits, mapping, and
|
|
40
|
+
reduction before writing. The engine appends the complete frame and syncs it
|
|
41
|
+
before acknowledging the batch, then exposes its already-computed derived state.
|
|
42
|
+
A failed validation or view operation cannot commit a batch prefix. An I/O error
|
|
43
|
+
can leave commit outcome uncertain, as with any durable append; reopen and retry
|
|
44
|
+
using explicit document identities rather than assuming a failed acknowledgement
|
|
45
|
+
means absence.
|
|
46
|
+
|
|
47
|
+
Opening verifies the complete log. An incomplete final frame can be discarded
|
|
48
|
+
as an interrupted append. A complete frame with corrupt checksums or invalid
|
|
49
|
+
content is an error; the engine does not skip committed source data. Frame size
|
|
50
|
+
is bounded to 8 MiB. The ordinary map-request limit is smaller and often limits a
|
|
51
|
+
batch first.
|
|
52
|
+
|
|
53
|
+
`checkpoint()` writes an atomic derived snapshot, and graceful `close()` also
|
|
54
|
+
checkpoints. Checkpoints are not written after every ingestion. Encoded cache
|
|
55
|
+
snapshots are limited to 1 GiB. Checkpoint errors, including on close, are reported;
|
|
56
|
+
they do not undo already-synced document batches. A failed close still releases
|
|
57
|
+
the native handle. A valid snapshot
|
|
58
|
+
must match the log identity, exact module digest, and verified prefix. The host
|
|
59
|
+
loads it and replays only the original suffix batches through Wasm. A missing,
|
|
60
|
+
invalid, or different-module cache triggers a full rebuild from the log.
|
|
61
|
+
|
|
62
|
+
A checkpoint is a performance hint: failure or absence must not change the
|
|
63
|
+
meaning of accepted documents. Its checksum and verified log prefix detect
|
|
64
|
+
accidental corruption and stale files; they are not an authenticity guarantee
|
|
65
|
+
against an adversary who can rewrite local files and checksums.
|
|
66
|
+
|
|
67
|
+
## Rebuild as the ordinary computation path
|
|
68
|
+
|
|
69
|
+
Live ingestion and replay use the same map, grouping, ordered fold, and finalizer.
|
|
70
|
+
Rebuild preserves accepted document order and original batch boundaries. That
|
|
71
|
+
also preserves batch-dependent engine sequence allocation; a separate export and
|
|
72
|
+
re-import with different boundaries need only preserve view state and results.
|
|
73
|
+
|
|
74
|
+
`rebuild()` discards derived state, replays the log, creates a new cursor
|
|
75
|
+
generation, and checkpoints it. Opening the same log with a changed module does
|
|
76
|
+
the same reconstruction automatically. Neither operation rewrites documents.
|
|
77
|
+
An unchanged valid cache preserves its generation across reopen; cursor consumers
|
|
78
|
+
must obtain a new snapshot after reconstruction.
|
|
79
|
+
|
|
80
|
+
Rebuild cost is a linear read of the log plus Wasm work for uncached documents
|
|
81
|
+
and their emissions. A valid cache avoids Wasm execution for its verified prefix,
|
|
82
|
+
but opening still reads that prefix to validate it. There is no unmeasured
|
|
83
|
+
throughput promise. Current documents, indexes, grouped states, and change history
|
|
84
|
+
grow in host memory; bounded per-call Wasm memory is not a total-memory bound.
|
|
85
|
+
Compaction, incremental checkpoint formats, and multiple native views remain
|
|
86
|
+
future work rather than implicit capabilities.
|
|
87
|
+
|
|
88
|
+
## Identity and order
|
|
89
|
+
|
|
90
|
+
The public input is a `Document(id, payload, position, source)`. Payloads are
|
|
91
|
+
finite JSON. `add` can generate IDs and source positions; `add_many` resolves one
|
|
92
|
+
atomic batch. Generated IDs are stable only after resolution, so an unnamed
|
|
93
|
+
retry creates another observation. External sources can provide their own IDs
|
|
94
|
+
and monotonically increasing positions with gaps. Positions start at zero when
|
|
95
|
+
assigned automatically and are scoped to a source.
|
|
96
|
+
|
|
97
|
+
An identical named append reuses its original position even after later records
|
|
98
|
+
arrive. A supplied source position can also identify a replay without a supplied
|
|
99
|
+
ID. Reusing an ID or position with different content fails. Previously unseen
|
|
100
|
+
positions behind the source checkpoint fail. Source progress and document
|
|
101
|
+
acceptance are one logical commit.
|
|
102
|
+
|
|
103
|
+
Per-key reduction follows ingestion order, including within a batch. Source
|
|
104
|
+
positions do not sort documents across sources, and timestamps do not reorder a
|
|
105
|
+
fold. Applications choose domain order before ingestion. Maps receive payloads;
|
|
106
|
+
identity, deduplication, positions, and transaction boundaries belong to the host.
|
|
107
|
+
Any domain metadata a view needs belongs in its explicit payload or declared
|
|
108
|
+
reproducible module data.
|
|
109
|
+
|
|
110
|
+
## Portable computation
|
|
111
|
+
|
|
112
|
+
A view exports `descriptor`, `map`, `identity`, `add`, `finalize`, and optionally
|
|
113
|
+
`merge` through ABI v1. AssemblyScript is the first SDK; the ABI does not require
|
|
114
|
+
that source language. A map returns zero or more JSON key/value contributions.
|
|
115
|
+
The host partitions by canonical keys and supplies ordered contributions to the
|
|
116
|
+
module's reducer.
|
|
117
|
+
|
|
118
|
+
State is explicit. Fresh Wasm instances prevent module globals from carrying
|
|
119
|
+
state between requests. Views must not depend on clocks, randomness, mutable
|
|
120
|
+
external data, or request boundaries. Splitting one ordered contribution sequence
|
|
121
|
+
across successive `add` calls must produce equivalent state. Implement `merge`
|
|
122
|
+
only when independently covered compatible states can be combined correctly;
|
|
123
|
+
an ordered lifecycle fold need not be mergeable.
|
|
124
|
+
|
|
125
|
+
The exact module SHA-256 binds cached state to computation, state schema, compiler,
|
|
126
|
+
and SDK runtime. Human-readable view and state versions explain changes but do
|
|
127
|
+
not override a changed digest. Preserve the previous module to reproduce its
|
|
128
|
+
previous result. Opening the same documents with another module is a new derived
|
|
129
|
+
view and invalidates old cursors.
|
|
130
|
+
|
|
131
|
+
Modules have no host imports. ABI requests and responses are limited to 256 KiB,
|
|
132
|
+
linear memory to 16 MiB, and native execution to a fuel budget. Ingestion is
|
|
133
|
+
bounded to 1024 documents and 4096 emissions per batch. JSON nesting is bounded
|
|
134
|
+
to 64 levels. Python releases the GIL while the native engine runs. These limits
|
|
135
|
+
isolate individual operations; they do not bound accumulated host storage.
|
|
136
|
+
|
|
137
|
+
JSON numbers follow finite IEEE-754 double semantics in both hosts. Python
|
|
138
|
+
rejects integers that cannot be represented exactly as doubles. Source positions
|
|
139
|
+
and engine sequences stay within JavaScript's nonnegative safe integer range.
|
|
140
|
+
Canonical object keys and numeric formatting agree across hosts. Floating-point
|
|
141
|
+
addition is not associative, so arbitrary merge trees can change rounding.
|
|
142
|
+
|
|
143
|
+
## Reads and cursor generations
|
|
144
|
+
|
|
145
|
+
A snapshot identifies a database generation, module digest, and committed
|
|
146
|
+
sequence. Bounded pages retain a stable prefix while ingestion continues. Change
|
|
147
|
+
pages return complete resulting key states after a cursor, coalesced per key
|
|
148
|
+
within each batch. Zero-emission documents still advance progress. Sequence is
|
|
149
|
+
not a document count: inserted documents and changed group states allocate it.
|
|
150
|
+
|
|
151
|
+
`rows()` and `documents()` pin their prefix on first iteration and release the
|
|
152
|
+
engine between pages. No lock spans a yield into application code. The persistent
|
|
153
|
+
file's ownership lock is retained for the database lifetime. Cursors are local
|
|
154
|
+
continuation markers, not access credentials. Rebuild or module change starts a
|
|
155
|
+
new generation and explicitly expires old cursors. Current history is retained;
|
|
156
|
+
there is no compaction or reader-retention policy yet.
|
|
157
|
+
|
|
158
|
+
## Python packaging and the browser
|
|
159
|
+
|
|
160
|
+
`Database` and `View` are the primary Python types; `PortableDatabase` and
|
|
161
|
+
`PortableView` are exact aliases. The package has one native storage and
|
|
162
|
+
computation path. `native/python` provides PyO3 bindings, and maturin builds the
|
|
163
|
+
extension into wheels. Source builds need Python 3.11+, Rust/Cargo 1.90+, and a C
|
|
164
|
+
toolchain. Bundled modules need no Node; authoring uses Node 20+.
|
|
165
|
+
|
|
166
|
+
The browser worker runs the same module bytes, with JavaScript owning grouping
|
|
167
|
+
and in-memory storage. It does not run the Rust log engine and has no persistent
|
|
168
|
+
browser storage yet. Export and replay resolved documents to preserve work.
|
|
169
|
+
Worker deadlines, retained-byte limits, and document/group/history caps bound
|
|
170
|
+
this preview's requests and retained data. A timeout discards its memory.
|
|
171
|
+
|
|
172
|
+
## Acceptance and evidence
|
|
173
|
+
|
|
174
|
+
Correctness requires immutable-identity conflicts, source-order enforcement,
|
|
175
|
+
atomic batches, interrupted-tail recovery, complete-corruption rejection,
|
|
176
|
+
single-owner locking, checkpoint validation, suffix replay, module replacement,
|
|
177
|
+
and explicit rebuild. Rebuild and live execution must agree on structured keys,
|
|
178
|
+
ordered state, and results. Snapshot/change continuity survives a valid cache
|
|
179
|
+
reopen and fails explicitly after a new generation. Native and actual browser
|
|
180
|
+
execution must agree for the same module and supported numerical inputs.
|
|
181
|
+
|
|
182
|
+
Installation checks exercise built wheels without local compilers, and source
|
|
183
|
+
distributions with build prerequisites. PyPI publication remains pending. Future
|
|
184
|
+
performance evidence must record workload, fixture, batch size, documents,
|
|
185
|
+
emissions, key cardinality, host/runtime, durability, log/cache bytes, peak memory,
|
|
186
|
+
rebuild time, reopen validation time, and document-to-query latency. Run `python scripts/benchmark_database.py --documents 10000 --keys 16
|
|
187
|
+
--batch-size 100 --live-documents 20 --output native-benchmark.json` to produce a
|
|
188
|
+
reproducible local report; `--storage-root` selects the measured filesystem. The
|
|
189
|
+
design promises reconstructibility and a clear cost model, rather than an
|
|
190
|
+
unmeasured speedup.
|
foldlitedb-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2016 255BITS
|
|
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.
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: foldlitedb
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Requires-Dist: playwright>=1.58,<2 ; extra == 'browser'
|
|
5
|
+
Requires-Dist: build>=1,<2 ; extra == 'dev'
|
|
6
|
+
Requires-Dist: maturin>=1.9,<2 ; extra == 'dev'
|
|
7
|
+
Requires-Dist: pytest>=8,<10 ; extra == 'dev'
|
|
8
|
+
Requires-Dist: pytest>=8,<10 ; extra == 'test'
|
|
9
|
+
Provides-Extra: browser
|
|
10
|
+
Provides-Extra: dev
|
|
11
|
+
Provides-Extra: test
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Summary: Immutable document logs and rebuildable views with Rust and portable WebAssembly.
|
|
14
|
+
License-Expression: MIT
|
|
15
|
+
Requires-Python: >=3.11
|
|
16
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
17
|
+
Project-URL: Documentation, https://255bits.github.io/foldlitedb/
|
|
18
|
+
Project-URL: Issues, https://github.com/255BITS/foldlitedb/issues
|
|
19
|
+
Project-URL: Repository, https://github.com/255BITS/foldlitedb
|
|
20
|
+
|
|
21
|
+
# Foldlite DB
|
|
22
|
+
|
|
23
|
+
**Immutable documents. Rebuildable live views. Rust and WebAssembly.**
|
|
24
|
+
|
|
25
|
+
Foldlite DB is a CouchDB-inspired map/reduce engine built around a simple rule:
|
|
26
|
+
keep immutable documents, derive everything else. The Rust engine appends accepted
|
|
27
|
+
document batches to a durable log. Indexes, source checkpoints, group states, and
|
|
28
|
+
change history form a disposable cache that can be reconstructed from that log.
|
|
29
|
+
There is one native implementation, exposed to Python; storage needs no database
|
|
30
|
+
server or external database library.
|
|
31
|
+
|
|
32
|
+
Write a view in AssemblyScript and compile it to WebAssembly. The same module
|
|
33
|
+
maps and reduces documents in Rust or entirely in a browser worker. Try the
|
|
34
|
+
[browser playground](https://255bits.github.io/foldlitedb/playground.html) or read
|
|
35
|
+
the [view authoring guide](docs/portable.html).
|
|
36
|
+
|
|
37
|
+
## Install
|
|
38
|
+
|
|
39
|
+
Use Python 3.11+ to install the 0.1.0 release:
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
python -m pip install foldlitedb==0.1.0
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Native wheels are provided for Linux x86-64 and ARM64, macOS Intel and Apple
|
|
46
|
+
Silicon, and Windows x86-64. Installing a matching wheel needs neither Rust nor
|
|
47
|
+
Node. The [hosted documentation](https://255bits.github.io/foldlitedb/) describes
|
|
48
|
+
the API and bundled portable views.
|
|
49
|
+
|
|
50
|
+
### Build from this checkout
|
|
51
|
+
|
|
52
|
+
Building from source requires Python 3.11+, Rust/Cargo 1.90+, and a platform C
|
|
53
|
+
compiler and linker. From the repository root:
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
python -m venv .venv
|
|
57
|
+
. .venv/bin/activate
|
|
58
|
+
python -m pip install --upgrade pip
|
|
59
|
+
python -m pip install .
|
|
60
|
+
python examples/portable_metrics.py
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
On Windows, activate with `.venv\Scripts\activate` and use an MSVC build
|
|
64
|
+
environment. Node.js is unnecessary for installation and bundled views. To make
|
|
65
|
+
a wheel, run `python -m pip wheel . --no-deps --wheel-dir dist`. Install that
|
|
66
|
+
wheel on a matching platform with `python -m pip install /path/to/the-built.whl`;
|
|
67
|
+
installing a built wheel needs neither Rust nor Node. See the
|
|
68
|
+
[release guide](docs/releasing.html) for PyPI Trusted Publisher setup and the
|
|
69
|
+
0.1.0 publication workflow.
|
|
70
|
+
|
|
71
|
+
## Append documents, read a live view
|
|
72
|
+
|
|
73
|
+
Start with a fresh `metrics.fold` file:
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
from foldlitedb import Database, View
|
|
77
|
+
|
|
78
|
+
view = View.bundled("metrics")
|
|
79
|
+
with Database("metrics.fold", view) as db:
|
|
80
|
+
documents = db.add_many([
|
|
81
|
+
{"metric": "loss", "value": 4},
|
|
82
|
+
{"metric": "loss", "value": 8},
|
|
83
|
+
])
|
|
84
|
+
assert list(db.rows())[0].result == {
|
|
85
|
+
"count": 2, "sum": 12, "min": 4, "max": 8, "mean": 6,
|
|
86
|
+
}
|
|
87
|
+
snapshot = db.query()
|
|
88
|
+
documents += (db.add({"metric": "loss", "value": 3}),)
|
|
89
|
+
assert db.changes(since=snapshot.cursor).rows[0].result["mean"] == 5
|
|
90
|
+
retained = tuple(db.documents())
|
|
91
|
+
db.checkpoint()
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Rust executes both map and reduce through a bounded Wasm interpreter. `metrics`
|
|
95
|
+
groups finite numbers by a string `metric`; `catalogue` demonstrates an ordered
|
|
96
|
+
fold over structured events. Each database holds one view module. `Database` and
|
|
97
|
+
`View` are the primary Python names; `PortableDatabase` and `PortableView` are
|
|
98
|
+
aliases for the same types.
|
|
99
|
+
|
|
100
|
+
Try the [telemetry collector](examples/telemetry.py) for bulk import, retries, and
|
|
101
|
+
a persistent changes consumer, or the [catalogue example](examples/catalogue.py)
|
|
102
|
+
for an ordered item lifecycle. If a payload produces no rows, inspect its map
|
|
103
|
+
output with [`db.preview(payload)`](docs/api.html#preview).
|
|
104
|
+
|
|
105
|
+
Every unnamed append creates a new observation. Give an observation an ID when
|
|
106
|
+
identical retries should count once. IDs and positions are scoped to a source;
|
|
107
|
+
conflicting reuse raises an error. Documents cannot be updated or deleted. Append
|
|
108
|
+
new observations to represent changes, then let the view fold their history.
|
|
109
|
+
|
|
110
|
+
`add_many` commits one atomic batch of at most 1024 documents. Its complete Wasm
|
|
111
|
+
map request must fit 256 KiB, so larger payloads need smaller batches.
|
|
112
|
+
`rows()` follows a stable snapshot in bounded pages; `query()` and
|
|
113
|
+
`changes(since=...)` expose continuation cursors. See the
|
|
114
|
+
[Python API](docs/api.html#database) for signatures and limits.
|
|
115
|
+
|
|
116
|
+
## A log you keep; a cache you can discard
|
|
117
|
+
|
|
118
|
+
For a persistent database, `metrics.fold` contains the immutable document log.
|
|
119
|
+
`metrics.fold.cache` is an optional checkpoint; `metrics.fold.lock` coordinates
|
|
120
|
+
one active owner. A batch is acknowledged after its log frame is synced. The
|
|
121
|
+
engine validates and computes a batch before appending it, so a map or reducer
|
|
122
|
+
failure does not commit a prefix.
|
|
123
|
+
|
|
124
|
+
`checkpoint()` writes an atomic cache snapshot; closing cleanly does the same.
|
|
125
|
+
On reopen, the engine verifies the log and matching cache prefix, then runs Wasm
|
|
126
|
+
only for batches after the checkpoint. Missing, corrupt, or incompatible caches
|
|
127
|
+
are rebuilt from the documents. `rebuild()` explicitly recomputes the view and
|
|
128
|
+
starts a new cursor generation. Neither operation changes the source documents.
|
|
129
|
+
|
|
130
|
+
The document log is independent of the view module. Opening it with different
|
|
131
|
+
module bytes rebuilds the cache in place; retain the exact module if you need to
|
|
132
|
+
reproduce its previous results. Close the database before backing up the log and
|
|
133
|
+
view artifacts; Windows locks prevent other handles from reading an active log.
|
|
134
|
+
The cache is replaceable; the only copy of a document log is not.
|
|
135
|
+
|
|
136
|
+
Rebuild uses the original batch order. It scans the log linearly and runs each
|
|
137
|
+
uncached batch through the same map/reduce path as live ingestion. A valid cache
|
|
138
|
+
avoids repeated Wasm work, but reopening still verifies the complete log. Current
|
|
139
|
+
indexes and history grow in memory with the data. Cache snapshots are limited to
|
|
140
|
+
1 GiB of encoded checkpoint data; a checkpoint or close error reports a failure
|
|
141
|
+
to save that accelerator, while committed log data remains intact. There is no
|
|
142
|
+
claim of constant memory or measured rebuild throughput.
|
|
143
|
+
|
|
144
|
+
To copy retained records into a fresh database:
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
with Database("copy.fold", view) as copied:
|
|
148
|
+
copied.ingest(retained)
|
|
149
|
+
assert list(copied.rows())[0].result["mean"] == 5
|
|
150
|
+
before = [(r.key, r.state, r.result) for r in copied.rows()]
|
|
151
|
+
copied.rebuild()
|
|
152
|
+
assert [(r.key, r.state, r.result) for r in copied.rows()] == before
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Use `ingest_many(records, batch_size=100)` for larger archives. **Iterate its
|
|
156
|
+
results to perform the import**: each yielded result commits one separate bounded
|
|
157
|
+
batch, and earlier batches remain committed if a later batch fails. See the
|
|
158
|
+
[retry-safe source import](docs/api.html#bulk-import) for constructing records with
|
|
159
|
+
upstream positions or stable IDs alone. Preserve record order; preserve original
|
|
160
|
+
batch boundaries too if you need identical engine sequence values.
|
|
161
|
+
|
|
162
|
+
## Author a view, run it on a website
|
|
163
|
+
|
|
164
|
+
The [AssemblyScript SDK](views/README.md) provides JSON helpers and the Wasm ABI.
|
|
165
|
+
Implement `map`, `identity`, `add`, and `finalize`; implement `merge` only for
|
|
166
|
+
states that can be combined correctly. Inputs and state are explicit, and views
|
|
167
|
+
must be deterministic. An ordered fold must give equivalent state when the same
|
|
168
|
+
contributions are split across successive batches.
|
|
169
|
+
|
|
170
|
+
Rebuild the two bundled examples with Node.js 20+:
|
|
171
|
+
|
|
172
|
+
```sh
|
|
173
|
+
npm ci --prefix views
|
|
174
|
+
npm run build --prefix views
|
|
175
|
+
npm test --prefix views
|
|
176
|
+
npm run check --prefix views
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
The build writes modules and SHA-256 manifests into
|
|
180
|
+
`src/foldlitedb/portable_assets/`. It builds the named `metrics` and `catalogue`
|
|
181
|
+
examples. Compile a custom view and generate its manifest with:
|
|
182
|
+
|
|
183
|
+
```sh
|
|
184
|
+
npm run build:view --prefix views -- assembly/examples/my-view.ts --out-dir .build
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Both paths are relative to `views/`. The
|
|
188
|
+
[authoring guide](docs/portable.html#authoring) includes a complete custom view
|
|
189
|
+
and the build command to generate its Wasm and digest manifest.
|
|
190
|
+
|
|
191
|
+
`foldlitedb.portable_assets()` exposes compiled modules plus `client.js`,
|
|
192
|
+
`worker.js`, and `host.js`. Copy them to a static site and import
|
|
193
|
+
`BrowserDatabase` from `client.js`. The [browser example](docs/portable.html#browser)
|
|
194
|
+
covers appends, snapshots, changes, export, and replay verification. JavaScript
|
|
195
|
+
owns in-memory grouping and storage in the browser worker; the Rust log engine
|
|
196
|
+
is not compiled into this browser build.
|
|
197
|
+
|
|
198
|
+
Browser state is lost on reload or close. Export resolved documents first. The
|
|
199
|
+
preview bounds documents, groups, history, and request sizes. Persistent browser
|
|
200
|
+
storage, log/history compaction, and multiple views per native database remain
|
|
201
|
+
future work. JSON numbers use IEEE-754 double precision; use strings for exact
|
|
202
|
+
arbitrary-precision identifiers.
|
|
203
|
+
|
|
204
|
+
## Development and documentation
|
|
205
|
+
|
|
206
|
+
```sh
|
|
207
|
+
python -m pip install '.[dev,browser]'
|
|
208
|
+
python -m playwright install chromium
|
|
209
|
+
python -m pytest
|
|
210
|
+
python -m pytest tests/browser
|
|
211
|
+
cargo test --locked --manifest-path native/Cargo.toml -p foldlitedb-portable-engine
|
|
212
|
+
npm ci --prefix views
|
|
213
|
+
npm test --prefix views
|
|
214
|
+
npm run check --prefix views
|
|
215
|
+
python scripts/build_docs.py
|
|
216
|
+
python scripts/check_docs.py --execute --browser
|
|
217
|
+
python -m http.server 8000 --directory _site
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
The docs checker executes annotated Python examples in fresh temporary
|
|
221
|
+
directories and checks links, search, and desktop/mobile rendering in Chromium.
|
|
222
|
+
Open `http://localhost:8000` for the built docs and playground. An authorized
|
|
223
|
+
maintainer can publish checked generated docs with
|
|
224
|
+
`python scripts/publish_docs.py`; building alone does not publish them.
|
|
225
|
+
|
|
226
|
+
Measure the native path on your target filesystem with:
|
|
227
|
+
|
|
228
|
+
```sh
|
|
229
|
+
python scripts/benchmark_database.py --documents 10000 --keys 16 --batch-size 100 --live-documents 20 --output native-benchmark.json
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Use `--storage-root /path/to/filesystem` to select the filesystem being measured.
|
|
233
|
+
The report compares durable ingestion, checkpointing, cached reopen, suffix
|
|
234
|
+
replay, and full reconstruction, while checking unchanged log bytes and matching
|
|
235
|
+
results. Local measurements describe that fixture and host.
|
|
236
|
+
|
|
237
|
+
See [DESIGN.md](DESIGN.md) for durability, replay, cache validation, and execution
|
|
238
|
+
contracts.
|
|
239
|
+
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# Foldlite DB
|
|
2
|
+
|
|
3
|
+
**Immutable documents. Rebuildable live views. Rust and WebAssembly.**
|
|
4
|
+
|
|
5
|
+
Foldlite DB is a CouchDB-inspired map/reduce engine built around a simple rule:
|
|
6
|
+
keep immutable documents, derive everything else. The Rust engine appends accepted
|
|
7
|
+
document batches to a durable log. Indexes, source checkpoints, group states, and
|
|
8
|
+
change history form a disposable cache that can be reconstructed from that log.
|
|
9
|
+
There is one native implementation, exposed to Python; storage needs no database
|
|
10
|
+
server or external database library.
|
|
11
|
+
|
|
12
|
+
Write a view in AssemblyScript and compile it to WebAssembly. The same module
|
|
13
|
+
maps and reduces documents in Rust or entirely in a browser worker. Try the
|
|
14
|
+
[browser playground](https://255bits.github.io/foldlitedb/playground.html) or read
|
|
15
|
+
the [view authoring guide](docs/portable.html).
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
Use Python 3.11+ to install the 0.1.0 release:
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
python -m pip install foldlitedb==0.1.0
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Native wheels are provided for Linux x86-64 and ARM64, macOS Intel and Apple
|
|
26
|
+
Silicon, and Windows x86-64. Installing a matching wheel needs neither Rust nor
|
|
27
|
+
Node. The [hosted documentation](https://255bits.github.io/foldlitedb/) describes
|
|
28
|
+
the API and bundled portable views.
|
|
29
|
+
|
|
30
|
+
### Build from this checkout
|
|
31
|
+
|
|
32
|
+
Building from source requires Python 3.11+, Rust/Cargo 1.90+, and a platform C
|
|
33
|
+
compiler and linker. From the repository root:
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
python -m venv .venv
|
|
37
|
+
. .venv/bin/activate
|
|
38
|
+
python -m pip install --upgrade pip
|
|
39
|
+
python -m pip install .
|
|
40
|
+
python examples/portable_metrics.py
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
On Windows, activate with `.venv\Scripts\activate` and use an MSVC build
|
|
44
|
+
environment. Node.js is unnecessary for installation and bundled views. To make
|
|
45
|
+
a wheel, run `python -m pip wheel . --no-deps --wheel-dir dist`. Install that
|
|
46
|
+
wheel on a matching platform with `python -m pip install /path/to/the-built.whl`;
|
|
47
|
+
installing a built wheel needs neither Rust nor Node. See the
|
|
48
|
+
[release guide](docs/releasing.html) for PyPI Trusted Publisher setup and the
|
|
49
|
+
0.1.0 publication workflow.
|
|
50
|
+
|
|
51
|
+
## Append documents, read a live view
|
|
52
|
+
|
|
53
|
+
Start with a fresh `metrics.fold` file:
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
from foldlitedb import Database, View
|
|
57
|
+
|
|
58
|
+
view = View.bundled("metrics")
|
|
59
|
+
with Database("metrics.fold", view) as db:
|
|
60
|
+
documents = db.add_many([
|
|
61
|
+
{"metric": "loss", "value": 4},
|
|
62
|
+
{"metric": "loss", "value": 8},
|
|
63
|
+
])
|
|
64
|
+
assert list(db.rows())[0].result == {
|
|
65
|
+
"count": 2, "sum": 12, "min": 4, "max": 8, "mean": 6,
|
|
66
|
+
}
|
|
67
|
+
snapshot = db.query()
|
|
68
|
+
documents += (db.add({"metric": "loss", "value": 3}),)
|
|
69
|
+
assert db.changes(since=snapshot.cursor).rows[0].result["mean"] == 5
|
|
70
|
+
retained = tuple(db.documents())
|
|
71
|
+
db.checkpoint()
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Rust executes both map and reduce through a bounded Wasm interpreter. `metrics`
|
|
75
|
+
groups finite numbers by a string `metric`; `catalogue` demonstrates an ordered
|
|
76
|
+
fold over structured events. Each database holds one view module. `Database` and
|
|
77
|
+
`View` are the primary Python names; `PortableDatabase` and `PortableView` are
|
|
78
|
+
aliases for the same types.
|
|
79
|
+
|
|
80
|
+
Try the [telemetry collector](examples/telemetry.py) for bulk import, retries, and
|
|
81
|
+
a persistent changes consumer, or the [catalogue example](examples/catalogue.py)
|
|
82
|
+
for an ordered item lifecycle. If a payload produces no rows, inspect its map
|
|
83
|
+
output with [`db.preview(payload)`](docs/api.html#preview).
|
|
84
|
+
|
|
85
|
+
Every unnamed append creates a new observation. Give an observation an ID when
|
|
86
|
+
identical retries should count once. IDs and positions are scoped to a source;
|
|
87
|
+
conflicting reuse raises an error. Documents cannot be updated or deleted. Append
|
|
88
|
+
new observations to represent changes, then let the view fold their history.
|
|
89
|
+
|
|
90
|
+
`add_many` commits one atomic batch of at most 1024 documents. Its complete Wasm
|
|
91
|
+
map request must fit 256 KiB, so larger payloads need smaller batches.
|
|
92
|
+
`rows()` follows a stable snapshot in bounded pages; `query()` and
|
|
93
|
+
`changes(since=...)` expose continuation cursors. See the
|
|
94
|
+
[Python API](docs/api.html#database) for signatures and limits.
|
|
95
|
+
|
|
96
|
+
## A log you keep; a cache you can discard
|
|
97
|
+
|
|
98
|
+
For a persistent database, `metrics.fold` contains the immutable document log.
|
|
99
|
+
`metrics.fold.cache` is an optional checkpoint; `metrics.fold.lock` coordinates
|
|
100
|
+
one active owner. A batch is acknowledged after its log frame is synced. The
|
|
101
|
+
engine validates and computes a batch before appending it, so a map or reducer
|
|
102
|
+
failure does not commit a prefix.
|
|
103
|
+
|
|
104
|
+
`checkpoint()` writes an atomic cache snapshot; closing cleanly does the same.
|
|
105
|
+
On reopen, the engine verifies the log and matching cache prefix, then runs Wasm
|
|
106
|
+
only for batches after the checkpoint. Missing, corrupt, or incompatible caches
|
|
107
|
+
are rebuilt from the documents. `rebuild()` explicitly recomputes the view and
|
|
108
|
+
starts a new cursor generation. Neither operation changes the source documents.
|
|
109
|
+
|
|
110
|
+
The document log is independent of the view module. Opening it with different
|
|
111
|
+
module bytes rebuilds the cache in place; retain the exact module if you need to
|
|
112
|
+
reproduce its previous results. Close the database before backing up the log and
|
|
113
|
+
view artifacts; Windows locks prevent other handles from reading an active log.
|
|
114
|
+
The cache is replaceable; the only copy of a document log is not.
|
|
115
|
+
|
|
116
|
+
Rebuild uses the original batch order. It scans the log linearly and runs each
|
|
117
|
+
uncached batch through the same map/reduce path as live ingestion. A valid cache
|
|
118
|
+
avoids repeated Wasm work, but reopening still verifies the complete log. Current
|
|
119
|
+
indexes and history grow in memory with the data. Cache snapshots are limited to
|
|
120
|
+
1 GiB of encoded checkpoint data; a checkpoint or close error reports a failure
|
|
121
|
+
to save that accelerator, while committed log data remains intact. There is no
|
|
122
|
+
claim of constant memory or measured rebuild throughput.
|
|
123
|
+
|
|
124
|
+
To copy retained records into a fresh database:
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
with Database("copy.fold", view) as copied:
|
|
128
|
+
copied.ingest(retained)
|
|
129
|
+
assert list(copied.rows())[0].result["mean"] == 5
|
|
130
|
+
before = [(r.key, r.state, r.result) for r in copied.rows()]
|
|
131
|
+
copied.rebuild()
|
|
132
|
+
assert [(r.key, r.state, r.result) for r in copied.rows()] == before
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Use `ingest_many(records, batch_size=100)` for larger archives. **Iterate its
|
|
136
|
+
results to perform the import**: each yielded result commits one separate bounded
|
|
137
|
+
batch, and earlier batches remain committed if a later batch fails. See the
|
|
138
|
+
[retry-safe source import](docs/api.html#bulk-import) for constructing records with
|
|
139
|
+
upstream positions or stable IDs alone. Preserve record order; preserve original
|
|
140
|
+
batch boundaries too if you need identical engine sequence values.
|
|
141
|
+
|
|
142
|
+
## Author a view, run it on a website
|
|
143
|
+
|
|
144
|
+
The [AssemblyScript SDK](views/README.md) provides JSON helpers and the Wasm ABI.
|
|
145
|
+
Implement `map`, `identity`, `add`, and `finalize`; implement `merge` only for
|
|
146
|
+
states that can be combined correctly. Inputs and state are explicit, and views
|
|
147
|
+
must be deterministic. An ordered fold must give equivalent state when the same
|
|
148
|
+
contributions are split across successive batches.
|
|
149
|
+
|
|
150
|
+
Rebuild the two bundled examples with Node.js 20+:
|
|
151
|
+
|
|
152
|
+
```sh
|
|
153
|
+
npm ci --prefix views
|
|
154
|
+
npm run build --prefix views
|
|
155
|
+
npm test --prefix views
|
|
156
|
+
npm run check --prefix views
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
The build writes modules and SHA-256 manifests into
|
|
160
|
+
`src/foldlitedb/portable_assets/`. It builds the named `metrics` and `catalogue`
|
|
161
|
+
examples. Compile a custom view and generate its manifest with:
|
|
162
|
+
|
|
163
|
+
```sh
|
|
164
|
+
npm run build:view --prefix views -- assembly/examples/my-view.ts --out-dir .build
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Both paths are relative to `views/`. The
|
|
168
|
+
[authoring guide](docs/portable.html#authoring) includes a complete custom view
|
|
169
|
+
and the build command to generate its Wasm and digest manifest.
|
|
170
|
+
|
|
171
|
+
`foldlitedb.portable_assets()` exposes compiled modules plus `client.js`,
|
|
172
|
+
`worker.js`, and `host.js`. Copy them to a static site and import
|
|
173
|
+
`BrowserDatabase` from `client.js`. The [browser example](docs/portable.html#browser)
|
|
174
|
+
covers appends, snapshots, changes, export, and replay verification. JavaScript
|
|
175
|
+
owns in-memory grouping and storage in the browser worker; the Rust log engine
|
|
176
|
+
is not compiled into this browser build.
|
|
177
|
+
|
|
178
|
+
Browser state is lost on reload or close. Export resolved documents first. The
|
|
179
|
+
preview bounds documents, groups, history, and request sizes. Persistent browser
|
|
180
|
+
storage, log/history compaction, and multiple views per native database remain
|
|
181
|
+
future work. JSON numbers use IEEE-754 double precision; use strings for exact
|
|
182
|
+
arbitrary-precision identifiers.
|
|
183
|
+
|
|
184
|
+
## Development and documentation
|
|
185
|
+
|
|
186
|
+
```sh
|
|
187
|
+
python -m pip install '.[dev,browser]'
|
|
188
|
+
python -m playwright install chromium
|
|
189
|
+
python -m pytest
|
|
190
|
+
python -m pytest tests/browser
|
|
191
|
+
cargo test --locked --manifest-path native/Cargo.toml -p foldlitedb-portable-engine
|
|
192
|
+
npm ci --prefix views
|
|
193
|
+
npm test --prefix views
|
|
194
|
+
npm run check --prefix views
|
|
195
|
+
python scripts/build_docs.py
|
|
196
|
+
python scripts/check_docs.py --execute --browser
|
|
197
|
+
python -m http.server 8000 --directory _site
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
The docs checker executes annotated Python examples in fresh temporary
|
|
201
|
+
directories and checks links, search, and desktop/mobile rendering in Chromium.
|
|
202
|
+
Open `http://localhost:8000` for the built docs and playground. An authorized
|
|
203
|
+
maintainer can publish checked generated docs with
|
|
204
|
+
`python scripts/publish_docs.py`; building alone does not publish them.
|
|
205
|
+
|
|
206
|
+
Measure the native path on your target filesystem with:
|
|
207
|
+
|
|
208
|
+
```sh
|
|
209
|
+
python scripts/benchmark_database.py --documents 10000 --keys 16 --batch-size 100 --live-documents 20 --output native-benchmark.json
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Use `--storage-root /path/to/filesystem` to select the filesystem being measured.
|
|
213
|
+
The report compares durable ingestion, checkpointing, cached reopen, suffix
|
|
214
|
+
replay, and full reconstruction, while checking unchanged log bytes and matching
|
|
215
|
+
results. Local measurements describe that fixture and host.
|
|
216
|
+
|
|
217
|
+
See [DESIGN.md](DESIGN.md) for durability, replay, cache validation, and execution
|
|
218
|
+
contracts.
|