Skip to content

Commit

Permalink
Use fastRand instead of locked-rand in skiplist (#1173)
Browse files Browse the repository at this point in the history
The math/rand package (https://golang.org/src/math/rand/rand.go) uses
a global lock to allow concurrent access to the rand object.

The PR replaces `math.Rand` with `ristretto/z.FastRand()`. `FastRand`
is much faster than `math.Rand` and `rand.New(..)` generators.

The change improves concurrent writes to skiplist by ~30%
```go
func BenchmarkWrite(b *testing.B) {
	value := newValue(123)
	l := NewSkiplist(int64((b.N + 1) * MaxNodeSize))
	defer l.DecrRef()
	b.ResetTimer()
	b.RunParallel(func(pb *testing.PB) {
		rng := rand.New(rand.NewSource(time.Now().UnixNano()))
		for pb.Next() {
			l.Put(randomKey(rng), y.ValueStruct{Value: value, Meta: 0, UserMeta: 0})
		}
	})
}
```
```
name      old time/op  new time/op  delta
Write-16   657ns ± 3%   441ns ± 1%  -32.94%  (p=0.000 n=9+10)
```

(cherry picked from commit 9d6512b)
  • Loading branch information
Ibrahim Jarif committed Mar 12, 2020
1 parent 68dabf6 commit 7c4bb47
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 20 deletions.
22 changes: 8 additions & 14 deletions levels_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,22 @@ import (
"math"
"testing"

"github.com/dgraph-io/badger/v2/options"
"github.com/dgraph-io/badger/v2/pb"
"github.com/dgraph-io/badger/v2/table"
"github.com/dgraph-io/badger/v2/y"
"github.com/dgraph-io/badger/options"
"github.com/dgraph-io/badger/pb"
"github.com/dgraph-io/badger/table"
"github.com/dgraph-io/badger/y"
"github.com/stretchr/testify/require"
)

// createAndOpen creates a table with the given data and adds it to the given level.
func createAndOpen(db *DB, td []keyValVersion, level int) {
opts := table.Options{
BlockSize: db.opt.BlockSize,
BloomFalsePositive: db.opt.BloomFalsePositive,
LoadingMode: options.LoadToRAM,
ChkMode: options.NoVerification,
}
b := table.NewTableBuilder(opts)
b := table.NewTableBuilder()

// Add all keys and versions to the table.
for _, item := range td {
key := y.KeyWithTs([]byte(item.key), uint64(item.version))
val := y.ValueStruct{Value: []byte(item.val), Meta: item.meta}
b.Add(key, val, 0)
b.Add(key, val)
}
fd, err := y.CreateSyncedFile(table.NewFilename(db.lc.reserveFileID(), db.opt.Dir), true)
if err != nil {
Expand All @@ -51,12 +45,12 @@ func createAndOpen(db *DB, td []keyValVersion, level int) {
if _, err = fd.Write(b.Finish()); err != nil {
panic(err)
}
tab, err := table.OpenTable(fd, opts)
tab, err := table.OpenTable(fd, options.LoadToRAM, nil)
if err != nil {
panic(err)
}
if err := db.manifest.addChanges([]*pb.ManifestChange{
newCreateChange(tab.ID(), level, 0, tab.CompressionType()),
newCreateChange(tab.ID(), level, nil),
}); err != nil {
panic(err)
}
Expand Down
8 changes: 4 additions & 4 deletions skl/skl.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ package skl

import (
"math"
"math/rand"
"sync/atomic"
"unsafe"

"github.com/dgraph-io/badger/y"
"github.com/dgraph-io/ristretto/z"
)

const (
Expand Down Expand Up @@ -165,9 +165,9 @@ func (s *node) casNextOffset(h int, old, val uint32) bool {
// return n != nil && y.CompareKeys(key, n.key) > 0
//}

func randomHeight() int {
func (s *Skiplist) randomHeight() int {
h := 1
for h < maxHeight && rand.Uint32() <= heightIncrease {
for h < maxHeight && z.FastRand() <= heightIncrease {
h++
}
return h
Expand Down Expand Up @@ -300,7 +300,7 @@ func (s *Skiplist) Put(key []byte, v y.ValueStruct) {
}

// We do need to create a new node.
height := randomHeight()
height := s.randomHeight()
x := newNode(s.arena, key, v, height)

// Try to increase s.height via CAS.
Expand Down
15 changes: 14 additions & 1 deletion skl/skl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ func BenchmarkReadWriteMap(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
for pb.Next() {
if rand.Float32() < readFrac {
if rng.Float32() < readFrac {
mutex.RLock()
_, ok := m[string(randomKey(rng))]
mutex.RUnlock()
Expand All @@ -475,3 +475,16 @@ func BenchmarkReadWriteMap(b *testing.B) {
})
}
}

func BenchmarkWrite(b *testing.B) {
value := newValue(123)
l := NewSkiplist(int64((b.N + 1) * MaxNodeSize))
defer l.DecrRef()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
for pb.Next() {
l.Put(randomKey(rng), y.ValueStruct{Value: value, Meta: 0, UserMeta: 0})
}
})
}
5 changes: 4 additions & 1 deletion table/table_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -644,7 +644,10 @@ func TestTableChecksum(t *testing.T) {
f := buildTestTable(t, "k", 10000)
fi, err := f.Stat()
require.NoError(t, err, "unable to get file information")
f.WriteAt(rb, rand.Int63n(fi.Size()))
// Write random bytes at random location.
n, err := f.WriteAt(rb, rand.Int63n(fi.Size()))
require.NoError(t, err)
require.Equal(t, n, len(rb))

_, err = OpenTable(f, options.LoadToRAM, []byte("wrong"))
if err == nil || !strings.Contains(err.Error(), "checksum") {
Expand Down

0 comments on commit 7c4bb47

Please sign in to comment.