Skip to content

Commit

Permalink
statedb: Avoid cloning of txn in Get()/GetWatch()
Browse files Browse the repository at this point in the history
If a table is queried with a WriteTxn and the table is being modified, then
in the general case we need to use a clone of the (part) transaction as the
future modifications must not affect the objects returned by the iterator.

However, this is not the case for Get()/GetWatch() and there we can avoid the
clone since no iterator is returned to the caller.

Signed-off-by: Jussi Maki <[email protected]>
  • Loading branch information
joamaki committed Aug 16, 2024
1 parent ff3cf86 commit 18a6dfc
Showing 1 changed file with 25 additions and 4 deletions.
29 changes: 25 additions & 4 deletions table.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,11 +215,32 @@ func (t *genTable[Obj]) Get(txn ReadTxn, q Query[Obj]) (obj Obj, revision uint64
}

func (t *genTable[Obj]) GetWatch(txn ReadTxn, q Query[Obj]) (obj Obj, revision uint64, watch <-chan struct{}, ok bool) {
indexTxn := txn.getTxn().mustIndexReadTxn(t, t.indexPos(q.index))
// Since we're not returning an iterator here we can optimize and not use
// indexReadTxn which clones if this is a WriteTxn (to avoid invalidating iterators).
indexPos := t.indexPos(q.index)
itxn := txn.getTxn()
var (
ops part.Ops[object]
unique bool
)
if itxn.modifiedTables != nil && itxn.modifiedTables[t.tablePos()] != nil {
var err error
iwtxn, err := itxn.indexWriteTxn(t, indexPos)
if err != nil {
panic(err)
}
ops = iwtxn.Txn
unique = iwtxn.unique
} else {
entry := itxn.root[t.tablePos()].indexes[indexPos]
ops = entry.tree
unique = entry.unique
}

var iobj object
if indexTxn.unique {
if unique {
// On a unique index we can do a direct get rather than a prefix search.
iobj, watch, ok = indexTxn.Get(q.key)
iobj, watch, ok = ops.Get(q.key)
if !ok {
return
}
Expand All @@ -229,7 +250,7 @@ func (t *genTable[Obj]) GetWatch(txn ReadTxn, q Query[Obj]) (obj Obj, revision u
}

// For a non-unique index we need to do a prefix search.
iter, watch := indexTxn.Prefix(q.key)
iter, watch := ops.Prefix(q.key)
for {
var key []byte
key, iobj, ok = iter.Next()
Expand Down

0 comments on commit 18a6dfc

Please sign in to comment.