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

Side by Side Diff: go/src/infra/gae/libs/wrapper/memory/key.go

Issue 1152383003: Simple memory testing for gae/wrapper (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@better_context_lite
Patch Set: final fixes? Created 5 years, 6 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package memory
6
7 import (
8 "bytes"
9 "errors"
10 "fmt"
11
12 "github.com/golang/protobuf/proto"
13 "github.com/luci/luci-go/common/funnybase"
14 "github.com/mjibson/goon"
15
16 "appengine/datastore"
17 "appengine_internal"
18 basepb "appengine_internal/base"
19 )
20
21 const keyNumToksReasonableLimit = 50
22
23 ///////////////////////////// fakeGAECtxForNewKey //////////////////////////////
24
25 type fakeGAECtxForNewKey string
26
27 func (fakeGAECtxForNewKey) Debugf(format string, args ...interface{}) {}
28 func (fakeGAECtxForNewKey) Infof(format string, args ...interface{}) {}
29 func (fakeGAECtxForNewKey) Warningf(format string, args ...interface{}) {}
30 func (fakeGAECtxForNewKey) Errorf(format string, args ...interface{}) {}
31 func (fakeGAECtxForNewKey) Criticalf(format string, args ...interface{}) {}
32 func (fakeGAECtxForNewKey) Request() interface{} { retur n nil }
33 func (f fakeGAECtxForNewKey) Call(service, method string, in, out appengine_inte rnal.ProtoMessage, opts *appengine_internal.CallOptions) error {
34 if service != "__go__" || method != "GetNamespace" {
35 panic(fmt.Errorf("fakeGAECtxForNewKey: cannot facilitate Call(%q , %q, ...)", service, method))
36 }
37 out.(*basepb.StringProto).Value = proto.String(string(f))
38 return nil
39 }
40 func (fakeGAECtxForNewKey) FullyQualifiedAppID() string { return "dev~my~app" }
41
42 /////////////////////////////// Key construction ///////////////////////////////
43
44 func newKey(ns, kind, stringID string, intID int64, parent *datastore.Key) *data store.Key {
45 return datastore.NewKey(fakeGAECtxForNewKey(ns), kind, stringID, intID, parent)
46 }
47 func newKeyObjError(ns string, knr goon.KindNameResolver, src interface{}) (*dat astore.Key, error) {
48 return (&goon.Goon{
49 Context: fakeGAECtxForNewKey(ns),
50 KindNameResolver: knr}).KeyError(src)
51 }
52 func newKeyObj(ns string, knr goon.KindNameResolver, obj interface{}) *datastore .Key {
53 k, err := newKeyObjError(ns, knr, obj)
54 if err != nil {
55 panic(err)
56 }
57 return k
58 }
59 func kind(ns string, knr goon.KindNameResolver, src interface{}) string {
60 return newKeyObj(ns, knr, src).Kind()
61 }
62
63 /////////////////////////////// Binary Encoding ////////////////////////////////
64
65 type keyTok struct {
66 kind string
67 intID uint64
68 stringID string
69 }
70
71 func keyToToks(key *datastore.Key) (namespace string, ret []*keyTok) {
72 var inner func(*datastore.Key)
73 inner = func(k *datastore.Key) {
74 if k.Parent() != nil {
75 inner(k.Parent())
76 }
77 ret = append(ret, &keyTok{k.Kind(), uint64(k.IntID()), k.StringI D()})
78 }
79 inner(key)
80 namespace = key.Namespace()
81 return
82 }
83
84 func toksToKey(ns string, toks []*keyTok) (ret *datastore.Key) {
85 for _, t := range toks {
86 ret = newKey(ns, t.kind, t.stringID, int64(t.intID), ret)
87 }
88 return
89 }
90
91 type nsOption bool
92
93 const (
94 withNS nsOption = true
95 noNS = false
96 )
97
98 func keyBytes(nso nsOption, k *datastore.Key) []byte {
99 buf := &bytes.Buffer{}
100 writeKey(buf, nso, k)
101 return buf.Bytes()
102 }
103
104 func keyFromByteString(nso nsOption, d string) (*datastore.Key, error) {
105 return readKey(bytes.NewBufferString(d), nso)
106 }
107
108 func writeKey(buf *bytes.Buffer, nso nsOption, k *datastore.Key) {
109 // namespace ++ #tokens ++ [tok.kind ++ tok.stringID ++ tok.intID?]*
110 namespace, toks := keyToToks(k)
111 if nso == withNS {
112 writeString(buf, namespace)
113 }
114 funnybase.WriteUint(buf, uint64(len(toks)))
115 for _, tok := range toks {
116 writeString(buf, tok.kind)
117 writeString(buf, tok.stringID)
118 if tok.stringID == "" {
119 funnybase.WriteUint(buf, tok.intID)
120 }
121 }
122 }
123
124 func readKey(buf *bytes.Buffer, nso nsOption) (*datastore.Key, error) {
125 namespace := ""
126 if nso == withNS {
127 var err error
128 namespace, err = readString(buf)
129 if err != nil {
130 return nil, err
131 }
132 }
133
134 numToks, err := funnybase.ReadUint(buf)
135 if err != nil {
136 return nil, err
137 }
138 if numToks > keyNumToksReasonableLimit {
139 return nil, fmt.Errorf("readKey: tried to decode huge key of len gth %d", numToks)
140 }
141
142 toks := make([]*keyTok, numToks)
143 for i := uint64(0); i < numToks; i++ {
144 tok := &keyTok{}
145 tok.kind, err = readString(buf)
M-A Ruel 2015/05/29 02:01:23 group lines 145-146
iannucci 2015/05/29 02:42:28 done.
146 if err != nil {
147 return nil, err
148 }
149 tok.stringID, err = readString(buf)
M-A Ruel 2015/05/29 02:01:23 same
iannucci 2015/05/29 02:42:28 done..
150 if err != nil {
151 return nil, err
152 }
153 if tok.stringID == "" {
154 tok.intID, err = funnybase.ReadUint(buf)
M-A Ruel 2015/05/29 02:01:23 same
iannucci 2015/05/29 02:42:28 done...
155 if err != nil {
156 return nil, err
157 }
158 if tok.intID == 0 {
159 return nil, errors.New("readKey: decoded key wit h empty stringID and empty intID.")
160 }
161 }
162 toks[i] = tok
163 }
164
165 return toksToKey(namespace, toks), nil
166 }
167
168 //////////////////////////////// Key utilities /////////////////////////////////
169
170 func rootKey(key *datastore.Key) *datastore.Key {
171 for key.Parent() != nil {
172 key = key.Parent()
173 }
174 return key
175 }
176
177 type keyValidOption bool
178
179 const (
180 // UserKeyOnly is used with KeyValid, and ensures that the key is only o ne
181 // that's valid for a user program to write to.
182 UserKeyOnly keyValidOption = false
183
184 // AllowSpecialKeys is used with KeyValid, and allows keys for special
185 // metadata objects (like "__entity_group__").
186 AllowSpecialKeys = true
187 )
188
189 // KeyValid checks to see if a key is valid by applying a bunch of constraint
190 // rules to it (e.g. can't have StringID and IntID set at the same time, can't
191 // have a parent key which is Incomplete(), etc.)
192 //
193 // It verifies that the key is also in the provided namespace. It can also
194 // reject keys which are 'special' e.g. have a Kind starting with "__". This
195 // behavior is controllable with opt.
196 func KeyValid(ns string, k *datastore.Key, opt keyValidOption) bool {
197 // copied from the appengine SDK because why would any user program need to
198 // see if a key is valid?
M-A Ruel 2015/05/29 02:01:23 Can't parse sarcasm. :)
iannucci 2015/05/29 02:42:28 add /s :)
199 if k == nil {
200 return false
201 }
202 // since we do "client-side" validataion of namespaces, check this here.
M-A Ruel 2015/05/29 02:01:23 validation
iannucci 2015/05/29 02:42:28 done
203 if k.Namespace() != ns {
204 return false
205 }
206 for ; k != nil; k = k.Parent() {
207 if opt == UserKeyOnly && len(k.Kind()) >= 2 && k.Kind()[:2] == " __" { // reserve all Kinds starting with __
208 return false
209 }
210 if k.Kind() == "" || k.AppID() == "" {
211 return false
212 }
213 if k.StringID() != "" && k.IntID() != 0 {
214 return false
215 }
216 if k.Parent() != nil {
217 if k.Parent().Incomplete() {
218 return false
219 }
220 if k.Parent().AppID() != k.AppID() || k.Parent().Namespa ce() != k.Namespace() {
221 return false
222 }
223 }
224 }
225 return true
226 }
227
228 // KeyCouldBeValid is like KeyValid, but it allows for the possibility that the
229 // last token of the key is Incomplete(). It returns true if the Key will become
230 // valid once it recieves an automatically-assigned ID.
231 func KeyCouldBeValid(ns string, k *datastore.Key, opt keyValidOption) bool {
232 // adds an id to k if it's incomplete.
233 testKey := k
M-A Ruel 2015/05/29 02:01:23 Remove
234 if k.Incomplete() {
235 testKey = newKey(ns, k.Kind(), "", 1, k.Parent())
M-A Ruel 2015/05/29 02:01:23 k = newKey(ns, k.Kind(), "", 1, k.Parent())
236 }
237 return KeyValid(ns, testKey, opt)
M-A Ruel 2015/05/29 02:01:23 return KeyValid(ns, k, opt)
iannucci 2015/05/29 02:42:28 done
238 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698