Skip to content

fix(ENGKNOW-3933): MAP/MULTIMAP cache key, single load per request and lower memory - #147

Draft
gmagnu wants to merge 1 commit into
mainfrom
ENGKNOW-3933-gor-map-cache-key-fix-and-memory-quick-wins
Draft

gmagnu wants to merge 1 commit into
mainfrom
ENGKNOW-3933-gor-map-cache-key-fix-and-memory-quick-wins

Conversation

@gmagnu

@gmagnu gmagnu commented Sep 30, 2026

Copy link
Copy Markdown
Contributor

Summary

Changes to MapAndListUtilities (the loaders behind MAP, MULTIMAP and INSET):

  1. Cache-key bug (correctness). The per-request cache key was built as "map"+filename+ic+oc.mkString(",")+asSet (and the same without asSet for multimap).
    • It left out caseInsensitive, so MAP -cis and a plain MAP of the same file in one request shared one cached map, and one of them returned wrong results.
    • It had no separator between ic and oc, so ic=1, oc=[23] and ic=12, oc=[3] collided.
    • The key is now delimited and includes every parameter.
  2. Single load per request. Concurrent pipelines of a request share the session cache (for example pgor partitions), and each one missed the cache and built its own full copy of the map. Loads now happen under a per-(request, key) lock that re-checks the cache after it is acquired. The lock entry is removed afterwards.
  3. Value dedup. Equal value strings share one instance while a map loads. MAP value columns repeat heavily. The pool is capped at 100k distinct values, so maps with mostly unique values don't pay for a large pool.
  4. MULTIMAP peak. Entries are moved into a presized output map instead of copied, so the ListBuffer map and the Array map are never both fully held.

Measurements

Heap retained after GC. Synthetic 1M-line files with values drawn from 50 distinct strings.

before after
Single map, 1M keys 160.8 MB 98.4 MB (−39%)
Multimap, 200k keys × 5 values, retained 90.4 MB 28.0 MB (−69%)
Multimap, peak during load 350.1 MB 305.9 MB (−13%)

Tests

  • New UTestMapAndListUtilities, 6 tests. All 6 fail on main and pass with this change:
    • -cis vs plain map and multimap caching
    • the ic/oc key collision
    • concurrent loads reading the file once: main read it 4,000 times with 4 threads instead of 1,000
    • value string sharing for map and multimap, with multimap value order kept
  • Existing map tests pass: UTestGorMapMultimap, UTestMapLookup, UTestMultiMapLookup, UTestGorPipeSession, UTestDAGMapAnalysis (42 tests, including the new ones).
  • :model:test passes: 1,548 tests, 17 skipped.

🤖 Generated with Claude Code

…d lower memory

- Cache key did not include caseInsensitive and had no separator between
  ic and oc, so MAP -cis and plain MAP of the same file shared one cached
  map, and ic=1,oc=[23] collided with ic=12,oc=[3]. Use a delimited key
  with all parameters.
- Concurrent pipelines of a request (e.g. pgor partitions) sharing the
  session cache each built their own copy of the same map. Load under a
  per request and key lock, re-checking the cache after acquiring it.
- Share repeated value strings while loading a map (bounded pool), map
  value columns repeat heavily.
- MULTIMAP: move entries into a presized output map instead of copying,
  so both maps are not fully held at the same time.

Measured heap retained after GC (1M line files, values from 50 distinct
strings): single map 160.8 MB -> 98.4 MB, multimap 90.4 MB -> 28.0 MB,
multimap peak during load 350.1 MB -> 305.9 MB.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Junit Tests - Summary

4 859 tests  +8   4 688 ✅ +9   20m 2s ⏱️ - 1m 10s
  506 suites +1     171 💤  - 1 
  506 files   +1       0 ❌ ±0 

Results for commit c9c1467. ± Comparison against base commit 9536c2f.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant