github.com/petermattis/pebble@v0.0.0-20190905164901-ab51a2166067/ptable/table_test.go (about) 1 // Copyright 2018 The LevelDB-Go and Pebble Authors. All rights reserved. Use 2 // of this source code is governed by a BSD-style license that can be found in 3 // the LICENSE file. 4 5 package ptable 6 7 import ( 8 "fmt" 9 "sort" 10 "testing" 11 "time" 12 13 "github.com/petermattis/pebble/cache" 14 "github.com/petermattis/pebble/internal/base" 15 "github.com/petermattis/pebble/vfs" 16 "golang.org/x/exp/rand" 17 ) 18 19 type testEnv []ColumnDef 20 21 func (e testEnv) Encode(row RowReader, buf []byte) (key, value []byte) { 22 for i := range e { 23 if row.Null(i) { 24 continue 25 } 26 switch e[i].Type { 27 case ColumnTypeInt64: 28 key = append(key, []byte(fmt.Sprintf("%08d", row.Int64(i)))...) 29 default: 30 panic("not reached") 31 } 32 } 33 34 return key, nil 35 } 36 37 func (e testEnv) Decode(key, value, buf []byte, writer RowWriter) { 38 } 39 40 func newEnv(schema ...ColumnDef) *Env { 41 t := testEnv(schema) 42 return &Env{ 43 Schema: schema, 44 Encode: t.Encode, 45 Decode: t.Decode, 46 } 47 } 48 49 type testRow []interface{} 50 51 func makeRow(cols ...interface{}) testRow { 52 return testRow(cols) 53 } 54 55 func (r testRow) Null(col int) bool { 56 return r[col] == nil 57 } 58 59 func (r testRow) Bool(col int) bool { 60 return r[col].(bool) 61 } 62 63 func (r testRow) Int8(col int) int8 { 64 return r[col].(int8) 65 } 66 67 func (r testRow) Int16(col int) int16 { 68 return r[col].(int16) 69 } 70 71 func (r testRow) Int32(col int) int32 { 72 return r[col].(int32) 73 } 74 75 func (r testRow) Int64(col int) int64 { 76 return r[col].(int64) 77 } 78 79 func (r testRow) Float32(col int) float32 { 80 return r[col].(float32) 81 } 82 83 func (r testRow) Float64(col int) float64 { 84 return r[col].(float64) 85 } 86 87 func (r testRow) Bytes(col int) []byte { 88 switch t := r[col].(type) { 89 case []byte: 90 return t 91 case string: 92 return []byte(t) 93 default: 94 panic("not reached") 95 } 96 } 97 98 func TestTable(t *testing.T) { 99 const count int64 = 1000 100 mem := vfs.NewMem() 101 env := newEnv(ColumnDef{Type: ColumnTypeInt64}) 102 103 { 104 f, err := mem.Create("test") 105 if err != nil { 106 t.Fatal(err) 107 } 108 w := NewWriter(f, env, nil, &base.LevelOptions{BlockSize: 100}) 109 for i := int64(0); i < count; i++ { 110 if err := w.AddRow(makeRow(i)); err != nil { 111 t.Fatal(err) 112 } 113 } 114 if err := w.Close(); err != nil { 115 t.Fatal(err) 116 } 117 } 118 119 { 120 f, err := mem.Open("test") 121 if err != nil { 122 t.Fatal(err) 123 } 124 r := NewReader(f, 0, nil) 125 iter := r.NewIter() 126 var j int64 127 for iter.First(); iter.Valid(); iter.Next() { 128 col := iter.Block().Column(0).Int64() 129 for _, i := range col { 130 if j != i { 131 t.Fatalf("expected %d, but found %d", j, i) 132 } 133 j++ 134 } 135 } 136 if count != j { 137 t.Fatalf("expected %d, but found %d", count, j) 138 } 139 140 for i := int64(0); i < count; i++ { 141 key, _ := env.Encode(makeRow(i), nil) 142 iter.SeekGE(key) 143 if !iter.Valid() { 144 t.Fatal("expected valid iterator") 145 } 146 var found bool 147 for _, v := range iter.Block().Column(0).Int64() { 148 if i == v { 149 found = true 150 break 151 } 152 } 153 if !found { 154 t.Fatalf("unable to find %d on block %d", i, iter.pos) 155 } 156 } 157 158 if err := r.Close(); err != nil { 159 t.Fatal(err) 160 } 161 } 162 } 163 164 func buildBenchmarkTable(b *testing.B, blockSize int, nullValues bool) (*Reader, [][]byte) { 165 mem := vfs.NewMem() 166 f0, err := mem.Create("bench") 167 if err != nil { 168 b.Fatal(err) 169 } 170 defer f0.Close() 171 172 env := newEnv(ColumnDef{Type: ColumnTypeInt64}, ColumnDef{Type: ColumnTypeInt64}) 173 w := NewWriter(f0, env, nil, &base.LevelOptions{BlockSize: blockSize}) 174 var keys [][]byte 175 for i := int64(0); i < 1e6; i++ { 176 var r testRow 177 if nullValues && (i%2) == 0 { 178 r = makeRow(i, nil) 179 } else { 180 r = makeRow(i, i) 181 } 182 w.AddRow(r) 183 key, _ := env.Encode(r, nil) 184 keys = append(keys, key) 185 } 186 if err := w.Close(); err != nil { 187 b.Fatal(err) 188 } 189 190 // Re-open that filename for reading. 191 f1, err := mem.Open("bench") 192 if err != nil { 193 b.Fatal(err) 194 } 195 return NewReader(f1, 0, &base.Options{ 196 Cache: cache.New(128 << 20), 197 }), keys 198 } 199 200 func BenchmarkTableIterSeekGE(b *testing.B) { 201 const blockSize = 32 << 10 202 203 r, keys := buildBenchmarkTable(b, blockSize, false /* NULL values */) 204 it := r.NewIter() 205 rng := rand.New(rand.NewSource(uint64(time.Now().UnixNano()))) 206 207 b.ResetTimer() 208 for i := 0; i < b.N; i++ { 209 v := int64(rng.Intn(len(keys))) 210 it.SeekGE(keys[v]) 211 if !it.Valid() { 212 b.Fatalf("unable to find block containing %d", v) 213 } 214 vals := it.Block().Column(0).Int64() 215 index := sort.Search(len(vals), func(j int) bool { 216 return vals[j] >= v 217 }) 218 if vals[index] != v { 219 b.Fatalf("unable to find %d", v) 220 } 221 } 222 } 223 224 func BenchmarkTableIterNext(b *testing.B) { 225 const blockSize = 32 << 10 226 227 r, _ := buildBenchmarkTable(b, blockSize, true /* NULL values */) 228 it := r.NewIter() 229 230 b.ResetTimer() 231 var sum int64 232 for i, k := 0, 0; i < b.N; i += k { 233 if !it.Valid() { 234 it.First() 235 } 236 237 col := it.Block().Column(1) 238 vals := col.Int64() 239 k = int(col.N) 240 if k > b.N-i { 241 k = b.N - i 242 } 243 for j := 0; j < k; j++ { 244 if r := col.Rank(j); r >= 0 { 245 sum += vals[r] 246 } 247 } 248 249 it.Next() 250 } 251 if testing.Verbose() { 252 fmt.Println(sum) 253 } 254 } 255 256 func BenchmarkTableIterPrev(b *testing.B) { 257 const blockSize = 32 << 10 258 259 r, _ := buildBenchmarkTable(b, blockSize, true /* NULL values */) 260 it := r.NewIter() 261 262 b.ResetTimer() 263 var sum int64 264 for i, k := 0, 0; i < b.N; i += k { 265 if !it.Valid() { 266 it.Last() 267 } 268 269 col := it.Block().Column(1) 270 vals := col.Int64() 271 k = int(col.N) 272 if k > b.N-i { 273 k = b.N - i 274 } 275 for j, e := int(col.N)-1, int(col.N)-k; j >= e; j-- { 276 if r := col.Rank(j); r >= 0 { 277 sum += vals[r] 278 } 279 } 280 281 it.Prev() 282 } 283 if testing.Verbose() { 284 fmt.Println(sum) 285 } 286 }