Use Go 1.5 vendoring instead of Godeps
Change made by: - running "gvt fetch" on each of the packages mentioned in Godeps/Godeps.json - `rm -rf Godeps` - tweaking the build scripts to not mention Godeps - tweaking the build scripts to test `./lib/...`, `./cmd/...` explicitly (to avoid testing vendor) - tweaking the build scripts to not juggle GOPATH for Godeps and instead set GO15VENDOREXPERIMENT. This also results in some updated packages at the same time I bet. Building with Go 1.3 and 1.4 still *works* but won't use our vendored dependencies - the user needs to have the actual packages in their GOPATH then, which they'll get with a normal "go get". Building with Go 1.6+ will get our vendored dependencies by default even when not using our build script, which is nice. By doing this we gain some freedom in that we can pick and choose manually what to include in vendor, as it's not based on just dependency analysis of our own code. This is also a risk as we might pick up dependencies we are unaware of, as the build may work locally with those packages present in GOPATH. On the other hand the build server will detect this as it has no packages in it's GOPATH beyond what is included in the repo. Recommended tool to manage dependencies is github.com/FiloSottile/gvt.
This commit is contained in:
222
vendor/github.com/syndtr/goleveldb/leveldb/testutil/db.go
generated
vendored
Normal file
222
vendor/github.com/syndtr/goleveldb/leveldb/testutil/db.go
generated
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
// 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"
|
||||
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/syndtr/goleveldb/leveldb/errors"
|
||||
"github.com/syndtr/goleveldb/leveldb/iterator"
|
||||
"github.com/syndtr/goleveldb/leveldb/util"
|
||||
)
|
||||
|
||||
type DB interface{}
|
||||
|
||||
type Put interface {
|
||||
TestPut(key []byte, value []byte) error
|
||||
}
|
||||
|
||||
type Delete interface {
|
||||
TestDelete(key []byte) error
|
||||
}
|
||||
|
||||
type Find interface {
|
||||
TestFind(key []byte) (rkey, rvalue []byte, err error)
|
||||
}
|
||||
|
||||
type Get interface {
|
||||
TestGet(key []byte) (value []byte, err error)
|
||||
}
|
||||
|
||||
type Has interface {
|
||||
TestHas(key []byte) (ret bool, err error)
|
||||
}
|
||||
|
||||
type NewIterator interface {
|
||||
TestNewIterator(slice *util.Range) iterator.Iterator
|
||||
}
|
||||
|
||||
type DBAct int
|
||||
|
||||
func (a DBAct) String() string {
|
||||
switch a {
|
||||
case DBNone:
|
||||
return "none"
|
||||
case DBPut:
|
||||
return "put"
|
||||
case DBOverwrite:
|
||||
return "overwrite"
|
||||
case DBDelete:
|
||||
return "delete"
|
||||
case DBDeleteNA:
|
||||
return "delete_na"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
const (
|
||||
DBNone DBAct = iota
|
||||
DBPut
|
||||
DBOverwrite
|
||||
DBDelete
|
||||
DBDeleteNA
|
||||
)
|
||||
|
||||
type DBTesting struct {
|
||||
Rand *rand.Rand
|
||||
DB interface {
|
||||
Get
|
||||
Put
|
||||
Delete
|
||||
}
|
||||
PostFn func(t *DBTesting)
|
||||
Deleted, Present KeyValue
|
||||
Act, LastAct DBAct
|
||||
ActKey, LastActKey []byte
|
||||
}
|
||||
|
||||
func (t *DBTesting) post() {
|
||||
if t.PostFn != nil {
|
||||
t.PostFn(t)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *DBTesting) setAct(act DBAct, key []byte) {
|
||||
t.LastAct, t.Act = t.Act, act
|
||||
t.LastActKey, t.ActKey = t.ActKey, key
|
||||
}
|
||||
|
||||
func (t *DBTesting) text() string {
|
||||
return fmt.Sprintf("last action was <%v> %q, <%v> %q", t.LastAct, t.LastActKey, t.Act, t.ActKey)
|
||||
}
|
||||
|
||||
func (t *DBTesting) Text() string {
|
||||
return "DBTesting " + t.text()
|
||||
}
|
||||
|
||||
func (t *DBTesting) TestPresentKV(key, value []byte) {
|
||||
rvalue, err := t.DB.TestGet(key)
|
||||
Expect(err).ShouldNot(HaveOccurred(), "Get on key %q, %s", key, t.text())
|
||||
Expect(rvalue).Should(Equal(value), "Value for key %q, %s", key, t.text())
|
||||
}
|
||||
|
||||
func (t *DBTesting) TestAllPresent() {
|
||||
t.Present.IterateShuffled(t.Rand, func(i int, key, value []byte) {
|
||||
t.TestPresentKV(key, value)
|
||||
})
|
||||
}
|
||||
|
||||
func (t *DBTesting) TestDeletedKey(key []byte) {
|
||||
_, err := t.DB.TestGet(key)
|
||||
Expect(err).Should(Equal(errors.ErrNotFound), "Get on deleted key %q, %s", key, t.text())
|
||||
}
|
||||
|
||||
func (t *DBTesting) TestAllDeleted() {
|
||||
t.Deleted.IterateShuffled(t.Rand, func(i int, key, value []byte) {
|
||||
t.TestDeletedKey(key)
|
||||
})
|
||||
}
|
||||
|
||||
func (t *DBTesting) TestAll() {
|
||||
dn := t.Deleted.Len()
|
||||
pn := t.Present.Len()
|
||||
ShuffledIndex(t.Rand, dn+pn, 1, func(i int) {
|
||||
if i >= dn {
|
||||
key, value := t.Present.Index(i - dn)
|
||||
t.TestPresentKV(key, value)
|
||||
} else {
|
||||
t.TestDeletedKey(t.Deleted.KeyAt(i))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (t *DBTesting) Put(key, value []byte) {
|
||||
if new := t.Present.PutU(key, value); new {
|
||||
t.setAct(DBPut, key)
|
||||
} else {
|
||||
t.setAct(DBOverwrite, key)
|
||||
}
|
||||
t.Deleted.Delete(key)
|
||||
err := t.DB.TestPut(key, value)
|
||||
Expect(err).ShouldNot(HaveOccurred(), t.Text())
|
||||
t.TestPresentKV(key, value)
|
||||
t.post()
|
||||
}
|
||||
|
||||
func (t *DBTesting) PutRandom() bool {
|
||||
if t.Deleted.Len() > 0 {
|
||||
i := t.Rand.Intn(t.Deleted.Len())
|
||||
key, value := t.Deleted.Index(i)
|
||||
t.Put(key, value)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (t *DBTesting) Delete(key []byte) {
|
||||
if exist, value := t.Present.Delete(key); exist {
|
||||
t.setAct(DBDelete, key)
|
||||
t.Deleted.PutU(key, value)
|
||||
} else {
|
||||
t.setAct(DBDeleteNA, key)
|
||||
}
|
||||
err := t.DB.TestDelete(key)
|
||||
Expect(err).ShouldNot(HaveOccurred(), t.Text())
|
||||
t.TestDeletedKey(key)
|
||||
t.post()
|
||||
}
|
||||
|
||||
func (t *DBTesting) DeleteRandom() bool {
|
||||
if t.Present.Len() > 0 {
|
||||
i := t.Rand.Intn(t.Present.Len())
|
||||
t.Delete(t.Present.KeyAt(i))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (t *DBTesting) RandomAct(round int) {
|
||||
for i := 0; i < round; i++ {
|
||||
if t.Rand.Int()%2 == 0 {
|
||||
t.PutRandom()
|
||||
} else {
|
||||
t.DeleteRandom()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func DoDBTesting(t *DBTesting) {
|
||||
if t.Rand == nil {
|
||||
t.Rand = NewRand()
|
||||
}
|
||||
|
||||
t.DeleteRandom()
|
||||
t.PutRandom()
|
||||
t.DeleteRandom()
|
||||
t.DeleteRandom()
|
||||
for i := t.Deleted.Len() / 2; i >= 0; i-- {
|
||||
t.PutRandom()
|
||||
}
|
||||
t.RandomAct((t.Deleted.Len() + t.Present.Len()) * 10)
|
||||
|
||||
// Additional iterator testing
|
||||
if db, ok := t.DB.(NewIterator); ok {
|
||||
iter := db.TestNewIterator(nil)
|
||||
Expect(iter.Error()).NotTo(HaveOccurred())
|
||||
|
||||
it := IteratorTesting{
|
||||
KeyValue: t.Present,
|
||||
Iter: iter,
|
||||
}
|
||||
|
||||
DoIteratorTesting(&it)
|
||||
iter.Release()
|
||||
}
|
||||
}
|
||||
21
vendor/github.com/syndtr/goleveldb/leveldb/testutil/ginkgo.go
generated
vendored
Normal file
21
vendor/github.com/syndtr/goleveldb/leveldb/testutil/ginkgo.go
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
package testutil
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func RunSuite(t GinkgoTestingT, name string) {
|
||||
RunDefer()
|
||||
|
||||
SynchronizedBeforeSuite(func() []byte {
|
||||
RunDefer("setup")
|
||||
return nil
|
||||
}, func(data []byte) {})
|
||||
SynchronizedAfterSuite(func() {
|
||||
RunDefer("teardown")
|
||||
}, func() {})
|
||||
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, name)
|
||||
}
|
||||
327
vendor/github.com/syndtr/goleveldb/leveldb/testutil/iter.go
generated
vendored
Normal file
327
vendor/github.com/syndtr/goleveldb/leveldb/testutil/iter.go
generated
vendored
Normal file
@@ -0,0 +1,327 @@
|
||||
// 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"
|
||||
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/syndtr/goleveldb/leveldb/iterator"
|
||||
)
|
||||
|
||||
type IterAct int
|
||||
|
||||
func (a IterAct) String() string {
|
||||
switch a {
|
||||
case IterNone:
|
||||
return "none"
|
||||
case IterFirst:
|
||||
return "first"
|
||||
case IterLast:
|
||||
return "last"
|
||||
case IterPrev:
|
||||
return "prev"
|
||||
case IterNext:
|
||||
return "next"
|
||||
case IterSeek:
|
||||
return "seek"
|
||||
case IterSOI:
|
||||
return "soi"
|
||||
case IterEOI:
|
||||
return "eoi"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
const (
|
||||
IterNone IterAct = iota
|
||||
IterFirst
|
||||
IterLast
|
||||
IterPrev
|
||||
IterNext
|
||||
IterSeek
|
||||
IterSOI
|
||||
IterEOI
|
||||
)
|
||||
|
||||
type IteratorTesting struct {
|
||||
KeyValue
|
||||
Iter iterator.Iterator
|
||||
Rand *rand.Rand
|
||||
PostFn func(t *IteratorTesting)
|
||||
Pos int
|
||||
Act, LastAct IterAct
|
||||
|
||||
once bool
|
||||
}
|
||||
|
||||
func (t *IteratorTesting) init() {
|
||||
if !t.once {
|
||||
t.Pos = -1
|
||||
t.once = true
|
||||
}
|
||||
}
|
||||
|
||||
func (t *IteratorTesting) post() {
|
||||
if t.PostFn != nil {
|
||||
t.PostFn(t)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *IteratorTesting) setAct(act IterAct) {
|
||||
t.LastAct, t.Act = t.Act, act
|
||||
}
|
||||
|
||||
func (t *IteratorTesting) text() string {
|
||||
return fmt.Sprintf("at pos %d and last action was <%v> -> <%v>", t.Pos, t.LastAct, t.Act)
|
||||
}
|
||||
|
||||
func (t *IteratorTesting) Text() string {
|
||||
return "IteratorTesting is " + t.text()
|
||||
}
|
||||
|
||||
func (t *IteratorTesting) IsFirst() bool {
|
||||
t.init()
|
||||
return t.Len() > 0 && t.Pos == 0
|
||||
}
|
||||
|
||||
func (t *IteratorTesting) IsLast() bool {
|
||||
t.init()
|
||||
return t.Len() > 0 && t.Pos == t.Len()-1
|
||||
}
|
||||
|
||||
func (t *IteratorTesting) TestKV() {
|
||||
t.init()
|
||||
key, value := t.Index(t.Pos)
|
||||
Expect(t.Iter.Key()).NotTo(BeNil())
|
||||
Expect(t.Iter.Key()).Should(Equal(key), "Key is invalid, %s", t.text())
|
||||
Expect(t.Iter.Value()).Should(Equal(value), "Value for key %q, %s", key, t.text())
|
||||
}
|
||||
|
||||
func (t *IteratorTesting) First() {
|
||||
t.init()
|
||||
t.setAct(IterFirst)
|
||||
|
||||
ok := t.Iter.First()
|
||||
Expect(t.Iter.Error()).ShouldNot(HaveOccurred())
|
||||
if t.Len() > 0 {
|
||||
t.Pos = 0
|
||||
Expect(ok).Should(BeTrue(), t.Text())
|
||||
t.TestKV()
|
||||
} else {
|
||||
t.Pos = -1
|
||||
Expect(ok).ShouldNot(BeTrue(), t.Text())
|
||||
}
|
||||
t.post()
|
||||
}
|
||||
|
||||
func (t *IteratorTesting) Last() {
|
||||
t.init()
|
||||
t.setAct(IterLast)
|
||||
|
||||
ok := t.Iter.Last()
|
||||
Expect(t.Iter.Error()).ShouldNot(HaveOccurred())
|
||||
if t.Len() > 0 {
|
||||
t.Pos = t.Len() - 1
|
||||
Expect(ok).Should(BeTrue(), t.Text())
|
||||
t.TestKV()
|
||||
} else {
|
||||
t.Pos = 0
|
||||
Expect(ok).ShouldNot(BeTrue(), t.Text())
|
||||
}
|
||||
t.post()
|
||||
}
|
||||
|
||||
func (t *IteratorTesting) Next() {
|
||||
t.init()
|
||||
t.setAct(IterNext)
|
||||
|
||||
ok := t.Iter.Next()
|
||||
Expect(t.Iter.Error()).ShouldNot(HaveOccurred())
|
||||
if t.Pos < t.Len()-1 {
|
||||
t.Pos++
|
||||
Expect(ok).Should(BeTrue(), t.Text())
|
||||
t.TestKV()
|
||||
} else {
|
||||
t.Pos = t.Len()
|
||||
Expect(ok).ShouldNot(BeTrue(), t.Text())
|
||||
}
|
||||
t.post()
|
||||
}
|
||||
|
||||
func (t *IteratorTesting) Prev() {
|
||||
t.init()
|
||||
t.setAct(IterPrev)
|
||||
|
||||
ok := t.Iter.Prev()
|
||||
Expect(t.Iter.Error()).ShouldNot(HaveOccurred())
|
||||
if t.Pos > 0 {
|
||||
t.Pos--
|
||||
Expect(ok).Should(BeTrue(), t.Text())
|
||||
t.TestKV()
|
||||
} else {
|
||||
t.Pos = -1
|
||||
Expect(ok).ShouldNot(BeTrue(), t.Text())
|
||||
}
|
||||
t.post()
|
||||
}
|
||||
|
||||
func (t *IteratorTesting) Seek(i int) {
|
||||
t.init()
|
||||
t.setAct(IterSeek)
|
||||
|
||||
key, _ := t.Index(i)
|
||||
oldKey, _ := t.IndexOrNil(t.Pos)
|
||||
|
||||
ok := t.Iter.Seek(key)
|
||||
Expect(t.Iter.Error()).ShouldNot(HaveOccurred())
|
||||
Expect(ok).Should(BeTrue(), fmt.Sprintf("Seek from key %q to %q, to pos %d, %s", oldKey, key, i, t.text()))
|
||||
|
||||
t.Pos = i
|
||||
t.TestKV()
|
||||
t.post()
|
||||
}
|
||||
|
||||
func (t *IteratorTesting) SeekInexact(i int) {
|
||||
t.init()
|
||||
t.setAct(IterSeek)
|
||||
var key0 []byte
|
||||
key1, _ := t.Index(i)
|
||||
if i > 0 {
|
||||
key0, _ = t.Index(i - 1)
|
||||
}
|
||||
key := BytesSeparator(key0, key1)
|
||||
oldKey, _ := t.IndexOrNil(t.Pos)
|
||||
|
||||
ok := t.Iter.Seek(key)
|
||||
Expect(t.Iter.Error()).ShouldNot(HaveOccurred())
|
||||
Expect(ok).Should(BeTrue(), fmt.Sprintf("Seek from key %q to %q (%q), to pos %d, %s", oldKey, key, key1, i, t.text()))
|
||||
|
||||
t.Pos = i
|
||||
t.TestKV()
|
||||
t.post()
|
||||
}
|
||||
|
||||
func (t *IteratorTesting) SeekKey(key []byte) {
|
||||
t.init()
|
||||
t.setAct(IterSeek)
|
||||
oldKey, _ := t.IndexOrNil(t.Pos)
|
||||
i := t.Search(key)
|
||||
|
||||
ok := t.Iter.Seek(key)
|
||||
Expect(t.Iter.Error()).ShouldNot(HaveOccurred())
|
||||
if i < t.Len() {
|
||||
key_, _ := t.Index(i)
|
||||
Expect(ok).Should(BeTrue(), fmt.Sprintf("Seek from key %q to %q (%q), to pos %d, %s", oldKey, key, key_, i, t.text()))
|
||||
t.Pos = i
|
||||
t.TestKV()
|
||||
} else {
|
||||
Expect(ok).ShouldNot(BeTrue(), fmt.Sprintf("Seek from key %q to %q, %s", oldKey, key, t.text()))
|
||||
}
|
||||
|
||||
t.Pos = i
|
||||
t.post()
|
||||
}
|
||||
|
||||
func (t *IteratorTesting) SOI() {
|
||||
t.init()
|
||||
t.setAct(IterSOI)
|
||||
Expect(t.Pos).Should(BeNumerically("<=", 0), t.Text())
|
||||
for i := 0; i < 3; i++ {
|
||||
t.Prev()
|
||||
}
|
||||
t.post()
|
||||
}
|
||||
|
||||
func (t *IteratorTesting) EOI() {
|
||||
t.init()
|
||||
t.setAct(IterEOI)
|
||||
Expect(t.Pos).Should(BeNumerically(">=", t.Len()-1), t.Text())
|
||||
for i := 0; i < 3; i++ {
|
||||
t.Next()
|
||||
}
|
||||
t.post()
|
||||
}
|
||||
|
||||
func (t *IteratorTesting) WalkPrev(fn func(t *IteratorTesting)) {
|
||||
t.init()
|
||||
for old := t.Pos; t.Pos > 0; old = t.Pos {
|
||||
fn(t)
|
||||
Expect(t.Pos).Should(BeNumerically("<", old), t.Text())
|
||||
}
|
||||
}
|
||||
|
||||
func (t *IteratorTesting) WalkNext(fn func(t *IteratorTesting)) {
|
||||
t.init()
|
||||
for old := t.Pos; t.Pos < t.Len()-1; old = t.Pos {
|
||||
fn(t)
|
||||
Expect(t.Pos).Should(BeNumerically(">", old), t.Text())
|
||||
}
|
||||
}
|
||||
|
||||
func (t *IteratorTesting) PrevAll() {
|
||||
t.WalkPrev(func(t *IteratorTesting) {
|
||||
t.Prev()
|
||||
})
|
||||
}
|
||||
|
||||
func (t *IteratorTesting) NextAll() {
|
||||
t.WalkNext(func(t *IteratorTesting) {
|
||||
t.Next()
|
||||
})
|
||||
}
|
||||
|
||||
func DoIteratorTesting(t *IteratorTesting) {
|
||||
if t.Rand == nil {
|
||||
t.Rand = NewRand()
|
||||
}
|
||||
t.SOI()
|
||||
t.NextAll()
|
||||
t.First()
|
||||
t.SOI()
|
||||
t.NextAll()
|
||||
t.EOI()
|
||||
t.PrevAll()
|
||||
t.Last()
|
||||
t.EOI()
|
||||
t.PrevAll()
|
||||
t.SOI()
|
||||
|
||||
t.NextAll()
|
||||
t.PrevAll()
|
||||
t.NextAll()
|
||||
t.Last()
|
||||
t.PrevAll()
|
||||
t.First()
|
||||
t.NextAll()
|
||||
t.EOI()
|
||||
|
||||
ShuffledIndex(t.Rand, t.Len(), 1, func(i int) {
|
||||
t.Seek(i)
|
||||
})
|
||||
|
||||
ShuffledIndex(t.Rand, t.Len(), 1, func(i int) {
|
||||
t.SeekInexact(i)
|
||||
})
|
||||
|
||||
ShuffledIndex(t.Rand, t.Len(), 1, func(i int) {
|
||||
t.Seek(i)
|
||||
if i%2 != 0 {
|
||||
t.PrevAll()
|
||||
t.SOI()
|
||||
} else {
|
||||
t.NextAll()
|
||||
t.EOI()
|
||||
}
|
||||
})
|
||||
|
||||
for _, key := range []string{"", "foo", "bar", "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"} {
|
||||
t.SeekKey([]byte(key))
|
||||
}
|
||||
}
|
||||
352
vendor/github.com/syndtr/goleveldb/leveldb/testutil/kv.go
generated
vendored
Normal file
352
vendor/github.com/syndtr/goleveldb/leveldb/testutil/kv.go
generated
vendored
Normal file
@@ -0,0 +1,352 @@
|
||||
// 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, 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) - 1)
|
||||
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 + 1
|
||||
for j += 1; 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
|
||||
}
|
||||
211
vendor/github.com/syndtr/goleveldb/leveldb/testutil/kvtest.go
generated
vendored
Normal file
211
vendor/github.com/syndtr/goleveldb/leveldb/testutil/kvtest.go
generated
vendored
Normal file
@@ -0,0 +1,211 @@
|
||||
// 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"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/syndtr/goleveldb/leveldb/errors"
|
||||
"github.com/syndtr/goleveldb/leveldb/util"
|
||||
)
|
||||
|
||||
func TestFind(db Find, kv KeyValue) {
|
||||
ShuffledIndex(nil, kv.Len(), 1, func(i int) {
|
||||
key_, key, value := kv.IndexInexact(i)
|
||||
|
||||
// Using exact key.
|
||||
rkey, rvalue, err := db.TestFind(key)
|
||||
Expect(err).ShouldNot(HaveOccurred(), "Error for key %q", key)
|
||||
Expect(rkey).Should(Equal(key), "Key")
|
||||
Expect(rvalue).Should(Equal(value), "Value for key %q", key)
|
||||
|
||||
// Using inexact key.
|
||||
rkey, rvalue, err = db.TestFind(key_)
|
||||
Expect(err).ShouldNot(HaveOccurred(), "Error for key %q (%q)", key_, key)
|
||||
Expect(rkey).Should(Equal(key))
|
||||
Expect(rvalue).Should(Equal(value), "Value for key %q (%q)", key_, key)
|
||||
})
|
||||
}
|
||||
|
||||
func TestFindAfterLast(db Find, kv KeyValue) {
|
||||
var key []byte
|
||||
if kv.Len() > 0 {
|
||||
key_, _ := kv.Index(kv.Len() - 1)
|
||||
key = BytesAfter(key_)
|
||||
}
|
||||
rkey, _, err := db.TestFind(key)
|
||||
Expect(err).Should(HaveOccurred(), "Find for key %q yield key %q", key, rkey)
|
||||
Expect(err).Should(Equal(errors.ErrNotFound))
|
||||
}
|
||||
|
||||
func TestGet(db Get, kv KeyValue) {
|
||||
ShuffledIndex(nil, kv.Len(), 1, func(i int) {
|
||||
key_, key, value := kv.IndexInexact(i)
|
||||
|
||||
// Using exact key.
|
||||
rvalue, err := db.TestGet(key)
|
||||
Expect(err).ShouldNot(HaveOccurred(), "Error for key %q", key)
|
||||
Expect(rvalue).Should(Equal(value), "Value for key %q", key)
|
||||
|
||||
// Using inexact key.
|
||||
if len(key_) > 0 {
|
||||
_, err = db.TestGet(key_)
|
||||
Expect(err).Should(HaveOccurred(), "Error for key %q", key_)
|
||||
Expect(err).Should(Equal(errors.ErrNotFound))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestHas(db Has, kv KeyValue) {
|
||||
ShuffledIndex(nil, kv.Len(), 1, func(i int) {
|
||||
key_, key, _ := kv.IndexInexact(i)
|
||||
|
||||
// Using exact key.
|
||||
ret, err := db.TestHas(key)
|
||||
Expect(err).ShouldNot(HaveOccurred(), "Error for key %q", key)
|
||||
Expect(ret).Should(BeTrue(), "False for key %q", key)
|
||||
|
||||
// Using inexact key.
|
||||
if len(key_) > 0 {
|
||||
ret, err = db.TestHas(key_)
|
||||
Expect(err).ShouldNot(HaveOccurred(), "Error for key %q", key_)
|
||||
Expect(ret).ShouldNot(BeTrue(), "True for key %q", key)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestIter(db NewIterator, r *util.Range, kv KeyValue) {
|
||||
iter := db.TestNewIterator(r)
|
||||
Expect(iter.Error()).ShouldNot(HaveOccurred())
|
||||
|
||||
t := IteratorTesting{
|
||||
KeyValue: kv,
|
||||
Iter: iter,
|
||||
}
|
||||
|
||||
DoIteratorTesting(&t)
|
||||
iter.Release()
|
||||
}
|
||||
|
||||
func KeyValueTesting(rnd *rand.Rand, kv KeyValue, p DB, setup func(KeyValue) DB, teardown func(DB)) {
|
||||
if rnd == nil {
|
||||
rnd = NewRand()
|
||||
}
|
||||
|
||||
if p == nil {
|
||||
BeforeEach(func() {
|
||||
p = setup(kv)
|
||||
})
|
||||
if teardown != nil {
|
||||
AfterEach(func() {
|
||||
teardown(p)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
It("Should find all keys with Find", func() {
|
||||
if db, ok := p.(Find); ok {
|
||||
TestFind(db, kv)
|
||||
}
|
||||
})
|
||||
|
||||
It("Should return error if Find on key after the last", func() {
|
||||
if db, ok := p.(Find); ok {
|
||||
TestFindAfterLast(db, kv)
|
||||
}
|
||||
})
|
||||
|
||||
It("Should only find exact key with Get", func() {
|
||||
if db, ok := p.(Get); ok {
|
||||
TestGet(db, kv)
|
||||
}
|
||||
})
|
||||
|
||||
It("Should only find present key with Has", func() {
|
||||
if db, ok := p.(Has); ok {
|
||||
TestHas(db, kv)
|
||||
}
|
||||
})
|
||||
|
||||
It("Should iterates and seeks correctly", func(done Done) {
|
||||
if db, ok := p.(NewIterator); ok {
|
||||
TestIter(db, nil, kv.Clone())
|
||||
}
|
||||
done <- true
|
||||
}, 3.0)
|
||||
|
||||
It("Should iterates and seeks slice correctly", func(done Done) {
|
||||
if db, ok := p.(NewIterator); ok {
|
||||
RandomIndex(rnd, kv.Len(), Min(kv.Len(), 50), func(i int) {
|
||||
type slice struct {
|
||||
r *util.Range
|
||||
start, limit int
|
||||
}
|
||||
|
||||
key_, _, _ := kv.IndexInexact(i)
|
||||
for _, x := range []slice{
|
||||
{&util.Range{Start: key_, Limit: nil}, i, kv.Len()},
|
||||
{&util.Range{Start: nil, Limit: key_}, 0, i},
|
||||
} {
|
||||
By(fmt.Sprintf("Random index of %d .. %d", x.start, x.limit), func() {
|
||||
TestIter(db, x.r, kv.Slice(x.start, x.limit))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
done <- true
|
||||
}, 50.0)
|
||||
|
||||
It("Should iterates and seeks slice correctly", func(done Done) {
|
||||
if db, ok := p.(NewIterator); ok {
|
||||
RandomRange(rnd, kv.Len(), Min(kv.Len(), 50), func(start, limit int) {
|
||||
By(fmt.Sprintf("Random range of %d .. %d", start, limit), func() {
|
||||
r := kv.Range(start, limit)
|
||||
TestIter(db, &r, kv.Slice(start, limit))
|
||||
})
|
||||
})
|
||||
}
|
||||
done <- true
|
||||
}, 50.0)
|
||||
}
|
||||
|
||||
func AllKeyValueTesting(rnd *rand.Rand, body, setup func(KeyValue) DB, teardown func(DB)) {
|
||||
Test := func(kv *KeyValue) func() {
|
||||
return func() {
|
||||
var p DB
|
||||
if setup != nil {
|
||||
Defer("setup", func() {
|
||||
p = setup(*kv)
|
||||
})
|
||||
}
|
||||
if teardown != nil {
|
||||
Defer("teardown", func() {
|
||||
teardown(p)
|
||||
})
|
||||
}
|
||||
if body != nil {
|
||||
p = body(*kv)
|
||||
}
|
||||
KeyValueTesting(rnd, *kv, p, func(KeyValue) DB {
|
||||
return p
|
||||
}, nil)
|
||||
}
|
||||
}
|
||||
|
||||
Describe("with no key/value (empty)", Test(&KeyValue{}))
|
||||
Describe("with empty key", Test(KeyValue_EmptyKey()))
|
||||
Describe("with empty value", Test(KeyValue_EmptyValue()))
|
||||
Describe("with one key/value", Test(KeyValue_OneKeyValue()))
|
||||
Describe("with big value", Test(KeyValue_BigValue()))
|
||||
Describe("with special key", Test(KeyValue_SpecialKey()))
|
||||
Describe("with multiple key/value", Test(KeyValue_MultipleKeyValue()))
|
||||
Describe("with generated key/value", Test(KeyValue_Generate(nil, 120, 1, 50, 10, 120)))
|
||||
}
|
||||
694
vendor/github.com/syndtr/goleveldb/leveldb/testutil/storage.go
generated
vendored
Normal file
694
vendor/github.com/syndtr/goleveldb/leveldb/testutil/storage.go
generated
vendored
Normal file
@@ -0,0 +1,694 @@
|
||||
// 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 (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/syndtr/goleveldb/leveldb/storage"
|
||||
"github.com/syndtr/goleveldb/leveldb/util"
|
||||
)
|
||||
|
||||
var (
|
||||
storageMu sync.Mutex
|
||||
storageUseFS = true
|
||||
storageKeepFS = false
|
||||
storageNum int
|
||||
)
|
||||
|
||||
type StorageMode int
|
||||
|
||||
const (
|
||||
ModeOpen StorageMode = 1 << iota
|
||||
ModeCreate
|
||||
ModeRemove
|
||||
ModeRename
|
||||
ModeRead
|
||||
ModeWrite
|
||||
ModeSync
|
||||
ModeClose
|
||||
)
|
||||
|
||||
const (
|
||||
modeOpen = iota
|
||||
modeCreate
|
||||
modeRemove
|
||||
modeRename
|
||||
modeRead
|
||||
modeWrite
|
||||
modeSync
|
||||
modeClose
|
||||
|
||||
modeCount
|
||||
)
|
||||
|
||||
const (
|
||||
typeManifest = iota
|
||||
typeJournal
|
||||
typeTable
|
||||
typeTemp
|
||||
|
||||
typeCount
|
||||
)
|
||||
|
||||
const flattenCount = modeCount * typeCount
|
||||
|
||||
func flattenType(m StorageMode, t storage.FileType) int {
|
||||
var x int
|
||||
switch m {
|
||||
case ModeOpen:
|
||||
x = modeOpen
|
||||
case ModeCreate:
|
||||
x = modeCreate
|
||||
case ModeRemove:
|
||||
x = modeRemove
|
||||
case ModeRename:
|
||||
x = modeRename
|
||||
case ModeRead:
|
||||
x = modeRead
|
||||
case ModeWrite:
|
||||
x = modeWrite
|
||||
case ModeSync:
|
||||
x = modeSync
|
||||
case ModeClose:
|
||||
x = modeClose
|
||||
default:
|
||||
panic("invalid storage mode")
|
||||
}
|
||||
x *= typeCount
|
||||
switch t {
|
||||
case storage.TypeManifest:
|
||||
return x + typeManifest
|
||||
case storage.TypeJournal:
|
||||
return x + typeJournal
|
||||
case storage.TypeTable:
|
||||
return x + typeTable
|
||||
case storage.TypeTemp:
|
||||
return x + typeTemp
|
||||
default:
|
||||
panic("invalid file type")
|
||||
}
|
||||
}
|
||||
|
||||
func listFlattenType(m StorageMode, t storage.FileType) []int {
|
||||
ret := make([]int, 0, flattenCount)
|
||||
add := func(x int) {
|
||||
x *= typeCount
|
||||
switch {
|
||||
case t&storage.TypeManifest != 0:
|
||||
ret = append(ret, x+typeManifest)
|
||||
case t&storage.TypeJournal != 0:
|
||||
ret = append(ret, x+typeJournal)
|
||||
case t&storage.TypeTable != 0:
|
||||
ret = append(ret, x+typeTable)
|
||||
case t&storage.TypeTemp != 0:
|
||||
ret = append(ret, x+typeTemp)
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case m&ModeOpen != 0:
|
||||
add(modeOpen)
|
||||
case m&ModeCreate != 0:
|
||||
add(modeCreate)
|
||||
case m&ModeRemove != 0:
|
||||
add(modeRemove)
|
||||
case m&ModeRename != 0:
|
||||
add(modeRename)
|
||||
case m&ModeRead != 0:
|
||||
add(modeRead)
|
||||
case m&ModeWrite != 0:
|
||||
add(modeWrite)
|
||||
case m&ModeSync != 0:
|
||||
add(modeSync)
|
||||
case m&ModeClose != 0:
|
||||
add(modeClose)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func packFile(fd storage.FileDesc) uint64 {
|
||||
if fd.Num>>(63-typeCount) != 0 {
|
||||
panic("overflow")
|
||||
}
|
||||
return uint64(fd.Num<<typeCount) | uint64(fd.Type)
|
||||
}
|
||||
|
||||
func unpackFile(x uint64) storage.FileDesc {
|
||||
return storage.FileDesc{storage.FileType(x) & storage.TypeAll, int64(x >> typeCount)}
|
||||
}
|
||||
|
||||
type emulatedError struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (err emulatedError) Error() string {
|
||||
return fmt.Sprintf("emulated storage error: %v", err.err)
|
||||
}
|
||||
|
||||
type storageLock struct {
|
||||
s *Storage
|
||||
r util.Releaser
|
||||
}
|
||||
|
||||
func (l storageLock) Release() {
|
||||
l.r.Release()
|
||||
l.s.logI("storage lock released")
|
||||
}
|
||||
|
||||
type reader struct {
|
||||
s *Storage
|
||||
fd storage.FileDesc
|
||||
storage.Reader
|
||||
}
|
||||
|
||||
func (r *reader) Read(p []byte) (n int, err error) {
|
||||
err = r.s.emulateError(ModeRead, r.fd.Type)
|
||||
if err == nil {
|
||||
r.s.stall(ModeRead, r.fd.Type)
|
||||
n, err = r.Reader.Read(p)
|
||||
}
|
||||
r.s.count(ModeRead, r.fd.Type, n)
|
||||
if err != nil && err != io.EOF {
|
||||
r.s.logI("read error, fd=%s n=%d err=%v", r.fd, n, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (r *reader) ReadAt(p []byte, off int64) (n int, err error) {
|
||||
err = r.s.emulateError(ModeRead, r.fd.Type)
|
||||
if err == nil {
|
||||
r.s.stall(ModeRead, r.fd.Type)
|
||||
n, err = r.Reader.ReadAt(p, off)
|
||||
}
|
||||
r.s.count(ModeRead, r.fd.Type, n)
|
||||
if err != nil && err != io.EOF {
|
||||
r.s.logI("readAt error, fd=%s offset=%d n=%d err=%v", r.fd, off, n, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (r *reader) Close() (err error) {
|
||||
return r.s.fileClose(r.fd, r.Reader)
|
||||
}
|
||||
|
||||
type writer struct {
|
||||
s *Storage
|
||||
fd storage.FileDesc
|
||||
storage.Writer
|
||||
}
|
||||
|
||||
func (w *writer) Write(p []byte) (n int, err error) {
|
||||
err = w.s.emulateError(ModeWrite, w.fd.Type)
|
||||
if err == nil {
|
||||
w.s.stall(ModeWrite, w.fd.Type)
|
||||
n, err = w.Writer.Write(p)
|
||||
}
|
||||
w.s.count(ModeWrite, w.fd.Type, n)
|
||||
if err != nil && err != io.EOF {
|
||||
w.s.logI("write error, fd=%s n=%d err=%v", w.fd, n, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (w *writer) Sync() (err error) {
|
||||
err = w.s.emulateError(ModeSync, w.fd.Type)
|
||||
if err == nil {
|
||||
w.s.stall(ModeSync, w.fd.Type)
|
||||
err = w.Writer.Sync()
|
||||
}
|
||||
w.s.count(ModeSync, w.fd.Type, 0)
|
||||
if err != nil {
|
||||
w.s.logI("sync error, fd=%s err=%v", w.fd, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (w *writer) Close() (err error) {
|
||||
return w.s.fileClose(w.fd, w.Writer)
|
||||
}
|
||||
|
||||
type Storage struct {
|
||||
storage.Storage
|
||||
path string
|
||||
onClose func() (preserve bool, err error)
|
||||
onLog func(str string)
|
||||
|
||||
lmu sync.Mutex
|
||||
lb bytes.Buffer
|
||||
|
||||
mu sync.Mutex
|
||||
rand *rand.Rand
|
||||
// Open files, true=writer, false=reader
|
||||
opens map[uint64]bool
|
||||
counters [flattenCount]int
|
||||
bytesCounter [flattenCount]int64
|
||||
emulatedError [flattenCount]error
|
||||
emulatedErrorOnce [flattenCount]bool
|
||||
emulatedRandomError [flattenCount]error
|
||||
emulatedRandomErrorProb [flattenCount]float64
|
||||
stallCond sync.Cond
|
||||
stalled [flattenCount]bool
|
||||
}
|
||||
|
||||
func (s *Storage) log(skip int, str string) {
|
||||
s.lmu.Lock()
|
||||
defer s.lmu.Unlock()
|
||||
_, file, line, ok := runtime.Caller(skip + 2)
|
||||
if ok {
|
||||
// Truncate file name at last file name separator.
|
||||
if index := strings.LastIndex(file, "/"); index >= 0 {
|
||||
file = file[index+1:]
|
||||
} else if index = strings.LastIndex(file, "\\"); index >= 0 {
|
||||
file = file[index+1:]
|
||||
}
|
||||
} else {
|
||||
file = "???"
|
||||
line = 1
|
||||
}
|
||||
fmt.Fprintf(&s.lb, "%s:%d: ", file, line)
|
||||
lines := strings.Split(str, "\n")
|
||||
if l := len(lines); l > 1 && lines[l-1] == "" {
|
||||
lines = lines[:l-1]
|
||||
}
|
||||
for i, line := range lines {
|
||||
if i > 0 {
|
||||
s.lb.WriteString("\n\t")
|
||||
}
|
||||
s.lb.WriteString(line)
|
||||
}
|
||||
if s.onLog != nil {
|
||||
s.onLog(s.lb.String())
|
||||
s.lb.Reset()
|
||||
} else {
|
||||
s.lb.WriteByte('\n')
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Storage) logISkip(skip int, format string, args ...interface{}) {
|
||||
pc, _, _, ok := runtime.Caller(skip + 1)
|
||||
if ok {
|
||||
if f := runtime.FuncForPC(pc); f != nil {
|
||||
fname := f.Name()
|
||||
if index := strings.LastIndex(fname, "."); index >= 0 {
|
||||
fname = fname[index+1:]
|
||||
}
|
||||
format = fname + ": " + format
|
||||
}
|
||||
}
|
||||
s.log(skip+1, fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
func (s *Storage) logI(format string, args ...interface{}) {
|
||||
s.logISkip(1, format, args...)
|
||||
}
|
||||
|
||||
func (s *Storage) OnLog(onLog func(log string)) {
|
||||
s.lmu.Lock()
|
||||
s.onLog = onLog
|
||||
if s.lb.Len() != 0 {
|
||||
log := s.lb.String()
|
||||
s.onLog(log[:len(log)-1])
|
||||
s.lb.Reset()
|
||||
}
|
||||
s.lmu.Unlock()
|
||||
}
|
||||
|
||||
func (s *Storage) Log(str string) {
|
||||
s.log(1, "Log: "+str)
|
||||
s.Storage.Log(str)
|
||||
}
|
||||
|
||||
func (s *Storage) Lock() (l storage.Lock, err error) {
|
||||
l, err = s.Storage.Lock()
|
||||
if err != nil {
|
||||
s.logI("storage locking failed, err=%v", err)
|
||||
} else {
|
||||
s.logI("storage locked")
|
||||
l = storageLock{s, l}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Storage) List(t storage.FileType) (fds []storage.FileDesc, err error) {
|
||||
fds, err = s.Storage.List(t)
|
||||
if err != nil {
|
||||
s.logI("list failed, err=%v", err)
|
||||
return
|
||||
}
|
||||
s.logI("list, type=0x%x count=%d", int(t), len(fds))
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Storage) GetMeta() (fd storage.FileDesc, err error) {
|
||||
fd, err = s.Storage.GetMeta()
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
s.logI("get meta failed, err=%v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
s.logI("get meta, fd=%s", fd)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Storage) SetMeta(fd storage.FileDesc) error {
|
||||
ExpectWithOffset(1, fd.Type).To(Equal(storage.TypeManifest))
|
||||
err := s.Storage.SetMeta(fd)
|
||||
if err != nil {
|
||||
s.logI("set meta failed, fd=%s err=%v", fd, err)
|
||||
} else {
|
||||
s.logI("set meta, fd=%s", fd)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Storage) fileClose(fd storage.FileDesc, closer io.Closer) (err error) {
|
||||
err = s.emulateError(ModeClose, fd.Type)
|
||||
if err == nil {
|
||||
s.stall(ModeClose, fd.Type)
|
||||
}
|
||||
x := packFile(fd)
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if err == nil {
|
||||
ExpectWithOffset(2, s.opens).To(HaveKey(x), "File closed, fd=%s", fd)
|
||||
err = closer.Close()
|
||||
}
|
||||
s.countNB(ModeClose, fd.Type, 0)
|
||||
writer := s.opens[x]
|
||||
if err != nil {
|
||||
s.logISkip(1, "file close failed, fd=%s writer=%v err=%v", fd, writer, err)
|
||||
} else {
|
||||
s.logISkip(1, "file closed, fd=%s writer=%v", fd, writer)
|
||||
delete(s.opens, x)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Storage) assertOpen(fd storage.FileDesc) {
|
||||
x := packFile(fd)
|
||||
ExpectWithOffset(2, s.opens).NotTo(HaveKey(x), "File open, fd=%s writer=%v", fd, s.opens[x])
|
||||
}
|
||||
|
||||
func (s *Storage) Open(fd storage.FileDesc) (r storage.Reader, err error) {
|
||||
err = s.emulateError(ModeOpen, fd.Type)
|
||||
if err == nil {
|
||||
s.stall(ModeOpen, fd.Type)
|
||||
}
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if err == nil {
|
||||
s.assertOpen(fd)
|
||||
s.countNB(ModeOpen, fd.Type, 0)
|
||||
r, err = s.Storage.Open(fd)
|
||||
}
|
||||
if err != nil {
|
||||
s.logI("file open failed, fd=%s err=%v", fd, err)
|
||||
} else {
|
||||
s.logI("file opened, fd=%s", fd)
|
||||
s.opens[packFile(fd)] = false
|
||||
r = &reader{s, fd, r}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Storage) Create(fd storage.FileDesc) (w storage.Writer, err error) {
|
||||
err = s.emulateError(ModeCreate, fd.Type)
|
||||
if err == nil {
|
||||
s.stall(ModeCreate, fd.Type)
|
||||
}
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if err == nil {
|
||||
s.assertOpen(fd)
|
||||
s.countNB(ModeCreate, fd.Type, 0)
|
||||
w, err = s.Storage.Create(fd)
|
||||
}
|
||||
if err != nil {
|
||||
s.logI("file create failed, fd=%s err=%v", fd, err)
|
||||
} else {
|
||||
s.logI("file created, fd=%s", fd)
|
||||
s.opens[packFile(fd)] = true
|
||||
w = &writer{s, fd, w}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Storage) Remove(fd storage.FileDesc) (err error) {
|
||||
err = s.emulateError(ModeRemove, fd.Type)
|
||||
if err == nil {
|
||||
s.stall(ModeRemove, fd.Type)
|
||||
}
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if err == nil {
|
||||
s.assertOpen(fd)
|
||||
s.countNB(ModeRemove, fd.Type, 0)
|
||||
err = s.Storage.Remove(fd)
|
||||
}
|
||||
if err != nil {
|
||||
s.logI("file remove failed, fd=%s err=%v", fd, err)
|
||||
} else {
|
||||
s.logI("file removed, fd=%s", fd)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Storage) ForceRemove(fd storage.FileDesc) (err error) {
|
||||
s.countNB(ModeRemove, fd.Type, 0)
|
||||
if err = s.Storage.Remove(fd); err != nil {
|
||||
s.logI("file remove failed (forced), fd=%s err=%v", fd, err)
|
||||
} else {
|
||||
s.logI("file removed (forced), fd=%s", fd)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Storage) Rename(oldfd, newfd storage.FileDesc) (err error) {
|
||||
err = s.emulateError(ModeRename, oldfd.Type)
|
||||
if err == nil {
|
||||
s.stall(ModeRename, oldfd.Type)
|
||||
}
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if err == nil {
|
||||
s.assertOpen(oldfd)
|
||||
s.assertOpen(newfd)
|
||||
s.countNB(ModeRename, oldfd.Type, 0)
|
||||
err = s.Storage.Rename(oldfd, newfd)
|
||||
}
|
||||
if err != nil {
|
||||
s.logI("file rename failed, oldfd=%s newfd=%s err=%v", oldfd, newfd, err)
|
||||
} else {
|
||||
s.logI("file renamed, oldfd=%s newfd=%s", oldfd, newfd)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Storage) ForceRename(oldfd, newfd storage.FileDesc) (err error) {
|
||||
s.countNB(ModeRename, oldfd.Type, 0)
|
||||
if err = s.Storage.Rename(oldfd, newfd); err != nil {
|
||||
s.logI("file rename failed (forced), oldfd=%s newfd=%s err=%v", oldfd, newfd, err)
|
||||
} else {
|
||||
s.logI("file renamed (forced), oldfd=%s newfd=%s", oldfd, newfd)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Storage) openFiles() string {
|
||||
out := "Open files:"
|
||||
for x, writer := range s.opens {
|
||||
fd := unpackFile(x)
|
||||
out += fmt.Sprintf("\n · fd=%s writer=%v", fd, writer)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (s *Storage) CloseCheck() {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
ExpectWithOffset(1, s.opens).To(BeEmpty(), s.openFiles())
|
||||
}
|
||||
|
||||
func (s *Storage) OnClose(onClose func() (preserve bool, err error)) {
|
||||
s.mu.Lock()
|
||||
s.onClose = onClose
|
||||
s.mu.Unlock()
|
||||
}
|
||||
|
||||
func (s *Storage) Close() error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
ExpectWithOffset(1, s.opens).To(BeEmpty(), s.openFiles())
|
||||
err := s.Storage.Close()
|
||||
if err != nil {
|
||||
s.logI("storage closing failed, err=%v", err)
|
||||
} else {
|
||||
s.logI("storage closed")
|
||||
}
|
||||
var preserve bool
|
||||
if s.onClose != nil {
|
||||
var err0 error
|
||||
if preserve, err0 = s.onClose(); err0 != nil {
|
||||
s.logI("onClose error, err=%v", err0)
|
||||
}
|
||||
}
|
||||
if s.path != "" {
|
||||
if storageKeepFS || preserve {
|
||||
s.logI("storage is preserved, path=%v", s.path)
|
||||
} else {
|
||||
if err1 := os.RemoveAll(s.path); err1 != nil {
|
||||
s.logI("cannot remove storage, err=%v", err1)
|
||||
} else {
|
||||
s.logI("storage has been removed")
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Storage) countNB(m StorageMode, t storage.FileType, n int) {
|
||||
s.counters[flattenType(m, t)]++
|
||||
s.bytesCounter[flattenType(m, t)] += int64(n)
|
||||
}
|
||||
|
||||
func (s *Storage) count(m StorageMode, t storage.FileType, n int) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.countNB(m, t, n)
|
||||
}
|
||||
|
||||
func (s *Storage) ResetCounter(m StorageMode, t storage.FileType) {
|
||||
for _, x := range listFlattenType(m, t) {
|
||||
s.counters[x] = 0
|
||||
s.bytesCounter[x] = 0
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Storage) Counter(m StorageMode, t storage.FileType) (count int, bytes int64) {
|
||||
for _, x := range listFlattenType(m, t) {
|
||||
count += s.counters[x]
|
||||
bytes += s.bytesCounter[x]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Storage) emulateError(m StorageMode, t storage.FileType) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
x := flattenType(m, t)
|
||||
if err := s.emulatedError[x]; err != nil {
|
||||
if s.emulatedErrorOnce[x] {
|
||||
s.emulatedError[x] = nil
|
||||
}
|
||||
return emulatedError{err}
|
||||
}
|
||||
if err := s.emulatedRandomError[x]; err != nil && s.rand.Float64() < s.emulatedRandomErrorProb[x] {
|
||||
return emulatedError{err}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Storage) EmulateError(m StorageMode, t storage.FileType, err error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
for _, x := range listFlattenType(m, t) {
|
||||
s.emulatedError[x] = err
|
||||
s.emulatedErrorOnce[x] = false
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Storage) EmulateErrorOnce(m StorageMode, t storage.FileType, err error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
for _, x := range listFlattenType(m, t) {
|
||||
s.emulatedError[x] = err
|
||||
s.emulatedErrorOnce[x] = true
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Storage) EmulateRandomError(m StorageMode, t storage.FileType, prob float64, err error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
for _, x := range listFlattenType(m, t) {
|
||||
s.emulatedRandomError[x] = err
|
||||
s.emulatedRandomErrorProb[x] = prob
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Storage) stall(m StorageMode, t storage.FileType) {
|
||||
x := flattenType(m, t)
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
for s.stalled[x] {
|
||||
s.stallCond.Wait()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Storage) Stall(m StorageMode, t storage.FileType) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
for _, x := range listFlattenType(m, t) {
|
||||
s.stalled[x] = true
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Storage) Release(m StorageMode, t storage.FileType) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
for _, x := range listFlattenType(m, t) {
|
||||
s.stalled[x] = false
|
||||
}
|
||||
s.stallCond.Broadcast()
|
||||
}
|
||||
|
||||
func NewStorage() *Storage {
|
||||
var (
|
||||
stor storage.Storage
|
||||
path string
|
||||
)
|
||||
if storageUseFS {
|
||||
for {
|
||||
storageMu.Lock()
|
||||
num := storageNum
|
||||
storageNum++
|
||||
storageMu.Unlock()
|
||||
path = filepath.Join(os.TempDir(), fmt.Sprintf("goleveldb-test%d0%d0%d", os.Getuid(), os.Getpid(), num))
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
stor, err = storage.OpenFile(path, false)
|
||||
ExpectWithOffset(1, err).NotTo(HaveOccurred(), "creating storage at %s", path)
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
stor = storage.NewMemStorage()
|
||||
}
|
||||
s := &Storage{
|
||||
Storage: stor,
|
||||
path: path,
|
||||
rand: NewRand(),
|
||||
opens: make(map[uint64]bool),
|
||||
}
|
||||
s.stallCond.L = &s.mu
|
||||
if s.path != "" {
|
||||
s.logI("using FS storage")
|
||||
s.logI("storage path: %s", s.path)
|
||||
} else {
|
||||
s.logI("using MEM storage")
|
||||
}
|
||||
return s
|
||||
}
|
||||
171
vendor/github.com/syndtr/goleveldb/leveldb/testutil/util.go
generated
vendored
Normal file
171
vendor/github.com/syndtr/goleveldb/leveldb/testutil/util.go
generated
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
// 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 (
|
||||
"bytes"
|
||||
"flag"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
"github.com/onsi/ginkgo/config"
|
||||
|
||||
"github.com/syndtr/goleveldb/leveldb/comparer"
|
||||
)
|
||||
|
||||
var (
|
||||
runfn = make(map[string][]func())
|
||||
runmu sync.Mutex
|
||||
)
|
||||
|
||||
func Defer(args ...interface{}) bool {
|
||||
var (
|
||||
group string
|
||||
fn func()
|
||||
)
|
||||
for _, arg := range args {
|
||||
v := reflect.ValueOf(arg)
|
||||
switch v.Kind() {
|
||||
case reflect.String:
|
||||
group = v.String()
|
||||
case reflect.Func:
|
||||
r := reflect.ValueOf(&fn).Elem()
|
||||
r.Set(v)
|
||||
}
|
||||
}
|
||||
if fn != nil {
|
||||
runmu.Lock()
|
||||
runfn[group] = append(runfn[group], fn)
|
||||
runmu.Unlock()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func RunDefer(groups ...string) bool {
|
||||
if len(groups) == 0 {
|
||||
groups = append(groups, "")
|
||||
}
|
||||
runmu.Lock()
|
||||
var runfn_ []func()
|
||||
for _, group := range groups {
|
||||
runfn_ = append(runfn_, runfn[group]...)
|
||||
delete(runfn, group)
|
||||
}
|
||||
runmu.Unlock()
|
||||
for _, fn := range runfn_ {
|
||||
fn()
|
||||
}
|
||||
return runfn_ != nil
|
||||
}
|
||||
|
||||
func RandomSeed() int64 {
|
||||
if !flag.Parsed() {
|
||||
panic("random seed not initialized")
|
||||
}
|
||||
return config.GinkgoConfig.RandomSeed
|
||||
}
|
||||
|
||||
func NewRand() *rand.Rand {
|
||||
return rand.New(rand.NewSource(RandomSeed()))
|
||||
}
|
||||
|
||||
var cmp = comparer.DefaultComparer
|
||||
|
||||
func BytesSeparator(a, b []byte) []byte {
|
||||
if bytes.Equal(a, b) {
|
||||
return b
|
||||
}
|
||||
i, n := 0, len(a)
|
||||
if n > len(b) {
|
||||
n = len(b)
|
||||
}
|
||||
for ; i < n && (a[i] == b[i]); i++ {
|
||||
}
|
||||
x := append([]byte{}, a[:i]...)
|
||||
if i < n {
|
||||
if c := a[i] + 1; c < b[i] {
|
||||
return append(x, c)
|
||||
}
|
||||
x = append(x, a[i])
|
||||
i++
|
||||
}
|
||||
for ; i < len(a); i++ {
|
||||
if c := a[i]; c < 0xff {
|
||||
return append(x, c+1)
|
||||
} else {
|
||||
x = append(x, c)
|
||||
}
|
||||
}
|
||||
if len(b) > i && b[i] > 0 {
|
||||
return append(x, b[i]-1)
|
||||
}
|
||||
return append(x, 'x')
|
||||
}
|
||||
|
||||
func BytesAfter(b []byte) []byte {
|
||||
var x []byte
|
||||
for _, c := range b {
|
||||
if c < 0xff {
|
||||
return append(x, c+1)
|
||||
} else {
|
||||
x = append(x, c)
|
||||
}
|
||||
}
|
||||
return append(x, 'x')
|
||||
}
|
||||
|
||||
func RandomIndex(rnd *rand.Rand, n, round int, fn func(i int)) {
|
||||
if rnd == nil {
|
||||
rnd = NewRand()
|
||||
}
|
||||
for x := 0; x < round; x++ {
|
||||
fn(rnd.Intn(n))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ShuffledIndex(rnd *rand.Rand, n, round int, fn func(i int)) {
|
||||
if rnd == nil {
|
||||
rnd = NewRand()
|
||||
}
|
||||
for x := 0; x < round; x++ {
|
||||
for _, i := range rnd.Perm(n) {
|
||||
fn(i)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func RandomRange(rnd *rand.Rand, n, round int, fn func(start, limit int)) {
|
||||
if rnd == nil {
|
||||
rnd = NewRand()
|
||||
}
|
||||
for x := 0; x < round; x++ {
|
||||
start := rnd.Intn(n)
|
||||
length := 0
|
||||
if j := n - start; j > 0 {
|
||||
length = rnd.Intn(j)
|
||||
}
|
||||
fn(start, start+length)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Max(x, y int) int {
|
||||
if x > y {
|
||||
return x
|
||||
}
|
||||
return y
|
||||
}
|
||||
|
||||
func Min(x, y int) int {
|
||||
if x < y {
|
||||
return x
|
||||
}
|
||||
return y
|
||||
}
|
||||
Reference in New Issue
Block a user