github.com/cilium/statedb@v0.3.2/any_table.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package statedb 5 6 import ( 7 "fmt" 8 "iter" 9 ) 10 11 // AnyTable allows any-typed access to a StateDB table. This is intended 12 // for building generic tooling for accessing the table and should be 13 // avoided if possible. 14 type AnyTable struct { 15 Meta TableMeta 16 } 17 18 func (t AnyTable) All(txn ReadTxn) iter.Seq2[any, Revision] { 19 all, _ := t.AllWatch(txn) 20 return all 21 } 22 23 func (t AnyTable) AllWatch(txn ReadTxn) (iter.Seq2[any, Revision], <-chan struct{}) { 24 indexTxn := txn.getTxn().mustIndexReadTxn(t.Meta, PrimaryIndexPos) 25 return partSeq[any](indexTxn.Iterator()), indexTxn.RootWatch() 26 } 27 28 func (t AnyTable) UnmarshalYAML(data []byte) (any, error) { 29 return t.Meta.unmarshalYAML(data) 30 } 31 32 func (t AnyTable) Insert(txn WriteTxn, obj any) (old any, hadOld bool, err error) { 33 var iobj object 34 iobj, hadOld, err = txn.getTxn().insert(t.Meta, Revision(0), obj) 35 if hadOld { 36 old = iobj.data 37 } 38 return 39 } 40 41 func (t AnyTable) Delete(txn WriteTxn, obj any) (old any, hadOld bool, err error) { 42 var iobj object 43 iobj, hadOld, err = txn.getTxn().delete(t.Meta, Revision(0), obj) 44 if hadOld { 45 old = iobj.data 46 } 47 return 48 } 49 50 func (t AnyTable) Get(txn ReadTxn, index string, key string) (any, Revision, bool, error) { 51 itxn, rawKey, err := t.queryIndex(txn, index, key) 52 if err != nil { 53 return nil, 0, false, err 54 } 55 if itxn.unique { 56 obj, _, ok := itxn.Get(rawKey) 57 return obj.data, obj.revision, ok, nil 58 } 59 // For non-unique indexes we need to prefix search and make sure to fully 60 // match the secondary key. 61 iter, _ := itxn.Prefix(rawKey) 62 for { 63 k, obj, ok := iter.Next() 64 if !ok { 65 break 66 } 67 secondary, _ := decodeNonUniqueKey(k) 68 if len(secondary) == len(rawKey) { 69 return obj.data, obj.revision, true, nil 70 } 71 } 72 return nil, 0, false, nil 73 } 74 75 func (t AnyTable) Prefix(txn ReadTxn, index string, key string) (iter.Seq2[any, Revision], error) { 76 itxn, rawKey, err := t.queryIndex(txn, index, key) 77 if err != nil { 78 return nil, err 79 } 80 iter, _ := itxn.Prefix(rawKey) 81 if itxn.unique { 82 return partSeq[any](iter), nil 83 } 84 return nonUniqueSeq[any](iter, true, rawKey), nil 85 } 86 87 func (t AnyTable) LowerBound(txn ReadTxn, index string, key string) (iter.Seq2[any, Revision], error) { 88 itxn, rawKey, err := t.queryIndex(txn, index, key) 89 if err != nil { 90 return nil, err 91 } 92 iter := itxn.LowerBound(rawKey) 93 if itxn.unique { 94 return partSeq[any](iter), nil 95 } 96 return nonUniqueLowerBoundSeq[any](iter, rawKey), nil 97 } 98 99 func (t AnyTable) List(txn ReadTxn, index string, key string) (iter.Seq2[any, Revision], error) { 100 itxn, rawKey, err := t.queryIndex(txn, index, key) 101 if err != nil { 102 return nil, err 103 } 104 iter, _ := itxn.Prefix(rawKey) 105 if itxn.unique { 106 // Unique index means that there can be only a single matching object. 107 // Doing a Get() is more efficient than constructing an iterator. 108 value, _, ok := itxn.Get(rawKey) 109 return func(yield func(any, Revision) bool) { 110 if ok { 111 yield(value.data, value.revision) 112 } 113 }, nil 114 } 115 return nonUniqueSeq[any](iter, false, rawKey), nil 116 } 117 118 func (t AnyTable) queryIndex(txn ReadTxn, index string, key string) (indexReadTxn, []byte, error) { 119 indexer := t.Meta.getIndexer(index) 120 if indexer == nil { 121 return indexReadTxn{}, nil, fmt.Errorf("invalid index %q", index) 122 } 123 rawKey, err := indexer.fromString(key) 124 if err != nil { 125 return indexReadTxn{}, nil, err 126 } 127 itxn, err := txn.getTxn().indexReadTxn(t.Meta, indexer.pos) 128 return itxn, rawKey, err 129 } 130 131 func (t AnyTable) Changes(txn WriteTxn) (anyChangeIterator, error) { 132 return t.Meta.anyChanges(txn) 133 } 134 135 func (t AnyTable) TableHeader() []string { 136 zero := t.Meta.proto() 137 if tw, ok := zero.(TableWritable); ok { 138 return tw.TableHeader() 139 } 140 return nil 141 } 142 143 func (t AnyTable) Proto() any { 144 return t.Meta.proto() 145 }