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

Side by Side Diff: logdog/common/storage/bigtable/testing.go

Issue 2607663002: Add treapstore, a treap-based in-memory data store (Closed)
Patch Set: Fix test race, better docs, valid zero values. 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 unified diff | Download patch
« no previous file with comments | « common/data/treapstore/store_test.go ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The LUCI Authors. All rights reserved. 1 // Copyright 2016 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0 2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file. 3 // that can be found in the LICENSE file.
4 4
5 package bigtable 5 package bigtable
6 6
7 import ( 7 import (
8 "bytes" 8 "bytes"
9 "fmt" 9 "fmt"
10 "time" 10 "time"
11 11
12 "github.com/luci/gkvlite"
13
14 "github.com/luci/luci-go/common/data/recordio" 12 "github.com/luci/luci-go/common/data/recordio"
13 "github.com/luci/luci-go/common/data/treapstore"
15 "github.com/luci/luci-go/logdog/common/storage" 14 "github.com/luci/luci-go/logdog/common/storage"
16 15
17 "golang.org/x/net/context" 16 "golang.org/x/net/context"
18 ) 17 )
19 18
19 type storageItem struct {
20 key []byte
21 value []byte
22 }
23
20 // btTableTest is an in-memory implementation of btTable interface for testing. 24 // btTableTest is an in-memory implementation of btTable interface for testing.
21 // 25 //
22 // This is a simple implementation; not an efficient one. 26 // This is a simple implementation; not an efficient one.
23 type btTableTest struct { 27 type btTableTest struct {
24 » s *gkvlite.Store 28 » s *treapstore.Store
25 » c *gkvlite.Collection 29 » c *treapstore.Collection
26 30
27 // err, if true, is the error immediately returned by functions. 31 // err, if true, is the error immediately returned by functions.
28 err error 32 err error
29 33
30 // maxLogAge is the currently-configured maximum log age. 34 // maxLogAge is the currently-configured maximum log age.
31 maxLogAge time.Duration 35 maxLogAge time.Duration
32 } 36 }
33 37
34 // Testing is an extension of storage.Storage with additional testing 38 // Testing is an extension of storage.Storage with additional testing
35 // capabilities. 39 // capabilities.
36 type Testing interface { 40 type Testing interface {
37 storage.Storage 41 storage.Storage
38 42
39 DataMap() map[string][]byte 43 DataMap() map[string][]byte
40 SetMaxRowSize(int) 44 SetMaxRowSize(int)
41 SetErr(error) 45 SetErr(error)
42 MaxLogAge() time.Duration 46 MaxLogAge() time.Duration
43 } 47 }
44 48
45 type btTestingStorage struct { 49 type btTestingStorage struct {
46 *btStorage 50 *btStorage
47 mem *btTableTest 51 mem *btTableTest
48 } 52 }
49 53
50 func (st *btTestingStorage) Close() {
51 // Override Close to make sure our gkvlite instance is closed.
52 st.mem.close()
53 st.btStorage.Close()
54 }
55
56 func (st *btTestingStorage) DataMap() map[string][]byte { return st.mem.dataMap( ) } 54 func (st *btTestingStorage) DataMap() map[string][]byte { return st.mem.dataMap( ) }
57 func (st *btTestingStorage) SetMaxRowSize(v int) { st.maxRowSize = v } 55 func (st *btTestingStorage) SetMaxRowSize(v int) { st.maxRowSize = v }
58 func (st *btTestingStorage) SetErr(err error) { st.mem.err = err } 56 func (st *btTestingStorage) SetErr(err error) { st.mem.err = err }
59 func (st *btTestingStorage) MaxLogAge() time.Duration { return st.mem.maxLogAg e } 57 func (st *btTestingStorage) MaxLogAge() time.Duration { return st.mem.maxLogAg e }
60 58
61 // NewMemoryInstance returns an in-memory BigTable Storage implementation. 59 // NewMemoryInstance returns an in-memory BigTable Storage implementation.
62 // This can be supplied in the Raw field in Options to simulate a BigTable 60 // This can be supplied in the Raw field in Options to simulate a BigTable
63 // connection. 61 // connection.
64 // 62 //
65 // Close should be called on the resulting value after the user is finished in 63 // Close should be called on the resulting value after the user is finished in
66 // order to free resources. 64 // order to free resources.
67 func NewMemoryInstance(c context.Context, opts Options) Testing { 65 func NewMemoryInstance(c context.Context, opts Options) Testing {
68 mem := &btTableTest{} 66 mem := &btTableTest{}
69 base := newBTStorage(c, opts, nil, nil, mem) 67 base := newBTStorage(c, opts, nil, nil, mem)
70 return &btTestingStorage{ 68 return &btTestingStorage{
71 btStorage: base, 69 btStorage: base,
72 mem: mem, 70 mem: mem,
73 } 71 }
74 } 72 }
75 73
76 func (t *btTableTest) close() { 74 func (t *btTableTest) close() {
77 » if t.s != nil { 75 » t.s = nil
78 » » t.s.Close() 76 » t.c = nil
79 » » t.s = nil
80 » }
81 } 77 }
82 78
83 func (t *btTableTest) collection() *gkvlite.Collection { 79 func (t *btTableTest) collection() *treapstore.Collection {
84 if t.s == nil { 80 if t.s == nil {
85 » » var err error 81 » » t.s = treapstore.New()
86 » » t.s, err = gkvlite.NewStore(nil) 82 » » t.c = t.s.CreateCollection("", func(a, b interface{}) int {
87 » » if err != nil { 83 » » » return bytes.Compare(a.(*storageItem).key, b.(*storageIt em).key)
88 » » » panic(err) 84 » » })
89 » » }
90 » » t.c = t.s.MakePrivateCollection(bytes.Compare)
91 } 85 }
92 return t.c 86 return t.c
93 } 87 }
94 88
95 func (t *btTableTest) putLogData(c context.Context, rk *rowKey, d []byte) error { 89 func (t *btTableTest) putLogData(c context.Context, rk *rowKey, d []byte) error {
96 if t.err != nil { 90 if t.err != nil {
97 return t.err 91 return t.err
98 } 92 }
99 93
100 // Record/count sanity check. 94 // Record/count sanity check.
101 records, err := recordio.Split(d) 95 records, err := recordio.Split(d)
102 if err != nil { 96 if err != nil {
103 return err 97 return err
104 } 98 }
105 if int64(len(records)) != rk.count { 99 if int64(len(records)) != rk.count {
106 return fmt.Errorf("count mismatch (%d != %d)", len(records), rk. count) 100 return fmt.Errorf("count mismatch (%d != %d)", len(records), rk. count)
107 } 101 }
108 102
109 enc := []byte(rk.encode()) 103 enc := []byte(rk.encode())
110 coll := t.collection() 104 coll := t.collection()
111 » if item, _ := coll.Get(enc); item != nil { 105 » if item := coll.Get(&storageItem{enc, nil}); item != nil {
112 return storage.ErrExists 106 return storage.ErrExists
113 } 107 }
114 108
115 clone := make([]byte, len(d)) 109 clone := make([]byte, len(d))
116 copy(clone, d) 110 copy(clone, d)
117 » if err := coll.Set(enc, clone); err != nil { 111 » coll.Put(&storageItem{enc, clone})
118 » » panic(err) 112
113 » return nil
114 }
115
116 func (t *btTableTest) forEachItem(start []byte, cb func(k, v []byte) bool) {
117 » it := t.collection().Iterator(&storageItem{start, nil})
118 » for {
119 » » itm, ok := it.Next()
120 » » if !ok {
121 » » » return
122 » » }
123 » » ent := itm.(*storageItem)
124 » » if !cb(ent.key, ent.value) {
125 » » » return
126 » » }
119 } 127 }
120 return nil
121 } 128 }
122 129
123 func (t *btTableTest) getLogData(c context.Context, rk *rowKey, limit int, keysO nly bool, cb btGetCallback) error { 130 func (t *btTableTest) getLogData(c context.Context, rk *rowKey, limit int, keysO nly bool, cb btGetCallback) error {
124 if t.err != nil { 131 if t.err != nil {
125 return t.err 132 return t.err
126 } 133 }
127 134
128 enc := []byte(rk.encode()) 135 enc := []byte(rk.encode())
129 prefix := rk.pathPrefix() 136 prefix := rk.pathPrefix()
130 var ierr error 137 var ierr error
131 » err := t.collection().VisitItemsAscend(enc, !keysOnly, func(i *gkvlite.I tem) bool { 138
139 » t.forEachItem(enc, func(k, v []byte) bool {
132 var drk *rowKey 140 var drk *rowKey
133 » » drk, ierr = decodeRowKey(string(i.Key)) 141 » » drk, ierr = decodeRowKey(string(k))
134 if ierr != nil { 142 if ierr != nil {
135 return false 143 return false
136 } 144 }
137 if drk.pathPrefix() != prefix { 145 if drk.pathPrefix() != prefix {
138 return false 146 return false
139 } 147 }
140 148
141 » » rowData := i.Val 149 » » rowData := v
142 if keysOnly { 150 if keysOnly {
143 rowData = nil 151 rowData = nil
144 } 152 }
145 153
146 if ierr = cb(drk, rowData); ierr != nil { 154 if ierr = cb(drk, rowData); ierr != nil {
147 if ierr == errStop { 155 if ierr == errStop {
148 ierr = nil 156 ierr = nil
149 } 157 }
150 return false 158 return false
151 } 159 }
152 160
153 if limit > 0 { 161 if limit > 0 {
154 limit-- 162 limit--
155 if limit == 0 { 163 if limit == 0 {
156 return false 164 return false
157 } 165 }
158 } 166 }
159 167
160 return true 168 return true
161 }) 169 })
162 if err != nil {
163 panic(err)
164 }
165 return ierr 170 return ierr
166 } 171 }
167 172
168 func (t *btTableTest) setMaxLogAge(c context.Context, d time.Duration) error { 173 func (t *btTableTest) setMaxLogAge(c context.Context, d time.Duration) error {
169 if t.err != nil { 174 if t.err != nil {
170 return t.err 175 return t.err
171 } 176 }
172 t.maxLogAge = d 177 t.maxLogAge = d
173 return nil 178 return nil
174 } 179 }
175 180
176 func (t *btTableTest) dataMap() map[string][]byte { 181 func (t *btTableTest) dataMap() map[string][]byte {
177 result := map[string][]byte{} 182 result := map[string][]byte{}
178 183
179 » err := t.collection().VisitItemsAscend([]byte(nil), true, func(i *gkvlit e.Item) bool { 184 » t.forEachItem(nil, func(k, v []byte) bool {
180 » » result[string(i.Key)] = i.Val 185 » » result[string(k)] = v
181 return true 186 return true
182 }) 187 })
183 if err != nil {
184 panic(err)
185 }
186 return result 188 return result
187 } 189 }
OLDNEW
« no previous file with comments | « common/data/treapstore/store_test.go ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698