test(8.0): cover pending-tier range queries + setRetentionBudget adaptive reclaim
Closes the two coverage gaps a temporal-completeness audit surfaced (the code was already correct, just untested): - changedBetween / generationsTouching include un-flushed PENDING generations and stay identical across the flush — the building blocks of since/diff/history see single-op writes with no forced flush. - setRetentionBudget() drives adaptive auto-compaction on flush() down to the byte budget: history is reclaimed, the live record is untouched (the cor #65 retention-consume wiring, proven end-to-end). 65 generation/temporal tests green; 1528 unit green.
This commit is contained in:
parent
5c3bb2c864
commit
3783e61b30
2 changed files with 38 additions and 0 deletions
|
|
@ -1240,6 +1240,26 @@ describe('8.0 Db API — generational MVCC', () => {
|
|||
await expect(reopened.asOf(1)).rejects.toBeInstanceOf(GenerationCompactedError)
|
||||
})
|
||||
|
||||
it('Model-B retention — setRetentionBudget drives adaptive reclaim on flush; live data intact', async () => {
|
||||
// Default brain → ADAPTIVE retention. A coordinator (e.g. cor's ResourceManager)
|
||||
// pushes a byte budget via setRetentionBudget(); auto-compaction on flush() reclaims
|
||||
// oldest history down toward it. Each update's before-image carries the full prior
|
||||
// 384-dim vector (~KBs), so ~13 generations far exceed a few-KB budget.
|
||||
const { brain } = await openFsBrain()
|
||||
const a = uid('ret-budget')
|
||||
await brain.add({ id: a, type: NounType.Document, data: 'v0', vector: vec(1), metadata: { v: 0 } })
|
||||
for (let v = 1; v <= 12; v++) await brain.update({ id: a, metadata: { v } })
|
||||
|
||||
brain.setRetentionBudget(6000) // ~6 KB — well below the accumulated history
|
||||
await brain.flush() // group-commit + adaptive auto-compaction under the budget
|
||||
|
||||
// History was reclaimed (the horizon advanced past the oldest generations)…
|
||||
expect(generationStoreOf(brain).horizon()).toBeGreaterThan(0)
|
||||
await expect(brain.asOf(1)).rejects.toBeInstanceOf(GenerationCompactedError)
|
||||
// …but the budget reclaims HISTORY only — the live record is untouched.
|
||||
expect((await brain.get(a))?.metadata?.v).toBe(12)
|
||||
})
|
||||
|
||||
// ==========================================================================
|
||||
// 9. asOf() / released-Db error paths (Y.15 spot-checks)
|
||||
// ==========================================================================
|
||||
|
|
|
|||
|
|
@ -363,6 +363,24 @@ describe('db/GenerationStore', () => {
|
|||
expect(store.hasCommittedAfter(g1)).toBe(true)
|
||||
})
|
||||
|
||||
it('range queries (changedBetween / generationsTouching) include un-flushed pending generations', async () => {
|
||||
// Two single-op writes to different ids, NEITHER flushed (still in the
|
||||
// pending tier). diff()/since()/history() are built on these, so they must
|
||||
// see un-flushed single-ops with NO forced flush.
|
||||
const g1 = await singleOpWrite(ID_A, 1)
|
||||
const g2 = await singleOpWrite(ID_B, 1)
|
||||
expect(store.committedGeneration()).toBe(0) // nothing on disk yet
|
||||
|
||||
const changed = await store.changedBetween(0, store.generation())
|
||||
expect(changed.nouns).toEqual([ID_A, ID_B]) // resolves over committed ∪ pending
|
||||
expect(await store.generationsTouching('noun', ID_A, 0, store.generation())).toEqual([g1])
|
||||
expect(await store.generationsTouching('noun', ID_B, 0, store.generation())).toEqual([g2])
|
||||
|
||||
// …and the range stays identical across the flush (now reading from disk).
|
||||
await store.flushPendingSingleOps()
|
||||
expect((await store.changedBetween(0, store.generation())).nouns).toEqual([ID_A, ID_B])
|
||||
})
|
||||
|
||||
it('flush persists pending single-op generations (groupCommit-marked) and advances committed', async () => {
|
||||
await singleOpWrite(ID_A, 1)
|
||||
await singleOpWrite(ID_A, 2)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue