From c324e6f2122dcbc583a14231e2d61b739dea403a Mon Sep 17 00:00:00 2001 From: Mike Jensen Date: Sun, 1 Dec 2024 21:45:12 -0700 Subject: [PATCH] Add `DeleteAll` function to clear the map --- ffmap/csv_map.go | 8 ++++++++ ffmap/csv_map_test.go | 22 +++++++++++++++++++++- ffmap/file_map.go | 7 +++++++ ffmap/file_map_test.go | 16 ++++++++++++++++ 4 files changed, 52 insertions(+), 1 deletion(-) diff --git a/ffmap/csv_map.go b/ffmap/csv_map.go index dd3e182..665306f 100644 --- a/ffmap/csv_map.go +++ b/ffmap/csv_map.go @@ -358,6 +358,14 @@ func (kv *KeyValueCSV) Delete(key string) { delete(kv.data, key) } +func (kv *KeyValueCSV) DeleteAll() { + kv.rwLock.Lock() + defer kv.rwLock.Unlock() + + kv.modCount++ + kv.data = make(map[string]dataItem) +} + // lockedRead will acquire a read lock before loading the value, use this function whenever you don't // already hold a lock. Using this ensures that the read lock is promptly released. func (kv *KeyValueCSV) lockedRead(key string) (dataItem, bool) { diff --git a/ffmap/csv_map_test.go b/ffmap/csv_map_test.go index 8741737..84adcdb 100644 --- a/ffmap/csv_map_test.go +++ b/ffmap/csv_map_test.go @@ -1037,8 +1037,28 @@ func TestDelete(t *testing.T) { m.Delete(key) + verifyEmpty(t, m, key) +} + +func TestDeleteAll(t *testing.T) { + t.Parallel() + tmpFile, m := makeTestMap(t) + defer os.Remove(tmpFile) + + key := "key" + require.NoError(t, m.Set(key, "value")) + require.NoError(t, m.Set("foo"+key, "value")) + + m.DeleteAll() + + verifyEmpty(t, m, key) +} + +func verifyEmpty(t *testing.T, m *KeyValueCSV, oldKey string) { + t.Helper() + var result string - found, err := m.Get(key, &result) + found, err := m.Get(oldKey, &result) require.NoError(t, err) assert.False(t, found) assert.Equal(t, 0, m.Size()) diff --git a/ffmap/file_map.go b/ffmap/file_map.go index dbe0951..95d12be 100644 --- a/ffmap/file_map.go +++ b/ffmap/file_map.go @@ -37,6 +37,8 @@ type MutableFFMap interface { Set(key string, value interface{}) error // Delete will remove the key from the map (if present). Delete(key string) + // DeleteAll will clear or delete all entries from the map. + DeleteAll() // Commit will update the disk representation to match the in-memory state. If this is not invoked the disk will // never be updated. This must not be called concurrently, and may be slow as the file format is optimized. Commit() error @@ -86,6 +88,11 @@ func (tfm *TypedFFMap[T]) Delete(key string) { tfm.ffm.Delete(key) } +// DeleteAll will clear or delete all entries from the map. +func (tfm *TypedFFMap[T]) DeleteAll() { + tfm.ffm.DeleteAll() +} + // Commit will update the disk representation to match the in-memory state. If this is not invoked the disk will // never be updated. This must not be called concurrently, and may be slow as the file format is optimized. func (tfm *TypedFFMap[T]) Commit() error { diff --git a/ffmap/file_map_test.go b/ffmap/file_map_test.go index 74f03b8..f9ae123 100644 --- a/ffmap/file_map_test.go +++ b/ffmap/file_map_test.go @@ -60,6 +60,10 @@ func (m *memoryFFMap) Delete(key string) { delete(m.data, key) } +func (m *memoryFFMap) DeleteAll() { + m.data = make(map[string]interface{}) +} + func (m *memoryFFMap) Commit() error { return nil } @@ -132,6 +136,18 @@ func TestTypedFFMap(t *testing.T) { require.NoError(t, err) tfm.Delete(key) + assert.False(t, tfm.ContainsKey(key)) + assert.Equal(t, 0, tfm.Size()) + }) + t.Run("DeleteAll", func(t *testing.T) { + t.Parallel() + tfm := NewTypedFFMap[string](newMemoryFFMap()) + + key := "key" + require.NoError(t, tfm.Set(key, "value")) + require.NoError(t, tfm.Set("foo"+key, "value")) + tfm.DeleteAll() + assert.False(t, tfm.ContainsKey(key)) assert.Equal(t, 0, tfm.Size()) })