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