You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
memory-upgrader.ts currently processes each entry with LLM enrichment AND store.update() inside the same lock cycle:
// Current flow (problematic)for(constentryofbatch){awaitthis.upgradeEntry(entry,noLlm);// LLM + lock per entry}
This causes:
N lock acquisitions for N entries = high contention
Plugin waits seconds while LLM runs between lock acquisitions
Cross-session lock contention between upgrade CLI and plugin
Solution: Two-Phase Approach
Separate LLM enrichment from DB writes:
// Phase 1: LLM enrichment - NO LOCKconstenriched=awaitPromise.all(batch.map(entry=>this.prepareEntry(entry,noLlm)));// Phase 2: Single lock for ALL DB writesawaitthis.store.runWithFileLock(async()=>{for(constentryofenriched){awaitthis.store.update(entry.id,{text: entry.l0_abstract,metadata: entry.metadata,});}});
Why This Works
Phase
Lock
Plugin Impact
Phase 1 (LLM)
No
None
Phase 2 (DB writes)
Yes
Plugin waits only for DB write time (ms)
Comparison
Approach
Lock Count (batch=10)
Plugin Wait Time
Current
10
Seconds (LLM time)
Fixed
1
Milliseconds (DB write time)
Key Changes Required
Extract prepareEntry() - Separate LLM logic from upgradeEntry()
Modify upgrade() loop - Two-phase processing
No new API needed - Use existing store.update() in lock
Unit Tests Needed
// Test 1: Lock acquired once per batchtest("upgrade acquires lock once per batch",async()=>{letlockCount=0;store.runWithFileLock=async(fn)=>{lockCount++;returnfn();};awaitupgrader.upgrade({batchSize: 5});assert.equal(lockCount,1);// Not 5});// Test 2: LLM runs before locktest("LLM enrichment happens before lock acquisition",async()=>{constorder=[];store.runWithFileLock=async(fn)=>{order.push("lock-start");awaitfn();order.push("lock-end");};upgrader.prepareEntry=async()=>{order.push("llm");returnmockEnriched;};awaitupgrader.upgradeBatch([entry]);constllmIdx=order.indexOf("llm");constlockIdx=order.indexOf("lock-start");assert.ok(llmIdx<lockIdx,"LLM should run before lock");});
Integration Test (Future)
Cross-session test requires real processes, not mocks:
test("cross-session: upgrade and plugin writes both succeed",async()=>{// Requires spawning real processes// Verifies proper-lockfile behavior across processes});
Implementation Plan
Extract prepareEntry() from upgradeEntry()
Modify upgrade() to use two-phase approach
Add unit tests
Test with real upgrade + plugin running concurrently
Issue #632 - Final Analysis and Solution
Problem Confirmed
memory-upgrader.tscurrently processes each entry with LLM enrichment AND store.update() inside the same lock cycle:This causes:
Solution: Two-Phase Approach
Separate LLM enrichment from DB writes:
Why This Works
Comparison
Key Changes Required
prepareEntry()- Separate LLM logic fromupgradeEntry()upgrade()loop - Two-phase processingstore.update()in lockUnit Tests Needed
Integration Test (Future)
Cross-session test requires real processes, not mocks:
Implementation Plan
prepareEntry()fromupgradeEntry()upgrade()to use two-phase approachRelated Issues