v1.1.0 - Cache Layer Overhaul
v1.1.0 — Cache Layer Overhaul
Overview
This release is a full architectural redesign of the data synchronization layer (RedisDataContainer). The previous implementation had an ambiguous cache hierarchy, race conditions, and potential data loss paths. All known issues have been addressed.
What's New
Redis-Master Cache Hierarchy
Redis is now the single source of truth across all layers. No external process can override Redis data. Priority order is strictly enforced: Redis → L1 Cache → MongoDB.
Redis Evict / TTL Recovery
If a key is evicted from Redis or expires via TTL, the L1 Sync task automatically restores it from L1 and marks it dirty so the flush task re-persists it to MongoDB. Previously, evicted keys were silently skipped.
Batch Reconciliation
The reconciliation task now processes entries in batches of 50 concurrent MongoDB requests. Previously, all entries were queried simultaneously — on datasets of 1000+ entries this caused uncontrolled request spikes against MongoDB.
O(1) ID Lookup
getDataModelFromId() previously performed a full linear scan (O(n)) over the entire in-memory map. A reverse index (id → key) has been added, making lookups instant regardless of dataset size.
Bug Fixes
- Data loss on flush failure —
dirtyKeys.remove()was called before confirming the MongoDB write. If the write failed, the dirty flag was already gone and the entry would never be retried. Fixed: flag is removed only after.get()confirms success. - TOCTOU race in
removeModel()—containsKey()followed byremove()is not atomic; another thread could delete the entry between the two calls. Fixed: directremove()with return value check. - Deadlock risk in reconciliation —
processTaskwas being called from inside an already-runningprocessTaskviathenAccept. Fixed: all reconciliation logic runs within a single task context. addModelFix()leaving Redis empty — the method wrote only to L1, leaving Redis without the key. The next L1 Sync would detect the missing key and trigger a redundant restore cycle. Fixed: both L1 and Redis are written together viawriteToL1AndRedis().
Internal Changes
idToDataListrenamed tokeyToModelfor clarityupdateInternal()renamed towriteToL1AndRedis()to reflect exact behaviourSystem.out.printlnreplaced withjava.util.logging.Loggerthroughout- Sync intervals adjusted: L1 Sync
10s, Auto Flush15s, Reconciliation3min
Upgrade Notes
This release is a drop-in replacement. Public API method signatures are unchanged.
addModelFix() behaviour has changed slightly — it now also writes to Redis immediately, which is the correct behaviour and should not affect existing call sites.