|
|
// Copyright (c) 2014, Suryandaru Triandana <syndtr@gmail.com>
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package testutil
import ( "fmt" "math/rand" "sort" "strings"
"github.com/syndtr/goleveldb/leveldb/util" )
type KeyValueEntry struct { key, value []byte }
type KeyValue struct { entries []KeyValueEntry nbytes int }
func (kv *KeyValue) Put(key, value []byte) { if n := len(kv.entries); n > 0 && cmp.Compare(kv.entries[n-1].key, key) >= 0 { panic(fmt.Sprintf("Put: keys are not in increasing order: %q, %q", kv.entries[n-1].key, key)) } kv.entries = append(kv.entries, KeyValueEntry{key, value}) kv.nbytes += len(key) + len(value) }
func (kv *KeyValue) PutString(key, value string) { kv.Put([]byte(key), []byte(value)) }
func (kv *KeyValue) PutU(key, value []byte) bool { if i, exist := kv.Get(key); !exist { if i < kv.Len() { kv.entries = append(kv.entries[:i+1], kv.entries[i:]...) kv.entries[i] = KeyValueEntry{key, value} } else { kv.entries = append(kv.entries, KeyValueEntry{key, value}) } kv.nbytes += len(key) + len(value) return true } else { kv.nbytes += len(value) - len(kv.ValueAt(i)) kv.entries[i].value = value } return false }
func (kv *KeyValue) PutUString(key, value string) bool { return kv.PutU([]byte(key), []byte(value)) }
func (kv *KeyValue) Delete(key []byte) (exist bool, value []byte) { i, exist := kv.Get(key) if exist { value = kv.entries[i].value kv.DeleteIndex(i) } return }
func (kv *KeyValue) DeleteIndex(i int) bool { if i < kv.Len() { kv.nbytes -= len(kv.KeyAt(i)) + len(kv.ValueAt(i)) kv.entries = append(kv.entries[:i], kv.entries[i+1:]...) return true } return false }
func (kv KeyValue) Len() int { return len(kv.entries) }
func (kv *KeyValue) Size() int { return kv.nbytes }
func (kv KeyValue) KeyAt(i int) []byte { return kv.entries[i].key }
func (kv KeyValue) ValueAt(i int) []byte { return kv.entries[i].value }
func (kv KeyValue) Index(i int) (key, value []byte) { if i < 0 || i >= len(kv.entries) { panic(fmt.Sprintf("Index #%d: out of range", i)) } return kv.entries[i].key, kv.entries[i].value }
func (kv KeyValue) IndexInexact(i int) (key_, key, value []byte) { key, value = kv.Index(i) var key0 []byte var key1 = kv.KeyAt(i) if i > 0 { key0 = kv.KeyAt(i - 1) } key_ = BytesSeparator(key0, key1) return }
func (kv KeyValue) IndexOrNil(i int) (key, value []byte) { if i >= 0 && i < len(kv.entries) { return kv.entries[i].key, kv.entries[i].value } return nil, nil }
func (kv KeyValue) IndexString(i int) (key, value string) { key_, _value := kv.Index(i) return string(key_), string(_value) }
func (kv KeyValue) Search(key []byte) int { return sort.Search(kv.Len(), func(i int) bool { return cmp.Compare(kv.KeyAt(i), key) >= 0 }) }
func (kv KeyValue) SearchString(key string) int { return kv.Search([]byte(key)) }
func (kv KeyValue) Get(key []byte) (i int, exist bool) { i = kv.Search(key) if i < kv.Len() && cmp.Compare(kv.KeyAt(i), key) == 0 { exist = true } return }
func (kv KeyValue) GetString(key string) (i int, exist bool) { return kv.Get([]byte(key)) }
func (kv KeyValue) Iterate(fn func(i int, key, value []byte)) { for i, x := range kv.entries { fn(i, x.key, x.value) } }
func (kv KeyValue) IterateString(fn func(i int, key, value string)) { kv.Iterate(func(i int, key, value []byte) { fn(i, string(key), string(value)) }) }
func (kv KeyValue) IterateShuffled(rnd *rand.Rand, fn func(i int, key, value []byte)) { ShuffledIndex(rnd, kv.Len(), 1, func(i int) { fn(i, kv.entries[i].key, kv.entries[i].value) }) }
func (kv KeyValue) IterateShuffledString(rnd *rand.Rand, fn func(i int, key, value string)) { kv.IterateShuffled(rnd, func(i int, key, value []byte) { fn(i, string(key), string(value)) }) }
func (kv KeyValue) IterateInexact(fn func(i int, key_, key, value []byte)) { for i := range kv.entries { key_, key, value := kv.IndexInexact(i) fn(i, key_, key, value) } }
func (kv KeyValue) IterateInexactString(fn func(i int, key_, key, value string)) { kv.IterateInexact(func(i int, key_, key, value []byte) { fn(i, string(key_), string(key), string(value)) }) }
func (kv KeyValue) Clone() KeyValue { return KeyValue{append([]KeyValueEntry{}, kv.entries...), kv.nbytes} }
func (kv KeyValue) Slice(start, limit int) KeyValue { if start < 0 || limit > kv.Len() { panic(fmt.Sprintf("Slice %d .. %d: out of range", start, limit)) } else if limit < start { panic(fmt.Sprintf("Slice %d .. %d: invalid range", start, limit)) } return KeyValue{append([]KeyValueEntry{}, kv.entries[start:limit]...), kv.nbytes} }
func (kv KeyValue) SliceKey(start, limit []byte) KeyValue { start_ := 0 limit_ := kv.Len() if start != nil { start_ = kv.Search(start) } if limit != nil { limit_ = kv.Search(limit) } return kv.Slice(start_, limit_) }
func (kv KeyValue) SliceKeyString(start, limit string) KeyValue { return kv.SliceKey([]byte(start), []byte(limit)) }
func (kv KeyValue) SliceRange(r *util.Range) KeyValue { if r != nil { return kv.SliceKey(r.Start, r.Limit) } return kv.Clone() }
func (kv KeyValue) Range(start, limit int) (r util.Range) { if kv.Len() > 0 { if start == kv.Len() { r.Start = BytesAfter(kv.KeyAt(start - 1)) } else { r.Start = kv.KeyAt(start) } } if limit < kv.Len() { r.Limit = kv.KeyAt(limit) } return }
func KeyValue_EmptyKey() *KeyValue { kv := &KeyValue{} kv.PutString("", "v") return kv }
func KeyValue_EmptyValue() *KeyValue { kv := &KeyValue{} kv.PutString("abc", "") kv.PutString("abcd", "") return kv }
func KeyValue_OneKeyValue() *KeyValue { kv := &KeyValue{} kv.PutString("abc", "v") return kv }
func KeyValue_BigValue() *KeyValue { kv := &KeyValue{} kv.PutString("big1", strings.Repeat("1", 200000)) return kv }
func KeyValue_SpecialKey() *KeyValue { kv := &KeyValue{} kv.PutString("\xff\xff", "v3") return kv }
func KeyValue_MultipleKeyValue() *KeyValue { kv := &KeyValue{} kv.PutString("a", "v") kv.PutString("aa", "v1") kv.PutString("aaa", "v2") kv.PutString("aaacccccccccc", "v2") kv.PutString("aaaccccccccccd", "v3") kv.PutString("aaaccccccccccf", "v4") kv.PutString("aaaccccccccccfg", "v5") kv.PutString("ab", "v6") kv.PutString("abc", "v7") kv.PutString("abcd", "v8") kv.PutString("accccccccccccccc", "v9") kv.PutString("b", "v10") kv.PutString("bb", "v11") kv.PutString("bc", "v12") kv.PutString("c", "v13") kv.PutString("c1", "v13") kv.PutString("czzzzzzzzzzzzzz", "v14") kv.PutString("fffffffffffffff", "v15") kv.PutString("g11", "v15") kv.PutString("g111", "v15") kv.PutString("g111\xff", "v15") kv.PutString("zz", "v16") kv.PutString("zzzzzzz", "v16") kv.PutString("zzzzzzzzzzzzzzzz", "v16") return kv }
var keymap = []byte("012345678ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxy")
func KeyValue_Generate(rnd *rand.Rand, n, incr, minlen, maxlen, vminlen, vmaxlen int) *KeyValue { if rnd == nil { rnd = NewRand() } if maxlen < minlen { panic("max len should >= min len") }
rrand := func(min, max int) int { if min == max { return max } return rnd.Intn(max-min) + min }
kv := &KeyValue{} endC := byte(len(keymap) - incr) gen := make([]byte, 0, maxlen) for i := 0; i < n; i++ { m := rrand(minlen, maxlen) last := gen retry: gen = last[:m] if k := len(last); m > k { for j := k; j < m; j++ { gen[j] = 0 } } else { for j := m - 1; j >= 0; j-- { c := last[j] if c == endC { continue } gen[j] = c + byte(incr) for j++; j < m; j++ { gen[j] = 0 } goto ok } if m < maxlen { m++ goto retry } panic(fmt.Sprintf("only able to generate %d keys out of %d keys, try increasing max len", kv.Len(), n)) ok: } key := make([]byte, m) for j := 0; j < m; j++ { key[j] = keymap[gen[j]] } value := make([]byte, rrand(vminlen, vmaxlen)) for n := copy(value, []byte(fmt.Sprintf("v%d", i))); n < len(value); n++ { value[n] = 'x' } kv.Put(key, value) } return kv }
|