diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 0672bafba..7a6ad9353 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1,4 +1,4 @@
# CODEOWNERS info: https://help.github.com/en/articles/about-code-owners
# Owners are automatically requested for review for PRs that changes code
# that they own.
-* @akon-dey @nosql22 @billprovince @joshua-goldstein @skrdgraph
+* @dgraph-io/committers
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 000000000..2e3cbc665
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,22 @@
+version: 2
+updates:
+ - package-ecosystem: "gomod"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ day: "wednesday"
+ time: "16:00"
+ rebase-strategy: "disabled"
+ groups:
+ patch:
+ update-types: ["patch"]
+ minor:
+ update-types: ["minor"]
+
+ - package-ecosystem: "github-actions"
+ # Workflow files stored in the default location of `.github/workflows`. (You don't need to specify `/.github/workflows` for `directory`. You can use `directory: "/"`.)
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ day: wednesday
+ time: "16:00"
diff --git a/.github/stale.yml b/.github/stale.yml
deleted file mode 100644
index 947c39f48..000000000
--- a/.github/stale.yml
+++ /dev/null
@@ -1,20 +0,0 @@
-# Number of days of inactivity before an issue becomes stale
-daysUntilStale: 30
-# Number of days of inactivity before a stale issue is closed
-daysUntilClose: 7
-# Issues with these labels will never be considered stale
-exemptLabels:
- - skip/stale
- - status/accepted
-# Label to use when marking an issue as stale
-staleLabel: status/stale
-# Comment to post when marking an issue as stale. Set to `false` to disable
-markComment: >
- This issue has been automatically marked as stale because it has not had
- recent activity. It will be closed if no further activity occurs. Thank you
- for your contributions.
-# Comment to post when closing a stale issue. Set to `false` to disable
-closeComment: >
- This issue was marked as stale and no activity has occurred since then,
- therefore it will now be closed. Please, reopen if the issue is still
- relevant.
diff --git a/.github/workflows/cd-badger.yml b/.github/workflows/cd-badger.yml
index 930fec9b9..2d6329bcb 100644
--- a/.github/workflows/cd-badger.yml
+++ b/.github/workflows/cd-badger.yml
@@ -8,9 +8,9 @@ on:
type: string
jobs:
badger-build-amd64:
- runs-on: ubuntu-20.04
+ runs-on: warp-ubuntu-latest-x64-4x
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
ref: '${{ github.event.inputs.releasetag }}'
- name: Get Go Version
@@ -19,7 +19,7 @@ jobs:
GOVERSION=$({ [ -f .go-version ] && cat .go-version; })
echo "GOVERSION=$GOVERSION" >> $GITHUB_ENV
- name: Set up Go
- uses: actions/setup-go@v3
+ uses: actions/setup-go@v5
with:
go-version: ${{ env.GOVERSION }}
- name: Set Badger Release Version
@@ -45,15 +45,16 @@ jobs:
- name: Tar Archive for Linux Build
run: cd badger && tar -zcvf badger-linux-amd64.tar.gz badger-linux-amd64
- name: Upload Badger Binary Build Artifacts
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
+ name: badger-linux-amd64-${{ github.run_id }}-${{ github.job }}
path: |
badger/badger-checksum-linux-amd64.sha256
badger/badger-linux-amd64.tar.gz
badger-build-arm64:
- runs-on: [self-hosted, ARM64]
+ runs-on: warp-ubuntu-latest-arm64-4x
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
ref: '${{ github.event.inputs.releasetag }}'
- name: Get Go Version
@@ -62,7 +63,7 @@ jobs:
GOVERSION=$({ [ -f .go-version ] && cat .go-version; })
echo "GOVERSION=$GOVERSION" >> $GITHUB_ENV
- name: Set up Go
- uses: actions/setup-go@v3
+ uses: actions/setup-go@v5
with:
go-version: ${{ env.GOVERSION }}
- name: Set Badger Release Version
@@ -87,9 +88,12 @@ jobs:
run: cd badger && sha256sum badger-linux-arm64 | cut -c-64 > badger-checksum-linux-arm64.sha256
- name: Tar Archive for Linux Build
run: cd badger && tar -zcvf badger-linux-arm64.tar.gz badger-linux-arm64
+ - name: List Artifacts
+ run: ls -al badger/
- name: Upload Badger Binary Build Artifacts
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
+ name: badger-linux-arm64-${{ github.run_id }}-${{ github.job }}
path: |
badger/badger-checksum-linux-arm64.sha256
badger/badger-linux-arm64.tar.gz
diff --git a/.github/workflows/ci-aqua-security-trivy-tests.yml b/.github/workflows/ci-aqua-security-trivy-tests.yml
index 6dff9300f..6eb09fee0 100644
--- a/.github/workflows/ci-aqua-security-trivy-tests.yml
+++ b/.github/workflows/ci-aqua-security-trivy-tests.yml
@@ -1,8 +1,5 @@
name: ci-aqua-security-trivy-tests
on:
- push:
- branches:
- - main
pull_request:
types:
- opened
@@ -10,16 +7,20 @@ on:
- synchronize
- ready_for_review
branches:
- - main
+ - main
schedule:
- - cron: "0 * * * *"
+ - cron: "0 0 * * *"
+
+permissions:
+ security-events: write
+
jobs:
build:
name: trivy-tests
- runs-on: ubuntu-20.04
+ runs-on: warp-ubuntu-latest-x64-4x
steps:
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
@@ -28,6 +29,6 @@ jobs:
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload Trivy scan results to GitHub Security tab
- uses: github/codeql-action/upload-sarif@v2
+ uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: 'trivy-results.sarif'
diff --git a/.github/workflows/ci-badger-bank-tests-nightly.yml b/.github/workflows/ci-badger-bank-tests-nightly.yml
index c30f1b72c..36a639d70 100644
--- a/.github/workflows/ci-badger-bank-tests-nightly.yml
+++ b/.github/workflows/ci-badger-bank-tests-nightly.yml
@@ -5,19 +5,19 @@ on:
- main
- 'release/v*'
schedule:
- - cron: "0 3 * * *"
+ - cron: "1 3 * * *"
jobs:
badger-bank:
- runs-on: ubuntu-20.04
+ runs-on: warp-ubuntu-latest-x64-4x
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Get Go Version
run: |
#!/bin/bash
GOVERSION=$({ [ -f .go-version ] && cat .go-version; })
echo "GOVERSION=$GOVERSION" >> $GITHUB_ENV
- name: Setup Go
- uses: actions/setup-go@v3
+ uses: actions/setup-go@v5
with:
go-version: ${{ env.GOVERSION }}
- name: Install Dependencies
diff --git a/.github/workflows/ci-badger-bank-tests.yml b/.github/workflows/ci-badger-bank-tests.yml
index 30a70c7d3..821e5202f 100644
--- a/.github/workflows/ci-badger-bank-tests.yml
+++ b/.github/workflows/ci-badger-bank-tests.yml
@@ -1,27 +1,21 @@
name: ci-badger-bank-tests
on:
- push:
- branches:
- - main
- - 'release/v*'
pull_request:
branches:
- main
- 'release/v*'
- schedule:
- - cron: "*/30 * * * *"
jobs:
badger-bank:
- runs-on: ubuntu-20.04
+ runs-on: warp-ubuntu-latest-x64-4x
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Get Go Version
run: |
#!/bin/bash
GOVERSION=$({ [ -f .go-version ] && cat .go-version; })
echo "GOVERSION=$GOVERSION" >> $GITHUB_ENV
- name: Setup Go
- uses: actions/setup-go@v3
+ uses: actions/setup-go@v5
with:
go-version: ${{ env.GOVERSION }}
- name: Install Dependencies
diff --git a/.github/workflows/ci-badger-tests-coverage.yml b/.github/workflows/ci-badger-tests-coverage.yml
index c5dccb3da..86b2d1966 100644
--- a/.github/workflows/ci-badger-tests-coverage.yml
+++ b/.github/workflows/ci-badger-tests-coverage.yml
@@ -1,14 +1,14 @@
name: ci-badger-tests-coverage
on:
- pull_request_target:
+ pull_request:
branches:
- main
- 'release/v*'
jobs:
badger-tests-coverage:
- runs-on: ubuntu-20.04
+ runs-on: warp-ubuntu-latest-x64-4x
steps:
- - uses: actions/checkout@v3 # checkout merge commit
+ - uses: actions/checkout@v4 # checkout merge commit
with:
ref: "refs/pull/${{ github.event.number }}/merge"
- name: Get Go Version
@@ -17,7 +17,7 @@ jobs:
GOVERSION=$({ [ -f .go-version ] && cat .go-version; })
echo "GOVERSION=$GOVERSION" >> $GITHUB_ENV
- name: Setup Go
- uses: actions/setup-go@v3
+ uses: actions/setup-go@v5
with:
go-version: ${{ env.GOVERSION }}
- name: Install Dependencies
diff --git a/.github/workflows/ci-badger-tests.yml b/.github/workflows/ci-badger-tests.yml
index cf698eca3..1da509eb1 100644
--- a/.github/workflows/ci-badger-tests.yml
+++ b/.github/workflows/ci-badger-tests.yml
@@ -1,27 +1,21 @@
name: ci-badger-tests
on:
- push:
- branches:
- - main
- - 'release/v*'
pull_request:
branches:
- main
- 'release/v*'
- schedule:
- - cron: "*/30 * * * *"
jobs:
badger-tests:
- runs-on: ubuntu-20.04
+ runs-on: warp-ubuntu-latest-x64-4x
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Get Go Version
run: |
#!/bin/bash
GOVERSION=$({ [ -f .go-version ] && cat .go-version; })
echo "GOVERSION=$GOVERSION" >> $GITHUB_ENV
- name: Setup Go
- uses: actions/setup-go@v3
+ uses: actions/setup-go@v5
with:
go-version: ${{ env.GOVERSION }}
- name: Install Dependencies
diff --git a/.github/workflows/ci-dgraph-tests.yml b/.github/workflows/ci-dgraph-tests.yml
index 5c277c6ba..0d1dcbc2a 100644
--- a/.github/workflows/ci-dgraph-tests.yml
+++ b/.github/workflows/ci-dgraph-tests.yml
@@ -5,10 +5,10 @@ on:
- main
jobs:
dgraph-tests:
- runs-on: [self-hosted, x64]
+ runs-on: warp-ubuntu-latest-x64-16x
steps:
- name: Checkout Dgraph repo
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
repository: dgraph-io/dgraph
ref: main
@@ -18,14 +18,14 @@ jobs:
GOVERSION=$({ [ -f .go-version ] && cat .go-version; })
echo "GOVERSION=$GOVERSION" >> $GITHUB_ENV
- name: Set up Go
- uses: actions/setup-go@v3
+ uses: actions/setup-go@v5
with:
go-version: ${{ env.GOVERSION }}
- name: Fetch latest Badger version
run: |
go get github.com/dgraph-io/badger/v4@main
- name: Set up Node
- uses: actions/setup-node@v3
+ uses: actions/setup-node@v4
with:
node-version: 16
- name: Install protobuf-compiler
diff --git a/.github/workflows/ci-golang-lint.yml b/.github/workflows/ci-golang-lint.yml
index b3d2647a2..4899b955d 100644
--- a/.github/workflows/ci-golang-lint.yml
+++ b/.github/workflows/ci-golang-lint.yml
@@ -1,37 +1,29 @@
name: ci-golang-lint
on:
- push:
- branches:
- - main
- - 'release/v*'
pull_request:
branches:
- main
- 'release/v*'
- schedule:
- - cron: "*/30 * * * *"
jobs:
go-lint:
name: lint
- runs-on: ubuntu-20.04
+ runs-on: warp-ubuntu-latest-x64-4x
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Get Go Version
run: |
#!/bin/bash
GOVERSION=$({ [ -f .go-version ] && cat .go-version; })
echo "GOVERSION=$GOVERSION" >> $GITHUB_ENV
- name: Setup Go
- uses: actions/setup-go@v3
+ uses: actions/setup-go@v5
with:
go-version: ${{ env.GOVERSION }}
- name: golang-lint
- env:
- # prevent OOM
- GOGC: 10
- uses: golangci/golangci-lint-action@v3.2.0
+ uses: golangci/golangci-lint-action@v6
with:
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
- version: v1.48
+ version: latest
only-new-issues: true
args: --timeout=10m
+ skip-cache: true
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
new file mode 100644
index 000000000..4f0a38bdc
--- /dev/null
+++ b/.github/workflows/stale.yml
@@ -0,0 +1,18 @@
+name: 'Close stale issues and PRs'
+on:
+ schedule:
+ - cron: '00 02,14 * * *'
+
+permissions:
+ issues: write
+ pull-requests: write
+
+jobs:
+ stale:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/stale@v9
+ with:
+ stale-issue-message: 'This issue has been stale for 60 days and will be closed automatically in 7 days. Comment to keep it open.'
+ stale-pr-message: 'This PR has been stale for 60 days and will be closed automatically in 7 days. Comment to keep it open.'
+ operations-per-run: 100
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a2ebd9b0b..acd51459a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
### Fixed
+- fix(db): avoid panic in parallel reads after closing DB (#1987)
- fix(logging): fix direct access to logger (#1980)
- fix(sec): bump google.golang.org/grpc from 1.20.1 to 1.53.0 (#1977)
- fix(sec): update gopkg.in/yaml.v2 package (#1969)
diff --git a/README.md b/README.md
index 0862aa4ca..06e91d5e6 100644
--- a/README.md
+++ b/README.md
@@ -39,7 +39,7 @@ Please consult the [Changelog] for more detailed information on releases.
For more details on our version naming schema please read [Choosing a version](#choosing-a-version).
-[Changelog]:https://github.com/dgraph-io/badger/blob/master/CHANGELOG.md
+[Changelog]:https://github.com/dgraph-io/badger/blob/main/CHANGELOG.md
## Table of Contents
- [BadgerDB](#badgerdb)
@@ -62,7 +62,7 @@ For more details on our version naming schema please read [Choosing a version](#
## Getting Started
### Installing
-To start using Badger, install Go 1.19 or above. Badger v3 needs go modules. From your project, run the following command
+To start using Badger, install Go 1.19 or above. Badger v3 and above needs go modules. From your project, run the following command
```sh
$ go get github.com/dgraph-io/badger/v4
@@ -219,6 +219,9 @@ Below is a list of known projects that use Badger:
* [Loggie](https://github.com/loggie-io/loggie) - A lightweight, cloud-native data transfer agent and aggregator.
* [raft-badger](https://github.com/rfyiamcool/raft-badger) - raft-badger implements LogStore and StableStore Interface of hashcorp/raft. it is used to store raft log and metadata of hashcorp/raft.
* [DVID](https://github.com/janelia-flyem/dvid) - A dataservice for branched versioning of a variety of data types. Originally created for large-scale brain reconstructions in Connectomics.
+* [KVS](https://github.com/tauraamui/kvs) - A library for making it easy to persist, load and query full structs into BadgerDB, using an ownership hierarchy model.
+* [LLS](https://github.com/Boc-chi-no/LLS) - LLS is an efficient URL Shortener that can be used to shorten links and track link usage. Support for BadgerDB and MongoDB. Improved performance by more than 30% when using BadgerDB
+* [lakeFS](https://github.com/treeverse/lakeFS) - lakeFS is an open-source data version control that transforms your object storage to Git-like repositories. lakeFS uses BadgerDB for its underlying local metadata KV store implementation.
If you are using Badger in a project please send a pull request to add it to the list.
diff --git a/batch_test.go b/batch_test.go
index d2dc01f37..0637dd6f1 100644
--- a/batch_test.go
+++ b/batch_test.go
@@ -103,7 +103,12 @@ func TestEmptyWriteBatch(t *testing.T) {
wb = db.NewWriteBatch()
require.NoError(t, wb.Flush())
wb = db.NewWriteBatch()
+ // Flush commits inner txn and sets a new one instead.
+ // Thus we need to save it to check if it was discarded.
+ txn := wb.txn
require.NoError(t, wb.Flush())
+ // check that flushed txn was discarded and marked as read.
+ require.True(t, txn.discarded)
})
})
t.Run("managed mode", func(t *testing.T) {
diff --git a/db.go b/db.go
index d30ac6c3d..ba060cc57 100644
--- a/db.go
+++ b/db.go
@@ -34,6 +34,7 @@ import (
humanize "github.com/dustin/go-humanize"
"github.com/pkg/errors"
+ "github.com/dgraph-io/badger/v4/fb"
"github.com/dgraph-io/badger/v4/options"
"github.com/dgraph-io/badger/v4/pb"
"github.com/dgraph-io/badger/v4/skl"
@@ -123,8 +124,8 @@ type DB struct {
pub *publisher
registry *KeyRegistry
- blockCache *ristretto.Cache
- indexCache *ristretto.Cache
+ blockCache *ristretto.Cache[[]byte, *table.Block]
+ indexCache *ristretto.Cache[uint64, *fb.TableIndex]
allocPool *z.AllocatorPool
}
@@ -162,10 +163,10 @@ func checkAndSetOptions(opt *Options) error {
// the transaction APIs. Transaction batches entries into batches of size opt.maxBatchSize.
if opt.ValueThreshold > opt.maxBatchSize {
return errors.Errorf("Valuethreshold %d greater than max batch size of %d. Either "+
- "reduce opt.ValueThreshold or increase opt.MaxTableSize.",
+ "reduce opt.ValueThreshold or increase opt.BaseTableSize.",
opt.ValueThreshold, opt.maxBatchSize)
}
- // ValueLogFileSize should be stricly LESS than 2<<30 otherwise we will
+ // ValueLogFileSize should be strictly LESS than 2<<30 otherwise we will
// overflow the uint32 when we mmap it in OpenMemtable.
if !(opt.ValueLogFileSize < 2<<30 && opt.ValueLogFileSize >= 1<<20) {
return ErrValueLogSize
@@ -274,14 +275,14 @@ func Open(opt Options) (*DB, error) {
numInCache = 1
}
- config := ristretto.Config{
+ config := ristretto.Config[[]byte, *table.Block]{
NumCounters: numInCache * 8,
MaxCost: opt.BlockCacheSize,
BufferItems: 64,
Metrics: true,
OnExit: table.BlockEvictHandler,
}
- db.blockCache, err = ristretto.NewCache(&config)
+ db.blockCache, err = ristretto.NewCache[[]byte, *table.Block](&config)
if err != nil {
return nil, y.Wrap(err, "failed to create data cache")
}
@@ -297,7 +298,7 @@ func Open(opt Options) (*DB, error) {
numInCache = 1
}
- config := ristretto.Config{
+ config := ristretto.Config[uint64, *fb.TableIndex]{
NumCounters: numInCache * 8,
MaxCost: opt.IndexCacheSize,
BufferItems: 64,
@@ -402,7 +403,7 @@ func Open(opt Options) (*DB, error) {
return db, nil
}
-// initBannedNamespaces retrieves the banned namepsaces from the DB and updates in-memory structure.
+// initBannedNamespaces retrieves the banned namespaces from the DB and updates in-memory structure.
func (db *DB) initBannedNamespaces() error {
if db.opt.NamespaceOffset < 0 {
return nil
@@ -904,7 +905,7 @@ func (db *DB) sendToWriteCh(entries []*Entry) (*request, error) {
return nil, ErrTxnTooBig
}
- // We can only service one request because we need each txn to be stored in a contigous section.
+ // We can only service one request because we need each txn to be stored in a contiguous section.
// Txns should not interleave among other txns or rewrites.
req := requestPool.Get().(*request)
req.reset()
@@ -1617,7 +1618,7 @@ func (db *DB) Flatten(workers int) error {
}
}
if len(levels) <= 1 {
- prios := db.lc.pickCompactLevels()
+ prios := db.lc.pickCompactLevels(nil)
if len(prios) == 0 || prios[0].score <= 1.0 {
db.opt.Infof("All tables consolidated into one level. Flattening done.\n")
return nil
@@ -1709,7 +1710,7 @@ func (db *DB) dropAll() (func(), error) {
if err != nil {
return f, err
}
- // prepareToDrop will stop all the incomming write and flushes any pending memtables.
+ // prepareToDrop will stop all the incoming write and flushes any pending memtables.
// Before we drop, we'll stop the compaction because anyways all the datas are going to
// be deleted.
db.stopCompactions()
@@ -1752,7 +1753,7 @@ func (db *DB) dropAll() (func(), error) {
// DropPrefix would drop all the keys with the provided prefix. It does this in the following way:
// - Stop accepting new writes.
-// - Stop memtable flushes before acquiring lock. Because we're acquring lock here
+// - Stop memtable flushes before acquiring lock. Because we're acquiring lock here
// and memtable flush stalls for lock, which leads to deadlock
// - Flush out all memtables, skipping over keys with the given prefix, Kp.
// - Write out the value log header to memtables when flushing, so we don't accidentally bring Kp
diff --git a/db_test.go b/db_test.go
index 1e2306a20..ca2803874 100644
--- a/db_test.go
+++ b/db_test.go
@@ -1800,7 +1800,7 @@ func TestLSMOnly(t *testing.T) {
// Also test for error, when ValueThresholdSize is greater than maxBatchSize.
dopts.ValueThreshold = LSMOnlyOptions(dir).ValueThreshold
- // maxBatchSize is calculated from MaxTableSize.
+ // maxBatchSize is calculated from BaseTableSize.
dopts.MemTableSize = LSMOnlyOptions(dir).ValueThreshold
_, err = Open(dopts)
require.Error(t, err, "db creation should have been failed")
diff --git a/docs/config.toml b/docs/config.toml
index eb6393175..146a343de 100644
--- a/docs/config.toml
+++ b/docs/config.toml
@@ -1,7 +1,6 @@
languageCode = "en-us"
theme = "hugo-docs"
canonifyURLs = false
-relativeURLs = true
[markup.goldmark.renderer]
unsafe = true
diff --git a/docs/content/faq/index.md b/docs/content/faq/index.md
index ed2e06bfb..599ec2438 100644
--- a/docs/content/faq/index.md
+++ b/docs/content/faq/index.md
@@ -57,7 +57,7 @@ workloads, you should be using the `Transaction` API.
If you're using Badger with `SyncWrites=false`, then your writes might not be written to value log
and won't get synced to disk immediately. Writes to LSM tree are done inmemory first, before they
-get compacted to disk. The compaction would only happen once `MaxTableSize` has been reached. So, if
+get compacted to disk. The compaction would only happen once `BaseTableSize` has been reached. So, if
you're doing a few writes and then checking, you might not see anything on disk. Once you `Close`
the database, you'll see these writes on disk.
diff --git a/docs/content/get-started/index.md b/docs/content/get-started/index.md
index 5d318fcf8..2d7b3087c 100644
--- a/docs/content/get-started/index.md
+++ b/docs/content/get-started/index.md
@@ -603,7 +603,7 @@ the `Options` struct that is passed in when opening the database using
- If you modify `Options.NumMemtables`, also adjust `Options.NumLevelZeroTables` and
`Options.NumLevelZeroTablesStall` accordingly.
- Number of concurrent compactions (`Options.NumCompactors`)
-- Size of table (`Options.MaxTableSize`)
+- Size of table (`Options.BaseTableSize`)
- Size of value log file (`Options.ValueLogFileSize`)
If you want to decrease the memory usage of Badger instance, tweak these
diff --git a/docs/content/projects-using-badger/index.md b/docs/content/projects-using-badger/index.md
index 234e22b47..664932cb1 100644
--- a/docs/content/projects-using-badger/index.md
+++ b/docs/content/projects-using-badger/index.md
@@ -56,5 +56,8 @@ Below is a list of known projects that use Badger:
* [Loggie](https://github.com/loggie-io/loggie) - A lightweight, cloud-native data transfer agent and aggregator.
* [raft-badger](https://github.com/rfyiamcool/raft-badger) - raft-badger implements LogStore and StableStore Interface of hashcorp/raft. it is used to store raft log and metadata of hashcorp/raft.
* [DVID](https://github.com/janelia-flyem/dvid) - A dataservice for branched versioning of a variety of data types. Originally created for large-scale brain reconstructions in Connectomics.
+* [KVS](https://github.com/tauraamui/kvs) - A library for making it easy to persist, load and query full structs into BadgerDB, using an ownership hierarchy model.
+* [LLS](https://github.com/Boc-chi-no/LLS) - LLS is an efficient URL Shortener that can be used to shorten links and track link usage. Support for BadgerDB and MongoDB. Improved performance by more than 30% when using BadgerDB
+* [ActionManager](https://mftlabs.io/actionmanager) - A dynamic entity manager based on rjsf schema and badger db
If you are using Badger in a project please send a pull request to add it to the list.
diff --git a/docs/themes/hugo-docs/layouts/partials/header.html b/docs/themes/hugo-docs/layouts/partials/header.html
index 56596976a..73b5b9f35 100644
--- a/docs/themes/hugo-docs/layouts/partials/header.html
+++ b/docs/themes/hugo-docs/layouts/partials/header.html
@@ -29,7 +29,7 @@
-
+
{{.Section | default "Badgerdb Documentation" | humanize}} — {{ .Site.Title }}
@@ -44,7 +44,7 @@
-
+
diff --git a/go.mod b/go.mod
index 2288f5c2f..1249fadd5 100644
--- a/go.mod
+++ b/go.mod
@@ -3,35 +3,31 @@ module github.com/dgraph-io/badger/v4
go 1.19
require (
- github.com/cespare/xxhash/v2 v2.2.0
- github.com/dgraph-io/ristretto v0.1.1
- github.com/dustin/go-humanize v1.0.0
+ github.com/cespare/xxhash/v2 v2.3.0
+ github.com/dgraph-io/ristretto v0.1.2-0.20240116140435-c67e07994f91
+ github.com/dustin/go-humanize v1.0.1
github.com/gogo/protobuf v1.3.2
- github.com/golang/protobuf v1.5.2
- github.com/golang/snappy v0.0.3
- github.com/google/flatbuffers v1.12.1
- github.com/klauspost/compress v1.12.3
+ github.com/golang/protobuf v1.5.4
+ github.com/google/flatbuffers v24.3.25+incompatible
+ github.com/klauspost/compress v1.17.9
github.com/pkg/errors v0.9.1
- github.com/spf13/cobra v0.0.5
- github.com/stretchr/testify v1.4.0
- go.opencensus.io v0.22.5
- golang.org/x/net v0.7.0
- golang.org/x/sys v0.5.0
+ github.com/spf13/cobra v1.8.1
+ github.com/stretchr/testify v1.9.0
+ go.opencensus.io v0.24.0
+ golang.org/x/net v0.28.0
+ golang.org/x/sys v0.24.0
)
require (
github.com/davecgh/go-spew v1.1.1 // indirect
- github.com/golang/glog v1.0.0 // indirect
- github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 // indirect
- github.com/inconshreveable/mousetrap v1.0.0 // indirect
- github.com/kr/pretty v0.1.0 // indirect
+ github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
+ github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/spf13/pflag v1.0.3 // indirect
- google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect
- google.golang.org/grpc v1.53.0 // indirect
- google.golang.org/protobuf v1.28.1 // indirect
- gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
- gopkg.in/yaml.v2 v2.2.8 // indirect
+ github.com/spf13/pflag v1.0.5 // indirect
+ google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
+ google.golang.org/grpc v1.56.3 // indirect
+ google.golang.org/protobuf v1.33.0 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
)
retract v4.0.0 // see #1888 and #1889
diff --git a/go.sum b/go.sum
index 406dc3ef4..60215369a 100644
--- a/go.sum
+++ b/go.sum
@@ -1,84 +1,78 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
-github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
-github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
+github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
-github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
-github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
-github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8=
-github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA=
-github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
-github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
-github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
-github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
-github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/dgraph-io/ristretto v0.1.2-0.20240116140435-c67e07994f91 h1:Pux6+xANi0I7RRo5E1gflI4EZ2yx3BGZ75JkAIvGEOA=
+github.com/dgraph-io/ristretto v0.1.2-0.20240116140435-c67e07994f91/go.mod h1:swkazRqnUf1N62d0Nutz7KIj2UKqsm/H8tD0nBJAXqM=
+github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y=
+github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
+github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=
-github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
-github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I=
-github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
-github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
-github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/google/flatbuffers v1.12.1 h1:MVlul7pQNoDzWRLTw5imwYsl+usrS1TXG2H4jg6ImGw=
-github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI=
+github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
-github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
-github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
-github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
+github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/klauspost/compress v1.12.3 h1:G5AfA94pHPysR56qqrkO2pxEexdDzrpFJ6yt/VqWxVU=
-github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
-github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
-github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
-github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
+github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
-github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
-github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
-github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
-github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
-github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
-github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
-github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
+github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
-github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
-github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
-github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-go.opencensus.io v0.22.5 h1:dntmOdLpSpHlVqbW5Eay97DelsZHe+55D+xC6i0dDS0=
-go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
-golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
+go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@@ -96,31 +90,29 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
-golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
+golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
-golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
+golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
+golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
@@ -131,21 +123,32 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w=
-google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
+google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
-google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc=
-google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
-google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
-google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
+google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc=
+google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
+google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
-gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/iterator.go b/iterator.go
index 2f69db6b2..a4a611001 100644
--- a/iterator.go
+++ b/iterator.go
@@ -589,7 +589,7 @@ func (it *Iterator) Next() {
// Set next item to current
it.item = it.data.pop()
- for it.iitr.Valid() {
+ for it.iitr.Valid() && hasPrefix(it.iitr, it.opt.Prefix) {
if it.parseItem() {
// parseItem calls one extra next.
// This is used to deal with the complexity of reverse iteration.
@@ -725,6 +725,13 @@ func (it *Iterator) fill(item *Item) {
}
}
+func hasPrefix(it y.Iterator, prefix []byte) bool {
+ if len(prefix) > 0 {
+ return bytes.HasPrefix(y.ParseKey(it.Key()), prefix)
+ }
+ return true
+}
+
func (it *Iterator) prefetch() {
prefetchSize := 2
if it.opt.PrefetchValues && it.opt.PrefetchSize > 1 {
@@ -734,7 +741,7 @@ func (it *Iterator) prefetch() {
i := it.iitr
var count int
it.item = nil
- for i.Valid() {
+ for i.Valid() && hasPrefix(i, it.opt.Prefix) {
if !it.parseItem() {
continue
}
diff --git a/level_handler.go b/level_handler.go
index 31673f15b..fc81cc452 100644
--- a/level_handler.go
+++ b/level_handler.go
@@ -165,8 +165,8 @@ func (s *levelHandler) addTable(t *table.Table) {
// sortTables sorts tables of levelHandler based on table.Smallest.
// Normally it should be called after all addTable calls.
func (s *levelHandler) sortTables() {
- s.RLock()
- defer s.RUnlock()
+ s.Lock()
+ defer s.Unlock()
sort.Slice(s.tables, func(i, j int) bool {
return y.CompareKeys(s.tables[i].Smallest(), s.tables[j].Smallest()) < 0
diff --git a/levels.go b/levels.go
index 3e397e704..6bbaf55ca 100644
--- a/levels.go
+++ b/levels.go
@@ -473,8 +473,13 @@ func (s *levelsController) runCompactor(id int, lc *z.Closer) {
}
return false
}
+
+ var priosBuffer []compactionPriority
runOnce := func() bool {
- prios := s.pickCompactLevels()
+ prios := s.pickCompactLevels(priosBuffer)
+ defer func() {
+ priosBuffer = prios
+ }()
if id == 0 {
// Worker ID zero prefers to compact L0 always.
prios = moveL0toFront(prios)
@@ -536,7 +541,9 @@ func (s *levelsController) lastLevel() *levelHandler {
// pickCompactLevel determines which level to compact.
// Based on: https://github.com/facebook/rocksdb/wiki/Leveled-Compaction
-func (s *levelsController) pickCompactLevels() (prios []compactionPriority) {
+// It tries to reuse priosBuffer to reduce memory allocation,
+// passing nil is acceptable, then new memory will be allocated.
+func (s *levelsController) pickCompactLevels(priosBuffer []compactionPriority) (prios []compactionPriority) {
t := s.levelTargets()
addPriority := func(level int, score float64) {
pri := compactionPriority{
@@ -548,6 +555,12 @@ func (s *levelsController) pickCompactLevels() (prios []compactionPriority) {
prios = append(prios, pri)
}
+ // Grow buffer to fit all levels.
+ if cap(priosBuffer) < len(s.levels) {
+ priosBuffer = make([]compactionPriority, 0, len(s.levels))
+ }
+ prios = priosBuffer[:0]
+
// Add L0 priority based on the number of tables.
addPriority(0, float64(s.levels[0].numTables())/float64(s.kv.opt.NumLevelZeroTables))
@@ -1707,7 +1720,7 @@ type LevelInfo struct {
func (s *levelsController) getLevelInfo() []LevelInfo {
t := s.levelTargets()
- prios := s.pickCompactLevels()
+ prios := s.pickCompactLevels(nil)
result := make([]LevelInfo, len(s.levels))
for i, l := range s.levels {
l.RLock()
diff --git a/options.go b/options.go
index ac046bc1d..bb6131b30 100644
--- a/options.go
+++ b/options.go
@@ -173,8 +173,6 @@ func DefaultOptions(path string) Options {
// Benchmark code can be found in table/builder_test.go file
ZSTDCompressionLevel: 1,
- // Nothing to read/write value log using standard File I/O
- // MemoryMap to mmap() the value log files
// (2^30 - 1)*2 when mmapping < 2^31 - 1, max int32.
// -1 so 2*ValueLogFileSize won't overflow on 32-bit systems.
ValueLogFileSize: 1<<30 - 1,
@@ -463,7 +461,7 @@ func (opt Options) WithLoggingLevel(val loggingLevel) Options {
return opt
}
-// WithBaseTableSize returns a new Options value with MaxTableSize set to the given value.
+// WithBaseTableSize returns a new Options value with BaseTableSize set to the given value.
//
// BaseTableSize sets the maximum size in bytes for LSM table or file in the base level.
//
diff --git a/stream_writer_test.go b/stream_writer_test.go
index 4d18db8b1..6d8610df1 100644
--- a/stream_writer_test.go
+++ b/stream_writer_test.go
@@ -349,7 +349,7 @@ func TestStreamWriter6(t *testing.T) {
}
}
- // list has 3 pairs for equal keys. Since each Key has size equal to MaxTableSize
+ // list has 3 pairs for equal keys. Since each Key has size equal to BaseTableSize
// we would have 6 tables, if keys are not equal. Here we should have 3 tables.
sw := db.NewStreamWriter()
require.NoError(t, sw.Prepare(), "sw.Prepare() failed")
diff --git a/table/builder.go b/table/builder.go
index 5c9e065e0..bf0ac319a 100644
--- a/table/builder.go
+++ b/table/builder.go
@@ -25,8 +25,8 @@ import (
"unsafe"
"github.com/golang/protobuf/proto"
- "github.com/golang/snappy"
fbs "github.com/google/flatbuffers/go"
+ "github.com/klauspost/compress/s2"
"github.com/pkg/errors"
"github.com/dgraph-io/badger/v4/fb"
@@ -159,7 +159,7 @@ func NewTableBuilder(opts Options) *Builder {
func maxEncodedLen(ctype options.CompressionType, sz int) int {
switch ctype {
case options.Snappy:
- return snappy.MaxEncodedLen(sz)
+ return s2.MaxEncodedLen(sz)
case options.ZSTD:
return y.ZSTDCompressBound(sz)
}
@@ -523,9 +523,9 @@ func (b *Builder) compressData(data []byte) ([]byte, error) {
case options.None:
return data, nil
case options.Snappy:
- sz := snappy.MaxEncodedLen(len(data))
+ sz := s2.MaxEncodedLen(len(data))
dst := b.alloc.Allocate(sz)
- return snappy.Encode(dst, data), nil
+ return s2.EncodeSnappy(dst, data), nil
case options.ZSTD:
sz := y.ZSTDCompressBound(len(data))
dst := b.alloc.Allocate(sz)
diff --git a/table/builder_test.go b/table/builder_test.go
index 0045b8887..bd693c92f 100644
--- a/table/builder_test.go
+++ b/table/builder_test.go
@@ -38,7 +38,7 @@ func TestTableIndex(t *testing.T) {
key := make([]byte, 32)
_, err := rand.Read(key)
require.NoError(t, err)
- cache, err := ristretto.NewCache(&ristretto.Config{
+ cache, err := ristretto.NewCache[uint64, *fb.TableIndex](&ristretto.Config[uint64, *fb.TableIndex]{
NumCounters: 1000,
MaxCost: 1 << 20,
BufferItems: 64,
@@ -178,12 +178,15 @@ func BenchmarkBuilder(b *testing.B) {
opt.BlockSize = 4 * 1024
opt.BloomFalsePositive = 0.01
opt.TableSize = 5 << 20
+
b.ResetTimer()
+ b.ReportAllocs()
for i := 0; i < b.N; i++ {
builder := NewTableBuilder(*opt)
for j := 0; j < keysCount; j++ {
builder.Add(keyList[j], vs, 0)
}
+
_ = builder.Finish()
builder.Close()
}
@@ -196,7 +199,7 @@ func BenchmarkBuilder(b *testing.B) {
})
b.Run("encryption", func(b *testing.B) {
var opt Options
- cache, err := ristretto.NewCache(&ristretto.Config{
+ cache, err := ristretto.NewCache(&ristretto.Config[uint64, *fb.TableIndex]{
NumCounters: 1000,
MaxCost: 1 << 20,
BufferItems: 64,
@@ -208,6 +211,11 @@ func BenchmarkBuilder(b *testing.B) {
opt.DataKey = &pb.DataKey{Data: key}
bench(b, &opt)
})
+ b.Run("snappy compression", func(b *testing.B) {
+ var opt Options
+ opt.Compression = options.Snappy
+ bench(b, &opt)
+ })
b.Run("zstd compression", func(b *testing.B) {
var opt Options
opt.Compression = options.ZSTD
diff --git a/table/iterator.go b/table/iterator.go
index 109856582..d99203e39 100644
--- a/table/iterator.go
+++ b/table/iterator.go
@@ -34,7 +34,7 @@ type blockIterator struct {
key []byte
val []byte
entryOffsets []uint32
- block *block
+ block *Block
tableID uint64
blockID int
@@ -43,7 +43,7 @@ type blockIterator struct {
prevOverlap uint16
}
-func (itr *blockIterator) setBlock(b *block) {
+func (itr *blockIterator) setBlock(b *Block) {
// Decrement the ref for the old block. If the old block was compressed, we
// might be able to reuse it.
itr.block.decrRef()
diff --git a/table/table.go b/table/table.go
index 0bbc91089..432bec3f2 100644
--- a/table/table.go
+++ b/table/table.go
@@ -32,7 +32,8 @@ import (
"unsafe"
"github.com/golang/protobuf/proto"
- "github.com/golang/snappy"
+ "github.com/klauspost/compress/snappy"
+ "github.com/klauspost/compress/zstd"
"github.com/pkg/errors"
"github.com/dgraph-io/badger/v4/fb"
@@ -76,8 +77,8 @@ type Options struct {
Compression options.CompressionType
// Block cache is used to cache decompressed and decrypted blocks.
- BlockCache *ristretto.Cache
- IndexCache *ristretto.Cache
+ BlockCache *ristretto.Cache[[]byte, *Block]
+ IndexCache *ristretto.Cache[uint64, *fb.TableIndex]
AllocPool *z.AllocatorPool
@@ -177,13 +178,11 @@ func (t *Table) DecrRef() error {
}
// BlockEvictHandler is used to reuse the byte slice stored in the block on cache eviction.
-func BlockEvictHandler(value interface{}) {
- if b, ok := value.(*block); ok {
- b.decrRef()
- }
+func BlockEvictHandler(b *Block) {
+ b.decrRef()
}
-type block struct {
+type Block struct {
offset int
data []byte
checksum []byte
@@ -198,7 +197,7 @@ var NumBlocks atomic.Int32
// incrRef increments the ref of a block and return a bool indicating if the
// increment was successful. A true value indicates that the block can be used.
-func (b *block) incrRef() bool {
+func (b *Block) incrRef() bool {
for {
// We can't blindly add 1 to ref. We need to check whether it has
// reached zero first, because if it did, then we should absolutely not
@@ -221,7 +220,7 @@ func (b *block) incrRef() bool {
}
}
}
-func (b *block) decrRef() {
+func (b *Block) decrRef() {
if b == nil {
return
}
@@ -241,12 +240,12 @@ func (b *block) decrRef() {
}
y.AssertTrue(b.ref.Load() >= 0)
}
-func (b *block) size() int64 {
+func (b *Block) size() int64 {
return int64(3*intSize /* Size of the offset, entriesIndexStart and chkLen */ +
cap(b.data) + cap(b.checksum) + cap(b.entryOffsets)*4)
}
-func (b *block) verifyCheckSum() error {
+func (b *Block) verifyCheckSum() error {
cs := &pb.Checksum{}
if err := proto.Unmarshal(b.checksum, cs); err != nil {
return y.Wrapf(err, "unable to unmarshal checksum for block")
@@ -520,7 +519,7 @@ func (t *Table) fetchIndex() *fb.TableIndex {
panic("Index Cache must be set for encrypted workloads")
}
if val, ok := t.opt.IndexCache.Get(t.indexKey()); ok && val != nil {
- return val.(*fb.TableIndex)
+ return val
}
index, err := t.readTableIndex()
@@ -536,7 +535,7 @@ func (t *Table) offsets(ko *fb.BlockOffset, i int) bool {
// block function return a new block. Each block holds a ref and the byte
// slice stored in the block will be reused when the ref becomes zero. The
// caller should release the block by calling block.decrRef() on it.
-func (t *Table) block(idx int, useCache bool) (*block, error) {
+func (t *Table) block(idx int, useCache bool) (*Block, error) {
y.AssertTruef(idx >= 0, "idx=%d", idx)
if idx >= t.offsetsLength() {
return nil, errors.New("block out of index")
@@ -548,15 +547,15 @@ func (t *Table) block(idx int, useCache bool) (*block, error) {
// Use the block only if the increment was successful. The block
// could get evicted from the cache between the Get() call and the
// incrRef() call.
- if b := blk.(*block); b.incrRef() {
- return b, nil
+ if blk.incrRef() {
+ return blk, nil
}
}
}
var ko fb.BlockOffset
y.AssertTrue(t.offsets(&ko, idx))
- blk := &block{offset: int(ko.Offset())}
+ blk := &Block{offset: int(ko.Offset())}
blk.ref.Store(1)
defer blk.decrRef() // Deal with any errors, where blk would not be returned.
NumBlocks.Add(1)
@@ -794,7 +793,7 @@ func NewFilename(id uint64, dir string) string {
}
// decompress decompresses the data stored in a block.
-func (t *Table) decompress(b *block) error {
+func (t *Table) decompress(b *Block) error {
var dst []byte
var err error
@@ -818,6 +817,11 @@ func (t *Table) decompress(b *block) error {
}
case options.ZSTD:
sz := int(float64(t.opt.BlockSize) * 1.2)
+ // Get frame content size from header.
+ var hdr zstd.Header
+ if err := hdr.Decode(b.data); err == nil && hdr.HasFCS && hdr.FrameContentSize < uint64(t.opt.BlockSize*2) {
+ sz = int(hdr.FrameContentSize)
+ }
dst = z.Calloc(sz, "Table.Decompress")
b.data, err = y.ZSTDDecompress(dst, b.data)
if err != nil {
diff --git a/table/table_test.go b/table/table_test.go
index d1fef13b7..3e1cf0ba6 100644
--- a/table/table_test.go
+++ b/table/table_test.go
@@ -705,7 +705,7 @@ func TestTableChecksum(t *testing.T) {
})
}
-var cacheConfig = ristretto.Config{
+var cacheConfig = ristretto.Config[[]byte, *Block]{
NumCounters: 1000000 * 10,
MaxCost: 1000000,
BufferItems: 64,
@@ -848,7 +848,7 @@ func BenchmarkRandomRead(b *testing.B) {
}
}
-func getTableForBenchmarks(b *testing.B, count int, cache *ristretto.Cache) *Table {
+func getTableForBenchmarks(b *testing.B, count int, cache *ristretto.Cache[[]byte, *Block]) *Table {
rand.Seed(time.Now().Unix())
opts := Options{Compression: options.ZSTD, BlockSize: 4 * 1024, BloomFalsePositive: 0.01}
if cache == nil {
diff --git a/txn.go b/txn.go
index 4a5fe476c..438af8d5d 100644
--- a/txn.go
+++ b/txn.go
@@ -661,7 +661,9 @@ func (txn *Txn) Commit() error {
// txn.conflictKeys can be zero if conflict detection is turned off. So we
// should check txn.pendingWrites.
if len(txn.pendingWrites) == 0 {
- return nil // Nothing to do.
+ // Discard the transaction so that the read is marked done.
+ txn.Discard()
+ return nil
}
// Precheck before discarding txn.
if err := txn.commitPrecheck(); err != nil {
@@ -716,6 +718,8 @@ func (txn *Txn) CommitWith(cb func(error)) {
// callback might be acquiring the same locks. Instead run the callback
// from another goroutine.
go runTxnCallback(&txnCb{user: cb, err: nil})
+ // Discard the transaction so that the read is marked done.
+ txn.Discard()
return
}
diff --git a/value_test.go b/value_test.go
index 25af06eda..cbdcf4793 100644
--- a/value_test.go
+++ b/value_test.go
@@ -977,7 +977,7 @@ func BenchmarkReadWrite(b *testing.B) {
opts.ValueThreshold = 0
db, err := Open(opts)
y.Check(err)
-
+ defer db.Close()
vl := &db.vlog
b.ResetTimer()
diff --git a/watermark_edge_test.go b/watermark_edge_test.go
new file mode 100644
index 000000000..12e4fb0a9
--- /dev/null
+++ b/watermark_edge_test.go
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2023 Dgraph Labs, Inc. and Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package badger
+
+import (
+ "crypto/rand"
+ "errors"
+ "fmt"
+ "math/big"
+ "sync"
+ "testing"
+ "time"
+)
+
+func TestWaterMarkEdgeCase(t *testing.T) {
+ const N = 1_000
+ runBadgerTest(t, nil, func(t *testing.T, db *DB) {
+ eg := make(chan error, N)
+ defer close(eg)
+
+ var wg sync.WaitGroup
+ wg.Add(N)
+ for i := 0; i < N; i++ {
+ go func(j int) {
+ defer wg.Done()
+ if err := doWork(db, j); errors.Is(err, ErrConflict) {
+ eg <- nil
+ } else {
+ eg <- fmt.Errorf("expected conflict not found, err: %v, i = %v", err, j)
+ }
+ }(i)
+ }
+ wg.Wait()
+
+ for i := 0; i < N; i++ {
+ if err := <-eg; err != nil {
+ t.Fatal(err)
+ }
+ }
+ })
+}
+
+func doWork(db *DB, i int) error {
+ delay()
+
+ key1 := fmt.Sprintf("v:%d:%s", i, generateRandomBytes())
+ key2 := fmt.Sprintf("v:%d:%s", i, generateRandomBytes())
+
+ tx1 := db.NewTransaction(true)
+ defer tx1.Discard()
+ tx2 := db.NewTransaction(true)
+ defer tx2.Discard()
+
+ getValue(tx2, key1)
+ getValue(tx2, key2)
+ getValue(tx1, key1)
+ getValue(tx2, key1)
+ setValue(tx2, key1, "value1")
+ setValue(tx2, key2, "value2")
+
+ if err := tx2.Commit(); err != nil {
+ return fmt.Errorf("tx2 failed: %w (key1 = %s, key2 = %s)", err, key1, key2)
+ }
+
+ setValue(tx1, key1, "value1-second")
+ getValue(tx1, key1)
+ setValue(tx1, key1, "value1-third")
+
+ delay()
+ if err := tx1.Commit(); err != nil {
+ return fmt.Errorf("tx1 failed: %w (key1 = %s, key2 = %s)", err, key1, key2)
+ }
+
+ return nil
+}
+
+func generateRandomBytes() []byte {
+ b := make([]byte, 20)
+ if _, err := rand.Read(b); err != nil {
+ panic(err)
+ }
+ return b
+}
+
+func getValue(txn *Txn, key string) {
+ if _, err := txn.Get([]byte(key)); err != nil {
+ if !errors.Is(err, ErrKeyNotFound) {
+ panic(err)
+ }
+ }
+}
+
+func setValue(txn *Txn, key, value string) {
+ if err := txn.Set([]byte(key), []byte(value)); err != nil {
+ panic(err)
+ }
+}
+
+func delay() {
+ jitter, err := rand.Int(rand.Reader, big.NewInt(100))
+ if err != nil {
+ panic(err)
+ }
+ <-time.After(time.Duration(jitter.Int64()) * time.Millisecond)
+}
diff --git a/y/watermark.go b/y/watermark.go
index cf2992b8b..7fc0c82c4 100644
--- a/y/watermark.go
+++ b/y/watermark.go
@@ -228,7 +228,8 @@ func (w *WaterMark) process(closer *z.Closer) {
}
}
} else {
- if mark.index > 0 {
+ // it is possible that mark.index is zero. We need to handle that case as well.
+ if mark.index > 0 || (mark.index == 0 && len(mark.indices) == 0) {
processOne(mark.index, mark.done)
}
for _, index := range mark.indices {