OLD | NEW |
---|---|
1 // Copyright 2015 The LUCI Authors. All rights reserved. | 1 // Copyright 2015 The LUCI Authors. All rights reserved. |
2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
4 | 4 |
5 package memory | 5 package memory |
6 | 6 |
7 import ( | 7 import ( |
8 "bytes" | 8 "bytes" |
9 "runtime" | 9 "runtime" |
10 "sync" | 10 "sync" |
11 | 11 |
12 "github.com/luci/gae/service/datastore" | 12 "github.com/luci/gae/service/datastore" |
13 "github.com/luci/gkvlite" | 13 "github.com/luci/gkvlite" |
14 ) | 14 ) |
15 | 15 |
16 func gkvCollide(o, n memCollection, f func(k, ov, nv []byte)) { | 16 func gkvCollide(o, n memCollection, f func(k, ov, nv []byte)) { |
17 if o != nil && !o.IsReadOnly() { | 17 if o != nil && !o.IsReadOnly() { |
18 panic("old collection is r/w") | 18 panic("old collection is r/w") |
19 } | 19 } |
20 if n != nil && !n.IsReadOnly() { | 20 if n != nil && !n.IsReadOnly() { |
21 panic("new collection is r/w") | 21 panic("new collection is r/w") |
22 } | 22 } |
23 | 23 |
24 // TODO(riannucci): reimplement in terms of *iterator. | 24 // TODO(riannucci): reimplement in terms of *iterator. |
25 oldItems, newItems := make(chan *gkvlite.Item), make(chan *gkvlite.Item) | 25 oldItems, newItems := make(chan *gkvlite.Item), make(chan *gkvlite.Item) |
26 walker := func(c memCollection, ch chan<- *gkvlite.Item, wg *sync.WaitGr oup) { | 26 walker := func(c memCollection, ch chan<- *gkvlite.Item, wg *sync.WaitGr oup) { |
27 defer close(ch) | 27 defer close(ch) |
28 defer wg.Done() | |
29 if c != nil { | 28 if c != nil { |
30 c.VisitItemsAscend(nil, true, func(i *gkvlite.Item) bool { | 29 c.VisitItemsAscend(nil, true, func(i *gkvlite.Item) bool { |
31 ch <- i | 30 ch <- i |
32 return true | 31 return true |
33 }) | 32 }) |
34 } | 33 } |
35 } | 34 } |
36 | 35 |
37 wg := &sync.WaitGroup{} | 36 wg := &sync.WaitGroup{} |
iannucci
2016/11/12 00:05:47
del wg too?
| |
38 wg.Add(2) | |
39 go walker(o, oldItems, wg) | 37 go walker(o, oldItems, wg) |
40 go walker(n, newItems, wg) | 38 go walker(n, newItems, wg) |
41 | 39 |
42 l, r := <-oldItems, <-newItems | 40 l, r := <-oldItems, <-newItems |
43 for { | 41 for { |
44 » » if l == nil && r == nil { | 42 » » switch { |
45 » » » break | 43 » » case l == nil && r == nil: |
46 » » } | 44 » » » return |
47 | 45 |
48 » » if l == nil { | 46 » » case l == nil: |
49 f(r.Key, nil, r.Val) | 47 f(r.Key, nil, r.Val) |
50 r = <-newItems | 48 r = <-newItems |
51 » » } else if r == nil { | 49 |
50 » » case r == nil: | |
52 f(l.Key, l.Val, nil) | 51 f(l.Key, l.Val, nil) |
53 l = <-oldItems | 52 l = <-oldItems |
54 » » } else { | 53 |
54 » » default: | |
55 switch bytes.Compare(l.Key, r.Key) { | 55 switch bytes.Compare(l.Key, r.Key) { |
56 case -1: // l < r | 56 case -1: // l < r |
57 f(l.Key, l.Val, nil) | 57 f(l.Key, l.Val, nil) |
58 l = <-oldItems | 58 l = <-oldItems |
59 case 0: // l == r | 59 case 0: // l == r |
60 f(l.Key, l.Val, r.Val) | 60 f(l.Key, l.Val, r.Val) |
61 l, r = <-oldItems, <-newItems | 61 l, r = <-oldItems, <-newItems |
62 case 1: // l > r | 62 case 1: // l > r |
63 f(r.Key, nil, r.Val) | 63 f(r.Key, nil, r.Val) |
64 r = <-newItems | 64 r = <-newItems |
65 } | 65 } |
66 } | 66 } |
67 } | 67 } |
68 wg.Wait() | |
69 } | 68 } |
70 | 69 |
71 // memStore is a gkvlite.Store which will panic for anything which might | 70 // memStore is a gkvlite.Store which will panic for anything which might |
72 // otherwise return an error. | 71 // otherwise return an error. |
73 // | 72 // |
74 // This is reasonable for in-memory Store objects, since the only errors that | 73 // This is reasonable for in-memory Store objects, since the only errors that |
75 // should occur happen with file IO on the underlying file (which of course | 74 // should occur happen with file IO on the underlying file (which of course |
76 // doesn't exist). | 75 // doesn't exist). |
77 type memStore interface { | 76 type memStore interface { |
78 datastore.TestingSnapshot | 77 datastore.TestingSnapshot |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
192 } | 191 } |
193 err := mc.c.VisitItemsAscend(target, withValue, visitor) | 192 err := mc.c.VisitItemsAscend(target, withValue, visitor) |
194 memoryCorruption(err) | 193 memoryCorruption(err) |
195 } | 194 } |
196 | 195 |
197 func (mc *memCollectionImpl) GetTotals() (numItems, numBytes uint64) { | 196 func (mc *memCollectionImpl) GetTotals() (numItems, numBytes uint64) { |
198 numItems, numBytes, err := mc.c.GetTotals() | 197 numItems, numBytes, err := mc.c.GetTotals() |
199 memoryCorruption(err) | 198 memoryCorruption(err) |
200 return | 199 return |
201 } | 200 } |
OLD | NEW |