mirror of https://github.com/tikv/client-go.git
feat: introduce GetLocal() and BatchGet cache for PipelinedMemDB (#1212)
* feat: introduce GetLocal() for MemBuffer Signed-off-by: ekexium <eke@fastmail.com> * downgrade tools to 0.18.0 Signed-off-by: ekexium <eke@fastmail.com> * fix: set flushingMemDB = nil when an error is returned from a flush Signed-off-by: ekexium <eke@fastmail.com> * impl BatchGet for MemBuffer Signed-off-by: you06 <you1474600@gmail.com> test membuffer batch get Signed-off-by: you06 <you1474600@gmail.com> * add Prefetch & GetPrefetchCache Signed-off-by: you06 <you1474600@gmail.com> * cache multi Prefetch call Signed-off-by: you06 <you1474600@gmail.com> * add tests Signed-off-by: you06 <you1474600@gmail.com> * workaround for golang ci lint failure Signed-off-by: you06 <you1474600@gmail.com> * replace assert with require Signed-off-by: you06 <you1474600@gmail.com> * workaround golangci lint Signed-off-by: you06 <you1474600@gmail.com> * lint Signed-off-by: you06 <you1474600@gmail.com> * remove prefetch interface, pipelined memdb will cache batch get result Signed-off-by: you06 <you1474600@gmail.com> * update tidb Signed-off-by: you06 <you1474600@gmail.com> * fix batch get cache when membuffer is empty Signed-off-by: you06 <you1474600@gmail.com> * fix returned delete value Signed-off-by: you06 <you1474600@gmail.com> * fix: handle resourceGroupTag of Flush Signed-off-by: ekexium <eke@fastmail.com> * fix: set resource group tag for committer if it's pipelined Signed-off-by: ekexium <eke@fastmail.com> * Update internal/unionstore/pipelined_memdb.go Co-authored-by: ekexium <eke@fastmail.com> * remove prefetch interface Signed-off-by: you06 <you1474600@gmail.com> * release mutex Signed-off-by: you06 <you1474600@gmail.com> * flush wait to avoid race Signed-off-by: you06 <you1474600@gmail.com> * fix unstopped test Signed-off-by: you06 <you1474600@gmail.com> * set resource group tags for committer Signed-off-by: ekexium <eke@fastmail.com> * skip test due to tikv image not updated yet Signed-off-by: you06 <you1474600@gmail.com> * skip more test Signed-off-by: you06 <you1474600@gmail.com> --------- Signed-off-by: ekexium <eke@fastmail.com> Signed-off-by: you06 <you1474600@gmail.com> Co-authored-by: you06 <you1474600@gmail.com>
This commit is contained in:
parent
0606e74e8e
commit
87a984a72d
|
|
@ -45,8 +45,8 @@ require (
|
|||
golang.org/x/text v0.14.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240228224816-df926f6c8641 // indirect
|
||||
google.golang.org/grpc v1.62.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240308144416-29370a3891b7 // indirect
|
||||
google.golang.org/grpc v1.62.1 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
)
|
||||
|
|
|
|||
|
|
@ -45,8 +45,8 @@ require (
|
|||
golang.org/x/text v0.14.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240228224816-df926f6c8641 // indirect
|
||||
google.golang.org/grpc v1.62.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240308144416-29370a3891b7 // indirect
|
||||
google.golang.org/grpc v1.62.1 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
)
|
||||
|
|
|
|||
|
|
@ -45,8 +45,8 @@ require (
|
|||
golang.org/x/text v0.14.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240228224816-df926f6c8641 // indirect
|
||||
google.golang.org/grpc v1.62.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240308144416-29370a3891b7 // indirect
|
||||
google.golang.org/grpc v1.62.1 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
)
|
||||
|
|
|
|||
|
|
@ -45,8 +45,8 @@ require (
|
|||
golang.org/x/text v0.14.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240228224816-df926f6c8641 // indirect
|
||||
google.golang.org/grpc v1.62.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240308144416-29370a3891b7 // indirect
|
||||
google.golang.org/grpc v1.62.1 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
)
|
||||
|
|
|
|||
|
|
@ -45,8 +45,8 @@ require (
|
|||
golang.org/x/text v0.14.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240228224816-df926f6c8641 // indirect
|
||||
google.golang.org/grpc v1.62.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240308144416-29370a3891b7 // indirect
|
||||
google.golang.org/grpc v1.62.1 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
)
|
||||
|
|
|
|||
|
|
@ -45,8 +45,8 @@ require (
|
|||
golang.org/x/text v0.14.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240228224816-df926f6c8641 // indirect
|
||||
google.golang.org/grpc v1.62.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240308144416-29370a3891b7 // indirect
|
||||
google.golang.org/grpc v1.62.1 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
)
|
||||
|
|
|
|||
|
|
@ -45,8 +45,8 @@ require (
|
|||
golang.org/x/text v0.14.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240228224816-df926f6c8641 // indirect
|
||||
google.golang.org/grpc v1.62.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240308144416-29370a3891b7 // indirect
|
||||
google.golang.org/grpc v1.62.1 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
)
|
||||
|
|
|
|||
|
|
@ -45,8 +45,8 @@ require (
|
|||
golang.org/x/text v0.14.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240228224816-df926f6c8641 // indirect
|
||||
google.golang.org/grpc v1.62.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240308144416-29370a3891b7 // indirect
|
||||
google.golang.org/grpc v1.62.1 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
)
|
||||
|
|
|
|||
|
|
@ -4,15 +4,15 @@ go 1.21
|
|||
|
||||
require (
|
||||
github.com/ninedraft/israce v0.0.3
|
||||
github.com/pingcap/errors v0.11.5-0.20231212100244-799fae176cfb
|
||||
github.com/pingcap/errors v0.11.5-0.20240311081613-f97970b88865
|
||||
github.com/pingcap/failpoint v0.0.0-20220801062533-2eaa32854a6c
|
||||
github.com/pingcap/kvproto v0.0.0-20240227073058-929ab83f9754
|
||||
github.com/pingcap/tidb v1.1.0-beta.0.20240126041650-de177d85b19e
|
||||
github.com/pingcap/tidb v1.1.0-beta.0.20240312154839-cd6dbc2af910
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/tidwall/gjson v1.14.1
|
||||
github.com/tikv/client-go/v2 v2.0.8-0.20240205071126-11cb7985f0ec
|
||||
github.com/tikv/pd/client v0.0.0-20240229062430-b207e514ece1
|
||||
github.com/tikv/client-go/v2 v2.0.8-0.20240313022320-d59fea5757db
|
||||
github.com/tikv/pd/client v0.0.0-20240229065730-92a31c12238e
|
||||
go.uber.org/goleak v1.3.0
|
||||
)
|
||||
|
||||
|
|
@ -69,18 +69,18 @@ require (
|
|||
github.com/pingcap/goleveldb v0.0.0-20191226122134-f82aafb29989 // indirect
|
||||
github.com/pingcap/log v1.1.1-0.20230317032135-a0d097d16e22 // indirect
|
||||
github.com/pingcap/sysutil v1.0.1-0.20230407040306-fb007c5aff21 // indirect
|
||||
github.com/pingcap/tidb/pkg/parser v0.0.0-20240111112854-1ad36eb0ef29 // indirect
|
||||
github.com/pingcap/tidb/pkg/parser v0.0.0-20240312154839-cd6dbc2af910 // indirect
|
||||
github.com/pingcap/tipb v0.0.0-20240116032918-9bb28c43bbfc // 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.18.0 // indirect
|
||||
github.com/prometheus/client_model v0.5.0 // indirect
|
||||
github.com/prometheus/common v0.46.0 // indirect
|
||||
github.com/prometheus/client_golang v1.19.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.0 // indirect
|
||||
github.com/prometheus/common v0.48.0 // indirect
|
||||
github.com/prometheus/procfs v0.12.0 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/rogpeppe/go-internal v1.11.0 // indirect
|
||||
github.com/sasha-s/go-deadlock v0.3.1 // indirect
|
||||
github.com/shirou/gopsutil/v3 v3.23.10 // indirect
|
||||
github.com/shirou/gopsutil/v3 v3.24.1 // indirect
|
||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/tiancaiamao/gp v0.0.0-20221230034425-4025bc8a4d4a // indirect
|
||||
|
|
@ -97,7 +97,7 @@ require (
|
|||
go.etcd.io/etcd/client/v3 v3.5.12 // indirect
|
||||
go.uber.org/atomic v1.11.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.26.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/crypto v0.21.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3 // indirect
|
||||
golang.org/x/net v0.22.0 // indirect
|
||||
|
|
@ -106,7 +106,6 @@ require (
|
|||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/tools v0.19.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240308144416-29370a3891b7 // indirect
|
||||
google.golang.org/grpc v1.62.1 // indirect
|
||||
|
|
@ -118,7 +117,7 @@ require (
|
|||
|
||||
replace (
|
||||
github.com/go-ldap/ldap/v3 => github.com/YangKeao/ldap/v3 v3.4.5-0.20230421065457-369a3bab1117
|
||||
github.com/pingcap/tidb => github.com/you06/tidb v1.1.0-beta.0.20240220121437-9d6b908d9a92
|
||||
github.com/pingcap/tidb/pkg/parser => github.com/you06/tidb/pkg/parser v0.0.0-20240220121437-9d6b908d9a92
|
||||
github.com/pingcap/tidb => github.com/ekexium/tidb v1.1.0-beta.0.20240314050256-444418ecf47b
|
||||
github.com/pingcap/tidb/pkg/parser => github.com/ekexium/tidb/pkg/parser v0.0.0-20240314050256-444418ecf47b
|
||||
github.com/tikv/client-go/v2 => ../
|
||||
)
|
||||
|
|
|
|||
|
|
@ -132,6 +132,10 @@ github.com/dolthub/swiss v0.2.1/go.mod h1:8AhKZZ1HK7g18j7v7k6c5cYIGEZJcPn0ARsai8
|
|||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
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/ekexium/tidb v1.1.0-beta.0.20240314050256-444418ecf47b h1:o19UOUiPY0xpX+YTM9zlpps50994eaZxIkYmphvTM1o=
|
||||
github.com/ekexium/tidb v1.1.0-beta.0.20240314050256-444418ecf47b/go.mod h1:7Gfn8N2wA499HqM6Q6pOHtwN0G2ktYL9BeO+ik+iSo8=
|
||||
github.com/ekexium/tidb/pkg/parser v0.0.0-20240314050256-444418ecf47b h1:J9U3bBzGPEkgrJypNzf5wCaZdCogvKxPB9FhqH+Naho=
|
||||
github.com/ekexium/tidb/pkg/parser v0.0.0-20240314050256-444418ecf47b/go.mod h1:c/4la2yfv1vBYvtIG8WCDyDinLMDIUC5+zLRHiafY+Y=
|
||||
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
|
||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||
|
|
@ -259,8 +263,6 @@ github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09
|
|||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE=
|
||||
github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0=
|
||||
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
|
||||
github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
|
|
@ -327,12 +329,12 @@ github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N
|
|||
github.com/lestrrat-go/blackmagic v1.0.2/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU=
|
||||
github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
|
||||
github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
|
||||
github.com/lestrrat-go/httprc v1.0.4 h1:bAZymwoZQb+Oq8MEbyipag7iSq6YIga8Wj6GOiJGdI8=
|
||||
github.com/lestrrat-go/httprc v1.0.4/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo=
|
||||
github.com/lestrrat-go/httprc v1.0.5 h1:bsTfiH8xaKOJPrg1R+E3iE/AWZr/x0Phj9PBTG/OLUk=
|
||||
github.com/lestrrat-go/httprc v1.0.5/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo=
|
||||
github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
|
||||
github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
|
||||
github.com/lestrrat-go/jwx/v2 v2.0.19 h1:ekv1qEZE6BVct89QA+pRF6+4pCpfVrOnEJnTnT4RXoY=
|
||||
github.com/lestrrat-go/jwx/v2 v2.0.19/go.mod h1:l3im3coce1lL2cDeAjqmaR+Awx+X8Ih+2k8BuHNJ4CU=
|
||||
github.com/lestrrat-go/jwx/v2 v2.0.21 h1:jAPKupy4uHgrHFEdjVjNkUgoBKtVDgrQPB/h55FHrR0=
|
||||
github.com/lestrrat-go/jwx/v2 v2.0.21/go.mod h1:09mLW8zto6bWL9GbwnqAli+ArLf+5M33QLQPDggkUWM=
|
||||
github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
|
||||
github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
||||
|
|
@ -402,8 +404,8 @@ github.com/pingcap/badger v1.5.1-0.20230103063557-828f39b09b6d/go.mod h1:p8QnkZn
|
|||
github.com/pingcap/errors v0.11.0/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
|
||||
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
|
||||
github.com/pingcap/errors v0.11.5-0.20190809092503-95897b64e011/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
|
||||
github.com/pingcap/errors v0.11.5-0.20231212100244-799fae176cfb h1:yqyP+k0mgRPpXJQDOCrtaG2YZym0ZDD+vt5JzlBUkrw=
|
||||
github.com/pingcap/errors v0.11.5-0.20231212100244-799fae176cfb/go.mod h1:X2r9ueLEUZgtx2cIogM0v4Zj5uvvzhuuiu7Pn8HzMPg=
|
||||
github.com/pingcap/errors v0.11.5-0.20240311081613-f97970b88865 h1:xzbnMPvFtnqLsY5HLALUov6JU1ONyfQUXVurE/Nqb8Y=
|
||||
github.com/pingcap/errors v0.11.5-0.20240311081613-f97970b88865/go.mod h1:X2r9ueLEUZgtx2cIogM0v4Zj5uvvzhuuiu7Pn8HzMPg=
|
||||
github.com/pingcap/failpoint v0.0.0-20220801062533-2eaa32854a6c h1:CgbKAHto5CQgWM9fSBIvaxsJHuGP0uM74HXtv3MyyGQ=
|
||||
github.com/pingcap/failpoint v0.0.0-20220801062533-2eaa32854a6c/go.mod h1:4qGtCB0QK0wBzKtFEGDhxXnSnbQApw1gc9siScUl8ew=
|
||||
github.com/pingcap/fn v1.0.0 h1:CyA6AxcOZkQh52wIqYlAmaVmF6EvrcqFywP463pjA8g=
|
||||
|
|
@ -434,15 +436,15 @@ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:Om
|
|||
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig=
|
||||
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/prometheus/client_golang v0.9.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
|
||||
github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA=
|
||||
github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
|
||||
github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
|
||||
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
|
||||
github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos=
|
||||
github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8=
|
||||
github.com/prometheus/common v0.0.0-20181020173914-7e9e6cabbd39/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.46.0 h1:doXzt5ybi1HBKpsZOL0sSkaNHJJqkyfEWZGGqqScV0Y=
|
||||
github.com/prometheus/common v0.46.0/go.mod h1:Tp0qkxpb9Jsg54QMe+EAmqXkSV7Evdy1BTn+g2pa/hQ=
|
||||
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
|
||||
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||
|
|
@ -460,13 +462,15 @@ github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR
|
|||
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0=
|
||||
github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM=
|
||||
github.com/scalalang2/golang-fifo v0.1.5 h1:cl70TQhlMGGpI2DZGcr+7/GFTJOjHMeor0t7wynEEoA=
|
||||
github.com/scalalang2/golang-fifo v0.1.5/go.mod h1:IK3OZBg7iHbVdQVGPDjcW1MWPb6JcWjaS/w0iRBS8gs=
|
||||
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
|
||||
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
|
||||
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/shirou/gopsutil/v3 v3.21.12/go.mod h1:BToYZVTlSVlfazpDDYFnsVZLaoRG+g8ufT6fPQLdJzA=
|
||||
github.com/shirou/gopsutil/v3 v3.23.10 h1:/N42opWlYzegYaVkWejXWJpbzKv2JDy3mrgGzKsh9hM=
|
||||
github.com/shirou/gopsutil/v3 v3.23.10/go.mod h1:JIE26kpucQi+innVlAUnIEOSBhBUkirr5b44yr55+WE=
|
||||
github.com/shirou/gopsutil/v3 v3.24.1 h1:R3t6ondCEvmARp3wxODhXMTLC/klMa87h2PHUw5m7QI=
|
||||
github.com/shirou/gopsutil/v3 v3.24.1/go.mod h1:UU7a2MSBQa+kW1uuDq8DeEBS8kmrnQwsv2b5O513rwU=
|
||||
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
|
||||
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
|
||||
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
|
||||
|
|
@ -498,8 +502,9 @@ github.com/spkg/bom v1.0.0/go.mod h1:lAz2VbTuYNcvs7iaFF8WW0ufXrHShJ7ck1fYFFbVXJs
|
|||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
|
|
@ -507,20 +512,23 @@ 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.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
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=
|
||||
github.com/tiancaiamao/appdash v0.0.0-20181126055449-889f96f722a2 h1:mbAskLJ0oJfDRtkanvQPiooDH8HvJ2FBh+iKT/OmiQQ=
|
||||
github.com/tiancaiamao/appdash v0.0.0-20181126055449-889f96f722a2/go.mod h1:2PfKggNGDuadAa0LElHrByyrz4JPZ9fFx6Gs7nx7ZZU=
|
||||
github.com/tiancaiamao/gp v0.0.0-20221230034425-4025bc8a4d4a h1:J/YdBZ46WKpXsxsW93SG+q0F8KI+yFrcIDT4c/RNoc4=
|
||||
github.com/tiancaiamao/gp v0.0.0-20221230034425-4025bc8a4d4a/go.mod h1:h4xBhSNtOeEosLJ4P7JyKXX7Cabg7AVkWCK5gV2vOrM=
|
||||
github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI=
|
||||
github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY=
|
||||
github.com/tidwall/gjson v1.14.1 h1:iymTbGkQBhveq21bEvAQ81I0LEBork8BFe1CUZXdyuo=
|
||||
github.com/tidwall/gjson v1.14.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tikv/pd/client v0.0.0-20240229062430-b207e514ece1 h1:KKa2bxKHhM+CmLn5Pp2VmNfi9AN2pWd+3m2EWnicdvE=
|
||||
github.com/tikv/pd/client v0.0.0-20240229062430-b207e514ece1/go.mod h1:Z/QAgOt29zvwBTd0H6pdx45VO6KRNc/O/DzGkVmSyZg=
|
||||
github.com/tikv/pd/client v0.0.0-20240229065730-92a31c12238e h1:kHXMmskVCNyH53u43I73Y5cmZ6yqqder/jGOiI7ylxs=
|
||||
github.com/tikv/pd/client v0.0.0-20240229065730-92a31c12238e/go.mod h1:Z/QAgOt29zvwBTd0H6pdx45VO6KRNc/O/DzGkVmSyZg=
|
||||
github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs=
|
||||
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
|
||||
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
||||
|
|
@ -555,10 +563,6 @@ github.com/xitongsys/parquet-go v1.5.5-0.20201110004701-b09c49d6d457 h1:tBbuFCty
|
|||
github.com/xitongsys/parquet-go v1.5.5-0.20201110004701-b09c49d6d457/go.mod h1:pheqtXeHQFzxJk45lRQ0UIGIivKnLXvialZSFWs81A8=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
|
||||
github.com/you06/tidb v1.1.0-beta.0.20240220121437-9d6b908d9a92 h1:2n6DSHF79pe9BGKMrZ6bUFdV1AL1BJaC3wbkS3TiL2E=
|
||||
github.com/you06/tidb v1.1.0-beta.0.20240220121437-9d6b908d9a92/go.mod h1:WNewIzAOHkWHcmkh5Yw5HOU/fl9EhX4mBpNVmW6Eydk=
|
||||
github.com/you06/tidb/pkg/parser v0.0.0-20240220121437-9d6b908d9a92 h1:W7CHjUFBHqpCitLUaK1X2gN+AKsX6kgmKZ2D+YGuoHw=
|
||||
github.com/you06/tidb/pkg/parser v0.0.0-20240220121437-9d6b908d9a92/go.mod h1:MWQK6otJgZRI6zcCVPV22U4qE26qOGJnN4fq8XawgBs=
|
||||
github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
|
||||
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
|
||||
github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc=
|
||||
|
|
@ -634,8 +638,8 @@ go.uber.org/zap v1.12.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
|||
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||
go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
|
||||
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
|
||||
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
|
|
@ -687,8 +691,8 @@ golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
|||
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
|
||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ=
|
||||
golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o=
|
||||
golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ=
|
||||
golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA=
|
||||
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-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
|
@ -733,7 +737,7 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
|
|
@ -782,11 +786,12 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
|||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca h1:PupagGYwj8+I4ubCxcmcBRk3VlUWtTg5huQpZR9flmE=
|
||||
gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
|
||||
gonum.org/v1/gonum v0.8.2 h1:CCXrcPKiGGotvnN6jfUsKk4rRqm7q09/YbKb5xCEvtM=
|
||||
gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
|
||||
gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
|
||||
google.golang.org/api v0.160.0 h1:SEspjXHVqE1m5a1fRy8JFB+5jSu+V0GEDKDghF3ttO4=
|
||||
google.golang.org/api v0.160.0/go.mod h1:0mu0TpK33qnydLvWqbImq2b1eQ5FHRSDCBzAxX9ZHyw=
|
||||
google.golang.org/api v0.162.0 h1:Vhs54HkaEpkMBdgGdOT2P6F0csGG/vxDS0hWHJzmmps=
|
||||
google.golang.org/api v0.162.0/go.mod h1:6SulDkfoBIg4NFmCuZ39XeeAgSHCPecfSUuDyYlAHs0=
|
||||
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/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
||||
|
|
|
|||
|
|
@ -261,3 +261,113 @@ func (s *testPipelinedMemDBSuite) TestPipelinedCommit() {
|
|||
s.Equal(key, val)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *testPipelinedMemDBSuite) TestPipelinedPrefetch() {
|
||||
failpoint.Enable("tikvclient/beforeSendReqToRegion", "return")
|
||||
defer failpoint.Disable("tikvclient/beforeSendReqToRegion")
|
||||
txn, err := s.store.Begin(tikv.WithPipelinedMemDB())
|
||||
s.Nil(err)
|
||||
|
||||
mustFlush := func(txn *transaction.KVTxn) {
|
||||
flushed, err := txn.GetMemBuffer().Flush(true)
|
||||
s.Nil(err)
|
||||
s.True(flushed)
|
||||
}
|
||||
|
||||
panicWhenReadingRemoteBuffer := func(key []byte) ([]byte, error) {
|
||||
ctx := context.WithValue(context.Background(), "sendReqToRegionHook", func(req *tikvrpc.Request) {
|
||||
if req.Type == tikvrpc.CmdBufferBatchGet {
|
||||
panic("should not read remote buffer")
|
||||
}
|
||||
})
|
||||
return txn.GetMemBuffer().Get(ctx, key)
|
||||
}
|
||||
|
||||
prefetchKeys := make([][]byte, 0, 100)
|
||||
prefetchResult := make(map[string][]byte, 100)
|
||||
nonPrefetchKeys := make([][]byte, 0, 100)
|
||||
for i := 0; i < 100; i++ {
|
||||
key := []byte(strconv.Itoa(i))
|
||||
value := key
|
||||
txn.Set(key, value)
|
||||
if i%2 == 0 {
|
||||
prefetchKeys = append(prefetchKeys, key)
|
||||
prefetchResult[string(key)] = value
|
||||
} else {
|
||||
nonPrefetchKeys = append(nonPrefetchKeys, key)
|
||||
}
|
||||
}
|
||||
mustFlush(txn)
|
||||
s.Nil(txn.GetMemBuffer().FlushWait())
|
||||
for _, key := range prefetchKeys {
|
||||
m, err := txn.BatchGet(context.Background(), [][]byte{key})
|
||||
s.Nil(err)
|
||||
result := map[string][]byte{string(key): prefetchResult[string(key)]}
|
||||
s.Equal(m, result)
|
||||
}
|
||||
// can read prefetched keys from prefetch cache
|
||||
for _, key := range prefetchKeys {
|
||||
v, err := txn.GetMemBuffer().Get(context.Background(), key)
|
||||
s.Nil(err)
|
||||
s.Equal(v, prefetchResult[string(key)])
|
||||
}
|
||||
// panics when reading non-prefetched keys from prefetch cache
|
||||
for _, key := range nonPrefetchKeys {
|
||||
s.Panics(func() {
|
||||
panicWhenReadingRemoteBuffer(key)
|
||||
})
|
||||
}
|
||||
mustFlush(txn)
|
||||
// prefetch cache is cleared after flush
|
||||
for _, key := range prefetchKeys {
|
||||
s.Panics(func() {
|
||||
panicWhenReadingRemoteBuffer(key)
|
||||
})
|
||||
}
|
||||
|
||||
s.Nil(txn.Commit(context.Background()))
|
||||
|
||||
txn, err = s.store.Begin(tikv.WithPipelinedMemDB())
|
||||
s.Nil(err)
|
||||
txn.Set([]byte("100"), []byte("100")) // snapshot: [0, 1, ..., 99], membuffer: [100]
|
||||
m, err := txn.BatchGet(context.Background(), [][]byte{[]byte("99"), []byte("100"), []byte("101")})
|
||||
s.Nil(err)
|
||||
s.Equal(m, map[string][]byte{"99": []byte("99"), "100": []byte("100")})
|
||||
cache := txn.GetSnapshot().SnapCache()
|
||||
// batch get cache: [99 -> not exist, 100 -> 100, 101 -> not exist]
|
||||
// snapshot cache: [99 -> 99, 101 -> not exist]
|
||||
_, err = panicWhenReadingRemoteBuffer([]byte("99"))
|
||||
s.Error(err)
|
||||
s.True(tikverr.IsErrNotFound(err))
|
||||
s.Equal(cache["99"], []byte("99"))
|
||||
v, err := panicWhenReadingRemoteBuffer([]byte("100"))
|
||||
s.Nil(err)
|
||||
s.Equal(v, []byte("100"))
|
||||
_, err = panicWhenReadingRemoteBuffer([]byte("101"))
|
||||
s.Error(err)
|
||||
s.True(tikverr.IsErrNotFound(err))
|
||||
s.Equal(cache["101"], []byte(nil))
|
||||
|
||||
txn.Delete([]byte("99"))
|
||||
mustFlush(txn)
|
||||
s.Nil(txn.GetMemBuffer().FlushWait())
|
||||
m, err = txn.BatchGet(context.Background(), [][]byte{[]byte("99")})
|
||||
s.Nil(err)
|
||||
// restore this check after tikv return pairs for buffer batch get
|
||||
//s.Equal(m, map[string][]byte{})
|
||||
//v, err = panicWhenReadingRemoteBuffer([]byte("99"))
|
||||
//s.Nil(err)
|
||||
//s.Equal(v, []byte{})
|
||||
txn.Rollback()
|
||||
|
||||
// empty memdb should also cache the not exist result.
|
||||
txn, err = s.store.Begin(tikv.WithPipelinedMemDB())
|
||||
// batch get cache: [99 -> not exist]
|
||||
m, err = txn.BatchGet(context.Background(), [][]byte{[]byte("99")})
|
||||
s.Nil(err)
|
||||
s.Equal(m, map[string][]byte{"99": []byte("99")})
|
||||
_, err = panicWhenReadingRemoteBuffer([]byte("99"))
|
||||
s.Error(err)
|
||||
s.True(tikverr.IsErrNotFound(err))
|
||||
txn.Rollback()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import (
|
|||
"github.com/tikv/client-go/v2/kv"
|
||||
"github.com/tikv/client-go/v2/metrics"
|
||||
"github.com/tikv/client-go/v2/tikvrpc"
|
||||
"github.com/tikv/client-go/v2/util"
|
||||
)
|
||||
|
||||
type testRegionCacheStaleReadSuite struct {
|
||||
|
|
@ -259,22 +260,22 @@ func TestRegionCacheStaleRead(t *testing.T) {
|
|||
{
|
||||
do: followerDown,
|
||||
leaderRegionValid: true,
|
||||
leaderAsyncReload: Some(false),
|
||||
leaderAsyncReload: util.Some(false),
|
||||
leaderSuccessReplica: []string{"z1"},
|
||||
leaderSuccessReadType: SuccessStaleRead,
|
||||
followerRegionValid: true,
|
||||
followerAsyncReload: Some(false),
|
||||
followerAsyncReload: util.Some(false),
|
||||
followerSuccessReplica: []string{"z1"},
|
||||
followerSuccessReadType: SuccessLeaderRead,
|
||||
},
|
||||
{
|
||||
do: followerDownAndUp,
|
||||
leaderRegionValid: true,
|
||||
leaderAsyncReload: None[bool](),
|
||||
leaderAsyncReload: util.None[bool](),
|
||||
leaderSuccessReplica: []string{"z1"},
|
||||
leaderSuccessReadType: SuccessStaleRead,
|
||||
followerRegionValid: true,
|
||||
followerAsyncReload: Some(true),
|
||||
followerAsyncReload: util.Some(true),
|
||||
followerSuccessReplica: []string{"z1"},
|
||||
// because follower's epoch is changed, leader will be selected.
|
||||
followerSuccessReadType: SuccessStaleRead,
|
||||
|
|
@ -283,11 +284,11 @@ func TestRegionCacheStaleRead(t *testing.T) {
|
|||
do: followerMove,
|
||||
recoverable: true,
|
||||
leaderRegionValid: true,
|
||||
leaderAsyncReload: Some(false),
|
||||
leaderAsyncReload: util.Some(false),
|
||||
leaderSuccessReplica: []string{"z1"},
|
||||
leaderSuccessReadType: SuccessStaleRead,
|
||||
followerRegionValid: false,
|
||||
followerAsyncReload: Some(false),
|
||||
followerAsyncReload: util.Some(false),
|
||||
// may async reload region and access it from leader.
|
||||
followerSuccessReplica: []string{},
|
||||
followerSuccessReadType: ReadFail,
|
||||
|
|
@ -295,67 +296,67 @@ func TestRegionCacheStaleRead(t *testing.T) {
|
|||
{
|
||||
do: evictLeader,
|
||||
leaderRegionValid: true,
|
||||
leaderAsyncReload: Some(false),
|
||||
leaderAsyncReload: util.Some(false),
|
||||
// leader is evicted, but can still serve as follower.
|
||||
leaderSuccessReplica: []string{"z1"},
|
||||
leaderSuccessReadType: SuccessStaleRead,
|
||||
followerRegionValid: true,
|
||||
followerAsyncReload: Some(false),
|
||||
followerAsyncReload: util.Some(false),
|
||||
followerSuccessReplica: []string{"z2"},
|
||||
followerSuccessReadType: SuccessStaleRead,
|
||||
},
|
||||
{
|
||||
do: leaderMove,
|
||||
leaderRegionValid: false,
|
||||
leaderAsyncReload: Some(false),
|
||||
leaderAsyncReload: util.Some(false),
|
||||
leaderSuccessReplica: []string{},
|
||||
leaderSuccessReadType: ReadFail,
|
||||
followerRegionValid: true,
|
||||
followerAsyncReload: Some(false),
|
||||
followerAsyncReload: util.Some(false),
|
||||
followerSuccessReplica: []string{"z2"},
|
||||
followerSuccessReadType: SuccessStaleRead,
|
||||
},
|
||||
{
|
||||
do: leaderDown,
|
||||
leaderRegionValid: true,
|
||||
leaderAsyncReload: Some(true),
|
||||
leaderAsyncReload: util.Some(true),
|
||||
leaderSuccessReplica: []string{"z2", "z3"},
|
||||
leaderSuccessReadType: SuccessFollowerRead,
|
||||
followerRegionValid: true,
|
||||
followerAsyncReload: Some(false),
|
||||
followerAsyncReload: util.Some(false),
|
||||
followerSuccessReplica: []string{"z2"},
|
||||
followerSuccessReadType: SuccessStaleRead,
|
||||
},
|
||||
{
|
||||
do: leaderDownAndUp,
|
||||
leaderRegionValid: true,
|
||||
leaderAsyncReload: Some(true),
|
||||
leaderAsyncReload: util.Some(true),
|
||||
leaderSuccessReplica: []string{"z2", "z3"},
|
||||
leaderSuccessReadType: SuccessFollowerRead,
|
||||
followerRegionValid: true,
|
||||
followerAsyncReload: None[bool](),
|
||||
followerAsyncReload: util.None[bool](),
|
||||
followerSuccessReplica: []string{"z2"},
|
||||
followerSuccessReadType: SuccessStaleRead,
|
||||
},
|
||||
{
|
||||
do: leaderDownAndElect,
|
||||
leaderRegionValid: true,
|
||||
leaderAsyncReload: Some(true),
|
||||
leaderAsyncReload: util.Some(true),
|
||||
leaderSuccessReplica: []string{"z2", "z3"},
|
||||
leaderSuccessReadType: SuccessFollowerRead,
|
||||
followerRegionValid: true,
|
||||
followerAsyncReload: None[bool](),
|
||||
followerAsyncReload: util.None[bool](),
|
||||
followerSuccessReplica: []string{"z2"},
|
||||
followerSuccessReadType: SuccessStaleRead,
|
||||
},
|
||||
{
|
||||
do: followerDataIsNotReady,
|
||||
leaderRegionValid: true,
|
||||
leaderAsyncReload: Some(false),
|
||||
leaderAsyncReload: util.Some(false),
|
||||
leaderSuccessReplica: []string{"z1"},
|
||||
leaderSuccessReadType: SuccessStaleRead,
|
||||
followerRegionValid: true,
|
||||
followerAsyncReload: Some(false),
|
||||
followerAsyncReload: util.Some(false),
|
||||
followerSuccessReplica: []string{"z1"},
|
||||
followerSuccessReadType: SuccessLeaderRead,
|
||||
},
|
||||
|
|
@ -364,11 +365,11 @@ func TestRegionCacheStaleRead(t *testing.T) {
|
|||
do: leaderServerIsBusy,
|
||||
recoverable: true,
|
||||
leaderRegionValid: true,
|
||||
leaderAsyncReload: Some(false),
|
||||
leaderAsyncReload: util.Some(false),
|
||||
leaderSuccessReplica: []string{"z2", "z3"},
|
||||
leaderSuccessReadType: SuccessFollowerRead,
|
||||
followerRegionValid: true,
|
||||
followerAsyncReload: Some(false),
|
||||
followerAsyncReload: util.Some(false),
|
||||
followerSuccessReplica: []string{"z2"},
|
||||
followerSuccessReadType: SuccessStaleRead,
|
||||
},
|
||||
|
|
@ -376,11 +377,11 @@ func TestRegionCacheStaleRead(t *testing.T) {
|
|||
do: followerServerIsBusy,
|
||||
recoverable: true,
|
||||
leaderRegionValid: true,
|
||||
leaderAsyncReload: Some(false),
|
||||
leaderAsyncReload: util.Some(false),
|
||||
leaderSuccessReplica: []string{"z1"},
|
||||
leaderSuccessReadType: SuccessStaleRead,
|
||||
followerRegionValid: true,
|
||||
followerAsyncReload: Some(false),
|
||||
followerAsyncReload: util.Some(false),
|
||||
followerSuccessReplica: []string{"z1"},
|
||||
followerSuccessReadType: SuccessLeaderRead,
|
||||
},
|
||||
|
|
@ -389,11 +390,11 @@ func TestRegionCacheStaleRead(t *testing.T) {
|
|||
extra: []func(suite *testRegionCacheStaleReadSuite){followerServerIsBusy},
|
||||
recoverable: true,
|
||||
leaderRegionValid: true,
|
||||
leaderAsyncReload: Some(false),
|
||||
leaderAsyncReload: util.Some(false),
|
||||
leaderSuccessReplica: []string{"z3"},
|
||||
leaderSuccessReadType: SuccessFollowerRead,
|
||||
followerRegionValid: true,
|
||||
followerAsyncReload: Some(false),
|
||||
followerAsyncReload: util.Some(false),
|
||||
followerSuccessReplica: []string{"z3"},
|
||||
followerSuccessReadType: SuccessFollowerRead,
|
||||
},
|
||||
|
|
@ -402,11 +403,11 @@ func TestRegionCacheStaleRead(t *testing.T) {
|
|||
extra: []func(suite *testRegionCacheStaleReadSuite){followerDataIsNotReady},
|
||||
recoverable: true,
|
||||
leaderRegionValid: true,
|
||||
leaderAsyncReload: Some(false),
|
||||
leaderAsyncReload: util.Some(false),
|
||||
leaderSuccessReplica: []string{"z2", "z3"},
|
||||
leaderSuccessReadType: SuccessFollowerRead,
|
||||
followerRegionValid: true,
|
||||
followerAsyncReload: Some(false),
|
||||
followerAsyncReload: util.Some(false),
|
||||
followerSuccessReplica: []string{"z2", "z3"},
|
||||
followerSuccessReadType: SuccessFollowerRead,
|
||||
},
|
||||
|
|
@ -415,11 +416,11 @@ func TestRegionCacheStaleRead(t *testing.T) {
|
|||
extra: []func(suite *testRegionCacheStaleReadSuite){followerDown},
|
||||
recoverable: true,
|
||||
leaderRegionValid: true,
|
||||
leaderAsyncReload: Some(false),
|
||||
leaderAsyncReload: util.Some(false),
|
||||
leaderSuccessReplica: []string{"z3"},
|
||||
leaderSuccessReadType: SuccessFollowerRead,
|
||||
followerRegionValid: true,
|
||||
followerAsyncReload: Some(false),
|
||||
followerAsyncReload: util.Some(false),
|
||||
followerSuccessReplica: []string{"z3"},
|
||||
followerSuccessReadType: SuccessFollowerRead,
|
||||
},
|
||||
|
|
@ -428,11 +429,11 @@ func TestRegionCacheStaleRead(t *testing.T) {
|
|||
extra: []func(suite *testRegionCacheStaleReadSuite){followerDataIsNotReady},
|
||||
recoverable: true,
|
||||
leaderRegionValid: true,
|
||||
leaderAsyncReload: Some(true),
|
||||
leaderAsyncReload: util.Some(true),
|
||||
leaderSuccessReplica: []string{"z2", "z3"},
|
||||
leaderSuccessReadType: SuccessFollowerRead,
|
||||
followerRegionValid: true,
|
||||
followerAsyncReload: Some(true),
|
||||
followerAsyncReload: util.Some(true),
|
||||
followerSuccessReplica: []string{"z2", "z3"},
|
||||
followerSuccessReadType: SuccessFollowerRead,
|
||||
},
|
||||
|
|
@ -441,11 +442,11 @@ func TestRegionCacheStaleRead(t *testing.T) {
|
|||
extra: []func(suite *testRegionCacheStaleReadSuite){followerServerIsBusy},
|
||||
recoverable: true,
|
||||
leaderRegionValid: true,
|
||||
leaderAsyncReload: Some(true),
|
||||
leaderAsyncReload: util.Some(true),
|
||||
leaderSuccessReplica: []string{"z3"},
|
||||
leaderSuccessReadType: SuccessFollowerRead,
|
||||
followerRegionValid: true,
|
||||
followerAsyncReload: Some(true),
|
||||
followerAsyncReload: util.Some(true),
|
||||
followerSuccessReplica: []string{"z3"},
|
||||
followerSuccessReadType: SuccessFollowerRead,
|
||||
},
|
||||
|
|
@ -454,11 +455,11 @@ func TestRegionCacheStaleRead(t *testing.T) {
|
|||
extra: []func(suite *testRegionCacheStaleReadSuite){followerDown},
|
||||
recoverable: true,
|
||||
leaderRegionValid: true,
|
||||
leaderAsyncReload: Some(true),
|
||||
leaderAsyncReload: util.Some(true),
|
||||
leaderSuccessReplica: []string{"z3"},
|
||||
leaderSuccessReadType: SuccessFollowerRead,
|
||||
followerRegionValid: true,
|
||||
followerAsyncReload: Some(true),
|
||||
followerAsyncReload: util.Some(true),
|
||||
followerSuccessReplica: []string{"z3"},
|
||||
followerSuccessReadType: SuccessFollowerRead,
|
||||
},
|
||||
|
|
@ -571,22 +572,6 @@ func testStaleRead(s *testRegionCacheStaleReadSuite, r *RegionCacheTestCase, zon
|
|||
s.True(find, msg)
|
||||
}
|
||||
|
||||
type Option[T interface{}] struct {
|
||||
inner *T
|
||||
}
|
||||
|
||||
func Some[T interface{}](inner T) Option[T] {
|
||||
return Option[T]{inner: &inner}
|
||||
}
|
||||
|
||||
func None[T interface{}]() Option[T] {
|
||||
return Option[T]{inner: nil}
|
||||
}
|
||||
|
||||
func (o Option[T]) Inner() *T {
|
||||
return o.inner
|
||||
}
|
||||
|
||||
type RegionCacheTestCase struct {
|
||||
debug bool
|
||||
do func(s *testRegionCacheStaleReadSuite)
|
||||
|
|
@ -594,12 +579,12 @@ type RegionCacheTestCase struct {
|
|||
recoverable bool
|
||||
// local peer is leader
|
||||
leaderRegionValid bool
|
||||
leaderAsyncReload Option[bool]
|
||||
leaderAsyncReload util.Option[bool]
|
||||
leaderSuccessReplica []string
|
||||
leaderSuccessReadType SuccessReadType
|
||||
// local peer is follower
|
||||
followerRegionValid bool
|
||||
followerAsyncReload Option[bool]
|
||||
followerAsyncReload util.Option[bool]
|
||||
followerSuccessReplica []string
|
||||
followerSuccessReadType SuccessReadType
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,12 @@ type PipelinedMemDB struct {
|
|||
generation uint64
|
||||
entryLimit, bufferLimit uint64
|
||||
flushOption flushOption
|
||||
// prefetchCache is used to cache the result of BatchGet, it's invalidated when Flush.
|
||||
// the values are wrapped by util.Option.
|
||||
// None -> not found
|
||||
// Some([...]) -> put
|
||||
// Some([]) -> delete
|
||||
batchGetCache map[string]util.Option[[]byte]
|
||||
}
|
||||
|
||||
const (
|
||||
|
|
@ -85,23 +91,13 @@ func newFlushOption() flushOption {
|
|||
return opt
|
||||
}
|
||||
|
||||
type pipelinedMemDBSkipRemoteBuffer struct{}
|
||||
|
||||
// TODO: skip remote buffer by context is too obscure, add a new method to read local buffer.
|
||||
var pipelinedMemDBSkipRemoteBufferKey = pipelinedMemDBSkipRemoteBuffer{}
|
||||
|
||||
// WithPipelinedMemDBSkipRemoteBuffer is used to skip reading remote buffer for saving RPC.
|
||||
func WithPipelinedMemDBSkipRemoteBuffer(ctx context.Context) context.Context {
|
||||
return context.WithValue(ctx, pipelinedMemDBSkipRemoteBufferKey, struct{}{})
|
||||
}
|
||||
|
||||
type FlushFunc func(uint64, *MemDB) error
|
||||
type BufferBatchGetter func(ctx context.Context, keys [][]byte) (map[string][]byte, error)
|
||||
|
||||
func NewPipelinedMemDB(bufferBatchGetter BufferBatchGetter, flushFunc FlushFunc) *PipelinedMemDB {
|
||||
memdb := newMemDB()
|
||||
memdb.setSkipMutex(true)
|
||||
flushOptoin := newFlushOption()
|
||||
flushOpt := newFlushOption()
|
||||
return &PipelinedMemDB{
|
||||
memDB: memdb,
|
||||
errCh: make(chan error, 1),
|
||||
|
|
@ -111,7 +107,7 @@ func NewPipelinedMemDB(bufferBatchGetter BufferBatchGetter, flushFunc FlushFunc)
|
|||
// keep entryLimit and bufferLimit same with the memdb's default values.
|
||||
entryLimit: memdb.entrySizeLimit,
|
||||
bufferLimit: memdb.bufferSizeLimit,
|
||||
flushOption: flushOptoin,
|
||||
flushOption: flushOpt,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -125,9 +121,7 @@ func (p *PipelinedMemDB) GetMemDB() *MemDB {
|
|||
panic("GetMemDB should not be invoked for PipelinedMemDB")
|
||||
}
|
||||
|
||||
// Get the value by given key, it returns tikverr.ErrNotExist if not exist.
|
||||
// The priority of the value is MemBuffer > flushingMemDB > flushed memdbs.
|
||||
func (p *PipelinedMemDB) Get(ctx context.Context, k []byte) ([]byte, error) {
|
||||
func (p *PipelinedMemDB) get(ctx context.Context, k []byte, skipRemoteBuffer bool) ([]byte, error) {
|
||||
v, err := p.memDB.Get(k)
|
||||
if err == nil {
|
||||
return v, nil
|
||||
|
|
@ -144,9 +138,19 @@ func (p *PipelinedMemDB) Get(ctx context.Context, k []byte) ([]byte, error) {
|
|||
return nil, err
|
||||
}
|
||||
}
|
||||
if ctx.Value(pipelinedMemDBSkipRemoteBufferKey) != nil {
|
||||
if skipRemoteBuffer {
|
||||
return nil, tikverr.ErrNotExist
|
||||
}
|
||||
if p.batchGetCache != nil {
|
||||
v, ok := p.batchGetCache[string(k)]
|
||||
if ok {
|
||||
inner := v.Inner()
|
||||
if inner == nil {
|
||||
return nil, tikverr.ErrNotExist
|
||||
}
|
||||
return *inner, nil
|
||||
}
|
||||
}
|
||||
// read remote buffer
|
||||
var (
|
||||
dataMap map[string][]byte
|
||||
|
|
@ -163,6 +167,19 @@ func (p *PipelinedMemDB) Get(ctx context.Context, k []byte) ([]byte, error) {
|
|||
return v, nil
|
||||
}
|
||||
|
||||
// Get the value by given key, it returns tikverr.ErrNotExist if not exist.
|
||||
// The priority of the value is MemBuffer > flushingMemDB > flushed memdbs.
|
||||
func (p *PipelinedMemDB) Get(ctx context.Context, k []byte) ([]byte, error) {
|
||||
return p.get(ctx, k, false)
|
||||
}
|
||||
|
||||
// GetLocal implements the MemBuffer interface.
|
||||
// It only checks the mutable memdb and the immutable memdb.
|
||||
// It does not check mutations that have been flushed to TiKV.
|
||||
func (p *PipelinedMemDB) GetLocal(ctx context.Context, key []byte) ([]byte, error) {
|
||||
return p.get(ctx, key, true)
|
||||
}
|
||||
|
||||
func (p *PipelinedMemDB) GetFlags(k []byte) (kv.KeyFlags, error) {
|
||||
f, err := p.memDB.GetFlags(k)
|
||||
if p.flushingMemDB != nil && tikverr.IsErrNotFound(err) {
|
||||
|
|
@ -174,6 +191,44 @@ func (p *PipelinedMemDB) GetFlags(k []byte) (kv.KeyFlags, error) {
|
|||
return f, nil
|
||||
}
|
||||
|
||||
func (p *PipelinedMemDB) BatchGet(ctx context.Context, keys [][]byte) (map[string][]byte, error) {
|
||||
m := make(map[string][]byte, len(keys))
|
||||
if p.batchGetCache == nil {
|
||||
p.batchGetCache = make(map[string]util.Option[[]byte], len(keys))
|
||||
}
|
||||
shrinkKeys := make([][]byte, 0, len(keys))
|
||||
for _, k := range keys {
|
||||
v, err := p.GetLocal(ctx, k)
|
||||
if err != nil {
|
||||
if tikverr.IsErrNotFound(err) {
|
||||
shrinkKeys = append(shrinkKeys, k)
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
m[string(k)] = v
|
||||
p.batchGetCache[string(k)] = util.Some(v)
|
||||
}
|
||||
storageValues, err := p.bufferBatchGetter(ctx, shrinkKeys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, k := range shrinkKeys {
|
||||
v, ok := storageValues[string(k)]
|
||||
if ok {
|
||||
// the protobuf cast empty byte slice to nil, we need to cast it back when receiving values from storage.
|
||||
if v == nil {
|
||||
v = []byte{}
|
||||
}
|
||||
m[string(k)] = v
|
||||
p.batchGetCache[string(k)] = util.Some(v)
|
||||
} else {
|
||||
p.batchGetCache[string(k)] = util.None[[]byte]()
|
||||
}
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (p *PipelinedMemDB) UpdateFlags(k []byte, ops ...kv.FlagsOp) {
|
||||
p.memDB.UpdateFlags(k, ops...)
|
||||
}
|
||||
|
|
@ -214,6 +269,8 @@ func (p *PipelinedMemDB) Flush(force bool) (bool, error) {
|
|||
if p.flushFunc == nil {
|
||||
return false, errors.New("flushFunc is not provided")
|
||||
}
|
||||
// invalidate the batch get cache whether the flush is really triggered.
|
||||
p.batchGetCache = nil
|
||||
if !force && !p.needFlush() {
|
||||
return false, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ package unionstore
|
|||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
|
@ -35,7 +36,6 @@ func TestPipelinedFlushTrigger(t *testing.T) {
|
|||
|
||||
// block the flush goroutine for checking the flushingMemDB status.
|
||||
blockCh := make(chan struct{})
|
||||
defer close(blockCh)
|
||||
// Will not flush when keys number >= MinFlushKeys and size < MinFlushSize
|
||||
memdb := NewPipelinedMemDB(emptyBufferBatchGetter, func(_ uint64, db *MemDB) error {
|
||||
<-blockCh
|
||||
|
|
@ -94,6 +94,8 @@ func TestPipelinedFlushTrigger(t *testing.T) {
|
|||
// the flushingMemDB length and size should be added to the total length and size.
|
||||
require.Equal(t, memdb.Len(), MinFlushKeys)
|
||||
require.Equal(t, memdb.Size(), memdb.flushingMemDB.Size())
|
||||
close(blockCh)
|
||||
require.Nil(t, memdb.FlushWait())
|
||||
}
|
||||
|
||||
func TestPipelinedFlushSkip(t *testing.T) {
|
||||
|
|
@ -131,11 +133,11 @@ func TestPipelinedFlushSkip(t *testing.T) {
|
|||
require.Nil(t, err)
|
||||
require.Equal(t, memdb.memDB.Len(), 0)
|
||||
require.Equal(t, memdb.len, 2*MinFlushKeys)
|
||||
require.Nil(t, memdb.FlushWait())
|
||||
}
|
||||
|
||||
func TestPipelinedFlushBlock(t *testing.T) {
|
||||
blockCh := make(chan struct{})
|
||||
defer close(blockCh)
|
||||
memdb := NewPipelinedMemDB(emptyBufferBatchGetter, func(_ uint64, db *MemDB) error {
|
||||
<-blockCh
|
||||
return nil
|
||||
|
|
@ -176,11 +178,12 @@ func TestPipelinedFlushBlock(t *testing.T) {
|
|||
blockCh <- struct{}{} // first flush done
|
||||
<-flushReturned // second flush start
|
||||
require.True(t, memdb.OnFlushing())
|
||||
close(blockCh)
|
||||
require.Nil(t, memdb.FlushWait())
|
||||
}
|
||||
|
||||
func TestPipelinedFlushGet(t *testing.T) {
|
||||
blockCh := make(chan struct{})
|
||||
defer close(blockCh)
|
||||
memdb := NewPipelinedMemDB(emptyBufferBatchGetter, func(_ uint64, db *MemDB) error {
|
||||
<-blockCh
|
||||
return nil
|
||||
|
|
@ -222,6 +225,8 @@ func TestPipelinedFlushGet(t *testing.T) {
|
|||
// now the key is guaranteed to be flushed into stores, though PipelinedMemDB.Get does not see it, snapshot get should get it.
|
||||
_, err = memdb.Get(context.Background(), []byte("key"))
|
||||
require.True(t, tikverr.IsErrNotFound(err))
|
||||
close(blockCh)
|
||||
require.Nil(t, memdb.FlushWait())
|
||||
}
|
||||
|
||||
func TestPipelinedFlushSize(t *testing.T) {
|
||||
|
|
@ -265,6 +270,7 @@ func TestPipelinedFlushSize(t *testing.T) {
|
|||
require.True(t, flushed)
|
||||
require.Equal(t, memdb.Len(), keys)
|
||||
require.Equal(t, memdb.Size(), size)
|
||||
require.Nil(t, memdb.FlushWait())
|
||||
}
|
||||
|
||||
func TestPipelinedFlushGeneration(t *testing.T) {
|
||||
|
|
@ -279,6 +285,7 @@ func TestPipelinedFlushGeneration(t *testing.T) {
|
|||
// generation start from 1
|
||||
require.Equal(t, <-generationCh, uint64(i+1))
|
||||
}
|
||||
require.Nil(t, memdb.FlushWait())
|
||||
}
|
||||
|
||||
func TestErrorIterator(t *testing.T) {
|
||||
|
|
@ -339,4 +346,110 @@ func TestPipelinedAdjustFlushCondition(t *testing.T) {
|
|||
require.Nil(t, failpoint.Disable("tikvclient/pipelinedMemDBMinFlushKeys"))
|
||||
require.Nil(t, failpoint.Disable("tikvclient/pipelinedMemDBMinFlushSize"))
|
||||
require.Nil(t, failpoint.Disable("tikvclient/pipelinedMemDBForceFlushSizeThreshold"))
|
||||
require.Nil(t, memdb.FlushWait())
|
||||
}
|
||||
|
||||
func TestMemBufferBatchGetCache(t *testing.T) {
|
||||
util.EnableFailpoints()
|
||||
flushDone := make(chan struct{})
|
||||
var remoteMutex sync.RWMutex
|
||||
remoteBuffer := make(map[string][]byte, 16)
|
||||
pipelinedMemdb := NewPipelinedMemDB(func(_ context.Context, keys [][]byte) (map[string][]byte, error) {
|
||||
remoteMutex.RLock()
|
||||
defer remoteMutex.RUnlock()
|
||||
m := make(map[string][]byte, len(keys))
|
||||
for _, k := range keys {
|
||||
if val, ok := remoteBuffer[string(k)]; ok {
|
||||
m[string(k)] = val
|
||||
}
|
||||
}
|
||||
return m, nil
|
||||
}, func(_ uint64, db *MemDB) error {
|
||||
remoteMutex.Lock()
|
||||
defer remoteMutex.Unlock()
|
||||
for it, _ := db.Iter(nil, nil); it.Valid(); it.Next() {
|
||||
remoteBuffer[string(it.Key())] = it.Value()
|
||||
}
|
||||
flushDone <- struct{}{}
|
||||
return nil
|
||||
})
|
||||
|
||||
mustGetFromCache := func(key []byte) ([]byte, error) {
|
||||
require.NotNil(t, pipelinedMemdb.batchGetCache)
|
||||
v, ok := pipelinedMemdb.batchGetCache[string(key)]
|
||||
require.True(t, ok)
|
||||
inner := v.Inner()
|
||||
if inner == nil {
|
||||
return nil, tikverr.ErrNotExist
|
||||
}
|
||||
return *inner, nil
|
||||
}
|
||||
mustNotExistInCache := func(key []byte) {
|
||||
require.NotNil(t, pipelinedMemdb.batchGetCache)
|
||||
_, ok := pipelinedMemdb.batchGetCache[string(key)]
|
||||
require.False(t, ok)
|
||||
}
|
||||
mustFlush := func() {
|
||||
flushed, err := pipelinedMemdb.Flush(true)
|
||||
require.Nil(t, err)
|
||||
require.True(t, flushed)
|
||||
<-flushDone
|
||||
}
|
||||
|
||||
err := pipelinedMemdb.Set([]byte("k1"), []byte("v11"))
|
||||
require.Nil(t, err)
|
||||
mustFlush()
|
||||
err = pipelinedMemdb.Set([]byte("k2"), []byte("v21"))
|
||||
require.Nil(t, err)
|
||||
mustFlush()
|
||||
// memdb: [], flushing memdb: [k2 -> v21], remoteBuffer: [k1 -> v11, k2 -> v21]
|
||||
_, err = pipelinedMemdb.GetLocal(context.Background(), []byte("k1"))
|
||||
require.Error(t, err)
|
||||
require.True(t, tikverr.IsErrNotFound(err))
|
||||
v, err := pipelinedMemdb.GetLocal(context.Background(), []byte("k2"))
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, v, []byte("v21"))
|
||||
// batch get caches the result
|
||||
// cache: [k1 -> v11, k2 -> v21]
|
||||
m, err := pipelinedMemdb.BatchGet(context.Background(), [][]byte{[]byte("k1"), []byte("k2")})
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, m, map[string][]byte{"k1": []byte("v11"), "k2": []byte("v21")})
|
||||
v, err = mustGetFromCache([]byte("k1"))
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, v, []byte("v11"))
|
||||
v, err = mustGetFromCache([]byte("k2"))
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, v, []byte("v21"))
|
||||
mustNotExistInCache([]byte("k3"))
|
||||
// cache: [k1 -> v11, k2 -> v21, k3 -> not exist]
|
||||
m, err = pipelinedMemdb.BatchGet(context.Background(), [][]byte{[]byte("k3")})
|
||||
require.Nil(t, err)
|
||||
require.Len(t, m, 0)
|
||||
_, err = mustGetFromCache([]byte("k3"))
|
||||
require.Error(t, err)
|
||||
require.True(t, tikverr.IsErrNotFound(err))
|
||||
|
||||
// memdb: [], flushing memdb: [k1 -> [], k3 -> []], remoteBuffer: [k1 -> [], k2 -> v21, k3 -> []]
|
||||
pipelinedMemdb.Delete([]byte("k1"))
|
||||
pipelinedMemdb.Set([]byte("k2"), []byte("v22"))
|
||||
pipelinedMemdb.Delete([]byte("k3"))
|
||||
mustFlush()
|
||||
require.Nil(t, pipelinedMemdb.batchGetCache)
|
||||
// cache: [k1 -> [], k2 -> v22, k3 -> [], k4 -> not exist]
|
||||
m, err = pipelinedMemdb.BatchGet(context.Background(), [][]byte{[]byte("k1"), []byte("k2"), []byte("k3"), []byte("k4")})
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, m, map[string][]byte{"k1": {}, "k2": []byte("v22"), "k3": {}})
|
||||
v, err = mustGetFromCache([]byte("k1"))
|
||||
require.Nil(t, err)
|
||||
require.Len(t, v, 0)
|
||||
v, err = mustGetFromCache([]byte("k2"))
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, v, []byte("v22"))
|
||||
v, err = mustGetFromCache([]byte("k3"))
|
||||
require.Nil(t, err)
|
||||
require.Len(t, v, 0)
|
||||
_, err = mustGetFromCache([]byte("k4"))
|
||||
require.Error(t, err)
|
||||
require.True(t, tikverr.IsErrNotFound(err))
|
||||
require.Nil(t, pipelinedMemdb.FlushWait())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -174,6 +174,11 @@ type MemBuffer interface {
|
|||
RUnlock()
|
||||
// Get gets the value for key k from the MemBuffer.
|
||||
Get(context.Context, []byte) ([]byte, error)
|
||||
// GetLocal gets the value from the buffer in local memory.
|
||||
// It makes nonsense for MemDB, but makes a difference for pipelined DML.
|
||||
GetLocal(context.Context, []byte) ([]byte, error)
|
||||
// BatchGet gets the values for given keys from the MemBuffer and cache the result if there are remote buffer.
|
||||
BatchGet(context.Context, [][]byte) (map[string][]byte, error)
|
||||
// GetFlags gets the flags for key k from the MemBuffer.
|
||||
GetFlags([]byte) (kv.KeyFlags, error)
|
||||
// Set sets the value for key k in the MemBuffer.
|
||||
|
|
@ -251,6 +256,10 @@ func (db *MemDBWithContext) Get(_ context.Context, k []byte) ([]byte, error) {
|
|||
return db.MemDB.Get(k)
|
||||
}
|
||||
|
||||
func (db *MemDBWithContext) GetLocal(_ context.Context, k []byte) ([]byte, error) {
|
||||
return db.MemDB.Get(k)
|
||||
}
|
||||
|
||||
func (db *MemDBWithContext) Flush(bool) (bool, error) { return false, nil }
|
||||
|
||||
func (db *MemDBWithContext) FlushWait() error { return nil }
|
||||
|
|
@ -259,3 +268,22 @@ func (db *MemDBWithContext) FlushWait() error { return nil }
|
|||
func (db *MemDBWithContext) GetMemDB() *MemDB {
|
||||
return db.MemDB
|
||||
}
|
||||
|
||||
// BatchGet returns the values for given keys from the MemBuffer.
|
||||
func (db *MemDBWithContext) BatchGet(ctx context.Context, keys [][]byte) (map[string][]byte, error) {
|
||||
if db.Len() == 0 {
|
||||
return map[string][]byte{}, nil
|
||||
}
|
||||
m := make(map[string][]byte, len(keys))
|
||||
for _, k := range keys {
|
||||
v, err := db.Get(ctx, k)
|
||||
if err != nil {
|
||||
if tikverr.IsErrNotFound(err) {
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
m[string(k)] = v
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,5 +57,3 @@ type MemBuffer = unionstore.MemBuffer
|
|||
|
||||
// MemDBCheckpoint is the checkpoint of memory DB.
|
||||
type MemDBCheckpoint = unionstore.MemDBCheckpoint
|
||||
|
||||
var WithPipelinedMemDBSkipRemoteBuffer = unionstore.WithPipelinedMemDBSkipRemoteBuffer
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ package transaction
|
|||
import (
|
||||
"context"
|
||||
|
||||
tikverr "github.com/tikv/client-go/v2/error"
|
||||
"github.com/tikv/client-go/v2/internal/unionstore"
|
||||
)
|
||||
|
||||
|
|
@ -45,6 +44,7 @@ import (
|
|||
type BatchBufferGetter interface {
|
||||
Len() int
|
||||
unionstore.Getter
|
||||
BatchGetter
|
||||
}
|
||||
|
||||
// BatchGetter is the interface for BatchGet.
|
||||
|
|
@ -66,31 +66,31 @@ func NewBufferBatchGetter(buffer BatchBufferGetter, snapshot BatchGetter) *Buffe
|
|||
|
||||
// BatchGet gets a batch of values.
|
||||
func (b *BufferBatchGetter) BatchGet(ctx context.Context, keys [][]byte) (map[string][]byte, error) {
|
||||
if b.buffer.Len() == 0 {
|
||||
return b.snapshot.BatchGet(ctx, keys)
|
||||
}
|
||||
bufferValues := make([][]byte, len(keys))
|
||||
shrinkKeys := make([][]byte, 0, len(keys))
|
||||
for i, key := range keys {
|
||||
val, err := b.buffer.Get(ctx, key)
|
||||
if err == nil {
|
||||
bufferValues[i] = val
|
||||
continue
|
||||
}
|
||||
if !tikverr.IsErrNotFound(err) {
|
||||
bufferValues, err := b.buffer.BatchGet(ctx, keys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(bufferValues) == 0 {
|
||||
return b.snapshot.BatchGet(ctx, keys)
|
||||
}
|
||||
shrinkKeys := make([][]byte, 0, len(keys)-len(bufferValues))
|
||||
for _, key := range keys {
|
||||
val, ok := bufferValues[string(key)]
|
||||
if !ok {
|
||||
shrinkKeys = append(shrinkKeys, key)
|
||||
continue
|
||||
}
|
||||
// the deleted key should be removed from the result, and also no need to snapshot read it again.
|
||||
if len(val) == 0 {
|
||||
delete(bufferValues, string(key))
|
||||
}
|
||||
}
|
||||
storageValues, err := b.snapshot.BatchGet(ctx, shrinkKeys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i, key := range keys {
|
||||
if len(bufferValues[i]) == 0 {
|
||||
continue
|
||||
for key, val := range storageValues {
|
||||
bufferValues[key] = val
|
||||
}
|
||||
storageValues[string(key)] = bufferValues[i]
|
||||
}
|
||||
return storageValues, nil
|
||||
return bufferValues, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,6 +105,9 @@ func (c *twoPhaseCommitter) buildPipelinedFlushRequest(batch batchMutations, gen
|
|||
},
|
||||
},
|
||||
)
|
||||
if c.resourceGroupTag == nil && c.resourceGroupTagger != nil {
|
||||
c.resourceGroupTagger(r)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -301,6 +301,9 @@ func (txn *KVTxn) SetPriority(pri txnutil.Priority) {
|
|||
func (txn *KVTxn) SetResourceGroupTag(tag []byte) {
|
||||
txn.resourceGroupTag = tag
|
||||
txn.GetSnapshot().SetResourceGroupTag(tag)
|
||||
if txn.committer != nil && txn.IsPipelined() {
|
||||
txn.committer.resourceGroupTag = tag
|
||||
}
|
||||
}
|
||||
|
||||
// SetResourceGroupTagger sets the resource tagger for both write and read.
|
||||
|
|
@ -309,12 +312,18 @@ func (txn *KVTxn) SetResourceGroupTag(tag []byte) {
|
|||
func (txn *KVTxn) SetResourceGroupTagger(tagger tikvrpc.ResourceGroupTagger) {
|
||||
txn.resourceGroupTagger = tagger
|
||||
txn.GetSnapshot().SetResourceGroupTagger(tagger)
|
||||
if txn.committer != nil && txn.IsPipelined() {
|
||||
txn.committer.resourceGroupTagger = tagger
|
||||
}
|
||||
}
|
||||
|
||||
// SetResourceGroupName set resource group name for both read and write.
|
||||
func (txn *KVTxn) SetResourceGroupName(name string) {
|
||||
txn.resourceGroupName = name
|
||||
txn.GetSnapshot().SetResourceGroupName(name)
|
||||
if txn.committer != nil && txn.IsPipelined() {
|
||||
txn.committer.resourceGroupName = name
|
||||
}
|
||||
}
|
||||
|
||||
// SetRPCInterceptor sets interceptor.RPCInterceptor for the transaction and its related snapshot.
|
||||
|
|
@ -545,6 +554,11 @@ func (txn *KVTxn) InitPipelinedMemDB() error {
|
|||
}
|
||||
return txn.committer.pipelinedFlushMutations(bo, mutations, generation)
|
||||
})
|
||||
txn.committer.priority = txn.priority.ToPB()
|
||||
txn.committer.syncLog = txn.syncLog
|
||||
txn.committer.resourceGroupTag = txn.resourceGroupTag
|
||||
txn.committer.resourceGroupTagger = txn.resourceGroupTagger
|
||||
txn.committer.resourceGroupName = txn.resourceGroupName
|
||||
txn.us = unionstore.NewUnionStore(pipelinedMemDB, txn.snapshot)
|
||||
return nil
|
||||
}
|
||||
|
|
@ -666,7 +680,8 @@ func (txn *KVTxn) Commit(ctx context.Context) error {
|
|||
}()
|
||||
// latches disabled
|
||||
// pessimistic transaction should also bypass latch.
|
||||
if txn.store.TxnLatches() == nil || txn.IsPessimistic() {
|
||||
// transaction with pipelined memdb should also bypass latch.
|
||||
if txn.store.TxnLatches() == nil || txn.IsPessimistic() || txn.IsPipelined() {
|
||||
err = committer.execute(ctx)
|
||||
if val == nil || sessionID > 0 {
|
||||
txn.onCommitted(err)
|
||||
|
|
|
|||
|
|
@ -255,7 +255,8 @@ func (s *KVSnapshot) BatchGetWithTier(ctx context.Context, keys [][]byte, readTi
|
|||
// Create a map to collect key-values from region servers.
|
||||
var mu sync.Mutex
|
||||
err := s.batchGetKeysByRegions(bo, keys, readTier, func(k, v []byte) {
|
||||
if len(v) == 0 {
|
||||
// when read buffer tier, empty value means a delete record, should also collect it.
|
||||
if len(v) == 0 && readTier != BatchGetBufferTier {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -1009,10 +1010,21 @@ func (s *KVSnapshot) SnapCacheHitCount() int {
|
|||
// SnapCacheSize gets the snapshot cache size. Only for test.
|
||||
func (s *KVSnapshot) SnapCacheSize() int {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
return len(s.mu.cached)
|
||||
}
|
||||
|
||||
// SnapCache gets the copy of snapshot cache. Only for test.
|
||||
func (s *KVSnapshot) SnapCache() map[string][]byte {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
cp := make(map[string][]byte, len(s.mu.cached))
|
||||
for k, v := range s.mu.cached {
|
||||
cp[k] = v
|
||||
}
|
||||
return cp
|
||||
}
|
||||
|
||||
// SetVars sets variables to the transaction.
|
||||
func (s *KVSnapshot) SetVars(vars *kv.Variables) {
|
||||
s.vars = vars
|
||||
|
|
|
|||
16
util/misc.go
16
util/misc.go
|
|
@ -210,3 +210,19 @@ func HexRegionKey(key []byte) []byte {
|
|||
func HexRegionKeyStr(key []byte) string {
|
||||
return String(HexRegionKey(key))
|
||||
}
|
||||
|
||||
type Option[T interface{}] struct {
|
||||
inner *T
|
||||
}
|
||||
|
||||
func Some[T interface{}](inner T) Option[T] {
|
||||
return Option[T]{inner: &inner}
|
||||
}
|
||||
|
||||
func None[T interface{}]() Option[T] {
|
||||
return Option[T]{inner: nil}
|
||||
}
|
||||
|
||||
func (o Option[T]) Inner() *T {
|
||||
return o.inner
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue