motedb-python 0.12.8__tar.gz → 0.12.9__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.
- {motedb_python-0.12.8 → motedb_python-0.12.9}/.gitignore +1 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/CHANGELOG.md +53 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/Cargo.lock +1 -1
- {motedb_python-0.12.8 → motedb_python-0.12.9}/Cargo.toml +1 -1
- {motedb_python-0.12.8 → motedb_python-0.12.9}/PKG-INFO +1 -1
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/Cargo.lock +2 -2
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/Cargo.toml +1 -1
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/tests/test_crash_recovery.py +28 -10
- {motedb_python-0.12.8 → motedb_python-0.12.9}/pyproject.toml +1 -1
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/api.rs +9 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/database/core.rs +128 -10
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/database/indexes/text.rs +22 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/database/persistence.rs +53 -7
- motedb_python-0.12.9/tests/repro_multirow_update_fts.rs +41 -0
- motedb_python-0.12.9/tests/test_fts_recovery_staleness.rs +107 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/.cargo/config.toml +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/.devcontainer/devcontainer.json +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/.github/workflows/ci.yml +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/.github/workflows/fuzz.yml +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/.github/workflows/perf-gate.yml +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/.github/workflows/publish.yml +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/.github/workflows/python-wheels.yml +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/.zcode/plans/plan-sess_abb2c954-05fb-477e-9d0a-3e22261e2449.md +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/.zcode/plans/plan-sess_b5937a06-b7bf-4471-9756-dbf2787b263c.md +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/LICENSE +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/Makefile +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/README.md +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/RELEASE_NOTES.md +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/README.md +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/bench/README.md +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/bench/adversarial_verify.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/bench/bench_edge.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/bench/compete_bench.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/bench/compete_fts_industry.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/bench/compete_scale.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/bench/compete_spatial_ts.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/bench/compete_vec_industry.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/bench/compete_writes.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/bench/fts_probe_once.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/bench/perf_ab.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/bench/perf_overall.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/bench/prof_ann.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/bench/prof_fts.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/bench/prof_insert.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/bench/prof_point.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/bench/prof_real.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/bench/prof_scale.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/bench/prof_scale_vec.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/bench/prof_vec_parallel.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/bench/resource_bench.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/bench/resource_bench_2026-09_profile.json +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/bench/resource_bench_v0.10.0.json +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/bench/spatial_eval.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/bench/text_eval.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/bench/ts_eval.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/bench/vector_recall_eval.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/build.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/e2e/e2e_workload.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/e2e/test_durability_kwarg.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/licenses/LICENSE +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/scripts/build_wheel.sh +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/src/lib.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/tests/test_backup.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/tests/test_e2e_cli.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/tests/test_e2e_functional.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/tests/test_feature_selfcheck.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/tests/test_fetch_arrays.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/tests/test_fuzz_bigtable.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/tests/test_fuzz_differential.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/tests/test_insert_arrays.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/tests/test_parallel_ab.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/bindings/python/tests/test_smoke.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/deny.toml +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/docs/01-quick-start.md +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/docs/02-installation.md +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/docs/03-sql-operations.md +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/docs/04-batch-operations.md +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/docs/05-transactions.md +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/docs/06-indexes-overview.md +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/docs/07-column-index.md +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/docs/08-vector-index.md +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/docs/09-text-index.md +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/docs/10-spatial-index.md +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/docs/11-timestamp-index.md +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/docs/12-performance.md +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/docs/13-data-types.md +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/docs/14-api-reference.md +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/docs/15-best-practices.md +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/docs/16-faq.md +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/docs/17-hybrid-arrow.md +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/docs/README.md +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/docs/benchmark_methodology.md +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/docs/paper/README.md +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/docs/paper/motedb.tex +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/examples/bench_300k.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/examples/bench_autocommit_lock.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/examples/bench_disk.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/examples/bench_exec_only.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/examples/bench_insert_engine.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/examples/bench_layer.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/examples/bench_memory.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/examples/bench_multimodal_vs_competitors.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/examples/bench_point_read.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/examples/bench_profile_hot.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/examples/bench_scaling.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/examples/bench_stability.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/examples/bench_vs_sqlite.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/examples/corruption_fuzz.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/examples/crud.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/examples/differential_fuzz.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/examples/hello_world.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/examples/join_differential_fuzz.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/examples/logging.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/examples/perf_smoke.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/examples/probe_filter_decomp.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/examples/probe_jemalloc.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/examples/probe_memory_source.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/examples/probe_tail_latency.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/examples/text_rank_probe.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/examples/vector_recall_real.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/licenses/LICENSE +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/python/motedb/__init__.py +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/scripts/Dockerfile.e2e +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/scripts/compete.sh +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/scripts/docker_e2e.sh +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/scripts/repro_point_query_gap.sh +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/bin/motedb-cli.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/cache/mod.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/cache/row_cache.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/catalog/mod.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/catalog/registry.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/config.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/database/crud.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/database/doctor.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/database/helpers.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/database/index_metadata.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/database/indexes/column.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/database/indexes/dashmap_migration.md +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/database/indexes/ioctree.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/database/indexes/mod.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/database/indexes/timestamp.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/database/indexes/vector.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/database/mem_buffer.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/database/mod.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/database/pk_cache.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/database/table.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/database/timeseries.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/database/transaction.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/distance/cosine.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/distance/euclidean.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/distance/mod.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/error.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/ffi.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/index/btree.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/index/btree_generic.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/index/builder.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/index/cached_index.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/index/column_value.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/index/fresh_graph.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/index/ioctree/leaf_store.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/index/ioctree/mod.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/index/ioctree/node.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/index/ioctree/persistence.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/index/ioctree/search.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/index/mod.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/index/primary_key.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/index/text_dictionary.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/index/text_encoding.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/index/text_fts.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/index/text_query.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/index/text_types.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/index/tokenizers.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/index/vamana/config.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/index/vamana/disk_graph.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/index/vamana/diskann_index.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/index/vamana/mod.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/index/vamana/pruner.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/index/vamana/sq8.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/index/vamana/sq8_vectors.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/lib.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/platform_io.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/sql/ast.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/sql/evaluator.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/sql/executor/agg.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/sql/executor/join.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/sql/executor/mod.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/sql/executor/scan.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/sql/join/hash_join.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/sql/join/index_join.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/sql/join/mod.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/sql/lexer.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/sql/mod.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/sql/optimizer.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/sql/parser.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/sql/row_converter.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/sql/token.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/sql/vector_exec.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/checksum.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/col_segment/manifest.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/col_segment/merge.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/col_segment/mod.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/col_segment/segment.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/col_segment/store.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/colbatch.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/columnar/column_encoding.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/columnar/config.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/columnar/gorilla.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/columnar/mod.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/columnar/segment.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/columnar/segment_manager.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/columnar/store.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/columnar/write_buffer.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/file_manager.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/lsm/blobstore.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/lsm/bloom.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/lsm/columnar.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/lsm/compaction.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/lsm/engine.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/lsm/memtable.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/lsm/merging_iterator.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/lsm/mod.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/lsm/sstable.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/lsm/unified_memtable.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/manifest/manifest.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/manifest/mod.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/manifest/version.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/mod.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/storage/row_format.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/txn/coordinator.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/txn/lock_manager.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/txn/mod.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/txn/mvcc.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/txn/recovery.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/txn/version_store.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/txn/wal.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/types/comp_sum.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/types/mod.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/types/spatial.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/types/table.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/types/tensor.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/types/text.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/src/types/timestamp.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/acid_test.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/bench_2m.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/bench_acid.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/bench_batch_ops.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/bench_compare.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/bench_comprehensive.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/bench_concurrent.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/bench_index_ops.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/bench_multimodal.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/bench_multimodal_full.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/bench_multimodal_ops.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/bench_perf_report.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/bench_quick_baseline.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/bench_release.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/bench_report.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/bench_resource.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/bench_sql_queries.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/bench_timeseries_index.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/bench_v060_report.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/bench_vs_sqlite_100k.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/bench_vs_sqlite_v05.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/common/mod.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/durability_probe.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/fts_probe.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/perf_test.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/repro_point_gap.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/stress_300k.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/stress_test.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_acid_audit.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_acid_comprehensive.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_advanced_hunt.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_api_correctness.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_auto_checkpoint_segments.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_backup.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_btree_integrity.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt2.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt3.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt4.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt5.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt6.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt7.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v10.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v100.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v101.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v11.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v12.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v13.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v14.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v15.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v16.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v17_cte.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v18.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v19.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v2.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v20.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v21.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v22.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v23.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v24.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v25.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v26.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v27.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v28.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v29.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v3.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v30.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v31.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v32.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v33.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v34.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v35.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v36.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v38.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v39.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v4.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v40.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v43.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v45.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v48.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v49.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v5.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v50.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v51.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v52.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v53.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v54.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v55.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v56.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v57.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v58.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v59.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v6.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v60.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v61.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v62.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v63.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v64.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v65.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v66.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v67.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v68.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v69.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v7.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v70.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v71.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v72.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v73.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v74.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v75.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v76.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v77.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v78.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v79.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v8.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v80.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v81.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v82.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v83.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v84.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v85.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v86.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v87.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v88.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v89.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v9.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v90.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v91.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v92.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v93.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v94.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v95.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v96.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v97.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v98.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_bug_hunt_v99.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_col_segment.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_col_segment_fastpaths.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_columnar.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_columnar_acid.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_compact_storage.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_compaction_integrity.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_compiled_where_semantics.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_comprehensive.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_comprehensive_audit.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_concurrent_sql_features.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_concurrent_stress.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_corruption_recovery.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_corruption_robustness.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_crash_injection.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_crash_recovery.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_data_types.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_db_path_hygiene.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_deadlock_stress.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_deep_edge.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_delete_persist.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_differential_correctness.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_disk_bloat.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_disk_usage.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_doctor.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_durability.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_e2e_crash_and_stress.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_edge_cases.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_edge_semantics.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_executemany.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_exists_subquery.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_explain.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_extreme_hunt.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_fast_paths.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_fuzz_sql_combinations.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_groupby_first_query.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_hybrid_search.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_index_maintenance.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_index_reopen.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_index_robustness.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_indexed_query_semantics.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_insert_engine.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_insert_explicit_fastpath.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_insert_paths_index_maintenance.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_insert_select.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_ioctree.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_isolation_levels.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_join_count_fold.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_knn_parallel.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_large_rows.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_m5_mines.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_memory_leak.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_memory_linear.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_multimodal.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_multimodal_e2e.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_mvcc_isolation.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_mvcc_recovery.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_no_bloat.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_optimization_regression.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_order_by_expr_keys.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_parser_fuzz_regression.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_performance_guarantees.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_pk_change_semantics.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_prepared_dml.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_public_api.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_query_equivalence.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_range_count.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_release_readiness.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_repro12.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_round12_optimizations.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_round12b_edge.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_round12c_e2e_bugs.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_round13_bug_hunt.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_row_api.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_savepoint_window.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_scalability.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_scan_integrity.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_semantic_edges.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_spatial_index.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_spatial_large_geometry.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_spatial_sql_semantics.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_sql_advanced.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_sql_correctness.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_sql_correctness_part2.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_sql_ddl_features.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_sql_errors_edges.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_sql_functions.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_sql_groupby.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_sql_joins.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_sql_scenarios.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_storage_integrity.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_stress.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_stress_hunt.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_text_ts_search_semantics.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_timeseries_index.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_timeseries_semantics.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_timestamp_recovery.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_transaction_semantics.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_txn_ddl_and_nan_ordering.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_update_perf.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_upsert.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_v050_features.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_vec_m0.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_vec_m4.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_vector_column_read_paths.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_vector_durability.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_vector_index_recall.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_vector_spatial_text.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_vector_visibility.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_wide_tables.rs +0 -0
- {motedb_python-0.12.8 → motedb_python-0.12.9}/tests/test_write_concurrency.rs +0 -0
|
@@ -1,5 +1,58 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.12.9] — 2026-10-10
|
|
4
|
+
|
|
5
|
+
- **🔑 崩溃恢复审计三连修(0.12.8 stale 检测的边界补全)**:
|
|
6
|
+
- **重建不清空旧索引 → 统计膨胀**: 恢复重建在已加载的(可能滞后的)
|
|
7
|
+
索引上**追加**而非重置 —— `batch_insert` 不幂等(total_docs 无条件
|
|
8
|
+
自增、`PostingList::add` 对已有 doc 抬 TF), 一次重建即 total_docs
|
|
9
|
+
翻倍 + 词频加倍(BM25 静默漂移, MATCH 成员正确所以压测没抓到)。
|
|
10
|
+
修复: 重建前硬重置(删除 text_{name}.fts.d 与 dict.d 目录、新建空
|
|
11
|
+
索引, 与 load 路径同构), 重建后 total_docs 精确等于活行探针实测
|
|
12
|
+
80/80。回归: tests/test_fts_recovery_staleness.rs(UPDATE/DELETE/
|
|
13
|
+
NULL 混合 + 标记契约 + 恢复幂等)
|
|
14
|
+
- **NULL 文本行 → 每次全量重建**: NULL 不入索引是常态, 但 0.12.8 的
|
|
15
|
+
`indexed < table_rows` 谓词把含 NULL 的表判为永久 stale → 每次
|
|
16
|
+
open 全量重建(且触发上面的追加膨胀)。修复: 引入**干净关闭标记**
|
|
17
|
+
`fts_indexes.fresh` —— Drop 时 flush 全部文本索引(有界锁等待,
|
|
18
|
+
builder 卡死则跳过标记而非卡死 Drop)并原子写标记; open 起始消费
|
|
19
|
+
标记, 标记在位 → 干净重开零校验零重建, 标记缺失(崩溃证据)→ 才
|
|
20
|
+
跑计数校验。干净重开实测零重建
|
|
21
|
+
- **墓碑丢失方向 → MATCH 幻影**: crash 前 DELETE 的内存 tombstone
|
|
22
|
+
未落盘 → 磁盘索引 total_docs **大于**表行数, 旧 `<` 谓词不触发
|
|
23
|
+
重建 → posting 残留已删行, `COUNT(*) WHERE MATCH` 快路径按索引
|
|
24
|
+
计数会多计。修复: 谓词改 `indexed != table_rows`(双向); 实证中
|
|
25
|
+
干净关闭/WAL 回放通常兜底此窗口, `!=` 为纵深防御。回归:
|
|
26
|
+
test_crash_recovery.py 扩展奇数轮 kill@DELCKPT(删除后 checkpoint
|
|
27
|
+
即杀), 断言 MATCH 与活行精确一致
|
|
28
|
+
- 详查结论: UPDATE 后多 segment 无同 key 双活(重建计数精确); 文本
|
|
29
|
+
索引磁盘产物全部位于 fts.d/dict.d 两目录(重置完整)
|
|
30
|
+
- **WAL 截断点 durability 对齐(纵深防御)**: checkpoint_impl 与 vacuum
|
|
31
|
+
在 `wal.checkpoint_all()` 截断前新增有界(2s try-write)FTS flush。
|
|
32
|
+
原理: UPDATE 的 term 级墓碑(deleted_term_docs)纯内存, 计数谓词
|
|
33
|
+
(total_docs 净变化为零)天然看不见内容级漂移; 截断 WAL 会移除本可
|
|
34
|
+
回放重放的索引变更。实测该窗口被 WAL 回放兜住(不 flush 崩溃结果
|
|
35
|
+
也正确), 此为原理性对齐而非实测缺陷修复; 锁竞争时跳过(不劣于
|
|
36
|
+
修复前)
|
|
37
|
+
- **🔑 在线 backup 竞态修复(全套件并行实抓, 上项改动的连带暴露)**:
|
|
38
|
+
backup 拷贝与"已 in-flight 的段交换"竞态时 NotFound 只重试 3×50ms
|
|
39
|
+
— 全套件并行负载下逃逸(backup_to 报 Io NotFound)。且 auto-checkpoint
|
|
40
|
+
持 is_flushing 的临界区因上面的 FTS flush 变长, backup 的 CAS 冲突
|
|
41
|
+
从"立即报错"概率上升。修复: 拷贝重试 3×50ms → 10×100ms; is_flushing
|
|
42
|
+
CAS 冲突内部重试 ~2.5s 后才上抛 "retry backup"。因果验证: 去 FTS
|
|
43
|
+
flush 的全套件 exit 0, 带上后 2/2 失败, 加宽重试后收敛
|
|
44
|
+
- **标记契约加固(二轮自查)**:
|
|
45
|
+
- **重置顺序(Windows 关键)**: `TextFTSIndex::new` 是 create-or-OPEN,
|
|
46
|
+
会加载残留文件; 旧索引对象持着 fts.d 内文件句柄时 Windows 删除目录
|
|
47
|
+
因共享冲突失败 → new() 会加载旧状态、追加膨胀复活。修复: 先从 map
|
|
48
|
+
移除旧条目(释放句柄)再删目录再新建(macOS 上不可测, 代码序保证)
|
|
49
|
+
- **盖章归属与僵尸句柄**: close() 释放 flock 后对象可存活到 GC ——
|
|
50
|
+
僵尸 Drop 在新实例 open 之后再盖章 = 给新会话中途状态谎报"干净"。
|
|
51
|
+
修复: close() 在**持锁期间**(release_lock 之前)盖章(Python 主路径
|
|
52
|
+
即时生效, 不依赖 GC); Drop 路径仅在仍持锁(从未 close)时盖章
|
|
53
|
+
- **标记持久化**: fsync 文件 + rename + unix 目录 fsync, 标记严格
|
|
54
|
+
排在被 flush 的索引数据之后(断电不出现"标记在、数据不在")
|
|
55
|
+
|
|
3
56
|
## [0.12.8] — 2026-10-09
|
|
4
57
|
|
|
5
58
|
- **🔑 kill -9 崩溃后全文索引静默滞后修复(PyPI 包压测实抓)**: 崩溃发生在
|
|
@@ -403,7 +403,7 @@ dependencies = [
|
|
|
403
403
|
|
|
404
404
|
[[package]]
|
|
405
405
|
name = "motedb"
|
|
406
|
-
version = "0.12.
|
|
406
|
+
version = "0.12.9"
|
|
407
407
|
dependencies = [
|
|
408
408
|
"arc-swap",
|
|
409
409
|
"bincode",
|
|
@@ -430,7 +430,7 @@ dependencies = [
|
|
|
430
430
|
|
|
431
431
|
[[package]]
|
|
432
432
|
name = "motedb-python"
|
|
433
|
-
version = "0.12.
|
|
433
|
+
version = "0.12.9"
|
|
434
434
|
dependencies = [
|
|
435
435
|
"motedb",
|
|
436
436
|
"pyo3",
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""kill -9 崩溃恢复回归: 表数据连续无缺口 + FTS
|
|
3
|
-
v0.12.8
|
|
2
|
+
"""kill -9 崩溃恢复回归: 表数据连续无缺口 + FTS 完整(双向)。
|
|
3
|
+
v0.12.8 修复: 已 checkpoint 的表崩溃后无 WAL 回放 → 文本索引的内存
|
|
4
4
|
pending 丢失且无人重建 → MATCH 静默缺行(实测 198/300, doctor 仍 PASS)。
|
|
5
|
-
|
|
5
|
+
v0.12.9 修复两个残余缺口:
|
|
6
|
+
(a) 重建在旧索引上追加而非重置 → total_docs/TF 膨胀(BM25 漂移);
|
|
7
|
+
(b) 墓碑丢失方向: crash 前 DELETE 的内存 tombstone 未落盘 → 磁盘索引
|
|
8
|
+
total_docs > 表行数, 旧 `<` 谓词不触发重建 → MATCH 幻影多计。
|
|
9
|
+
偶数轮 kill@CKPT 打插入丢失窗口, 奇数轮 kill@DELCKPT 打墓碑丢失窗口;
|
|
10
|
+
两方向都断言 MATCH 计数与活行精确一致。"""
|
|
6
11
|
import os
|
|
7
12
|
import shutil
|
|
8
13
|
import subprocess
|
|
@@ -25,6 +30,8 @@ WRITER = textwrap.dedent("""
|
|
|
25
30
|
db.execute("INSERT INTO c VALUES (?, ?)", params=[i, f"post {i}"])
|
|
26
31
|
if i % 50 == 0:
|
|
27
32
|
db.checkpoint(); print(f"CKPT{i}", flush=True)
|
|
33
|
+
db.execute("DELETE FROM c WHERE id >= 400")
|
|
34
|
+
db.checkpoint(); print("DELCKPT", flush=True)
|
|
28
35
|
""")
|
|
29
36
|
|
|
30
37
|
|
|
@@ -32,7 +39,7 @@ def main():
|
|
|
32
39
|
tmp = tempfile.mkdtemp()
|
|
33
40
|
path = os.path.join(tmp, "crash.mote")
|
|
34
41
|
fails = 0
|
|
35
|
-
trials = int(sys.argv[1]) if len(sys.argv) > 1 else
|
|
42
|
+
trials = int(sys.argv[1]) if len(sys.argv) > 1 else 6
|
|
36
43
|
try:
|
|
37
44
|
for t in range(trials):
|
|
38
45
|
if os.path.isdir(path):
|
|
@@ -42,12 +49,17 @@ def main():
|
|
|
42
49
|
proc = subprocess.Popen(
|
|
43
50
|
[sys.executable, "-c", WRITER, path],
|
|
44
51
|
stdout=subprocess.PIPE, text=True)
|
|
52
|
+
# Even trials: kill in the post-checkpoint INSERT window
|
|
53
|
+
# (index behind). Odd trials: kill right after the post-DELETE
|
|
54
|
+
# checkpoint (tombstones still memory-only → index ahead).
|
|
55
|
+
want = "DELCKPT" if t % 2 else "CKPT"
|
|
45
56
|
killed = None
|
|
46
57
|
for line in proc.stdout:
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
killed =
|
|
50
|
-
|
|
58
|
+
s = line.strip()
|
|
59
|
+
if s.startswith("CKPT") and want == "CKPT":
|
|
60
|
+
proc.kill(); killed = s; break
|
|
61
|
+
if s == "DELCKPT" and want == "DELCKPT":
|
|
62
|
+
proc.kill(); killed = s; break
|
|
51
63
|
proc.wait()
|
|
52
64
|
db = motedb.Database(path)
|
|
53
65
|
n = db.execute("SELECT COUNT(*) AS n FROM c")[0]["n"]
|
|
@@ -55,10 +67,16 @@ def main():
|
|
|
55
67
|
cnt = db.execute("SELECT COUNT(DISTINCT id) AS d FROM c")[0]["d"]
|
|
56
68
|
fts = db.execute(
|
|
57
69
|
"SELECT COUNT(*) AS n FROM c WHERE MATCH(v, 'common')")[0]["n"]
|
|
70
|
+
post_live = db.execute(
|
|
71
|
+
"SELECT COUNT(*) AS n FROM c WHERE id >= 300")[0]["n"]
|
|
72
|
+
post_fts = db.execute(
|
|
73
|
+
"SELECT COUNT(*) AS n FROM c WHERE MATCH(v, 'post')")[0]["n"]
|
|
58
74
|
db.close()
|
|
59
|
-
ok = cnt == mx + 1 and fts == 300
|
|
75
|
+
ok = (cnt == mx + 1 and fts == 300
|
|
76
|
+
and post_fts == post_live) # exact: no missing, no phantoms
|
|
60
77
|
print(f"{'ok ' if ok else 'FAIL'} trial{t} kill@{killed} "
|
|
61
|
-
f"rows={n} contiguous={cnt == mx + 1} fts={fts}/300"
|
|
78
|
+
f"rows={n} contiguous={cnt == mx + 1} fts={fts}/300 "
|
|
79
|
+
f"post fts={post_fts}/live{post_live}")
|
|
62
80
|
if not ok:
|
|
63
81
|
fails += 1
|
|
64
82
|
finally:
|
|
@@ -4,7 +4,7 @@ build-backend = "maturin"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "motedb-python"
|
|
7
|
-
version = "0.12.
|
|
7
|
+
version = "0.12.9"
|
|
8
8
|
description = "AI-native embedded multimodal database — SQL, vectors, full-text, spatial and time-series in one ACID engine, with edge presets for robots and edge devices."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -533,6 +533,15 @@ impl Database {
|
|
|
533
533
|
self.inner
|
|
534
534
|
.is_closed
|
|
535
535
|
.store(true, std::sync::atomic::Ordering::Release);
|
|
536
|
+
// 🔒 v0.12.9: stamp the FTS freshness marker while we still hold the
|
|
537
|
+
// exclusive lock (release_lock is below). Stamping here — not only in
|
|
538
|
+
// MoteDB::Drop — makes the marker prompt for explicit close() users
|
|
539
|
+
// (the Python binding's primary path; Drop may wait for GC), and the
|
|
540
|
+
// lock ordering guarantees no NEW instance can have opened yet, so
|
|
541
|
+
// the marker can never attest freshness for someone else's session.
|
|
542
|
+
if result.is_ok() {
|
|
543
|
+
self.inner.stamp_fts_freshness_marker("[close]");
|
|
544
|
+
}
|
|
536
545
|
// Release the exclusive flock so a subsequent open() on the same
|
|
537
546
|
// directory (or another process) can acquire it. Without this, the
|
|
538
547
|
// lock is held until the MoteDB is dropped — which may be much later
|
|
@@ -891,6 +891,14 @@ impl MoteDB {
|
|
|
891
891
|
// 🔒 Acquire exclusive file lock to prevent concurrent opens
|
|
892
892
|
let lock_file = Self::acquire_lock(&db_path)?;
|
|
893
893
|
|
|
894
|
+
// 🔒 Crash-evidence gate (v0.12.9): a clean Drop flushes the FTS
|
|
895
|
+
// indexes and stamps this marker. Its absence ⇒ index durability is
|
|
896
|
+
// suspect (crash / kill -9) ⇒ the stale-count check in the rebuild
|
|
897
|
+
// loop below runs and rebuilds on mismatch. Captured BEFORE removal
|
|
898
|
+
// (a crash mid-open must never leave a stale marker behind).
|
|
899
|
+
let clean_close = db_path.join("fts_indexes.fresh").exists();
|
|
900
|
+
let _ = std::fs::remove_file(db_path.join("fts_indexes.fresh"));
|
|
901
|
+
|
|
894
902
|
// 🎯 统一目录结构:从 {name}.mote/ 目录读取
|
|
895
903
|
let wal_path = db_path.join("wal");
|
|
896
904
|
let lsm_dir = db_path.join("lsm");
|
|
@@ -1862,15 +1870,25 @@ impl MoteDB {
|
|
|
1862
1870
|
for name in txt_idx {
|
|
1863
1871
|
if let Some((table, column)) = db.index_registry.resolve_index_name(&name) {
|
|
1864
1872
|
let corrupt = corrupt_loaded.iter().any(|n| n == &name);
|
|
1865
|
-
// 🔒 Stale-index detection (kill -9 recovery audit,
|
|
1866
|
-
// a crash between table-data durability
|
|
1867
|
-
// flush leaves the index VALID but
|
|
1868
|
-
// lists are memory-only
|
|
1869
|
-
//
|
|
1870
|
-
//
|
|
1871
|
-
//
|
|
1872
|
-
//
|
|
1873
|
-
|
|
1873
|
+
// 🔒 Stale-index detection (kill -9 recovery audit,
|
|
1874
|
+
// v0.12.8/v0.12.9): a crash between table-data durability
|
|
1875
|
+
// and text-index flush leaves the index VALID but WRONG in
|
|
1876
|
+
// EITHER direction — pending posting lists are memory-only
|
|
1877
|
+
// (index BEHIND: MATCH silently missed rows, measured
|
|
1878
|
+
// 198/300 after kill) and in-memory tombstones are equally
|
|
1879
|
+
// volatile (index AHEAD: postings still reference deleted
|
|
1880
|
+
// rows, phantom MATCH hits / COUNT overcount). No WAL
|
|
1881
|
+
// replay happens for already-checkpointed tables, so the
|
|
1882
|
+
// v1 trigger (replayed/corrupt only) skipped both classes.
|
|
1883
|
+
// Rebuild on ANY count mismatch. NULL texts are legitimately
|
|
1884
|
+
// unindexed, so mismatched-but-clean tables (NULL-bearing)
|
|
1885
|
+
// also rebuild here — that is crash-path-only work: a clean
|
|
1886
|
+
// Drop stamps `fts_indexes.fresh`, and open skips this
|
|
1887
|
+
// check entirely when the marker was present (marker is
|
|
1888
|
+
// consumed at open start, above). Replayed/corrupt triggers
|
|
1889
|
+
// stay live regardless of the marker — they carry their own
|
|
1890
|
+
// evidence.
|
|
1891
|
+
let stale = !clean_close && {
|
|
1874
1892
|
// NOTE: this runs BEFORE table_row_count is
|
|
1875
1893
|
// initialized in open() — count live rows straight
|
|
1876
1894
|
// from the segment store (the authoritative source
|
|
@@ -1885,11 +1903,51 @@ impl MoteDB {
|
|
|
1885
1903
|
.get(&name)
|
|
1886
1904
|
.map(|i| i.read().stats().total_docs)
|
|
1887
1905
|
.unwrap_or(0);
|
|
1888
|
-
|
|
1906
|
+
indexed != table_rows
|
|
1889
1907
|
};
|
|
1890
1908
|
if !replayed_tables.contains(&table) && !corrupt && !stale {
|
|
1891
1909
|
continue;
|
|
1892
1910
|
}
|
|
1911
|
+
// 🔒 v0.12.9: HARD RESET before rebuilding. The rebuild
|
|
1912
|
+
// used to APPEND into the loaded (possibly stale) index:
|
|
1913
|
+
// batch_insert is not idempotent — total_docs += n
|
|
1914
|
+
// unconditionally and PostingList::add bumps TF for
|
|
1915
|
+
// already-present docs — so a rebuild over surviving state
|
|
1916
|
+
// inflated total_docs (~2×) and doubled term frequencies
|
|
1917
|
+
// (silent BM25 drift, permanent until a full reset).
|
|
1918
|
+
// Mirror the load path's reset (drop both on-disk dirs,
|
|
1919
|
+
// start a fresh index) so rebuilt == exactly the live
|
|
1920
|
+
// rows. Re-resetting an already-fresh index (replayed /
|
|
1921
|
+
// corrupt paths reset during load) is harmless.
|
|
1922
|
+
//
|
|
1923
|
+
// 🔒 ORDER MATTERS (Windows): TextFTSIndex::new is
|
|
1924
|
+
// create-OR-OPEN — it loads whatever files still exist.
|
|
1925
|
+
// The map entry is therefore removed FIRST so the last
|
|
1926
|
+
// Arc (and its open handles into text_*.fts.d) drops
|
|
1927
|
+
// BEFORE remove_dir_all: with the loaded index still
|
|
1928
|
+
// alive, Windows sharing violations make the removal
|
|
1929
|
+
// fail and new() would re-load the stale state, silently
|
|
1930
|
+
// reviving the append bug. (The builder pipeline starts
|
|
1931
|
+
// only after this loop, so the map is the sole holder.)
|
|
1932
|
+
db.text_indexes.remove(&name);
|
|
1933
|
+
let fts_dir = indexes_dir.join(format!("text_{}.fts.d", name));
|
|
1934
|
+
let dict_dir = indexes_dir.join(format!("text_{}.dict.d", name));
|
|
1935
|
+
let _ = std::fs::remove_dir_all(&fts_dir);
|
|
1936
|
+
let _ = std::fs::remove_dir_all(&dict_dir);
|
|
1937
|
+
match TextFTSIndex::new(indexes_dir.join(format!("text_{}", name))) {
|
|
1938
|
+
Ok(fresh) => {
|
|
1939
|
+
db.text_indexes.insert(
|
|
1940
|
+
name.clone(),
|
|
1941
|
+
std::sync::Arc::new(parking_lot::RwLock::new(fresh)),
|
|
1942
|
+
);
|
|
1943
|
+
}
|
|
1944
|
+
Err(e) => warn_log!(
|
|
1945
|
+
"[Recovery] ⚠️ text index '{}' reset failed ({:?}) — \
|
|
1946
|
+
index left absent; queries on it error until re-created",
|
|
1947
|
+
name,
|
|
1948
|
+
e
|
|
1949
|
+
),
|
|
1950
|
+
}
|
|
1893
1951
|
if let Ok(schema) = db.table_registry.get_table(&table) {
|
|
1894
1952
|
if let Some(col_def) = schema.columns.iter().find(|c| c.name == column) {
|
|
1895
1953
|
let pos = col_def.position;
|
|
@@ -3074,9 +3132,69 @@ impl Drop for MoteDB {
|
|
|
3074
3132
|
warn_log!("[Drop] Final checkpoint failed: {:?}", e);
|
|
3075
3133
|
warn_log!("[Drop] WAL files may not be cleaned up");
|
|
3076
3134
|
} else {
|
|
3135
|
+
// 🔒 v0.12.9 clean-close marker (Drop path — covers handles that
|
|
3136
|
+
// were never explicitly closed). Gated on the exclusive flock:
|
|
3137
|
+
// close() releases the lock but the object may stay alive until
|
|
3138
|
+
// GC — a zombie Drop stamping AFTER a new instance opened would
|
|
3139
|
+
// fake freshness for that new session's mid-flight state.
|
|
3140
|
+
// close() itself stamps under the lock before releasing it.
|
|
3141
|
+
if self.holds_exclusive_lock() {
|
|
3142
|
+
self.stamp_fts_freshness_marker("[MoteDB::Drop]");
|
|
3143
|
+
}
|
|
3077
3144
|
debug_log!("[MoteDB::Drop] ✅ Final checkpoint complete, WAL cleaned");
|
|
3078
3145
|
}
|
|
3079
3146
|
|
|
3080
3147
|
debug_log!("[MoteDB::Drop] 👋 Database closed cleanly");
|
|
3081
3148
|
}
|
|
3082
3149
|
}
|
|
3150
|
+
|
|
3151
|
+
impl MoteDB {
|
|
3152
|
+
/// True while this instance still owns the exclusive directory lock,
|
|
3153
|
+
/// i.e. `close()` has not run (`release_lock` takes the File).
|
|
3154
|
+
fn holds_exclusive_lock(&self) -> bool {
|
|
3155
|
+
self._lock_file
|
|
3156
|
+
.lock()
|
|
3157
|
+
.map(|guard| guard.is_some())
|
|
3158
|
+
.unwrap_or(false)
|
|
3159
|
+
}
|
|
3160
|
+
|
|
3161
|
+
/// 🔒 v0.12.9 clean-close marker: flush the FTS indexes (bounded — never
|
|
3162
|
+
/// hang the caller on a wedged index write lock; skipping the marker
|
|
3163
|
+
/// just means the next open pays the crash-verify path) and durably
|
|
3164
|
+
/// stamp `fts_indexes.fresh`. CALLER MUST HOLD THE EXCLUSIVE LOCK — see
|
|
3165
|
+
/// `holds_exclusive_lock`.
|
|
3166
|
+
pub(crate) fn stamp_fts_freshness_marker(&self, who: &str) {
|
|
3167
|
+
if !self.try_flush_text_indexes_bounded(std::time::Duration::from_secs(2)) {
|
|
3168
|
+
warn_log!(
|
|
3169
|
+
"{who} ⚠️ FTS flush not confirmed — skipping fts_indexes.fresh stamp \
|
|
3170
|
+
(next open pays crash-verify)"
|
|
3171
|
+
);
|
|
3172
|
+
return;
|
|
3173
|
+
}
|
|
3174
|
+
// Durable stamp (fs::write alone is page-cache only): fsync the
|
|
3175
|
+
// file, rename, then fsync the dir (unix-only — Windows opens on
|
|
3176
|
+
// directories return Access Denied, v0.12.6). This orders the marker
|
|
3177
|
+
// STRICTLY AFTER the flushed index data so a power loss can never
|
|
3178
|
+
// leave the marker claiming freshness for postings that didn't
|
|
3179
|
+
// survive.
|
|
3180
|
+
let marker = self.path.join("fts_indexes.fresh");
|
|
3181
|
+
let tmp = self.path.join(".fts_indexes.fresh.tmp");
|
|
3182
|
+
let stamped = (|| -> std::io::Result<()> {
|
|
3183
|
+
use std::io::Write;
|
|
3184
|
+
let mut f = std::fs::File::create(&tmp)?;
|
|
3185
|
+
f.write_all(b"v1")?;
|
|
3186
|
+
f.sync_all()?;
|
|
3187
|
+
drop(f);
|
|
3188
|
+
std::fs::rename(&tmp, &marker)?;
|
|
3189
|
+
#[cfg(unix)]
|
|
3190
|
+
std::fs::File::open(&self.path)?.sync_all()?;
|
|
3191
|
+
Ok(())
|
|
3192
|
+
})();
|
|
3193
|
+
match stamped {
|
|
3194
|
+
Ok(()) => debug_log!("{who} ✅ FTS flushed, freshness marker stamped"),
|
|
3195
|
+
Err(e) => warn_log!(
|
|
3196
|
+
"{who} ⚠️ fts_indexes.fresh stamp failed ({e:?}) — next open pays crash-verify"
|
|
3197
|
+
),
|
|
3198
|
+
}
|
|
3199
|
+
}
|
|
3200
|
+
}
|
|
@@ -358,4 +358,26 @@ impl MoteDB {
|
|
|
358
358
|
|
|
359
359
|
Ok(())
|
|
360
360
|
}
|
|
361
|
+
|
|
362
|
+
/// 🔒 Drop-path bounded flush (v0.12.9): the index-builder thread was
|
|
363
|
+
/// asked to stop before this runs, but a wedged sub-thread could still
|
|
364
|
+
/// hold an index write lock (join timeout edge). A blocking `write()`
|
|
365
|
+
/// here could hang Drop forever; try-bounded instead and report whether
|
|
366
|
+
/// EVERY index flushed — the caller only stamps the clean-close marker
|
|
367
|
+
/// on `true` (no marker ⇒ next open runs the crash-verify path, which
|
|
368
|
+
/// is correct, merely slower).
|
|
369
|
+
pub fn try_flush_text_indexes_bounded(&self, timeout: std::time::Duration) -> bool {
|
|
370
|
+
let mut all_flushed = true;
|
|
371
|
+
for entry in self.text_indexes.iter() {
|
|
372
|
+
match entry.value().try_write_for(timeout) {
|
|
373
|
+
Some(mut index) => {
|
|
374
|
+
if index.flush().is_err() {
|
|
375
|
+
all_flushed = false;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
None => all_flushed = false,
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
all_flushed
|
|
382
|
+
}
|
|
361
383
|
}
|
|
@@ -112,11 +112,26 @@ impl MoteDB {
|
|
|
112
112
|
// Same discipline as flush(): CAS the reentrancy flag, then hold
|
|
113
113
|
// checkpoint_mutex so auto-checkpoint/compaction can't rewrite
|
|
114
114
|
// segment files mid-copy.
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
115
|
+
// 🔒 v0.12.9: auto-checkpoint holds this flag for its whole run
|
|
116
|
+
// (index flush + WAL truncation + segment compaction — seconds under
|
|
117
|
+
// load). Erroring on first collision made concurrent backup+checkpoint
|
|
118
|
+
// flaky at full-suite parallelism; retry the CAS briefly before
|
|
119
|
+
// surfacing the "retry backup" contract error.
|
|
120
|
+
let mut acquired = false;
|
|
121
|
+
for attempt in 0..6 {
|
|
122
|
+
if self
|
|
123
|
+
.is_flushing
|
|
124
|
+
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
|
|
125
|
+
.is_ok()
|
|
126
|
+
{
|
|
127
|
+
acquired = true;
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
if attempt < 5 {
|
|
131
|
+
std::thread::sleep(std::time::Duration::from_millis(250));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if !acquired {
|
|
120
135
|
return Err(StorageError::InvalidData(
|
|
121
136
|
"a flush/checkpoint is in progress — retry backup".into(),
|
|
122
137
|
));
|
|
@@ -164,9 +179,16 @@ impl MoteDB {
|
|
|
164
179
|
let result = match flush_result {
|
|
165
180
|
Ok(()) => {
|
|
166
181
|
let mut out = Ok(());
|
|
167
|
-
|
|
182
|
+
// 🔒 The copy can race a writer whose flush_buffer (or a
|
|
183
|
+
// background lsm-flush) was ALREADY in flight when the write
|
|
184
|
+
// stripes were taken: it finishes during the copy, atomically
|
|
185
|
+
// swapping segment files. NotFound is transient by
|
|
186
|
+
// construction — retry with enough patience to ride out a
|
|
187
|
+
// loaded runner (3×50ms escaped under full-suite parallelism;
|
|
188
|
+
// 10×100ms measured sufficient with margin).
|
|
189
|
+
for attempt in 0..10 {
|
|
168
190
|
if attempt > 0 {
|
|
169
|
-
std::thread::sleep(std::time::Duration::from_millis(
|
|
191
|
+
std::thread::sleep(std::time::Duration::from_millis(100));
|
|
170
192
|
let _ = std::fs::remove_dir_all(&dest);
|
|
171
193
|
}
|
|
172
194
|
match Self::copy_dir_durable(&self.path, &dest) {
|
|
@@ -457,6 +479,16 @@ impl MoteDB {
|
|
|
457
479
|
for entry in self.col_segment_stores.iter() {
|
|
458
480
|
let _ = entry.flush_buffer();
|
|
459
481
|
}
|
|
482
|
+
// 🔒 v0.12.9: same FTS-before-truncation discipline as
|
|
483
|
+
// checkpoint_impl — UPDATE-class text staleness is invisible to
|
|
484
|
+
// count-based recovery checks, so it must never outlive the WAL
|
|
485
|
+
// records that could replay it.
|
|
486
|
+
if !self.try_flush_text_indexes_bounded(std::time::Duration::from_secs(2)) {
|
|
487
|
+
warn_log!(
|
|
488
|
+
"[VACUUM] FTS flush skipped (index lock contention) — \
|
|
489
|
+
text index may lag until close"
|
|
490
|
+
);
|
|
491
|
+
}
|
|
460
492
|
if let Err(e) = self.wal.checkpoint_all() {
|
|
461
493
|
warn_log!("[VACUUM] WAL truncation failed (non-fatal): {}", e);
|
|
462
494
|
}
|
|
@@ -562,6 +594,20 @@ impl MoteDB {
|
|
|
562
594
|
warn_log!("[Flush] Columnar store flush failed: {}", e);
|
|
563
595
|
}
|
|
564
596
|
|
|
597
|
+
// 🔒 v0.12.9: persist FTS in-memory state (tombstones + pending
|
|
598
|
+
// postings) BEFORE the WAL truncation below. The truncation removes
|
|
599
|
+
// the replay that would otherwise re-apply text mutations on reopen,
|
|
600
|
+
// and an UPDATE changes total_docs by ZERO — the open-time count
|
|
601
|
+
// predicate cannot see the lost tombstone/re-post. Bounded try-write
|
|
602
|
+
// past the drain wait above: if the builder still holds a lock, skip
|
|
603
|
+
// — same exposure as before this fix, never worse.
|
|
604
|
+
if !self.try_flush_text_indexes_bounded(std::time::Duration::from_secs(2)) {
|
|
605
|
+
warn_log!(
|
|
606
|
+
"[checkpoint] FTS flush skipped (index lock contention) — \
|
|
607
|
+
text index may lag until close"
|
|
608
|
+
);
|
|
609
|
+
}
|
|
610
|
+
|
|
565
611
|
let checkpoint_done = if immutable_queue_len == 0 || !self.col_segment_stores.is_empty() {
|
|
566
612
|
// All data has been flushed:
|
|
567
613
|
// - LSM memtables are empty (immutable_queue is 0), OR
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
//! Multi-row UPDATE × FTS: only rows the UPDATE touched may change their
|
|
2
|
+
//! match sets. Rows 0..149 become "gamma delta"; rows 150..299 keep
|
|
3
|
+
//! "alpha beta {i}". A stale index (lost term tombstones) would return
|
|
4
|
+
//! alpha=300 (phantoms) or gamma<150 (missing).
|
|
5
|
+
use motedb::{DBConfig, Database};
|
|
6
|
+
use tempfile::TempDir;
|
|
7
|
+
|
|
8
|
+
fn n(db: &Database, sql: &str) -> i64 {
|
|
9
|
+
let r = db.execute(sql).unwrap().materialize().unwrap();
|
|
10
|
+
let (_, rows) = r.select_rows().unwrap();
|
|
11
|
+
match &rows[0][0] {
|
|
12
|
+
motedb::types::Value::Integer(i) => *i,
|
|
13
|
+
other => panic!("{other:?}"),
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
#[test]
|
|
18
|
+
fn multirow_update_fts_exact_matches() {
|
|
19
|
+
let dir = TempDir::new().unwrap();
|
|
20
|
+
let mut config = DBConfig::for_testing();
|
|
21
|
+
config.auto_checkpoint = None;
|
|
22
|
+
let db = Database::create_with_config(dir.path().join("x.mote"), config).unwrap();
|
|
23
|
+
db.execute("CREATE TABLE c (id INTEGER PRIMARY KEY, v TEXT)").unwrap();
|
|
24
|
+
db.execute("CREATE TEXT INDEX ci ON c(v)").unwrap();
|
|
25
|
+
for i in 0..300 {
|
|
26
|
+
db.execute(&format!("INSERT INTO c VALUES ({i}, 'alpha beta {i}')"))
|
|
27
|
+
.unwrap();
|
|
28
|
+
}
|
|
29
|
+
// Checkpoint so the auto-flush threshold fires for the insert postings.
|
|
30
|
+
db.checkpoint().unwrap();
|
|
31
|
+
let pre = n(&db, "SELECT COUNT(*) FROM c WHERE MATCH(v, 'alpha')");
|
|
32
|
+
assert_eq!(pre, 300, "pre-update sanity");
|
|
33
|
+
|
|
34
|
+
db.execute("UPDATE c SET v = 'gamma delta' WHERE id < 150").unwrap();
|
|
35
|
+
|
|
36
|
+
let post = n(&db, "SELECT COUNT(*) FROM c WHERE MATCH(v, 'alpha')");
|
|
37
|
+
let gamma = n(&db, "SELECT COUNT(*) FROM c WHERE MATCH(v, 'gamma')");
|
|
38
|
+
println!("post-update: alpha={post} (want 150) gamma={gamma} (want 150)");
|
|
39
|
+
assert_eq!(gamma, 150, "updated rows must match the new text");
|
|
40
|
+
assert_eq!(post, 150, "only untouched rows may still match the old text");
|
|
41
|
+
}
|