fix(sync): ignore terminal legacy generation capacity
This commit is contained in:
parent
0f7d793960
commit
a88e85c235
2 changed files with 64 additions and 1 deletions
|
|
@ -95,6 +95,54 @@ class GenerationArchiveTest(unittest.TestCase):
|
||||||
with sqlite3.connect(self.database) as database:
|
with sqlite3.connect(self.database) as database:
|
||||||
self.assertEqual(0, database.execute("SELECT COUNT(*) FROM sync_generation_archives").fetchone()[0])
|
self.assertEqual(0, database.execute("SELECT COUNT(*) FROM sync_generation_archives").fetchone()[0])
|
||||||
|
|
||||||
|
def test_historical_acknowledged_rows_without_ack_ledger_do_not_exhaust_admission(self):
|
||||||
|
with sqlite3.connect(self.database) as database:
|
||||||
|
producer = generation.peer_identity(database, "desktop")
|
||||||
|
database.commit()
|
||||||
|
parent = None
|
||||||
|
for index in range(generation.MAX_RETAINED_PER_PEER):
|
||||||
|
suffix = f"{index + 1:012d}"
|
||||||
|
generation_id = f"gen_10000000-0000-4000-8000-{suffix}"
|
||||||
|
run_id = f"sy_20000000-0000-4000-8000-{suffix}"
|
||||||
|
database.execute(
|
||||||
|
"INSERT INTO sync_generations VALUES(?,?,?,?,?,?,?,?,?,?,?,?)",
|
||||||
|
(
|
||||||
|
generation_id,
|
||||||
|
run_id,
|
||||||
|
producer,
|
||||||
|
PEER,
|
||||||
|
"desktop",
|
||||||
|
f"2026-09-16T00:00:{index:02d}+00:00",
|
||||||
|
parent,
|
||||||
|
"0" * 64,
|
||||||
|
"acknowledged",
|
||||||
|
"{}",
|
||||||
|
str(self.owned / "staging" / generation_id),
|
||||||
|
f"2026-09-16T00:01:{index:02d}+00:00",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
parent = generation_id
|
||||||
|
database.commit()
|
||||||
|
|
||||||
|
stage, manifest, _ = generation.capture_desktop(self.database, self.owned, PEER)
|
||||||
|
self.assertTrue(stage.is_dir())
|
||||||
|
self.assertEqual(parent, manifest["parent_generation_id"])
|
||||||
|
with sqlite3.connect(self.database) as database:
|
||||||
|
self.assertEqual(
|
||||||
|
0,
|
||||||
|
database.execute(
|
||||||
|
"SELECT COUNT(*) FROM sync_acknowledgements "
|
||||||
|
"WHERE generation_id LIKE 'gen_10000000-%'"
|
||||||
|
).fetchone()[0],
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
0,
|
||||||
|
database.execute(
|
||||||
|
"SELECT COUNT(*) FROM sync_generation_archives "
|
||||||
|
"WHERE generation_id LIKE 'gen_10000000-%'"
|
||||||
|
).fetchone()[0],
|
||||||
|
)
|
||||||
|
|
||||||
def test_missing_then_late_ack_is_protected_until_correlated(self):
|
def test_missing_then_late_ack_is_protected_until_correlated(self):
|
||||||
values = self.create_acknowledged()
|
values = self.create_acknowledged()
|
||||||
stage, manifest, digest = generation.capture_desktop(self.database, self.owned, PEER)
|
stage, manifest, digest = generation.capture_desktop(self.database, self.owned, PEER)
|
||||||
|
|
|
||||||
|
|
@ -364,7 +364,22 @@ def capture_desktop(database: Path, owned_root: Path, consumer: str,
|
||||||
archive_acknowledged(database, owned_root, consumer)
|
archive_acknowledged(database, owned_root, consumer)
|
||||||
with closing(connect_database(database)) as admission:
|
with closing(connect_database(database)) as admission:
|
||||||
require_schema(admission)
|
require_schema(admission)
|
||||||
retained = admission.execute("SELECT COUNT(*) FROM sync_generations g WHERE consumer_peer_id=? AND status IN('captured','published','waiting_acknowledgement','acknowledged') AND NOT EXISTS(SELECT 1 FROM sync_generation_archives a WHERE a.generation_id=g.generation_id)", (consumer,)).fetchone()[0]
|
# WHY: early private generation builds can contain terminal
|
||||||
|
# acknowledged rows from before durable ACK-ledger insertion was
|
||||||
|
# enforced. They cannot be archived without fabricating missing ACK
|
||||||
|
# evidence, but they are terminal and must not permanently consume the
|
||||||
|
# active admission window. Current production acknowledgements always
|
||||||
|
# have a durable sync_acknowledgements row and remain counted until
|
||||||
|
# archive_acknowledged() safely moves them out of the active window.
|
||||||
|
retained = admission.execute(
|
||||||
|
"SELECT COUNT(*) FROM sync_generations g WHERE consumer_peer_id=? "
|
||||||
|
"AND (g.status IN('captured','published','waiting_acknowledgement') OR "
|
||||||
|
"(g.status='acknowledged' AND EXISTS(SELECT 1 FROM sync_acknowledgements k "
|
||||||
|
"WHERE k.generation_id=g.generation_id))) "
|
||||||
|
"AND NOT EXISTS(SELECT 1 FROM sync_generation_archives a "
|
||||||
|
"WHERE a.generation_id=g.generation_id)",
|
||||||
|
(consumer,),
|
||||||
|
).fetchone()[0]
|
||||||
if retained >= MAX_RETAINED_PER_PEER:
|
if retained >= MAX_RETAINED_PER_PEER:
|
||||||
raise GenerationError("generation retention capacity exhausted")
|
raise GenerationError("generation retention capacity exhausted")
|
||||||
stage = owned_root / "staging" / generation
|
stage = owned_root / "staging" / generation
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue