Skip to content

Commit 591cec8

Browse files
committed
statedb: Fix regression in Modify()
The change to not call merge() if the object did not exist was broken as merge() wasn't called for the object inserted into secondary indexes. Fix the issue by returning the merged new object from tableIndexTxn.modify and inserting that into the secondary indexes. Signed-off-by: Jussi Maki <jussi.maki@isovalent.com>
1 parent d890fff commit 591cec8

File tree

8 files changed

+23
-19
lines changed

8 files changed

+23
-19
lines changed

lpm_index.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ func (l *lpmIndexTxn) insert(key index.Key, obj object) (old object, hadOld bool
312312
}
313313

314314
// modify implements tableIndexTxn.
315-
func (l *lpmIndexTxn) modify(key index.Key, obj object, mod func(old, new object) object) (old object, hadOld bool, watch <-chan struct{}) {
315+
func (l *lpmIndexTxn) modify(key index.Key, obj object, mod func(old, new object) object) (old object, newObj object, hadOld bool, watch <-chan struct{}) {
316316
panic("LPM index cannot be the primary index")
317317
}
318318

part/part_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,7 @@ func Test_modify(t *testing.T) {
672672

673673
txn := tree.Txn()
674674
for i := range 1000 {
675-
old, hadOld := txn.Modify(key, 123, func(x, _ int) int { return x + 1 })
675+
old, _, hadOld := txn.Modify(key, 123, func(x, _ int) int { return x + 1 })
676676
require.True(t, hadOld)
677677
require.Equal(t, i+1, old)
678678
}

part/tree.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ func (t *Tree[T]) Insert(key []byte, value T) (old T, hadOld bool, tree Tree[T])
127127
// Returns the old value if it exists.
128128
func (t *Tree[T]) Modify(key []byte, value T, mod func(T, T) T) (old T, hadOld bool, tree Tree[T]) {
129129
txn := t.Txn()
130-
old, hadOld = txn.Modify(key, value, mod)
130+
old, _, hadOld = txn.Modify(key, value, mod)
131131
tree = txn.CommitAndNotify()
132132
return
133133
}

part/txn.go

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ func (txn *Txn[T]) Insert(key []byte, value T) (old T, hadOld bool) {
8080
// Returns the old value if it exists and a watch channel that closes when the
8181
// key changes again.
8282
func (txn *Txn[T]) InsertWatch(key []byte, value T) (old T, hadOld bool, watch <-chan struct{}) {
83-
old, hadOld, watch, txn.root = txn.insert(txn.root, key, value)
83+
old, _, hadOld, watch, txn.root = txn.insert(txn.root, key, value)
8484
validateTree(txn.root, nil, txn.watches, txn.txnID)
8585
if !hadOld {
8686
txn.size++
@@ -93,19 +93,19 @@ func (txn *Txn[T]) InsertWatch(key []byte, value T) (old T, hadOld bool, watch <
9393

9494
// Modify a value in the tree. It is up to the
9595
// caller to not mutate the value in-place and to return a clone.
96-
// Returns the old value if it exists.
97-
func (txn *Txn[T]) Modify(key []byte, value T, mod func(T, T) T) (old T, hadOld bool) {
98-
old, hadOld, _ = txn.ModifyWatch(key, value, mod)
96+
// Returns the old value (if it exists) and the new possibly merged value.
97+
func (txn *Txn[T]) Modify(key []byte, value T, mod func(T, T) T) (old T, newValue T, hadOld bool) {
98+
old, newValue, hadOld, _ = txn.ModifyWatch(key, value, mod)
9999
return
100100
}
101101

102102
// Modify a value in the tree. If the key does not exist the modify
103103
// function is called with the zero value for T. It is up to the
104104
// caller to not mutate the value in-place and to return a clone.
105-
// Returns the old value if it exists and a watch channel that closes
106-
// when the key changes again.
107-
func (txn *Txn[T]) ModifyWatch(key []byte, value T, mod func(T, T) T) (old T, hadOld bool, watch <-chan struct{}) {
108-
old, hadOld, watch, txn.root = txn.modify(txn.root, key, value, mod)
105+
// Returns the old value (if it exists) and the new possibly merged value,
106+
// and a watch channel that closes when the key changes again.
107+
func (txn *Txn[T]) ModifyWatch(key []byte, value T, mod func(T, T) T) (old T, newValue T, hadOld bool, watch <-chan struct{}) {
108+
old, newValue, hadOld, watch, txn.root = txn.modify(txn.root, key, value, mod)
109109
validateTree(txn.root, nil, txn.watches, txn.txnID)
110110
if !hadOld {
111111
txn.size++
@@ -243,17 +243,18 @@ func (txn *Txn[T]) cloneNode(n *header[T]) *header[T] {
243243
return n
244244
}
245245

246-
func (txn *Txn[T]) insert(root *header[T], key []byte, value T) (oldValue T, hadOld bool, watch <-chan struct{}, newRoot *header[T]) {
246+
func (txn *Txn[T]) insert(root *header[T], key []byte, value T) (oldValue T, newValue T, hadOld bool, watch <-chan struct{}, newRoot *header[T]) {
247247
return txn.modify(root, key, value, nil)
248248
}
249249

250-
func (txn *Txn[T]) modify(root *header[T], key []byte, newValue T, mod func(T, T) T) (oldValue T, hadOld bool, watch <-chan struct{}, newRoot *header[T]) {
250+
func (txn *Txn[T]) modify(root *header[T], key []byte, newValue T, mod func(T, T) T) (oldValue T, newValueOut T, hadOld bool, watch <-chan struct{}, newRoot *header[T]) {
251251
txn.dirty = true
252252
fullKey := key
253+
newValueOut = newValue
253254

254255
if root == nil {
255256
leaf := newLeaf(txn.opts, key, fullKey, newValue)
256-
return oldValue, false, leaf.watch, leaf.self()
257+
return oldValue, newValueOut, false, leaf.watch, leaf.self()
257258
}
258259

259260
// Start recursing from the root to find the insertion point.
@@ -323,7 +324,8 @@ func (txn *Txn[T]) modify(root *header[T], key []byte, newValue T, mod func(T, T
323324
}
324325
watch = leaf.watch
325326
if mod != nil {
326-
leaf.value = mod(oldValue, newValue)
327+
newValueOut = mod(oldValue, newValue)
328+
leaf.value = newValueOut
327329
} else {
328330
leaf.value = newValue
329331
}

part_index.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ func (r *partIndexTxn) len() int {
321321
}
322322

323323
// modify implements tableIndexTxn.
324-
func (r *partIndexTxn) modify(key index.Key, obj object, mod func(old, new object) object) (old object, hadOld bool, watch <-chan struct{}) {
324+
func (r *partIndexTxn) modify(key index.Key, obj object, mod func(old, new object) object) (old object, newObj object, hadOld bool, watch <-chan struct{}) {
325325
return r.tx.ModifyWatch(key, obj, mod)
326326
}
327327

table.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,7 @@ func (t *genTable[Obj]) InsertWatch(txn WriteTxn, obj Obj) (oldObj Obj, hadOld b
486486

487487
func (t *genTable[Obj]) Modify(txn WriteTxn, obj Obj, merge func(old, new Obj) Obj) (oldObj Obj, hadOld bool, err error) {
488488
mergeObjects := func(old object, new object) object {
489-
new.data = merge(old.data.(Obj), obj)
489+
new.data = merge(old.data.(Obj), new.data.(Obj))
490490
return new
491491
}
492492
var old object

types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ type tableIndexTxn interface {
414414
tableIndex
415415

416416
insert(key index.Key, obj object) (old object, hadOld bool, watch <-chan struct{})
417-
modify(key index.Key, obj object, mod func(old, new object) object) (old object, hadOld bool, watch <-chan struct{})
417+
modify(key index.Key, obj object, mod func(old, new object) object) (old object, new object, hadOld bool, watch <-chan struct{})
418418
delete(key index.Key) (old object, hadOld bool)
419419
reindex(primaryKey index.Key, old object, new object)
420420
}

write_txn.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,9 @@ func (txn *writeTxnState) modify(meta TableMeta, guardRevision Revision, newData
139139
if merge == nil {
140140
oldObj, oldExists, watch = idIndexTxn.insert(idKey, obj)
141141
} else {
142-
oldObj, oldExists, watch = idIndexTxn.modify(idKey, obj, merge)
142+
// Insert the object into the primary index. This returns the merged new
143+
// object which we'll then insert into the secondary indexes.
144+
oldObj, obj, oldExists, watch = idIndexTxn.modify(idKey, obj, merge)
143145
}
144146

145147
// Sanity check: is the same object being inserted back and thus the

0 commit comments

Comments
 (0)