From dd5726a4d19fd67d98629cc40cb858ba79601918 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Tue, 29 Nov 2011 17:33:10 -0500 Subject: [PATCH] index: cleanup and formalizing key formats into their own types Change-Id: I36aaa74ee7a4349bb00c1ac06285d4c43f4c61bc --- lib/go/camli/index/index.go | 43 ++++++++++++++------- lib/go/camli/index/keys.go | 68 +++++++++++++++++++++++++++++++++ lib/go/camli/index/keys_test.go | 27 +++++++++++++ lib/go/camli/index/receive.go | 1 + 4 files changed, 125 insertions(+), 14 deletions(-) create mode 100644 lib/go/camli/index/keys.go create mode 100644 lib/go/camli/index/keys_test.go diff --git a/lib/go/camli/index/index.go b/lib/go/camli/index/index.go index b6f962bb7..1e87c4ef9 100644 --- a/lib/go/camli/index/index.go +++ b/lib/go/camli/index/index.go @@ -127,6 +127,30 @@ func New(s IndexStorage) *Index { } } +type prefixIter struct { + Iterator + prefix string +} + +func (p *prefixIter) Next() bool { + v := p.Iterator.Next() + if v && !strings.HasPrefix(p.Key(), p.prefix) { + return false + } + return v +} + +func (x *Index) queryPrefix(key *keyType, args ...interface{}) *prefixIter { + return x.queryPrefixString(key.Prefix(args...)) +} + +func (x *Index) queryPrefixString(prefix string) *prefixIter { + return &prefixIter{ + prefix: prefix, + Iterator: x.s.Find(prefix), + } +} + func (x *Index) GetRecentPermanodes(dest chan *search.Result, owner *blobref.BlobRef, limit int) os.Error { defer close(dest) // TODO(bradfitz): this will need to be a context wrapper too, like storage @@ -141,13 +165,10 @@ func (x *Index) GetRecentPermanodes(dest chan *search.Result, owner *blobref.Blo sent := 0 var seenPermanode dupSkipper - prefix := pipes("recpn", keyId, "") - it := x.s.Find(prefix) + + it := x.queryPrefix(keyRecentPermanode, keyId) defer it.Close() for it.Next() { - if !strings.HasPrefix(it.Key(), prefix) { - break - } permaStr := it.Value() parts := strings.SplitN(it.Key(), "|", 4) if len(parts) != 4 { @@ -191,12 +212,9 @@ func (x *Index) GetOwnerClaims(permaNode, owner *blobref.BlobRef) (cl search.Cla return nil, err } prefix := pipes("claim", permaNode, keyId, "") - it := x.s.Find(prefix) + it := x.queryPrefixString(prefix) defer it.Close() for it.Next() { - if !strings.HasPrefix(it.Key(), prefix) { - break - } keyPart := strings.Split(it.Key(), "|") valPart := strings.Split(it.Value(), "|") if len(keyPart) < 5 || len(valPart) < 3 { @@ -257,13 +275,10 @@ func (x *Index) PermanodeOfSignerAttrValue(signer *blobref.BlobRef, attr, val st if err != nil { return nil, err } - prefix := pipes("signerattrvalue", keyId, urle(attr), urle(val), "") - it := x.s.Find(prefix) + it := x.queryPrefixString(pipes("signerattrvalue", keyId, urle(attr), urle(val), "")) defer it.Close() if it.Next() { - if strings.HasPrefix(it.Key(), prefix) { - return blobref.Parse(it.Value()), nil - } + return blobref.Parse(it.Value()), nil } return nil, os.ENOENT } diff --git a/lib/go/camli/index/keys.go b/lib/go/camli/index/keys.go new file mode 100644 index 000000000..bc86058b5 --- /dev/null +++ b/lib/go/camli/index/keys.go @@ -0,0 +1,68 @@ +/* +Copyright 2011 Google Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package index + +import ( + "bytes" + "fmt" +) + +type keyType struct { + name string + parts []keyPart +} + +func (k *keyType) Prefix(args ...interface{}) string { + var buf bytes.Buffer + buf.WriteString(k.name) + for _, arg := range args { + buf.WriteString("|") + // TODO(bradfitz): verify the type matches + if s, ok := arg.(string); ok { + buf.WriteString(s) + } else { + buf.WriteString(arg.(fmt.Stringer).String()) + } + } + buf.WriteString("|") + return buf.String() +} + +type keyPart struct { + name string + typ partType +} + +type partType int + +const ( + typeKeyId partType = iota // PGP key id + typeTime + typeReverseTime // time prepended with "rt" + each numeric digit reversed from '9' + typeBlobRef +) + +var ( + keyRecentPermanode = &keyType{ + "recpn", + []keyPart{ + {"owner", typeKeyId}, + {"modtime", typeReverseTime}, + {"claim", typeBlobRef}, + }, + } +) diff --git a/lib/go/camli/index/keys_test.go b/lib/go/camli/index/keys_test.go new file mode 100644 index 000000000..8214fa226 --- /dev/null +++ b/lib/go/camli/index/keys_test.go @@ -0,0 +1,27 @@ +/* +Copyright 2011 Google Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package index + +import ( + "testing" +) + +func TestKeyPrefix(t *testing.T) { + if g, e := keyRecentPermanode.Prefix("ABC"), "recpn|ABC|"; g != e { + t.Errorf("recpn = %q; want %q", g, e) + } +} diff --git a/lib/go/camli/index/receive.go b/lib/go/camli/index/receive.go index a90e35b44..3346a1dc2 100644 --- a/lib/go/camli/index/receive.go +++ b/lib/go/camli/index/receive.go @@ -121,6 +121,7 @@ func (ix *Index) populateClaim(br *blobref.BlobRef, ss *schema.Superset, sniffer bm.Set("signerkeyid:"+vr.CamliSigner.String(), verifiedKeyId) + // TODO(bradfitz): use keyRecentPermanode here instead of pipes() with "recpn". recentKey := pipes("recpn", verifiedKeyId, reverseTimeString(ss.ClaimDate), br) bm.Set(recentKey, pnbr.String())