Index: go/src/infra/gae/libs/wrapper/memory/gkvlite_utils.go |
diff --git a/go/src/infra/gae/libs/wrapper/memory/gkvlite_utils.go b/go/src/infra/gae/libs/wrapper/memory/gkvlite_utils.go |
index ea8fb200d9abf1b649d20f440b7e7452feed4834..a21c9bbad1354b14cdc2029ddcdeb74e630c434c 100644 |
--- a/go/src/infra/gae/libs/wrapper/memory/gkvlite_utils.go |
+++ b/go/src/infra/gae/libs/wrapper/memory/gkvlite_utils.go |
@@ -5,9 +5,59 @@ |
package memory |
import ( |
+ "bytes" |
+ "sync" |
+ |
"github.com/luci/gkvlite" |
) |
+func gkvCollide(o, n *memCollection, f func(k, ov, nv []byte)) { |
+ oldItems, newItems := make(chan *gkvlite.Item), make(chan *gkvlite.Item) |
+ walker := func(c *memCollection, ch chan<- *gkvlite.Item, wg *sync.WaitGroup) { |
+ defer close(ch) |
+ defer wg.Done() |
+ if c != nil { |
+ c.VisitItemsAscend(nil, true, func(i *gkvlite.Item) bool { |
+ ch <- i |
+ return true |
+ }) |
+ } |
+ } |
+ |
+ wg := &sync.WaitGroup{} |
+ wg.Add(2) |
+ go walker(o, oldItems, wg) |
+ go walker(n, newItems, wg) |
+ |
+ l, r := <-oldItems, <-newItems |
+ for { |
+ if l == nil && r == nil { |
+ break |
+ } |
+ |
+ if l == nil { |
+ f(r.Key, nil, r.Val) |
+ r = <-newItems |
+ } else if r == nil { |
+ f(l.Key, l.Val, nil) |
+ l = <-oldItems |
+ } else { |
+ switch bytes.Compare(l.Key, r.Key) { |
+ case -1: // l < r |
+ f(l.Key, l.Val, nil) |
+ l = <-oldItems |
+ case 0: // l == r |
+ f(l.Key, l.Val, r.Val) |
+ l, r = <-oldItems, <-newItems |
+ case 1: // l > r |
+ f(r.Key, nil, r.Val) |
+ r = <-newItems |
+ } |
+ } |
+ } |
+ wg.Wait() |
+} |
+ |
// memStore is a gkvlite.Store which will panic for anything which might |
// otherwise return an error. |
// |
@@ -40,6 +90,14 @@ func (ms *memStore) SetCollection(name string, cmp gkvlite.KeyCompare) *memColle |
return (*memCollection)((*gkvlite.Store)(ms).SetCollection(name, cmp)) |
} |
+func (ms *memStore) RemoveCollection(name string) { |
+ (*gkvlite.Store)(ms).RemoveCollection(name) |
+} |
+ |
+func (ms *memStore) GetCollectionNames() []string { |
+ return (*gkvlite.Store)(ms).GetCollectionNames() |
+} |
+ |
// memCollection is a gkvlite.Collection which will panic for anything which |
// might otherwise return an error. |
// |
@@ -56,6 +114,14 @@ func (mc *memCollection) Get(k []byte) []byte { |
return ret |
} |
+func (mc *memCollection) MinItem(withValue bool) *gkvlite.Item { |
+ ret, err := (*gkvlite.Collection)(mc).MinItem(withValue) |
+ if err != nil { |
+ panic(err) |
+ } |
+ return ret |
+} |
+ |
func (mc *memCollection) Set(k, v []byte) { |
if err := (*gkvlite.Collection)(mc).Set(k, v); err != nil { |
panic(err) |
@@ -76,12 +142,6 @@ func (mc *memCollection) VisitItemsAscend(target []byte, withValue bool, visitor |
} |
} |
-func (mc *memCollection) VisitItemsDescend(target []byte, withValue bool, visitor gkvlite.ItemVisitor) { |
- if err := (*gkvlite.Collection)(mc).VisitItemsDescend(target, withValue, visitor); err != nil { |
- panic(err) |
- } |
-} |
- |
func (mc *memCollection) GetTotals() (numItems, numBytes uint64) { |
numItems, numBytes, err := (*gkvlite.Collection)(mc).GetTotals() |
if err != nil { |