@@ -21,6 +21,8 @@ import (
21
21
"time"
22
22
)
23
23
24
+ type updateFn [V any ] func (cur , prev V ) bool
25
+
24
26
// TODO: Do we need this to be a separate struct from Item?
25
27
type storeItem [V any ] struct {
26
28
key uint64
@@ -53,6 +55,7 @@ type store[V any] interface {
53
55
Cleanup (policy * defaultPolicy [V ], onEvict func (item * Item [V ]))
54
56
// Clear clears all contents of the store.
55
57
Clear (onEvict func (item * Item [V ]))
58
+ SetShouldUpdateFn (f updateFn [V ])
56
59
}
57
60
58
61
// newStore returns the default store implementation.
@@ -78,6 +81,12 @@ func newShardedMap[V any]() *shardedMap[V] {
78
81
return sm
79
82
}
80
83
84
+ func (m * shardedMap [V ]) SetShouldUpdateFn (f updateFn [V ]) {
85
+ for i := range m .shards {
86
+ m .shards [i ].setShouldUpdateFn (f )
87
+ }
88
+ }
89
+
81
90
func (sm * shardedMap [V ]) Get (key , conflict uint64 ) (V , bool ) {
82
91
return sm .shards [key % numShards ].get (key , conflict )
83
92
}
@@ -116,17 +125,25 @@ func (sm *shardedMap[V]) Clear(onEvict func(item *Item[V])) {
116
125
117
126
type lockedMap [V any ] struct {
118
127
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 ]
121
131
}
122
132
123
133
func newLockedMap [V any ](em * expirationMap [V ]) * lockedMap [V ] {
124
134
return & lockedMap [V ]{
125
135
data : make (map [uint64 ]storeItem [V ]),
126
136
em : em ,
137
+ shouldUpdate : func (cur , prev V ) bool {
138
+ return true
139
+ },
127
140
}
128
141
}
129
142
143
+ func (m * lockedMap [V ]) setShouldUpdateFn (f updateFn [V ]) {
144
+ m .shouldUpdate = f
145
+ }
146
+
130
147
func (m * lockedMap [V ]) get (key , conflict uint64 ) (V , bool ) {
131
148
m .RLock ()
132
149
item , ok := m .data [key ]
@@ -167,6 +184,9 @@ func (m *lockedMap[V]) Set(i *Item[V]) {
167
184
if i .Conflict != 0 && (i .Conflict != item .conflict ) {
168
185
return
169
186
}
187
+ if m .shouldUpdate != nil && ! m .shouldUpdate (i .Value , item .value ) {
188
+ return
189
+ }
170
190
m .em .update (i .Key , i .Conflict , item .expiration , i .Expiration )
171
191
} else {
172
192
// 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) {
211
231
if newItem .Conflict != 0 && (newItem .Conflict != item .conflict ) {
212
232
return zeroValue [V ](), false
213
233
}
234
+ if m .shouldUpdate != nil && ! m .shouldUpdate (newItem .Value , item .value ) {
235
+ return item .value , false
236
+ }
214
237
215
238
m .em .update (newItem .Key , newItem .Conflict , item .expiration , newItem .Expiration )
216
239
m .data [newItem .Key ] = storeItem [V ]{
0 commit comments