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

Side by Side Diff: common/data/treapstore/store_test.go

Issue 2607663002: Add treapstore, a treap-based in-memory data store (Closed)
Patch Set: Use treapstore for LogDog BigTable testing. 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
OLDNEW
(Empty)
1 // Copyright 2016 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file.
4
5 package treapstore
6
7 import (
8 "fmt"
9 "strconv"
10 "strings"
11 "testing"
12
13 "github.com/luci/gtreap"
14
15 . "github.com/smartystreets/goconvey/convey"
16 )
17
18 func newStringStore() *Store {
19 return New(func(a, b interface{}) int {
20 return strings.Compare(a.(string), b.(string))
21 })
22 }
23
24 func iterAll(it *gtreap.Iterator) []string {
25 all := []string{}
26 for {
27 v, ok := it.Next()
28 if !ok {
29 return all
30 }
31 all = append(all, v.(string))
32 }
33 }
34
35 func TestStore(t *testing.T) {
36 t.Parallel()
37
38 Convey(`Testing a string Store`, t, func() {
39 st := newStringStore()
40 st.GetOrCreateCollection("")
41
42 Convey(`When empty`, func() {
43 checkEmpty := func(c *Collection) {
44 So(c.Get("foo"), ShouldBeNil)
45 So(iterAll(c.Iterator("")), ShouldResemble, []st ring{})
46 }
47
48 // Check the basic Store.
49 checkEmpty(st.GetCollection(""))
50
51 // Take a snapshot, then mutate the base Store. Assert t hat the snapshot
52 // is still empty.
53 snap := st.Snapshot()
54 st.GetCollection("").Put("foo")
55 checkEmpty(snap.GetCollection(""))
56 })
57
58 Convey(`With keys`, func() {
59 coll := st.GetCollection("")
60 coll.Put("a")
61 coll.Put("b")
62 coll.Put("z")
63
64 checkKeys := func(coll *Collection, keys ...string) {
65 for _, k := range keys {
66 So(coll.Get(k), ShouldEqual, k)
67 }
68
69 So(iterAll(coll.Iterator("")), ShouldResemble, k eys)
70 for i, k := range keys {
71 So(iterAll(coll.Iterator(k)), ShouldRese mble, keys[i:])
72 So(iterAll(coll.Iterator(k+"1")), Should Resemble, keys[i+1:])
73 }
74 }
75 checkKeys(coll, "a", "b", "z")
76
77 // Take a snapshot, then mutate the base Store. Assert t hat the snapshot
78 // is still empty.
79 snap := st.Snapshot()
80 snapColl := snap.GetCollection("")
81 coll.Put("foo")
82 checkKeys(snapColl, "a", "b", "z")
83 checkKeys(coll, "a", "b", "foo", "z")
84 })
85 })
86 }
87
88 // TestStoreParallel performs several rounds of parallel accesses. Each round
89 // takes a snapshot of the "head" Store, then simultaneusly dispatches a round
90 // of parallel writes agains the "head" store, reads against the snapshot, and
91 // reads against the "head" store.
92 //
93 // This is meant to be run with "-race" to trigger on race conditions.
94 func TestStoreParallel(t *testing.T) {
95 t.Parallel()
96
97 Convey(`Testing a string Store for parallel access.`, t, func() {
98 const (
99 readers = 128
100 writers = 16
101 rounds = 8
102 )
103
104 head := newStringStore()
105 var snaps []*Store
106
107 // Dispatch readers.
108 doReads := func() int {
109 readDoneC := make(chan int, readers)
110 for i := 0; i < readers; i++ {
111 go func() {
112 var (
113 doneC = make(chan int, 1+len(sna ps))
114 )
115
116 // "head"
117 go func() {
118 doneC <- len(iterAll(head.GetCol lection("").Iterator("")))
119 }()
120
121 // "snap"
122 for _, snap := range snaps {
123 go func(snap *Store) {
124 doneC <- len(iterAll(sna p.GetCollection("").Iterator("")))
125 }(snap)
126 }
127
128 total := 0
129 for i := 0; i < 1+len(snaps); i++ {
130 total += <-doneC
131 }
132 readDoneC <- total
133 }()
134 }
135
136 total := 0
137 for i := 0; i < readers; i++ {
138 total += <-readDoneC
139 }
140 return total
141 }
142
143 // Dispatch writers.
144 doWrite := func(base string) {
145 writeDoneC := make(chan struct{}, writers)
146 for i := 0; i < writers; i++ {
147 go func(idx int) {
148 head.GetOrCreateCollection("").Put(fmt.S printf("%s.%d", base, idx))
149 writeDoneC <- struct{}{}
150 }(i)
151 }
152
153 for i := 0; i < writers; i++ {
154 <-writeDoneC
155 }
156 }
157
158 // Main loop.
159 for i := 0; i < rounds; i++ {
160 writeDoneC := make(chan struct{})
161 readDoneC := make(chan int)
162 go func() {
163 doWrite(strconv.Itoa(i))
164 close(writeDoneC)
165 }()
166 if i > 0 {
167 // The first round has to actually create the Co llection.
168 go func() {
169 readDoneC <- doReads()
170 }()
171 }
172
173 <-writeDoneC
174 if i > 0 {
175 So(<-readDoneC, ShouldBeGreaterThan, 0)
176 }
177 snaps = append(snaps, head.Snapshot())
178 }
179 })
180 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698