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: 2 additions & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ All tests must pass before a change is considered complete.
- Release build: `./scripts/build.sh -r`
- Release build with C++ unit test binary: `./scripts/build.sh -r -t`
- For regular development and focused Python-side test runs, prefer the release build because it is significantly faster. Unless C++ tests are important for the current change, build without `-t`; skipping the C++ test binary is much faster.
- Use a debug build when tracking a specific deep bug that needs assertions or debug-level checks, and before final handoff only when the user explicitly asks for handoff validation.
- Use debug builds only when tracking a specific deep bug that needs assertions/debug-level checks, or when the user explicitly asks for debug validation. Do not run debug validation as a default final handoff step.

### Running tests

- Python tests: `./scripts/run_tests.sh`
- Final Python test checks: `./scripts/run_tests.sh -j 6`
- C++ tests after a `-t` build: `./build/release/tests.x`
- Broad debug/release builds and full-suite checks are final handoff validation only; run them when the user explicitly asks for handoff.
- Before final handoff, also verify the code in debug mode with a debug build (`./scripts/build.sh -d`) and the relevant Python tests against that debug build. Debug assertions are part of the required validation, not optional diagnostics.
- For normal development and handoff, validate against release builds. Run debug-mode tests only when debugging a hard-to-locate problem or when the user explicitly requests them.
- During development, do not run stress tests by default; they are intentionally slow. Run focused tests specific to the feature or refactor being worked on before finalization.
- If any C++ source under the native/core part of the project was modified, also run the C++ test suite during final handoff validation (do not rely on the Python tests alone to cover native changes).

Expand All @@ -40,10 +40,6 @@ Never mark a task done while tests are failing.

Never make cosmetic changes unless they are explicitly requested by the task.

### Temporary immutable objects design

When working on immutable objects, use `design/IMMUTABLE_OBJECTS_DESIGN.md` as the implementation design reference. This file is temporary and should be removed after the feature is complete.

### v_object constructor conventions

Types derived from `v_object` should follow the project-wide constructor pattern:
Expand Down
96 changes: 0 additions & 96 deletions benchmarks/read_only_reads.py

This file was deleted.

76 changes: 25 additions & 51 deletions benchmarks/tagging.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,45 +19,24 @@
- Build: release
- Commands:
python3 benchmarks/tagging.py --scenario fresh-tags --target-seconds 30
python3 benchmarks/tagging.py --scenario fresh-tags --target-seconds 30 --passive
python3 benchmarks/tagging.py --scenario precreated-tags --target-seconds 30
python3 benchmarks/tagging.py --scenario precreated-tags --target-seconds 30 --passive
- Current result, fresh-tags:
regular:
object_count=10000
batch_size=1000
tags_per_batch=1
batches=1442
elapsed_seconds=30.012787
tag_assignments=1442000
tag_assignments_per_second=48046.187
passive:
object_count=10000
batch_size=1000
tags_per_batch=1
batches=1546
elapsed_seconds=30.021849
tag_assignments=1546000
tag_assignments_per_second=51495.829
object_count=10000
batch_size=1000
tags_per_batch=1
batches=1442
elapsed_seconds=30.012787
tag_assignments=1442000
tag_assignments_per_second=48046.187
- Current result, precreated-tags:
regular:
object_count=10000
batch_size=1000
tags_per_batch=1
precreated_tag_count=5000
batches=1334
elapsed_seconds=30.006962
tag_assignments=1334000
tag_assignments_per_second=44456.349
passive:
object_count=10000
batch_size=1000
tags_per_batch=1
precreated_tag_count=5000
batches=1484
elapsed_seconds=30.018302
tag_assignments=1484000
tag_assignments_per_second=49436.507
object_count=10000
batch_size=1000
tags_per_batch=1
precreated_tag_count=5000
batches=1334
elapsed_seconds=30.006962
tag_assignments=1334000
tag_assignments_per_second=44456.349
"""

import argparse
Expand Down Expand Up @@ -96,27 +75,27 @@ def prepare_objects(object_count, batch_size):
return objects, target_objects


def prepare_precreated_tags(tag_count, passive):
def prepare_precreated_tags(tag_count):
tag_owner = TagBenchmarkMemo(-1)
db0.commit()
tags = [
f"{'passive' if passive else 'regular'}-precreated-tag-{index}"
f"precreated-tag-{index}"
for index in range(tag_count)
]
db0.tags(tag_owner, passive=passive).add(tags)
db0.tags(tag_owner).add(tags)
db0.commit()
return tag_owner, tags


def apply_tag_batch(target_objects, tags, passive):
db0.tags(*target_objects, passive=passive).add(tags)
def apply_tag_batch(target_objects, tags):
db0.tags(*target_objects).add(tags)
db0.commit()
return len(target_objects) * len(tags)


def fresh_tag_batch(passive, batch_index, tags_per_batch):
def fresh_tag_batch(batch_index, tags_per_batch):
return [
f"{'passive' if passive else 'regular'}-fresh-tag-{batch_index}-{index}"
f"fresh-tag-{batch_index}-{index}"
for index in range(tags_per_batch)
]

Expand All @@ -129,7 +108,7 @@ def precreated_tag_batch(tags, batch_index, tags_per_batch):
return tags[start:end]


def measure(target_objects, passive, target_seconds, tags_per_batch, tag_batch_factory):
def measure(target_objects, target_seconds, tags_per_batch, tag_batch_factory):
total_assignments = 0
batches = 0
exhausted_tags = False
Expand All @@ -143,7 +122,7 @@ def measure(target_objects, passive, target_seconds, tags_per_batch, tag_batch_f
if tags is None:
exhausted_tags = True
break
total_assignments += apply_tag_batch(target_objects, tags, passive)
total_assignments += apply_tag_batch(target_objects, tags)
batches += 1
if time.perf_counter() >= deadline:
break
Expand All @@ -161,7 +140,6 @@ def main():
choices=("fresh-tags", "precreated-tags"),
default="fresh-tags",
)
parser.add_argument("--passive", action="store_true", help="assign passive tags")
parser.add_argument("--target-seconds", type=float, default=30.0)
parser.add_argument("--object-count", type=int, default=10000)
parser.add_argument("--batch-size", type=int, default=1000)
Expand Down Expand Up @@ -193,13 +171,11 @@ def main():
if args.precreated_tag_count < args.tags_per_batch:
parser.error("--precreated-tag-count must cover at least one measured batch")
precreated_tag_owner, precreated_tags = prepare_precreated_tags(
args.precreated_tag_count,
args.passive,
args.precreated_tag_count
)

if args.scenario == "fresh-tags":
tag_batch_factory = lambda batch: fresh_tag_batch(
args.passive,
batch,
args.tags_per_batch,
)
Expand All @@ -212,7 +188,6 @@ def main():

elapsed, assignments, batches, exhausted_tags = measure(
target_objects,
args.passive,
args.target_seconds,
args.tags_per_batch,
tag_batch_factory,
Expand All @@ -223,7 +198,6 @@ def main():
print(f"build_flags={db0.build_flags()}")
print(f"pid={os.getpid()}")
print(f"scenario={args.scenario}")
print(f"passive={args.passive}")
print(f"object_count={len(objects)}")
print(f"batch_size={args.batch_size}")
print(f"tags_per_batch={args.tags_per_batch}")
Expand Down
20 changes: 14 additions & 6 deletions dbzero/build_package.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#!/bin/bash
set -euo pipefail

function show_help {
echo "Build dbzero python package in the ./build directory and optionally install it"
echo "Use: build_package.sh [options]"
Expand All @@ -7,26 +10,31 @@ function show_help {
}

while true ; do
case "$1" in
case "${1-}" in
-h|--help) show_help ; shift ;;
--install) INSTALL="1" ; shift ;;
--) shift ; break ;;
*) break;;
esac
done

mkdir .build
mkdir .build/dbzero
cp ./dbzero/* ./.build/dbzero
if ! python3 -c 'import setuptools' >/dev/null 2>&1; then
exit 0
fi

package_root="$PWD"
rm -rf .build
trap 'rm -rf "$package_root/.build"' EXIT
mkdir -p .build/dbzero
find ./dbzero -maxdepth 1 -type f -exec cp {} ./.build/dbzero/ \;
cp setup.py .build/setup.py
cp LICENSE .build/LICENSE
cp README.md .build/README.md
cd .build
python3 setup.py sdist
install "$(ls dbzero_package/dist/*.whl | sort | tail -n 1)" --break-system-packages
# Get the current Python3 version
PYTHON3_VERSION=$(python3 -c 'import sys; print(f"{sys.version_info.minor}")')
if [ "${INSTALL}" ] ; then
if [ "${INSTALL-}" ] ; then
if [ "$PYTHON3_VERSION" -ge 11 ]; then
pip3 install "$(ls ./dist/*.tar.gz | sort | tail -n 1)" --break-system-packages
else
Expand Down
2 changes: 0 additions & 2 deletions dbzero/dbzero/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@
# Copyright (c) 2025 DBZero Software sp. z o.o.

from .dbzero import *
from .dbzero import _check_interned, _in_read_only, _init_data_filter, _init_data_masking
from .memo import *
from .enum import *
from .fast_query import *
from .reflection_api import *
from .storage_api import *
from .atomic import *
from .locked import *
from .read_only import *
from .utilities import taggify
from .decorators import *
from .select import *
Expand Down
Loading
Loading