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. | |
| 22 func storeEntryCompare(a, b interface{}) int { | |
| 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 && r == nil: | |
| 50 return | |
| 51 | |
| 52 case l == nil: | |
| 53 f(r.key, nil, r.value) | |
|
Vadim Sh.
2016/12/28 01:57:05
nit: this can be micro optimized by avoiding calls
dnj
2016/12/28 02:52:15
I was initially trying to stay as close to the ori
| |
| 54 r = newIter.Next() | |
| 55 | |
| 56 case r == nil: | |
| 57 f(l.key, l.value, nil) | |
| 58 l = oldIter.Next() | |
| 59 | |
| 60 default: | |
| 61 switch bytes.Compare(l.key, r.key) { | |
| 62 case -1: // l < r | |
| 63 f(l.key, l.value, nil) | |
| 64 l = oldIter.Next() | |
| 65 case 0: // l == r | |
| 66 f(l.key, l.value, r.value) | |
| 67 l, r = oldIter.Next(), newIter.Next() | |
| 68 case 1: // l > r | |
| 69 f(r.key, nil, r.value) | |
| 70 r = newIter.Next() | |
| 71 } | |
| 72 } | |
| 73 } | |
| 74 } | |
| 75 | |
| 76 // memStore is a treapstore.Store which will panic for anything which might | |
| 77 // otherwise return an error. | |
| 78 // | |
| 79 // This is reasonable for in-memory Store objects, since the only errors that | |
| 80 // should occur happen with file IO on the underlying file (which of course | |
|
Vadim Sh.
2016/12/28 01:57:05
the comment is probably stale. There should be no
dnj
2016/12/28 02:52:15
Done.
| |
| 81 // doesn't exist). | |
| 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 treapstore.Collection which will panic for anything which | |
| 99 // might otherwise return an error. | |
| 100 // | |
| 101 // This is reasonable for in-memory Store objects, since the only errors that | |
| 102 // should occur happen with file IO on the underlying file (which of course | |
| 103 // doesn't exist. | |
| 104 type memCollection interface { | |
| 105 Name() string | |
| 106 Delete(k []byte) | |
| 107 Get(k []byte) []byte | |
| 108 MinItem() *storeEntry | |
| 109 Set(k, v []byte) | |
| 110 Iterator(pivot []byte) memIterator | |
| 111 | |
| 112 IsReadOnly() bool | |
| 113 } | |
| 114 | |
| 115 type memStoreImpl struct { | |
| 116 s *treapstore.Store | |
| 117 } | |
| 118 | |
| 119 var _ memStore = (*memStoreImpl)(nil) | |
| 120 | |
| 121 func (*memStoreImpl) ImATestingSnapshot() {} | |
| 122 | |
| 123 func (ms *memStoreImpl) IsReadOnly() bool { return ms.s.IsReadOnly() } | |
| 124 | |
| 125 func newMemStore() memStore { | |
| 126 ret := memStore(&memStoreImpl{treapstore.New(storeEntryCompare)}) | |
| 127 if *logMemCollectionFolder != "" { | |
| 128 ret = wrapTracingMemStore(ret) | |
| 129 } | |
| 130 return ret | |
| 131 } | |
| 132 | |
| 133 func (ms *memStoreImpl) Snapshot() memStore { | |
| 134 if ms.s.IsReadOnly() { | |
| 135 return ms | |
| 136 } | |
| 137 return &memStoreImpl{ms.s.Snapshot()} | |
| 138 } | |
| 139 | |
| 140 func (ms *memStoreImpl) GetCollection(name string) memCollection { | |
| 141 coll := ms.s.GetCollection(name) | |
| 142 if coll == nil { | |
| 143 return nil | |
| 144 } | |
| 145 return &memCollectionImpl{coll} | |
| 146 } | |
| 147 | |
| 148 func (ms *memStoreImpl) GetOrCreateCollection(name string) memCollection { | |
| 149 return &memCollectionImpl{ms.s.GetOrCreateCollection(name)} | |
| 150 } | |
| 151 | |
| 152 func (ms *memStoreImpl) GetCollectionNames() []string { return ms.s.GetCollectio nNames() } | |
| 153 | |
| 154 type memIteratorImpl struct { | |
| 155 base *gtreap.Iterator | |
| 156 } | |
| 157 | |
| 158 func (it *memIteratorImpl) Next() *storeEntry { | |
| 159 v, ok := it.base.Next() | |
| 160 if !ok { | |
| 161 return nil | |
| 162 } | |
| 163 return v.(*storeEntry) | |
| 164 } | |
| 165 | |
| 166 type memCollectionImpl struct { | |
| 167 c *treapstore.Collection | |
| 168 } | |
| 169 | |
| 170 var _ memCollection = (*memCollectionImpl)(nil) | |
| 171 | |
| 172 func (mc *memCollectionImpl) Name() string { return mc.c.Name() } | |
| 173 func (mc *memCollectionImpl) IsReadOnly() bool { return mc.c.IsReadOnly() } | |
| 174 | |
| 175 func (mc *memCollectionImpl) Get(k []byte) []byte { | |
| 176 if ent := mc.c.Get(storeKey(k)); ent != nil { | |
| 177 return ent.(*storeEntry).value | |
| 178 } | |
| 179 return nil | |
| 180 } | |
| 181 | |
| 182 func (mc *memCollectionImpl) MinItem() *storeEntry { | |
| 183 ent, _ := mc.c.Min().(*storeEntry) | |
| 184 return ent | |
| 185 } | |
| 186 | |
| 187 func (mc *memCollectionImpl) Set(k, v []byte) { mc.c.Put(&storeEntry{k, v}) } | |
| 188 func (mc *memCollectionImpl) Delete(k []byte) { mc.c.Delete(storeKey(k)) } | |
| 189 | |
| 190 func (mc *memCollectionImpl) Iterator(target []byte) memIterator { | |
| 191 if !mc.c.IsReadOnly() { | |
| 192 // We prevent this to ensure our internal logic, not because it' s actually | |
| 193 // an invalid operation. | |
| 194 panic("attempting to get Iterator from r/w memCollection") | |
| 195 } | |
| 196 return &memIteratorImpl{mc.c.Iterator(storeKey(target))} | |
| 197 } | |
| 198 | |
| 199 func storeKey(k []byte) *storeEntry { return &storeEntry{k, nil} } | |
| 200 | |
| 201 // nilIterator is a memIterator that begins in a depleted state. | |
| 202 type nilIterator struct{} | |
| 203 | |
| 204 func (it nilIterator) Next() *storeEntry { return nil } | |
| 205 | |
| 206 func forEachItem(mc memCollection, cb func(k, v []byte) bool) { | |
| 207 it := mc.Iterator(nil) | |
| 208 for ent := it.Next(); ent != nil; ent = it.Next() { | |
| 209 if !cb(ent.key, ent.value) { | |
| 210 break | |
| 211 } | |
| 212 } | |
| 213 } | |
| OLD | NEW |