Monorepo for wisp.place. A static site hosting service built on top of the AT Protocol.
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

sync lastAccessed back to the in-memory metadataIndex

authored by

nekomimi.pet and committed by
Tangled
21178540 bd8e5367

+77
+9
packages/@wispplace/tiered-storage/src/tiers/DiskStorageTier.ts
··· 482 482 } 483 483 484 484 await this.writeMetadataAtomically(metaPath, metadata) 485 + 486 + // Keep in-memory index in sync so eviction (LRU sort) sees updated lastAccessed 487 + const entry = this.metadataIndex.get(key) 488 + if (entry) { 489 + entry.lastAccessed = metadata.lastAccessed 490 + if (metadata.ttl) { 491 + entry.ttl = metadata.ttl 492 + } 493 + } 485 494 } 486 495 487 496 async getStats(): Promise<TierStats> {
+68
packages/@wispplace/tiered-storage/test/DiskStorageTier.gc.test.ts
··· 190 190 }) 191 191 }) 192 192 }) 193 + 194 + describe('DiskStorageTier - LRU eviction respects setMetadata updates', () => { 195 + const lruTestDir = './test-disk-lru' 196 + 197 + beforeEach(async () => { 198 + await rm(lruTestDir, { recursive: true, force: true }) 199 + }) 200 + 201 + afterAll(async () => { 202 + await rm(lruTestDir, { recursive: true, force: true }) 203 + }) 204 + 205 + test('setMetadata updates lastAccessed on disk so LRU order survives restart', async () => { 206 + const data = new TextEncoder().encode('x'.repeat(80)) 207 + 208 + const tier1 = new DiskStorageTier({ directory: lruTestDir, maxSizeBytes: 200, evictionPolicy: 'lru' }) 209 + 210 + const old = new Date(Date.now() - 3000) 211 + const mid = new Date(Date.now() - 2000) 212 + 213 + await tier1.set('a', data, { ...makeMetadata('a', data.byteLength), lastAccessed: old }) 214 + await tier1.set('b', data, { ...makeMetadata('b', data.byteLength), lastAccessed: mid }) 215 + 216 + // Touch 'a' so its lastAccessed is now newest — persisted to disk via setMetadata 217 + const metaA = (await tier1.getMetadata('a'))! 218 + metaA.lastAccessed = new Date() 219 + await tier1.setMetadata('a', metaA) 220 + 221 + // Simulate restart — new instance rebuilds index from disk 222 + const tier2 = new DiskStorageTier({ directory: lruTestDir, maxSizeBytes: 200, evictionPolicy: 'lru' }) 223 + await new Promise((resolve) => setTimeout(resolve, 100)) // let rebuildIndex complete 224 + 225 + // 'b' is now LRU; writing a third entry should evict 'b', not 'a' 226 + await tier2.set('c', data, makeMetadata('c', data.byteLength)) 227 + 228 + expect(await tier2.exists('a')).toBe(true) 229 + expect(await tier2.exists('b')).toBe(false) 230 + expect(await tier2.exists('c')).toBe(true) 231 + }) 232 + 233 + test('recently-accessed entry survives eviction over stale entries', async () => { 234 + // Capacity: 200 bytes, each entry is 80 bytes. 235 + // Write 'a' (old) and 'b' (mid) — 160 bytes total, fits fine. 236 + // Touch 'a' to make it freshest. Then write 'c' (160+80=240 > 200) → eviction. 237 + // 'b' is now the LRU victim; 'a' must survive. 238 + const tier = new DiskStorageTier({ directory: lruTestDir, maxSizeBytes: 200, evictionPolicy: 'lru' }) 239 + const data = new TextEncoder().encode('x'.repeat(80)) 240 + 241 + const old = new Date(Date.now() - 3000) 242 + const mid = new Date(Date.now() - 2000) 243 + 244 + await tier.set('a', data, { ...makeMetadata('a', data.byteLength), lastAccessed: old }) 245 + await tier.set('b', data, { ...makeMetadata('b', data.byteLength), lastAccessed: mid }) 246 + 247 + // Touch 'a' so it becomes the most recently accessed 248 + const metaA = (await tier.getMetadata('a'))! 249 + metaA.lastAccessed = new Date() 250 + await tier.setMetadata('a', metaA) 251 + 252 + // Writing 'c' triggers eviction. Without the fix, 'a' would be evicted 253 + // (stale timestamp in metadataIndex). With the fix, 'b' is evicted instead. 254 + await tier.set('c', data, makeMetadata('c', data.byteLength)) 255 + 256 + expect(await tier.exists('a')).toBe(true) // freshly touched — must survive 257 + expect(await tier.exists('b')).toBe(false) // true LRU victim 258 + expect(await tier.exists('c')).toBe(true) 259 + }) 260 + })