Skip to content

Commit 8e90274

Browse files
[FSSDK-11159] lru cache impl update (#391)
1 parent dd69bea commit 8e90274

File tree

2 files changed

+120
-0
lines changed

2 files changed

+120
-0
lines changed

OptimizelySDK.Tests/OdpTests/LruCacheTest.cs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,5 +208,113 @@ public void ShouldHandleWhenCacheIsReset()
208208

209209
Assert.AreEqual(0, cache.CurrentCacheKeysForTesting().Length);
210210
}
211+
212+
[Test]
213+
public void ShouldHandleRemoveNonExistentKey()
214+
{
215+
var cache = new LruCache<List<string>>();
216+
cache.Save("user1", _segments1And2);
217+
cache.Save("user2", _segments3And4);
218+
219+
// Remove a key that doesn't exist
220+
cache.Remove("user3");
221+
222+
// Existing keys should still be there
223+
Assert.AreEqual(_segments1And2, cache.Lookup("user1"));
224+
Assert.AreEqual(_segments3And4, cache.Lookup("user2"));
225+
}
226+
227+
[Test]
228+
public void ShouldHandleRemoveExistingKey()
229+
{
230+
var cache = new LruCache<List<string>>();
231+
232+
cache.Save("user1", _segments1And2);
233+
cache.Save("user2", _segments3And4);
234+
cache.Save("user3", _segments5And6);
235+
236+
Assert.AreEqual(_segments1And2, cache.Lookup("user1"));
237+
Assert.AreEqual(_segments3And4, cache.Lookup("user2"));
238+
Assert.AreEqual(_segments5And6, cache.Lookup("user3"));
239+
240+
cache.Remove("user2");
241+
242+
Assert.AreEqual(_segments1And2, cache.Lookup("user1"));
243+
Assert.IsNull(cache.Lookup("user2"));
244+
Assert.AreEqual(_segments5And6, cache.Lookup("user3"));
245+
}
246+
247+
[Test]
248+
public void ShouldHandleRemoveFromZeroSizedCache()
249+
{
250+
var cache = new LruCache<List<string>>(0);
251+
252+
cache.Save("user1", _segments1And2);
253+
cache.Remove("user1");
254+
255+
Assert.IsNull(cache.Lookup("user1"));
256+
Assert.AreEqual(0, cache.CurrentCacheKeysForTesting().Length);
257+
}
258+
259+
[Test]
260+
public void ShouldHandleRemoveAndAddBack()
261+
{
262+
var cache = new LruCache<List<string>>();
263+
264+
cache.Save("user1", _segments1And2);
265+
cache.Save("user2", _segments3And4);
266+
cache.Save("user3", _segments5And6);
267+
268+
// Remove user2 and add it back with different data
269+
cache.Remove("user2");
270+
cache.Save("user2", _segments1And2);
271+
272+
Assert.AreEqual(_segments1And2, cache.Lookup("user1"));
273+
Assert.AreEqual(_segments1And2, cache.Lookup("user2"));
274+
Assert.AreEqual(_segments5And6, cache.Lookup("user3"));
275+
276+
Assert.AreEqual(3, cache.CurrentCacheKeysForTesting().Length);
277+
}
278+
279+
[Test]
280+
public void ShouldHandleThreadSafetyWithRemove()
281+
{
282+
var cache = new LruCache<string>(100);
283+
284+
for (int i = 1; i <= 100; i++)
285+
{
286+
cache.Save($"key{i}", $"value{i}");
287+
}
288+
289+
var threads = new List<Thread>();
290+
291+
for (int i = 1; i <= 50; i++)
292+
{
293+
int localI = i; // Capture variable for closure
294+
var thread = new Thread(() => cache.Remove($"key{localI}"));
295+
threads.Add(thread);
296+
thread.Start();
297+
}
298+
299+
// Wait for all threads to complete
300+
foreach (var thread in threads)
301+
{
302+
thread.Join();
303+
}
304+
305+
for (int i = 1; i <= 100; i++)
306+
{
307+
if (i <= 50)
308+
{
309+
Assert.IsNull(cache.Lookup($"key{i}"), $"key{i} should be removed");
310+
}
311+
else
312+
{
313+
Assert.AreEqual($"value{i}", cache.Lookup($"key{i}"), $"key{i} should still exist");
314+
}
315+
}
316+
317+
Assert.AreEqual(50, cache.CurrentCacheKeysForTesting().Length);
318+
}
211319
}
212320
}

OptimizelySDK/Odp/LruCache.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,18 @@ public void Reset()
165165
}
166166
}
167167

168+
/// <summary>
169+
/// Remove the element associated with the provided key from the cache
170+
/// </summary>
171+
/// <param name="key">Key of element to remove from the cache</param>
172+
public void Remove(string key)
173+
{
174+
lock (_mutex)
175+
{
176+
_cache.Remove(key);
177+
}
178+
}
179+
168180
/// <summary>
169181
/// Wrapping class around a generic value stored in the cache
170182
/// </summary>

0 commit comments

Comments
 (0)