blob: 43dc254e50c714a2b834ffc15d488a5218c33efa [file] [log] [blame]
Manish R Jain02eca142018-12-30 19:35:111/*
2 * Copyright 2018 Dgraph Labs, Inc. and Contributors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package badger
18
19import (
20 "context"
21 "fmt"
22 "io/ioutil"
23 "math"
Manish R Jain02eca142018-12-30 19:35:1124 "strconv"
25 "strings"
26 "testing"
27
aman bansalb69163b2021-01-13 05:25:3728 "github.com/dgraph-io/badger/v3/pb"
29 bpb "github.com/dgraph-io/badger/v3/pb"
30 "github.com/dgraph-io/badger/v3/y"
Manish R Jainab8b5d92020-11-25 18:44:3131 "github.com/dgraph-io/ristretto/z"
Manish R Jain8d26d522020-10-13 21:31:3132 "github.com/golang/protobuf/proto"
Manish R Jain02eca142018-12-30 19:35:1133 "github.com/stretchr/testify/require"
34)
35
Manish R Jain02eca142018-12-30 19:35:1136func keyWithPrefix(prefix string, k int) []byte {
37 return []byte(fmt.Sprintf("%s-%d", prefix, k))
38}
39
40func keyToInt(k []byte) (string, int) {
41 splits := strings.Split(string(k), "-")
42 key, err := strconv.Atoi(splits[1])
43 y.Check(err)
44 return splits[0], key
45}
46
47func value(k int) []byte {
48 return []byte(fmt.Sprintf("%08d", k))
49}
50
51type collector struct {
52 kv []*bpb.KV
53}
54
Manish R Jainab8b5d92020-11-25 18:44:3155func (c *collector) Send(buf *z.Buffer) error {
56 list, err := BufferToKVList(buf)
57 if err != nil {
58 return err
59 }
Manish R Jain8d26d522020-10-13 21:31:3160 for _, kv := range list.Kv {
61 if kv.StreamDone == true {
Manish R Jainab8b5d92020-11-25 18:44:3162 return nil
Manish R Jain8d26d522020-10-13 21:31:3163 }
64 cp := proto.Clone(kv).(*bpb.KV)
65 c.kv = append(c.kv, cp)
66 }
Manish R Jainab8b5d92020-11-25 18:44:3167 return err
Manish R Jain02eca142018-12-30 19:35:1168}
69
70var ctxb = context.Background()
71
72func TestStream(t *testing.T) {
Ashish Goswami8c85c272019-06-19 08:21:2273 dir, err := ioutil.TempDir("", "badger-test")
Manish R Jain02eca142018-12-30 19:35:1174 require.NoError(t, err)
Ibrahim Jarif00039ea2019-10-17 13:02:3275 defer removeDir(dir)
Manish R Jain02eca142018-12-30 19:35:1176
Francesc Campoy2bb87c02019-06-24 21:57:5677 db, err := OpenManaged(DefaultOptions(dir))
Manish R Jain02eca142018-12-30 19:35:1178 require.NoError(t, err)
79
80 var count int
81 for _, prefix := range []string{"p0", "p1", "p2"} {
82 txn := db.NewTransactionAt(math.MaxUint64, true)
83 for i := 1; i <= 100; i++ {
Ashish Goswamie9447c92019-05-28 05:28:3784 require.NoError(t, txn.SetEntry(NewEntry(keyWithPrefix(prefix, i), value(i))))
Manish R Jain02eca142018-12-30 19:35:1185 count++
86 }
87 require.NoError(t, txn.CommitAt(5, nil))
88 }
89
90 stream := db.NewStreamAt(math.MaxUint64)
91 stream.LogPrefix = "Testing"
92 c := &collector{}
Martin Martinez Riverac8922512020-07-13 18:29:3893 stream.Send = c.Send
Manish R Jain02eca142018-12-30 19:35:1194
95 // Test case 1. Retrieve everything.
96 err = stream.Orchestrate(ctxb)
97 require.NoError(t, err)
98 require.Equal(t, 300, len(c.kv), "Expected 300. Got: %d", len(c.kv))
99
100 m := make(map[string]int)
101 for _, kv := range c.kv {
102 prefix, ki := keyToInt(kv.Key)
103 expected := value(ki)
104 require.Equal(t, expected, kv.Value)
105 m[prefix]++
106 }
107 require.Equal(t, 3, len(m))
108 for pred, count := range m {
109 require.Equal(t, 100, count, "Count mismatch for pred: %s", pred)
110 }
111
112 // Test case 2. Retrieve only 1 predicate.
113 stream.Prefix = []byte("p1")
114 c.kv = c.kv[:0]
115 err = stream.Orchestrate(ctxb)
116 require.NoError(t, err)
117 require.Equal(t, 100, len(c.kv), "Expected 100. Got: %d", len(c.kv))
118
119 m = make(map[string]int)
120 for _, kv := range c.kv {
121 prefix, ki := keyToInt(kv.Key)
122 expected := value(ki)
123 require.Equal(t, expected, kv.Value)
124 m[prefix]++
125 }
126 require.Equal(t, 1, len(m))
127 for pred, count := range m {
128 require.Equal(t, 100, count, "Count mismatch for pred: %s", pred)
129 }
130
131 // Test case 3. Retrieve select keys within the predicate.
132 c.kv = c.kv[:0]
133 stream.ChooseKey = func(item *Item) bool {
134 _, k := keyToInt(item.Key())
135 return k%2 == 0
136 }
137 err = stream.Orchestrate(ctxb)
138 require.NoError(t, err)
139 require.Equal(t, 50, len(c.kv), "Expected 50. Got: %d", len(c.kv))
140
141 m = make(map[string]int)
142 for _, kv := range c.kv {
143 prefix, ki := keyToInt(kv.Key)
144 expected := value(ki)
145 require.Equal(t, expected, kv.Value)
146 m[prefix]++
147 }
148 require.Equal(t, 1, len(m))
149 for pred, count := range m {
150 require.Equal(t, 50, count, "Count mismatch for pred: %s", pred)
151 }
152
153 // Test case 4. Retrieve select keys from all predicates.
154 c.kv = c.kv[:0]
155 stream.Prefix = []byte{}
156 err = stream.Orchestrate(ctxb)
157 require.NoError(t, err)
158 require.Equal(t, 150, len(c.kv), "Expected 150. Got: %d", len(c.kv))
159
160 m = make(map[string]int)
161 for _, kv := range c.kv {
162 prefix, ki := keyToInt(kv.Key)
163 expected := value(ki)
164 require.Equal(t, expected, kv.Value)
165 m[prefix]++
166 }
167 require.Equal(t, 3, len(m))
168 for pred, count := range m {
169 require.Equal(t, 50, count, "Count mismatch for pred: %s", pred)
170 }
Ibrahim Jarif00039ea2019-10-17 13:02:32171 require.NoError(t, db.Close())
Manish R Jain02eca142018-12-30 19:35:11172}
Martin Martinez Rivera6eaa5002020-05-22 17:45:26173
174func TestStreamWithThreadId(t *testing.T) {
175 dir, err := ioutil.TempDir("", "badger-test")
176 require.NoError(t, err)
177 defer removeDir(dir)
178
179 db, err := OpenManaged(DefaultOptions(dir))
180 require.NoError(t, err)
181
182 var count int
183 for _, prefix := range []string{"p0", "p1", "p2"} {
184 txn := db.NewTransactionAt(math.MaxUint64, true)
185 for i := 1; i <= 100; i++ {
186 require.NoError(t, txn.SetEntry(NewEntry(keyWithPrefix(prefix, i), value(i))))
187 count++
188 }
189 require.NoError(t, txn.CommitAt(5, nil))
190 }
191
192 stream := db.NewStreamAt(math.MaxUint64)
193 stream.LogPrefix = "Testing"
194 stream.KeyToList = func(key []byte, itr *Iterator) (
195 *bpb.KVList, error) {
196 require.Less(t, itr.ThreadId, stream.NumGo)
197 return stream.ToList(key, itr)
198 }
199 c := &collector{}
Martin Martinez Riverac8922512020-07-13 18:29:38200 stream.Send = c.Send
Martin Martinez Rivera6eaa5002020-05-22 17:45:26201
202 err = stream.Orchestrate(ctxb)
203 require.NoError(t, err)
204 require.Equal(t, 300, len(c.kv), "Expected 300. Got: %d", len(c.kv))
205
206 m := make(map[string]int)
207 for _, kv := range c.kv {
208 prefix, ki := keyToInt(kv.Key)
209 expected := value(ki)
210 require.Equal(t, expected, kv.Value)
211 m[prefix]++
212 }
213 require.Equal(t, 3, len(m))
214 for pred, count := range m {
215 require.Equal(t, 100, count, "Count mismatch for pred: %s", pred)
216 }
217 require.NoError(t, db.Close())
218}
Martin Martinez Riverac8922512020-07-13 18:29:38219
220func TestBigStream(t *testing.T) {
Rahul Gurnani774a99d2020-11-02 23:39:09221 if !*manual {
222 t.Skip("Skipping test meant to be run manually.")
223 return
224 }
Martin Martinez Riverac8922512020-07-13 18:29:38225 // Set the maxStreamSize to 1MB for the duration of the test so that the it can use a smaller
226 // dataset than it would otherwise need.
227 originalMaxStreamSize := maxStreamSize
228 maxStreamSize = 1 << 20
229 defer func() {
230 maxStreamSize = originalMaxStreamSize
231 }()
232
233 testSize := int(1e6)
234 dir, err := ioutil.TempDir("", "badger-big-test")
235 require.NoError(t, err)
236 defer removeDir(dir)
237
238 db, err := OpenManaged(DefaultOptions(dir))
239 require.NoError(t, err)
240
241 var count int
242 wb := db.NewWriteBatchAt(5)
243 for _, prefix := range []string{"p0", "p1", "p2"} {
244 for i := 1; i <= testSize; i++ {
245 require.NoError(t, wb.SetEntry(NewEntry(keyWithPrefix(prefix, i), value(i))))
246 count++
247 }
248 }
249 require.NoError(t, wb.Flush())
250
251 stream := db.NewStreamAt(math.MaxUint64)
252 stream.LogPrefix = "Testing"
253 c := &collector{}
254 stream.Send = c.Send
255
256 // Test case 1. Retrieve everything.
257 err = stream.Orchestrate(ctxb)
258 require.NoError(t, err)
259 require.Equal(t, 3*testSize, len(c.kv), "Expected 30000. Got: %d", len(c.kv))
260
261 m := make(map[string]int)
262 for _, kv := range c.kv {
263 prefix, ki := keyToInt(kv.Key)
264 expected := value(ki)
265 require.Equal(t, expected, kv.Value)
266 m[prefix]++
267 }
268 require.Equal(t, 3, len(m))
269 for pred, count := range m {
270 require.Equal(t, testSize, count, "Count mismatch for pred: %s", pred)
271 }
272 require.NoError(t, db.Close())
273}
Manish R Jainb94b5612020-11-11 21:02:30274
275// There was a bug in the stream writer code which would cause allocators to be
276// freed up twice if the default keyToList was not used. This test verifies that issue.
277func TestStreamCustomKeyToList(t *testing.T) {
278 dir, err := ioutil.TempDir("", "badger-test")
279 require.NoError(t, err)
280 defer removeDir(dir)
281
282 db, err := OpenManaged(DefaultOptions(dir))
283 require.NoError(t, err)
284
285 var count int
286 for _, key := range []string{"p0", "p1", "p2"} {
287 for i := 1; i <= 100; i++ {
288 txn := db.NewTransactionAt(math.MaxUint64, true)
289 require.NoError(t, txn.SetEntry(NewEntry([]byte(key), value(i))))
290 count++
291 require.NoError(t, txn.CommitAt(uint64(i), nil))
292 }
293 }
294
295 stream := db.NewStreamAt(math.MaxUint64)
296 stream.LogPrefix = "Testing"
297 stream.KeyToList = func(key []byte, itr *Iterator) (*pb.KVList, error) {
298 item := itr.Item()
299 val, err := item.ValueCopy(nil)
300 if err != nil {
301 return nil, err
302 }
Manish R Jaina75cb552020-12-04 20:59:40303 kv := &pb.KV{
Manish R Jainb94b5612020-11-11 21:02:30304 Key: y.Copy(item.Key()),
305 Value: val,
306 }
307 return &pb.KVList{
308 Kv: []*pb.KV{kv},
309 }, nil
310 }
311 res := map[string]struct{}{"p0": {}, "p1": {}, "p2": {}}
Manish R Jainab8b5d92020-11-25 18:44:31312 stream.Send = func(buf *z.Buffer) error {
313 list, err := BufferToKVList(buf)
314 require.NoError(t, err)
Manish R Jainb94b5612020-11-11 21:02:30315 for _, kv := range list.Kv {
316 key := string(kv.Key)
317 if _, ok := res[key]; !ok {
318 panic(fmt.Sprintf("%s key not found", key))
319 }
320 delete(res, key)
321 }
322 return nil
323 }
324 require.NoError(t, stream.Orchestrate(ctxb))
325 require.Zero(t, len(res))
326}