Round #221

07 May 2026, 15:01· csharp· meta/llama-3.3-70b-instruct· r12-real-contracts
Complexity
band 0
ZP / UO / OBS
1 / 5 / 2
Journey weight
560
Lightshift ΔL

Prompt

Add cache stampede protection using lazy loading and locks

Zero-point index (what the engine surfaced)

ZPI-ZPI-0014 | 2026-05-07T15:01:31Z Add cache stampede protection using lazy loading and locks ZERO POINT — 1 entries (structural invariants) ● hsl(145.55, 100%, 21%) IMemoryCache [contract] UNOBSERVED — 5 entries (implied truths) ○ hsl(27.69, 100%, 50%) async [feature] ○ hsl(199.38, 100%, 16%) Redis distributed cache [function] ○ hsl(188.31, 100%, 16%) Distributed cache (IDistributedCache) [function] ○ hsl(31.38, 100%, 40%) Scoped registration [function] ○ hsl(44.31, 100%, 25%) IOptions of T binding [function] OBSERVED — 2 entries (explicit in request) ◉ hsl(85.13, 100%, 36%) using [feature] ◉ hsl(234.87, 100%, 36%) using [feature] COMPLEXITY │ 8 entries │ spread: 207° │ band: LOW

Baseline response (no ZPI)

**Cache Stampede Protection using Lazy Loading and Locks in C#** Cache stampede is a phenomenon where multiple threads or requests try to retrieve a cache value simultaneously, resulting in a large number of requests to the underlying data source. To prevent this, we can implement cache stampede protection using lazy loading and locks. ### Implementation Here's an example implementation in C#: ```csharp using System; using System.Collections.Concurrent; using System.Threading; using System.Threading.Tasks; public class CacheStampedeProtection<T> { private readonly ConcurrentDictionary<string, Lazy<T>> _cache; private readonly ReaderWriterLockSlim _lock; public CacheStampedeProtection() { _cache = new ConcurrentDictionary<string, Lazy<T>>(); _lock = new ReaderWriterLockSlim(); } public T GetOrAdd(string key, Func<T> valueFactory) { // Try to get the value from the cache if (_cache.TryGetValue(key, out var lazyValue)) { // If the value is already in the cache, return it return lazyValue.Value; } // Acquire a write lock to prevent other threads from adding the value _lock.EnterWriteLock(); try { // Check again if the value is already in the cache if (_cache.TryGetValue(key, out lazyValue)) { // If the value is already in the cache, return it return lazyValue.Value; } // Create a new lazy value and add it to the cache lazyValue = new Lazy<T>(valueFactory, LazyThreadSafetyMode.ExecutionAndPublication); _cache.TryAdd(key, lazyValue); // Return the value return lazyValue.Value; } finally { // Release the write lock _lock.ExitWriteLock(); } } public void Remove(string key) { // Acquire a write lock to prevent other threads from accessing the cache _lock.EnterWriteLock(); try { // Remove the value from the cache _cache.TryRemove(key, out _); } finally { // Release the write lock _lock.ExitWriteLock(); } } } ``` ### Example Usage Here's an example usage of the `CacheStampedeProtection` class: ```csharp public class Program { public static void Main() { var cache = new CacheStampedeProtection<string>(); // Add a value to the cache var value = cache.GetOrAdd("key", () => { Console.WriteLine("Loading value from data source..."); return "Hello, World!"; }); Console.WriteLine(value); // Remove the value from the cache cache.Remove("key"); } } ``` ### Explanation The `CacheStampedeProtection` class uses a `ConcurrentDictionary` to store the cache values and a `ReaderWriterLockSlim` to synchronize access to the cache. The `GetOrAdd` method tries to retrieve the value from the cache. If the value is not in the cache, it acquires a write lock, checks again if the value is in the cache, and if not, creates a new lazy value and adds it to the cache. The `Remove` method acquires a write lock and removes the value from the cache. The `LazyThreadSafetyMode.ExecutionAndPublication` mode ensures that the value is only loaded once, even if multiple threads try to retrieve it simultaneously. This implementation provides cache stampede protection by preventing multiple threads from loading the same value simultaneously.

Enhanced response (with ZPI)

```csharp using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Options; using System; using System.Threading; using System.Threading.Tasks; public class CacheStampedeProtection { private readonly IDistributedCache _distributedCache; private readonly IMemoryCache _memoryCache; private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(); public CacheStampedeProtection(IDistributedCache distributedCache, IMemoryCache memoryCache) { _distributedCache = distributedCache; _memoryCache = memoryCache; } public async Task<string> GetOrAddAsync(string key, Func<Task<string>> factory, DistributedCacheEntryOptions options) { // Check if the value is already in the memory cache if (_memoryCache.TryGetValue(key, out string value)) { return value; } // Acquire a write lock to prevent concurrent execution of the factory _lock.EnterWriteLock(); try { // Re-check the memory cache after acquiring the lock if (_memoryCache.TryGetValue(key, out value)) { return value; } // Execute the factory and store the result in the memory cache value = await factory(); var cacheEntryOptions = new MemoryCacheEntryOptions().AddExpirationToken(new CancellationChangeToken(new CancellationTokenSource(options.AbsoluteExpirationRelativeToNow).Token)); _memoryCache.Set(key, value, cacheEntryOptions); // Store the result in the distributed cache await _distributedCache.SetStringAsync(key, value, options); } finally { _lock.ExitWriteLock(); } return value; } } public class CacheStampedeProtectionOptions { public TimeSpan AbsoluteExpirationRelativeToNow { get; set; } } public class CacheStampedeProtectionFactory { private readonly IOptions<CacheStampedeProtectionOptions> _options; public CacheStampedeProtectionFactory(IOptions<CacheStampedeProtectionOptions> options) { _options = options; } public CacheStampedeProtection Create(IDistributedCache distributedCache, IMemoryCache memoryCache) { return new CacheStampedeProtection(distributedCache, memoryCache); } } public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddDistributedMemoryCache(); services.AddMemoryCache(); services.Configure<CacheStampedeProtectionOptions>(options => { options.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1); }); services.AddSingleton<CacheStampedeProtectionFactory>(); services.AddSingleton<CacheStampedeProtection>(provider => { var factory = provider.GetService<CacheStampedeProtectionFactory>(); var distributedCache = provider.GetService<IDistributedCache>(); var memoryCache = provider.GetService<IMemoryCache>(); return factory.Create(distributedCache, memoryCache); }); } } ``` This implementation provides a `CacheStampedeProtection` class that uses lazy loading and locks to prevent cache stampede. The `GetOrAddAsync` method checks if the value is already in the memory cache, and if not, acquires a write lock to prevent concurrent execution of the factory. The factory is then executed, and the result is stored in both the memory cache and the distributed cache. The `CacheStampedeProtectionOptions` class is used to configure the absolute expiration time for the cache entries. The `CacheStampedeProtectionFactory` class is used to create instances of the `CacheStampedeProtection` class. In the `Startup` class, the `ConfigureServices` method is used to register the services and configure the options. The `AddDistributedMemoryCache` and `AddMemoryCache` methods are used to add the distributed memory cache and memory cache services, respectively. The `Configure` method is used to configure the `CacheStampedeProtectionOptions`. The `AddSingleton` method is used to register the `CacheStampedeProtectionFactory` and `CacheStampedeProtection` classes as singletons. This implementation provides a thread-safe and efficient way to prevent cache stampede using lazy loading and locks. The use of the `ReaderWriterLockSlim` class ensures that only one thread can execute the factory at a time, while allowing multiple threads to read the cache simultaneously. The use of the `IDistributedCache` and `IMemoryCache` interfaces ensures that the implementation is decoupled from the specific cache implementation.

Grader chain

Each grader reads the same baseline + enhanced pair and casts an independent verdict. Disagreement is the framework's own signal — not noise to be averaged away.

V1claude-haiku-4-5-20251001
Worse
V4qwen2.5-coder-7b-instruct
Better

Comments

Our grader said what it said. What do you say? Comment as a guest below.

No comments yet. Be the first to say what you make of this round.

← back to all rounds