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
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# ArcadeDB Embedded for Python

> **Moved: the Python bindings now live in [ArcadeData/arcadedb-python](https://github.com/ArcadeData/arcadedb-python).** Install `arcadedb` (the native build, the default) or `arcadedb-jvm` (the JVM build); both use `import arcadedb`. [Which package?](https://github.com/ArcadeData/arcadedb-python/blob/main/docs/modules/ROOT/pages/which-package.adoc) explains the choice. The first releases of the new packages are 26.11.1, starting as pre-releases (`uv add --pre arcadedb`). `arcadedb-embedded` and `import arcadedb_embedded` are deprecated: `arcadedb-embedded` will get a last release that installs `arcadedb`. Report bindings issues and send bindings pull requests to the new repository. This repository will be archived; the benchmark tooling stays here for now.
> **Moved: the Python bindings now live in [ArcadeData/arcadedb-python](https://github.com/ArcadeData/arcadedb-python).** Install `arcadedb` (the native build, the default) or `arcadedb-jvm` (the JVM build); both use `import arcadedb`. [Which package?](https://github.com/ArcadeData/arcadedb-python/blob/main/docs/modules/ROOT/pages/which-package.adoc) explains the choice. Both packages are released as 26.11.1 (`uv add arcadedb`). `arcadedb-embedded` and `import arcadedb_embedded` are deprecated: the last release of `arcadedb-embedded`, 26.11.1, installs `arcadedb`. Report bindings issues and send bindings pull requests to the new repository. This repository will be archived once the benchmark tooling moves to [humemai/dbbench](https://github.com/humemai/dbbench) (planned for mid-November 2026, after the last measuring pass); until then the tooling stays here.

[![PyPI](https://img.shields.io/pypi/v/arcadedb?include_prereleases)](https://pypi.org/project/arcadedb/)
[![PyPI](https://img.shields.io/pypi/v/arcadedb)](https://pypi.org/project/arcadedb/)
[![Docs](https://img.shields.io/badge/docs-arcadedb.com-892122)](https://docs.arcadedb.com/arcadedb-python/)

---
Expand All @@ -18,8 +18,8 @@
Install the package and read the documentation from the new repository:

```bash
uv add --pre arcadedb # native build; until 26.11.1 is a final release
uv add --pre arcadedb-jvm # JVM build, only if you need it
uv add arcadedb # native build, the default
uv add arcadedb-jvm # JVM build, only if you need it
```

- Documentation: [https://docs.arcadedb.com/arcadedb-python/](https://docs.arcadedb.com/arcadedb-python/)
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Two suites. Both reach embedded ArcadeDB through the Python package (the
live harness's served arms reach it over HTTP instead, on a server built from
the same upstream commit as the wheel), run every backend in Docker under the
same CPU and memory caps, report five repetitions per cell, and publish the
same CPU and memory caps, report up to five repetitions per cell (n=3 for every engine first, then n=4, then n=5), and publish the
rows their numbers are computed from. They differ
in scope and in where they publish, not in the kind of thing they measure.

Expand Down
4 changes: 2 additions & 2 deletions benchmarks/experiments/CAMPAIGN.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion benchmarks/experiments/PAGE-SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ The DBBench page at `humem.ai/research/dbbench` is the PRIMARY artifact: its lan
## 0. The rules every published cell obeys

1. **Serial, full cpuset.** Every published latency, throughput, percentile, and memory cell runs one at a time on mini's `cpuset 0-11` (the 12 P-core THREADS on 6 physical P-cores; see 0a), `workers=1`, `tier=paper`. Parallel shards exist for sweeps and exploration only and may never reach the page. Enforced: `runner.py` refuses `workers != 1` at paper tier; `load_canonical` drops partial cpusets.
2. **N=5, median [min-max].** Five repetitions per cell, reached in two passes (PROTOCOL.md section 1). Any table with a cell below n=5 states its n in a condition, and no page sentence may assert an n that a cell it covers does not meet. Per-table operation and repetition counts are generated conditions (`export_web._counts_note`), never typed.
2. **N=5, median [min-max].** Five repetitions per cell, reached in whole passes: n=3 for every engine first (the four ArcadeDB arms included), then n=4, then n=5 (PROTOCOL.md section 1). Any table with a cell below n=5 states its n in a condition, and no page sentence may assert an n that a cell it covers does not meet. Per-table operation and repetition counts are generated conditions (`export_web._counts_note`), never typed.
3. **One engine commit per table.** Every ArcadeDB row in one table comes from the same upstream commit, stamped as `engine_commit`. Comparators are digest-pinned images. See section 1. Enforced at production time: `runner.py` refuses a paper-tier ArcadeDB run when `ARCADEDB_ENGINE_COMMIT` is unset, before any cell starts, and `bench_common.run_conditions()` reads it so bespoke probes carry it too. A rule the page depends on may not be a printed reminder to a human.
4. **One corpus per table.** Every row in a table describes the same dataset at the same size. A table whose rows disagree on `n_docs` (or the lane's size field) is a defect, not a comparison. The fingerprint must come from the corpus the lane loaded, not from a module constant (`l2_graph.py` and `l3_sparse.py` point it at the loaded data; BUGS.md F6 is the sparse lane running the synthetic corpus under a paper label).
5. **A knob the campaign sets must reach the cell, be honoured by the lane, and resolve inside the container.** `runner.py`'s env passthrough is a CLOSED tuple: a knob absent from it silently runs the in-script default. Three checks, each of which has failed once: DELIVERED (diff every lane's `environ.get("UPPER_CASE")` against what the runner passes), HONOURED (an unknown mode is a hard error, not a silent fallback to a literal default), and RESOLVED where the process runs (the mount is printed in the preamble and a missing corpus is refused on the host). Run the delivery diff whenever a lane gains a knob.
Expand Down
4 changes: 2 additions & 2 deletions benchmarks/experiments/PROTOCOL.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ The admission filter is `make_paper_tables.load_canonical()`. Every test below r
- Dedupe key is `(lane, scale, n_docs, workload, backend, gav is not False, rep, durability_class)`, latest `ts_utc`, never `run_id`. Without the `gav` term the no-view ablation overwrites T3, and without the class term the strict arm of a write cell overwrites its relaxed twin (DECISIONS #90; a row with no class counts as relaxed, which is what it was). **GATE** `load_canonical`
- One released engine line per table. Delete preference cascades, never reorder them. **GATE** T4 refusal in `make_paper_tables` and five of f8's six bars in `make_paper_figures`; **REMEMBERED** for f8's dense bar, whose `_dense_multipass` source reads no version field, and for every other table (F5)
- Lane scripts publish; bespoke drivers investigate. Both known protocol violations were bespoke-driver rows promoted to cells, and T5's dense half is still an overlay from `dense_multipass_driver.py`, run through `runner.py --driver`. **GATE** `fairness_check.report_producers` (F6b) for `runs.jsonl` lanes, which sees no overlay record; **REMEMBERED** for every overlay-fed cell
- Every cell is N=5, or its shortfall is disclosed in `EXPECTED` and in the caption, and the disclosure is deleted when the shortfall is fixed. **N=5 is reached in two passes on the 26.10.1 measurement (DECISIONS #164): reps 1 to 3 for every arm first, reps 4 and 5 in a later pass, one whole lane at a time so every engine of a lane is topped up within days. A table landed between the passes states n=3 in its caption and in `EXPECTED`, and the later landing deletes both. Medians of three carry no rank test (the smallest two-sided Mann-Whitney p at 3 versus 3 is 0.1), so a claim under about 1.3x waits for the top-up, and the two batches are compared before they are pooled.** **GATE** `provenance_check.caption_n` over the generated `.tex` tables, skipped on a lane-scoped landing (`BENCH_ONLY_LANES`); **REMEMBERED** for T5's dense half and for the deletion half, which `if ns == {5}: continue` short-circuits
- Every cell is N=5, or its shortfall is disclosed in `EXPECTED` and in the caption, and the disclosure is deleted when the shortfall is fixed. **N=5 is reached in two passes on the 26.10.1 measurement (DECISIONS #164): reps 1 to 3 for every arm first, reps 4 and 5 in a later pass, one whole lane at a time so every engine of a lane is topped up within days. A table landed between the passes states n=3 in its caption and in `EXPECTED`, and the later landing deletes both. Medians of three carry no rank test (the smallest two-sided Mann-Whitney p at 3 versus 3 is 0.1), so a claim under about 1.3x waits for the top-up, and the two batches are compared before they are pooled.** On the 2026-11 pass the order runs across the whole roster by repetition: n=3 for every engine first, the four ArcadeDB arms (embedded and served, JVM and native) included, then n=4, then n=5, each a whole pass (CAMPAIGN.md, paper profile). The paper's comparators are n=3 for sure and n=5 where passes 4 and 5 finish before the tables freeze. **GATE** `provenance_check.caption_n` over the generated `.tex` tables, skipped on a lane-scoped landing (`BENCH_ONLY_LANES`); **REMEMBERED** for T5's dense half and for the deletion half, which `if ns == {5}: continue` short-circuits
- Never publish a scale where comparators have rows and we do not; print what was withheld and why at export time. **GATE** withheld-scale guard in `export_web`
- Every artifact the page cites lives in this repository, and the superseded run is not left where it can be compared against. **GATE (report only)** `provenance_check.FEEDS`: an empty feed prints "(no result files)" and counts nothing. **GATE**: every pinned reader refuses when `<name>_<pin>` is missing
- Every overlay directory and top-level result file feeding a table records run conditions and a real version; "feeds a table" means "is opened by `make_paper_tables`". **GATE** `run_conditions`, `lane_files` and `_is_real_version` for the two lane files; **REMEMBERED** for the overlay directories T4 and T5 print, whose audit accepts any non-empty string
Expand Down Expand Up @@ -96,7 +96,7 @@ Every row carries these fields. The code is `memory_probe.py`, and `bench_common
- **What compares across engines and what does not.** `mem_<phase>_owned_mib` and its parts, and `mem_<phase>_peak_mib`, compare across every engine: they come from the same kernel counters of the same kind of container, and the page prints one headline column from them. `jvm_*` compares across JVM engines only and says nothing about a native engine; `proc_*` compares across embedded engines only. A JVM engine's `owned` and its `jvm_used_after_gc` differ by the JVM's slack (committed but free heap, metaspace, code cache, thread stacks, native memory): the first is what the container held, the second is what the engine needed, and neither replaces the other.
- **A pinned heap makes the kernel's numbers show the cap.** With `-Xms` equal to `-Xmx` the JVM commits the whole heap at start and touches it as it grows, so anon and RSS read near the cap whatever the engine needs, and a larger cap reads larger with the same workload. The ArcadeDB arms, embedded and served, do not pin the heap (`-Xms` is left unset), so their memory column reads demand up to `-Xmx`; the JVM arms that have a pinned tier heap (Elasticsearch, Neo4j) read the pin, and the other served engines keep following their vendors' documentation for the heap they start with. An unpinned heap is no cure for the headline: a JVM that has grown stays grown unless the collector returns the pages, which is why `jvm_used_after_gc_mib` sits beside it, and why a row records `jvm_<phase>_committed_mib` next to the heap the engine needed.
- **Disk per phase, the same way for every engine.** At the same boundaries the runner reads, for the container that holds the engine's data (the server container for a served engine, the client's for an embedded one), the bytes it is responsible for: the writable layer plus every declared volume, the reading `container_disk` already takes, here as one sample after a flush rather than the settled pair. `disk_<phase>_mib` is that reading, `disk_<phase>_data_mib` is the headline: it less the same container's empty-start reading (`server_disk_baseline_mb` or `client_disk_baseline_mb`), so it is what the workload left, comparable with `disk_data_mb`. `disk_<phase>_wal_mib` is the write-ahead log or journal alone, found inside the container by name (`*.wal`, `pg_wal`, `journal`, `translog`, `neostore.transaction.db.*`); an engine with another layout reads 0.0, which means none was found, and it is context, not a comparison. `disk_close_mib` and `disk_close_data_mib` are the runner's existing settled reading taken after the lane has closed the database; a phase reading of the same bytes can be lower or higher than it by what background compaction and checkpointing do in between, which is the point of reading both.
- **IO per phase: `io_<phase>_read_mib`, `io_<phase>_write_mib`.** The bytes the cell's containers read from and wrote to disk since the previous boundary (the cgroup `io.stat` counters are cumulative, so a phase is a difference; the first phase starts when the client container does), summed over the containers. The server's startup is not in `load`. The disk and IO readings are taken before the peak restarts, so the helper processes they start inside the container never land in the next phase's peak.
- **IO per phase: `io_<phase>_read_mib`, `io_<phase>_write_mib`.** The bytes the cell's containers read from and wrote to disk since the previous boundary (the cgroup `io.stat` counters are cumulative, so a phase is a difference; the first phase starts when the client container does), summed over the containers. The server's startup is not in `load`. The disk and IO readings are taken before the peak restarts, so the helper processes they start inside the container never land in the next phase's peak. **Mini rows written before the fix for issue #555 count a stacked block device twice:** the runner summed every device line of `io.stat`, and on the mini the NVMe (`259:0`) and the device-mapper device on top of it (`252:0`) list identical bytes, so every `io_*_mib` figure of those rows (the per-phase fields, the `_sum` pair, and the per-side and per-container ones) is about twice its value. The fix counts a device built on another listed device once and stamps `io_stat_dedup: 1` into every row the fixed runner writes. The freeze halves the io figures of mini rows that lack the stamp, in `runs_paper.csv` only: `runs.jsonl` keeps the raw values, and `generated/io_stat_correction.json` lists each corrected row with its raw values (PUBLISHING.md). No other field of a row is affected.
- **Where this stops.** A forced GC changes the heap for the phase that follows (a full collection empties young generations and caches the next phase would have found warm), which is why it runs only after the last timed phase and in `idle`, never before a timed phase, and is recorded in `jvm_forced_gc_phases`; and the lane waits for the answer, so the phases that follow a probe start a few hundred milliseconds later than they would have. A lane that prints no `PHASE` marker of the ones above (the lifecycle and restart lanes) takes no per-phase reading and keeps only the whole-cell fields.

## 3. How a comparison is kept fair
Expand Down
4 changes: 2 additions & 2 deletions bindings/python/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ArcadeDB Python Bindings

> **Moved: the Python bindings now live in [ArcadeData/arcadedb-python](https://github.com/ArcadeData/arcadedb-python).** Install `arcadedb` (the native build, the default) or `arcadedb-jvm` (the JVM build); both use `import arcadedb`. [Which package?](https://github.com/ArcadeData/arcadedb-python/blob/main/docs/modules/ROOT/pages/which-package.adoc) explains the choice. The first releases of the new packages are 26.11.1, starting as pre-releases (`uv add --pre arcadedb`). `arcadedb-embedded` and `import arcadedb_embedded` are deprecated: `arcadedb-embedded` will get a last release that installs `arcadedb`. Report bindings issues and send bindings pull requests to the new repository. This repository will be archived; the benchmark tooling stays here for now.
> **Moved: the Python bindings now live in [ArcadeData/arcadedb-python](https://github.com/ArcadeData/arcadedb-python).** Install `arcadedb` (the native build, the default) or `arcadedb-jvm` (the JVM build); both use `import arcadedb`. [Which package?](https://github.com/ArcadeData/arcadedb-python/blob/main/docs/modules/ROOT/pages/which-package.adoc) explains the choice. Both packages are released as 26.11.1 (`uv add arcadedb`). `arcadedb-embedded` and `import arcadedb_embedded` are deprecated: the last release of `arcadedb-embedded`, 26.11.1, installs `arcadedb`. Report bindings issues and send bindings pull requests to the new repository. This repository will be archived once the benchmark tooling moves to [humemai/dbbench](https://github.com/humemai/dbbench) (planned for mid-November 2026, after the last measuring pass); until then the tooling stays here.

Native Python bindings for ArcadeDB - the multi-model database that supports Graph, Document, Key/Value, Search Engine, Time Series, and Vector models.

Expand All @@ -19,7 +19,7 @@ Native Python bindings for ArcadeDB - the multi-model database that supports Gra
### Installation

```bash
uv add arcadedb-embedded # deprecated; new projects use: uv add --pre arcadedb
uv add arcadedb-embedded # deprecated; new projects use: uv add arcadedb
```

**Requirements:**
Expand Down
2 changes: 1 addition & 1 deletion bindings/python/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

!!! warning "Moved to ArcadeData/arcadedb-python"

The Python bindings now live in [ArcadeData/arcadedb-python](https://github.com/ArcadeData/arcadedb-python). Install `arcadedb` (the native build, the default) or `arcadedb-jvm` (the JVM build); both use `import arcadedb`. [Which package?](https://github.com/ArcadeData/arcadedb-python/blob/main/docs/modules/ROOT/pages/which-package.adoc) explains the choice. The first releases of the new packages are 26.11.1, starting as pre-releases (`uv add --pre arcadedb`). `arcadedb-embedded` and `import arcadedb_embedded` are deprecated: `arcadedb-embedded` will get a last release that installs `arcadedb`. Report bindings issues and send bindings pull requests to the new repository. This repository will be archived; the benchmark tooling stays here for now.
The Python bindings now live in [ArcadeData/arcadedb-python](https://github.com/ArcadeData/arcadedb-python). Install `arcadedb` (the native build, the default) or `arcadedb-jvm` (the JVM build); both use `import arcadedb`. [Which package?](https://github.com/ArcadeData/arcadedb-python/blob/main/docs/modules/ROOT/pages/which-package.adoc) explains the choice. Both packages are released as 26.11.1 (`uv add arcadedb`). `arcadedb-embedded` and `import arcadedb_embedded` are deprecated: the last release of `arcadedb-embedded`, 26.11.1, installs `arcadedb`. Report bindings issues and send bindings pull requests to the new repository. This repository will be archived once the benchmark tooling moves to [humemai/dbbench](https://github.com/humemai/dbbench) (planned for mid-November 2026, after the last measuring pass); until then the tooling stays here.

<div class="grid cards" markdown>

Expand Down
Loading