Chromium Code Reviews| 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 gtrea.Compare function for *storeEntry. | |
|
iannucci
2017/01/07 19:06:17
gtreap
dnj
2017/01/08 03:38:14
Done.
| |
| 22 func storeEntryCompare(a, b interface{}) int { | |
|
iannucci
2017/01/07 19:06:17
that's unfortunate :/ no way we can hack up gtreap
dnj
2017/01/08 03:38:14
Yeah we totally could do this. Might be worth dete
| |
| 23 return bytes.Compare(a.(*storeEntry).key, b.(*storeEntry).key) | |
| 24 } | |
| 25 | |
| 26 func memStoreCollide(o, n memCollection, f func(k, ov, nv []byte)) { | |
| 27 var oldIter, newIter memIterator | |
| 28 if o != nil { | |
| 29 if !o.IsReadOnly() { | |
| 30 panic("old collection is r/w") | |
| 31 } | |
| 32 oldIter = o.Iterator(nil) | |
| 33 } else { | |
| 34 oldIter = nilIterator{} | |
| 35 } | |
| 36 | |
| 37 if n != nil { | |
| 38 if !n.IsReadOnly() { | |
| 39 panic("new collection is r/w") | |
| 40 } | |
| 41 newIter = n.Iterator(nil) | |
| 42 } else { | |
| 43 newIter = nilIterator{} | |
| 44 } | |
| 45 | |
| 46 l, r := oldIter.Next(), newIter.Next() | |
| 47 for { | |
| 48 switch { | |
| 49 case l == nil: | |
| 50 // No more "old" items, use up the rest of "new" and fin ish. | |
| 51 for r != nil { | |
| 52 f(r.key, nil, r.value) | |
| 53 r = newIter.Next() | |
| 54 } | |
| 55 return | |
| 56 | |
| 57 case r == nil: | |
| 58 // No more "new" items, use up the rest of "old" and fin ish. | |
| 59 for l != nil { | |
| 60 f(l.key, l.value, nil) | |
| 61 l = oldIter.Next() | |
| 62 } | |
| 63 return | |
| 64 | |
| 65 default: | |
| 66 switch bytes.Compare(l.key, r.key) { | |
| 67 case -1: // l < r | |
| 68 f(l.key, l.value, nil) | |
| 69 l = oldIter.Next() | |
| 70 case 0: // l == r | |
| 71 f(l.key, l.value, r.value) | |
| 72 l, r = oldIter.Next(), newIter.Next() | |
| 73 case 1: // l > r | |
| 74 f(r.key, nil, r.value) | |
| 75 r = newIter.Next() | |
| 76 } | |
| 77 } | |
| 78 } | |
| 79 } | |
| 80 | |
| 81 // memStore is a generic interface modeled after treapstore.Store. | |
| 82 type memStore interface { | |
| 83 datastore.TestingSnapshot | |
| 84 | |
| 85 GetCollection(name string) memCollection | |
| 86 GetCollectionNames() []string | |
| 87 GetOrCreateCollection(name string) memCollection | |
| 88 Snapshot() memStore | |
| 89 | |
| 90 IsReadOnly() bool | |
| 91 } | |
| 92 | |
| 93 // memIterator is an iterator over a memStore's contents. | |
| 94 type memIterator interface { | |
| 95 Next() *storeEntry | |
| 96 } | |
| 97 | |
| 98 // memCollection is a generic interface modeled after treapstore.Collection. | |
| 99 type memCollection interface { | |
| 100 Name() string | |
| 101 Delete(k []byte) | |
| 102 Get(k []byte) []byte | |
| 103 MinItem() *storeEntry | |
| 104 Set(k, v []byte) | |
| 105 Iterator(pivot []byte) memIterator | |
| 106 | |
| 107 IsReadOnly() bool | |
| 108 } | |
| 109 | |
| 110 type memStoreImpl struct { | |
| 111 s *treapstore.Store | |
| 112 } | |
| 113 | |
| 114 var _ memStore = (*memStoreImpl)(nil) | |
| 115 | |
| 116 func (*memStoreImpl) ImATestingSnapshot() {} | |
| 117 | |
| 118 func (ms *memStoreImpl) IsReadOnly() bool { return ms.s.IsReadOnly() } | |
| 119 | |
| 120 func newMemStore() memStore { | |
| 121 ret := memStore(&memStoreImpl{treapstore.New()}) | |
| 122 if *logMemCollectionFolder != "" { | |
| 123 ret = wrapTracingMemStore(ret) | |
| 124 } | |
| 125 return ret | |
| 126 } | |
| 127 | |
| 128 func (ms *memStoreImpl) Snapshot() memStore { | |
| 129 if ms.s.IsReadOnly() { | |
| 130 return ms | |
| 131 } | |
| 132 return &memStoreImpl{ms.s.Snapshot()} | |
| 133 } | |
| 134 | |
| 135 func (ms *memStoreImpl) GetCollection(name string) memCollection { | |
| 136 coll := ms.s.GetCollection(name) | |
| 137 if coll == nil { | |
| 138 return nil | |
| 139 } | |
| 140 return &memCollectionImpl{coll} | |
| 141 } | |
| 142 | |
| 143 func (ms *memStoreImpl) GetOrCreateCollection(name string) memCollection { | |
| 144 coll := ms.s.GetCollection(name) | |
| 145 if coll == nil { | |
| 146 coll = ms.s.CreateCollection(name, storeEntryCompare) | |
| 147 } | |
| 148 return &memCollectionImpl{coll} | |
| 149 } | |
| 150 | |
| 151 func (ms *memStoreImpl) GetCollectionNames() []string { return ms.s.GetCollectio nNames() } | |
| 152 | |
| 153 type memIteratorImpl struct { | |
| 154 base *gtreap.Iterator | |
| 155 } | |
| 156 | |
| 157 func (it *memIteratorImpl) Next() *storeEntry { | |
| 158 v, ok := it.base.Next() | |
| 159 if !ok { | |
| 160 return nil | |
| 161 } | |
| 162 return v.(*storeEntry) | |
| 163 } | |
| 164 | |
| 165 type memCollectionImpl struct { | |
| 166 c *treapstore.Collection | |
| 167 } | |
| 168 | |
| 169 var _ memCollection = (*memCollectionImpl)(nil) | |
| 170 | |
| 171 func (mc *memCollectionImpl) Name() string { return mc.c.Name() } | |
| 172 func (mc *memCollectionImpl) IsReadOnly() bool { return mc.c.IsReadOnly() } | |
| 173 | |
| 174 func (mc *memCollectionImpl) Get(k []byte) []byte { | |
| 175 if ent := mc.c.Get(storeKey(k)); ent != nil { | |
| 176 return ent.(*storeEntry).value | |
| 177 } | |
| 178 return nil | |
| 179 } | |
| 180 | |
| 181 func (mc *memCollectionImpl) MinItem() *storeEntry { | |
| 182 ent, _ := mc.c.Min().(*storeEntry) | |
| 183 return ent | |
| 184 } | |
| 185 | |
| 186 func (mc *memCollectionImpl) Set(k, v []byte) { mc.c.Put(&storeEntry{k, v}) } | |
| 187 func (mc *memCollectionImpl) Delete(k []byte) { mc.c.Delete(storeKey(k)) } | |
| 188 | |
| 189 func (mc *memCollectionImpl) Iterator(target []byte) memIterator { | |
| 190 if !mc.c.IsReadOnly() { | |
| 191 // We prevent this to ensure our internal logic, not because it' s actually | |
| 192 // an invalid operation. | |
| 193 panic("attempting to get Iterator from r/w memCollection") | |
| 194 } | |
| 195 return &memIteratorImpl{mc.c.Iterator(storeKey(target))} | |
| 196 } | |
| 197 | |
| 198 func storeKey(k []byte) *storeEntry { return &storeEntry{k, nil} } | |
| 199 | |
| 200 // nilIterator is a memIterator that begins in a depleted state. | |
| 201 type nilIterator struct{} | |
| 202 | |
| 203 func (it nilIterator) Next() *storeEntry { return nil } | |
| 204 | |
| 205 func forEachItem(mc memCollection, cb func(k, v []byte) bool) { | |
| 206 it := mc.Iterator(nil) | |
| 207 for ent := it.Next(); ent != nil; ent = it.Next() { | |
| 208 if !cb(ent.key, ent.value) { | |
| 209 break | |
| 210 } | |
| 211 } | |
| 212 } | |
| OLD | NEW |