| 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 {
|
|
|