go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/gae/impl/memory/memstore.go (about) 1 // Copyright 2015 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package memory 16 17 import ( 18 "bytes" 19 20 "github.com/luci/gtreap" 21 22 "go.chromium.org/luci/common/data/treapstore" 23 24 "go.chromium.org/luci/gae/service/datastore" 25 ) 26 27 type storeEntry struct { 28 key []byte 29 value []byte 30 } 31 32 // storeEntryCompare is a gtreap.Compare function for *storeEntry. 33 func storeEntryCompare(a, b any) int { 34 // TODO(dnj): Investigate optimizing this by removing the type assertions, 35 // either by explicitly tailoring gtreap / treapstore to use []byte or by 36 // optimizing via special-case interface. 37 return bytes.Compare(a.(*storeEntry).key, b.(*storeEntry).key) 38 } 39 40 func memStoreCollide(o, n memCollection, f func(k, ov, nv []byte)) { 41 var oldIter, newIter memIterator 42 if o != nil { 43 if !o.IsReadOnly() { 44 panic("old collection is r/w") 45 } 46 oldIter = o.Iterator(nil) 47 } else { 48 oldIter = nilIterator{} 49 } 50 51 if n != nil { 52 if !n.IsReadOnly() { 53 panic("new collection is r/w") 54 } 55 newIter = n.Iterator(nil) 56 } else { 57 newIter = nilIterator{} 58 } 59 60 l, r := oldIter.Next(), newIter.Next() 61 for { 62 switch { 63 case l == nil: 64 // No more "old" items, use up the rest of "new" and finish. 65 for r != nil { 66 f(r.key, nil, r.value) 67 r = newIter.Next() 68 } 69 return 70 71 case r == nil: 72 // No more "new" items, use up the rest of "old" and finish. 73 for l != nil { 74 f(l.key, l.value, nil) 75 l = oldIter.Next() 76 } 77 return 78 79 default: 80 switch bytes.Compare(l.key, r.key) { 81 case -1: // l < r 82 f(l.key, l.value, nil) 83 l = oldIter.Next() 84 case 0: // l == r 85 f(l.key, l.value, r.value) 86 l, r = oldIter.Next(), newIter.Next() 87 case 1: // l > r 88 f(r.key, nil, r.value) 89 r = newIter.Next() 90 } 91 } 92 } 93 } 94 95 // memStore is a generic interface modeled after treapstore.Store. 96 type memStore interface { 97 datastore.TestingSnapshot 98 99 GetCollection(name string) memCollection 100 GetCollectionNames() []string 101 GetOrCreateCollection(name string) memCollection 102 Snapshot() memStore 103 104 IsReadOnly() bool 105 } 106 107 // memIterator is an iterator over a memStore's contents. 108 type memIterator interface { 109 Next() *storeEntry 110 } 111 112 // memVisitor is a callback for ForEachItem. 113 type memVisitor func(k, v []byte) bool 114 115 // memCollection is a generic interface modeled after treapstore.Collection. 116 type memCollection interface { 117 Name() string 118 Delete(k []byte) 119 Get(k []byte) []byte 120 MinItem() *storeEntry 121 Set(k, v []byte) 122 Iterator(pivot []byte) memIterator 123 ForEachItem(memVisitor) 124 125 IsReadOnly() bool 126 } 127 128 type memStoreImpl struct { 129 s *treapstore.Store 130 } 131 132 var _ memStore = (*memStoreImpl)(nil) 133 134 func (*memStoreImpl) ImATestingSnapshot() {} 135 136 func (ms *memStoreImpl) IsReadOnly() bool { return ms.s.IsReadOnly() } 137 138 func newMemStore() memStore { 139 ret := memStore(&memStoreImpl{treapstore.New()}) 140 if *logMemCollectionFolder != "" { 141 ret = wrapTracingMemStore(ret) 142 } 143 return ret 144 } 145 146 func (ms *memStoreImpl) Snapshot() memStore { 147 if ms.s.IsReadOnly() { 148 return ms 149 } 150 return &memStoreImpl{ms.s.Snapshot()} 151 } 152 153 func (ms *memStoreImpl) GetCollection(name string) memCollection { 154 coll := ms.s.GetCollection(name) 155 if coll == nil { 156 return nil 157 } 158 return &memCollectionImpl{coll} 159 } 160 161 func (ms *memStoreImpl) GetOrCreateCollection(name string) memCollection { 162 coll := ms.s.GetCollection(name) 163 if coll == nil { 164 coll = ms.s.CreateCollection(name, storeEntryCompare) 165 } 166 return &memCollectionImpl{coll} 167 } 168 169 func (ms *memStoreImpl) GetCollectionNames() []string { return ms.s.GetCollectionNames() } 170 171 type memIteratorImpl struct { 172 base *gtreap.Iterator 173 } 174 175 func (it *memIteratorImpl) Next() *storeEntry { 176 v, ok := it.base.Next() 177 if !ok { 178 return nil 179 } 180 return v.(*storeEntry) 181 } 182 183 type memCollectionImpl struct { 184 c *treapstore.Collection 185 } 186 187 var _ memCollection = (*memCollectionImpl)(nil) 188 189 func (mc *memCollectionImpl) Name() string { return mc.c.Name() } 190 func (mc *memCollectionImpl) IsReadOnly() bool { return mc.c.IsReadOnly() } 191 192 func (mc *memCollectionImpl) Get(k []byte) []byte { 193 if ent := mc.c.Get(storeKey(k)); ent != nil { 194 return ent.(*storeEntry).value 195 } 196 return nil 197 } 198 199 func (mc *memCollectionImpl) MinItem() *storeEntry { 200 ent, _ := mc.c.Min().(*storeEntry) 201 return ent 202 } 203 204 func (mc *memCollectionImpl) Set(k, v []byte) { mc.c.Put(&storeEntry{k, v}) } 205 func (mc *memCollectionImpl) Delete(k []byte) { mc.c.Delete(storeKey(k)) } 206 207 func (mc *memCollectionImpl) Iterator(target []byte) memIterator { 208 if !mc.c.IsReadOnly() { 209 // We prevent this to ensure our internal logic, not because it's actually 210 // an invalid operation. 211 panic("attempting to get Iterator from r/w memCollection") 212 } 213 return &memIteratorImpl{mc.c.Iterator(storeKey(target))} 214 } 215 216 func (mc *memCollectionImpl) ForEachItem(fn memVisitor) { 217 mc.c.VisitAscend(storeKey(nil), func(it gtreap.Item) bool { 218 ent := it.(*storeEntry) 219 return fn(ent.key, ent.value) 220 }) 221 } 222 223 func storeKey(k []byte) *storeEntry { return &storeEntry{k, nil} } 224 225 // nilIterator is a memIterator that begins in a depleted state. 226 type nilIterator struct{} 227 228 func (it nilIterator) Next() *storeEntry { return nil }