@@ -21,6 +21,8 @@ import (
2121 "time"
2222)
2323
24+ type updateFn [V any ] func (cur , prev V ) bool
25+
2426// TODO: Do we need this to be a separate struct from Item?
2527type storeItem [V any ] struct {
2628 key uint64
@@ -53,6 +55,7 @@ type store[V any] interface {
5355 Cleanup (policy * defaultPolicy [V ], onEvict func (item * Item [V ]))
5456 // Clear clears all contents of the store.
5557 Clear (onEvict func (item * Item [V ]))
58+ SetShouldUpdateFn (f updateFn [V ])
5659}
5760
5861// newStore returns the default store implementation.
@@ -78,6 +81,12 @@ func newShardedMap[V any]() *shardedMap[V] {
7881 return sm
7982}
8083
84+ func (m * shardedMap [V ]) SetShouldUpdateFn (f updateFn [V ]) {
85+ for i := range m .shards {
86+ m .shards [i ].setShouldUpdateFn (f )
87+ }
88+ }
89+
8190func (sm * shardedMap [V ]) Get (key , conflict uint64 ) (V , bool ) {
8291 return sm .shards [key % numShards ].get (key , conflict )
8392}
@@ -116,17 +125,25 @@ func (sm *shardedMap[V]) Clear(onEvict func(item *Item[V])) {
116125
117126type lockedMap [V any ] struct {
118127 sync.RWMutex
119- data map [uint64 ]storeItem [V ]
120- em * expirationMap [V ]
128+ data map [uint64 ]storeItem [V ]
129+ em * expirationMap [V ]
130+ shouldUpdate updateFn [V ]
121131}
122132
123133func newLockedMap [V any ](em * expirationMap [V ]) * lockedMap [V ] {
124134 return & lockedMap [V ]{
125135 data : make (map [uint64 ]storeItem [V ]),
126136 em : em ,
137+ shouldUpdate : func (cur , prev V ) bool {
138+ return true
139+ },
127140 }
128141}
129142
143+ func (m * lockedMap [V ]) setShouldUpdateFn (f updateFn [V ]) {
144+ m .shouldUpdate = f
145+ }
146+
130147func (m * lockedMap [V ]) get (key , conflict uint64 ) (V , bool ) {
131148 m .RLock ()
132149 item , ok := m .data [key ]
@@ -167,6 +184,9 @@ func (m *lockedMap[V]) Set(i *Item[V]) {
167184 if i .Conflict != 0 && (i .Conflict != item .conflict ) {
168185 return
169186 }
187+ if m .shouldUpdate != nil && ! m .shouldUpdate (i .Value , item .value ) {
188+ return
189+ }
170190 m .em .update (i .Key , i .Conflict , item .expiration , i .Expiration )
171191 } else {
172192 // The value is not in the map already. There's no need to return anything.
@@ -211,6 +231,9 @@ func (m *lockedMap[V]) Update(newItem *Item[V]) (V, bool) {
211231 if newItem .Conflict != 0 && (newItem .Conflict != item .conflict ) {
212232 return zeroValue [V ](), false
213233 }
234+ if m .shouldUpdate != nil && ! m .shouldUpdate (newItem .Value , item .value ) {
235+ return item .value , false
236+ }
214237
215238 m .em .update (newItem .Key , newItem .Conflict , item .expiration , newItem .Expiration )
216239 m .data [newItem .Key ] = storeItem [V ]{
0 commit comments