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:
|
||||
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):
|
||||
values = self.create_acknowledged()
|
||||
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)
|
||||
with closing(connect_database(database)) as 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:
|
||||
raise GenerationError("generation retention capacity exhausted")
|
||||
stage = owned_root / "staging" / generation
|
||||
|
|
|
|||
Loading…
Reference in a new issue