From fa1834871e30f21ebc862ec7c8eadc7cd14c897c Mon Sep 17 00:00:00 2001 From: lni Date: Tue, 14 Jun 2022 20:53:57 +0800 Subject: [PATCH] Initial commit of LogService and HAKeeper (#2970) * logservice: initial commit * logservice: added LogShardManager * logservice: renamed service.go -> shards.go * logservice: added hakeeper and tests * logservice: some cleanups * logservice: added stateMachine.LeaseHistory * logservice: added the ability to filter internal entries * logservice: fixed various issues in LogStore * logservice: updated store APIs to expose LogRecord and LSN * logservice: pass meta info to NodeHost * logservice: allow NodeHostID to be specified * logservice: added the ability to query serviceAddress * logservice: added the ability to query shard info * logservice: minor update * logservice: truncate log asynchronously in a worker goroutine * logservice: fixed copyright notice * logservice: added heartbeat message ready to be sent to HAKeeper * logservice: use gogofaster to generate .pb.go * logservice: minor update to reflect dragonboat v4 changes * logservice: added pb/rpc * logservice: added server side rpc support * logservice: bumped cube version to avoid pebble version conflicts * logservice: added error handling * logservice: more error handling * logservice: added some tests * logservice: minor fixess for errors.go * logservice: added DN heartbeat messages * logservice: minor cleanups * logservice: minor fix for error handling * logservice: moved hakeeper code to its own directory * logservice: made logservice rsm a IStateMachine * hakeeper: use Lookup() for querying shard ID * logservice: move pb file to matrixone/proto, some other cleanups * hakeeper: added hakeeper/state.go * logservice: added methods for updating hakeeper * hakeeper: minor fix, added some tests * logservice: added ticker for hakeeper replica * logservice: minor fix for service.go * logservice: fixed some issues in transport.go * logservice: added client.go * logservice: minor refactoring * logservice: added client_test.go, fixed a few bugs * logservice: readonly clients now reject write requests * logservice: refactored query shard info API * logservice: added tests for Servide.GetShardInfo * logservice: fixed a few static-check reported issues --- go.mod | 35 +- go.sum | 113 +- pkg/common/moerr/error.go | 7 + pkg/hakeeper/rsm.go | 243 +++ pkg/hakeeper/rsm_test.go | 211 ++ pkg/hakeeper/state.go | 138 ++ pkg/hakeeper/state_test.go | 168 ++ pkg/logservice/README.md | 3 + pkg/logservice/client.go | 199 ++ pkg/logservice/client_test.go | 159 ++ pkg/logservice/config.go | 99 + pkg/logservice/config_test.go | 92 + pkg/logservice/errors.go | 85 + pkg/logservice/errors_test.go | 46 + pkg/logservice/rsm.go | 233 ++ pkg/logservice/rsm_test.go | 246 +++ pkg/logservice/service.go | 270 +++ pkg/logservice/service_test.go | 372 ++++ pkg/logservice/shardinfo.go | 63 + pkg/logservice/store.go | 517 +++++ pkg/logservice/store_test.go | 286 +++ pkg/logservice/transport.go | 321 +++ pkg/logservice/transport_test.go | 263 +++ pkg/logservice/utils.go | 37 + pkg/pb/logservice/logservice.pb.go | 3278 ++++++++++++++++++++++++++++ pkg/pb/plan/plan.pb.go | 2 + proto/logservice.proto | 151 ++ 27 files changed, 7609 insertions(+), 28 deletions(-) create mode 100644 pkg/hakeeper/rsm.go create mode 100644 pkg/hakeeper/rsm_test.go create mode 100644 pkg/hakeeper/state.go create mode 100644 pkg/hakeeper/state_test.go create mode 100644 pkg/logservice/README.md create mode 100644 pkg/logservice/client.go create mode 100644 pkg/logservice/client_test.go create mode 100644 pkg/logservice/config.go create mode 100644 pkg/logservice/config_test.go create mode 100644 pkg/logservice/errors.go create mode 100644 pkg/logservice/errors_test.go create mode 100644 pkg/logservice/rsm.go create mode 100644 pkg/logservice/rsm_test.go create mode 100644 pkg/logservice/service.go create mode 100644 pkg/logservice/service_test.go create mode 100644 pkg/logservice/shardinfo.go create mode 100644 pkg/logservice/store.go create mode 100644 pkg/logservice/store_test.go create mode 100644 pkg/logservice/transport.go create mode 100644 pkg/logservice/transport_test.go create mode 100644 pkg/logservice/utils.go create mode 100644 pkg/pb/logservice/logservice.pb.go create mode 100644 proto/logservice.proto diff --git a/go.mod b/go.mod index 90edaef1fdb7e..4568fc5e7cf8f 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/axiomhq/hyperloglog v0.0.0-20220105174342-98591331716a github.com/bxcodec/faker/v3 v3.8.0 github.com/cespare/xxhash/v2 v2.1.2 - github.com/cockroachdb/pebble v0.0.0-20210526183633-dd2a545f5d75 + github.com/cockroachdb/pebble v0.0.0-20220407171941-2120d145e292 github.com/fagongzi/goetty v1.13.0 github.com/fagongzi/util v0.0.0-20210923134909-bccc37b5040d github.com/go-sql-driver/mysql v1.6.0 @@ -21,7 +21,9 @@ require ( github.com/golang/mock v1.6.0 github.com/google/btree v1.0.1 github.com/google/gofuzz v1.2.0 - github.com/matrixorigin/matrixcube v0.3.1-0.20220511071845-cfc4bac02bb4 + github.com/lni/dragonboat/v4 v4.0.0-20220604123758-e40bf3f57b59 + github.com/lni/goutils v1.3.1-0.20220604063047-388d67b4dbc4 + github.com/matrixorigin/matrixcube v0.3.1-0.20220606032431-c944d801f1e5 github.com/matrixorigin/simdcsv v0.0.0-20210926114300-591bf748a770 github.com/minio/minio-go/v7 v7.0.27 github.com/panjf2000/ants/v2 v2.4.6 @@ -39,6 +41,8 @@ require ( ) require ( + github.com/VictoriaMetrics/metrics v1.18.1 // indirect + github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.2 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.12 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.6 // indirect @@ -47,15 +51,27 @@ require ( github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.7 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.6 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.6 // indirect + github.com/getsentry/sentry-go v0.12.0 // indirect github.com/golang/protobuf v1.5.2 // indirect - github.com/google/uuid v1.1.2 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/hashicorp/go-immutable-radix v1.0.0 // indirect + github.com/hashicorp/go-msgpack v0.5.3 // indirect + github.com/hashicorp/go-multierror v1.0.0 // indirect + github.com/hashicorp/go-sockaddr v1.0.0 // indirect + github.com/hashicorp/golang-lru v0.5.1 // indirect + github.com/hashicorp/memberlist v0.3.1 // indirect github.com/klauspost/cpuid v1.3.1 // indirect - github.com/lni/goutils v1.3.0 // indirect + github.com/miekg/dns v1.1.26 // indirect github.com/minio/md5-simd v1.1.0 // indirect github.com/minio/sha256-simd v0.1.1 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/pierrec/lz4/v4 v4.1.14 // indirect github.com/rs/xid v1.2.1 // indirect + github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect github.com/smartystreets/assertions v1.2.0 // indirect + github.com/valyala/fastrand v1.1.0 // indirect + github.com/valyala/histogram v1.2.0 // indirect gopkg.in/ini.v1 v1.57.0 // indirect ) @@ -64,10 +80,9 @@ require ( github.com/DataDog/zstd v1.5.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.2.0 // indirect - github.com/cockroachdb/errors v1.8.2 // indirect - github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f // indirect - github.com/cockroachdb/redact v1.0.8 // indirect - github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 // indirect + github.com/cockroachdb/errors v1.9.0 + github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f // indirect + github.com/cockroachdb/redact v1.1.3 // indirect github.com/coreos/go-semver v0.3.0 // indirect github.com/coreos/go-systemd/v22 v22.3.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect @@ -86,12 +101,12 @@ require ( github.com/jonboulle/clockwork v0.2.2 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/jtolds/gls v4.20.0+incompatible // indirect - github.com/juju/ratelimit v1.0.1 // indirect + github.com/juju/ratelimit v1.0.2-0.20191002062651-f60b32039441 // indirect github.com/klauspost/compress v1.13.6 // indirect github.com/klauspost/cpuid/v2 v2.0.3 // indirect github.com/kr/pretty v0.3.0 // indirect github.com/kr/text v0.2.0 // indirect - github.com/lni/vfs v0.2.1-0.20210810090357-27c7525cf64f // indirect + github.com/lni/vfs v0.2.1-0.20220408085249-8be85be1c3c1 github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect diff --git a/go.sum b/go.sum index 3deecfabcef0b..f4a75cda944b3 100644 --- a/go.sum +++ b/go.sum @@ -52,7 +52,9 @@ github.com/BurntSushi/toml v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= +github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= +github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/DataDog/zstd v1.5.0 h1:+K/VEwIAaPcHiMtQvpLD4lqW7f0Gk3xdYZmI1hD+CXo= github.com/DataDog/zstd v1.5.0/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= @@ -65,6 +67,8 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE github.com/RoaringBitmap/roaring v0.9.4 h1:ckvZSX5gwCRaJYBNe7syNawCU5oruY9gQmjXlp4riwo= github.com/RoaringBitmap/roaring v0.9.4/go.mod h1:icnadbWcNyfEHlYdr+tDlOTih1Bf/h+rzPpv4sbomAA= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= +github.com/VictoriaMetrics/metrics v1.18.1 h1:OZ0+kTTto8oPfHnVAnTOoyl0XlRhRkoQrD2n2cOuRw0= +github.com/VictoriaMetrics/metrics v1.18.1/go.mod h1:ArjwVz7WpgpegX/JpB0zpNF2h2232kErkEnzH1sxMmA= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -74,6 +78,7 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5 github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aws/aws-sdk-go-v2 v1.16.5 h1:Ah9h1TZD9E2S1LzHpViBO3Jz9FPL5+rmflmb8hXirtI= @@ -139,23 +144,26 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= -github.com/cockroachdb/datadriven v1.0.0 h1:uhZrAfEayBecH2w2tZmhe20HJ7hDvrrA4x2Bg9YdZKM= github.com/cockroachdb/datadriven v1.0.0/go.mod h1:5Ib8Meh+jk1RlHIXej6Pzevx/NLlNvQB9pmSBZErGA4= +github.com/cockroachdb/datadriven v1.0.1-0.20211007161720-b558070c3be0/go.mod h1:5Ib8Meh+jk1RlHIXej6Pzevx/NLlNvQB9pmSBZErGA4= +github.com/cockroachdb/datadriven v1.0.1-0.20220214170620-9913f5bc19b7 h1:GCR5egmFNSTyGOv9IvMh636aELybEhZOlpPlW2NtuiU= +github.com/cockroachdb/datadriven v1.0.1-0.20220214170620-9913f5bc19b7/go.mod h1:hi0MtSY3AYDQNDi83kDkMH5/yqM/CsIrsOITkSoH7KI= github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= github.com/cockroachdb/errors v1.6.1/go.mod h1:tm6FTP5G81vwJ5lC0SizQo374JNCOPrHyXGitRJoDqM= github.com/cockroachdb/errors v1.7.5/go.mod h1:m/IWRCPXYZ6TvLLDuC0kfLR1pp/+BiZ0h16WHaBMRMM= github.com/cockroachdb/errors v1.8.1/go.mod h1:qGwQn6JmZ+oMjuLwjWzUNqblqk0xl4CVV3SQbGwK7Ac= -github.com/cockroachdb/errors v1.8.2 h1:rnnWK9Nn5kEMOGz9531HuDx/FOleL4NVH20VsDexVC8= -github.com/cockroachdb/errors v1.8.2/go.mod h1:qGwQn6JmZ+oMjuLwjWzUNqblqk0xl4CVV3SQbGwK7Ac= -github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY= +github.com/cockroachdb/errors v1.8.8/go.mod h1:z6VnEL3hZ/2ONZEvG7S5Ym0bU2AqPcEKnIiA1wbsSu0= +github.com/cockroachdb/errors v1.9.0 h1:B48dYem5SlAY7iU8AKsgedb4gH6mo+bDkbtLIvM/a88= +github.com/cockroachdb/errors v1.9.0/go.mod h1:vaNcEYYqbIqB5JhKBhFV9CneUqeuEbB2OYJBK4GBNYQ= github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= -github.com/cockroachdb/pebble v0.0.0-20210503173641-1387689d3d7c/go.mod h1:1XpB4cLQcF189RAcWi4gUc110zJgtOfT7SVNGY8sOe0= -github.com/cockroachdb/pebble v0.0.0-20210526183633-dd2a545f5d75 h1:rvbFUnq/+3udiF//O+UfPxh1MLXSW7UMH/ERJmNwvqk= -github.com/cockroachdb/pebble v0.0.0-20210526183633-dd2a545f5d75/go.mod h1:1XpB4cLQcF189RAcWi4gUc110zJgtOfT7SVNGY8sOe0= +github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f h1:6jduT9Hfc0njg5jJ1DdKCFPdMBrp/mdZfCpa5h+WM74= +github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= +github.com/cockroachdb/pebble v0.0.0-20220407171941-2120d145e292 h1:7fLxcRpQTdi1iic0cIUpK+hKKLM5XdPhEbWRRrxfvLU= +github.com/cockroachdb/pebble v0.0.0-20220407171941-2120d145e292/go.mod h1:buxOO9GBtOcq1DiXDpIPYrmxY020K2A8lOrwno5FetU= github.com/cockroachdb/redact v1.0.6/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= -github.com/cockroachdb/redact v1.0.8 h1:8QG/764wK+vmEYoOlfobpe12EQcS81ukx/a4hdVMxNw= github.com/cockroachdb/redact v1.0.8/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= -github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 h1:IKgmqgMQlVJIZj19CdocBeSfSaiCbEBZGKODaixqtHM= +github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= +github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= @@ -215,6 +223,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= +github.com/getsentry/sentry-go v0.12.0 h1:era7g0re5iY13bHSdN/xMkyV+5zZppjRVQhZrXCaEIk= +github.com/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TBdRL1M71JZW2c= github.com/ghemawat/stream v0.0.0-20171120220530-696b145b53b9/go.mod h1:106OIgooyS7OzLDOpUGgm9fA3bQENb/cFSyyBmMoJDs= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= @@ -242,6 +252,7 @@ github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6Wezm github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= @@ -249,6 +260,7 @@ github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -284,7 +296,6 @@ github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.2-0.20190904063534-ff6b7dc882cf/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -331,8 +342,9 @@ github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= 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/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= @@ -340,6 +352,7 @@ github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gosimple/slug v1.1.1/go.mod h1:ER78kgg1Mv0NQGlXiDe57DpCyfbNywXXZ9mIorhxAf0= @@ -354,27 +367,37 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4 github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/memberlist v0.3.1 h1:MXgUXLqva1QvpVEDQW1IQLG0wivQAtmFlHRQ+1vWZfM= +github.com/hashicorp/memberlist v0.3.1/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= 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/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= @@ -383,6 +406,8 @@ github.com/influxdata/influxdb v1.7.6/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOpr github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI= +github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= +github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g= github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= @@ -391,6 +416,7 @@ github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9q github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -401,22 +427,29 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= -github.com/juju/ratelimit v1.0.1 h1:+7AIFJVQ0EQgq/K9+0Krm7m530Du7tIz0METWzN0RgY= github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= +github.com/juju/ratelimit v1.0.2-0.20191002062651-f60b32039441 h1:b5Jqi7ir58EzfeZDyp7OSYQG/IVgyY4JWfHuJUF2AZI= +github.com/juju/ratelimit v1.0.2-0.20191002062651-f60b32039441/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk= +github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8= github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U= +github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE= github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw= +github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE= github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0= +github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro= +github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= @@ -437,34 +470,45 @@ 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/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= +github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= -github.com/lni/goutils v1.3.0 h1:oBhV7Z5DjNWbcy/c3fFj6qo4SnHcpyTY28qfKvLy6UM= +github.com/lni/dragonboat/v4 v4.0.0-20220604123758-e40bf3f57b59 h1:QQnr5/JOG9upSf0WXP6LVg18vBlbycJbY5egnpyWcKQ= +github.com/lni/dragonboat/v4 v4.0.0-20220604123758-e40bf3f57b59/go.mod h1:5dd7hX8qUJ+72UVKdZZIBw5UbhZTaGY5PIt/TTdIeSY= github.com/lni/goutils v1.3.0/go.mod h1:PUPtBAnZlRPUKWUXCsYkIRWubJbtNHpTAee0sczhlf4= -github.com/lni/vfs v0.2.1-0.20210810090357-27c7525cf64f h1:ykmePP2E9ZuNRhfZL2bqjMdoYitgzYvIdVogbvnlvhs= -github.com/lni/vfs v0.2.1-0.20210810090357-27c7525cf64f/go.mod h1:Z98QaAJnPYmgpw5VsksNdEPKpHDp4yeHTTvfHbX5JWE= +github.com/lni/goutils v1.3.1-0.20220604063047-388d67b4dbc4 h1:6gzI38ZJmbzZ7oZebXz6jII0uVK+MZ3+ds+7mIt1ioI= +github.com/lni/goutils v1.3.1-0.20220604063047-388d67b4dbc4/go.mod h1:LIHvF0fflR+zyXUQFQOiHPpKANf3UIr7DFIv5CBPOoU= +github.com/lni/vfs v0.2.1-0.20220408085249-8be85be1c3c1 h1:350K9Ph9R+ExT49poOnsNa8Ev3yb0YZgODfeBsLATHc= +github.com/lni/vfs v0.2.1-0.20220408085249-8be85be1c3c1/go.mod h1:LOatfyR8Xeej1jbXybwYGVfCccR0u+BQRG9xg7BD7xo= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/matrixorigin/etcd/raft/v3 v3.5.1-0.20210824022435-0203115049c2 h1:s7CQEsRxL8+/sAPW23uIqpwR+M8Aje81AH6w3/ZkxQw= github.com/matrixorigin/etcd/raft/v3 v3.5.1-0.20210824022435-0203115049c2/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= -github.com/matrixorigin/matrixcube v0.3.1-0.20220511071845-cfc4bac02bb4 h1:dRHX6Z7DzZ2nNaunhXWVAnKIxWOhpDmVUvsGnHiNxn0= -github.com/matrixorigin/matrixcube v0.3.1-0.20220511071845-cfc4bac02bb4/go.mod h1:la08nf8VKIcYmAH/uc/stLiOLzwUJUXluFpaAbfIq+A= +github.com/matrixorigin/matrixcube v0.3.1-0.20220606032431-c944d801f1e5 h1:b+9G1IWfgxbccwkw3OgF6jLC1hq+3zwX1Mv8vIh7JuM= +github.com/matrixorigin/matrixcube v0.3.1-0.20220606032431-c944d801f1e5/go.mod h1:DVpm2zTKCao8/xafx3VASK6AVrFnMF8EDGEXXF/SBC0= github.com/matrixorigin/simdcsv v0.0.0-20210926114300-591bf748a770 h1:apc228jeCtUvvfkaydzJygk1jdH8y+THma2o73Yv4Vg= github.com/matrixorigin/simdcsv v0.0.0-20210926114300-591bf748a770/go.mod h1:A7O+LRuZcr/BbOLsMzM/q69ZmoLENUMpptYG0pPzTFQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg= github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ= +github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.26 h1:gPxPSwALAeHJSjarOs00QjVdV9QoBvc1D2ujQUr5BzU= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/minio/md5-simd v1.1.0 h1:QPfiOqlZH+Cj9teu0t9b1nTBfPbyTl16Of5MeuShdK4= github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw= github.com/minio/minio-go/v7 v7.0.27 h1:yJCvm78B+2+ll1PqO9eSD1as6Ibw3IYnnD8PyBEB2zo= @@ -494,14 +538,18 @@ github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM= github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= @@ -509,12 +557,15 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/panjf2000/ants/v2 v2.4.6 h1:drmj9mcygn2gawZ155dRbo+NfXEfAssjZNU1qoIb4gQ= github.com/panjf2000/ants/v2 v2.4.6/go.mod h1:f6F0NZVFsGCp5A7QW/Zj/m92atWwOkY0OIhFxRNFr4A= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/phf/go-queue v0.0.0-20170504031614-9abe38d0371d h1:U+PMnTlV2tu7RuMK5etusZG3Cf+rpow5hqQByeCzJ2g= github.com/phf/go-queue v0.0.0-20170504031614-9abe38d0371d/go.mod h1:lXfE4PvvTW5xOjO6Mba8zDPyw8M93B6AQ7frTGnMlA8= github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE= +github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pingcap/check v0.0.0-20190102082844-67f458068fc8/go.mod h1:B1+S9LNcuMyLH/4HMTViQOJevkGiik3wW2AN9zb2fNQ= github.com/pingcap/errors v0.11.0/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= @@ -572,8 +623,11 @@ github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shirou/gopsutil/v3 v3.22.3 h1:UebRzEomgMpv61e3hgD1tGooqX5trFbdU/ehphbHd00= github.com/shirou/gopsutil/v3 v3.22.3/go.mod h1:D01hZJ4pVHPpCTZ3m3T2+wDF2YAGfd+H4ifUguaQzHM= @@ -624,11 +678,18 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1 github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 h1:uruHq4dN7GR16kFc5fp3d1RIYzJW5onx8Ybykw2YQFA= github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= 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.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= +github.com/valyala/fastrand v1.1.0 h1:f+5HkLW4rsgzdNoleUOB69hyT9IlD2ZQh9GyDMfb5G8= +github.com/valyala/fastrand v1.1.0/go.mod h1:HWqCzkrkg6QXT8V2EXWvXCoow7vLwOFN002oeRzjapQ= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= +github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/valyala/histogram v1.2.0 h1:wyYGAZZt3CpwUiIb9AU/Zbllg1llXyrtApRS815OLoQ= +github.com/valyala/histogram v1.2.0/go.mod h1:Hb4kBwb4UxsaNbbbh+RRz8ZR6pdodR57tzWUS3BUzXY= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= @@ -726,9 +787,13 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220214200702-86341886e292 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -789,6 +854,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -814,6 +880,7 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM= golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -867,6 +934,8 @@ golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -875,6 +944,7 @@ golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -910,12 +980,15 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210909193231-528a39cd75f3/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -935,6 +1008,7 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M= golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -956,6 +1030,7 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1158,6 +1233,7 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.57.0 h1:9unxIsFcTt4I55uWluz+UmL95q4kdJ0buvQ1ZIqVQww= gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= @@ -1176,6 +1252,7 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pkg/common/moerr/error.go b/pkg/common/moerr/error.go index 08ed9f0184b28..53d649c15907e 100644 --- a/pkg/common/moerr/error.go +++ b/pkg/common/moerr/error.go @@ -34,6 +34,13 @@ const ( // Group 2: numeric DIVIVISION_BY_ZERO = 2000 + iota OUT_OF_RANGE + + // Group 3: invalid input + BAD_CONFIGURATION = 3000 + iota + INVALID_INPUT + + // Group 4: unexpected state + INVALID_STATE = 4000 + iota ) type Error struct { diff --git a/pkg/hakeeper/rsm.go b/pkg/hakeeper/rsm.go new file mode 100644 index 0000000000000..5ae0a3843d929 --- /dev/null +++ b/pkg/hakeeper/rsm.go @@ -0,0 +1,243 @@ +// Copyright 2021 - 2022 Matrix Origin +// +// 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 hakeeper + +import ( + "encoding/binary" + "encoding/gob" + "io" + "time" + + "github.com/lni/dragonboat/v4/logger" + sm "github.com/lni/dragonboat/v4/statemachine" + + "github.com/matrixorigin/matrixone/pkg/common/moerr" + "github.com/matrixorigin/matrixone/pkg/pb/logservice" +) + +var ( + plog = logger.GetLogger("hakeeper") +) + +var ( + binaryEnc = binary.BigEndian +) + +const ( + // TickDuration defines the frequency of ticks. + TickDuration = time.Second + // DefaultHAKeeperShardID is the shard ID assigned to the special HAKeeper + // shard. + DefaultHAKeeperShardID uint64 = 0 + + headerSize = 2 +) + +const ( + createLogShardTag uint16 = iota + 0xAE01 + tickTag + dnHeartbeatTag + logHeartbeatTag +) + +type logShardIDQuery struct { + name string +} + +type logShardIDQueryResult struct { + id uint64 + found bool +} + +type stateMachine struct { + replicaID uint64 + + Tick uint64 + NextID uint64 + + LogShards map[string]uint64 + DNState DNState + LogState LogState +} + +func parseCmdTag(cmd []byte) uint16 { + return binaryEnc.Uint16(cmd) +} + +func getCreateLogShardCmd(name string) []byte { + return getLogShardCmd(name, createLogShardTag) +} + +func getLogShardCmd(name string, tag uint16) []byte { + cmd := make([]byte, headerSize+len(name)) + binaryEnc.PutUint16(cmd, tag) + copy(cmd[headerSize:], []byte(name)) + return cmd +} + +func isCreateLogShardCmd(cmd []byte) (string, bool) { + return isLogShardCmd(cmd, createLogShardTag) +} + +func isDNHeartbeatCmd(cmd []byte) bool { + return isHeartbeatCmd(cmd, dnHeartbeatTag) +} + +func isLogHeartbeatCmd(cmd []byte) bool { + return isHeartbeatCmd(cmd, logHeartbeatTag) +} + +func isHeartbeatCmd(cmd []byte, tag uint16) bool { + if len(cmd) <= headerSize { + return false + } + return parseCmdTag(cmd) == tag +} + +func parseHeartbeatCmd(cmd []byte) []byte { + return cmd[headerSize:] +} + +func isLogShardCmd(cmd []byte, tag uint16) (string, bool) { + if len(cmd) <= headerSize { + return "", false + } + if parseCmdTag(cmd) == tag { + return string(cmd[headerSize:]), true + } + return "", false +} + +func isTickCmd(cmd []byte) bool { + return len(cmd) == headerSize && binaryEnc.Uint16(cmd) == tickTag +} + +func GetTickCmd() []byte { + cmd := make([]byte, headerSize) + binaryEnc.PutUint16(cmd, tickTag) + return cmd +} + +func GetLogStoreHeartbeatCmd(data []byte) []byte { + return getHeartbeatCmd(data, logHeartbeatTag) +} + +func GetDNStoreHeartbeatCmd(data []byte) []byte { + return getHeartbeatCmd(data, dnHeartbeatTag) +} + +func getHeartbeatCmd(data []byte, tag uint16) []byte { + cmd := make([]byte, headerSize+len(data)) + binaryEnc.PutUint16(cmd, tag) + copy(cmd[headerSize:], data) + return cmd +} + +func NewStateMachine(shardID uint64, replicaID uint64) sm.IStateMachine { + if shardID != DefaultHAKeeperShardID { + panic(moerr.NewError(moerr.INVALID_INPUT, "invalid HAKeeper shard ID")) + } + return &stateMachine{ + replicaID: replicaID, + LogShards: make(map[string]uint64), + DNState: NewDNState(), + LogState: NewLogState(), + } +} + +func (s *stateMachine) Close() error { + return nil +} + +func (s *stateMachine) assignID() uint64 { + s.NextID++ + return s.NextID +} + +func (s *stateMachine) handleCreateLogShardCmd(cmd []byte) (sm.Result, error) { + name, ok := isCreateLogShardCmd(cmd) + if !ok { + panic(moerr.NewError(moerr.INVALID_INPUT, "not create log shard cmd")) + } + if shardID, ok := s.LogShards[name]; ok { + data := make([]byte, 8) + binaryEnc.PutUint64(data, shardID) + return sm.Result{Value: 0, Data: data}, nil + } + s.LogShards[name] = s.assignID() + return sm.Result{Value: s.NextID}, nil +} + +func (s *stateMachine) handleDNHeartbeat(cmd []byte) (sm.Result, error) { + data := parseHeartbeatCmd(cmd) + var hb logservice.DNStoreHeartbeat + if err := hb.Unmarshal(data); err != nil { + panic(err) + } + s.DNState.Update(hb, s.Tick) + return sm.Result{}, nil +} + +func (s *stateMachine) handleLogHeartbeat(cmd []byte) (sm.Result, error) { + data := parseHeartbeatCmd(cmd) + var hb logservice.LogStoreHeartbeat + if err := hb.Unmarshal(data); err != nil { + panic(err) + } + s.LogState.Update(hb, s.Tick) + return sm.Result{}, nil +} + +func (s *stateMachine) handleTick(cmd []byte) (sm.Result, error) { + s.Tick++ + return sm.Result{}, nil +} + +func (s *stateMachine) Update(e sm.Entry) (sm.Result, error) { + cmd := e.Cmd + if _, ok := isCreateLogShardCmd(cmd); ok { + return s.handleCreateLogShardCmd(cmd) + } else if isDNHeartbeatCmd(cmd) { + return s.handleDNHeartbeat(cmd) + } else if isLogHeartbeatCmd(cmd) { + return s.handleLogHeartbeat(cmd) + } else if isTickCmd(cmd) { + return s.handleTick(cmd) + } + panic(moerr.NewError(moerr.INVALID_INPUT, "unexpected haKeeper cmd")) +} + +func (s *stateMachine) Lookup(query interface{}) (interface{}, error) { + if q, ok := query.(*logShardIDQuery); ok { + id, ok := s.LogShards[q.name] + if ok { + return &logShardIDQueryResult{found: true, id: id}, nil + } + return &logShardIDQueryResult{found: false}, nil + } + panic("unknown query type") +} + +func (s *stateMachine) SaveSnapshot(w io.Writer, + _ sm.ISnapshotFileCollection, _ <-chan struct{}) error { + enc := gob.NewEncoder(w) + return enc.Encode(s) +} + +func (s *stateMachine) RecoverFromSnapshot(r io.Reader, + _ []sm.SnapshotFile, _ <-chan struct{}) error { + dec := gob.NewDecoder(r) + return dec.Decode(s) +} diff --git a/pkg/hakeeper/rsm_test.go b/pkg/hakeeper/rsm_test.go new file mode 100644 index 0000000000000..1b2b64e3260b5 --- /dev/null +++ b/pkg/hakeeper/rsm_test.go @@ -0,0 +1,211 @@ +// Copyright 2021 - 2022 Matrix Origin +// +// 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 hakeeper + +import ( + "bytes" + "testing" + + sm "github.com/lni/dragonboat/v4/statemachine" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/matrixorigin/matrixone/pkg/pb/logservice" +) + +func TestAssignID(t *testing.T) { + tsm := NewStateMachine(0, 1).(*stateMachine) + assert.Equal(t, uint64(0), tsm.NextID) + assert.Equal(t, uint64(1), tsm.assignID()) + assert.Equal(t, uint64(1), tsm.NextID) +} + +func TestCreateLogShardCmd(t *testing.T) { + cmd := getCreateLogShardCmd("test") + name, ok := isCreateLogShardCmd(cmd) + assert.True(t, ok) + assert.Equal(t, "test", name) +} + +func TestHAKeeperStateMachineCanBeCreated(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Fatalf("failed to panic") + } + }() + tsm := NewStateMachine(0, 1).(*stateMachine) + assert.Equal(t, uint64(1), tsm.replicaID) + NewStateMachine(1, 1) +} + +func TestHAKeeperStateMachineSnapshot(t *testing.T) { + tsm1 := NewStateMachine(0, 1).(*stateMachine) + tsm2 := NewStateMachine(0, 2).(*stateMachine) + tsm1.NextID = 12345 + tsm1.LogShards["test1"] = 23456 + tsm1.LogShards["test2"] = 34567 + + buf := bytes.NewBuffer(nil) + assert.Nil(t, tsm1.SaveSnapshot(buf, nil, nil)) + assert.Nil(t, tsm2.RecoverFromSnapshot(buf, nil, nil)) + assert.Equal(t, tsm1.NextID, tsm2.NextID) + assert.Equal(t, tsm1.LogShards, tsm2.LogShards) + assert.True(t, tsm1.replicaID != tsm2.replicaID) +} + +func TestHAKeeperLogShardCanBeCreated(t *testing.T) { + cmd := getCreateLogShardCmd("test1") + tsm1 := NewStateMachine(0, 1).(*stateMachine) + tsm1.NextID = 100 + + result, err := tsm1.Update(sm.Entry{Cmd: cmd}) + assert.Nil(t, err) + assert.Equal(t, sm.Result{Value: 101}, result) + assert.Equal(t, uint64(101), tsm1.NextID) + + tsm1.NextID = 200 + result, err = tsm1.Update(sm.Entry{Cmd: cmd}) + assert.Nil(t, err) + data := make([]byte, 8) + binaryEnc.PutUint64(data, 101) + assert.Equal(t, sm.Result{Data: data}, result) +} + +func TestHAKeeperQueryLogShardID(t *testing.T) { + cmd := getCreateLogShardCmd("test1") + tsm1 := NewStateMachine(0, 1).(*stateMachine) + tsm1.NextID = 100 + result, err := tsm1.Update(sm.Entry{Cmd: cmd}) + assert.Nil(t, err) + assert.Equal(t, sm.Result{Value: 101}, result) + + q1 := &logShardIDQuery{name: "test1"} + r, err := tsm1.Lookup(q1) + assert.NoError(t, err) + r1, ok := r.(*logShardIDQueryResult) + assert.True(t, ok) + assert.True(t, r1.found) + assert.Equal(t, uint64(101), r1.id) + + q2 := &logShardIDQuery{name: "test2"} + r, err = tsm1.Lookup(q2) + assert.NoError(t, err) + r2, ok := r.(*logShardIDQueryResult) + assert.True(t, ok) + assert.False(t, r2.found) +} + +func TestHAKeeperCanBeClosed(t *testing.T) { + tsm1 := NewStateMachine(0, 1).(*stateMachine) + assert.Nil(t, tsm1.Close()) +} + +func TestHAKeeperTick(t *testing.T) { + tsm1 := NewStateMachine(0, 1).(*stateMachine) + assert.Equal(t, uint64(0), tsm1.Tick) + cmd := GetTickCmd() + _, err := tsm1.Update(sm.Entry{Cmd: cmd}) + assert.NoError(t, err) + _, err = tsm1.Update(sm.Entry{Cmd: cmd}) + assert.NoError(t, err) + assert.Equal(t, uint64(2), tsm1.Tick) +} + +func TestHandleLogHeartbeat(t *testing.T) { + tsm1 := NewStateMachine(0, 1).(*stateMachine) + cmd := GetTickCmd() + _, err := tsm1.Update(sm.Entry{Cmd: cmd}) + assert.NoError(t, err) + _, err = tsm1.Update(sm.Entry{Cmd: cmd}) + assert.NoError(t, err) + _, err = tsm1.Update(sm.Entry{Cmd: cmd}) + assert.NoError(t, err) + + hb := logservice.LogStoreHeartbeat{ + UUID: "uuid1", + RaftAddress: "localhost:9090", + ServiceAddress: "localhost:9091", + GossipAddress: "localhost:9092", + Shards: []logservice.LogShardInfo{ + { + ShardID: 100, + Replicas: map[uint64]string{ + 200: "localhost:8000", + 300: "localhost:9000", + }, + Epoch: 200, + LeaderID: 200, + Term: 10, + }, + { + ShardID: 101, + Replicas: map[uint64]string{ + 201: "localhost:8000", + 301: "localhost:9000", + }, + Epoch: 202, + LeaderID: 201, + Term: 30, + }, + }, + } + data, err := hb.Marshal() + require.NoError(t, err) + cmd = GetLogStoreHeartbeatCmd(data) + _, err = tsm1.Update(sm.Entry{Cmd: cmd}) + assert.NoError(t, err) + s := tsm1.LogState + assert.Equal(t, 1, len(s.Stores)) + lsinfo, ok := s.Stores[hb.UUID] + require.True(t, ok) + assert.Equal(t, uint64(3), lsinfo.Tick) + assert.Equal(t, hb.RaftAddress, lsinfo.RaftAddress) + assert.Equal(t, hb.ServiceAddress, lsinfo.ServiceAddress) + assert.Equal(t, hb.GossipAddress, lsinfo.GossipAddress) + assert.Equal(t, 2, len(lsinfo.Shards)) + assert.Equal(t, hb.Shards, lsinfo.Shards) +} + +func TestHandleDNHeartbeat(t *testing.T) { + tsm1 := NewStateMachine(0, 1).(*stateMachine) + cmd := GetTickCmd() + _, err := tsm1.Update(sm.Entry{Cmd: cmd}) + assert.NoError(t, err) + _, err = tsm1.Update(sm.Entry{Cmd: cmd}) + assert.NoError(t, err) + _, err = tsm1.Update(sm.Entry{Cmd: cmd}) + assert.NoError(t, err) + + hb := logservice.DNStoreHeartbeat{ + UUID: "uuid1", + Shards: []logservice.DNShardInfo{ + {ShardID: 1, ReplicaID: 1}, + {ShardID: 2, ReplicaID: 1}, + {ShardID: 3, ReplicaID: 1}, + }, + } + data, err := hb.Marshal() + require.NoError(t, err) + cmd = GetDNStoreHeartbeatCmd(data) + _, err = tsm1.Update(sm.Entry{Cmd: cmd}) + assert.NoError(t, err) + s := tsm1.DNState + assert.Equal(t, 1, len(s.Stores)) + dninfo, ok := s.Stores[hb.UUID] + assert.True(t, ok) + assert.Equal(t, uint64(3), dninfo.Tick) + require.Equal(t, 3, len(dninfo.Shards)) + assert.Equal(t, hb.Shards, dninfo.Shards) +} diff --git a/pkg/hakeeper/state.go b/pkg/hakeeper/state.go new file mode 100644 index 0000000000000..f7bcccb20ef9a --- /dev/null +++ b/pkg/hakeeper/state.go @@ -0,0 +1,138 @@ +// Copyright 2021 - 2022 Matrix Origin +// +// 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 hakeeper + +import ( + "reflect" + + "github.com/matrixorigin/matrixone/pkg/pb/logservice" +) + +// FIXME: dragonboat should have a public value indicating what is NoLeader node id +const ( + // NoLeader is the replica ID of the leader node. + NoLeader uint64 = 0 +) + +// DNShardInfo contins information on a list of shards. +type DNShardInfo struct { + Tick uint64 + Shards []logservice.DNShardInfo +} + +// DNState contains all DN details known to the HAKeeper. +type DNState struct { + // Stores is keyed by DN store UUID, it contains details found on each DN + // store. + Stores map[string]DNShardInfo +} + +// NewDNState creates a new DNState. +func NewDNState() DNState { + return DNState{ + Stores: make(map[string]DNShardInfo), + } +} + +// Update applies the incoming DNStoreHeartbeat into HAKeeper. Tick is the +// current tick of the HAKeeper which can be used as the timestamp of the +// heartbeat. +func (s *DNState) Update(hb logservice.DNStoreHeartbeat, tick uint64) { + shardInfo, ok := s.Stores[hb.UUID] + if !ok { + shardInfo = DNShardInfo{} + } + shardInfo.Tick = tick + shardInfo.Shards = hb.Shards + s.Stores[hb.UUID] = shardInfo +} + +// LogShardInfo contains information of all replicas found on a Log store. +type LogShardInfo struct { + Tick uint64 + RaftAddress string + ServiceAddress string + GossipAddress string + Shards []logservice.LogShardInfo +} + +type LogState struct { + // Shards is keyed by ShardID, it contains details aggregated from all Log + // stores. Each logservice.LogShardInfo here contains data aggregated from + // different replicas and thus reflect a more accurate description on each + // shard. + Shards map[uint64]logservice.LogShardInfo + // Stores is keyed by log store UUID, it contains details found on each store. + // Each LogShardInfo here reflects what was last reported by each Log store. + Stores map[string]LogShardInfo +} + +// NewLogState creates a new LogState. +func NewLogState() LogState { + return LogState{ + Shards: make(map[uint64]logservice.LogShardInfo), + Stores: make(map[string]LogShardInfo), + } +} + +// Update applies the incoming heartbeat message to the LogState with the +// specified tick used as the timestamp. +func (s *LogState) Update(hb logservice.LogStoreHeartbeat, tick uint64) { + s.updateStores(hb, tick) + s.updateShards(hb) +} + +func (s *LogState) updateStores(hb logservice.LogStoreHeartbeat, tick uint64) { + shardInfo, ok := s.Stores[hb.UUID] + if !ok { + shardInfo = LogShardInfo{} + } + shardInfo.Tick = tick + shardInfo.RaftAddress = hb.RaftAddress + shardInfo.ServiceAddress = hb.ServiceAddress + shardInfo.GossipAddress = hb.GossipAddress + shardInfo.Shards = hb.Shards + s.Stores[hb.UUID] = shardInfo +} + +func (s *LogState) updateShards(hb logservice.LogStoreHeartbeat) { + for _, incoming := range hb.Shards { + recorded, ok := s.Shards[incoming.ShardID] + if !ok { + recorded = logservice.LogShardInfo{ + ShardID: incoming.ShardID, + Replicas: make(map[uint64]string), + } + } + + if incoming.Epoch > recorded.Epoch { + recorded.Epoch = incoming.Epoch + recorded.Replicas = incoming.Replicas + } else if incoming.Epoch == recorded.Epoch && incoming.Epoch > 0 { + if !reflect.DeepEqual(recorded.Replicas, incoming.Replicas) { + plog.Panicf("inconsistent replicas, %+v, %+v, nil: %t, nil: %t", + recorded.Replicas, incoming.Replicas, + recorded.Replicas == nil, incoming.Replicas == nil) + } + } + + if incoming.Term > recorded.Term && incoming.LeaderID != NoLeader { + recorded.Term = incoming.Term + recorded.LeaderID = incoming.LeaderID + } + + s.Shards[incoming.ShardID] = recorded + } +} diff --git a/pkg/hakeeper/state_test.go b/pkg/hakeeper/state_test.go new file mode 100644 index 0000000000000..7a0a9b1a30803 --- /dev/null +++ b/pkg/hakeeper/state_test.go @@ -0,0 +1,168 @@ +// Copyright 2021 - 2022 Matrix Origin +// +// 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 hakeeper + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/matrixorigin/matrixone/pkg/pb/logservice" +) + +func TestDNStateUpdate(t *testing.T) { + s := NewDNState() + hb := logservice.DNStoreHeartbeat{ + UUID: "uuid1", + Shards: []logservice.DNShardInfo{ + {ShardID: 1, ReplicaID: 1}, + {ShardID: 2, ReplicaID: 1}, + {ShardID: 3, ReplicaID: 1}, + }, + } + s.Update(hb, 1) + assert.Equal(t, 1, len(s.Stores)) + dninfo, ok := s.Stores[hb.UUID] + assert.True(t, ok) + assert.Equal(t, uint64(1), dninfo.Tick) + require.Equal(t, 3, len(dninfo.Shards)) + assert.Equal(t, hb.Shards, dninfo.Shards) + + hb = logservice.DNStoreHeartbeat{ + UUID: "uuid2", + Shards: []logservice.DNShardInfo{ + {ShardID: 100, ReplicaID: 1}, + }, + } + s.Update(hb, 2) + + hb = logservice.DNStoreHeartbeat{ + UUID: "uuid1", + Shards: []logservice.DNShardInfo{ + {ShardID: 1, ReplicaID: 1}, + {ShardID: 3, ReplicaID: 1}, + {ShardID: 4, ReplicaID: 1}, + {ShardID: 100, ReplicaID: 1}, + }, + } + s.Update(hb, 2) + assert.Equal(t, 2, len(s.Stores)) + dninfo, ok = s.Stores[hb.UUID] + assert.True(t, ok) + assert.Equal(t, uint64(2), dninfo.Tick) + require.Equal(t, 4, len(dninfo.Shards)) + assert.Equal(t, hb.Shards, dninfo.Shards) +} + +func TestUpdateLogStateStore(t *testing.T) { + s := NewLogState() + hb := logservice.LogStoreHeartbeat{ + UUID: "uuid1", + RaftAddress: "localhost:9090", + ServiceAddress: "localhost:9091", + GossipAddress: "localhost:9092", + Shards: []logservice.LogShardInfo{ + { + ShardID: 100, + Replicas: map[uint64]string{ + 200: "localhost:8000", + 300: "localhost:9000", + }, + Epoch: 200, + LeaderID: 200, + Term: 10, + }, + { + ShardID: 101, + Replicas: map[uint64]string{ + 201: "localhost:8000", + 301: "localhost:9000", + }, + Epoch: 202, + LeaderID: 201, + Term: 30, + }, + }, + } + s.Update(hb, 3) + + assert.Equal(t, 1, len(s.Stores)) + lsinfo, ok := s.Stores[hb.UUID] + require.True(t, ok) + assert.Equal(t, uint64(3), lsinfo.Tick) + assert.Equal(t, hb.RaftAddress, lsinfo.RaftAddress) + assert.Equal(t, hb.ServiceAddress, lsinfo.ServiceAddress) + assert.Equal(t, hb.GossipAddress, lsinfo.GossipAddress) + assert.Equal(t, 2, len(lsinfo.Shards)) + assert.Equal(t, hb.Shards, lsinfo.Shards) + + require.Equal(t, 2, len(s.Shards)) + shard1, ok := s.Shards[100] + assert.True(t, ok) + assert.Equal(t, hb.Shards[0], shard1) + shard2, ok := s.Shards[101] + assert.True(t, ok) + assert.Equal(t, hb.Shards[1], shard2) + + hb2 := logservice.LogStoreHeartbeat{ + UUID: "uuid1", + RaftAddress: "localhost:9090", + ServiceAddress: "localhost:9091", + GossipAddress: "localhost:9092", + Shards: []logservice.LogShardInfo{ + { + ShardID: 100, + Replicas: map[uint64]string{ + 200: "localhost:8000", + 300: "localhost:9000", + 400: "localhost:10000", + }, + Epoch: 201, + LeaderID: 400, + Term: 20, + }, + { + ShardID: 101, + Replicas: map[uint64]string{ + 201: "localhost:8000", + }, + Epoch: 200, + LeaderID: NoLeader, + Term: 100, + }, + }, + } + s.Update(hb2, 4) + + assert.Equal(t, 1, len(s.Stores)) + lsinfo, ok = s.Stores[hb.UUID] + require.True(t, ok) + assert.Equal(t, uint64(4), lsinfo.Tick) + assert.Equal(t, hb2.RaftAddress, lsinfo.RaftAddress) + assert.Equal(t, hb2.ServiceAddress, lsinfo.ServiceAddress) + assert.Equal(t, hb2.GossipAddress, lsinfo.GossipAddress) + assert.Equal(t, 2, len(lsinfo.Shards)) + assert.Equal(t, hb2.Shards, lsinfo.Shards) + + require.Equal(t, 2, len(s.Shards)) + shard1, ok = s.Shards[100] + assert.True(t, ok) + assert.Equal(t, hb2.Shards[0], shard1) + shard2, ok = s.Shards[101] + assert.True(t, ok) + // shard2 didn't change to hb2.Shard[1] + assert.Equal(t, hb.Shards[1], shard2) +} diff --git a/pkg/logservice/README.md b/pkg/logservice/README.md new file mode 100644 index 0000000000000..c0b8394de0443 --- /dev/null +++ b/pkg/logservice/README.md @@ -0,0 +1,3 @@ +## About + +Log Service provides reliable logging for MatrixOne. diff --git a/pkg/logservice/client.go b/pkg/logservice/client.go new file mode 100644 index 0000000000000..dbcd10412f055 --- /dev/null +++ b/pkg/logservice/client.go @@ -0,0 +1,199 @@ +// Copyright 2021 - 2022 Matrix Origin +// +// 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 logservice + +import ( + "context" + "net" + + "github.com/matrixorigin/matrixone/pkg/common/moerr" + pb "github.com/matrixorigin/matrixone/pkg/pb/logservice" +) + +var ( + // ErrIncompatibleClient is returned when write requests are made on read-only clients. + ErrIncompatibleClient = moerr.NewError(moerr.INVALID_INPUT, "incompatible client") +) + +type LogServiceClientConfig struct { + ReadOnly bool + ShardID uint64 + ReplicaID uint64 + // LogService nodes service addresses + ServiceAddresses []string +} + +type Client interface { + Close() error + Config() LogServiceClientConfig + Append(ctx context.Context, rec pb.LogRecord) (Lsn, error) + Read(ctx context.Context, firstIndex Lsn, maxSize uint64) ([]pb.LogRecord, Lsn, error) + Truncate(ctx context.Context, index Lsn) error + GetTruncatedIndex(ctx context.Context) (Lsn, error) +} + +type client struct { + conn net.Conn + cfg LogServiceClientConfig + buf []byte +} + +var _ Client = (*client)(nil) + +func CreateClient(ctx context.Context, + name string, cfg LogServiceClientConfig) (Client, error) { + c := &client{ + cfg: cfg, + buf: make([]byte, reqBufSize), + } + var e error + for _, addr := range cfg.ServiceAddresses { + conn, err := getConnection(ctx, addr) + if err != nil { + e = err + continue + } + c.conn = conn + if cfg.ReadOnly { + if err := c.connectReadOnly(ctx); err == nil { + return c, nil + } else { + e = err + } + } else { + if err := c.connectReadWrite(ctx); err == nil { + return c, nil + } else { + e = err + } + } + } + return nil, e +} + +func (c *client) Close() error { + if err := sendPoison(c.conn, poisonNumber[:]); err != nil { + return err + } + return waitPoisonAck(c.conn) +} + +func (c *client) Config() LogServiceClientConfig { + return c.cfg +} + +func (c *client) Append(ctx context.Context, rec pb.LogRecord) (Lsn, error) { + if c.readOnly() { + return 0, ErrIncompatibleClient + } + // TODO: check piggybacked hint on whether we are connected to the leader node + return c.append(ctx, rec) +} + +func (c *client) Read(ctx context.Context, + firstIndex Lsn, maxSize uint64) ([]pb.LogRecord, Lsn, error) { + return c.read(ctx, firstIndex, maxSize) +} + +func (c *client) Truncate(ctx context.Context, lsn Lsn) error { + if c.readOnly() { + return ErrIncompatibleClient + } + return c.truncate(ctx, lsn) +} + +func (c *client) GetTruncatedIndex(ctx context.Context) (Lsn, error) { + return c.getTruncatedIndex(ctx) +} + +func (c *client) readOnly() bool { + return c.cfg.ReadOnly +} + +func (c *client) connectReadWrite(ctx context.Context) error { + if c.readOnly() { + panic(ErrIncompatibleClient) + } + return c.connect(ctx, pb.MethodType_CONNECT) +} + +func (c *client) connectReadOnly(ctx context.Context) error { + return c.connect(ctx, pb.MethodType_CONNECT_RO) +} + +func (c *client) request(ctx context.Context, + mt pb.MethodType, payload []byte, index Lsn, + maxSize uint64) (pb.Response, []pb.LogRecord, error) { + timeout, err := getTimeoutFromContext(ctx) + if err != nil { + return pb.Response{}, nil, err + } + req := pb.Request{ + Method: mt, + ShardID: c.cfg.ShardID, + DNID: c.cfg.ReplicaID, + Timeout: int64(timeout), + Index: index, + MaxSize: maxSize, + PayloadSize: uint64(len(payload)), + } + if err := writeRequest(c.conn, req, c.buf, payload); err != nil { + return pb.Response{}, nil, err + } + resp, recs, err := readResponse(c.conn, c.buf) + if err != nil { + return pb.Response{}, nil, err + } + err = toError(resp) + if err != nil { + return pb.Response{}, nil, err + } + return resp, recs.Records, nil +} + +func (c *client) connect(ctx context.Context, mt pb.MethodType) error { + _, _, err := c.request(ctx, mt, nil, 0, 0) + return err +} + +func (c *client) append(ctx context.Context, rec pb.LogRecord) (Lsn, error) { + resp, _, err := c.request(ctx, pb.MethodType_APPEND, rec.Data, 0, 0) + if err != nil { + return 0, err + } + return resp.Index, nil +} + +func (c *client) read(ctx context.Context, + firstIndex Lsn, maxSize uint64) ([]pb.LogRecord, Lsn, error) { + resp, recs, err := c.request(ctx, pb.MethodType_READ, nil, firstIndex, maxSize) + if err != nil { + return nil, 0, err + } + return recs, resp.LastIndex, nil +} + +func (c *client) truncate(ctx context.Context, lsn Lsn) error { + _, _, err := c.request(ctx, pb.MethodType_TRUNCATE, nil, lsn, 0) + return err +} + +func (c *client) getTruncatedIndex(ctx context.Context) (Lsn, error) { + resp, _, err := c.request(ctx, pb.MethodType_GET_TRUNCATE, nil, 0, 0) + if err != nil { + return 0, err + } + return resp.Index, nil +} diff --git a/pkg/logservice/client_test.go b/pkg/logservice/client_test.go new file mode 100644 index 0000000000000..77b582b71bb34 --- /dev/null +++ b/pkg/logservice/client_test.go @@ -0,0 +1,159 @@ +// Copyright 2021 - 2022 Matrix Origin +// +// 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 logservice + +import ( + "context" + "math" + "math/rand" + "testing" + "time" + + "github.com/lni/goutils/leaktest" + "github.com/lni/vfs" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + pb "github.com/matrixorigin/matrixone/pkg/pb/logservice" +) + +func runClientTest(t *testing.T, + readOnly bool, fn func(*testing.T, LogServiceClientConfig, Client)) { + defer leaktest.AfterTest(t)() + cfg := getServiceTestConfig() + defer vfs.ReportLeakedFD(cfg.FS, t) + service, err := NewService(cfg) + require.NoError(t, err) + defer func() { + assert.NoError(t, service.Close()) + }() + + init := make(map[uint64]string) + init[2] = service.ID() + assert.NoError(t, service.store.StartReplica(1, 2, init)) + + scfg := LogServiceClientConfig{ + ReadOnly: readOnly, + ShardID: 1, + ReplicaID: 2, + ServiceAddresses: []string{testServiceAddress}, + } + + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + c, err := CreateClient(ctx, "shard1", scfg) + require.NoError(t, err) + defer func() { + assert.NoError(t, c.Close()) + }() + + fn(t, scfg, c) +} + +func TestClientCanBeCreated(t *testing.T) { + fn := func(t *testing.T, cfg LogServiceClientConfig, c Client) { + } + runClientTest(t, false, fn) + runClientTest(t, true, fn) +} + +func TestClientAppend(t *testing.T) { + fn := func(t *testing.T, cfg LogServiceClientConfig, c Client) { + cmd := make([]byte, 16+headerSize+8) + cmd = getAppendCmd(cmd, cfg.ReplicaID) + rand.Read(cmd[headerSize+8:]) + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + lsn, err := c.Append(ctx, pb.LogRecord{Data: cmd}) + require.NoError(t, err) + assert.Equal(t, uint64(4), lsn) + + lsn, err = c.Append(ctx, pb.LogRecord{Data: cmd}) + require.NoError(t, err) + assert.Equal(t, uint64(5), lsn) + + cmd = getAppendCmd(cmd, cfg.ReplicaID+1) + _, err = c.Append(ctx, pb.LogRecord{Data: cmd}) + assert.Equal(t, ErrNotLeaseHolder, err) + } + runClientTest(t, false, fn) +} + +func TestClientRead(t *testing.T) { + fn := func(t *testing.T, cfg LogServiceClientConfig, c Client) { + cmd := make([]byte, 16+headerSize+8) + cmd = getAppendCmd(cmd, cfg.ReplicaID) + rand.Read(cmd[headerSize+8:]) + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + lsn, err := c.Append(ctx, pb.LogRecord{Data: cmd}) + require.NoError(t, err) + assert.Equal(t, uint64(4), lsn) + + cmd2 := make([]byte, 16+headerSize+8) + cmd2 = getAppendCmd(cmd2, cfg.ReplicaID) + rand.Read(cmd2[headerSize+8:]) + lsn, err = c.Append(ctx, pb.LogRecord{Data: cmd2}) + require.NoError(t, err) + assert.Equal(t, uint64(5), lsn) + + // FIXME: returned records should contain correct Index value + recs, lsn, err := c.Read(ctx, 4, math.MaxUint64) + require.NoError(t, err) + assert.Equal(t, uint64(4), lsn) + assert.Equal(t, 2, len(recs)) + assert.Equal(t, cmd, recs[0].Data) + assert.Equal(t, cmd2, recs[1].Data) + + _, _, err = c.Read(ctx, 6, math.MaxUint64) + assert.Equal(t, ErrOutOfRange, err) + } + runClientTest(t, false, fn) +} + +func TestClientTruncate(t *testing.T) { + fn := func(t *testing.T, cfg LogServiceClientConfig, c Client) { + cmd := make([]byte, 16+headerSize+8) + cmd = getAppendCmd(cmd, cfg.ReplicaID) + rand.Read(cmd[headerSize+8:]) + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + lsn, err := c.Append(ctx, pb.LogRecord{Data: cmd}) + require.NoError(t, err) + assert.Equal(t, uint64(4), lsn) + + require.NoError(t, c.Truncate(ctx, 4)) + lsn, err = c.GetTruncatedIndex(ctx) + assert.NoError(t, err) + assert.Equal(t, Lsn(4), lsn) + + assert.Equal(t, ErrInvalidTruncateIndex, c.Truncate(ctx, 3)) + } + runClientTest(t, false, fn) +} + +func TestReadOnlyClientRejectWriteRequests(t *testing.T) { + fn := func(t *testing.T, cfg LogServiceClientConfig, c Client) { + cmd := make([]byte, 16+headerSize+8) + cmd = getAppendCmd(cmd, cfg.ReplicaID) + rand.Read(cmd[headerSize+8:]) + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + _, err := c.Append(ctx, pb.LogRecord{Data: cmd}) + require.Equal(t, ErrIncompatibleClient, err) + require.Equal(t, ErrIncompatibleClient, c.Truncate(ctx, 4)) + } + runClientTest(t, true, fn) +} diff --git a/pkg/logservice/config.go b/pkg/logservice/config.go new file mode 100644 index 0000000000000..7e70dda83bd79 --- /dev/null +++ b/pkg/logservice/config.go @@ -0,0 +1,99 @@ +// Copyright 2021 - 2022 Matrix Origin +// +// 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 logservice + +import ( + "github.com/cockroachdb/errors" + "github.com/lni/vfs" + + "github.com/matrixorigin/matrixone/pkg/common/moerr" +) + +const ( + defaultDataDir = "mo-logservice-data" + defaultServiceAddress = "0.0.0.0:32000" + defaultRaftAddress = "0.0.0.0:32001" + defaultGossipAddress = "0.0.0.0:32002" +) + +var ( + ErrInvalidConfig = moerr.NewError(moerr.BAD_CONFIGURATION, "invalid log service configuration") +) + +// TODO: add toml or json support +// Config defines the Configurations supported by the Log Service. +type Config struct { + FS vfs.FS + DeploymentID uint64 + NodeHostID string + RTTMillisecond uint64 + DataDir string + ServiceAddress string + ServiceListenAddress string + RaftAddress string + RaftListenAddress string + GossipAddress string + GossipListenAddress string + GossipSeedAddresses []string +} + +// Validate validates the configuration. +func (c *Config) Validate() error { + if c.DeploymentID == 0 { + return errors.Wrapf(ErrInvalidConfig, "DeploymentID not set") + } + // when *ListenAddress is not empty and *Address is empty, consider it as an + // error + if len(c.ServiceAddress) == 0 && len(c.ServiceListenAddress) != 0 { + return errors.Wrapf(ErrInvalidConfig, "ServiceAddress not set") + } + if len(c.RaftAddress) == 0 && len(c.RaftListenAddress) != 0 { + return errors.Wrapf(ErrInvalidConfig, "RaftAddress not set") + } + if len(c.GossipAddress) == 0 && len(c.GossipListenAddress) != 0 { + return errors.Wrapf(ErrInvalidConfig, "GossipAddress not set") + } + if len(c.GossipSeedAddresses) == 0 { + return errors.Wrapf(ErrInvalidConfig, "GossipSeedAddresses not set") + } + return nil +} + +func (c *Config) Fill() { + if c.RTTMillisecond == 0 { + c.RTTMillisecond = 200 + } + if len(c.DataDir) == 0 { + c.DataDir = defaultDataDir + } + if len(c.ServiceAddress) == 0 { + c.ServiceAddress = defaultServiceAddress + c.ServiceListenAddress = defaultServiceAddress + } else if len(c.ServiceAddress) != 0 && len(c.ServiceListenAddress) == 0 { + c.ServiceListenAddress = c.ServiceAddress + } + if len(c.RaftAddress) == 0 { + c.RaftAddress = defaultRaftAddress + c.RaftListenAddress = defaultRaftAddress + } else if len(c.RaftAddress) != 0 && len(c.RaftListenAddress) == 0 { + c.RaftListenAddress = c.RaftAddress + } + if len(c.GossipAddress) == 0 { + c.GossipAddress = defaultGossipAddress + c.GossipListenAddress = defaultGossipAddress + } else if len(c.GossipAddress) != 0 && len(c.GossipListenAddress) == 0 { + c.GossipListenAddress = c.GossipAddress + } +} diff --git a/pkg/logservice/config_test.go b/pkg/logservice/config_test.go new file mode 100644 index 0000000000000..79625e817d6f2 --- /dev/null +++ b/pkg/logservice/config_test.go @@ -0,0 +1,92 @@ +// Copyright 2021 - 2022 Matrix Origin +// +// 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 logservice + +import ( + "testing" + + "github.com/cockroachdb/errors" + "github.com/stretchr/testify/assert" +) + +func getTestConfig() Config { + return Config{ + DeploymentID: 100, + DataDir: "/mydata/dir", + ServiceAddress: "localhost:9000", + ServiceListenAddress: "localhost:9000", + RaftAddress: "localhost:9001", + RaftListenAddress: "localhost:9001", + GossipAddress: "localhost:9002", + GossipListenAddress: "localhost:9002", + GossipSeedAddresses: []string{"localhost:9002"}, + } +} + +func TestConfigCanBeValidated(t *testing.T) { + c := getTestConfig() + assert.Nil(t, c.Validate()) + + c1 := c + c1.DeploymentID = 0 + assert.True(t, errors.Is(c1.Validate(), ErrInvalidConfig)) + + c2 := c + c2.ServiceAddress = "" + assert.True(t, errors.Is(c2.Validate(), ErrInvalidConfig)) + + c3 := c + c3.RaftAddress = "" + assert.True(t, errors.Is(c3.Validate(), ErrInvalidConfig)) + + c4 := c + c4.GossipAddress = "" + assert.True(t, errors.Is(c4.Validate(), ErrInvalidConfig)) + + c5 := c + c5.GossipSeedAddresses = []string{} + assert.True(t, errors.Is(c5.Validate(), ErrInvalidConfig)) +} + +func TestFillConfig(t *testing.T) { + c := Config{} + c.Fill() + + assert.Equal(t, uint64(0), c.DeploymentID) + assert.Equal(t, defaultDataDir, c.DataDir) + assert.Equal(t, defaultServiceAddress, c.ServiceAddress) + assert.Equal(t, defaultServiceAddress, c.ServiceListenAddress) + assert.Equal(t, defaultRaftAddress, c.RaftAddress) + assert.Equal(t, defaultRaftAddress, c.RaftListenAddress) + assert.Equal(t, defaultGossipAddress, c.GossipAddress) + assert.Equal(t, defaultGossipAddress, c.GossipListenAddress) + assert.Equal(t, 0, len(c.GossipSeedAddresses)) +} + +func TestListenAddressCanBeFilled(t *testing.T) { + cfg := Config{ + DeploymentID: 1, + RTTMillisecond: 5, + DataDir: "data-1", + ServiceAddress: "127.0.0.1:9002", + RaftAddress: "127.0.0.1:9000", + GossipAddress: "127.0.0.1:9001", + GossipSeedAddresses: []string{"127.0.0.1:9011"}, + } + cfg.Fill() + assert.Equal(t, cfg.ServiceAddress, cfg.ServiceListenAddress) + assert.Equal(t, cfg.RaftAddress, cfg.RaftListenAddress) + assert.Equal(t, cfg.GossipAddress, cfg.GossipListenAddress) +} diff --git a/pkg/logservice/errors.go b/pkg/logservice/errors.go new file mode 100644 index 0000000000000..2bdddaeb8c98c --- /dev/null +++ b/pkg/logservice/errors.go @@ -0,0 +1,85 @@ +// Copyright 2021 - 2022 Matrix Origin +// +// 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 logservice + +import ( + "github.com/cockroachdb/errors" + "github.com/lni/dragonboat/v4" + + "github.com/matrixorigin/matrixone/pkg/common/moerr" + pb "github.com/matrixorigin/matrixone/pkg/pb/logservice" +) + +var ( + ErrUnknownError = moerr.NewError(moerr.INVALID_STATE, "unknown error") +) + +type errorToCode struct { + err error + code pb.ErrorCode + reverse bool +} + +var errorToCodeMappings = getErrorToCodeMapping() + +func getErrorToCodeMapping() []errorToCode { + return []errorToCode{ + {dragonboat.ErrTimeout, pb.ErrorCode_Timeout, true}, + {dragonboat.ErrShardNotFound, pb.ErrorCode_InvalidShard, true}, + // TODO: why ErrTimeoutTooSmall is possible + {dragonboat.ErrTimeoutTooSmall, pb.ErrorCode_Timeout, false}, + {dragonboat.ErrPayloadTooBig, pb.ErrorCode_InvalidPayloadSize, true}, + {dragonboat.ErrRejected, pb.ErrorCode_Rejected, true}, + {dragonboat.ErrShardNotReady, pb.ErrorCode_ShardNotReady, true}, + {dragonboat.ErrSystemBusy, pb.ErrorCode_ShardNotReady, false}, + {dragonboat.ErrClosed, pb.ErrorCode_SystemClosed, true}, + + {ErrInvalidTruncateIndex, pb.ErrorCode_IndexAlreadyTruncated, true}, + {ErrNotLeaseHolder, pb.ErrorCode_NotLeaseHolder, true}, + {ErrOutOfRange, pb.ErrorCode_OutOfRange, true}, + } +} + +func toErrorCode(err error) (pb.ErrorCode, string) { + if err == nil { + return pb.ErrorCode_NoError, "" + } + for _, rec := range errorToCodeMappings { + if errors.Is(err, rec.err) { + plog.Errorf("error: %v, converted to code %d", err, rec.code) + return rec.code, "" + } + } + plog.Errorf("unrecognized error %v, converted to %d", err, + pb.ErrorCode_OtherSystemError) + return pb.ErrorCode_OtherSystemError, err.Error() +} + +func toError(resp pb.Response) error { + if resp.ErrorCode == pb.ErrorCode_NoError { + return nil + } else if resp.ErrorCode == pb.ErrorCode_OtherSystemError { + return errors.Wrapf(ErrUnknownError, resp.ErrorMessage) + } + + for _, rec := range errorToCodeMappings { + if rec.code == resp.ErrorCode && rec.reverse { + return rec.err + } + } + plog.Panicf("Unknown error code: %d", resp.ErrorCode) + // will never reach here + return nil +} diff --git a/pkg/logservice/errors_test.go b/pkg/logservice/errors_test.go new file mode 100644 index 0000000000000..8ed7ecd12f45a --- /dev/null +++ b/pkg/logservice/errors_test.go @@ -0,0 +1,46 @@ +// Copyright 2021 - 2022 Matrix Origin +// +// 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 logservice + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/assert" + + pb "github.com/matrixorigin/matrixone/pkg/pb/logservice" +) + +func TestErrorConversion(t *testing.T) { + mappings := getErrorToCodeMapping() + for _, rec := range mappings { + if rec.reverse { + code, msg := toErrorCode(rec.err) + resp := pb.Response{ + ErrorCode: code, + ErrorMessage: msg, + } + err := toError(resp) + assert.Equal(t, err, rec.err) + } + } +} + +func TestUnknownErrorIsHandled(t *testing.T) { + err := errors.New("test error") + code, str := toErrorCode(err) + assert.Equal(t, pb.ErrorCode_OtherSystemError, code) + assert.Equal(t, err.Error(), str) +} diff --git a/pkg/logservice/rsm.go b/pkg/logservice/rsm.go new file mode 100644 index 0000000000000..753c9b0803ea7 --- /dev/null +++ b/pkg/logservice/rsm.go @@ -0,0 +1,233 @@ +// Copyright 2021 - 2022 Matrix Origin +// +// 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 logservice + +import ( + "encoding/binary" + "encoding/gob" + "io" + + sm "github.com/lni/dragonboat/v4/statemachine" +) + +var ( + binaryEnc = binary.BigEndian +) + +const ( + headerSize = 2 +) + +const ( + leaseHolderIDTag uint16 = iota + 0xBF01 + truncatedIndexTag + userEntryTag + indexTag +) + +type leaseHistoryQuery struct { + index uint64 +} + +func getAppendCmd(cmd []byte, replicaID uint64) []byte { + if len(cmd) < headerSize+8 { + panic("cmd too small") + } + binaryEnc.PutUint16(cmd, userEntryTag) + binaryEnc.PutUint64(cmd[headerSize:], replicaID) + return cmd +} + +func parseCmdTag(cmd []byte) uint16 { + return binaryEnc.Uint16(cmd) +} + +func parseTruncatedIndex(cmd []byte) uint64 { + return binaryEnc.Uint64(cmd[headerSize:]) +} + +func parseLeaseHolderID(cmd []byte) uint64 { + return binaryEnc.Uint64(cmd[headerSize:]) +} + +func getSetLeaseHolderCmd(leaseHolderID uint64) []byte { + cmd := make([]byte, headerSize+8) + binaryEnc.PutUint16(cmd, leaseHolderIDTag) + binaryEnc.PutUint64(cmd[headerSize:], leaseHolderID) + return cmd +} + +func getSetTruncatedIndexCmd(index uint64) []byte { + cmd := make([]byte, headerSize+8) + binaryEnc.PutUint16(cmd, truncatedIndexTag) + binaryEnc.PutUint64(cmd[headerSize:], index) + return cmd +} + +func isSetLeaseHolderUpdate(cmd []byte) bool { + return tagMatch(cmd, leaseHolderIDTag) +} + +func isSetTruncatedIndexUpdate(cmd []byte) bool { + return tagMatch(cmd, truncatedIndexTag) +} + +func isUserUpdate(cmd []byte) bool { + if len(cmd) < headerSize+8 { + return false + } + return parseCmdTag(cmd) == userEntryTag +} + +func tagMatch(cmd []byte, expectedTag uint16) bool { + if len(cmd) != headerSize+8 { + return false + } + return parseCmdTag(cmd) == expectedTag +} + +type stateMachine struct { + shardID uint64 + replicaID uint64 + Index uint64 + LeaseHolderID uint64 + TruncatedIndex uint64 + LeaseHistory map[uint64]uint64 // log index -> truncate index +} + +var _ (sm.IStateMachine) = (*stateMachine)(nil) + +// making this a IConcurrentStateMachine for now, IStateMachine need to be updated +// to provide raft entry index to its Update() method +func newStateMachine(shardID uint64, replicaID uint64) sm.IStateMachine { + return &stateMachine{ + shardID: shardID, + replicaID: replicaID, + LeaseHistory: make(map[uint64]uint64), + } +} + +func (s *stateMachine) setLeaseHolderID(index uint64, cmd []byte) { + if !isSetLeaseHolderUpdate(cmd) { + panic("not a setLeaseHolder update") + } + s.LeaseHolderID = parseLeaseHolderID(cmd) + s.LeaseHistory[index] = s.LeaseHolderID +} + +func (s *stateMachine) truncateLeaseHistory(index uint64) { + _, index = s.getLeaseHistory(index) + for key := range s.LeaseHistory { + if key < index { + delete(s.LeaseHistory, key) + } + } +} + +func (s *stateMachine) getLeaseHistory(index uint64) (uint64, uint64) { + max := uint64(0) + lease := uint64(0) + for key, val := range s.LeaseHistory { + if key >= index { + continue + } + if key > max { + max = key + lease = val + } + } + return lease, max +} + +func (s *stateMachine) setTruncatedIndex(cmd []byte) bool { + if !isSetTruncatedIndexUpdate(cmd) { + panic("not a setTruncatedIndex update") + } + index := parseTruncatedIndex(cmd) + if index > s.TruncatedIndex { + s.TruncatedIndex = index + s.truncateLeaseHistory(index) + return true + } + return false +} + +// handleUserUpdate returns an empty sm.Result on success or it returns a +// sm.Result value with the Value field set to the current lease holder ID +// to indicate rejection by mismatched lease holder ID. +func (s *stateMachine) handleUserUpdate(index uint64, cmd []byte) sm.Result { + if !isUserUpdate(cmd) { + panic("not user update") + } + if s.LeaseHolderID != parseLeaseHolderID(cmd) { + data := make([]byte, 8) + binaryEnc.PutUint64(data, s.LeaseHolderID) + return sm.Result{Data: data} + } + return sm.Result{Value: index} +} + +func (s *stateMachine) Close() error { + return nil +} + +func (s *stateMachine) Update(e sm.Entry) (sm.Result, error) { + cmd := e.Cmd + s.Index = e.Index + if isSetLeaseHolderUpdate(cmd) { + s.setLeaseHolderID(e.Index, cmd) + return sm.Result{}, nil + } else if isSetTruncatedIndexUpdate(cmd) { + if s.setTruncatedIndex(cmd) { + return sm.Result{}, nil + } else { + return sm.Result{Value: s.TruncatedIndex}, nil + } + } else if isUserUpdate(cmd) { + return s.handleUserUpdate(e.Index, cmd), nil + } + panic("corrupted entry") +} + +func (s *stateMachine) Lookup(query interface{}) (interface{}, error) { + if v, ok := query.(uint16); ok { + if v == indexTag { + return s.Index, nil + } else if v == leaseHolderIDTag { + return s.LeaseHolderID, nil + } else if v == truncatedIndexTag { + return s.TruncatedIndex, nil + } else { + panic("unknown lookup command type") + } + } + if v, ok := query.(leaseHistoryQuery); ok { + lease, _ := s.getLeaseHistory(v.index) + return lease, nil + } + panic("unknown lookup command type") +} + +func (s *stateMachine) SaveSnapshot(w io.Writer, + _ sm.ISnapshotFileCollection, _ <-chan struct{}) error { + enc := gob.NewEncoder(w) + return enc.Encode(s) +} + +func (s *stateMachine) RecoverFromSnapshot(r io.Reader, + _ []sm.SnapshotFile, _ <-chan struct{}) error { + dec := gob.NewDecoder(r) + return dec.Decode(s) +} diff --git a/pkg/logservice/rsm_test.go b/pkg/logservice/rsm_test.go new file mode 100644 index 0000000000000..84743fd61180a --- /dev/null +++ b/pkg/logservice/rsm_test.go @@ -0,0 +1,246 @@ +// Copyright 2021 - 2022 Matrix Origin +// +// 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 logservice + +import ( + "bytes" + "testing" + + sm "github.com/lni/dragonboat/v4/statemachine" + "github.com/stretchr/testify/assert" +) + +func TestGetLeaseHistory(t *testing.T) { + tsm := newStateMachine(1, 2).(*stateMachine) + tsm.LeaseHistory[100] = 1000 + tsm.LeaseHistory[200] = 2000 + tsm.LeaseHistory[300] = 3000 + lease, index := tsm.getLeaseHistory(150) + assert.Equal(t, uint64(1000), lease) + assert.Equal(t, uint64(100), index) + + lease, index = tsm.getLeaseHistory(200) + assert.Equal(t, uint64(1000), lease) + assert.Equal(t, uint64(100), index) + + lease, index = tsm.getLeaseHistory(100) + assert.Equal(t, uint64(0), lease) + assert.Equal(t, uint64(0), index) + + lease, index = tsm.getLeaseHistory(400) + assert.Equal(t, uint64(3000), lease) + assert.Equal(t, uint64(300), index) +} + +func TestTruncateLeaseHistory(t *testing.T) { + getSM := func() *stateMachine { + tsm := newStateMachine(1, 2).(*stateMachine) + tsm.LeaseHistory[100] = 1000 + tsm.LeaseHistory[200] = 2000 + tsm.LeaseHistory[300] = 3000 + return tsm + } + + tsm := getSM() + tsm.truncateLeaseHistory(105) + assert.Equal(t, 3, len(tsm.LeaseHistory)) + tsm.truncateLeaseHistory(200) + assert.Equal(t, 3, len(tsm.LeaseHistory)) + tsm.truncateLeaseHistory(201) + assert.Equal(t, 2, len(tsm.LeaseHistory)) + _, ok1 := tsm.LeaseHistory[200] + _, ok2 := tsm.LeaseHistory[300] + assert.True(t, ok1) + assert.True(t, ok2) + + tsm = getSM() + tsm.truncateLeaseHistory(300) + assert.Equal(t, 2, len(tsm.LeaseHistory)) + _, ok := tsm.LeaseHistory[100] + assert.False(t, ok) + + tsm = getSM() + tsm.truncateLeaseHistory(301) + assert.Equal(t, 1, len(tsm.LeaseHistory)) + _, ok = tsm.LeaseHistory[300] + assert.True(t, ok) +} + +func TestGetSetLeaseHolderCmd(t *testing.T) { + cmd := getSetLeaseHolderCmd(100) + assert.True(t, isSetLeaseHolderUpdate(cmd)) + cmd2 := getSetTruncatedIndexCmd(200) + assert.False(t, isSetLeaseHolderUpdate(cmd2)) +} + +func TestGetSetTruncatedIndexCmd(t *testing.T) { + cmd := getSetTruncatedIndexCmd(1234) + assert.True(t, isSetTruncatedIndexUpdate(cmd)) + cmd2 := getSetLeaseHolderCmd(1234) + assert.False(t, isSetTruncatedIndexUpdate(cmd2)) +} + +func TestIsUserUpdate(t *testing.T) { + cmd := make([]byte, headerSize+8+1) + binaryEnc.PutUint16(cmd, userEntryTag) + assert.True(t, isUserUpdate(cmd)) + cmd2 := getSetLeaseHolderCmd(1234) + cmd3 := getSetTruncatedIndexCmd(200) + assert.False(t, isUserUpdate(cmd2)) + assert.False(t, isUserUpdate(cmd3)) +} + +func TestNewStateMachine(t *testing.T) { + tsm := newStateMachine(100, 200).(*stateMachine) + assert.Equal(t, uint64(100), tsm.shardID) + assert.Equal(t, uint64(200), tsm.replicaID) +} + +func TestStateMachineCanBeClosed(t *testing.T) { + tsm := newStateMachine(100, 200) + assert.Nil(t, tsm.Close()) +} + +func TestDNLeaseHolderCanBeUpdated(t *testing.T) { + cmd := getSetLeaseHolderCmd(500) + tsm := newStateMachine(1, 2).(*stateMachine) + assert.Equal(t, uint64(0), tsm.LeaseHolderID) + e := sm.Entry{Cmd: cmd, Index: 100} + result, err := tsm.Update(e) + assert.Equal(t, sm.Result{}, result) + assert.Nil(t, err) + assert.Equal(t, uint64(500), tsm.LeaseHolderID) + assert.Equal(t, 1, len(tsm.LeaseHistory)) + v, ok := tsm.LeaseHistory[100] + assert.True(t, ok) + assert.Equal(t, uint64(500), v) + + cmd = getSetLeaseHolderCmd(1000) + e = sm.Entry{Cmd: cmd, Index: 200} + result, err = tsm.Update(e) + assert.Equal(t, sm.Result{}, result) + assert.Nil(t, err) + assert.Equal(t, uint64(1000), tsm.LeaseHolderID) + assert.Equal(t, 2, len(tsm.LeaseHistory)) + v, ok = tsm.LeaseHistory[200] + assert.True(t, ok) + assert.Equal(t, uint64(1000), v) + + cmd = getSetTruncatedIndexCmd(110) + e = sm.Entry{Cmd: cmd} + result, err = tsm.Update(e) + assert.Equal(t, sm.Result{}, result) + assert.Nil(t, err) + // first lease history record won't be truncated + assert.Equal(t, 2, len(tsm.LeaseHistory)) +} + +func TestTruncatedIndexCanBeUpdated(t *testing.T) { + cmd := getSetTruncatedIndexCmd(200) + tsm := newStateMachine(1, 2).(*stateMachine) + e := sm.Entry{Cmd: cmd} + result, err := tsm.Update(e) + assert.Equal(t, sm.Result{}, result) + assert.Nil(t, err) + + cmd2 := getSetTruncatedIndexCmd(220) + e2 := sm.Entry{Cmd: cmd2} + result, err = tsm.Update(e2) + assert.Equal(t, sm.Result{}, result) + assert.Nil(t, err) + + cmd3 := getSetTruncatedIndexCmd(100) + e3 := sm.Entry{Cmd: cmd3} + result, err = tsm.Update(e3) + assert.Equal(t, sm.Result{Value: 220}, result) + assert.Nil(t, err) +} + +func TestStateMachineUserUpdate(t *testing.T) { + cmd := make([]byte, headerSize+8+1) + binaryEnc.PutUint16(cmd, userEntryTag) + binaryEnc.PutUint64(cmd[headerSize:], uint64(1234)) + + tsm := newStateMachine(1, 2).(*stateMachine) + tsm.LeaseHolderID = 1234 + e := sm.Entry{Index: 100, Cmd: cmd} + result, err := tsm.Update(e) + assert.Nil(t, err) + assert.Equal(t, e.Index, result.Value) + assert.Nil(t, result.Data) + + tsm.LeaseHolderID = 2345 + e = sm.Entry{Cmd: cmd} + result, err = tsm.Update(e) + assert.Nil(t, err) + assert.Equal(t, uint64(0), result.Value) + assert.NotNil(t, result.Data) + assert.Equal(t, tsm.LeaseHolderID, binaryEnc.Uint64(result.Data)) +} + +func TestStateMachineSnapshot(t *testing.T) { + buf := bytes.NewBuffer(nil) + tsm := newStateMachine(1, 2).(*stateMachine) + tsm.LeaseHolderID = 123456 + tsm.TruncatedIndex = 456789 + assert.Nil(t, tsm.SaveSnapshot(buf, nil, nil)) + + tsm2 := newStateMachine(3, 4).(*stateMachine) + assert.Nil(t, tsm2.RecoverFromSnapshot(buf, nil, nil)) + assert.Equal(t, tsm.LeaseHolderID, tsm2.LeaseHolderID) + assert.Equal(t, tsm.TruncatedIndex, tsm2.TruncatedIndex) + assert.Equal(t, uint64(3), tsm2.shardID) + assert.Equal(t, uint64(4), tsm2.replicaID) +} + +func TestStateMachineLookup(t *testing.T) { + tsm := newStateMachine(1, 2).(*stateMachine) + tsm.Index = 1234 + tsm.LeaseHolderID = 123456 + tsm.TruncatedIndex = 456789 + v, err := tsm.Lookup(leaseHolderIDTag) + assert.Nil(t, err) + assert.Equal(t, tsm.LeaseHolderID, v.(uint64)) + + v2, err := tsm.Lookup(truncatedIndexTag) + assert.Nil(t, err) + assert.Equal(t, tsm.TruncatedIndex, v2.(uint64)) + + v3, err := tsm.Lookup(indexTag) + assert.Nil(t, err) + assert.Equal(t, tsm.Index, v3.(uint64)) +} + +func TestStateMachineLookupPanicOnUnexpectedInputValue(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Fatalf("failed to panic") + } + }() + tsm := newStateMachine(1, 2).(*stateMachine) + _, err := tsm.Lookup(uint16(1234)) + assert.NoError(t, err) +} + +func TestStateMachineLookupPanicOnUnexpectedInputType(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Fatalf("failed to panic") + } + }() + tsm := newStateMachine(1, 2).(*stateMachine) + _, err := tsm.Lookup(uint64(1234)) + assert.NoError(t, err) +} diff --git a/pkg/logservice/service.go b/pkg/logservice/service.go new file mode 100644 index 0000000000000..900df86c6b1ef --- /dev/null +++ b/pkg/logservice/service.go @@ -0,0 +1,270 @@ +// Copyright 2021 - 2022 Matrix Origin +// +// 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 logservice + +import ( + "context" + "net" + "sync" + "time" + + "github.com/cockroachdb/errors" + "github.com/lni/dragonboat/v4/logger" + "github.com/lni/goutils/netutil" + "github.com/lni/goutils/syncutil" + + pb "github.com/matrixorigin/matrixone/pkg/pb/logservice" +) + +var ( + plog = logger.GetLogger("LogService") +) + +type Lsn = uint64 + +type LogRecord = pb.LogRecord + +type Service struct { + cfg Config + store *logStore + stopper *syncutil.Stopper + connStopper *syncutil.Stopper +} + +func NewService(cfg Config) (*Service, error) { + if err := cfg.Validate(); err != nil { + return nil, err + } + cfg.Fill() + + store, err := newLogStore(cfg) + if err != nil { + plog.Errorf("failed to create log store %v", err) + return nil, err + } + service := &Service{ + cfg: cfg, + store: store, + stopper: syncutil.NewStopper(), + connStopper: syncutil.NewStopper(), + } + // TODO: before making the service available to the outside world, restore all + // replicas already known to the local store + if err := service.startServer(); err != nil { + plog.Errorf("failed to start the server %v", err) + if err := store.Close(); err != nil { + plog.Errorf("failed to close the store, %v", err) + } + return nil, err + } + return service, nil +} + +func (s *Service) Close() error { + s.stopper.Stop() + s.connStopper.Stop() + return s.store.Close() +} + +func (s *Service) ID() string { + return s.store.ID() +} + +func (s *Service) startServer() error { + listener, err := netutil.NewStoppableListener(s.cfg.ServiceListenAddress, + nil, s.stopper.ShouldStop()) + if err != nil { + return err + } + s.connStopper.RunWorker(func() { + // sync.WaitGroup's doc mentions that + // "Note that calls with a positive delta that occur when the counter is + // zero must happen before a Wait." + // It is unclear that whether the stdlib is going complain in future + // releases when Wait() is called when the counter is zero and Add() with + // positive delta has never been called. + <-s.connStopper.ShouldStop() + }) + s.stopper.RunWorker(func() { + for { + conn, err := listener.Accept() + if err != nil { + if err == netutil.ErrListenerStopped { + return + } + panic(err) + } + var once sync.Once + closeFn := func() { + once.Do(func() { + if err := conn.Close(); err != nil { + plog.Errorf("failed to close the connection, %v", err) + } + }) + } + s.connStopper.RunWorker(func() { + <-s.stopper.ShouldStop() + closeFn() + }) + s.connStopper.RunWorker(func() { + s.serve(conn) + closeFn() + }) + } + }) + return nil +} + +func (s *Service) serve(conn net.Conn) { + magicNum := make([]byte, len(magicNumber)) + reqBuf := make([]byte, reqBufSize) + recvBuf := make([]byte, recvBufSize) + + for { + err := readMagicNumber(conn, magicNum) + if err != nil { + if errors.Is(err, errPoisonReceived) { + if err := sendPoisonAck(conn, poisonNumber[:]); err != nil { + plog.Errorf("failed to send poison ack, %v", err) + } + return + } + if errors.Is(err, ErrBadMessage) { + return + } + operr, ok := err.(net.Error) + if ok && operr.Timeout() { + continue + } else { + return + } + } + req, payload, err := readRequest(conn, reqBuf, recvBuf) + if err != nil { + plog.Errorf("failed to read request, %v", err) + return + } + // with error already encoded into the resp + resp, records := s.handle(req, payload) + var recs []byte + if len(records.Records) > 0 { + data := MustMarshal(&records) + resp.PayloadSize = uint64(len(data)) + recs = data + } + if err := writeResponse(conn, resp, recs, recvBuf); err != nil { + plog.Errorf("failed to write response, %v", err) + return + } + } +} + +func (s *Service) handle(req pb.Request, + payload []byte) (pb.Response, pb.LogRecordResponse) { + switch req.Method { + case pb.MethodType_CREATE: + panic("not implemented") + case pb.MethodType_DESTROY: + panic("not implemented") + case pb.MethodType_APPEND: + return s.handleAppend(req, payload), pb.LogRecordResponse{} + case pb.MethodType_READ: + return s.handleRead(req) + case pb.MethodType_TRUNCATE: + return s.handleTruncate(req), pb.LogRecordResponse{} + case pb.MethodType_GET_TRUNCATE: + return s.handleGetTruncatedIndex(req), pb.LogRecordResponse{} + case pb.MethodType_CONNECT: + return s.handleConnect(req), pb.LogRecordResponse{} + case pb.MethodType_CONNECT_RO: + return s.handleConnectRO(req), pb.LogRecordResponse{} + default: + panic("unknown method type") + } +} + +func getResponse(req pb.Request) pb.Response { + return pb.Response{Method: req.Method} +} + +func (s *Service) handleConnect(req pb.Request) pb.Response { + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(req.Timeout)) + defer cancel() + resp := getResponse(req) + if err := s.store.GetOrExtendDNLease(ctx, req.ShardID, req.DNID); err != nil { + resp.ErrorCode, resp.ErrorMessage = toErrorCode(err) + } + return resp +} + +func (s *Service) handleConnectRO(req pb.Request) pb.Response { + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(req.Timeout)) + defer cancel() + resp := getResponse(req) + // we only check whether the specified shard is available + if _, err := s.store.GetTruncatedIndex(ctx, req.ShardID); err != nil { + resp.ErrorCode, resp.ErrorMessage = toErrorCode(err) + } + return resp +} + +func (s *Service) handleAppend(req pb.Request, payload []byte) pb.Response { + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(req.Timeout)) + defer cancel() + resp := getResponse(req) + lsn, err := s.store.Append(ctx, req.ShardID, payload) + if err != nil { + resp.ErrorCode, resp.ErrorMessage = toErrorCode(err) + } else { + resp.Index = lsn + } + return resp +} + +func (s *Service) handleRead(req pb.Request) (pb.Response, pb.LogRecordResponse) { + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(req.Timeout)) + defer cancel() + resp := getResponse(req) + records, lsn, err := s.store.QueryLog(ctx, req.ShardID, req.Index, req.MaxSize) + if err != nil { + resp.ErrorCode, resp.ErrorMessage = toErrorCode(err) + } else { + resp.LastIndex = lsn + } + return resp, pb.LogRecordResponse{Records: records} +} + +func (s *Service) handleTruncate(req pb.Request) pb.Response { + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(req.Timeout)) + defer cancel() + resp := getResponse(req) + if err := s.store.TruncateLog(ctx, req.ShardID, req.Index); err != nil { + resp.ErrorCode, resp.ErrorMessage = toErrorCode(err) + } + return resp +} + +func (s *Service) handleGetTruncatedIndex(req pb.Request) pb.Response { + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(req.Timeout)) + defer cancel() + resp := getResponse(req) + index, err := s.store.GetTruncatedIndex(ctx, req.ShardID) + if err != nil { + resp.ErrorCode, resp.ErrorMessage = toErrorCode(err) + } else { + resp.Index = index + } + return resp +} diff --git a/pkg/logservice/service_test.go b/pkg/logservice/service_test.go new file mode 100644 index 0000000000000..a982bb792612d --- /dev/null +++ b/pkg/logservice/service_test.go @@ -0,0 +1,372 @@ +// Copyright 2021 - 2022 Matrix Origin +// +// 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 logservice + +import ( + "testing" + "time" + + "github.com/lni/dragonboat/v4" + "github.com/lni/goutils/leaktest" + "github.com/lni/vfs" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + pb "github.com/matrixorigin/matrixone/pkg/pb/logservice" +) + +const ( + testServiceAddress = "localhost:9000" +) + +func getServiceTestConfig() Config { + return Config{ + RTTMillisecond: 10, + GossipSeedAddresses: []string{"127.0.0.1:9000"}, + DeploymentID: 1, + FS: vfs.NewStrictMem(), + ServiceListenAddress: testServiceAddress, + ServiceAddress: testServiceAddress, + } +} + +func runServiceTest(t *testing.T, fn func(*testing.T, *Service)) { + defer leaktest.AfterTest(t)() + cfg := getServiceTestConfig() + defer vfs.ReportLeakedFD(cfg.FS, t) + service, err := NewService(cfg) + require.NoError(t, err) + peers := make(map[uint64]dragonboat.Target) + peers[1] = service.ID() + require.NoError(t, service.store.StartReplica(1, 1, peers)) + defer func() { + assert.NoError(t, service.Close()) + }() + fn(t, service) +} + +func TestNewService(t *testing.T) { + defer leaktest.AfterTest(t)() + cfg := getServiceTestConfig() + defer vfs.ReportLeakedFD(cfg.FS, t) + service, err := NewService(cfg) + require.NoError(t, err) + assert.NoError(t, service.Close()) +} + +func TestServiceConnect(t *testing.T) { + fn := func(t *testing.T, s *Service) { + req := pb.Request{ + Method: pb.MethodType_CONNECT, + ShardID: 1, + Timeout: int64(time.Second), + DNID: 100, + } + resp := s.handleConnect(req) + assert.Equal(t, pb.ErrorCode_NoError, resp.ErrorCode) + assert.Equal(t, "", resp.ErrorMessage) + } + runServiceTest(t, fn) +} + +func TestServiceConnectTimeout(t *testing.T) { + fn := func(t *testing.T, s *Service) { + req := pb.Request{ + Method: pb.MethodType_CONNECT, + ShardID: 1, + Timeout: 50 * int64(time.Millisecond), + DNID: 100, + } + resp := s.handleConnect(req) + assert.Equal(t, pb.ErrorCode_Timeout, resp.ErrorCode) + assert.Equal(t, "", resp.ErrorMessage) + } + runServiceTest(t, fn) +} + +func TestServiceConnectRO(t *testing.T) { + fn := func(t *testing.T, s *Service) { + req := pb.Request{ + Method: pb.MethodType_CONNECT_RO, + ShardID: 1, + Timeout: int64(time.Second), + DNID: 100, + } + resp := s.handleConnect(req) + assert.Equal(t, pb.ErrorCode_NoError, resp.ErrorCode) + assert.Equal(t, "", resp.ErrorMessage) + } + runServiceTest(t, fn) +} + +func getTestAppendCmd(id uint64, data []byte) []byte { + cmd := make([]byte, len(data)+headerSize+8) + binaryEnc.PutUint16(cmd, userEntryTag) + binaryEnc.PutUint64(cmd[headerSize:], id) + copy(cmd[headerSize+8:], data) + return cmd +} + +func TestServiceHandleAppend(t *testing.T) { + fn := func(t *testing.T, s *Service) { + req := pb.Request{ + Method: pb.MethodType_CONNECT_RO, + ShardID: 1, + Timeout: int64(time.Second), + DNID: 100, + } + resp := s.handleConnect(req) + assert.Equal(t, pb.ErrorCode_NoError, resp.ErrorCode) + assert.Equal(t, "", resp.ErrorMessage) + + data := make([]byte, 8) + cmd := getTestAppendCmd(req.DNID, data) + req = pb.Request{ + Method: pb.MethodType_APPEND, + ShardID: 1, + Timeout: int64(time.Second), + } + resp = s.handleAppend(req, cmd) + assert.Equal(t, pb.ErrorCode_NoError, resp.ErrorCode) + assert.Equal(t, "", resp.ErrorMessage) + assert.Equal(t, uint64(4), resp.Index) + } + runServiceTest(t, fn) +} + +func TestServiceHandleAppendWhenNotBeingTheLeaseHolder(t *testing.T) { + fn := func(t *testing.T, s *Service) { + req := pb.Request{ + Method: pb.MethodType_CONNECT_RO, + ShardID: 1, + Timeout: int64(time.Second), + DNID: 100, + } + resp := s.handleConnect(req) + assert.Equal(t, pb.ErrorCode_NoError, resp.ErrorCode) + assert.Equal(t, "", resp.ErrorMessage) + + data := make([]byte, 8) + cmd := getTestAppendCmd(req.DNID+1, data) + req = pb.Request{ + Method: pb.MethodType_APPEND, + ShardID: 1, + Timeout: int64(time.Second), + } + resp = s.handleAppend(req, cmd) + assert.Equal(t, pb.ErrorCode_NotLeaseHolder, resp.ErrorCode) + assert.Equal(t, "", resp.ErrorMessage) + assert.Equal(t, uint64(0), resp.Index) + } + runServiceTest(t, fn) +} + +func TestServiceHandleRead(t *testing.T) { + fn := func(t *testing.T, s *Service) { + req := pb.Request{ + Method: pb.MethodType_CONNECT_RO, + ShardID: 1, + Timeout: int64(time.Second), + DNID: 100, + } + resp := s.handleConnect(req) + assert.Equal(t, pb.ErrorCode_NoError, resp.ErrorCode) + assert.Equal(t, "", resp.ErrorMessage) + + data := make([]byte, 8) + cmd := getTestAppendCmd(req.DNID, data) + req = pb.Request{ + Method: pb.MethodType_APPEND, + ShardID: 1, + Timeout: int64(time.Second), + } + resp = s.handleAppend(req, cmd) + assert.Equal(t, pb.ErrorCode_NoError, resp.ErrorCode) + assert.Equal(t, "", resp.ErrorMessage) + assert.Equal(t, uint64(4), resp.Index) + + req = pb.Request{ + Method: pb.MethodType_READ, + ShardID: 1, + Timeout: int64(time.Second), + Index: 1, + MaxSize: 1024 * 32, + } + resp, records := s.handleRead(req) + assert.Equal(t, pb.ErrorCode_NoError, resp.ErrorCode) + assert.Equal(t, "", resp.ErrorMessage) + assert.Equal(t, uint64(1), resp.LastIndex) + require.Equal(t, 1, len(records.Records)) + assert.Equal(t, cmd, records.Records[0].Data) + } + runServiceTest(t, fn) +} + +func TestServiceTruncate(t *testing.T) { + fn := func(t *testing.T, s *Service) { + req := pb.Request{ + Method: pb.MethodType_CONNECT_RO, + ShardID: 1, + Timeout: int64(time.Second), + DNID: 100, + } + resp := s.handleConnect(req) + assert.Equal(t, pb.ErrorCode_NoError, resp.ErrorCode) + assert.Equal(t, "", resp.ErrorMessage) + + data := make([]byte, 8) + cmd := getTestAppendCmd(req.DNID, data) + req = pb.Request{ + Method: pb.MethodType_APPEND, + ShardID: 1, + Timeout: int64(time.Second), + } + resp = s.handleAppend(req, cmd) + assert.Equal(t, pb.ErrorCode_NoError, resp.ErrorCode) + assert.Equal(t, "", resp.ErrorMessage) + assert.Equal(t, uint64(4), resp.Index) + + req = pb.Request{ + Method: pb.MethodType_TRUNCATE, + ShardID: 1, + Timeout: int64(time.Second), + Index: 4, + } + resp = s.handleTruncate(req) + assert.Equal(t, pb.ErrorCode_NoError, resp.ErrorCode) + assert.Equal(t, "", resp.ErrorMessage) + assert.Equal(t, uint64(0), resp.Index) + + req = pb.Request{ + Method: pb.MethodType_GET_TRUNCATE, + ShardID: 1, + Timeout: int64(time.Second), + } + resp = s.handleGetTruncatedIndex(req) + assert.Equal(t, pb.ErrorCode_NoError, resp.ErrorCode) + assert.Equal(t, "", resp.ErrorMessage) + assert.Equal(t, uint64(4), resp.Index) + + req = pb.Request{ + Method: pb.MethodType_TRUNCATE, + ShardID: 1, + Timeout: int64(time.Second), + Index: 3, + } + resp = s.handleTruncate(req) + assert.Equal(t, pb.ErrorCode_IndexAlreadyTruncated, resp.ErrorCode) + assert.Equal(t, "", resp.ErrorMessage) + } + runServiceTest(t, fn) +} + +func TestShardInfoCanBeQueried(t *testing.T) { + defer leaktest.AfterTest(t)() + cfg1 := Config{ + FS: vfs.NewStrictMem(), + DeploymentID: 1, + RTTMillisecond: 5, + DataDir: "data-1", + ServiceAddress: "127.0.0.1:9002", + RaftAddress: "127.0.0.1:9000", + GossipAddress: "127.0.0.1:9001", + GossipSeedAddresses: []string{"127.0.0.1:9011"}, + } + cfg2 := Config{ + FS: vfs.NewStrictMem(), + DeploymentID: 1, + RTTMillisecond: 5, + DataDir: "data-2", + ServiceAddress: "127.0.0.1:9012", + RaftAddress: "127.0.0.1:9010", + GossipAddress: "127.0.0.1:9011", + GossipSeedAddresses: []string{"127.0.0.1:9001"}, + } + + service1, err := NewService(cfg1) + require.NoError(t, err) + defer func() { + assert.NoError(t, service1.Close()) + }() + peers1 := make(map[uint64]dragonboat.Target) + peers1[1] = service1.ID() + assert.NoError(t, service1.store.StartReplica(1, 1, peers1)) + + service2, err := NewService(cfg2) + require.NoError(t, err) + defer func() { + assert.NoError(t, service2.Close()) + }() + peers2 := make(map[uint64]dragonboat.Target) + peers2[1] = service2.ID() + assert.NoError(t, service2.store.StartReplica(2, 1, peers2)) + + nhID1 := service1.ID() + nhID2 := service2.ID() + + done := false + for i := 0; i < 3000; i++ { + si1, ok := service1.GetShardInfo(1) + if !ok || si1.LeaderID != 1 { + time.Sleep(time.Millisecond) + continue + } + assert.Equal(t, 1, len(si1.Replicas)) + require.Equal(t, uint64(1), si1.ShardID) + ri, ok := si1.Replicas[1] + assert.True(t, ok) + assert.Equal(t, nhID1, ri.UUID) + assert.Equal(t, cfg1.ServiceAddress, ri.ServiceAddress) + + si2, ok := service1.GetShardInfo(2) + if !ok || si2.LeaderID != 1 { + time.Sleep(time.Millisecond) + continue + } + assert.Equal(t, 1, len(si2.Replicas)) + require.Equal(t, uint64(2), si2.ShardID) + ri, ok = si2.Replicas[1] + assert.True(t, ok) + assert.Equal(t, nhID2, ri.UUID) + assert.Equal(t, cfg2.ServiceAddress, ri.ServiceAddress) + + si1, ok = service2.GetShardInfo(1) + if !ok || si1.LeaderID != 1 { + time.Sleep(time.Millisecond) + continue + } + assert.Equal(t, 1, len(si1.Replicas)) + require.Equal(t, uint64(1), si1.ShardID) + ri, ok = si1.Replicas[1] + assert.True(t, ok) + assert.Equal(t, nhID1, ri.UUID) + assert.Equal(t, cfg1.ServiceAddress, ri.ServiceAddress) + + si2, ok = service2.GetShardInfo(2) + if !ok || si2.LeaderID != 1 { + time.Sleep(time.Millisecond) + continue + } + assert.Equal(t, 1, len(si2.Replicas)) + require.Equal(t, uint64(2), si2.ShardID) + ri, ok = si2.Replicas[1] + assert.True(t, ok) + assert.Equal(t, nhID2, ri.UUID) + assert.Equal(t, cfg2.ServiceAddress, ri.ServiceAddress) + + done = true + } + assert.True(t, done) +} diff --git a/pkg/logservice/shardinfo.go b/pkg/logservice/shardinfo.go new file mode 100644 index 0000000000000..1dd0316e50445 --- /dev/null +++ b/pkg/logservice/shardinfo.go @@ -0,0 +1,63 @@ +// Copyright 2021 - 2022 Matrix Origin +// +// 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 logservice + +import ( + "github.com/matrixorigin/matrixone/pkg/common/moerr" +) + +type ReplicaInfo struct { + UUID string + ServiceAddress string +} + +type ShardInfo struct { + ShardID uint64 + Replicas map[uint64]ReplicaInfo + Epoch uint64 + LeaderID uint64 + Term uint64 +} + +func (s *Service) GetShardInfo(shardID uint64) (ShardInfo, bool) { + r, ok := s.store.nh.GetNodeHostRegistry() + if !ok { + panic(moerr.NewError(moerr.INVALID_STATE, "gossip registry not enabled")) + } + shard, ok := r.GetShardInfo(shardID) + if !ok { + return ShardInfo{}, false + } + result := ShardInfo{ + ShardID: shard.ShardID, + Epoch: shard.ConfigChangeIndex, + LeaderID: shard.LeaderID, + Term: shard.Term, + Replicas: make(map[uint64]ReplicaInfo), + } + for nodeID, uuid := range shard.Nodes { + data, ok := r.GetMeta(uuid) + if !ok { + return ShardInfo{}, false + } + var md logStoreMeta + md.unmarshal(data) + result.Replicas[nodeID] = ReplicaInfo{ + UUID: uuid, + ServiceAddress: md.serviceAddress, + } + } + return result, true +} diff --git a/pkg/logservice/store.go b/pkg/logservice/store.go new file mode 100644 index 0000000000000..4699e5a844937 --- /dev/null +++ b/pkg/logservice/store.go @@ -0,0 +1,517 @@ +// Copyright 2021 - 2022 Matrix Origin +// +// 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 logservice + +import ( + "context" + "sync" + "time" + + "github.com/cockroachdb/errors" + "github.com/lni/dragonboat/v4" + cli "github.com/lni/dragonboat/v4/client" + "github.com/lni/dragonboat/v4/config" + "github.com/lni/dragonboat/v4/raftpb" + sm "github.com/lni/dragonboat/v4/statemachine" + "github.com/lni/goutils/syncutil" + + "github.com/matrixorigin/matrixone/pkg/common/moerr" + "github.com/matrixorigin/matrixone/pkg/hakeeper" + pb "github.com/matrixorigin/matrixone/pkg/pb/logservice" +) + +var ( + ErrInvalidTruncateIndex = moerr.NewError(moerr.INVALID_INPUT, "invalid input") + ErrNotLeaseHolder = moerr.NewError(moerr.INVALID_STATE, "not lease holder") + ErrOutOfRange = moerr.NewError(moerr.INVALID_INPUT, "query out of range") + ErrInvalidShardID = moerr.NewError(moerr.INVALID_INPUT, "invalid shard ID") +) + +type logStoreMeta struct { + serviceAddress string +} + +func (l *logStoreMeta) marshal() []byte { + return []byte(l.serviceAddress) +} + +func (l *logStoreMeta) unmarshal(data []byte) { + l.serviceAddress = string(data) +} + +func getNodeHostConfig(cfg Config) config.NodeHostConfig { + meta := logStoreMeta{ + serviceAddress: cfg.ServiceAddress, + } + return config.NodeHostConfig{ + DeploymentID: cfg.DeploymentID, + NodeHostID: cfg.NodeHostID, + NodeHostDir: cfg.DataDir, + RTTMillisecond: cfg.RTTMillisecond, + AddressByNodeHostID: true, + RaftAddress: cfg.RaftAddress, + ListenAddress: cfg.RaftListenAddress, + Expert: config.ExpertConfig{ + FS: cfg.FS, + // FIXME: dragonboat need to be updated to make this field a first class + // citizen + TestGossipProbeInterval: 50 * time.Millisecond, + }, + Gossip: config.GossipConfig{ + BindAddress: cfg.GossipListenAddress, + AdvertiseAddress: cfg.GossipAddress, + Seed: cfg.GossipSeedAddresses, + Meta: meta.marshal(), + }, + } +} + +func getRaftConfig(shardID uint64, replicaID uint64) config.Config { + return config.Config{ + ShardID: shardID, + ReplicaID: replicaID, + CheckQuorum: true, + PreVote: true, + ElectionRTT: 10, + HeartbeatRTT: 1, + OrderedConfigChange: true, + } +} + +type logStore struct { + cfg Config + nh *dragonboat.NodeHost + haKeeperReplicaID uint64 + stopper *syncutil.Stopper + + mu struct { + sync.Mutex + truncateCh chan struct{} + pendingTruncate map[uint64]struct{} + } +} + +func newLogStore(cfg Config) (*logStore, error) { + nh, err := dragonboat.NewNodeHost(getNodeHostConfig(cfg)) + if err != nil { + return nil, err + } + ls := &logStore{ + cfg: cfg, + nh: nh, + stopper: syncutil.NewStopper(), + } + ls.mu.truncateCh = make(chan struct{}) + ls.mu.pendingTruncate = make(map[uint64]struct{}) + ls.stopper.RunWorker(func() { + ls.truncationWorker() + }) + return ls, nil +} + +func (l *logStore) Close() error { + l.stopper.Stop() + if l.nh != nil { + l.nh.Close() + } + return nil +} + +func (l *logStore) ID() string { + return l.nh.ID() +} + +func (l *logStore) StartHAKeeperReplica(replicaID uint64, + initialReplicas map[uint64]dragonboat.Target) error { + l.haKeeperReplicaID = replicaID + raftConfig := getRaftConfig(hakeeper.DefaultHAKeeperShardID, replicaID) + // TODO: add another API for joining + if err := l.nh.StartReplica(initialReplicas, + false, hakeeper.NewStateMachine, raftConfig); err != nil { + return err + } + l.stopper.RunWorker(func() { + l.ticker() + }) + return nil +} + +func (l *logStore) StartReplica(shardID uint64, replicaID uint64, + initialReplicas map[uint64]dragonboat.Target) error { + if shardID == hakeeper.DefaultHAKeeperShardID { + return ErrInvalidShardID + } + raftConfig := getRaftConfig(shardID, replicaID) + // TODO: add another API for joining + return l.nh.StartReplica(initialReplicas, false, newStateMachine, raftConfig) +} + +func (l *logStore) propose(ctx context.Context, + session *cli.Session, cmd []byte) (sm.Result, error) { + count := 0 + for { + count++ + result, err := l.nh.SyncPropose(ctx, session, cmd) + if err != nil { + if errors.Is(err, dragonboat.ErrShardNotReady) { + time.Sleep(time.Duration(l.nh.NodeHostConfig().RTTMillisecond) * time.Millisecond) + continue + } + if errors.Is(err, dragonboat.ErrTimeoutTooSmall) && count > 1 { + return sm.Result{}, dragonboat.ErrTimeout + } + return sm.Result{}, err + } + return result, nil + } +} + +func (l *logStore) read(ctx context.Context, + shardID uint64, query interface{}) (interface{}, error) { + count := 0 + for { + count++ + result, err := l.nh.SyncRead(ctx, shardID, query) + if err != nil { + if errors.Is(err, dragonboat.ErrShardNotReady) { + time.Sleep(time.Duration(l.nh.NodeHostConfig().RTTMillisecond) * time.Millisecond) + continue + } + if errors.Is(err, dragonboat.ErrTimeoutTooSmall) && count > 1 { + return nil, dragonboat.ErrTimeout + } + return nil, err + } + return result, nil + } +} + +func (l *logStore) GetOrExtendDNLease(ctx context.Context, + shardID uint64, dnID uint64) error { + session := l.nh.GetNoOPSession(shardID) + cmd := getSetLeaseHolderCmd(dnID) + _, err := l.propose(ctx, session, cmd) + return err +} + +func (l *logStore) TruncateLog(ctx context.Context, + shardID uint64, index Lsn) error { + session := l.nh.GetNoOPSession(shardID) + cmd := getSetTruncatedIndexCmd(index) + result, err := l.propose(ctx, session, cmd) + if err != nil { + plog.Errorf("propose truncate log cmd failed, %v", err) + return err + } + if result.Value > 0 { + plog.Errorf("shardID %d already truncated to index %d", shardID, result.Value) + return errors.Wrapf(ErrInvalidTruncateIndex, "already truncated to %d", result.Value) + } + l.mu.Lock() + l.mu.pendingTruncate[shardID] = struct{}{} + l.mu.Unlock() + l.mu.truncateCh <- struct{}{} + return nil +} + +func (l *logStore) Append(ctx context.Context, + shardID uint64, cmd []byte) (Lsn, error) { + if !isUserUpdate(cmd) { + panic(moerr.NewError(moerr.INVALID_INPUT, "not user update")) + } + session := l.nh.GetNoOPSession(shardID) + result, err := l.propose(ctx, session, cmd) + if err != nil { + plog.Errorf("propose failed, %v", err) + return 0, err + } + if len(result.Data) > 0 { + plog.Errorf("not current lease holder (%d)", binaryEnc.Uint64(result.Data)) + return 0, errors.Wrapf(ErrNotLeaseHolder, + "current lease holder ID %d", binaryEnc.Uint64(result.Data)) + } + if result.Value == 0 { + panic(moerr.NewError(moerr.INVALID_STATE, "unexpected Lsn value")) + } + return result.Value, nil +} + +func (l *logStore) GetTruncatedIndex(ctx context.Context, + shardID uint64) (uint64, error) { + v, err := l.read(ctx, shardID, truncatedIndexTag) + if err != nil { + return 0, err + } + return v.(uint64), nil +} + +func (l *logStore) AddLogStoreHeartbeat(ctx context.Context, + hb pb.LogStoreHeartbeat) error { + data := MustMarshal(&hb) + cmd := hakeeper.GetLogStoreHeartbeatCmd(data) + session := l.nh.GetNoOPSession(hakeeper.DefaultHAKeeperShardID) + if _, err := l.propose(ctx, session, cmd); err != nil { + plog.Errorf("propose failed, %v", err) + return err + } + return nil +} + +func (l *logStore) AddDNStoreHeartbeat(ctx context.Context, + hb pb.DNStoreHeartbeat) error { + data := MustMarshal(&hb) + cmd := hakeeper.GetDNStoreHeartbeatCmd(data) + session := l.nh.GetNoOPSession(hakeeper.DefaultHAKeeperShardID) + if _, err := l.propose(ctx, session, cmd); err != nil { + plog.Errorf("propose failed, %v", err) + return err + } + return nil +} + +func (l *logStore) getLeaseHolderID(ctx context.Context, + shardID uint64, entries []raftpb.Entry) (uint64, error) { + if len(entries) == 0 { + panic("empty entries") + } + // first entry is a update lease cmd + e := entries[0] + if isSetLeaseHolderUpdate(e.Cmd) { + return parseLeaseHolderID(e.Cmd), nil + } + v, err := l.read(ctx, shardID, leaseHistoryQuery{index: e.Index}) + if err != nil { + plog.Errorf("failed to read, %v", err) + return 0, err + } + return v.(uint64), nil +} + +func (l *logStore) decodeCmd(e raftpb.Entry) []byte { + if e.Type == raftpb.ApplicationEntry { + panic(moerr.NewError(moerr.INVALID_STATE, "unexpected entry type")) + } + if e.Type == raftpb.EncodedEntry { + if e.Cmd[0] != 0 { + panic(moerr.NewError(moerr.INVALID_STATE, "unexpected cmd header")) + } + return e.Cmd[1:] + } + panic(moerr.NewError(moerr.INVALID_STATE, "invalid cmd")) +} + +func isRaftInternalEntry(e raftpb.Entry) bool { + if len(e.Cmd) == 0 { + return true + } + return e.Type == raftpb.ConfigChangeEntry || e.Type == raftpb.MetadataEntry +} + +func (l *logStore) filterEntries(ctx context.Context, + shardID uint64, entries []raftpb.Entry) ([]LogRecord, error) { + if len(entries) == 0 { + return []LogRecord{}, nil + } + leaseHolderID, err := l.getLeaseHolderID(ctx, shardID, entries) + if err != nil { + return nil, err + } + result := make([]LogRecord, 0) + for _, e := range entries { + if isRaftInternalEntry(e) { + // raft internal stuff + continue + } + cmd := l.decodeCmd(e) + if isSetLeaseHolderUpdate(cmd) { + leaseHolderID = parseLeaseHolderID(cmd) + continue + } + if isUserUpdate(cmd) { + if parseLeaseHolderID(cmd) != leaseHolderID { + // lease not match, skip + continue + } + result = append(result, LogRecord{Data: cmd, Index: e.Index}) + } + } + return result, nil +} + +func getNextIndex(entries []raftpb.Entry, firstIndex Lsn, lastIndex Lsn) Lsn { + if len(entries) == 0 { + return firstIndex + } + lastResultIndex := entries[len(entries)-1].Index + if lastResultIndex+1 < lastIndex { + return lastResultIndex + 1 + } + return firstIndex +} + +func (l *logStore) QueryLog(ctx context.Context, shardID uint64, + firstIndex Lsn, maxSize uint64) ([]LogRecord, Lsn, error) { + v, err := l.read(ctx, shardID, indexTag) + if err != nil { + return nil, 0, err + } + lastIndex := v.(uint64) + // FIXME: check whether lastIndex >= firstIndex + rs, err := l.nh.QueryRaftLog(shardID, firstIndex, lastIndex+1, maxSize) + if err != nil { + plog.Errorf("QueryRaftLog failed, %v", err) + return nil, 0, err + } + select { + case v := <-rs.CompletedC: + if v.Completed() { + entries, logRange := v.RaftLogs() + next := getNextIndex(entries, firstIndex, logRange.LastIndex) + results, err := l.filterEntries(ctx, shardID, entries) + if err != nil { + plog.Errorf("filterEntries failed, %v", err) + return nil, 0, err + } + return results, next, nil + } else if v.RequestOutOfRange() { + plog.Errorf("OutOfRange query found") + return nil, 0, ErrOutOfRange + } + panic(moerr.NewError(moerr.INVALID_STATE, "unexpected rs state")) + case <-ctx.Done(): + return nil, 0, ctx.Err() + } +} + +func (l *logStore) ticker() { + ticker := time.NewTicker(hakeeper.TickDuration) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + if err := l.hakeeperTick(); err != nil { + panic(err) + } + case <-l.stopper.ShouldStop(): + return + } + } +} + +func (l *logStore) truncationWorker() { + for { + select { + case <-l.stopper.ShouldStop(): + return + case <-l.mu.truncateCh: + if err := l.truncateLog(); err != nil { + panic(err) + } + } + } +} + +// TODO: add test for this +// FIXME: ignore temp errors +func (l *logStore) hakeeperTick() error { + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + leaderID, ok, err := l.nh.GetLeaderID(hakeeper.DefaultHAKeeperShardID) + if err != nil { + plog.Errorf("failed to get HAKeeper Leader ID, %v", err) + return err + } + if ok && leaderID == l.haKeeperReplicaID { + cmd := hakeeper.GetTickCmd() + session := l.nh.GetNoOPSession(hakeeper.DefaultHAKeeperShardID) + if _, err := l.propose(ctx, session, cmd); err != nil { + plog.Errorf("propose failed, %v", err) + return err + } + } + return nil +} + +// TODO: add tests for this +func (l *logStore) truncateLog() error { + l.mu.Lock() + pendings := l.mu.pendingTruncate + l.mu.pendingTruncate = make(map[uint64]struct{}) + l.mu.Unlock() + + for shardID := range pendings { + select { + case <-l.stopper.ShouldStop(): + return nil + default: + } + + if err := func() error { + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() + index, err := l.GetTruncatedIndex(ctx, shardID) + if err != nil { + plog.Errorf("GetTruncatedIndex failed, %v", err) + // FIXME: check error type, see whether it is a tmp one + return err + } + // the first 4 entries for a 3-replica raft group are tiny anyway + if index > 1 { + opts := dragonboat.SnapshotOption{ + OverrideCompactionOverhead: true, + CompactionIndex: index - 1, + } + if _, err := l.nh.SyncRequestSnapshot(ctx, shardID, opts); err != nil { + plog.Errorf("SyncRequestSnapshot failed, %v", err) + // FIXME: check error type, see whether it is a tmp one + return err + } + } + return nil + }(); err != nil { + return err + } + } + return nil +} + +func (l *logStore) getHeartbeatMessage() pb.LogStoreHeartbeat { + m := pb.LogStoreHeartbeat{ + UUID: l.cfg.NodeHostID, + RaftAddress: l.cfg.RaftAddress, + ServiceAddress: l.cfg.ServiceAddress, + GossipAddress: l.cfg.GossipAddress, + Shards: make([]pb.LogShardInfo, 0), + } + opts := dragonboat.NodeHostInfoOption{ + SkipLogInfo: true, + } + nhi := l.nh.GetNodeHostInfo(opts) + for _, ci := range nhi.ShardInfoList { + shardInfo := pb.LogShardInfo{ + ShardID: ci.ShardID, + Replicas: ci.Nodes, + Epoch: ci.ConfigChangeIndex, + LeaderID: ci.LeaderID, + Term: ci.Term, + } + if shardInfo.Replicas == nil { + shardInfo.Replicas = make(map[uint64]dragonboat.Target) + } + m.Shards = append(m.Shards, shardInfo) + } + return m +} diff --git a/pkg/logservice/store_test.go b/pkg/logservice/store_test.go new file mode 100644 index 0000000000000..46668840004c8 --- /dev/null +++ b/pkg/logservice/store_test.go @@ -0,0 +1,286 @@ +// Copyright 2021 - 2022 Matrix Origin +// +// 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 logservice + +import ( + "context" + "math" + "testing" + "time" + + "github.com/cockroachdb/errors" + "github.com/lni/dragonboat/v4" + "github.com/lni/goutils/leaktest" + "github.com/lni/vfs" + "github.com/stretchr/testify/assert" + + pb "github.com/matrixorigin/matrixone/pkg/pb/logservice" +) + +var ( + testIOTimeout = 5 * time.Second +) + +func TestNodeHostConfig(t *testing.T) { + cfg := Config{ + DeploymentID: 1234, + DataDir: "lalala", + } + nhConfig := getNodeHostConfig(cfg) + assert.Equal(t, cfg.DeploymentID, nhConfig.DeploymentID) + assert.Equal(t, cfg.DataDir, nhConfig.NodeHostDir) + assert.True(t, nhConfig.AddressByNodeHostID) +} + +func TestRaftConfig(t *testing.T) { + cfg := getRaftConfig(1, 1) + assert.True(t, cfg.CheckQuorum) + assert.True(t, cfg.OrderedConfigChange) +} + +func getStoreTestConfig() Config { + cfg := Config{ + RTTMillisecond: 10, + GossipSeedAddresses: []string{"127.0.0.1:9000"}, + DeploymentID: 1, + FS: vfs.NewStrictMem(), + } + cfg.Fill() + return cfg +} + +func TestStoreCanBeCreatedAndClosed(t *testing.T) { + defer leaktest.AfterTest(t)() + cfg := getStoreTestConfig() + defer vfs.ReportLeakedFD(cfg.FS, t) + store, err := newLogStore(cfg) + assert.NoError(t, err) + defer func() { + assert.NoError(t, store.Close()) + }() +} + +func getTestStore(cfg Config) (*logStore, error) { + store, err := newLogStore(cfg) + if err != nil { + return nil, err + } + peers := make(map[uint64]dragonboat.Target) + peers[2] = store.nh.ID() + if err := store.StartReplica(1, 2, peers); err != nil { + store.Close() + return nil, err + } + return store, nil +} + +func TestHAKeeperCanBeStarted(t *testing.T) { + defer leaktest.AfterTest(t)() + cfg := getStoreTestConfig() + defer vfs.ReportLeakedFD(cfg.FS, t) + store, err := newLogStore(cfg) + assert.NoError(t, err) + peers := make(map[uint64]dragonboat.Target) + peers[2] = store.nh.ID() + assert.NoError(t, store.StartHAKeeperReplica(2, peers)) + defer func() { + assert.NoError(t, store.Close()) + }() +} + +func TestStateMachineCanBeStarted(t *testing.T) { + defer leaktest.AfterTest(t)() + cfg := getStoreTestConfig() + defer vfs.ReportLeakedFD(cfg.FS, t) + store, err := getTestStore(cfg) + assert.NoError(t, err) + defer func() { + assert.NoError(t, store.Close()) + }() +} + +func runStoreTest(t *testing.T, fn func(*testing.T, *logStore)) { + defer leaktest.AfterTest(t)() + cfg := getStoreTestConfig() + defer vfs.ReportLeakedFD(cfg.FS, t) + store, err := getTestStore(cfg) + assert.NoError(t, err) + defer func() { + assert.NoError(t, store.Close()) + }() + fn(t, store) +} + +func getTestUserEntry() []byte { + cmd := make([]byte, 2+8+8) + binaryEnc.PutUint16(cmd, userEntryTag) + binaryEnc.PutUint64(cmd[headerSize:], 100) + binaryEnc.PutUint64(cmd[headerSize+8:], 1234567890) + return cmd +} + +func TestGetOrExtendLease(t *testing.T) { + fn := func(t *testing.T, store *logStore) { + ctx, cancel := context.WithTimeout(context.Background(), testIOTimeout) + defer cancel() + assert.NoError(t, store.GetOrExtendDNLease(ctx, 1, 100)) + } + runStoreTest(t, fn) +} + +func TestAppendLog(t *testing.T) { + fn := func(t *testing.T, store *logStore) { + ctx, cancel := context.WithTimeout(context.Background(), testIOTimeout) + defer cancel() + assert.NoError(t, store.GetOrExtendDNLease(ctx, 1, 100)) + cmd := getTestUserEntry() + lsn, err := store.Append(ctx, 1, cmd) + assert.NoError(t, err) + assert.Equal(t, uint64(4), lsn) + } + runStoreTest(t, fn) +} + +func TestAppendLogIsRejectedForMismatchedLeaseHolderID(t *testing.T) { + fn := func(t *testing.T, store *logStore) { + ctx, cancel := context.WithTimeout(context.Background(), testIOTimeout) + defer cancel() + assert.NoError(t, store.GetOrExtendDNLease(ctx, 1, 100)) + cmd := make([]byte, 2+8+8) + binaryEnc.PutUint16(cmd, userEntryTag) + binaryEnc.PutUint64(cmd[headerSize:], 101) + binaryEnc.PutUint64(cmd[headerSize+8:], 1234567890) + _, err := store.Append(ctx, 1, cmd) + assert.True(t, errors.Is(err, ErrNotLeaseHolder)) + } + runStoreTest(t, fn) +} + +func TestTruncateLog(t *testing.T) { + fn := func(t *testing.T, store *logStore) { + ctx, cancel := context.WithTimeout(context.Background(), testIOTimeout) + defer cancel() + assert.NoError(t, store.GetOrExtendDNLease(ctx, 1, 100)) + cmd := getTestUserEntry() + _, err := store.Append(ctx, 1, cmd) + assert.NoError(t, err) + assert.NoError(t, store.TruncateLog(ctx, 1, 4)) + err = store.TruncateLog(ctx, 1, 3) + assert.True(t, errors.Is(err, ErrInvalidTruncateIndex)) + } + runStoreTest(t, fn) +} + +func TestGetTruncatedIndex(t *testing.T) { + fn := func(t *testing.T, store *logStore) { + ctx, cancel := context.WithTimeout(context.Background(), testIOTimeout) + defer cancel() + index, err := store.GetTruncatedIndex(ctx, 1) + assert.Equal(t, uint64(0), index) + assert.NoError(t, err) + assert.NoError(t, store.GetOrExtendDNLease(ctx, 1, 100)) + cmd := getTestUserEntry() + _, err = store.Append(ctx, 1, cmd) + assert.NoError(t, err) + assert.NoError(t, store.TruncateLog(ctx, 1, 4)) + index, err = store.GetTruncatedIndex(ctx, 1) + assert.Equal(t, uint64(4), index) + assert.NoError(t, err) + } + runStoreTest(t, fn) +} + +func TestQueryLog(t *testing.T) { + fn := func(t *testing.T, store *logStore) { + ctx, cancel := context.WithTimeout(context.Background(), testIOTimeout) + defer cancel() + assert.NoError(t, store.GetOrExtendDNLease(ctx, 1, 100)) + cmd := getTestUserEntry() + _, err := store.Append(ctx, 1, cmd) + assert.NoError(t, err) + entries, lsn, err := store.QueryLog(ctx, 1, 4, math.MaxUint64) + assert.NoError(t, err) + assert.Equal(t, 1, len(entries)) + assert.Equal(t, uint64(4), lsn) + assert.Equal(t, entries[0].Data, cmd) + // lease holder ID update cmd at entry index 3 + entries, lsn, err = store.QueryLog(ctx, 1, 3, math.MaxUint64) + assert.NoError(t, err) + assert.Equal(t, 1, len(entries)) + assert.Equal(t, uint64(3), lsn) + assert.Equal(t, entries[0].Data, cmd) + // size limited + _, err = store.Append(ctx, 1, cmd) + assert.NoError(t, err) + entries, lsn, err = store.QueryLog(ctx, 1, 4, 1) + assert.NoError(t, err) + assert.Equal(t, 1, len(entries)) + assert.Equal(t, uint64(5), lsn) + assert.Equal(t, entries[0].Data, cmd) + // more log available + entries, lsn, err = store.QueryLog(ctx, 1, 5, 1) + assert.NoError(t, err) + assert.Equal(t, 1, len(entries)) + assert.Equal(t, uint64(5), lsn) + assert.Equal(t, entries[0].Data, cmd) + } + runStoreTest(t, fn) +} + +func TestHAKeeperTick(t *testing.T) { + fn := func(t *testing.T, store *logStore) { + peers := make(map[uint64]dragonboat.Target) + peers[1] = store.ID() + assert.NoError(t, store.StartHAKeeperReplica(1, peers)) + + assert.NoError(t, store.hakeeperTick()) + } + runStoreTest(t, fn) +} + +func TestGetHeartbeatMessage(t *testing.T) { + fn := func(t *testing.T, store *logStore) { + peers := make(map[uint64]dragonboat.Target) + peers[1] = store.ID() + assert.NoError(t, store.StartReplica(10, 1, peers)) + assert.NoError(t, store.StartHAKeeperReplica(1, peers)) + + m := store.getHeartbeatMessage() + // hakeeper shard is included + assert.Equal(t, 3, len(m.Shards)) + } + runStoreTest(t, fn) +} + +func TestAddHeartbeat(t *testing.T) { + fn := func(t *testing.T, store *logStore) { + peers := make(map[uint64]dragonboat.Target) + peers[1] = store.ID() + assert.NoError(t, store.StartHAKeeperReplica(1, peers)) + + m := store.getHeartbeatMessage() + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + assert.NoError(t, store.AddLogStoreHeartbeat(ctx, m)) + + dnMsg := pb.DNStoreHeartbeat{ + UUID: store.ID(), + Shards: make([]pb.DNShardInfo, 0), + } + dnMsg.Shards = append(dnMsg.Shards, pb.DNShardInfo{ShardID: 2, ReplicaID: 3}) + assert.NoError(t, store.AddDNStoreHeartbeat(ctx, dnMsg)) + } + runStoreTest(t, fn) +} diff --git a/pkg/logservice/transport.go b/pkg/logservice/transport.go new file mode 100644 index 0000000000000..44ed870af43e0 --- /dev/null +++ b/pkg/logservice/transport.go @@ -0,0 +1,321 @@ +// Copyright 2021 - 2022 Matrix Origin +// +// 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 logservice + +import ( + "bytes" + "context" + "io" + "net" + "time" + + "github.com/matrixorigin/matrixone/pkg/common/moerr" + pb "github.com/matrixorigin/matrixone/pkg/pb/logservice" +) + +var ( + ErrInvalidBuffer = moerr.NewError(moerr.INVALID_STATE, "invalid buffer size") + ErrBadMessage = moerr.NewError(moerr.INVALID_INPUT, "invalid message") + errPoisonReceived = moerr.NewError(moerr.INVALID_STATE, "poison received") + ErrDeadlineNotSet = moerr.NewError(moerr.INVALID_INPUT, "deadline not set") + ErrInvalidDeadline = moerr.NewError(moerr.INVALID_INPUT, "invalid deadline") + + magicNumber = [2]byte{0x2A, 0xBD} + poisonNumber = [2]byte{0x2B, 0xBE} + requestSendDuration = 2 * time.Second + requestReadDuration = 2 * time.Second + responseSendDuration = 2 * time.Second + responseReadDuration = 2 * time.Second + writeDuration = 10 * time.Second + readDuration = 10 * time.Second + keepAlivePeriod = 5 * time.Second + + reqBufSize = 2 * 1024 + recvBufSize = 512 * 1024 +) + +func sendPoison(conn net.Conn, poison []byte) error { + tt := time.Now().Add(requestSendDuration) + if err := conn.SetWriteDeadline(tt); err != nil { + return err + } + if _, err := conn.Write(poison); err != nil { + return err + } + return nil +} + +func sendPoisonAck(conn net.Conn, poisonAck []byte) error { + return sendPoison(conn, poisonAck) +} + +func waitPoisonAck(conn net.Conn) error { + ack := make([]byte, len(poisonNumber)) + tt := time.Now().Add(keepAlivePeriod) + if err := conn.SetReadDeadline(tt); err != nil { + return err + } + if _, err := io.ReadFull(conn, ack); err != nil { + return err + } + return nil +} + +func readSize(conn net.Conn, buf []byte) (int, error) { + if len(buf) < 4 { + buf = make([]byte, 4) + } + szbuf := buf[:4] + tt := time.Now().Add(requestReadDuration) + if err := conn.SetWriteDeadline(tt); err != nil { + return 0, err + } + if _, err := io.ReadFull(conn, szbuf); err != nil { + return 0, err + } + return int(binaryEnc.Uint32(szbuf)), nil +} + +// FIXME: add data corruption check +func writeRequest(conn net.Conn, + req pb.Request, buf []byte, payload []byte) error { + if len(buf) < req.Size()+4+len(magicNumber[:]) { + buf = make([]byte, req.Size()+4+len(magicNumber[:])) + } + n, err := req.MarshalTo(buf[4+len(magicNumber[:]):]) + if err != nil { + panic(err) + } + + copy(buf, magicNumber[:]) + binaryEnc.PutUint32(buf[len(magicNumber[:]):], uint32(n)) + buf = buf[:n+4+len(magicNumber[:])] + + tt := time.Now().Add(requestSendDuration) + if err := conn.SetWriteDeadline(tt); err != nil { + return err + } + if _, err := conn.Write(buf); err != nil { + return err + } + if len(payload) > 0 { + tt = time.Now().Add(writeDuration) + if err := conn.SetWriteDeadline(tt); err != nil { + return err + } + if _, err := conn.Write(payload); err != nil { + return err + } + } + return nil +} + +func readRequest(conn net.Conn, + buf []byte, payload []byte) (pb.Request, []byte, error) { + size, err := readSize(conn, buf) + if err != nil { + return pb.Request{}, nil, err + } + if len(buf) < size { + buf = make([]byte, size) + } + buf = buf[:size] + if _, err := io.ReadFull(conn, buf); err != nil { + return pb.Request{}, nil, err + } + var req pb.Request + MustUnmarshal(&req, buf) + if req.PayloadSize > 0 { + if uint64(len(payload)) < req.PayloadSize { + payload = make([]byte, req.PayloadSize) + } + payload = payload[:req.PayloadSize] + tt := time.Now().Add(readDuration) + if err := conn.SetWriteDeadline(tt); err != nil { + return pb.Request{}, nil, err + } + if _, err := io.ReadFull(conn, payload); err != nil { + return pb.Request{}, nil, err + } + } + return req, payload, nil +} + +func writeResponse(conn net.Conn, resp pb.Response, + records []byte, buf []byte) error { + if len(buf) < resp.Size()+4 { + buf = make([]byte, resp.Size()+4) + } + if resp.PayloadSize != uint64(len(records)) { + panic("Payload size not set") + } + + n, err := resp.MarshalTo(buf[4:]) + if err != nil { + panic(err) + } + buf = buf[:n+4] + binaryEnc.PutUint32(buf, uint32(n)) + + tt := time.Now().Add(responseSendDuration) + if err := conn.SetWriteDeadline(tt); err != nil { + return err + } + if _, err := conn.Write(buf); err != nil { + return err + } + + if len(records) > 0 { + sent := 0 + bufSize := int(recvBufSize) + for sent < len(records) { + if sent+bufSize > len(records) { + bufSize = len(records) - sent + } + tt = time.Now().Add(writeDuration) + if err := conn.SetWriteDeadline(tt); err != nil { + return err + } + if _, err := conn.Write(records[sent : sent+bufSize]); err != nil { + return err + } + sent += bufSize + } + } + + return nil +} + +func readResponse(conn net.Conn, + buf []byte) (pb.Response, pb.LogRecordResponse, error) { + size, err := readSize(conn, buf) + if err != nil { + return pb.Response{}, pb.LogRecordResponse{}, err + } + + if len(buf) < size { + buf = make([]byte, size) + } + buf = buf[:size] + + tt := time.Now().Add(responseReadDuration) + if err := conn.SetReadDeadline(tt); err != nil { + return pb.Response{}, pb.LogRecordResponse{}, err + } + if _, err := io.ReadFull(conn, buf); err != nil { + return pb.Response{}, pb.LogRecordResponse{}, err + } + var resp pb.Response + MustUnmarshal(&resp, buf) + size = int(resp.PayloadSize) + if size > len(buf) { + buf = make([]byte, size) + } else { + buf = buf[:size] + } + + received := uint64(0) + var recvBuf []byte + if size < recvBufSize { + recvBuf = buf[:size] + } else { + recvBuf = buf[:recvBufSize] + } + toRead := size + for toRead > 0 { + tt = time.Now().Add(readDuration) + if err := conn.SetReadDeadline(tt); err != nil { + return pb.Response{}, pb.LogRecordResponse{}, err + } + if _, err := io.ReadFull(conn, recvBuf); err != nil { + return pb.Response{}, pb.LogRecordResponse{}, err + } + toRead -= len(recvBuf) + received += uint64(len(recvBuf)) + if toRead < recvBufSize { + recvBuf = buf[received : received+uint64(toRead)] + } else { + recvBuf = buf[received : received+uint64(recvBufSize)] + } + } + + var logs pb.LogRecordResponse + MustUnmarshal(&logs, buf) + + return resp, logs, nil +} + +func readMagicNumber(conn net.Conn, buf []byte) error { + tt := time.Now().Add(requestReadDuration) + if err := conn.SetReadDeadline(tt); err != nil { + return err + } + if len(buf) < len(magicNumber[:]) { + buf = make([]byte, len(magicNumber[:])) + } + buf = buf[:len(magicNumber[:])] + if _, err := io.ReadFull(conn, buf); err != nil { + return err + } + if bytes.Equal(buf, poisonNumber[:]) { + return errPoisonReceived + } + if !bytes.Equal(buf, magicNumber[:]) { + return ErrBadMessage + } + return nil +} + +func getConnection(ctx context.Context, target string) (net.Conn, error) { + timeout, err := getTimeoutFromContext(ctx) + if err != nil { + return nil, err + } + conn, err := net.DialTimeout("tcp", target, timeout) + if err != nil { + return nil, err + } + tcpconn, ok := conn.(*net.TCPConn) + if ok { + if err := setTCPConn(tcpconn); err != nil { + return nil, err + } + } else { + panic("unexpected connection type") + } + return conn, nil +} + +func setTCPConn(conn *net.TCPConn) error { + if err := conn.SetLinger(0); err != nil { + return err + } + if err := conn.SetKeepAlive(true); err != nil { + return err + } + return conn.SetKeepAlivePeriod(keepAlivePeriod) +} + +func getTimeoutFromContext(ctx context.Context) (time.Duration, error) { + d, ok := ctx.Deadline() + if !ok { + return 0, ErrDeadlineNotSet + } + now := time.Now() + if now.After(d) { + return 0, ErrInvalidDeadline + } + return d.Sub(now), nil +} diff --git a/pkg/logservice/transport_test.go b/pkg/logservice/transport_test.go new file mode 100644 index 0000000000000..d51c8be7a0125 --- /dev/null +++ b/pkg/logservice/transport_test.go @@ -0,0 +1,263 @@ +// Copyright 2021 - 2022 Matrix Origin +// +// 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 logservice + +import ( + "bytes" + "context" + "math/rand" + "net" + "testing" + "time" + + "github.com/stretchr/testify/assert" + + pb "github.com/matrixorigin/matrixone/pkg/pb/logservice" +) + +type testConn struct { + buf bytes.Buffer +} + +var _ net.Conn = (*testConn)(nil) + +func newTestConn() *testConn { + return &testConn{} +} + +func (t *testConn) Read(data []byte) (int, error) { + return t.buf.Read(data) +} + +func (t *testConn) Write(data []byte) (int, error) { + return t.buf.Write(data) +} + +func (t *testConn) Close() error { + return nil +} + +func (t *testConn) LocalAddr() net.Addr { + panic("not implemented") +} + +func (t *testConn) RemoteAddr() net.Addr { + panic("not implemented") +} + +func (t *testConn) SetDeadline(tt time.Time) error { + return nil +} + +func (t *testConn) SetReadDeadline(tt time.Time) error { + return nil +} + +func (t *testConn) SetWriteDeadline(tt time.Time) error { + return nil +} + +func TestSendPoisonAndAck(t *testing.T) { + conn := newTestConn() + assert.NoError(t, sendPoison(conn, poisonNumber[:])) + data := conn.buf.Bytes() + assert.Equal(t, poisonNumber[:], data) + + conn = newTestConn() + assert.NoError(t, sendPoisonAck(conn, poisonNumber[:])) + data = conn.buf.Bytes() + assert.Equal(t, poisonNumber[:], data) +} + +func TestReadSize(t *testing.T) { + conn := newTestConn() + szbuf := make([]byte, 4) + sz := uint32(12345) + binaryEnc.PutUint32(szbuf, sz) + _, err := conn.Write(szbuf) + assert.NoError(t, err) + + result, err := readSize(conn, nil) + assert.Equal(t, int(sz), result) + assert.NoError(t, err) +} + +func TestWriteRequest(t *testing.T) { + conn := newTestConn() + req := pb.Request{ + Method: pb.MethodType_APPEND, + Name: "test", + DNID: 1234567890, + PayloadSize: 32, + } + payload := make([]byte, 32) + rand.Read(payload) + err := writeRequest(conn, req, nil, payload) + assert.NoError(t, err) + + result := make([]byte, req.Size()+4+len(magicNumber[:])) + n, err := conn.Read(result) + assert.NoError(t, err) + assert.Equal(t, req.Size()+4+len(magicNumber[:]), n) + + assert.Equal(t, magicNumber[:], result[:len(magicNumber[:])]) + sz := binaryEnc.Uint32(result[len(magicNumber[:]):]) + assert.Equal(t, int(sz), req.Size()) + + data := MustMarshal(&req) + assert.Equal(t, data, result[len(magicNumber[:])+4:]) +} + +func TestReadRequest(t *testing.T) { + conn := newTestConn() + req := pb.Request{ + Method: pb.MethodType_APPEND, + Name: "test", + PayloadSize: 32, + } + payload := make([]byte, 32) + rand.Read(payload) + err := writeRequest(conn, req, nil, payload) + assert.NoError(t, err) + + mn := make([]byte, len(magicNumber[:])) + _, err = conn.Read(mn) + assert.NoError(t, err) + assert.Equal(t, magicNumber[:], mn) + + reqResult, payloadResult, err := readRequest(conn, nil, nil) + assert.NoError(t, err) + assert.Equal(t, req, reqResult) + assert.Equal(t, payload, payloadResult) +} + +func TestWriteResponse(t *testing.T) { + testWriteResponse(t, recvBufSize) + testWriteResponse(t, recvBufSize-1) + testWriteResponse(t, recvBufSize+1) + testWriteResponse(t, recvBufSize*3) + testWriteResponse(t, recvBufSize*3-1) + testWriteResponse(t, recvBufSize*3+1) +} + +func testWriteResponse(t *testing.T, sz int) { + conn := newTestConn() + resp := pb.Response{ + Method: pb.MethodType_APPEND, + ShardID: 1234567890, + LastIndex: 234567890, + } + assert.NoError(t, writeResponse(conn, resp, nil, nil)) + + szbuf := make([]byte, 4) + _, err := conn.Read(szbuf) + assert.NoError(t, err) + assert.Equal(t, resp.Size(), int(binaryEnc.Uint32(szbuf))) + data := make([]byte, binaryEnc.Uint32(szbuf)) + _, err = conn.Read(data) + assert.NoError(t, err) + var respResult pb.Response + assert.NoError(t, respResult.Unmarshal(data)) + assert.Equal(t, resp, respResult) + + records := pb.LogRecordResponse{ + Records: []pb.LogRecord{ + {Data: make([]byte, sz)}, + }, + } + rand.Read(records.Records[0].Data) + conn = newTestConn() + recs := MustMarshal(&records) + resp.PayloadSize = uint64(len(recs)) + assert.NoError(t, writeResponse(conn, resp, recs, nil)) + + ignored := make([]byte, 4+resp.Size()) + _, err = conn.Read(ignored) + assert.NoError(t, err) + + data = make([]byte, resp.PayloadSize) + _, err = conn.Read(data) + assert.NoError(t, err) + recordsResult := pb.LogRecordResponse{} + assert.NoError(t, recordsResult.Unmarshal(data)) + assert.Equal(t, records, recordsResult) +} + +func TestReadResponse(t *testing.T) { + testReadResponse(t, recvBufSize-1) + testReadResponse(t, recvBufSize+1) + testReadResponse(t, recvBufSize*3) + testReadResponse(t, recvBufSize*3-1) + testReadResponse(t, recvBufSize*3+1) +} + +func testReadResponse(t *testing.T, sz int) { + conn := newTestConn() + resp := pb.Response{ + Method: pb.MethodType_APPEND, + ShardID: 1234567890, + LastIndex: 234567890, + } + assert.NoError(t, writeResponse(conn, resp, nil, nil)) + respResult, recordsResult, err := readResponse(conn, nil) + assert.NoError(t, err) + assert.Equal(t, resp, respResult) + assert.Equal(t, pb.LogRecordResponse{}, recordsResult) + + records := pb.LogRecordResponse{ + Records: []pb.LogRecord{ + {Data: make([]byte, sz)}, + }, + } + recs := MustMarshal(&records) + resp.PayloadSize = uint64(len(recs)) + assert.NoError(t, writeResponse(conn, resp, recs, nil)) + respResult, recordsResult, err = readResponse(conn, nil) + assert.NoError(t, err) + assert.Equal(t, resp, respResult) + assert.Equal(t, records, recordsResult) +} + +func TestReadMagicNumber(t *testing.T) { + conn := newTestConn() + _, err := conn.Write([]byte{0, 0}) + assert.NoError(t, err) + assert.Equal(t, ErrBadMessage, readMagicNumber(conn, nil)) + + conn = newTestConn() + _, err = conn.Write(magicNumber[:]) + assert.NoError(t, err) + assert.NoError(t, readMagicNumber(conn, nil)) + + conn = newTestConn() + _, err = conn.Write(poisonNumber[:]) + assert.NoError(t, err) + assert.Equal(t, errPoisonReceived, readMagicNumber(conn, nil)) +} + +func TestGetTimeoutFromContext(t *testing.T) { + _, err := getTimeoutFromContext(context.Background()) + assert.Equal(t, ErrDeadlineNotSet, err) + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + d, err := getTimeoutFromContext(ctx) + assert.NoError(t, err) + assert.True(t, d > 55*time.Second) + ctx1, cancel1 := context.WithTimeout(context.Background(), time.Microsecond) + defer cancel1() + time.Sleep(time.Millisecond) + _, err = getTimeoutFromContext(ctx1) + assert.Equal(t, ErrInvalidDeadline, err) +} diff --git a/pkg/logservice/utils.go b/pkg/logservice/utils.go new file mode 100644 index 0000000000000..ff96f570375ac --- /dev/null +++ b/pkg/logservice/utils.go @@ -0,0 +1,37 @@ +// Copyright 2021 - 2022 Matrix Origin +// +// 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 logservice + +type Marshaler interface { + Marshal() ([]byte, error) +} + +type Unmarshaler interface { + Unmarshal([]byte) error +} + +func MustMarshal(m Marshaler) []byte { + data, err := m.Marshal() + if err != nil { + panic(err) + } + return data +} + +func MustUnmarshal(m Unmarshaler, data []byte) { + if err := m.Unmarshal(data); err != nil { + panic(err) + } +} diff --git a/pkg/pb/logservice/logservice.pb.go b/pkg/pb/logservice/logservice.pb.go new file mode 100644 index 0000000000000..68637af359caa --- /dev/null +++ b/pkg/pb/logservice/logservice.pb.go @@ -0,0 +1,3278 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: logservice.proto + +package logservice + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type MethodType int32 + +const ( + MethodType_CREATE MethodType = 0 + MethodType_DESTROY MethodType = 1 + MethodType_APPEND MethodType = 2 + MethodType_READ MethodType = 3 + MethodType_TRUNCATE MethodType = 4 + MethodType_GET_TRUNCATE MethodType = 5 + MethodType_CONNECT MethodType = 6 + MethodType_CONNECT_RO MethodType = 7 +) + +var MethodType_name = map[int32]string{ + 0: "CREATE", + 1: "DESTROY", + 2: "APPEND", + 3: "READ", + 4: "TRUNCATE", + 5: "GET_TRUNCATE", + 6: "CONNECT", + 7: "CONNECT_RO", +} + +var MethodType_value = map[string]int32{ + "CREATE": 0, + "DESTROY": 1, + "APPEND": 2, + "READ": 3, + "TRUNCATE": 4, + "GET_TRUNCATE": 5, + "CONNECT": 6, + "CONNECT_RO": 7, +} + +func (x MethodType) String() string { + return proto.EnumName(MethodType_name, int32(x)) +} + +func (MethodType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_fd1040c5381ab5a7, []int{0} +} + +type ErrorCode int32 + +const ( + ErrorCode_NoError ErrorCode = 0 + ErrorCode_Timeout ErrorCode = 1 + ErrorCode_Canceled ErrorCode = 2 + ErrorCode_InvalidShard ErrorCode = 3 + ErrorCode_InvalidTimeout ErrorCode = 4 + ErrorCode_InvalidPayload ErrorCode = 5 + ErrorCode_InvalidPayloadSize ErrorCode = 6 + ErrorCode_Rejected ErrorCode = 7 + ErrorCode_ShardNotReady ErrorCode = 8 + ErrorCode_SystemClosed ErrorCode = 9 + ErrorCode_IndexAlreadyTruncated ErrorCode = 100 + ErrorCode_OutOfRange ErrorCode = 101 + ErrorCode_NotLeaseHolder ErrorCode = 102 + ErrorCode_OtherSystemError ErrorCode = 1000 +) + +var ErrorCode_name = map[int32]string{ + 0: "NoError", + 1: "Timeout", + 2: "Canceled", + 3: "InvalidShard", + 4: "InvalidTimeout", + 5: "InvalidPayload", + 6: "InvalidPayloadSize", + 7: "Rejected", + 8: "ShardNotReady", + 9: "SystemClosed", + 100: "IndexAlreadyTruncated", + 101: "OutOfRange", + 102: "NotLeaseHolder", + 1000: "OtherSystemError", +} + +var ErrorCode_value = map[string]int32{ + "NoError": 0, + "Timeout": 1, + "Canceled": 2, + "InvalidShard": 3, + "InvalidTimeout": 4, + "InvalidPayload": 5, + "InvalidPayloadSize": 6, + "Rejected": 7, + "ShardNotReady": 8, + "SystemClosed": 9, + "IndexAlreadyTruncated": 100, + "OutOfRange": 101, + "NotLeaseHolder": 102, + "OtherSystemError": 1000, +} + +func (x ErrorCode) String() string { + return proto.EnumName(ErrorCode_name, int32(x)) +} + +func (ErrorCode) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_fd1040c5381ab5a7, []int{1} +} + +type ShardState_State int32 + +const ( + ShardState_REGISTERED ShardState_State = 0 + ShardState_LAUNCHING ShardState_State = 1 + ShardState_LAUNCHED ShardState_State = 2 + ShardState_ABORTED ShardState_State = 3 +) + +var ShardState_State_name = map[int32]string{ + 0: "REGISTERED", + 1: "LAUNCHING", + 2: "LAUNCHED", + 3: "ABORTED", +} + +var ShardState_State_value = map[string]int32{ + "REGISTERED": 0, + "LAUNCHING": 1, + "LAUNCHED": 2, + "ABORTED": 3, +} + +func (x ShardState_State) String() string { + return proto.EnumName(ShardState_State_name, int32(x)) +} + +func (ShardState_State) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_fd1040c5381ab5a7, []int{0, 0} +} + +// ShardState represents the state of a registered Shard. +type ShardState struct { + Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"` + ShardID uint64 `protobuf:"varint,2,opt,name=ShardID,proto3" json:"ShardID,omitempty"` + LaunchState ShardState_State `protobuf:"varint,3,opt,name=LaunchState,proto3,enum=logservice.ShardState_State" json:"LaunchState,omitempty"` + // InitialReplicas is a map of ReplicaID to LogStore UUIDs, it describes the + // initial replicas assigned for the given shard. + InitialReplicas map[uint64]string `protobuf:"bytes,4,rep,name=InitialReplicas,proto3" json:"InitialReplicas,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ShardState) Reset() { *m = ShardState{} } +func (m *ShardState) String() string { return proto.CompactTextString(m) } +func (*ShardState) ProtoMessage() {} +func (*ShardState) Descriptor() ([]byte, []int) { + return fileDescriptor_fd1040c5381ab5a7, []int{0} +} +func (m *ShardState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ShardState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ShardState.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ShardState) XXX_Merge(src proto.Message) { + xxx_messageInfo_ShardState.Merge(m, src) +} +func (m *ShardState) XXX_Size() int { + return m.Size() +} +func (m *ShardState) XXX_DiscardUnknown() { + xxx_messageInfo_ShardState.DiscardUnknown(m) +} + +var xxx_messageInfo_ShardState proto.InternalMessageInfo + +func (m *ShardState) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *ShardState) GetShardID() uint64 { + if m != nil { + return m.ShardID + } + return 0 +} + +func (m *ShardState) GetLaunchState() ShardState_State { + if m != nil { + return m.LaunchState + } + return ShardState_REGISTERED +} + +func (m *ShardState) GetInitialReplicas() map[uint64]string { + if m != nil { + return m.InitialReplicas + } + return nil +} + +// LogShardInfo contains information of a launched shard. +type LogShardInfo struct { + ShardID uint64 `protobuf:"varint,1,opt,name=ShardID,proto3" json:"ShardID,omitempty"` + // Replicas is a map of ReplicaID to LogStore UUID, it describe the member + // replicas of the shard at the given Epoch. + Replicas map[uint64]string `protobuf:"bytes,2,rep,name=Replicas,proto3" json:"Replicas,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // Epoch is the epoch value of the Shard, member replicas of the Shard can + // change across epochs. + Epoch uint64 `protobuf:"varint,3,opt,name=Epoch,proto3" json:"Epoch,omitempty"` + // LeaderID is the ReplicaID of the leader replica at the given term. When + // LeaderID is 0, it means there is no leader or the leader is unknown. + LeaderID uint64 `protobuf:"varint,4,opt,name=LeaderID,proto3" json:"LeaderID,omitempty"` + // Term is the Raft term value. + Term uint64 `protobuf:"varint,5,opt,name=Term,proto3" json:"Term,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *LogShardInfo) Reset() { *m = LogShardInfo{} } +func (m *LogShardInfo) String() string { return proto.CompactTextString(m) } +func (*LogShardInfo) ProtoMessage() {} +func (*LogShardInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_fd1040c5381ab5a7, []int{1} +} +func (m *LogShardInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *LogShardInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_LogShardInfo.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *LogShardInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_LogShardInfo.Merge(m, src) +} +func (m *LogShardInfo) XXX_Size() int { + return m.Size() +} +func (m *LogShardInfo) XXX_DiscardUnknown() { + xxx_messageInfo_LogShardInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_LogShardInfo proto.InternalMessageInfo + +func (m *LogShardInfo) GetShardID() uint64 { + if m != nil { + return m.ShardID + } + return 0 +} + +func (m *LogShardInfo) GetReplicas() map[uint64]string { + if m != nil { + return m.Replicas + } + return nil +} + +func (m *LogShardInfo) GetEpoch() uint64 { + if m != nil { + return m.Epoch + } + return 0 +} + +func (m *LogShardInfo) GetLeaderID() uint64 { + if m != nil { + return m.LeaderID + } + return 0 +} + +func (m *LogShardInfo) GetTerm() uint64 { + if m != nil { + return m.Term + } + return 0 +} + +// LogStoreHeartbeat is the periodic message sent to the HAKeeper by Log Stores. +type LogStoreHeartbeat struct { + // UUID is the uuid of the Log Store. + UUID string `protobuf:"bytes,1,opt,name=UUID,proto3" json:"UUID,omitempty"` + RaftAddress string `protobuf:"bytes,2,opt,name=RaftAddress,proto3" json:"RaftAddress,omitempty"` + ServiceAddress string `protobuf:"bytes,3,opt,name=ServiceAddress,proto3" json:"ServiceAddress,omitempty"` + GossipAddress string `protobuf:"bytes,4,opt,name=GossipAddress,proto3" json:"GossipAddress,omitempty"` + // Shards is a list of LogShardInfo instances collected on the specified + // LogStore. Details in Shards are based on the local knowledge of each + // replica running on the current LogStore, it may not be accurate or + // update to date due to various reasons. + Shards []LogShardInfo `protobuf:"bytes,5,rep,name=Shards,proto3" json:"Shards"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *LogStoreHeartbeat) Reset() { *m = LogStoreHeartbeat{} } +func (m *LogStoreHeartbeat) String() string { return proto.CompactTextString(m) } +func (*LogStoreHeartbeat) ProtoMessage() {} +func (*LogStoreHeartbeat) Descriptor() ([]byte, []int) { + return fileDescriptor_fd1040c5381ab5a7, []int{2} +} +func (m *LogStoreHeartbeat) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *LogStoreHeartbeat) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_LogStoreHeartbeat.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *LogStoreHeartbeat) XXX_Merge(src proto.Message) { + xxx_messageInfo_LogStoreHeartbeat.Merge(m, src) +} +func (m *LogStoreHeartbeat) XXX_Size() int { + return m.Size() +} +func (m *LogStoreHeartbeat) XXX_DiscardUnknown() { + xxx_messageInfo_LogStoreHeartbeat.DiscardUnknown(m) +} + +var xxx_messageInfo_LogStoreHeartbeat proto.InternalMessageInfo + +func (m *LogStoreHeartbeat) GetUUID() string { + if m != nil { + return m.UUID + } + return "" +} + +func (m *LogStoreHeartbeat) GetRaftAddress() string { + if m != nil { + return m.RaftAddress + } + return "" +} + +func (m *LogStoreHeartbeat) GetServiceAddress() string { + if m != nil { + return m.ServiceAddress + } + return "" +} + +func (m *LogStoreHeartbeat) GetGossipAddress() string { + if m != nil { + return m.GossipAddress + } + return "" +} + +func (m *LogStoreHeartbeat) GetShards() []LogShardInfo { + if m != nil { + return m.Shards + } + return nil +} + +// DNShardInfo contains information of a launched DN shard. +type DNShardInfo struct { + // ShardID uniquely identifies a DN shard. Each DN shard manages a Primary + // Key range or hashed Primary Key value range. + ShardID uint64 `protobuf:"varint,1,opt,name=ShardID,proto3" json:"ShardID,omitempty"` + // ReplicaID uniquely identifies a DN shard instance. After repairing a + // failed DN shard, a new DN shard instance is created with a new ReplicaID + // value. + ReplicaID uint64 `protobuf:"varint,2,opt,name=ReplicaID,proto3" json:"ReplicaID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DNShardInfo) Reset() { *m = DNShardInfo{} } +func (m *DNShardInfo) String() string { return proto.CompactTextString(m) } +func (*DNShardInfo) ProtoMessage() {} +func (*DNShardInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_fd1040c5381ab5a7, []int{3} +} +func (m *DNShardInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DNShardInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DNShardInfo.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DNShardInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_DNShardInfo.Merge(m, src) +} +func (m *DNShardInfo) XXX_Size() int { + return m.Size() +} +func (m *DNShardInfo) XXX_DiscardUnknown() { + xxx_messageInfo_DNShardInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_DNShardInfo proto.InternalMessageInfo + +func (m *DNShardInfo) GetShardID() uint64 { + if m != nil { + return m.ShardID + } + return 0 +} + +func (m *DNShardInfo) GetReplicaID() uint64 { + if m != nil { + return m.ReplicaID + } + return 0 +} + +// DNStoreHeartbeat is the periodic message sent to the HAKeeper by DN stores. +type DNStoreHeartbeat struct { + // UUID is the uuid of the DN Store. + UUID string `protobuf:"bytes,1,opt,name=UUID,proto3" json:"UUID,omitempty"` + // Shards is a list of DNShardInfo instances collected on the specified + // DN store. + Shards []DNShardInfo `protobuf:"bytes,2,rep,name=Shards,proto3" json:"Shards"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DNStoreHeartbeat) Reset() { *m = DNStoreHeartbeat{} } +func (m *DNStoreHeartbeat) String() string { return proto.CompactTextString(m) } +func (*DNStoreHeartbeat) ProtoMessage() {} +func (*DNStoreHeartbeat) Descriptor() ([]byte, []int) { + return fileDescriptor_fd1040c5381ab5a7, []int{4} +} +func (m *DNStoreHeartbeat) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DNStoreHeartbeat) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DNStoreHeartbeat.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DNStoreHeartbeat) XXX_Merge(src proto.Message) { + xxx_messageInfo_DNStoreHeartbeat.Merge(m, src) +} +func (m *DNStoreHeartbeat) XXX_Size() int { + return m.Size() +} +func (m *DNStoreHeartbeat) XXX_DiscardUnknown() { + xxx_messageInfo_DNStoreHeartbeat.DiscardUnknown(m) +} + +var xxx_messageInfo_DNStoreHeartbeat proto.InternalMessageInfo + +func (m *DNStoreHeartbeat) GetUUID() string { + if m != nil { + return m.UUID + } + return "" +} + +func (m *DNStoreHeartbeat) GetShards() []DNShardInfo { + if m != nil { + return m.Shards + } + return nil +} + +type LogRecord struct { + Index uint64 `protobuf:"varint,1,opt,name=Index,proto3" json:"Index,omitempty"` + Data []byte `protobuf:"bytes,2,opt,name=Data,proto3" json:"Data,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *LogRecord) Reset() { *m = LogRecord{} } +func (m *LogRecord) String() string { return proto.CompactTextString(m) } +func (*LogRecord) ProtoMessage() {} +func (*LogRecord) Descriptor() ([]byte, []int) { + return fileDescriptor_fd1040c5381ab5a7, []int{5} +} +func (m *LogRecord) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *LogRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_LogRecord.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *LogRecord) XXX_Merge(src proto.Message) { + xxx_messageInfo_LogRecord.Merge(m, src) +} +func (m *LogRecord) XXX_Size() int { + return m.Size() +} +func (m *LogRecord) XXX_DiscardUnknown() { + xxx_messageInfo_LogRecord.DiscardUnknown(m) +} + +var xxx_messageInfo_LogRecord proto.InternalMessageInfo + +func (m *LogRecord) GetIndex() uint64 { + if m != nil { + return m.Index + } + return 0 +} + +func (m *LogRecord) GetData() []byte { + if m != nil { + return m.Data + } + return nil +} + +type Request struct { + Method MethodType `protobuf:"varint,1,opt,name=Method,proto3,enum=logservice.MethodType" json:"Method,omitempty"` + Name string `protobuf:"bytes,2,opt,name=Name,proto3" json:"Name,omitempty"` + ShardID uint64 `protobuf:"varint,3,opt,name=ShardID,proto3" json:"ShardID,omitempty"` + Index uint64 `protobuf:"varint,4,opt,name=Index,proto3" json:"Index,omitempty"` + MaxSize uint64 `protobuf:"varint,5,opt,name=MaxSize,proto3" json:"MaxSize,omitempty"` + Timeout int64 `protobuf:"varint,6,opt,name=Timeout,proto3" json:"Timeout,omitempty"` + DNShardID uint64 `protobuf:"varint,7,opt,name=DNShardID,proto3" json:"DNShardID,omitempty"` + DNID uint64 `protobuf:"varint,8,opt,name=DNID,proto3" json:"DNID,omitempty"` + PayloadSize uint64 `protobuf:"varint,9,opt,name=PayloadSize,proto3" json:"PayloadSize,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Request) Reset() { *m = Request{} } +func (m *Request) String() string { return proto.CompactTextString(m) } +func (*Request) ProtoMessage() {} +func (*Request) Descriptor() ([]byte, []int) { + return fileDescriptor_fd1040c5381ab5a7, []int{6} +} +func (m *Request) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Request.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Request) XXX_Merge(src proto.Message) { + xxx_messageInfo_Request.Merge(m, src) +} +func (m *Request) XXX_Size() int { + return m.Size() +} +func (m *Request) XXX_DiscardUnknown() { + xxx_messageInfo_Request.DiscardUnknown(m) +} + +var xxx_messageInfo_Request proto.InternalMessageInfo + +func (m *Request) GetMethod() MethodType { + if m != nil { + return m.Method + } + return MethodType_CREATE +} + +func (m *Request) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *Request) GetShardID() uint64 { + if m != nil { + return m.ShardID + } + return 0 +} + +func (m *Request) GetIndex() uint64 { + if m != nil { + return m.Index + } + return 0 +} + +func (m *Request) GetMaxSize() uint64 { + if m != nil { + return m.MaxSize + } + return 0 +} + +func (m *Request) GetTimeout() int64 { + if m != nil { + return m.Timeout + } + return 0 +} + +func (m *Request) GetDNShardID() uint64 { + if m != nil { + return m.DNShardID + } + return 0 +} + +func (m *Request) GetDNID() uint64 { + if m != nil { + return m.DNID + } + return 0 +} + +func (m *Request) GetPayloadSize() uint64 { + if m != nil { + return m.PayloadSize + } + return 0 +} + +type Response struct { + Method MethodType `protobuf:"varint,1,opt,name=Method,proto3,enum=logservice.MethodType" json:"Method,omitempty"` + ErrorCode ErrorCode `protobuf:"varint,2,opt,name=ErrorCode,proto3,enum=logservice.ErrorCode" json:"ErrorCode,omitempty"` + ErrorMessage string `protobuf:"bytes,3,opt,name=ErrorMessage,proto3" json:"ErrorMessage,omitempty"` + ShardID uint64 `protobuf:"varint,4,opt,name=ShardID,proto3" json:"ShardID,omitempty"` + Index uint64 `protobuf:"varint,5,opt,name=Index,proto3" json:"Index,omitempty"` + LastIndex uint64 `protobuf:"varint,6,opt,name=LastIndex,proto3" json:"LastIndex,omitempty"` + PayloadSize uint64 `protobuf:"varint,7,opt,name=PayloadSize,proto3" json:"PayloadSize,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Response) Reset() { *m = Response{} } +func (m *Response) String() string { return proto.CompactTextString(m) } +func (*Response) ProtoMessage() {} +func (*Response) Descriptor() ([]byte, []int) { + return fileDescriptor_fd1040c5381ab5a7, []int{7} +} +func (m *Response) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Response) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Response.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Response) XXX_Merge(src proto.Message) { + xxx_messageInfo_Response.Merge(m, src) +} +func (m *Response) XXX_Size() int { + return m.Size() +} +func (m *Response) XXX_DiscardUnknown() { + xxx_messageInfo_Response.DiscardUnknown(m) +} + +var xxx_messageInfo_Response proto.InternalMessageInfo + +func (m *Response) GetMethod() MethodType { + if m != nil { + return m.Method + } + return MethodType_CREATE +} + +func (m *Response) GetErrorCode() ErrorCode { + if m != nil { + return m.ErrorCode + } + return ErrorCode_NoError +} + +func (m *Response) GetErrorMessage() string { + if m != nil { + return m.ErrorMessage + } + return "" +} + +func (m *Response) GetShardID() uint64 { + if m != nil { + return m.ShardID + } + return 0 +} + +func (m *Response) GetIndex() uint64 { + if m != nil { + return m.Index + } + return 0 +} + +func (m *Response) GetLastIndex() uint64 { + if m != nil { + return m.LastIndex + } + return 0 +} + +func (m *Response) GetPayloadSize() uint64 { + if m != nil { + return m.PayloadSize + } + return 0 +} + +type LogRecordResponse struct { + Records []LogRecord `protobuf:"bytes,1,rep,name=Records,proto3" json:"Records"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *LogRecordResponse) Reset() { *m = LogRecordResponse{} } +func (m *LogRecordResponse) String() string { return proto.CompactTextString(m) } +func (*LogRecordResponse) ProtoMessage() {} +func (*LogRecordResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_fd1040c5381ab5a7, []int{8} +} +func (m *LogRecordResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *LogRecordResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_LogRecordResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *LogRecordResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_LogRecordResponse.Merge(m, src) +} +func (m *LogRecordResponse) XXX_Size() int { + return m.Size() +} +func (m *LogRecordResponse) XXX_DiscardUnknown() { + xxx_messageInfo_LogRecordResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_LogRecordResponse proto.InternalMessageInfo + +func (m *LogRecordResponse) GetRecords() []LogRecord { + if m != nil { + return m.Records + } + return nil +} + +func init() { + proto.RegisterEnum("logservice.MethodType", MethodType_name, MethodType_value) + proto.RegisterEnum("logservice.ErrorCode", ErrorCode_name, ErrorCode_value) + proto.RegisterEnum("logservice.ShardState_State", ShardState_State_name, ShardState_State_value) + proto.RegisterType((*ShardState)(nil), "logservice.ShardState") + proto.RegisterMapType((map[uint64]string)(nil), "logservice.ShardState.InitialReplicasEntry") + proto.RegisterType((*LogShardInfo)(nil), "logservice.LogShardInfo") + proto.RegisterMapType((map[uint64]string)(nil), "logservice.LogShardInfo.ReplicasEntry") + proto.RegisterType((*LogStoreHeartbeat)(nil), "logservice.LogStoreHeartbeat") + proto.RegisterType((*DNShardInfo)(nil), "logservice.DNShardInfo") + proto.RegisterType((*DNStoreHeartbeat)(nil), "logservice.DNStoreHeartbeat") + proto.RegisterType((*LogRecord)(nil), "logservice.LogRecord") + proto.RegisterType((*Request)(nil), "logservice.Request") + proto.RegisterType((*Response)(nil), "logservice.Response") + proto.RegisterType((*LogRecordResponse)(nil), "logservice.LogRecordResponse") +} + +func init() { proto.RegisterFile("logservice.proto", fileDescriptor_fd1040c5381ab5a7) } + +var fileDescriptor_fd1040c5381ab5a7 = []byte{ + // 982 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x95, 0xcf, 0x6f, 0xe3, 0x44, + 0x14, 0xc7, 0x6b, 0xc7, 0xf9, 0xe1, 0xd7, 0x34, 0xcc, 0x8e, 0xb6, 0x8b, 0xa9, 0xaa, 0x12, 0x45, + 0x68, 0x55, 0x2d, 0x22, 0x2b, 0x75, 0x55, 0x84, 0x40, 0x42, 0x4a, 0x63, 0xab, 0x0d, 0x4a, 0x9d, + 0x6a, 0xe2, 0x1e, 0x38, 0xa0, 0xd5, 0x34, 0x9e, 0x26, 0x01, 0xc7, 0x13, 0xec, 0x49, 0xd5, 0x70, + 0x45, 0x5c, 0xf9, 0xbb, 0xf6, 0x06, 0x47, 0x4e, 0x08, 0xf5, 0xc4, 0x8d, 0x7f, 0x01, 0xcd, 0x8c, + 0xe3, 0x38, 0x61, 0x2b, 0x2d, 0x7b, 0x89, 0xe6, 0x7d, 0xe7, 0xbd, 0x37, 0xef, 0x7d, 0xe6, 0x79, + 0x02, 0x28, 0xe2, 0xe3, 0x94, 0x25, 0x77, 0xd3, 0x11, 0x6b, 0xcf, 0x13, 0x2e, 0x38, 0x86, 0xb5, + 0x72, 0xf0, 0xd9, 0x78, 0x2a, 0x26, 0x8b, 0x9b, 0xf6, 0x88, 0xcf, 0x5e, 0x8e, 0xf9, 0x98, 0xbf, + 0x54, 0x2e, 0x37, 0x8b, 0x5b, 0x65, 0x29, 0x43, 0xad, 0x74, 0x68, 0xeb, 0x0f, 0x13, 0x60, 0x38, + 0xa1, 0x49, 0x38, 0x14, 0x54, 0x30, 0x8c, 0xc1, 0xf2, 0xe9, 0x8c, 0x39, 0x46, 0xd3, 0x38, 0xb6, + 0x89, 0x5a, 0x63, 0x07, 0xaa, 0xca, 0xa3, 0xe7, 0x3a, 0x66, 0xd3, 0x38, 0xb6, 0xc8, 0xca, 0xc4, + 0x5f, 0xc3, 0x6e, 0x9f, 0x2e, 0xe2, 0xd1, 0x44, 0x05, 0x3b, 0xa5, 0xa6, 0x71, 0xdc, 0x38, 0x39, + 0x6c, 0x17, 0xea, 0x5b, 0xa7, 0x6e, 0xab, 0x5f, 0x52, 0x0c, 0xc0, 0xd7, 0xf0, 0x41, 0x2f, 0x9e, + 0x8a, 0x29, 0x8d, 0x08, 0x9b, 0x47, 0xd3, 0x11, 0x4d, 0x1d, 0xab, 0x59, 0x3a, 0xde, 0x3d, 0xf9, + 0xf4, 0x91, 0x1c, 0x5b, 0xde, 0x5e, 0x2c, 0x92, 0x25, 0xd9, 0xce, 0x71, 0x70, 0x06, 0x4f, 0xdf, + 0xe6, 0x88, 0x11, 0x94, 0x7e, 0x60, 0x4b, 0xd5, 0x9b, 0x45, 0xe4, 0x12, 0x3f, 0x85, 0xf2, 0x1d, + 0x8d, 0x16, 0x4c, 0x35, 0x66, 0x13, 0x6d, 0x7c, 0x69, 0x7e, 0x61, 0xb4, 0x3a, 0x50, 0xd6, 0x35, + 0x36, 0x00, 0x88, 0x77, 0xde, 0x1b, 0x06, 0x1e, 0xf1, 0x5c, 0xb4, 0x83, 0xf7, 0xc0, 0xee, 0x77, + 0xae, 0xfd, 0xee, 0x45, 0xcf, 0x3f, 0x47, 0x06, 0xae, 0x43, 0x4d, 0x9b, 0x9e, 0x8b, 0x4c, 0xbc, + 0x0b, 0xd5, 0xce, 0xd9, 0x80, 0x04, 0x9e, 0x8b, 0x4a, 0xad, 0x7f, 0x0c, 0xa8, 0xf7, 0xf9, 0x58, + 0xc3, 0x8a, 0x6f, 0x79, 0x11, 0xa4, 0xb1, 0x09, 0xf2, 0x0c, 0x6a, 0x39, 0x01, 0x53, 0x11, 0x78, + 0x5e, 0x24, 0x50, 0xcc, 0xd2, 0xde, 0x6c, 0x3e, 0x8f, 0x93, 0xbd, 0x78, 0x73, 0x3e, 0x9a, 0xa8, + 0x6b, 0xb0, 0x88, 0x36, 0xf0, 0x01, 0xd4, 0xfa, 0x8c, 0x86, 0x2c, 0xe9, 0xb9, 0x8e, 0xa5, 0x36, + 0x72, 0x5b, 0x5e, 0x76, 0xc0, 0x92, 0x99, 0x53, 0x56, 0xba, 0x5a, 0x1f, 0x7c, 0x05, 0x7b, 0xef, + 0x0f, 0xed, 0x37, 0x03, 0x9e, 0xc8, 0x5a, 0x05, 0x4f, 0xd8, 0x05, 0xa3, 0x89, 0xb8, 0x61, 0x54, + 0xc8, 0x63, 0xae, 0xaf, 0xb3, 0x9e, 0x6d, 0xa2, 0xd6, 0xb8, 0x09, 0xbb, 0x84, 0xde, 0x8a, 0x4e, + 0x18, 0x26, 0x2c, 0x4d, 0xb3, 0x4c, 0x45, 0x09, 0x3f, 0x87, 0xc6, 0x50, 0xb7, 0xbf, 0x72, 0x2a, + 0x29, 0xa7, 0x2d, 0x15, 0x7f, 0x02, 0x7b, 0xe7, 0x3c, 0x4d, 0xa7, 0xf3, 0x95, 0x9b, 0xa5, 0xdc, + 0x36, 0x45, 0xfc, 0x39, 0x54, 0x14, 0xc1, 0xd4, 0x29, 0x2b, 0xbc, 0xce, 0x63, 0x78, 0xcf, 0xac, + 0x37, 0x7f, 0x7e, 0xbc, 0x43, 0x32, 0xef, 0x96, 0x07, 0xbb, 0xae, 0xff, 0x2e, 0x37, 0x78, 0x08, + 0x76, 0xc6, 0x2d, 0xff, 0x4c, 0xd6, 0x42, 0xeb, 0x3b, 0x40, 0xae, 0xff, 0x0e, 0x58, 0x4e, 0xf3, + 0x32, 0xf5, 0x14, 0x7c, 0x58, 0x2c, 0xb3, 0x50, 0xc8, 0x56, 0x95, 0xa7, 0x60, 0xf7, 0xf9, 0x98, + 0xb0, 0x11, 0x4f, 0x42, 0x79, 0x3d, 0xbd, 0x38, 0x64, 0xf7, 0x59, 0x85, 0xda, 0x90, 0xa7, 0xb9, + 0x54, 0x50, 0x55, 0x5a, 0x9d, 0xa8, 0x75, 0xeb, 0x17, 0x13, 0xaa, 0x84, 0xfd, 0xb8, 0x60, 0xa9, + 0xc0, 0x6d, 0xa8, 0x5c, 0x32, 0x31, 0xe1, 0xa1, 0x0a, 0x6b, 0x9c, 0x3c, 0x2b, 0x9e, 0xac, 0x77, + 0x82, 0xe5, 0x9c, 0x91, 0xcc, 0x2b, 0x7f, 0x28, 0xcc, 0xb7, 0x3f, 0x14, 0xa5, 0x4d, 0x3a, 0x79, + 0x4d, 0x56, 0xb1, 0x26, 0x07, 0xaa, 0x97, 0xf4, 0x7e, 0x38, 0xfd, 0x89, 0x65, 0x23, 0xb8, 0x32, + 0xe5, 0x4e, 0x30, 0x9d, 0x31, 0xbe, 0x10, 0x4e, 0xa5, 0x69, 0x1c, 0x97, 0xc8, 0xca, 0x94, 0x9c, + 0x57, 0x1c, 0x5c, 0xa7, 0xaa, 0x39, 0xe7, 0x82, 0xea, 0xd2, 0xef, 0xb9, 0x4e, 0x4d, 0x4f, 0xb4, + 0x5c, 0xcb, 0x51, 0xbb, 0xa2, 0xcb, 0x88, 0xd3, 0x50, 0x9d, 0x64, 0xab, 0xad, 0xa2, 0xd4, 0xfa, + 0xd9, 0x94, 0x9f, 0x5f, 0x3a, 0xe7, 0x71, 0xca, 0xfe, 0x37, 0x88, 0x57, 0x60, 0x7b, 0x49, 0xc2, + 0x93, 0x2e, 0x0f, 0x35, 0x8d, 0xc6, 0xc9, 0x7e, 0x31, 0x24, 0xdf, 0x24, 0x6b, 0x3f, 0xdc, 0x82, + 0xba, 0x32, 0x2e, 0x59, 0x9a, 0xd2, 0x31, 0xcb, 0x46, 0x7b, 0x43, 0x2b, 0xd2, 0xb4, 0x1e, 0xa1, + 0x59, 0x2e, 0xd2, 0x3c, 0x04, 0xbb, 0x4f, 0x53, 0xa1, 0x77, 0x2a, 0x9a, 0x4c, 0x2e, 0x6c, 0x53, + 0xa8, 0xfe, 0x97, 0xc2, 0x37, 0xea, 0xdb, 0xd5, 0x43, 0x94, 0xd3, 0x38, 0x95, 0x13, 0x22, 0x95, + 0xd4, 0x31, 0xd4, 0x44, 0xee, 0x6f, 0x7d, 0x38, 0x7a, 0x37, 0x9b, 0xc7, 0x95, 0xef, 0x8b, 0x7b, + 0x80, 0x35, 0x2a, 0x0c, 0x50, 0xe9, 0x12, 0xaf, 0x13, 0x78, 0x68, 0x47, 0xbe, 0x90, 0xae, 0x37, + 0x0c, 0xc8, 0xe0, 0x5b, 0x64, 0xc8, 0x8d, 0xce, 0xd5, 0x95, 0xe7, 0xcb, 0xa7, 0xb3, 0x06, 0x16, + 0xf1, 0x3a, 0x2e, 0x2a, 0xc9, 0x27, 0x35, 0x20, 0xd7, 0x7e, 0x57, 0x06, 0x58, 0x18, 0x41, 0xfd, + 0xdc, 0x0b, 0x5e, 0xe7, 0x4a, 0x59, 0xa6, 0xe8, 0x0e, 0x7c, 0xdf, 0xeb, 0x06, 0xa8, 0x22, 0x9f, + 0xe7, 0xcc, 0x78, 0x4d, 0x06, 0xa8, 0xfa, 0xe2, 0x57, 0xb3, 0x70, 0x1f, 0xd2, 0xd5, 0xe7, 0xca, + 0xd4, 0x47, 0x67, 0x53, 0xa4, 0xdf, 0xed, 0x2e, 0x8d, 0x47, 0x2c, 0x62, 0x21, 0x32, 0xe5, 0x21, + 0xbd, 0xf8, 0x8e, 0x46, 0xd3, 0x50, 0x31, 0x46, 0x25, 0x8c, 0xa1, 0x91, 0x29, 0xab, 0x18, 0xab, + 0xa0, 0x65, 0xdc, 0x50, 0x19, 0x3f, 0x03, 0xbc, 0xa9, 0x49, 0x96, 0xa8, 0x22, 0xf3, 0x13, 0xf6, + 0x3d, 0x1b, 0x09, 0x16, 0xa2, 0x2a, 0x7e, 0x02, 0x7b, 0x2a, 0xb1, 0xcf, 0x05, 0x61, 0x34, 0x5c, + 0xa2, 0x9a, 0x3c, 0x72, 0xb8, 0x4c, 0x05, 0x9b, 0x75, 0x23, 0x9e, 0xb2, 0x10, 0xd9, 0xf8, 0x23, + 0xd8, 0x57, 0x77, 0xd5, 0x89, 0x12, 0xe9, 0x13, 0x24, 0x8b, 0x78, 0x44, 0x65, 0x7c, 0x28, 0xbb, + 0x1c, 0x2c, 0xc4, 0xe0, 0x96, 0xd0, 0x78, 0xcc, 0x90, 0xfc, 0x9b, 0x6e, 0xf8, 0x5c, 0xf4, 0x19, + 0x4d, 0xd9, 0x05, 0x8f, 0x42, 0x96, 0xa0, 0x5b, 0xbc, 0x0f, 0x68, 0x20, 0x26, 0x2c, 0xd1, 0x59, + 0x75, 0xd3, 0x7f, 0x57, 0xcf, 0xea, 0x6f, 0x1e, 0x8e, 0x8c, 0xdf, 0x1f, 0x8e, 0x8c, 0xbf, 0x1e, + 0x8e, 0x8c, 0x9b, 0x8a, 0xfa, 0xd7, 0x7f, 0xf5, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x9c, 0x85, + 0xf2, 0x9a, 0x44, 0x08, 0x00, 0x00, +} + +func (m *ShardState) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ShardState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ShardState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.InitialReplicas) > 0 { + for k := range m.InitialReplicas { + v := m.InitialReplicas[k] + baseI := i + i -= len(v) + copy(dAtA[i:], v) + i = encodeVarintLogservice(dAtA, i, uint64(len(v))) + i-- + dAtA[i] = 0x12 + i = encodeVarintLogservice(dAtA, i, uint64(k)) + i-- + dAtA[i] = 0x8 + i = encodeVarintLogservice(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x22 + } + } + if m.LaunchState != 0 { + i = encodeVarintLogservice(dAtA, i, uint64(m.LaunchState)) + i-- + dAtA[i] = 0x18 + } + if m.ShardID != 0 { + i = encodeVarintLogservice(dAtA, i, uint64(m.ShardID)) + i-- + dAtA[i] = 0x10 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintLogservice(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *LogShardInfo) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *LogShardInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *LogShardInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Term != 0 { + i = encodeVarintLogservice(dAtA, i, uint64(m.Term)) + i-- + dAtA[i] = 0x28 + } + if m.LeaderID != 0 { + i = encodeVarintLogservice(dAtA, i, uint64(m.LeaderID)) + i-- + dAtA[i] = 0x20 + } + if m.Epoch != 0 { + i = encodeVarintLogservice(dAtA, i, uint64(m.Epoch)) + i-- + dAtA[i] = 0x18 + } + if len(m.Replicas) > 0 { + for k := range m.Replicas { + v := m.Replicas[k] + baseI := i + i -= len(v) + copy(dAtA[i:], v) + i = encodeVarintLogservice(dAtA, i, uint64(len(v))) + i-- + dAtA[i] = 0x12 + i = encodeVarintLogservice(dAtA, i, uint64(k)) + i-- + dAtA[i] = 0x8 + i = encodeVarintLogservice(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x12 + } + } + if m.ShardID != 0 { + i = encodeVarintLogservice(dAtA, i, uint64(m.ShardID)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *LogStoreHeartbeat) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *LogStoreHeartbeat) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *LogStoreHeartbeat) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Shards) > 0 { + for iNdEx := len(m.Shards) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Shards[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintLogservice(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + } + if len(m.GossipAddress) > 0 { + i -= len(m.GossipAddress) + copy(dAtA[i:], m.GossipAddress) + i = encodeVarintLogservice(dAtA, i, uint64(len(m.GossipAddress))) + i-- + dAtA[i] = 0x22 + } + if len(m.ServiceAddress) > 0 { + i -= len(m.ServiceAddress) + copy(dAtA[i:], m.ServiceAddress) + i = encodeVarintLogservice(dAtA, i, uint64(len(m.ServiceAddress))) + i-- + dAtA[i] = 0x1a + } + if len(m.RaftAddress) > 0 { + i -= len(m.RaftAddress) + copy(dAtA[i:], m.RaftAddress) + i = encodeVarintLogservice(dAtA, i, uint64(len(m.RaftAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.UUID) > 0 { + i -= len(m.UUID) + copy(dAtA[i:], m.UUID) + i = encodeVarintLogservice(dAtA, i, uint64(len(m.UUID))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *DNShardInfo) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DNShardInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DNShardInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.ReplicaID != 0 { + i = encodeVarintLogservice(dAtA, i, uint64(m.ReplicaID)) + i-- + dAtA[i] = 0x10 + } + if m.ShardID != 0 { + i = encodeVarintLogservice(dAtA, i, uint64(m.ShardID)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *DNStoreHeartbeat) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DNStoreHeartbeat) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DNStoreHeartbeat) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Shards) > 0 { + for iNdEx := len(m.Shards) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Shards[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintLogservice(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.UUID) > 0 { + i -= len(m.UUID) + copy(dAtA[i:], m.UUID) + i = encodeVarintLogservice(dAtA, i, uint64(len(m.UUID))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *LogRecord) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *LogRecord) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *LogRecord) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Data) > 0 { + i -= len(m.Data) + copy(dAtA[i:], m.Data) + i = encodeVarintLogservice(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0x12 + } + if m.Index != 0 { + i = encodeVarintLogservice(dAtA, i, uint64(m.Index)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *Request) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Request) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Request) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.PayloadSize != 0 { + i = encodeVarintLogservice(dAtA, i, uint64(m.PayloadSize)) + i-- + dAtA[i] = 0x48 + } + if m.DNID != 0 { + i = encodeVarintLogservice(dAtA, i, uint64(m.DNID)) + i-- + dAtA[i] = 0x40 + } + if m.DNShardID != 0 { + i = encodeVarintLogservice(dAtA, i, uint64(m.DNShardID)) + i-- + dAtA[i] = 0x38 + } + if m.Timeout != 0 { + i = encodeVarintLogservice(dAtA, i, uint64(m.Timeout)) + i-- + dAtA[i] = 0x30 + } + if m.MaxSize != 0 { + i = encodeVarintLogservice(dAtA, i, uint64(m.MaxSize)) + i-- + dAtA[i] = 0x28 + } + if m.Index != 0 { + i = encodeVarintLogservice(dAtA, i, uint64(m.Index)) + i-- + dAtA[i] = 0x20 + } + if m.ShardID != 0 { + i = encodeVarintLogservice(dAtA, i, uint64(m.ShardID)) + i-- + dAtA[i] = 0x18 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintLogservice(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0x12 + } + if m.Method != 0 { + i = encodeVarintLogservice(dAtA, i, uint64(m.Method)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *Response) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Response) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Response) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.PayloadSize != 0 { + i = encodeVarintLogservice(dAtA, i, uint64(m.PayloadSize)) + i-- + dAtA[i] = 0x38 + } + if m.LastIndex != 0 { + i = encodeVarintLogservice(dAtA, i, uint64(m.LastIndex)) + i-- + dAtA[i] = 0x30 + } + if m.Index != 0 { + i = encodeVarintLogservice(dAtA, i, uint64(m.Index)) + i-- + dAtA[i] = 0x28 + } + if m.ShardID != 0 { + i = encodeVarintLogservice(dAtA, i, uint64(m.ShardID)) + i-- + dAtA[i] = 0x20 + } + if len(m.ErrorMessage) > 0 { + i -= len(m.ErrorMessage) + copy(dAtA[i:], m.ErrorMessage) + i = encodeVarintLogservice(dAtA, i, uint64(len(m.ErrorMessage))) + i-- + dAtA[i] = 0x1a + } + if m.ErrorCode != 0 { + i = encodeVarintLogservice(dAtA, i, uint64(m.ErrorCode)) + i-- + dAtA[i] = 0x10 + } + if m.Method != 0 { + i = encodeVarintLogservice(dAtA, i, uint64(m.Method)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *LogRecordResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *LogRecordResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *LogRecordResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Records) > 0 { + for iNdEx := len(m.Records) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Records[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintLogservice(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintLogservice(dAtA []byte, offset int, v uint64) int { + offset -= sovLogservice(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *ShardState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + sovLogservice(uint64(l)) + } + if m.ShardID != 0 { + n += 1 + sovLogservice(uint64(m.ShardID)) + } + if m.LaunchState != 0 { + n += 1 + sovLogservice(uint64(m.LaunchState)) + } + if len(m.InitialReplicas) > 0 { + for k, v := range m.InitialReplicas { + _ = k + _ = v + mapEntrySize := 1 + sovLogservice(uint64(k)) + 1 + len(v) + sovLogservice(uint64(len(v))) + n += mapEntrySize + 1 + sovLogservice(uint64(mapEntrySize)) + } + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *LogShardInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ShardID != 0 { + n += 1 + sovLogservice(uint64(m.ShardID)) + } + if len(m.Replicas) > 0 { + for k, v := range m.Replicas { + _ = k + _ = v + mapEntrySize := 1 + sovLogservice(uint64(k)) + 1 + len(v) + sovLogservice(uint64(len(v))) + n += mapEntrySize + 1 + sovLogservice(uint64(mapEntrySize)) + } + } + if m.Epoch != 0 { + n += 1 + sovLogservice(uint64(m.Epoch)) + } + if m.LeaderID != 0 { + n += 1 + sovLogservice(uint64(m.LeaderID)) + } + if m.Term != 0 { + n += 1 + sovLogservice(uint64(m.Term)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *LogStoreHeartbeat) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.UUID) + if l > 0 { + n += 1 + l + sovLogservice(uint64(l)) + } + l = len(m.RaftAddress) + if l > 0 { + n += 1 + l + sovLogservice(uint64(l)) + } + l = len(m.ServiceAddress) + if l > 0 { + n += 1 + l + sovLogservice(uint64(l)) + } + l = len(m.GossipAddress) + if l > 0 { + n += 1 + l + sovLogservice(uint64(l)) + } + if len(m.Shards) > 0 { + for _, e := range m.Shards { + l = e.Size() + n += 1 + l + sovLogservice(uint64(l)) + } + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *DNShardInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ShardID != 0 { + n += 1 + sovLogservice(uint64(m.ShardID)) + } + if m.ReplicaID != 0 { + n += 1 + sovLogservice(uint64(m.ReplicaID)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *DNStoreHeartbeat) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.UUID) + if l > 0 { + n += 1 + l + sovLogservice(uint64(l)) + } + if len(m.Shards) > 0 { + for _, e := range m.Shards { + l = e.Size() + n += 1 + l + sovLogservice(uint64(l)) + } + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *LogRecord) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Index != 0 { + n += 1 + sovLogservice(uint64(m.Index)) + } + l = len(m.Data) + if l > 0 { + n += 1 + l + sovLogservice(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *Request) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Method != 0 { + n += 1 + sovLogservice(uint64(m.Method)) + } + l = len(m.Name) + if l > 0 { + n += 1 + l + sovLogservice(uint64(l)) + } + if m.ShardID != 0 { + n += 1 + sovLogservice(uint64(m.ShardID)) + } + if m.Index != 0 { + n += 1 + sovLogservice(uint64(m.Index)) + } + if m.MaxSize != 0 { + n += 1 + sovLogservice(uint64(m.MaxSize)) + } + if m.Timeout != 0 { + n += 1 + sovLogservice(uint64(m.Timeout)) + } + if m.DNShardID != 0 { + n += 1 + sovLogservice(uint64(m.DNShardID)) + } + if m.DNID != 0 { + n += 1 + sovLogservice(uint64(m.DNID)) + } + if m.PayloadSize != 0 { + n += 1 + sovLogservice(uint64(m.PayloadSize)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *Response) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Method != 0 { + n += 1 + sovLogservice(uint64(m.Method)) + } + if m.ErrorCode != 0 { + n += 1 + sovLogservice(uint64(m.ErrorCode)) + } + l = len(m.ErrorMessage) + if l > 0 { + n += 1 + l + sovLogservice(uint64(l)) + } + if m.ShardID != 0 { + n += 1 + sovLogservice(uint64(m.ShardID)) + } + if m.Index != 0 { + n += 1 + sovLogservice(uint64(m.Index)) + } + if m.LastIndex != 0 { + n += 1 + sovLogservice(uint64(m.LastIndex)) + } + if m.PayloadSize != 0 { + n += 1 + sovLogservice(uint64(m.PayloadSize)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *LogRecordResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Records) > 0 { + for _, e := range m.Records { + l = e.Size() + n += 1 + l + sovLogservice(uint64(l)) + } + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func sovLogservice(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozLogservice(x uint64) (n int) { + return sovLogservice(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *ShardState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ShardState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ShardState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthLogservice + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLogservice + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ShardID", wireType) + } + m.ShardID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ShardID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field LaunchState", wireType) + } + m.LaunchState = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.LaunchState |= ShardState_State(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InitialReplicas", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthLogservice + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLogservice + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.InitialReplicas == nil { + m.InitialReplicas = make(map[uint64]string) + } + var mapkey uint64 + var mapvalue string + for iNdEx < postIndex { + entryPreIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + if fieldNum == 1 { + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + mapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + } else if fieldNum == 2 { + var stringLenmapvalue uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapvalue |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapvalue := int(stringLenmapvalue) + if intStringLenmapvalue < 0 { + return ErrInvalidLengthLogservice + } + postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthLogservice + } + if postStringIndexmapvalue > l { + return io.ErrUnexpectedEOF + } + mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue]) + iNdEx = postStringIndexmapvalue + } else { + iNdEx = entryPreIndex + skippy, err := skipLogservice(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLogservice + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + m.InitialReplicas[mapkey] = mapvalue + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipLogservice(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLogservice + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *LogShardInfo) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: LogShardInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: LogShardInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ShardID", wireType) + } + m.ShardID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ShardID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Replicas", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthLogservice + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLogservice + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Replicas == nil { + m.Replicas = make(map[uint64]string) + } + var mapkey uint64 + var mapvalue string + for iNdEx < postIndex { + entryPreIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + if fieldNum == 1 { + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + mapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + } else if fieldNum == 2 { + var stringLenmapvalue uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapvalue |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapvalue := int(stringLenmapvalue) + if intStringLenmapvalue < 0 { + return ErrInvalidLengthLogservice + } + postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthLogservice + } + if postStringIndexmapvalue > l { + return io.ErrUnexpectedEOF + } + mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue]) + iNdEx = postStringIndexmapvalue + } else { + iNdEx = entryPreIndex + skippy, err := skipLogservice(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLogservice + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + m.Replicas[mapkey] = mapvalue + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Epoch", wireType) + } + m.Epoch = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Epoch |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field LeaderID", wireType) + } + m.LeaderID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.LeaderID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Term", wireType) + } + m.Term = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Term |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipLogservice(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLogservice + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *LogStoreHeartbeat) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: LogStoreHeartbeat: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: LogStoreHeartbeat: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UUID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthLogservice + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLogservice + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.UUID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RaftAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthLogservice + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLogservice + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RaftAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ServiceAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthLogservice + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLogservice + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ServiceAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GossipAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthLogservice + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLogservice + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.GossipAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Shards", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthLogservice + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLogservice + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Shards = append(m.Shards, LogShardInfo{}) + if err := m.Shards[len(m.Shards)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipLogservice(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLogservice + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DNShardInfo) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DNShardInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DNShardInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ShardID", wireType) + } + m.ShardID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ShardID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ReplicaID", wireType) + } + m.ReplicaID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ReplicaID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipLogservice(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLogservice + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DNStoreHeartbeat) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DNStoreHeartbeat: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DNStoreHeartbeat: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UUID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthLogservice + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLogservice + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.UUID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Shards", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthLogservice + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLogservice + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Shards = append(m.Shards, DNShardInfo{}) + if err := m.Shards[len(m.Shards)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipLogservice(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLogservice + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *LogRecord) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: LogRecord: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: LogRecord: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Index", wireType) + } + m.Index = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Index |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthLogservice + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthLogservice + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) + if m.Data == nil { + m.Data = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipLogservice(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLogservice + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Request) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Request: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Request: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Method", wireType) + } + m.Method = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Method |= MethodType(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthLogservice + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLogservice + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ShardID", wireType) + } + m.ShardID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ShardID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Index", wireType) + } + m.Index = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Index |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxSize", wireType) + } + m.MaxSize = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxSize |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Timeout", wireType) + } + m.Timeout = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Timeout |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DNShardID", wireType) + } + m.DNShardID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DNShardID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DNID", wireType) + } + m.DNID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DNID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 9: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PayloadSize", wireType) + } + m.PayloadSize = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PayloadSize |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipLogservice(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLogservice + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Response) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Response: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Response: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Method", wireType) + } + m.Method = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Method |= MethodType(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ErrorCode", wireType) + } + m.ErrorCode = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ErrorCode |= ErrorCode(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ErrorMessage", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthLogservice + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLogservice + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ErrorMessage = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ShardID", wireType) + } + m.ShardID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ShardID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Index", wireType) + } + m.Index = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Index |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field LastIndex", wireType) + } + m.LastIndex = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.LastIndex |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PayloadSize", wireType) + } + m.PayloadSize = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PayloadSize |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipLogservice(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLogservice + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *LogRecordResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: LogRecordResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: LogRecordResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Records", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLogservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthLogservice + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLogservice + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Records = append(m.Records, LogRecord{}) + if err := m.Records[len(m.Records)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipLogservice(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLogservice + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipLogservice(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowLogservice + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowLogservice + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowLogservice + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthLogservice + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupLogservice + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthLogservice + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthLogservice = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowLogservice = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupLogservice = fmt.Errorf("proto: unexpected end of group") +) diff --git a/pkg/pb/plan/plan.pb.go b/pkg/pb/plan/plan.pb.go index 4fa59cab73617..ab1723d870010 100644 --- a/pkg/pb/plan/plan.pb.go +++ b/pkg/pb/plan/plan.pb.go @@ -6785,6 +6785,8 @@ func (m *Node) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x5a } + i-- + dAtA[i] = 0x6a } if len(m.GroupingSet) > 0 { for iNdEx := len(m.GroupingSet) - 1; iNdEx >= 0; iNdEx-- { diff --git a/proto/logservice.proto b/proto/logservice.proto new file mode 100644 index 0000000000000..eb228825c4a49 --- /dev/null +++ b/proto/logservice.proto @@ -0,0 +1,151 @@ +// Copyright 2022 MatrixOrigin. +// +// 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, +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; +package logservice; + +import "github.com/gogo/protobuf/gogoproto/gogo.proto"; + +// ShardState represents the state of a registered Shard. +message ShardState { + enum State { + REGISTERED = 0; + LAUNCHING = 1; + LAUNCHED = 2; + ABORTED = 3; + } + string Name = 1; + uint64 ShardID = 2; + State LaunchState = 3; + // InitialReplicas is a map of ReplicaID to LogStore UUIDs, it describes the + // initial replicas assigned for the given shard. + map InitialReplicas = 4; +}; + +// LogShardInfo contains information of a launched shard. +message LogShardInfo { + uint64 ShardID = 1; + // Replicas is a map of ReplicaID to LogStore UUID, it describe the member + // replicas of the shard at the given Epoch. + map Replicas = 2; + // Epoch is the epoch value of the Shard, member replicas of the Shard can + // change across epochs. + uint64 Epoch = 3; + // LeaderID is the ReplicaID of the leader replica at the given term. When + // LeaderID is 0, it means there is no leader or the leader is unknown. + uint64 LeaderID = 4; + // Term is the Raft term value. + uint64 Term = 5; + + // TODO: per shard stats like CPU/memory/network usage can be added here +}; + +// LogStoreHeartbeat is the periodic message sent to the HAKeeper by Log Stores. +message LogStoreHeartbeat { + // UUID is the uuid of the Log Store. + string UUID = 1; + + string RaftAddress = 2; + string ServiceAddress = 3; + string GossipAddress = 4; + + // Shards is a list of LogShardInfo instances collected on the specified + // LogStore. Details in Shards are based on the local knowledge of each + // replica running on the current LogStore, it may not be accurate or + // update to date due to various reasons. + repeated LogShardInfo Shards = 5 [(gogoproto.nullable) = false]; +}; + +// DNShardInfo contains information of a launched DN shard. +message DNShardInfo { + // ShardID uniquely identifies a DN shard. Each DN shard manages a Primary + // Key range or hashed Primary Key value range. + uint64 ShardID = 1; + // ReplicaID uniquely identifies a DN shard instance. After repairing a + // failed DN shard, a new DN shard instance is created with a new ReplicaID + // value. + uint64 ReplicaID = 2; + + // TODO: per shard stats like CPU/memory/network usage can be added here +}; + +// DNStoreHeartbeat is the periodic message sent to the HAKeeper by DN stores. +message DNStoreHeartbeat { + // UUID is the uuid of the DN Store. + string UUID = 1; + // Shards is a list of DNShardInfo instances collected on the specified + // DN store. + repeated DNShardInfo Shards = 2 [(gogoproto.nullable) = false]; +}; + +enum MethodType { + CREATE = 0; + DESTROY = 1; + APPEND = 2; + READ = 3; + TRUNCATE = 4; + GET_TRUNCATE = 5; + CONNECT = 6; + CONNECT_RO = 7; +}; + +message LogRecord { + uint64 Index = 1; + bytes Data = 2; +}; + +message Request { + MethodType Method = 1; + string Name = 2; + uint64 ShardID = 3; + uint64 Index = 4; + uint64 MaxSize = 5; + int64 Timeout = 6; + + uint64 DNShardID = 7; + uint64 DNID = 8; + uint64 PayloadSize = 9; +}; + +enum ErrorCode { + NoError = 0; + Timeout = 1; + Canceled = 2; + InvalidShard = 3; + InvalidTimeout = 4; + InvalidPayload = 5; + InvalidPayloadSize = 6; + Rejected = 7; + ShardNotReady = 8; + SystemClosed = 9; + + IndexAlreadyTruncated = 100; + OutOfRange = 101; + NotLeaseHolder = 102; + + OtherSystemError = 1000; +}; + +message Response { + MethodType Method = 1; + ErrorCode ErrorCode = 2; + string ErrorMessage = 3; + uint64 ShardID = 4; + uint64 Index = 5; + uint64 LastIndex = 6; + uint64 PayloadSize = 7; +}; + +message LogRecordResponse { + repeated LogRecord Records = 1 [(gogoproto.nullable) = false]; +};