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 |