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

[DNM] memdb: replace the current implementation with ART(adaptive radix tree) #1400

Draft
wants to merge 18 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 3 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
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ require (
github.com/pingcap/kvproto v0.0.0-20240620063548-118a4cab53e4
github.com/pingcap/log v1.1.1-0.20221110025148-ca232912c9f3
github.com/pkg/errors v0.9.1
github.com/plar/go-adaptive-radix-tree v1.0.5
github.com/prometheus/client_golang v1.18.0
github.com/prometheus/client_model v0.5.0
github.com/stretchr/testify v1.8.2
Expand Down Expand Up @@ -59,3 +60,5 @@ require (
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

replace github.com/plar/go-adaptive-radix-tree => github.com/you06/go-adaptive-radix-tree v0.0.0-20240523051018-0278e8bfcd2b
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we also need to review this? Shall we consider merge the changes to upstream?

Copy link
Contributor Author

@you06 you06 Jul 30, 2024

Choose a reason for hiding this comment

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

No need to review this, I import it only for benchmark test. My changes in 0278e8bfcd2b is only for the special usage in p-dml. As the mem arena implementation, I don't think the auther would like to accept it, since the impact of this change is too large(all the pointers are replaced by our self-defined address), and it actually sacrifice the read performance by introducing vlog.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe the memory arena without vlog is useful for them, but I don't have any performance data for it, what about discussing with them to see if they would like to adopt our improvement, which is not related to our implementation in client-go(I think client-go's requirements are quite unique).

3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
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.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/tiancaiamao/gp v0.0.0-20221230034425-4025bc8a4d4a h1:J/YdBZ46WKpXsxsW93SG+q0F8KI+yFrcIDT4c/RNoc4=
Expand All @@ -115,6 +116,8 @@ github.com/tikv/pd/client v0.0.0-20240620115049-049de1761e56 h1:7TLLfwrKoty9UeJM
github.com/tikv/pd/client v0.0.0-20240620115049-049de1761e56/go.mod h1:EHHidLItrJGh0jqfdfFhIHG5vwkR8+43tFnp7v7iv1Q=
github.com/twmb/murmur3 v1.1.3 h1:D83U0XYKcHRYwYIpBKf3Pks91Z0Byda/9SJ8B6EMRcA=
github.com/twmb/murmur3 v1.1.3/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ=
github.com/you06/go-adaptive-radix-tree v0.0.0-20240523051018-0278e8bfcd2b h1:gSNk6E3PAahr4Ro3b+Oo5NHivzgWIv9zwrTFIAUeESE=
github.com/you06/go-adaptive-radix-tree v0.0.0-20240523051018-0278e8bfcd2b/go.mod h1:15VOUO7R9MhJL8HOJdpydR0rvanrtRE6fA6XSa/tqWE=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.etcd.io/etcd/api/v3 v3.5.10 h1:szRajuUUbLyppkhs9K6BRtjY37l66XQQmw7oZRANE4k=
Expand Down
8 changes: 4 additions & 4 deletions integration_tests/2pc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2466,10 +2466,10 @@ func (s *testCommitterSuite) TestFlagsInMemBufferMutations() {
})

// Create memBufferMutations object and add keys with flags to it.
mutations := transaction.NewMemBufferMutationsProbe(db.Len(), db.GetMemDB())
mutations := transaction.NewMemBufferMutationsProbe(db.Len(), transaction.ToArenaArt(db))

forEachCase(func(op kvrpcpb.Op, key []byte, value []byte, i int, isPessimisticLock, assertExist, assertNotExist bool) {
handle := db.GetMemDB().IterWithFlags(key, nil).Handle()
handle := transaction.ToArenaArt(db).IterWithFlags(key, nil).Handle()
mutations.Push(op, isPessimisticLock, assertExist, assertNotExist, false, handle)
})

Expand Down Expand Up @@ -2499,8 +2499,8 @@ func (s *testCommitterSuite) TestExtractKeyExistsErr() {
txn.GetMemBuffer().UpdateFlags([]byte("de"), kv.DelPresumeKeyNotExists)
err = committer.PrewriteAllMutations(context.Background())
s.ErrorContains(err, "existErr")
s.True(txn.GetMemBuffer().GetMemDB().TryLock())
txn.GetMemBuffer().GetMemDB().Unlock()
s.True(transaction.ToArenaArt(txn.GetMemBuffer()).TryLock())
transaction.ToArenaArt(txn.GetMemBuffer()).Unlock()
}

func (s *testCommitterSuite) TestKillSignal() {
Expand Down
3 changes: 3 additions & 0 deletions integration_tests/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ require (
github.com/pingcap/sysutil v1.0.1-0.20240311050922-ae81ee01f3a5 // indirect
github.com/pingcap/tidb/pkg/parser v0.0.0-20240703042657-230bbc2ef5ef // indirect
github.com/pingcap/tipb v0.0.0-20240318032315-55a7867ddd50 // indirect
github.com/plar/go-adaptive-radix-tree v1.0.5 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
github.com/prometheus/client_golang v1.19.1 // indirect
Expand Down Expand Up @@ -122,3 +123,5 @@ replace (

github.com/tikv/client-go/v2 => ../
)

replace github.com/plar/go-adaptive-radix-tree => github.com/you06/go-adaptive-radix-tree v0.0.0-20240523051018-0278e8bfcd2b
3 changes: 3 additions & 0 deletions integration_tests/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,7 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
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.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
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=
Expand Down Expand Up @@ -500,6 +501,8 @@ github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510/go.mod h1:UETIi67q
github.com/xitongsys/parquet-go v1.6.3-0.20240520233950-75e935fc3e17 h1:mr+7gGPUasLmH3/5Iv1zwQwiY0WgGO21Ym7Q4FVw+xs=
github.com/xitongsys/parquet-go v1.6.3-0.20240520233950-75e935fc3e17/go.mod h1:u9udtIEWeBkphB2isZ8V8xVIMWgcUobH+7FRMO/Ld6c=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/you06/go-adaptive-radix-tree v0.0.0-20240523051018-0278e8bfcd2b h1:gSNk6E3PAahr4Ro3b+Oo5NHivzgWIv9zwrTFIAUeESE=
github.com/you06/go-adaptive-radix-tree v0.0.0-20240523051018-0278e8bfcd2b/go.mod h1:15VOUO7R9MhJL8HOJdpydR0rvanrtRE6fA6XSa/tqWE=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
Expand Down
133 changes: 133 additions & 0 deletions internal/unionstore/arena_art.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package unionstore

import (
"context"

tikverr "github.com/tikv/client-go/v2/error"
art "github.com/tikv/client-go/v2/internal/unionstore/art"
)

var _ MemBuffer = &ArenaArt{}

type ArenaArt struct {
*art.Art
}

func NewArenaArt() *ArenaArt {
return &ArenaArt{
Art: art.New(),
}
}

func (a *ArenaArt) setSkipMutex(skip bool) {
a.Art.SetSkipMutex(skip)
}

func (a *ArenaArt) Get(_ context.Context, k []byte) ([]byte, error) {
return a.Art.Get(k)
}

// GetLocal gets the value from the buffer in local memory.
// It makes nonsense for MemDB, but makes a difference for pipelined DML.
func (a *ArenaArt) GetLocal(_ context.Context, key []byte) ([]byte, error) {
return a.Art.Get(key)
}

// BatchGet gets the values for given keys from the MemBuffer and cache the result if there are remote buffer.
func (a *ArenaArt) BatchGet(_ context.Context, keys [][]byte) (map[string][]byte, error) {
if !a.Art.Dirty() {
return map[string][]byte{}, nil
}
m := make(map[string][]byte, len(keys))
for _, k := range keys {
v, err := a.Art.Get(k)
if err != nil {
if tikverr.IsErrNotFound(err) {
continue
}
return nil, err
}
m[string(k)] = v
}
return m, nil
}

func (a *ArenaArt) RemoveFromBuffer(key []byte) {}

// Iter implements the Retriever interface.
func (a *ArenaArt) Iter(start []byte, end []byte) (Iterator, error) {
it, err := a.Art.Iter(start, end)
if err != nil {
return nil, err
}
return it, err
}

// IterReverse implements the Retriever interface.
func (a *ArenaArt) IterReverse(end, start []byte) (Iterator, error) {
it, err := a.Art.IterReverse(end, start)
if err != nil {
return nil, err
}
return it, err
}

// SnapshotIter returns an Iterator for a snapshot of MemBuffer.
func (a *ArenaArt) SnapshotIter(lower, upper []byte) Iterator {
return a.Art.SnapshotIter(lower, upper)
}

// SnapshotIterReverse returns a reversed Iterator for a snapshot of MemBuffer.
func (a *ArenaArt) SnapshotIterReverse(upper, lower []byte) Iterator {
return a.Art.SnapshotIterReverse(upper, lower)
}

func (a *ArenaArt) SnapshotGetter() Getter {
return a.Art.SnapshotGetter()
}

func (a *ArenaArt) Dirty() bool {
return a.Art.Dirty()
}

// Checkpoint returns the checkpoint of the MemBuffer.
func (a *ArenaArt) Checkpoint() *MemDBCheckpoint {
blockSize, blocks, offsetInBlock := a.Art.Checkpoint()
return &MemDBCheckpoint{
blockSize: blockSize,
blocks: blocks,
offsetInBlock: offsetInBlock,
}
}

// RevertToCheckpoint reverts the MemBuffer to the specified checkpoint.
func (a *ArenaArt) RevertToCheckpoint(cp *MemDBCheckpoint) {
a.Art.RevertToCheckpoint(cp.blockSize, cp.blocks, cp.offsetInBlock)
}

// GetMemDB returns the MemDB binding to this MemBuffer.
// This method can also be used for bypassing the wrapper of MemDB.
func (a *ArenaArt) GetMemDB() *MemDB {
return nil
}

// Flush flushes the pipelined memdb when the keys or sizes reach the threshold.
// If force is true, it will flush the memdb without size limitation.
// it returns true when the memdb is flushed, and returns error when there are any failures.
func (a *ArenaArt) Flush(force bool) (bool, error) {
return false, nil
}

// FlushWait waits for the flushing task done and return error.
func (a *ArenaArt) FlushWait() error {
return nil
}

// GetFlushMetrics returns the metrics related to flushing
func (a *ArenaArt) GetFlushMetrics() FlushMetrics {
return FlushMetrics{}
}

func (a *ArenaArt) stages() []art.ARTCheckpoint {
return a.Art.Stages()
}
Loading
Loading