From 8e6243dda5d708667c49a5ef02eb9be52e7d6dee Mon Sep 17 00:00:00 2001 From: Han Kang Date: Sun, 30 Jul 2023 17:31:00 -0700 Subject: [PATCH] first pass at sqlite implementation (rebased) use non-cgo implementation first, so that builds continue to function Change-Id: I05aa62ad56a771552e81d397e59570737767346f Signed-off-by: Han Kang --- bill-of-materials.json | 72 ++++ etcdutl/go.mod | 8 + etcdutl/go.sum | 19 + go.mod | 7 + go.sum | 16 + server/config/config.go | 3 + server/databases/bbolt/bbolt.go | 3 - server/databases/sqlite/sqlite.go | 536 +++++++++++++++++++++++++ server/databases/sqlite/sqlite_test.go | 175 ++++++++ server/embed/config.go | 20 +- server/embed/etcd.go | 1 + server/go.mod | 8 + server/go.sum | 19 + server/storage/backend/backend.go | 55 ++- tests/go.mod | 7 + tests/go.sum | 16 + 16 files changed, 954 insertions(+), 11 deletions(-) create mode 100644 server/databases/sqlite/sqlite.go create mode 100644 server/databases/sqlite/sqlite_test.go diff --git a/bill-of-materials.json b/bill-of-materials.json index b5cf5d624f0..c3dfefc105e 100644 --- a/bill-of-materials.json +++ b/bill-of-materials.json @@ -125,6 +125,15 @@ } ] }, + { + "project": "github.com/glebarez/go-sqlite", + "licenses": [ + { + "type": "BSD 3-clause \"New\" or \"Revised\" License", + "confidence": 0.9707112970711297 + } + ] + }, { "project": "github.com/go-logr/logr", "licenses": [ @@ -197,6 +206,15 @@ } ] }, + { + "project": "github.com/google/uuid", + "licenses": [ + { + "type": "BSD 3-clause \"New\" or \"Revised\" License", + "confidence": 0.9663865546218487 + } + ] + }, { "project": "github.com/gorilla/websocket", "licenses": [ @@ -350,6 +368,15 @@ } ] }, + { + "project": "github.com/remyoudompheng/bigfft", + "licenses": [ + { + "type": "BSD 3-clause \"New\" or \"Revised\" License", + "confidence": 0.9663865546218487 + } + ] + }, { "project": "github.com/rivo/uniseg", "licenses": [ @@ -759,6 +786,51 @@ } ] }, + { + "project": "modernc.org/libc", + "licenses": [ + { + "type": "BSD 3-clause \"New\" or \"Revised\" License", + "confidence": 0.9617021276595744 + } + ] + }, + { + "project": "modernc.org/libc/honnef.co/go/netdb", + "licenses": [ + { + "type": "MIT License", + "confidence": 0.9891304347826086 + } + ] + }, + { + "project": "modernc.org/mathutil", + "licenses": [ + { + "type": "BSD 3-clause \"New\" or \"Revised\" License", + "confidence": 0.9617021276595744 + } + ] + }, + { + "project": "modernc.org/memory", + "licenses": [ + { + "type": "BSD 3-clause \"New\" or \"Revised\" License", + "confidence": 0.9617021276595744 + } + ] + }, + { + "project": "modernc.org/sqlite/lib", + "licenses": [ + { + "type": "BSD 3-clause \"New\" or \"Revised\" License", + "confidence": 0.9707112970711297 + } + ] + }, { "project": "sigs.k8s.io/json", "licenses": [ diff --git a/etcdutl/go.mod b/etcdutl/go.mod index 326abbe8a08..484d8f63808 100644 --- a/etcdutl/go.mod +++ b/etcdutl/go.mod @@ -38,21 +38,25 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/glebarez/go-sqlite v1.21.2 // indirect github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/btree v1.1.2 // indirect + github.com/google/uuid v1.3.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jonboulle/clockwork v0.4.0 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/prometheus/client_golang v1.16.0 // indirect github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/common v0.43.0 // indirect github.com/prometheus/procfs v0.10.1 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect @@ -72,5 +76,9 @@ require ( google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6 // indirect google.golang.org/grpc v1.52.0 // indirect google.golang.org/protobuf v1.31.0 // indirect + modernc.org/libc v1.22.5 // indirect + modernc.org/mathutil v1.5.0 // indirect + modernc.org/memory v1.5.0 // indirect + modernc.org/sqlite v1.23.1 // indirect sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect ) diff --git a/etcdutl/go.sum b/etcdutl/go.sum index bcee9c2c6e9..3f41f2474bc 100644 --- a/etcdutl/go.sum +++ b/etcdutl/go.sum @@ -33,6 +33,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo= +github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -57,7 +59,10 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= @@ -70,6 +75,8 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= @@ -89,6 +96,9 @@ github.com/prometheus/common v0.43.0 h1:iq+BVjvYLei5f27wiuNiB1DN6DYQkp1c8Bx0Vykh github.com/prometheus/common v0.43.0/go.mod h1:NCvr5cQIh3Y/gy73/RdVtC9r8xxrxwJnB+2lB3BxrFc= github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= @@ -170,6 +180,7 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -219,5 +230,13 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE= +modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY= +modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds= +modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/sqlite v1.23.1 h1:nrSBg4aRQQwq59JpvGEQ15tNxoO5pX/kUjcRNwSAGQM= +modernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= diff --git a/go.mod b/go.mod index 5cd17324401..9f0d7c928ec 100644 --- a/go.mod +++ b/go.mod @@ -47,6 +47,7 @@ require ( github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fatih/color v1.15.0 // indirect + github.com/glebarez/go-sqlite v1.21.2 // indirect github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect @@ -55,6 +56,7 @@ require ( github.com/golang/protobuf v1.5.3 // indirect github.com/google/btree v1.1.2 // indirect github.com/google/go-cmp v0.5.9 // indirect + github.com/google/uuid v1.3.0 // indirect github.com/gorilla/websocket v1.4.2 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect @@ -72,6 +74,7 @@ require ( github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/common v0.43.0 // indirect github.com/prometheus/procfs v0.10.1 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/sirupsen/logrus v1.8.1 // indirect github.com/soheilhy/cmux v0.1.5 // indirect @@ -98,6 +101,10 @@ require ( gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + modernc.org/libc v1.22.5 // indirect + modernc.org/mathutil v1.5.0 // indirect + modernc.org/memory v1.5.0 // indirect + modernc.org/sqlite v1.23.1 // indirect sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index fd631d03527..eba9780ee83 100644 --- a/go.sum +++ b/go.sum @@ -91,6 +91,8 @@ github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo= +github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -164,8 +166,11 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= @@ -222,6 +227,9 @@ github.com/prometheus/common v0.43.0 h1:iq+BVjvYLei5f27wiuNiB1DN6DYQkp1c8Bx0Vykh github.com/prometheus/common v0.43.0/go.mod h1:NCvr5cQIh3Y/gy73/RdVtC9r8xxrxwJnB+2lB3BxrFc= github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= @@ -585,6 +593,14 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE= +modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY= +modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds= +modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/sqlite v1.23.1 h1:nrSBg4aRQQwq59JpvGEQ15tNxoO5pX/kUjcRNwSAGQM= +modernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/server/config/config.go b/server/config/config.go index ee595127ec1..e285a17bb1d 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -204,6 +204,9 @@ type ServerConfig struct { // ExperimentalMaxLearners sets a limit to the number of learner members that can exist in the cluster membership. ExperimentalMaxLearners int `json:"experimental-max-learners"` + // ExperimentalBackendType sets the backend type. + ExperimentalBackendType string `json:"experimental-backend-type"` + // V2Deprecation defines a phase of v2store deprecation process. V2Deprecation V2DeprecationEnum `json:"v2-deprecation"` } diff --git a/server/databases/bbolt/bbolt.go b/server/databases/bbolt/bbolt.go index 050e0491c91..67726affe10 100644 --- a/server/databases/bbolt/bbolt.go +++ b/server/databases/bbolt/bbolt.go @@ -275,7 +275,6 @@ func (b *BBoltDB) defrag(odb, tmpdb *bolt.DB, limit int) error { return err } } - return tmptx.Commit() } @@ -481,5 +480,3 @@ func (b *BBoltBucket) ForEachBucket(fn interface{}) error { func (b *BBoltBucket) Stats() interface{} { return b.bucket.Stats() } - -//db, err := bolt.Open(bcfg.Path, 0600, bopts) diff --git a/server/databases/sqlite/sqlite.go b/server/databases/sqlite/sqlite.go new file mode 100644 index 00000000000..da66c491eb1 --- /dev/null +++ b/server/databases/sqlite/sqlite.go @@ -0,0 +1,536 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package sqlite + +import ( + // sqlite DB driver + + "bufio" + "database/sql" + "fmt" + "hash/crc32" + "io" + "log" + "os" + "strings" + + _ "github.com/glebarez/go-sqlite" + "github.com/prometheus/client_golang/prometheus" + "go.uber.org/zap" + + bolt "go.etcd.io/bbolt" + "go.etcd.io/etcd/server/v3/interfaces" +) + +const ( + hasBucketQuery = `SELECT name FROM sqlite_master WHERE type='table' AND name=?;` + queryTableNames = `SELECT name FROM sqlite_schema WHERE type='table' ORDER BY name;` + dropBucketQuery = `DROP TABLE IF EXISTS ?;` + createBucketQuery = "CREATE TABLE IF NOT EXISTS %s (key STRING PRIMARY KEY, value BLOB);" + genericUnsafeRangeQuery = "select key, value from %s WHERE key >= ? AND key <= ? ORDER BY key limit ?;" + genericUnsafeRangeQueryNoEnd = "select key, value from %s WHERE key >= ? ORDER BY key limit ?;" + genericGet = "SELECT value from %s WHERE key=?;" + genericUpsert = "INSERT INTO %s (key, value) VALUES(?, ?) ON CONFLICT(key) DO UPDATE SET value=excluded.value;" + genericDelete = "DELETE from %s where key = ?;" + genericForEach = "select key, value from %s;" + + sizeQuery = `SELECT page_count * page_size as size FROM pragma_page_count(), pragma_page_size();` + defragCommand = `VACUUM;` + UpsertKV = `INSERT INTO KVs (key, value) + VALUES(?, ?) ON CONFLICT(key) DO UPDATE SET value=excluded.value;` + + dbName = "db" +) + +type SqliteDB struct { + DB *sql.DB + Dir string + dbName string + FreeListType string // no-opts +} + +type BackendBucket interface { + Name() []byte +} + +func NewBlankSqliteDB(dir string) (*SqliteDB, error) { + parts := strings.Split(dir, "/") + subdir := strings.Join(parts[:len(parts)-1], "/") + name := parts[len(parts)-1] + if err := os.MkdirAll(subdir, 0755); err != nil { + fmt.Printf("couldn't make directory: %s", dir) + return nil, err + } + db, err := sql.Open("sqlite", subdir+"/"+dbName) + + if err != nil { + return nil, err + } + db.SetConnMaxLifetime(0) + db.SetMaxIdleConns(50) + db.SetMaxOpenConns(50) + // ensure that DB is functional + if err = db.Ping(); err != nil { + return nil, err + } + if err != nil { + return nil, err + } + sdb := newDB(db, subdir, name) + return sdb, nil +} + +func NewSqliteDB[B BackendBucket](dir string, buckets ...B) (*SqliteDB, error) { + parts := strings.Split(dir, "/") + subdir := strings.Join(parts[:len(parts)-1], "/") + name := parts[len(parts)-1] + db, err := sql.Open("sqlite", dir) + + if err != nil { + return nil, err + } + db.SetConnMaxLifetime(0) + db.SetMaxIdleConns(50) + db.SetMaxOpenConns(50) + // ensure that DB is functional + if err = db.Ping(); err != nil { + return nil, err + } + for _, b := range buckets { + tn := resolveTableName(string(b.Name())) + createTableQuery := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s (key STRING PRIMARY KEY, value BLOB );", tn) + _, err = db.Exec(createTableQuery) + } + + if err != nil { + return nil, err + } + sdb := newDB(db, subdir, name) + return sdb, nil +} + +func newDB(db *sql.DB, dir string, dbName string) *SqliteDB { + return &SqliteDB{ + DB: db, + Dir: dir, + dbName: dbName, + FreeListType: string(bolt.FreelistMapType), // dummy value + } +} + +func (s *SqliteDB) Path() string { + return s.Dir +} + +func (s *SqliteDB) GoString() string { + return s.Dir + "/" + dbName +} + +func (s *SqliteDB) Buckets() []string { + rows, err := s.DB.Query(queryTableNames) + if err != nil { + return nil + } + defer rows.Close() + names := make([]string, 0) + + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + // Check for a scan error. + // Query rows will be closed with defer. + log.Fatal(err) + } + names = append(names, name) + } + return names +} + +func (s *SqliteDB) HasBucket(name string) bool { + tableName := resolveTableName(name) + rows, err := s.DB.Query(hasBucketQuery, tableName) + if err != nil { + return false + } + defer rows.Close() + names := make([]string, 0) + + for rows.Next() { + var n string + if err := rows.Scan(&n); err != nil { + // Check for a scan error. + // Query rows will be closed with defer. + log.Fatal(err) + } + names = append(names, n) + } + if len(names) < 1 { + return false + } else if len(names) > 1 { + panic("too many keys of the same bucket") + } else { + return true + } +} + +func (s *SqliteDB) DeleteBucket(name []byte) error { + tableName := resolveTableName(string(name)) + _, err := s.DB.Exec(dropBucketQuery, tableName) + if err != nil { + return err + } + return nil +} + +func (s *SqliteDB) CreateBucket(s2 string) { + tableName := resolveTableName(s2) + query := fmt.Sprintf(createBucketQuery, tableName) + if _, err := s.DB.Exec(query); err != nil { + panic(err) + } +} + +func (s *SqliteDB) GetFromBucket(bucket string, key string) []byte { + tableName := resolveTableName(bucket) + query := fmt.Sprintf(genericGet, tableName) + r, err := s.DB.Query(query, key) + if err != nil { + return nil + } + defer r.Close() + var val []byte + for r.Next() { + if err := r.Scan(&val); err != nil { + log.Fatal(err) + } + return val + } + return nil +} + +func resolveTableName(bucket string) string { + tableName := bucket + if tableName == "key" { + tableName = "KVs" + } + return tableName +} + +func (s *SqliteDB) String() string { + //TODO implement me + panic("implement me") +} + +func (s *SqliteDB) Close() error { + return s.DB.Close() +} + +func (s *SqliteDB) Begin(writable bool) (interfaces.Tx, error) { + tx, err := s.DB.Begin() + if err != nil { + return nil, err + } + return &SqliteTx{tx: tx, writable: writable, db: s.DB, dir: s.Dir, dbName: s.dbName}, nil +} + +func (s *SqliteDB) Size() (size int64) { + if rows, err := s.DB.Query(sizeQuery); err != nil { + return 0 + } else { + var val int64 + defer rows.Close() + rows.Next() + rows.Scan(&val) + return val + } +} + +func (s *SqliteDB) Sync() error { + // no-opt. + return nil +} + +func (s *SqliteDB) Stats() interface{} { + return s.DB.Stats() +} + +func (s *SqliteDB) Info() interface{} { + return s.DB.Stats() +} + +func (s *SqliteDB) SetFreelistType(freelistType string) { + s.FreeListType = freelistType +} + +func (s *SqliteDB) FreelistType() string { + return s.FreeListType +} + +func (s *SqliteDB) DBType() string { + return "sqlite" +} + +func (s *SqliteDB) HashBuckets(ignores func(bucketName []byte, keyName []byte) bool) (uint32, error) { + h := crc32.New(crc32.MakeTable(crc32.Castagnoli)) + // todo(logicalhan) fixme + return h.Sum32(), nil +} + +func (s *SqliteDB) Defrag(logger *zap.Logger, dbopts interface{}, limit int) error { + _, err := s.DB.Exec(defragCommand) + return err +} + +type SqliteTx struct { + tx *sql.Tx + db *sql.DB + dir string + dbName string + writable bool + size int64 +} + +func (s *SqliteTx) DB() interfaces.DB { + return newDB(s.db, s.dir, s.dbName) +} + +func (s *SqliteTx) Size() int64 { + if s.size == 0 { + return s.DB().Size() + } + return s.size +} + +func (s *SqliteTx) Writable() bool { + return s.writable +} + +func (s *SqliteTx) Stats() interface{} { + panic("implement me") +} + +func (s *SqliteTx) Bucket(name []byte) interfaces.Bucket { + tableName := resolveTableName(string(name)) + return &SqliteBucket{ + name: tableName, + db: s.db, + dbName: s.dbName, + TX: s.tx, + dir: s.dir, + writable: s.writable, + } +} + +func (s *SqliteTx) CreateBucket(name []byte) (interfaces.Bucket, error) { + tableName := resolveTableName(string(name)) + query := fmt.Sprintf(createBucketQuery, tableName) + _, err := s.tx.Exec(query) + if err != nil { + return nil, err + } + return &SqliteBucket{ + name: tableName, + db: s.db, + TX: s.tx, + dbName: s.dbName, + dir: s.dir, + writable: s.writable, + }, nil +} + +func (s *SqliteTx) DeleteBucket(name []byte) error { + _, err := s.tx.Exec(dropBucketQuery, string(name)) + return err +} + +func (s *SqliteTx) ForEach(i interface{}) error { + //TODO implement me + panic("implement me") +} + +func (s *SqliteTx) Observe(rebalanceHist, spillHist, writeHist prometheus.Histogram) { + // no-opt +} + +func (s *SqliteTx) WriteTo(w io.Writer) (n int64, err error) { + tmpdir := os.TempDir() + os.MkdirAll(tmpdir, 0755) + backup := tmpdir + "etcd.sqlite" + os.Remove(backup) + if _, err := s.db.Exec(`VACUUM main INTO ?;`, backup); err != nil { + return 0, err + } + stat, err := os.Stat(backup) + if err != nil { + return 0, err + } + size := stat.Size() + s.size = size + f, err := os.Open(backup) + defer f.Close() + if err != nil { + return 0, err + } + + r := bufio.NewReader(f) + return r.WriteTo(w) +} + +func (s *SqliteTx) CopyDatabase(lg *zap.Logger, dst string) (err error) { + //TODO implement me + panic("implement me") +} + +func (s *SqliteTx) Commit() error { + return s.tx.Commit() +} + +func (s *SqliteTx) Rollback() error { + return s.tx.Rollback() +} + +type SqliteBucket struct { + TX *sql.Tx + name string + dbName string + db *sql.DB + dir string + writable bool +} + +func (s *SqliteBucket) Tx() interfaces.Tx { + return &SqliteTx{ + tx: s.TX, + db: s.db, + dbName: s.dbName, + dir: s.dir, + writable: s.writable, + } +} + +func (s *SqliteBucket) Writable() bool { + return s.writable +} + +func (s *SqliteBucket) Get(key []byte) []byte { + query := fmt.Sprintf(genericGet, s.name) + r, err := s.TX.Query(query, string(key)) + defer r.Close() + if err != nil { + return nil + } + val := []byte{} + + for r.Next() { + var v []byte + if err := r.Scan(&v); err != nil { + // Check for a scan error. + // Query rows will be closed with defer. + log.Fatal(err) + } + val = append(val, v...) + } + return val +} + +func (s *SqliteBucket) Put(key []byte, value []byte) error { + query := fmt.Sprintf(genericUpsert, s.name) + _, err := s.TX.Exec(query, string(key), value) + return err +} + +func (s *SqliteBucket) UnsafeRange(key, endKey []byte, limit int64) (keys [][]byte, vs [][]byte) { + if endKey == nil || limit == 0 || limit == 1 { + query := fmt.Sprintf(genericGet, s.name) + r, err := s.TX.Query(query, string(key)) + defer r.Close() + if err != nil { + return + } + for r.Next() { + var val []byte + r.Scan(&val) + keys = append(keys, key) + vs = append(vs, val) + return + } + } + var query string + var r *sql.Rows + var err error + if endKey == nil { + query = fmt.Sprintf(genericUnsafeRangeQueryNoEnd, s.name) + r, err = s.TX.Query(query, string(key), limit) + } else { + query := fmt.Sprintf(genericUnsafeRangeQuery, s.name) + r, err = s.TX.Query(query, string(key), string(endKey), limit) + } + + if err != nil { + return nil, nil + } + defer r.Close() + names := make([][]byte, 0) + values := make([][]byte, 0) + for r.Next() { + var key string + var v []byte + if err := r.Scan(&key, &v); err != nil { + // Check for a scan error. + // Query rows will be closed with defer. + log.Fatal(err) + } + names = append(names, []byte(key)) + values = append(values, v) + } + return names, values +} + +func (s *SqliteBucket) Delete(key []byte) error { + query := fmt.Sprintf(genericDelete, s.name) + _, err := s.TX.Exec(query, string(key)) + return err +} + +func (s *SqliteBucket) ForEach(f func(k []byte, v []byte) error) error { + query := fmt.Sprintf(genericForEach, s.name) + r, err := s.TX.Query(query) + defer r.Close() + if err != nil { + return err + } + for r.Next() { + var key string + var v []byte + if err := r.Scan(&key, &v); err != nil { + return err + } + if err := f([]byte(key), v); err != nil { + return err + } + + } + return err +} + +func (s *SqliteBucket) Stats() interface{} { + return nil +} + +func (s *SqliteBucket) SetFillPercent(f float64) { + return +} diff --git a/server/databases/sqlite/sqlite_test.go b/server/databases/sqlite/sqlite_test.go new file mode 100644 index 00000000000..14bd99e937b --- /dev/null +++ b/server/databases/sqlite/sqlite_test.go @@ -0,0 +1,175 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package sqlite_test + +import ( + "bytes" + "strconv" + "testing" + + "go.etcd.io/etcd/server/v3/bucket" + "go.etcd.io/etcd/server/v3/databases/sqlite" +) + +func TestOpen(t *testing.T) { + _, err := sqlite.NewSqliteDB(t.TempDir()+"/db", bucket.Buckets...) + if err != nil { + t.Fatalf("expected no err, got %v", err) + } +} + +func TestBuckets(t *testing.T) { + db, err := sqlite.NewSqliteDB(t.TempDir()+"/db", bucket.Buckets...) + if err != nil { + t.Fatalf("expected no err, got %v", err) + } + // create a extra bucket + db.CreateBucket("foo") + tables := db.Buckets() + + if len(tables) != len(bucket.Buckets)+1 { + t.Errorf("got %v buckets, wanted %d", len(tables), len(bucket.Buckets)+1) + } +} + +func TestSize(t *testing.T) { + db, err := sqlite.NewSqliteDB(t.TempDir()+"/db", bucket.Buckets...) + if err != nil { + t.Fatalf("expected no err, got %v", err) + } + originalSize := db.Size() + for i := 0; i < 100; i++ { + if _, err := db.DB.Exec(sqlite.UpsertKV, "key-"+strconv.Itoa(i), make([]byte, 1000)); err != nil { + t.Fatalf("error inserting %s", strconv.Itoa(i)) + } + } + newSize := db.Size() + if originalSize == newSize { + t.Errorf("got %d size, but want original(%d)!=new(%d)", newSize, originalSize, newSize) + } +} + +func TestPutAndGetFromBucket(t *testing.T) { + db, err := sqlite.NewSqliteDB(t.TempDir()+"/db", bucket.Buckets...) + if err != nil { + t.Fatalf("expected no err, got %v", err) + } + + txn, err := db.Begin(true) + if err != nil { + t.Errorf("expected no err, got %v", err) + } + testBucket := []byte("test") + txn.CreateBucket(testBucket) + b := txn.Bucket(testBucket) + firstVal := []byte("firstval") + firstKey := []byte("firstkey") + b.Put(firstKey, firstVal) + txn.Commit() + txn2, err := db.Begin(true) + if err != nil { + t.Errorf("expected no err, got %v", err) + } + b2 := txn2.Bucket(testBucket) + v2 := b2.Get(firstKey) + + if err := b2.Tx().Commit(); err != nil { + t.Errorf("unexpected err %v", err) + } + if !bytes.Equal(firstVal, v2) { + t.Errorf("got %v, want %v", v2, firstVal) + } +} + +func TestUnsafeRange(t *testing.T) { + db, err := sqlite.NewSqliteDB(t.TempDir()+"/db", bucket.Buckets...) + if err != nil { + t.Fatalf("expected no err, got %v", err) + } + for i := 0; i < 1000; i++ { + if _, err := db.DB.Exec(sqlite.UpsertKV, "key-"+strconv.Itoa(i), make([]byte, 1000)); err != nil { + t.Fatalf("error inserting %s", strconv.Itoa(i)) + } + } + txn, err := db.Begin(true) + if err != nil { + t.Errorf("expected no err, got %v", err) + } + keys, _ := txn.Bucket([]byte("KVs")).UnsafeRange([]byte("key-1"), []byte("key-300"), 100) + if len(keys) != 100 { + t.Errorf("got %d keys, expected %d keys", len(keys), 100) + } +} + +func TestUnsafeRangeUncommitted(t *testing.T) { + db, err := sqlite.NewSqliteDB(t.TempDir()+"/db", bucket.Buckets...) + if err != nil { + t.Fatalf("expected no err, got %v", err) + } + txn, err := db.Begin(true) + if err != nil { + t.Errorf("expected no err, got %v", err) + } + bkt := txn.Bucket([]byte("KVs")) + for i := 0; i < 1000; i++ { + stringNum := strconv.Itoa(i) + if len(stringNum) == 1 { + stringNum = "00" + stringNum + } else if len(stringNum) == 2 { + stringNum = "0" + stringNum + } + if err := bkt.Put([]byte("key-"+stringNum), make([]byte, 1000)); err != nil { + t.Fatalf("error inserting %s", strconv.Itoa(i)) + } + } + if err != nil { + t.Errorf("expected no err, got %v", err) + } + keys, _ := bkt.UnsafeRange([]byte("key-0"), []byte("key-300"), 100) + if len(keys) != 100 { + t.Errorf("got %d keys, expected %d keys", len(keys), 100) + } + if string(keys[0]) != "key-000" { + t.Errorf("got %s, wanted %s", string(keys[0]), "key-000") + } + if string(keys[99]) != "key-099" { + t.Errorf("got %s, wanted %s", string(keys[0]), "key-099") + } +} + +func TestForEach(t *testing.T) { + db, err := sqlite.NewSqliteDB(t.TempDir()+"/db", bucket.Buckets...) + if err != nil { + t.Fatalf("expected no err, got %v", err) + } + + for i := 0; i < 1000; i++ { + if _, err := db.DB.Exec(sqlite.UpsertKV, "key-"+strconv.Itoa(i), "value-"+strconv.Itoa(i)); err != nil { + t.Fatalf("error inserting %s", strconv.Itoa(i)) + } + } + txn, err := db.Begin(true) + if err != nil { + t.Errorf("expected no err, got %v", err) + } + err = txn.Bucket([]byte("KVs")).ForEach(func(k []byte, v []byte) error { + return nil + }) + if err != nil { + t.Errorf("expected no err, got %v", err) + } +} diff --git a/server/embed/config.go b/server/embed/config.go index affdf6a4a7c..dce2f672587 100644 --- a/server/embed/config.go +++ b/server/embed/config.go @@ -109,6 +109,9 @@ const ( // DefaultBackendType defaults the backend to bolt DefaultBackendType = "bolt" + + // SqliteBackendType defaults the backend to sqlite + SqliteBackendType = "sqlite" ) var ( @@ -474,13 +477,10 @@ type securityConfig struct { } func NewSqliteConfig() *Config { - c := NewConfig() - c.ExperimentalBackendType = "sqlite" - return c + return NewGenericConfig(SqliteBackendType) } -// NewConfig creates a new Config populated with default values. -func NewConfig() *Config { +func NewGenericConfig(backendType string) *Config { lpurl, _ := url.Parse(DefaultListenPeerURLs) apurl, _ := url.Parse(DefaultInitialAdvertisePeerURLs) lcurl, _ := url.Parse(DefaultListenClientURLs) @@ -498,7 +498,7 @@ func NewConfig() *Config { MaxRequestBytes: DefaultMaxRequestBytes, MaxConcurrentStreams: DefaultMaxConcurrentStreams, ExperimentalWarningApplyDuration: DefaultWarningApplyDuration, - ExperimentalBackendType: DefaultBackendType, + ExperimentalBackendType: backendType, GRPCKeepAliveMinTime: DefaultGRPCKeepAliveMinTime, GRPCKeepAliveInterval: DefaultGRPCKeepAliveInterval, @@ -571,6 +571,11 @@ func NewConfig() *Config { return cfg } +// NewConfig creates a new Config populated with default values. +func NewConfig() *Config { + return NewGenericConfig(DefaultBackendType) +} + func ConfigFromFile(path string) (*Config, error) { cfg := &configYAML{Config: *NewConfig()} if err := cfg.configFromFile(path); err != nil { @@ -810,6 +815,9 @@ func (cfg *Config) Validate() error { return fmt.Errorf("distributed tracing configurition is not valid: (%v)", err) } } + if cfg.ExperimentalBackendType == "sqlite" { + cfg.logger.Warn("Detected sqlite as a backend.") + } if !cfg.ExperimentalEnableLeaseCheckpointPersist && cfg.ExperimentalEnableLeaseCheckpoint { cfg.logger.Warn("Detected that checkpointing is enabled without persistence. Consider enabling experimental-enable-lease-checkpoint-persist") diff --git a/server/embed/etcd.go b/server/embed/etcd.go index 7eeb6aa08e5..2ac782845d6 100644 --- a/server/embed/etcd.go +++ b/server/embed/etcd.go @@ -373,6 +373,7 @@ func print(lg *zap.Logger, ec Config, sc config.ServerConfig, memberInitialized zap.String("downgrade-check-interval", sc.DowngradeCheckTime.String()), zap.Int("max-learners", sc.ExperimentalMaxLearners), + zap.String("backend-type", sc.ExperimentalBackendType), ) } diff --git a/server/go.mod b/server/go.mod index cba5b151eb6..4ee4d8130cf 100644 --- a/server/go.mod +++ b/server/go.mod @@ -6,6 +6,7 @@ require ( github.com/coreos/go-semver v0.3.1 github.com/coreos/go-systemd/v22 v22.5.0 github.com/dustin/go-humanize v1.0.1 + github.com/glebarez/go-sqlite v1.21.2 github.com/gogo/protobuf v1.3.2 github.com/golang-jwt/jwt/v4 v4.5.0 github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da @@ -53,13 +54,16 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/uuid v1.3.0 // indirect github.com/gorilla/websocket v1.4.2 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/common v0.43.0 // indirect github.com/prometheus/procfs v0.10.1 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/sirupsen/logrus v1.8.1 // indirect github.com/spf13/pflag v1.0.5 // indirect go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.2 // indirect @@ -72,6 +76,10 @@ require ( golang.org/x/text v0.11.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + modernc.org/libc v1.22.5 // indirect + modernc.org/mathutil v1.5.0 // indirect + modernc.org/memory v1.5.0 // indirect + modernc.org/sqlite v1.23.1 // indirect sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect ) diff --git a/server/go.sum b/server/go.sum index 0adddd81028..add056052af 100644 --- a/server/go.sum +++ b/server/go.sum @@ -83,6 +83,8 @@ github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go. github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo= +github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -155,8 +157,11 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= @@ -187,6 +192,8 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -203,6 +210,9 @@ github.com/prometheus/common v0.43.0 h1:iq+BVjvYLei5f27wiuNiB1DN6DYQkp1c8Bx0Vykh github.com/prometheus/common v0.43.0/go.mod h1:NCvr5cQIh3Y/gy73/RdVtC9r8xxrxwJnB+2lB3BxrFc= github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= @@ -387,6 +397,7 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -559,6 +570,14 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE= +modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY= +modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds= +modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/sqlite v1.23.1 h1:nrSBg4aRQQwq59JpvGEQ15tNxoO5pX/kUjcRNwSAGQM= +modernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/server/storage/backend/backend.go b/server/storage/backend/backend.go index 8aad12192de..e72e8ec05b8 100644 --- a/server/storage/backend/backend.go +++ b/server/storage/backend/backend.go @@ -20,6 +20,8 @@ import ( "sync/atomic" "time" + "go.etcd.io/etcd/server/v3/databases/sqlite" + "go.etcd.io/etcd/server/v3/bucket" "go.etcd.io/etcd/server/v3/databases/bbolt" "go.etcd.io/etcd/server/v3/interfaces" @@ -177,8 +179,9 @@ func New(bcfg BackendConfig) Backend { if bcfg.BackendType == "" || bcfg.BackendType == "bolt" { return newBoltBackend(bcfg) } + println("Using sqlite") // todo(logicalhan) replace with sqlite - return newBoltBackend(bcfg) + return newSqliteBackend(bcfg) } func NewDefaultBackend(lg *zap.Logger, path string, backendType string) Backend { @@ -191,8 +194,56 @@ func NewDefaultBackend(lg *zap.Logger, path string, backendType string) Backend return newBoltBackend(bcfg) } else { // todo(logicalhan) replace with sqlite - return newBoltBackend(bcfg) + return newSqliteBackend(bcfg) + } +} + +func newSqliteBackend(bcfg BackendConfig) *backend { + + db, err := sqlite.NewSqliteDB(bcfg.Path, bucket.Buckets...) + if err != nil { + bcfg.Logger.Panic("failed to open database", zap.String("path", bcfg.Path), zap.Error(err)) } + + // In future, may want to make buffering optional for low-concurrency systems + // or dynamically swap between buffered/non-buffered depending on workload. + b := &backend{ + db: db, + + batchInterval: bcfg.BatchInterval, + batchLimit: bcfg.BatchLimit, + mlock: bcfg.Mlock, + backendType: bcfg.BackendType, + + readTx: &readTx{ + baseReadTx: baseReadTx{ + buf: txReadBuffer{ + txBuffer: txBuffer{make(map[bucket.BucketID]*bucketBuffer)}, + bufVersion: 0, + }, + buckets: make(map[bucket.BucketID]interfaces.Bucket), + txWg: new(sync.WaitGroup), + txMu: new(sync.RWMutex), + }, + }, + txReadBufferCache: txReadBufferCache{ + mu: sync.Mutex{}, + bufVersion: 0, + buf: nil, + }, + + stopc: make(chan struct{}), + donec: make(chan struct{}), + + lg: bcfg.Logger, + } + + b.batchTx = newBatchTxBuffered(b) + // We set it after newBatchTxBuffered to skip the 'empty' commit. + b.hooks = bcfg.Hooks + + go b.run() + return b } func newBoltBackend(bcfg BackendConfig) *backend { diff --git a/tests/go.mod b/tests/go.mod index aed29b9b773..d10f7786b2a 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -59,6 +59,7 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/fatih/color v1.15.0 // indirect + github.com/glebarez/go-sqlite v1.21.2 // indirect github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect @@ -66,6 +67,7 @@ require ( github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/btree v1.1.2 // indirect + github.com/google/uuid v1.3.0 // indirect github.com/gorilla/websocket v1.4.2 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect @@ -78,6 +80,7 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/procfs v0.10.1 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/sirupsen/logrus v1.8.1 // indirect github.com/spf13/cobra v1.7.0 // indirect @@ -99,6 +102,10 @@ require ( gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + modernc.org/libc v1.22.5 // indirect + modernc.org/mathutil v1.5.0 // indirect + modernc.org/memory v1.5.0 // indirect + modernc.org/sqlite v1.23.1 // indirect sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/tests/go.sum b/tests/go.sum index ec7fe98fcc6..c65b32c6c44 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -95,6 +95,8 @@ github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo= +github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -168,8 +170,11 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= @@ -226,6 +231,9 @@ github.com/prometheus/common v0.43.0 h1:iq+BVjvYLei5f27wiuNiB1DN6DYQkp1c8Bx0Vykh github.com/prometheus/common v0.43.0/go.mod h1:NCvr5cQIh3Y/gy73/RdVtC9r8xxrxwJnB+2lB3BxrFc= github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= @@ -590,6 +598,14 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE= +modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY= +modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds= +modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/sqlite v1.23.1 h1:nrSBg4aRQQwq59JpvGEQ15tNxoO5pX/kUjcRNwSAGQM= +modernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=