fix: query-cap memory misread (MemAvailable + floor) + rootDirectory getter for native mmap fast-path
Two platform-wide production fixes for consumers on bare VMs / mmap-filesystem storage. BUG A — auto maxQueryLimit collapsed to ~1000 on healthy VMs → 500s on legitimate queries. getAvailableMemory() read os.freemem() (kernel MemFree, which excludes reclaimable page cache and reads as tens of MB on a page-cache-heavy mmap box). Now reads /proc/meminfo MemAvailable (the `free -h` figure), falling back to os.freemem() only off-Linux; auto-detected caps (container/free branches) are floored at 10k so a misread can't collapse them. Explicit maxQueryLimit/reservedQueryMemory are honored as-is. BUG B — native mmap vector fast-path never engaged (per-entity reads → 57s cold start on a 283MB brain). FileSystemStorage now exposes a public `rootDirectory` getter; the native vector provider feature-detects it to enable its memory-mapped graph path. brainy stored it as the protected `rootDir`, so the gate silently failed. Self-heals after the first post-upgrade flush writes the mmap file. Regression tests: auto-cap floor (container/free/explicit-override) + the rootDirectory getter. Build clean; full suite 1483 green.
This commit is contained in:
parent
4f8159c572
commit
3f8e0971a2
5 changed files with 127 additions and 6 deletions
|
|
@ -399,4 +399,32 @@ describe('Memory Limits - Container Detection & Smart Calculation', () => {
|
|||
await brain.close()
|
||||
})
|
||||
})
|
||||
|
||||
// Regression: a memory MISREAD (tiny detected limit, or os.freemem reading a
|
||||
// sliver on a page-cache-heavy mmap box) must NOT collapse the auto cap to
|
||||
// ~1000 and 500 legitimate queries. Auto-detected caps are floored at 10k;
|
||||
// explicit operator settings still pass through unfloored.
|
||||
describe('Auto-cap floor (BUG: querycap collapse on healthy VM)', () => {
|
||||
it('floors the container-derived cap so a tiny/misread limit cannot collapse it', () => {
|
||||
// 50 MB → queryMemory 12.5 MB → floor(12.5/25)·1000 = 0 pre-fix.
|
||||
process.env.MEMORY_LIMIT = String(50 * 1024 * 1024)
|
||||
const config = ValidationConfig.getInstance()
|
||||
expect(config.limitBasis).toBe('containerMemory')
|
||||
expect(config.maxLimit).toBe(10000) // floored, not 0/1000
|
||||
})
|
||||
|
||||
it('floors the free-memory-derived cap as well', () => {
|
||||
// No container env → freeMemory branch. On any real box this is well
|
||||
// above the floor; the guarantee is it can never drop below it.
|
||||
const config = ValidationConfig.getInstance()
|
||||
expect(config.limitBasis).toBe('freeMemory')
|
||||
expect(config.maxLimit).toBeGreaterThanOrEqual(10000)
|
||||
})
|
||||
|
||||
it('does NOT floor an explicit (small) operator override', () => {
|
||||
const config = ValidationConfig.getInstance({ maxQueryLimit: 500 })
|
||||
expect(config.limitBasis).toBe('override')
|
||||
expect(config.maxLimit).toBe(500) // explicit intent respected, not floored
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue