github.com/cilium/statedb@v0.3.2/deletetracker.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package statedb
     5  
     6  import (
     7  	"sync/atomic"
     8  
     9  	"github.com/cilium/statedb/index"
    10  )
    11  
    12  type deleteTracker[Obj any] struct {
    13  	db          *DB
    14  	trackerName string
    15  	table       Table[Obj]
    16  
    17  	// revision is the last observed revision. Starts out at zero
    18  	// in which case the garbage collector will not care about this
    19  	// tracker when considering which objects to delete.
    20  	revision atomic.Uint64
    21  }
    22  
    23  // setRevision is called to set the starting low watermark when
    24  // this deletion tracker is inserted into the table.
    25  func (dt *deleteTracker[Obj]) setRevision(rev uint64) {
    26  	dt.revision.Store(rev)
    27  }
    28  
    29  // getRevision is called by the graveyard garbage collector to
    30  // compute the global low watermark.
    31  func (dt *deleteTracker[Obj]) getRevision() uint64 {
    32  	return dt.revision.Load()
    33  }
    34  
    35  // Deleted returns an iterator for deleted objects in this table starting from
    36  // 'minRevision'. The deleted objects are not garbage-collected unless 'Mark' is
    37  // called!
    38  func (dt *deleteTracker[Obj]) deleted(txn *txn, minRevision Revision) Iterator[Obj] {
    39  	indexEntry := txn.root[dt.table.tablePos()].indexes[GraveyardRevisionIndexPos]
    40  	indexTxn := indexReadTxn{indexEntry.tree, indexEntry.unique}
    41  	iter := indexTxn.LowerBound(index.Uint64(minRevision))
    42  	return &iterator[Obj]{iter}
    43  }
    44  
    45  // Mark the revision up to which deleted objects have been processed. This sets
    46  // the low watermark for deleted object garbage collection.
    47  func (dt *deleteTracker[Obj]) mark(upTo Revision) {
    48  	// Store the new low watermark and trigger a round of garbage collection.
    49  	dt.revision.Store(upTo)
    50  	select {
    51  	case dt.db.gcTrigger <- struct{}{}:
    52  	default:
    53  	}
    54  }
    55  
    56  func (dt *deleteTracker[Obj]) close() {
    57  	if dt.db == nil {
    58  		return
    59  	}
    60  
    61  	// Remove the delete tracker from the table.
    62  	txn := dt.db.WriteTxn(dt.table).getTxn()
    63  	dt.db = nil
    64  	db := txn.db
    65  	table := txn.modifiedTables[dt.table.tablePos()]
    66  	if table == nil {
    67  		panic("BUG: Table missing from write transaction")
    68  	}
    69  	_, _, table.deleteTrackers = table.deleteTrackers.Delete([]byte(dt.trackerName))
    70  	txn.Commit()
    71  
    72  	db.metrics.DeleteTrackerCount(dt.table.Name(), table.deleteTrackers.Len())
    73  
    74  	// Trigger garbage collection without this delete tracker to garbage
    75  	// collect any deleted objects that may not have been consumed.
    76  	select {
    77  	case db.gcTrigger <- struct{}{}:
    78  	default:
    79  	}
    80  
    81  }
    82  
    83  var closedWatchChannel = func() <-chan struct{} {
    84  	ch := make(chan struct{})
    85  	close(ch)
    86  	return ch
    87  }()