Skip to content

Commit

Permalink
[Performance] Investigate and decrease RAM usage - add pebble kvstore (
Browse files Browse the repository at this point in the history
…#52)

Signed-off-by: Dima K. <[email protected]>
Co-authored-by: Daniel Olshansky <[email protected]>
  • Loading branch information
okdas and Olshansk authored Aug 22, 2024
1 parent 3de80fe commit 21ea863
Show file tree
Hide file tree
Showing 19 changed files with 1,390 additions and 49 deletions.
10 changes: 9 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ test_all: ## runs the test suite
test_badger: ## runs the badger KVStore submodule's test suite
go test -v -p 1 -count=1 ./kvstore/badger/... -mod=readonly -race

.PHONY: test_pebble
test_pebble: ## runs the pebble KVStore submodule's test suite
go test -v -p 1 -count=1 ./kvstore/pebble/... -mod=readonly -race


#####################
### go helpers ###
Expand Down Expand Up @@ -93,6 +97,10 @@ benchmark_smst_ops: ## runs the benchmarks test different operations on the SMS
benchmark_proof_sizes: ## runs the benchmarks test the proof sizes for different sized tries
go test -tags=benchmark -v ./benchmarks -run ProofSizes

.PHONY: benchmark_pebble
benchmark_pebble: ## TODO: Add the pebble benchmarks
echo "TODO: Implement pebble benchmarks"

###########################
### Release Helpers ###
###########################
Expand Down Expand Up @@ -120,4 +128,4 @@ tag_minor_release: ## Tag a new minor release (e.g. v1.0.0 -> v1.1.0)
@echo "New minor release version tagged: $(NEW_TAG)"
@echo "Run the following commands to push the new tag:"
@echo " git push origin $(NEW_TAG)"
@echo "And draft a new release at https://github.com/pokt-network/smt/releases/new"
@echo "And draft a new release at https://github.com/pokt-network/smt/releases/new"
10 changes: 6 additions & 4 deletions go.work
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
go 1.20

use (
// Include the main SMT module
.
// Include the badger KVStore submodule
./kvstore/badger
// Include the main SMT module
.
// Include the badger KVStore submodule
./kvstore/badger
// Include the pebble KVStore submodule
./kvstore/pebble
)
82 changes: 75 additions & 7 deletions go.work.sum
Original file line number Diff line number Diff line change
@@ -1,43 +1,111 @@
cloud.google.com/go v0.26.0 h1:e0WKqKTd5BnrG8aKH3J3h+QvEIQtSUcf2n5UZ5ZgLtQ=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno=
github.com/CloudyKit/jet/v6 v6.2.0/go.mod h1:d3ypHeIRNo2+XyqnGA8s+aphtcVpjP5hPwP/Lzo7Ro4=
github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
github.com/Joker/jade v1.1.3/go.mod h1:T+2WLyt7VH6Lp0TRxQrUYEs64nRc83wkMQrfeIQKduM=
github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM=
github.com/aclements/go-moremath v0.0.0-20210112150236-f10218a38794/go.mod h1:7e+I0LQFUI9AXWxOfsQROs9xPhoJtbsyWcjJqDd4KPY=
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8=
github.com/ghemawat/stream v0.0.0-20171120220530-696b145b53b9/go.mod h1:106OIgooyS7OzLDOpUGgm9fA3bQENb/cFSyyBmMoJDs=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4=
github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
github.com/golang/mock v1.1.1 h1:G5FRp8JnTd7RQH5kemVNlMeyXQAztQ3mOWV95KxsXH8=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
github.com/guptarohit/asciigraph v0.5.5/go.mod h1:dYl5wwK4gNsnFf9Zp+l06rFiDZ5YtXM6x7SRWZ3KGag=
github.com/hydrogen18/memlistener v1.0.0/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/iris-contrib/schema v0.0.6/go.mod h1:iYszG0IOsuIsfzjymw1kMzTL8YQcCWlm65f3wX8J5iA=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/kataras/blocks v0.0.7/go.mod h1:UJIU97CluDo0f+zEjbnbkeMRlvYORtmc1304EeyXf4I=
github.com/kataras/golog v0.1.8/go.mod h1:rGPAin4hYROfk1qT9wZP6VY2rsb4zzc37QpdPjdkqVw=
github.com/kataras/iris/v12 v12.2.0/go.mod h1:BLzBpEunc41GbE68OUaQlqX4jzi791mx5HU04uPb90Y=
github.com/kataras/pio v0.0.11/go.mod h1:38hH6SWH6m4DKSYmRhlrCJ5WItwWgCVrTNU62XZyUvI=
github.com/kataras/sitemap v0.0.6/go.mod h1:dW4dOCNs896OR1HmG+dMLdT7JjDk7mYBzoIRwuj5jA4=
github.com/kataras/tunnel v0.0.4/go.mod h1:9FkU4LaeifdMWqZu7o20ojmW4B7hdhv2CMLwfnHGpYw=
github.com/kisielk/errcheck v1.5.0 h1:e8esj/e4R+SAOwFwN+n3zr0nYeCyeweozKfO23MvHzY=
github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=
github.com/labstack/echo/v4 v4.10.0/go.mod h1:S/T/5fy/GigaXnHTkh0ZGe4LpkkQysvRjFMSUTkDRNQ=
github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/mailgun/raymond/v2 v2.0.48/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/microcosm-cc/bluemonday v1.0.23/go.mod h1:mN70sk7UkkF8TUr2IGBpNN0jAgStuPzlK76QuruE/z4=
github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
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/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
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/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/tdewolff/minify/v2 v2.12.4/go.mod h1:h+SRvSIX3kwgwTFOpSckvSxgax3uy8kZTSF1Ojrr3bk=
github.com/tdewolff/parse/v2 v2.6.4/go.mod h1:woz0cgbLwFdtbjJu8PIKxhW05KplTFQkOdX78o+Jgrs=
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.40.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0=
github.com/yuin/goldmark v1.2.1 h1:ruQGxdhGHe7FWOJPT0mKs5+pD2Xs1Bm/kdGlHO04FmM=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4 h1:c2HOrn5iMezYjSlGPncknSEr/8x5LELb/ilJbXi9DEA=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3 h1:XQyxROzUlZH+WIQwySDgnISgOivlhjIEwaQaJEJrrN0=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
golang.org/x/perf v0.0.0-20230113213139-801c7ef9e5c5/go.mod h1:UBKtEnL8aqnd+0JHqZ+2qoMDwtuy6cYhhKNoHLBiTQc=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a h1:CB3a9Nez8M13wwlr/E2YtwoU+qYHKfC+JrDa45RXXoQ=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
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-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
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/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099 h1:XJP7lxbSxWLOMNdBE4B/STaqVy6L73o0knwj2vIlxnw=
3 changes: 3 additions & 0 deletions kvstore/badger/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,7 @@ var (
// ErrBadgerGettingStoreLength is returned when the badger store fails to
// get the length of the database
ErrBadgerGettingStoreLength = errors.New("unable to get database length")
// ErrBadgerUnableToCheckExistence is returned when the badger store fails to
// check if a key exists
ErrBadgerUnableToCheckExistence = errors.New("unable to check key existence")
)
16 changes: 1 addition & 15 deletions kvstore/badger/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,7 @@ var _ kvstore.MapStore = (BadgerKVStore)(nil)
// This is a superset of the MapStore interface that offers more
// features and can be used as a standalone key-value store.
type BadgerKVStore interface {
// --- Store methods ---

// Get returns the value for a given key
Get(key []byte) ([]byte, error)
// Set sets/updates the value for a given key
Set(key, value []byte) error
// Delete removes a key
Delete(key []byte) error
kvstore.MapStore

// --- Lifecycle methods ---

Expand All @@ -41,11 +34,4 @@ type BadgerKVStore interface {
GetAll(prefixKey []byte, descending bool) (keys, values [][]byte, err error)
// Exists returns true if the key exists
Exists(key []byte) (bool, error)
// Len returns the number of key-value pairs in the store
Len() int

// --- Data management ---

// ClearAll deletes all key-value pairs in the store
ClearAll() error
}
57 changes: 45 additions & 12 deletions kvstore/badger/kvstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ type badgerKVStore struct {

// NewKVStore creates a new BadgerKVStore using badger as the underlying database
// if no path for a persistence database is provided it will create one in-memory
// TODO_CONSIDERATION: consider exposing the low-level options (`badgerv4.Options`) via a
// config file to make it easier to test under different load conditions.
func NewKVStore(path string) (BadgerKVStore, error) {
var db *badgerv4.DB
var err error
Expand All @@ -31,6 +33,7 @@ func NewKVStore(path string) (BadgerKVStore, error) {
if err != nil {
return nil, errors.Join(ErrBadgerOpeningStore, err)
}

return &badgerKVStore{db: db}, nil
}

Expand Down Expand Up @@ -109,13 +112,26 @@ func (store *badgerKVStore) GetAll(prefix []byte, descending bool) (keys, values
return keys, values, nil
}

// Exists checks whether the key exists in the store
// Exists checks whether the key exists in the store without retrieving the full value.
// This avoids unnecessary memory allocations and copying that would occur with a full Get.
func (store *badgerKVStore) Exists(key []byte) (bool, error) {
val, err := store.Get(key)
var exists bool
err := store.db.View(func(tx *badgerv4.Txn) error {
item, err := tx.Get(key)
if err != nil {
return err
}
// Check if the value is nil
err = item.Value(func(val []byte) error {
exists = len(val) > 0
return nil
})
return err
})
if err != nil {
return false, err
return false, errors.Join(ErrBadgerUnableToCheckExistence, err)
}
return val != nil, nil
return exists, nil
}

// ClearAll deletes all key-value pairs in the store
Expand Down Expand Up @@ -159,9 +175,9 @@ func (store *badgerKVStore) Stop() error {
}

// Len gives the number of keys in the store
func (store *badgerKVStore) Len() int {
count := 0
if err := store.db.View(func(tx *badgerv4.Txn) error {
func (store *badgerKVStore) Len() (int, error) {
var count int
err := store.db.View(func(tx *badgerv4.Txn) error {
opt := badgerv4.DefaultIteratorOptions
opt.Prefix = []byte{}
opt.Reverse = false
Expand All @@ -171,14 +187,22 @@ func (store *badgerKVStore) Len() int {
count++
}
return nil
}); err != nil {
panic(errors.Join(ErrBadgerGettingStoreLength, err))
})
if err != nil {
return 0, errors.Join(ErrBadgerGettingStoreLength, err)
}
return count
return count, nil
}

// PrefixEndBytes returns the end byteslice for a noninclusive range
// that would include all byte slices for which the input is the prefix
// prefixEndBytes returns the end byteslice for a noninclusive range
// that would include all byte slices for which the input is the prefix.
// It's used in reverse iteration to set the upper bound of the key range.
//
// Example:
// If prefix is []byte("user:1"), prefixEndBytes returns []byte("user:2").
// This ensures that in reverse iteration:
// - Keys like "user:1", "user:1:profile", "user:10" are included.
// - But "user:2", "user:2:profile" are not included.
func prefixEndBytes(prefix []byte) []byte {
if len(prefix) == 0 {
return nil
Expand All @@ -194,7 +218,16 @@ func prefixEndBytes(prefix []byte) []byte {

// badgerOptions returns the badger options for the store being created
func badgerOptions(path string) badgerv4.Options {
// DEV_NOTE: Parameters should be adjusted carefully, depending on the type of load. We need to experiment more to find the best
// values, and even then they might need further adjustments as the type of load/environment (e.g. memory dedicated
// to the process) changes.
//
// Good links to read about options:
// - https://github.com/dgraph-io/badger/issues/1304#issuecomment-630078745
// - https://github.com/dgraph-io/badger/blob/master/options.go#L37
// - https://github.com/open-policy-agent/opa/issues/4014#issuecomment-1003700744
opts := badgerv4.DefaultOptions(path)
opts.Logger = nil // disable badger's logger since it's very noisy

return opts
}
7 changes: 5 additions & 2 deletions kvstore/badger/kvstore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/stretchr/testify/require"

badgerv4 "github.com/dgraph-io/badger/v4"
"github.com/pokt-network/smt/kvstore/badger"
)

Expand Down Expand Up @@ -280,7 +281,7 @@ func TestBadger_KVStore_Exists(t *testing.T) {

// Key does not exist
exists, err = store.Exists([]byte("oof"))
require.ErrorIs(t, err, badger.ErrBadgerUnableToGetValue)
require.ErrorIs(t, err, badgerv4.ErrKeyNotFound)
require.False(t, exists)

err = store.Stop()
Expand Down Expand Up @@ -389,7 +390,9 @@ func TestBadger_KVStore_Len(t *testing.T) {

for _, tc := range tests {
require.NoError(t, store.Set(tc.key, tc.value))
require.Equal(t, tc.size, store.Len())
len, err := store.Len()
require.NoError(t, err)
require.Equal(t, tc.size, len)
}
}

Expand Down
2 changes: 1 addition & 1 deletion kvstore/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type MapStore interface {
// Delete removes a key
Delete(key []byte) error
// Len returns the number of key-value pairs in the store
Len() int
Len() (int, error)

// --- Debug ---

Expand Down
36 changes: 36 additions & 0 deletions kvstore/pebble/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package pebble

import "errors"

// Error definitions
var (
// ErrPebbleOpeningStore is returned when there's an error opening the Pebble database.
ErrPebbleOpeningStore = errors.New("error opening the store")

// ErrPebbleUnableToSetValue is returned when a value cannot be set in the store.
ErrPebbleUnableToSetValue = errors.New("unable to set value")

// ErrPebbleUnableToGetValue is returned when a value cannot be retrieved from the store.
ErrPebbleUnableToGetValue = errors.New("unable to get value")

// ErrPebbleUnableToDeleteValue is returned when a value cannot be deleted from the store.
ErrPebbleUnableToDeleteValue = errors.New("unable to delete value")

// ErrPebbleIteratingStore is returned when there's an error iterating over the database.
ErrPebbleIteratingStore = errors.New("unable to iterate over database")

// ErrPebbleClearingStore is returned when there's an error clearing all data from the store.
ErrPebbleClearingStore = errors.New("unable to clear store")

// ErrPebbleUnableToBackup is returned when there's an error backing up the database.
ErrPebbleUnableToBackup = errors.New("unable to backup database")

// ErrPebbleUnableToRestore is returned when there's an error restoring the database from a backup.
ErrPebbleUnableToRestore = errors.New("unable to restore database")

// ErrPebbleClosingStore is returned when there's an error closing the database connection.
ErrPebbleClosingStore = errors.New("unable to close database")

// ErrPebbleGettingStoreLength is returned when there's an error getting the number of key-value pairs in the database.
ErrPebbleGettingStoreLength = errors.New("unable to get database length")
)
Loading

0 comments on commit 21ea863

Please sign in to comment.