1
2
3
4
5
6
7 package leveldb
8
9 import (
10 "bytes"
11 "fmt"
12 "math/rand"
13 "testing"
14 "testing/quick"
15
16 "github.com/syndtr/goleveldb/leveldb/testutil"
17 )
18
19 func TestBatchHeader(t *testing.T) {
20 f := func(seq uint64, length uint32) bool {
21 encoded := encodeBatchHeader(nil, seq, int(length))
22 decSeq, decLength, err := decodeBatchHeader(encoded)
23 return err == nil && decSeq == seq && decLength == int(length)
24 }
25 config := &quick.Config{
26 Rand: testutil.NewRand(),
27 }
28 if err := quick.Check(f, config); err != nil {
29 t.Error(err)
30 }
31 }
32
33 type batchKV struct {
34 kt keyType
35 k, v []byte
36 }
37
38 func TestBatch(t *testing.T) {
39 var (
40 kvs []batchKV
41 internalLen int
42 )
43 batch := new(Batch)
44 rbatch := new(Batch)
45 abatch := new(Batch)
46 testBatch := func(i int, kt keyType, k, v []byte) error {
47 kv := kvs[i]
48 if kv.kt != kt {
49 return fmt.Errorf("invalid key type, index=%d: %d vs %d", i, kv.kt, kt)
50 }
51 if !bytes.Equal(kv.k, k) {
52 return fmt.Errorf("invalid key, index=%d", i)
53 }
54 if !bytes.Equal(kv.v, v) {
55 return fmt.Errorf("invalid value, index=%d", i)
56 }
57 return nil
58 }
59 f := func(ktr uint8, k, v []byte) bool {
60 kt := keyType(ktr % 2)
61 if kt == keyTypeVal {
62 batch.Put(k, v)
63 rbatch.Put(k, v)
64 kvs = append(kvs, batchKV{kt: kt, k: k, v: v})
65 internalLen += len(k) + len(v) + 8
66 } else {
67 batch.Delete(k)
68 rbatch.Delete(k)
69 kvs = append(kvs, batchKV{kt: kt, k: k})
70 internalLen += len(k) + 8
71 }
72 if batch.Len() != len(kvs) {
73 t.Logf("batch.Len: %d vs %d", len(kvs), batch.Len())
74 return false
75 }
76 if batch.internalLen != internalLen {
77 t.Logf("abatch.internalLen: %d vs %d", internalLen, batch.internalLen)
78 return false
79 }
80 if len(kvs)%1000 == 0 {
81 if err := batch.replayInternal(testBatch); err != nil {
82 t.Logf("batch.replayInternal: %v", err)
83 return false
84 }
85
86 abatch.append(rbatch)
87 rbatch.Reset()
88 if abatch.Len() != len(kvs) {
89 t.Logf("abatch.Len: %d vs %d", len(kvs), abatch.Len())
90 return false
91 }
92 if abatch.internalLen != internalLen {
93 t.Logf("abatch.internalLen: %d vs %d", internalLen, abatch.internalLen)
94 return false
95 }
96 if err := abatch.replayInternal(testBatch); err != nil {
97 t.Logf("abatch.replayInternal: %v", err)
98 return false
99 }
100
101 nbatch := new(Batch)
102 if err := nbatch.Load(batch.Dump()); err != nil {
103 t.Logf("nbatch.Load: %v", err)
104 return false
105 }
106 if nbatch.Len() != len(kvs) {
107 t.Logf("nbatch.Len: %d vs %d", len(kvs), nbatch.Len())
108 return false
109 }
110 if nbatch.internalLen != internalLen {
111 t.Logf("nbatch.internalLen: %d vs %d", internalLen, nbatch.internalLen)
112 return false
113 }
114 if err := nbatch.replayInternal(testBatch); err != nil {
115 t.Logf("nbatch.replayInternal: %v", err)
116 return false
117 }
118 }
119 if len(kvs)%10000 == 0 {
120 nbatch := new(Batch)
121 if err := batch.Replay(nbatch); err != nil {
122 t.Logf("batch.Replay: %v", err)
123 return false
124 }
125 if nbatch.Len() != len(kvs) {
126 t.Logf("nbatch.Len: %d vs %d", len(kvs), nbatch.Len())
127 return false
128 }
129 if nbatch.internalLen != internalLen {
130 t.Logf("nbatch.internalLen: %d vs %d", internalLen, nbatch.internalLen)
131 return false
132 }
133 if err := nbatch.replayInternal(testBatch); err != nil {
134 t.Logf("nbatch.replayInternal: %v", err)
135 return false
136 }
137 }
138 return true
139 }
140 config := &quick.Config{
141 MaxCount: 40000,
142 Rand: testutil.NewRand(),
143 }
144 if err := quick.Check(f, config); err != nil {
145 t.Error(err)
146 }
147 t.Logf("length=%d internalLen=%d", len(kvs), internalLen)
148 }
149
150 func BenchmarkDefaultBatchWrite(b *testing.B) {
151 benchmarkBatchWrite(b, nil)
152 }
153
154 func BenchmarkFastAllocationBatchWrite(b *testing.B) {
155 benchmarkBatchWrite(b, &BatchConfig{
156 GrowLimit: 10 * batchGrowLimit,
157 })
158 }
159
160 func benchmarkBatchWrite(b *testing.B, config *BatchConfig) {
161 var (
162 keys [][]byte
163 vals [][]byte
164 r = rand.New(rand.NewSource(1337))
165 )
166 for i := 0; i < 50000; i++ {
167 keys = append(keys, randomString(r, 32))
168 vals = append(vals, randomString(r, 100))
169 }
170 b.ResetTimer()
171 for round := 0; round < b.N; round++ {
172 batch := MakeBatchWithConfig(config)
173 for i := 0; i < len(keys); i++ {
174 batch.Put(keys[i], vals[i])
175 }
176 }
177 b.ReportAllocs()
178 }
179
View as plain text