Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use cache for storing block offsets #1336

Merged
merged 8 commits into from
May 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion iterator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ func TestPickSortTables(t *testing.T) {
}

func TestIteratePrefix(t *testing.T) {
runBadgerTest(t, nil, func(t *testing.T, db *DB) {
testIteratorPrefix := func(t *testing.T, db *DB) {
bkey := func(i int) []byte {
return []byte(fmt.Sprintf("%04d", i))
}
Expand Down Expand Up @@ -198,7 +198,38 @@ func TestIteratePrefix(t *testing.T) {
for i := 0; i < n; i++ {
require.Equal(t, 1, countOneKey(bkey(i)))
}
}

t.Run("With Default options", func(t *testing.T) {
runBadgerTest(t, nil, func(t *testing.T, db *DB) {
testIteratorPrefix(t, db)
})
})

t.Run("With Block Offsets in Cache", func(t *testing.T) {
opts := getTestOptions("")
opts = opts.WithKeepBlockIndicesInCache(true)
runBadgerTest(t, &opts, func(t *testing.T, db *DB) {
testIteratorPrefix(t, db)
})
})

t.Run("With Block Offsets and Blocks in Cache", func(t *testing.T) {
opts := getTestOptions("")
opts = opts.WithKeepBlockIndicesInCache(true).WithKeepBlocksInCache(true)
runBadgerTest(t, &opts, func(t *testing.T, db *DB) {
testIteratorPrefix(t, db)
})
})

t.Run("With Blocks in Cache", func(t *testing.T) {
opts := getTestOptions("")
opts = opts.WithKeepBlocksInCache(true)
runBadgerTest(t, &opts, func(t *testing.T, db *DB) {
testIteratorPrefix(t, db)
})
})

}

// go test -v -run=XXX -bench=BenchmarkIterate -benchtime=3s
Expand Down
61 changes: 53 additions & 8 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@ type Options struct {
// ChecksumVerificationMode decides when db should verify checksums for SSTable blocks.
ChecksumVerificationMode options.ChecksumVerificationMode

// KeepBlockIndicesInCache decides whether to keep the block offsets in the cache or not.
KeepBlockIndicesInCache bool

// KeepBlocksInCache decides whether to keep the sst blocks in the cache or not.
KeepBlocksInCache bool

// Transaction start and commit timestamps are managed by end-user.
// This is only useful for databases built on top of Badger (like Dgraph).
// Not recommended for most users.
Expand Down Expand Up @@ -157,19 +163,23 @@ func DefaultOptions(path string) Options {
LogRotatesToFlush: 2,
EncryptionKey: []byte{},
EncryptionKeyRotationDuration: 10 * 24 * time.Hour, // Default 10 days.
KeepBlocksInCache: false,
KeepBlockIndicesInCache: false,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it the same cache that is referenced in 21735af?

}
}

func buildTableOptions(opt Options) table.Options {
return table.Options{
TableSize: uint64(opt.MaxTableSize),
BlockSize: opt.BlockSize,
BloomFalsePositive: opt.BloomFalsePositive,
LoadBloomsOnOpen: opt.LoadBloomsOnOpen,
LoadingMode: opt.TableLoadingMode,
ChkMode: opt.ChecksumVerificationMode,
Compression: opt.Compression,
ZSTDCompressionLevel: opt.ZSTDCompressionLevel,
TableSize: uint64(opt.MaxTableSize),
BlockSize: opt.BlockSize,
BloomFalsePositive: opt.BloomFalsePositive,
LoadBloomsOnOpen: opt.LoadBloomsOnOpen,
LoadingMode: opt.TableLoadingMode,
ChkMode: opt.ChecksumVerificationMode,
Compression: opt.Compression,
ZSTDCompressionLevel: opt.ZSTDCompressionLevel,
KeepBlockIndicesInCache: opt.KeepBlockIndicesInCache,
KeepBlocksInCache: opt.KeepBlocksInCache,
}
}

Expand Down Expand Up @@ -631,3 +641,38 @@ func (opt Options) WithLoadBloomsOnOpen(b bool) Options {
opt.LoadBloomsOnOpen = b
return opt
}

// WithKeepBlockIndicesInCache returns a new Option value with KeepBlockOffsetInCache set to the
// given value.
//
// When this option is set badger will store the block offsets in a cache along with the blocks.
// The size of the cache is determined by the MaxCacheSize option.If the MaxCacheSize is set to
// zero, then MaxCacheSize is set to 100 mb. When indices are stored in the cache, the read
// performance might be affected but the cache limits the amount of memory used by the indices.
//
// The default value of KeepBlockOffsetInCache is false.
func (opt Options) WithKeepBlockIndicesInCache(val bool) Options {
opt.KeepBlockIndicesInCache = val

if val && opt.MaxCacheSize == 0 {
opt.MaxCacheSize = 100 << 20
}
return opt
}

// WithKeepBlocksInCache returns a new Option value with KeepBlocksInCache set to the
// given value.
//
// When this option is set badger will store the block in the cache. The size of the cache is
// determined by the MaxCacheSize option.If the MaxCacheSize is set to zero,
// then MaxCacheSize is set to 100 mb.
//
// The default value of KeepBlocksInCache is false.
func (opt Options) WithKeepBlocksInCache(val bool) Options {
opt.KeepBlocksInCache = val

if val && opt.MaxCacheSize == 0 {
opt.MaxCacheSize = 100 << 20
}
return opt
}
4 changes: 2 additions & 2 deletions table/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@ func TestTableIndex(t *testing.T) {
}

// Ensure index is built correctly
require.Equal(t, blockCount, len(tbl.blockIndex))
for i, ko := range tbl.blockIndex {
require.Equal(t, blockCount, tbl.noOfBlocks)
for i, ko := range tbl.readTableIndex().Offsets {
require.Equal(t, ko.Key, blockFirstKeys[i])
}
f.Close()
Expand Down
12 changes: 6 additions & 6 deletions table/iterator.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ func (itr *Iterator) Valid() bool {
}

func (itr *Iterator) seekToFirst() {
numBlocks := len(itr.t.blockIndex)
numBlocks := itr.t.noOfBlocks
if numBlocks == 0 {
itr.err = io.EOF
return
Expand All @@ -212,7 +212,7 @@ func (itr *Iterator) seekToFirst() {
}

func (itr *Iterator) seekToLast() {
numBlocks := len(itr.t.blockIndex)
numBlocks := itr.t.noOfBlocks
if numBlocks == 0 {
itr.err = io.EOF
return
Expand Down Expand Up @@ -249,8 +249,8 @@ func (itr *Iterator) seekFrom(key []byte, whence int) {
case current:
}

idx := sort.Search(len(itr.t.blockIndex), func(idx int) bool {
ko := itr.t.blockIndex[idx]
idx := sort.Search(itr.t.noOfBlocks, func(idx int) bool {
ko := itr.t.blockOffsets()[idx]
return y.CompareKeys(ko.Key, key) > 0
})
if idx == 0 {
Expand All @@ -269,7 +269,7 @@ func (itr *Iterator) seekFrom(key []byte, whence int) {
itr.seekHelper(idx-1, key)
if itr.err == io.EOF {
// Case 1. Need to visit block[idx].
if idx == len(itr.t.blockIndex) {
if idx == itr.t.noOfBlocks {
// If idx == len(itr.t.blockIndex), then input key is greater than ANY element of table.
// There's nothing we can do. Valid() should return false as we seek to end of table.
return
Expand Down Expand Up @@ -297,7 +297,7 @@ func (itr *Iterator) seekForPrev(key []byte) {
func (itr *Iterator) next() {
itr.err = nil

if itr.bpos >= len(itr.t.blockIndex) {
if itr.bpos >= itr.t.noOfBlocks {
itr.err = io.EOF
return
}
Expand Down
Loading