Some checks failed
Build / Test on ubuntu-latest, py-3.8 (push) Successful in 4m21s
Lint / lint (push) Successful in 25s
Build / Test on macOS-latest, py-3.8 (push) Has been cancelled
Build / Test on windows-latest, py-3.8 (push) Has been cancelled
CodeQL / Analyze (python) (push) Failing after 1s
67 lines
2.3 KiB
Python
67 lines
2.3 KiB
Python
"""
|
|
Peewee-storage-specific tests, mainly for the schema/index migration in
|
|
auto_migrate() and for guarding against query-plan regressions.
|
|
"""
|
|
|
|
import logging
|
|
|
|
from aw_datastore.storages import PeeweeStorage
|
|
from aw_datastore.storages import peewee as peewee_storage
|
|
|
|
from . import context # noqa: F401
|
|
|
|
logging.basicConfig(level=logging.DEBUG)
|
|
|
|
|
|
def _indexes(db) -> set:
|
|
return {row[1] for row in db.execute_sql("PRAGMA index_list(eventmodel)")}
|
|
|
|
|
|
def test_index_migration():
|
|
"""auto_migrate() replaces the old single-column indexes with the composite one."""
|
|
storage = PeeweeStorage(testing=True)
|
|
db = storage.db
|
|
path = db.database
|
|
|
|
assert "eventmodel_bucket_id_timestamp" in _indexes(db)
|
|
|
|
# Recreate the pre-migration state: single-column indexes, no composite
|
|
db.execute_sql("DROP INDEX eventmodel_bucket_id_timestamp")
|
|
db.execute_sql("CREATE INDEX eventmodel_bucket_id ON eventmodel (bucket_id)")
|
|
db.execute_sql("CREATE INDEX eventmodel_timestamp ON eventmodel (timestamp)")
|
|
|
|
peewee_storage.auto_migrate(path)
|
|
|
|
indexes = _indexes(db)
|
|
assert "eventmodel_bucket_id_timestamp" in indexes
|
|
assert "eventmodel_bucket_id" not in indexes
|
|
assert "eventmodel_timestamp" not in indexes
|
|
|
|
|
|
def test_query_plan_uses_composite_index():
|
|
"""
|
|
The last-event query (issued by replace_last on every merged heartbeat) and
|
|
range queries must be served by the composite index in a single pass.
|
|
|
|
Without it, SQLite reads *all* of a bucket's rows and sorts them in a temp
|
|
B-tree even for LIMIT 1, which on multi-million-event buckets meant seconds
|
|
of CPU/IO per heartbeat (and terabytes read per day).
|
|
"""
|
|
storage = PeeweeStorage(testing=True)
|
|
db = storage.db
|
|
|
|
queries = [
|
|
# replace_last/_get_last
|
|
"SELECT * FROM eventmodel WHERE bucket_id = 1"
|
|
" ORDER BY timestamp DESC LIMIT 1",
|
|
# get_events with a time range
|
|
"SELECT * FROM eventmodel WHERE bucket_id = 1"
|
|
" AND timestamp >= '2026-01-01' AND timestamp <= '2026-01-02'"
|
|
" ORDER BY timestamp DESC LIMIT 100",
|
|
]
|
|
for query in queries:
|
|
rows = db.execute_sql(f"EXPLAIN QUERY PLAN {query}").fetchall()
|
|
plan = "\n".join(str(row) for row in rows)
|
|
assert "eventmodel_bucket_id_timestamp" in plan, plan
|
|
assert "TEMP B-TREE" not in plan, plan
|