Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(265)

Unified Diff: impl/memory/memstore_iter.go

Issue 2604943002: impl/memory: Replace gkvlite with "treapstore". (Closed)
Patch Set: Comments. Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « impl/memory/memstore.go ('k') | impl/memory/memstore_iter_test.go » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: impl/memory/memstore_iter.go
diff --git a/impl/memory/memstore_iter.go b/impl/memory/memstore_iter.go
new file mode 100644
index 0000000000000000000000000000000000000000..3dff0fbd22f89af1a273cad8dd28c724e19cb774
--- /dev/null
+++ b/impl/memory/memstore_iter.go
@@ -0,0 +1,152 @@
+// Copyright 2015 The LUCI Authors. All rights reserved.
+// Use of this source code is governed under the Apache License, Version 2.0
+// that can be found in the LICENSE file.
+
+package memory
+
+import (
+ "bytes"
+
+ "github.com/luci/gae/service/datastore/serialize"
+)
+
+type iterDefinition struct {
+ // The collection to iterate over
+ c memCollection
+
+ // The prefix to always assert for every row. A nil prefix matches every row.
+ prefix []byte
+
+ // prefixLen is the number of prefix bytes that the caller cares about. It
+ // may be <= len(prefix). When doing a multiIterator, this number will be used
+ // to determine the amount of suffix to transfer accross iterators. This is
+ // used specifically when using builtin indexes to service ancestor queries.
+ // The builtin index represents the ancestor key with prefix bytes, but in a
+ // multiIterator context, it wants the entire key to be included in the
+ // suffix.
+ prefixLen int
+
+ // The start cursor. It's appended to prefix to find the first row.
+ start []byte
+
+ // The end cursor. It's appended to prefix to find the last row (which is not
+ // included in the interation result). If this is nil, then there's no end
+ // except the natural end of the collection.
+ end []byte
+}
+
+func multiIterate(defs []*iterDefinition, cb func(suffix []byte) error) error {
+ if len(defs) == 0 {
+ return nil
+ }
+
+ ts := make([]*iterator, len(defs))
+ prefixLens := make([]int, len(defs))
+ for i, def := range defs {
+ // bind i so that the defer below doesn't get goofed by the loop variable
+ i := i
+ ts[i] = def.mkIter()
+ prefixLens[i] = def.prefixLen
+ }
+
+ suffix := []byte(nil)
+ skip := -1
+
+MainLoop:
+ for {
+ for idx, it := range ts {
+ if skip >= 0 && skip == idx {
+ continue
+ }
+
+ pfxLen := prefixLens[idx]
+ it.skip(serialize.Join(it.def.prefix[:pfxLen], suffix))
+ ent := it.next()
+ if ent == nil {
+ // we hit the end of an iterator, we're now done with the whole
+ // query.
+ return nil
+ }
+ sfxRO := ent.key[pfxLen:]
+
+ if bytes.Compare(sfxRO, suffix) > 0 {
+ // this row has a higher suffix than anything we've seen before. Set
+ // ourself to be the skip, and resart this loop from the top.
+ suffix = append(suffix[:0], sfxRO...)
+ skip = idx
+ if idx != 0 {
+ // no point to restarting on the 0th index
+ continue MainLoop
+ }
+ }
+ }
+
+ if err := cb(suffix); err != nil {
+ return err
+ }
+ suffix = nil
+ skip = -1
+ }
+}
+
+type iterator struct {
+ def *iterDefinition
+ base memIterator
+
+ start []byte
+ end []byte
+ lastKey []byte
+}
+
+func (def *iterDefinition) mkIter() *iterator {
+ if !def.c.IsReadOnly() {
+ panic("attempting to make an iterator with r/w collection")
+ }
+
+ it := iterator{
+ def: def,
+ }
+
+ // convert the suffixes from the iterDefinition into full rows for the
+ // underlying storage.
+ it.start = serialize.Join(def.prefix, def.start)
+ if def.end != nil {
+ it.end = serialize.Join(def.prefix, def.end)
+ }
+ return &it
+}
+
+func (it *iterator) skip(targ []byte) {
+ if bytes.Compare(targ, it.start) < 0 {
+ targ = it.start
+ }
+ if it.base == nil || bytes.Compare(targ, it.lastKey) > 0 {
+ // If our skip target is >= our last key, then create a new Iterator
+ // starting from that target.
+ it.base = it.def.c.Iterator(targ)
+ }
+}
+
+func (it *iterator) next() *storeEntry {
+ if it.base == nil {
+ it.skip(nil)
+ }
+
+ ent := it.base.Next()
+ switch {
+ case ent == nil:
+ return nil
+
+ case !bytes.HasPrefix(ent.key, it.def.prefix):
+ // we're no longer in prefix, terminate
+ return nil
+
+ case it.end != nil && bytes.Compare(ent.key, it.end) >= 0:
+ // we hit our cap, terminate.
+ return nil
+
+ default:
+ it.lastKey = ent.key
+ return ent
+ }
+}
« no previous file with comments | « impl/memory/memstore.go ('k') | impl/memory/memstore_iter_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698