diff --git a/deletetracker.go b/deletetracker.go index a2e6a03..dc664ba 100644 --- a/deletetracker.go +++ b/deletetracker.go @@ -4,6 +4,7 @@ package statedb import ( + "runtime" "sync/atomic" "github.com/cilium/statedb/index" @@ -53,8 +54,14 @@ func (dt *deleteTracker[Obj]) mark(upTo Revision) { } func (dt *deleteTracker[Obj]) close() { + if dt.db == nil { + return + } + runtime.SetFinalizer(dt, nil) + // Remove the delete tracker from the table. txn := dt.db.WriteTxn(dt.table).getTxn() + dt.db = nil db := txn.db table := txn.modifiedTables[dt.table.tablePos()] if table == nil { @@ -71,6 +78,7 @@ func (dt *deleteTracker[Obj]) close() { case db.gcTrigger <- struct{}{}: default: } + } var closedWatchChannel = func() <-chan struct{} { diff --git a/txn.go b/txn.go index 3645a4c..310a84a 100644 --- a/txn.go +++ b/txn.go @@ -244,8 +244,11 @@ func (txn *txn) addDeleteTracker(meta TableMeta, trackerName string, dt anyDelet table := txn.modifiedTables[meta.tablePos()] _, _, table.deleteTrackers = table.deleteTrackers.Insert([]byte(trackerName), dt) txn.db.metrics.DeleteTrackerCount(meta.Name(), table.deleteTrackers.Len()) - return nil + // Add a finalizer to make sure delete trackers are always closed. + runtime.SetFinalizer(dt, func(dt anyDeleteTracker) { dt.close() }) + + return nil } func (txn *txn) delete(meta TableMeta, guardRevision Revision, data any) (object, bool, error) { diff --git a/types.go b/types.go index 4c6f811..84d6d15 100644 --- a/types.go +++ b/types.go @@ -352,6 +352,7 @@ type anyIndexer struct { type anyDeleteTracker interface { setRevision(uint64) getRevision() uint64 + close() } type indexEntry struct {