Skip to content

Commit 6ca2395

Browse files
author
Ibrahim Jarif
committed
Use fastRand instead of locked-rand in skiplist (#1173)
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)
1 parent 3dc7f27 commit 6ca2395

File tree

4 files changed

+26
-6
lines changed

4 files changed

+26
-6
lines changed

skl/skl.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,11 @@ package skl
3434

3535
import (
3636
"math"
37-
"math/rand"
3837
"sync/atomic"
3938
"unsafe"
4039

4140
"github.com/dgraph-io/badger/v2/y"
41+
"github.com/dgraph-io/ristretto/z"
4242
)
4343

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

168-
func randomHeight() int {
168+
func (s *Skiplist) randomHeight() int {
169169
h := 1
170-
for h < maxHeight && rand.Uint32() <= heightIncrease {
170+
for h < maxHeight && z.FastRand() <= heightIncrease {
171171
h++
172172
}
173173
return h
@@ -300,7 +300,7 @@ func (s *Skiplist) Put(key []byte, v y.ValueStruct) {
300300
}
301301

302302
// We do need to create a new node.
303-
height := randomHeight()
303+
height := s.randomHeight()
304304
x := newNode(s.arena, key, v, height)
305305

306306
// Try to increase s.height via CAS.

skl/skl_test.go

+14-1
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,7 @@ func BenchmarkReadWriteMap(b *testing.B) {
499499
b.RunParallel(func(pb *testing.PB) {
500500
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
501501
for pb.Next() {
502-
if rand.Float32() < readFrac {
502+
if rng.Float32() < readFrac {
503503
mutex.RLock()
504504
_, ok := m[string(randomKey(rng))]
505505
mutex.RUnlock()
@@ -516,3 +516,16 @@ func BenchmarkReadWriteMap(b *testing.B) {
516516
})
517517
}
518518
}
519+
520+
func BenchmarkWrite(b *testing.B) {
521+
value := newValue(123)
522+
l := NewSkiplist(int64((b.N + 1) * MaxNodeSize))
523+
defer l.DecrRef()
524+
b.ResetTimer()
525+
b.RunParallel(func(pb *testing.PB) {
526+
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
527+
for pb.Next() {
528+
l.Put(randomKey(rng), y.ValueStruct{Value: value, Meta: 0, UserMeta: 0})
529+
}
530+
})
531+
}

table/table.go

+4
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ func OpenTable(fd *os.File, opts Options) (*Table, error) {
232232
if err := t.initBiggestAndSmallest(); err != nil {
233233
return nil, errors.Wrapf(err, "failed to initialize table")
234234
}
235+
235236
if opts.ChkMode == options.OnTableRead || opts.ChkMode == options.OnTableAndBlockRead {
236237
if err := t.VerifyChecksum(); err != nil {
237238
_ = fd.Close()
@@ -320,6 +321,9 @@ func (t *Table) readIndex() error {
320321
readPos -= 4
321322
buf := t.readNoFail(readPos, 4)
322323
checksumLen := int(y.BytesToU32(buf))
324+
if checksumLen < 0 {
325+
return errors.New("checksum length less than zero. Data corrupted")
326+
}
323327

324328
// Read checksum.
325329
expectedChk := &pb.Checksum{}

table/table_test.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -743,7 +743,10 @@ func TestTableChecksum(t *testing.T) {
743743
f := buildTestTable(t, "k", 10000, opts)
744744
fi, err := f.Stat()
745745
require.NoError(t, err, "unable to get file information")
746-
f.WriteAt(rb, rand.Int63n(fi.Size()))
746+
// Write random bytes at random location.
747+
n, err := f.WriteAt(rb, rand.Int63n(fi.Size()))
748+
require.NoError(t, err)
749+
require.Equal(t, n, len(rb))
747750

748751
_, err = OpenTable(f, opts)
749752
if err == nil || !strings.Contains(err.Error(), "checksum") {

0 commit comments

Comments
 (0)