├── .github ├── dependabot.yml └── workflows │ ├── golangci-lint.yml │ └── test.yml ├── .gitignore ├── .gitpod.yml ├── .idea ├── codeStyles │ └── codeStyleConfig.xml ├── dictionaries │ └── drdrxp.xml ├── misc.xml ├── modules.xml ├── paxoskv.iml ├── vcs.xml └── watcherTasks.xml ├── .travis.yml ├── Makefile ├── README.md ├── faq └── diff-from-epaxos-indirect-deps │ ├── image-20220411135435500.png │ └── index.md ├── gen-proto.sh ├── go.mod ├── go.sum ├── goid ├── getg_386.s ├── getg_amd64.s ├── getg_amd64p32.s ├── getg_arm.s ├── getg_arm64.s ├── go_tls.h ├── goid.go └── goid_test.go ├── install-protoc.sh ├── loc.sh ├── paxoskv ├── api.go ├── apply.go ├── apply_data.go ├── apply_test.go ├── apply_vc.go ├── apply_vc_test.go ├── column.go ├── column_test.go ├── conf.go ├── derive.go ├── derive_test.go ├── error.go ├── example_setget_kvapi_test.go ├── handler.go ├── handler_test.go ├── instance.go ├── instance_test.go ├── log.go ├── logging.go ├── mmp.go ├── mmp_test.go ├── paxoskv.pb.go ├── recover.go ├── recover_test.go ├── server.go ├── setget_test.go ├── state_machine.go ├── tostr.go ├── tostr_test.go └── util.go └── proto └── paxoskv.proto /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "gomod" 9 | directory: "/" 10 | schedule: 11 | interval: "daily" 12 | -------------------------------------------------------------------------------- /.github/workflows/golangci-lint.yml: -------------------------------------------------------------------------------- 1 | name: golangci-lint 2 | on: 3 | push: 4 | branches-ignore: 5 | - '**' 6 | # tags: 7 | # - v* 8 | # branches: 9 | # - '*' 10 | # pull_request: 11 | jobs: 12 | golangci: 13 | name: lint 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v2 17 | 18 | - name: golangci-lint 19 | uses: golangci/golangci-lint-action@v2 20 | with: 21 | # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. 22 | version: v1.29 23 | 24 | # Optional: working directory, useful for monorepos 25 | # working-directory: somedir 26 | 27 | # Optional: golangci-lint command line arguments. 28 | # args: --issues-exit-code=0 29 | 30 | # Optional: show only new issues if it's a pull request. The default value is `false`. 31 | # only-new-issues: true 32 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | on: 3 | push: 4 | pull_request: 5 | 6 | jobs: 7 | test: 8 | strategy: 9 | matrix: 10 | go-version: 11 | - 1.14.x 12 | - 1.15.x 13 | - 1.16.x 14 | - 1.17.x 15 | os: [ubuntu-latest, macos-latest, windows-latest] 16 | runs-on: ${{ matrix.os }} 17 | steps: 18 | - name: Install Go 19 | uses: actions/setup-go@v3 20 | with: 21 | go-version: ${{ matrix.go-version }} 22 | 23 | - name: checkout 24 | uses: actions/checkout@v2 25 | 26 | - name: cache 27 | uses: actions/cache@v2 28 | with: 29 | path: ~/go/pkg/mod 30 | key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} 31 | restore-keys: | 32 | ${{ runner.os }}-go- 33 | 34 | - name: test 35 | run: go test -v ./... 36 | 37 | test_build_proto: 38 | strategy: 39 | matrix: 40 | go-version: 41 | - 1.14.x 42 | - 1.15.x 43 | - 1.16.x 44 | - 1.17.x 45 | os: [ubuntu-latest] 46 | runs-on: ${{ matrix.os }} 47 | steps: 48 | - name: Install Go 49 | uses: actions/setup-go@v3 50 | with: 51 | go-version: ${{ matrix.go-version }} 52 | 53 | - name: checkout 54 | uses: actions/checkout@v2 55 | 56 | - name: cache 57 | uses: actions/cache@v2 58 | with: 59 | path: ~/go/pkg/mod 60 | key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} 61 | restore-keys: | 62 | ${{ runner.os }}-go- 63 | 64 | - run: | 65 | ./install-protoc.sh 66 | # mac issue: need to add execute privilege 67 | chmod +x bin/protoc 68 | echo "$PWD/bin" >> $GITHUB_PATH 69 | 70 | - run: | 71 | go get github.com/gogo/protobuf/protoc-gen-gogofaster@v1.3.2 72 | 73 | - run: | 74 | go env GOPATH 75 | export GOPATH=$(go env GOPATH) 76 | echo "GOPATH: ($GOPATH)" 77 | ./gen-proto.sh 78 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, build with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Mac hidden file 15 | .DS_Store 16 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | image: gitpod/workspace-full 2 | 3 | tasks: 4 | - init: go get && go build ./... && go test ./... && make 5 | command: go run 6 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/dictionaries/drdrxp.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | paxos 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/paxoskv.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/watcherTasks.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 16 | 28 | 29 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.14.x 5 | - 1.15.x 6 | - 1.16.x 7 | - 1.17.x 8 | - tip 9 | 10 | jobs: 11 | # go tip does not pass: 12 | # paxoskv/impl.go:12:2: no required module provides package golang.org/x/net/context; try 'go mod tidy' to add it 13 | allow_failures: 14 | - go: tip 15 | install: 16 | - ./install-protoc.sh 17 | - go get github.com/gogo/protobuf/protoc-gen-gogofaster@v1.3.2 18 | script: 19 | - ./gen-proto.sh 20 | - go test ./... 21 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | gen: 2 | ./gen-proto.sh 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mmp3: multi-master Paxos based kv storage 2 | 3 | ![main](https://github.com/openacid/mmp3/workflows/test/badge.svg?branch=main) 4 | [![travis](https://travis-ci.com/openacid/mmp3.svg?branch=naive)](https://travis-ci.com/openacid/mmp3) 5 | 6 | ![](https://blog.openacid.com/post-res/mmp3/digraphqueue_demosize=1010dpi=10-b5ab13197d2fba30.jpg) 7 | 8 | mmp3 中文介绍: https://blog.openacid.com/algo/mmp3 9 | 10 | MMP3 is a multi-master distributed consensus protocol built on top of classic Paxos. 11 | The application API is similar to raft except that **every node is a leader** and can handle write requests. 12 | 13 | - Exhibits a distributed **log-state-machine** model, similar to raft. 14 | - Exactly three nodes in a cluster. 15 | - Every node is a leader and is able to handle write requests without conflict. 16 | - A message is committed in **exactly one RTT**(unlike epaxos which requires two RTT if logs interfere with others). 17 | 18 | # Question 19 | 20 | Any questions or suggestions, feel free to open a [issue][] :DDD. 21 | 22 | 23 | [issue]: https://github.com/openacid/mmp3/issues/new/choose 24 | -------------------------------------------------------------------------------- /faq/diff-from-epaxos-indirect-deps/image-20220411135435500.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openacid/mmp3/69c406a6676a54435d022d87b0eff0d6ed45e3f5/faq/diff-from-epaxos-indirect-deps/image-20220411135435500.png -------------------------------------------------------------------------------- /faq/diff-from-epaxos-indirect-deps/index.md: -------------------------------------------------------------------------------- 1 | mmp3 协议中易被忽略的细节: 包含间接依赖才能保证线性一致性 2 | 3 | [mmp3](https://blog.openacid.com/algo/mmp3/) 跟 epaxos 有个不同的地方, instance 复制到 replica 时要记录所有依赖的instance, 包括间接依赖的. 这是mmp3 保证 线性一致性的一个条件, 读过epaxos的同学可能会漏掉这个细节导致无法证明线性一致性. 例如下面这个容易出现疑问的 case: 4 | 5 | ``` 6 | Legend: 7 | 8 | Ri: replica 9 | A, B, C: instance 10 | A->{B}: instance A depends on instance B 11 | A->{B, C}: instance A depends on instance B and C 12 | 13 | timeline: 14 | 15 | R1 A B->{A} A->{C} 16 | | ^ | ^ 17 | .----------------|---' '-----|----. 18 | | | .----' v 19 | R2 B C->{B} | | B->{A} 20 | ^ '----. '---. | 21 | .--' v v | 22 | R3 C C->{B} A->{C} 23 | ---+--+------+------+---+-------+----+------> time 24 | t1 t2 t3 t4 t5 t6 t7 25 | ``` 26 | 27 | - t1: R2 propose B, 写到本地, R3 propose C, 写到本地. 28 | - t2: R3 复制 C 到 R2, 写到 R2 磁盘的 C 包含对 B 的依赖: `C->{B}`. 29 | - t3: R3 收到 response, 提交 `C->{B}`. 30 | - t4: R1 propose A. 31 | - **t5**: R1 复制 A 到 R3, R3记录 `A->{C}`(这步是有问题的, **重点**), 同时 R2 复制 B 到 R1, R1 记录 `B->{A}`. 32 | - t6: R1 收到 response, 提交 `A->{C}`. 33 | - t7: R2 收到 response, 提交 `B->{A}`. 34 | 35 | 这里有个容易漏掉的细节是, t5 时, 在 R3 上记录的 A, 应记录 `A->{B,C}`, 而不仅是`A->{B}`. 36 | 37 | 也就是说, **间接依赖的 instance 都应被记录到一个 instance 的依赖集(`Deps`) 里**. 这是 mmp3 跟 epaxos 不一样的地方, 这个改进保证了 mmp3 算法的正确性. (也是这个原因, epaxos 里因为没有记录间接依赖, 在修复过程中会导致也不一致). 38 | 39 | 如果没有这个细节, 最终形成的依赖关系是: 40 | 41 | ``` 42 | B <---. 43 | | | 44 | | | 45 | v | 46 | A --> C 47 | ``` 48 | 49 | 通过比较每个 instance 的依赖集的大小和column index,最终执行顺序是ABC, 违反了Linearizability的原则: A 在 C 提交之后被propose, 应该在C之后被apply. 50 | 51 | 加入这个间接依赖的约束后, t5时间A的依赖应为`{B,C}`,最终形成的依赖图如下: 52 | 53 | 54 | ``` 55 | B <---. 56 | |^ | 57 | || | 58 | v| | 59 | A ---> C 60 | ``` 61 | 62 | - `A->{B,C}` 63 | - `B->{A}` 64 | - `C->{A}` 65 | 66 | 此时B被先 apply, 剩下`A->C`, 再apply C,然后是A, 保证了 Linearizability 的约束. 67 | 68 | ![image-20220411135435500](image-20220411135435500.png) 69 | 70 | - mmp3 介绍: https://blog.openacid.com/algo/mmp3/ 71 | - mmp3 源码: https://github.com/openacid/mmp3 72 | 73 | 欢迎在原文评论区讨论:DD https://blog.openacid.com/algo/mmp3/ 74 | -------------------------------------------------------------------------------- /gen-proto.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | 4 | # go get github.com/gogo/protobuf/protoc-gen-gogofast 5 | # go get github.com/gogo/protobuf/protoc-gen-gogofaster 6 | # go get github.com/gogo/protobuf/protoc-gen-gogoslick 7 | 8 | echo "GOPATH: ($GOPATH)" 9 | 10 | protoc -I=. \ 11 | -I=$GOPATH/pkg/mod/github.com/gogo/protobuf@v1.3.2 \ 12 | --proto_path=proto \ 13 | --gogofaster_out=plugins=grpc:paxoskv \ 14 | paxoskv.proto 15 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/openacid/mmp3 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/davecgh/go-spew v1.1.0 // indirect 7 | github.com/gogo/protobuf v1.3.2 // indirect 8 | github.com/golang/protobuf v1.5.2 // indirect 9 | github.com/kr/pretty v0.3.0 // indirect 10 | github.com/kr/text v0.2.0 // indirect 11 | github.com/patrickmn/go-cache v2.1.0+incompatible // indirect 12 | github.com/pmezard/go-difflib v1.0.0 // indirect 13 | github.com/rogpeppe/go-internal v1.6.1 // indirect 14 | github.com/stretchr/testify v1.7.1 // indirect 15 | golang.org/x/net v0.0.0-20201021035429-f5854403a974 // indirect 16 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f // indirect 17 | golang.org/x/text v0.3.3 // indirect 18 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect 19 | google.golang.org/grpc v1.45.0 // indirect 20 | google.golang.org/protobuf v1.26.0 // indirect 21 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect 22 | ) 23 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 4 | github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= 5 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 6 | github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 7 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 8 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 9 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 10 | github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= 11 | github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 12 | github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 13 | github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 14 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 15 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 16 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 17 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 18 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 19 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 20 | github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 21 | github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= 22 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 23 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 24 | github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= 25 | github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 26 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 27 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 28 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 29 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 30 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 31 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 32 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 33 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 34 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 35 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 36 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 37 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 38 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 39 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 40 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 41 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 42 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 43 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 44 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 45 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 46 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 47 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 48 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 49 | github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= 50 | github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= 51 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 52 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 53 | github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= 54 | github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= 55 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 56 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 57 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 58 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 59 | github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= 60 | github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= 61 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 62 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 63 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 64 | github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= 65 | github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= 66 | github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= 67 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 68 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 69 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 70 | github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= 71 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 72 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 73 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 74 | go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= 75 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 76 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 77 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 78 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 79 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 80 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 81 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 82 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 83 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 84 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 85 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 86 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 87 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 88 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 89 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 90 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 91 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 92 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 93 | golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= 94 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 95 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 96 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 97 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 98 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 99 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 100 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 101 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 102 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 103 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 104 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 105 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 106 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 107 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= 108 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 109 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 110 | golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= 111 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 112 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 113 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 114 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 115 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 116 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 117 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 118 | golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 119 | golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 120 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 121 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 122 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 123 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 124 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 125 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 126 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 127 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 128 | google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 129 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= 130 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 131 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 132 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 133 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 134 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 135 | google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= 136 | google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 137 | google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M= 138 | google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= 139 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 140 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 141 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 142 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 143 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 144 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 145 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 146 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 147 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 148 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 149 | google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= 150 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 151 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 152 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 153 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 154 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 155 | gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 156 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 157 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 158 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 159 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 160 | -------------------------------------------------------------------------------- /goid/getg_386.s: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Huan Du. All rights reserved. 2 | // Licensed under the MIT license that can be found in the LICENSE file. 3 | 4 | #include "go_asm.h" 5 | #include "go_tls.h" 6 | #include "textflag.h" 7 | 8 | TEXT ·getg(SB), NOSPLIT, $0-4 9 | get_tls(CX) 10 | MOVL g(CX), AX 11 | MOVL AX, ret+0(FP) 12 | RET 13 | -------------------------------------------------------------------------------- /goid/getg_amd64.s: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Huan Du. All rights reserved. 2 | // Licensed under the MIT license that can be found in the LICENSE file. 3 | 4 | #include "go_asm.h" 5 | #include "go_tls.h" 6 | #include "textflag.h" 7 | 8 | TEXT ·getg(SB), NOSPLIT, $0-8 9 | get_tls(CX) 10 | MOVQ g(CX), AX 11 | MOVQ AX, ret+0(FP) 12 | RET 13 | -------------------------------------------------------------------------------- /goid/getg_amd64p32.s: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Huan Du. All rights reserved. 2 | // Licensed under the MIT license that can be found in the LICENSE file. 3 | 4 | #include "getg_amd64.s" 5 | -------------------------------------------------------------------------------- /goid/getg_arm.s: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Huan Du. All rights reserved. 2 | // Licensed under the MIT license that can be found in the LICENSE file. 3 | 4 | #include "go_asm.h" 5 | #include "textflag.h" 6 | 7 | TEXT ·getg(SB), NOSPLIT, $0-4 8 | MOVW g, R8 9 | MOVW R8, ret+0(FP) 10 | RET 11 | -------------------------------------------------------------------------------- /goid/getg_arm64.s: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Huan Du. All rights reserved. 2 | // Licensed under the MIT license that can be found in the LICENSE file. 3 | 4 | #include "go_asm.h" 5 | #include "textflag.h" 6 | 7 | TEXT ·getg(SB), NOSPLIT, $0-4 8 | MOVW g, R8 9 | MOVW R8, ret+0(FP) 10 | RET 11 | -------------------------------------------------------------------------------- /goid/go_tls.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #ifdef GOARCH_arm 6 | #define LR R14 7 | #endif 8 | 9 | #ifdef GOARCH_amd64 10 | #define get_tls(r) MOVQ TLS, r 11 | #define g(r) 0(r)(TLS*1) 12 | #endif 13 | 14 | #ifdef GOARCH_amd64p32 15 | #define get_tls(r) MOVL TLS, r 16 | #define g(r) 0(r)(TLS*1) 17 | #endif 18 | 19 | #ifdef GOARCH_386 20 | #define get_tls(r) MOVL TLS, r 21 | #define g(r) 0(r)(TLS*1) 22 | #endif 23 | -------------------------------------------------------------------------------- /goid/goid.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Huan Du. All rights reserved. 2 | // Licensed under the MIT license that can be found in the LICENSE file. 3 | 4 | // Package g exposes goroutine struct g to user space. 5 | package goid 6 | 7 | import ( 8 | "fmt" 9 | "strconv" 10 | "time" 11 | "unsafe" 12 | 13 | "github.com/patrickmn/go-cache" 14 | ) 15 | 16 | var defID string = "0x0000000000" 17 | 18 | var idCache *cache.Cache 19 | var expTime = 120 * time.Minute 20 | var cleanTime = 1 * time.Minute 21 | var cleanExpTime = 5 * time.Minute 22 | 23 | func init() { 24 | idCache = cache.New(expTime, cleanTime) 25 | } 26 | 27 | func getg() unsafe.Pointer 28 | 29 | // G returns current g (the goroutine struct) to user space. 30 | func G() unsafe.Pointer { 31 | return getg() 32 | } 33 | 34 | func gP() (s string) { 35 | defer func() { 36 | if p := recover(); p != nil { 37 | s = defID 38 | } 39 | }() 40 | 41 | g := G() 42 | 43 | if g == nil { 44 | s = defID 45 | } else { 46 | s = fmt.Sprintf("%p", g) 47 | } 48 | 49 | return s 50 | } 51 | 52 | // ID returns goroutine g struct mem address with seq number as the id 53 | // note it's not the only one to guarantee that 54 | func ID() (s string) { 55 | id := gP() 56 | 57 | if v, ok := idCache.Get(id); ok { 58 | return id + strconv.FormatInt(v.(int64), 10) 59 | } 60 | 61 | return id + strconv.FormatInt(0, 10) 62 | } 63 | 64 | // SetID set goroutine id 65 | func SetID() (s string) { 66 | id := gP() 67 | 68 | // try to incr 1, may be error when id not exist 69 | if v, err := idCache.IncrementInt64(id, int64(1)); err == nil { 70 | idCache.Set(id, v, expTime) 71 | return id + strconv.FormatInt(v, 10) 72 | } 73 | 74 | // add id in cache, when it not exist, or it just deleted 75 | if err := idCache.Add(id, int64(0), expTime); err == nil { 76 | return id + strconv.FormatInt(0, 10) 77 | } 78 | 79 | //maybe someone else has already added it, so incr it again 80 | if v, err := idCache.IncrementInt64(id, int64(1)); err == nil { 81 | idCache.Set(id, v, expTime) 82 | return id + strconv.FormatInt(v, 10) 83 | } 84 | 85 | return id 86 | } 87 | 88 | // ExpireID expire goroutine id 89 | func ExpireID() { 90 | id := gP() 91 | 92 | v, ok := idCache.Get(id) 93 | if !ok { 94 | return 95 | } 96 | 97 | idCache.Set(id, v, cleanExpTime) 98 | } 99 | -------------------------------------------------------------------------------- /goid/goid_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Huan Du. All rights reserved. 2 | // Licensed under the MIT license that can be found in the LICENSE file. 3 | 4 | package goid 5 | 6 | import ( 7 | "sync" 8 | "testing" 9 | "time" 10 | ) 11 | 12 | func TestID(t *testing.T) { 13 | id1 := ID() 14 | 15 | if id1 == defID { 16 | t.Fatalf("fail to get goroutine id.") 17 | } 18 | 19 | t.Run("G in another goroutine", func(t *testing.T) { 20 | id2 := ID() 21 | 22 | if id2 == defID { 23 | t.Fatalf("fail to get goroutine id.") 24 | } 25 | 26 | if id2 == id1 { 27 | t.Fatalf("every living goroutine id must be different. [id1:%s] [id2:%s]", id1, id2) 28 | } 29 | }) 30 | } 31 | 32 | func TestSetID(t *testing.T) { 33 | SetID() 34 | id1 := ID() 35 | 36 | SetID() 37 | id2 := ID() 38 | 39 | if id1 == id2 { 40 | t.Fatalf("goroutine id must be different. [id1:%s] [id2:%s]", id1, id2) 41 | } 42 | } 43 | 44 | func TestExpireID(t *testing.T) { 45 | SetID() 46 | _ = ID() 47 | ExpireID() 48 | 49 | _, et, ok := idCache.GetWithExpiration(gP()) 50 | if !ok { 51 | t.Fatalf("failed get goroutine id") 52 | } 53 | 54 | if et.Sub(time.Now()) > cleanExpTime { 55 | t.Fatalf("expire id error") 56 | } 57 | } 58 | 59 | func TestConcurrentGetID(t *testing.T) { 60 | cntG := 100 61 | var wg sync.WaitGroup 62 | wg.Add(cntG) 63 | 64 | for i := 0; i < cntG; i++ { 65 | go func() { 66 | SetID() 67 | 68 | id1 := ID() 69 | 70 | for j := 0; j < 100000; j++ { 71 | id2 := ID() 72 | if id1 != id2 { 73 | t.Fatalf("goroutine id must be equal. [id1:%s] [id2:%s]", id1, id2) 74 | } 75 | } 76 | wg.Done() 77 | }() 78 | } 79 | wg.Wait() 80 | } 81 | 82 | func BenchmarkID(b *testing.B) { 83 | SetID() 84 | _ = ID() 85 | } 86 | -------------------------------------------------------------------------------- /install-protoc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | PROTOBUF_VERSION=3.10.0 4 | PROTOC_FILENAME=protoc-${PROTOBUF_VERSION}-linux-x86_64.zip 5 | 6 | ( 7 | 8 | cd /home/travis 9 | 10 | wget https://github.com/google/protobuf/releases/download/v$PROTOBUF_VERSION/$PROTOC_FILENAME 11 | unzip $PROTOC_FILENAME 12 | bin/protoc --version 13 | 14 | ) 15 | -------------------------------------------------------------------------------- /loc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | 4 | fns=$(find . -name "*.go" \ 5 | | grep -v "\.pb\.go" \ 6 | | grep -v "_test.go") 7 | 8 | echo fns: $fns 9 | 10 | # fns=./paxoskv/impl.go 11 | 12 | for fn in $fns;do 13 | echo $fn 14 | cat $fn \ 15 | | grep -v "^ *//" \ 16 | | grep -v "^$" \ 17 | | grep -v "pretty\." \ 18 | | grep -v "dd(" \ 19 | | wc 20 | done 21 | 22 | cat $fns \ 23 | | grep -v "^ *//" \ 24 | | grep -v "^$" \ 25 | | grep -v "pretty\." \ 26 | | grep -v "dd(" \ 27 | | wc 28 | -------------------------------------------------------------------------------- /paxoskv/api.go: -------------------------------------------------------------------------------- 1 | package paxoskv 2 | 3 | import ( 4 | "sort" 5 | 6 | "golang.org/x/net/context" 7 | ) 8 | 9 | func (s *KVServer) HandlePaxos(c context.Context, req *Request) (*Reply, error) { 10 | _ = c 11 | 12 | dd(s, "recv HandlePaxos-req: %s", req.str()) 13 | 14 | s.Lock() 15 | defer s.Unlock() 16 | 17 | col := s.log.columns[req.Column] 18 | 19 | reply := &Reply{ 20 | LastBal: col.LastBal.Clone(), 21 | Instances: make(map[int64]*Ins), 22 | } 23 | 24 | if req.Bal.Less(col.LastBal) { 25 | return reply, nil 26 | } 27 | 28 | // granted 29 | 30 | col.LastBal = req.Bal.Clone() 31 | 32 | lsns := make([]int64, 0) 33 | for lsn := range req.Instances { 34 | lsns = append(lsns, lsn) 35 | } 36 | 37 | sort.Slice(lsns, func(i, j int) bool { 38 | return lsns[i] < lsns[j] 39 | }) 40 | 41 | for _, lsn := range lsns { 42 | inst := req.Instances[lsn] 43 | inst = s.hdlOps(req, inst) 44 | reply.Instances[lsn] = inst 45 | } 46 | 47 | dd(s, "send Reply: %s", reply.str()) 48 | 49 | return reply, nil 50 | } 51 | 52 | // Set impl the KV API and handles a Set request from client. 53 | // Only the Key and Vi64 should be set in req. 54 | func (s *KVServer) Set(c context.Context, cmd *Cmd) (*Cmd, error) { 55 | 56 | dd(s, "hdl Set: %s", cmd.str()) 57 | 58 | for { 59 | select { 60 | case <-c.Done(): 61 | return nil, c.Err() 62 | default: 63 | } 64 | 65 | s.Lock() 66 | inst := s.allocNewInst(s.Id, cmd) 67 | s.Unlock() 68 | 69 | h := NewHandler(s, inst) 70 | dd(h, "hdl set: %s", cmd.str()) 71 | 72 | lsn := inst.getLSN() 73 | committed := h.runPaxosLoop(s.Id, lsn, s.other) 74 | 75 | dd(h, "committed: %s, proposed: %s", committed.str(), inst.str()) 76 | if committed.InsId.Equal(inst.InsId) { 77 | return cmd, nil 78 | } 79 | dd(h, "another value committed, need to re-commit: %s", inst.str()) 80 | } 81 | } 82 | 83 | // Get impl the KV-API get method. 84 | // Only req.Key should be specified. 85 | func (s *KVServer) Get(c context.Context, req *Cmd) (*Cmd, error) { 86 | _ = c 87 | return s.stateMachine.get(req.Key) 88 | } 89 | -------------------------------------------------------------------------------- /paxoskv/apply.go: -------------------------------------------------------------------------------- 1 | package paxoskv 2 | 3 | // applier defines the API of an apply algorithm impl 4 | type applier interface { 5 | // getColumnToApply finds the column for next apply, by looking for an applicable instance starting from column `column`. 6 | // The returned column may not be `column`, i.e., the instance at `nextApplies` on column `column` depends on an instance on another column. 7 | // If no instance can be applied, i.e., a dependent instance is not isCommitted, error UncommittedErr returned. 8 | getColumnToApply(d *applyData, column int64) (int64, error) 9 | } 10 | 11 | func (h *Handler) apply() (int, error) { 12 | nApplied := 0 13 | for { 14 | n := h.applyAnyColumn() 15 | nApplied += n 16 | if n == 0 { 17 | return nApplied, nil 18 | } 19 | } 20 | } 21 | 22 | func (h *Handler) applyAnyColumn() int { 23 | nApplied := 0 24 | 25 | i := int64(0) 26 | // apply one of the columns 27 | for ; i < 3; i++ { 28 | n, err := h.applyNext(i) 29 | _ = err 30 | nApplied += n 31 | } 32 | return nApplied 33 | } 34 | 35 | // applyNext tries to apply the lowest non-applied instance on column `column`. 36 | func (h *Handler) applyNext(column int64) (int, error) { 37 | 38 | s := h.kvServer 39 | d := NewApplyData(s.log, s.stateMachine, h.getLogger()) 40 | 41 | applyColumn, err := h.kvServer.applier.getColumnToApply(d, column) 42 | dd(h, "applyNext from: %d, err: %v", applyColumn, err) 43 | if err != nil { 44 | return 0, err 45 | } 46 | 47 | lsn := s.stateMachine.nextApplies[applyColumn] 48 | 49 | inst := s.log.refInstance(applyColumn, lsn) 50 | 51 | s.stateMachine.applyInstance(h, inst) 52 | return 1, nil 53 | } 54 | -------------------------------------------------------------------------------- /paxoskv/apply_data.go: -------------------------------------------------------------------------------- 1 | package paxoskv 2 | 3 | import "log" 4 | 5 | // applyData contains all the info to decide which column is the next to apply: 6 | // - the LSN of the next instance to apply on every column 7 | // - the latest isCommitted LSN+1 on every column. 8 | // - what other instance LSNs the instance to apply sees. 9 | type applyData struct { 10 | nextCommits []int64 11 | nextApplies []int64 12 | seens [][]int64 13 | lg *log.Logger 14 | } 15 | 16 | // NewApplyData extracts info for applier to find out next instance to apply. 17 | func NewApplyData(log *Log, st *StateMachine, lg *log.Logger) *applyData { 18 | a := &applyData{ 19 | nextCommits: log.getNextCommits(), 20 | nextApplies: st.getNextApplies(), 21 | seens: [][]int64{nil, nil, nil}, 22 | lg: lg, 23 | } 24 | 25 | for column := int64(0); column < 3; column++ { 26 | if a.isCommitted(column) { 27 | ins := log.refInstance(column, a.nextApplies[column]) 28 | a.seens[column] = append(a.seens[column], ins.Deps...) 29 | } 30 | } 31 | 32 | return a 33 | } 34 | 35 | func (d *applyData) getLogger() *log.Logger { 36 | return d.lg 37 | } 38 | 39 | func (d *applyData) isCommitted(column int64) bool { 40 | return d.nextCommits[column] > d.nextApplies[column] 41 | } 42 | 43 | func (d *applyData) doesDependOn(column, depColumn int64) bool { 44 | return d.seens[column][depColumn] > d.nextApplies[depColumn] 45 | } 46 | 47 | // getDeps returns column index that is dependent by `column`. 48 | // If the next instance to apply on a dependent column is not isCommitted, NeedCommitted error returns. 49 | func (d *applyData) getDeps(column int64) ([]int64, error) { 50 | 51 | dd(d, "to find dep of %d", column) 52 | 53 | dependencies := make([]int64, 0, 3) 54 | for depColumn := int64(0); depColumn < 3; depColumn++ { 55 | if depColumn == column { 56 | continue 57 | } 58 | 59 | if d.doesDependOn(column, depColumn) { 60 | // column depends on depColumn 61 | if !d.isCommitted(depColumn) { 62 | return nil, &UncommittedErr{Column: depColumn} 63 | } 64 | dependencies = append(dependencies, depColumn) 65 | } 66 | } 67 | 68 | dd(d, "found deps of %d: %v", column, dependencies) 69 | return dependencies, nil 70 | } 71 | -------------------------------------------------------------------------------- /paxoskv/apply_test.go: -------------------------------------------------------------------------------- 1 | package paxoskv 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestKVServer_apply(t *testing.T) { 11 | 12 | ta := require.New(t) 13 | 14 | cases := []struct { 15 | name string 16 | fromColumn []*Column 17 | nextCommits []int64 18 | nextApply []int64 19 | wantSnapshot map[string]int64 20 | wantN int 21 | }{ 22 | { 23 | name: "no deps", 24 | fromColumn: []*Column{ 25 | {Log: []*Ins{nil, {InsId: NewInsId(0, 1, 0), Val: &Cmd{Key: "x", Vi64: 1}, Deps: []int64{1, 1, 1}, Committed: true}}}, 26 | {}, 27 | {}, 28 | }, 29 | nextCommits: []int64{2, 0, 0}, 30 | nextApply: []int64{1, 1, 1}, 31 | wantSnapshot: map[string]int64{"x": 1}, 32 | wantN: 1, 33 | }, 34 | { 35 | name: "depends on a nil log", 36 | fromColumn: []*Column{ 37 | {Log: []*Ins{nil, {Deps: []int64{1, 0, 0}}}}, 38 | {}, 39 | {}, 40 | }, 41 | nextCommits: []int64{0, 0, 0}, 42 | nextApply: []int64{0, 1, 1}, 43 | wantSnapshot: map[string]int64{}, 44 | wantN: 0, 45 | }, 46 | { 47 | name: "none committed", 48 | fromColumn: []*Column{ 49 | {Log: []*Ins{nil, {InsId: NewInsId(0, 1, 0), Deps: []int64{0, 2, 0}}}}, 50 | {}, 51 | {}, 52 | }, 53 | nextCommits: []int64{2, 1, 1}, 54 | nextApply: []int64{1, 1, 1}, 55 | wantSnapshot: map[string]int64{}, 56 | wantN: 0, 57 | }, 58 | { 59 | name: "committed, dep not committed", 60 | fromColumn: []*Column{ 61 | {column: 0, Log: []*Ins{nil, {InsId: NewInsId(0, 1, 0), Deps: []int64{0, 2, 0}, Committed: true}}}, 62 | {column: 1, Log: []*Ins{nil, {InsId: NewInsId(1, 1, 0), Deps: []int64{0, 1, 0}, Committed: false}}}, 63 | {column: 2}, 64 | }, 65 | nextCommits: []int64{2, 1, 0}, 66 | nextApply: []int64{1, 1, 1}, 67 | wantSnapshot: map[string]int64{}, 68 | wantN: 0, 69 | }, 70 | { 71 | name: "not committed, dep committed, only dep applied", 72 | fromColumn: []*Column{ 73 | {Log: []*Ins{nil, {InsId: NewInsId(0, 1, 0), Deps: []int64{0, 2, 0}}}}, 74 | {Log: []*Ins{nil, {InsId: NewInsId(1, 1, 0), Val: &Cmd{Key: "y", Vi64: 2}, Deps: []int64{0, 1, 0}, Committed: true}}}, 75 | {}, 76 | }, 77 | nextCommits: []int64{1, 2, 0}, 78 | nextApply: []int64{1, 1, 1}, 79 | wantSnapshot: map[string]int64{"y": 2}, 80 | wantN: 1, 81 | }, 82 | { 83 | name: "0->1 xx", 84 | fromColumn: []*Column{ 85 | {column: 0, Log: []*Ins{nil, {InsId: NewInsId(0, 1, 0), Val: &Cmd{Key: "x", Vi64: 1}, Deps: []int64{0, 2, 0}, Committed: true}}}, 86 | {column: 1, Log: []*Ins{nil, {InsId: NewInsId(1, 1, 0), Val: &Cmd{Key: "x", Vi64: 2}, Deps: []int64{0, 0, 0}, Committed: true}}}, 87 | {}, 88 | }, 89 | nextCommits: []int64{2, 2, 0}, 90 | nextApply: []int64{1, 1, 1}, 91 | wantSnapshot: map[string]int64{"x": 1}, 92 | wantN: 2, 93 | }, 94 | { 95 | name: "0->1, xy", 96 | fromColumn: []*Column{ 97 | {column: 0, Log: []*Ins{nil, {InsId: NewInsId(0, 1, 0), Val: &Cmd{Key: "x", Vi64: 1}, Deps: []int64{0, 2, 0}, Committed: true}}}, 98 | {column: 1, Log: []*Ins{nil, {InsId: NewInsId(1, 1, 0), Val: &Cmd{Key: "y", Vi64: 2}, Deps: []int64{0, 0, 0}, Committed: true}}}, 99 | {}, 100 | }, 101 | nextCommits: []int64{2, 2, 0}, 102 | nextApply: []int64{1, 1, 1}, 103 | wantSnapshot: map[string]int64{"x": 1, "y": 2}, 104 | wantN: 2, 105 | }, 106 | { 107 | name: "0->1<>2, 0->2, xyz", 108 | fromColumn: []*Column{ 109 | {column: 0, Log: []*Ins{nil, {InsId: NewInsId(0, 1, 0), Val: &Cmd{Key: "x", Vi64: 1}, Deps: []int64{0, 2, 2}, Committed: true}}}, 110 | {column: 1, Log: []*Ins{nil, {InsId: NewInsId(1, 1, 0), Val: &Cmd{Key: "y", Vi64: 2}, Deps: []int64{0, 0, 2}, Committed: true}}}, 111 | {column: 2, Log: []*Ins{nil, {InsId: NewInsId(2, 1, 0), Val: &Cmd{Key: "z", Vi64: 3}, Deps: []int64{0, 2, 0}, Committed: true}}}, 112 | }, 113 | nextCommits: []int64{2, 2, 2}, 114 | nextApply: []int64{1, 1, 1}, 115 | wantSnapshot: map[string]int64{"x": 1, "y": 2, "z": 3}, 116 | wantN: 3, 117 | }, 118 | { 119 | name: "0->1<>2, 0->2, yyz", 120 | fromColumn: []*Column{ 121 | {column: 0, Log: []*Ins{nil, {InsId: NewInsId(0, 1, 0), Val: &Cmd{Key: "y", Vi64: 1}, Deps: []int64{0, 2, 2}, Committed: true}}}, 122 | {column: 1, Log: []*Ins{nil, {InsId: NewInsId(1, 1, 0), Val: &Cmd{Key: "y", Vi64: 2}, Deps: []int64{0, 0, 2}, Committed: true}}}, 123 | {column: 2, Log: []*Ins{nil, {InsId: NewInsId(2, 1, 0), Val: &Cmd{Key: "z", Vi64: 3}, Deps: []int64{0, 2, 0}, Committed: true}}}, 124 | }, 125 | nextCommits: []int64{2, 2, 2}, 126 | nextApply: []int64{1, 1, 1}, 127 | wantSnapshot: map[string]int64{"y": 1, "z": 3}, 128 | wantN: 3, 129 | }, 130 | { 131 | name: "0->1<>2->0, xyz", 132 | fromColumn: []*Column{ 133 | {column: 0, Log: []*Ins{nil, {InsId: NewInsId(0, 1, 0), Val: &Cmd{Key: "x", Vi64: 1}, Deps: []int64{0, 2, 0}, Committed: true}}}, 134 | {column: 1, Log: []*Ins{nil, {InsId: NewInsId(1, 1, 0), Val: &Cmd{Key: "y", Vi64: 2}, Deps: []int64{0, 0, 2}, Committed: true}}}, 135 | {column: 2, Log: []*Ins{nil, {InsId: NewInsId(2, 1, 0), Val: &Cmd{Key: "z", Vi64: 3}, Deps: []int64{2, 2, 0}, Committed: true}}}, 136 | }, 137 | nextCommits: []int64{2, 2, 2}, 138 | nextApply: []int64{1, 1, 1}, 139 | wantSnapshot: map[string]int64{"x": 1, "y": 2, "z": 3}, 140 | wantN: 3, 141 | }, 142 | { 143 | name: "0->1<>2, 0->2 zyz", 144 | fromColumn: []*Column{ 145 | {column: 0, Log: []*Ins{nil, {InsId: NewInsId(0, 1, 0), Val: &Cmd{Key: "z", Vi64: 1}, Deps: []int64{0, 2, 2}, Committed: true}}}, 146 | {column: 1, Log: []*Ins{nil, {InsId: NewInsId(1, 1, 0), Val: &Cmd{Key: "y", Vi64: 2}, Deps: []int64{0, 0, 2}, Committed: true}}}, 147 | {column: 2, Log: []*Ins{nil, {InsId: NewInsId(2, 1, 0), Val: &Cmd{Key: "z", Vi64: 3}, Deps: []int64{0, 2, 0}, Committed: true}}}, 148 | }, 149 | nextCommits: []int64{2, 2, 2}, 150 | nextApply: []int64{1, 1, 1}, 151 | wantSnapshot: map[string]int64{"z": 1, "y": 2}, 152 | wantN: 3, 153 | }, 154 | { 155 | name: "0->1<>2->0 zyz", 156 | fromColumn: []*Column{ 157 | {column: 0, Log: []*Ins{nil, {InsId: NewInsId(0, 1, 0), Val: &Cmd{Key: "z", Vi64: 1}, Deps: []int64{0, 2, 0}, Committed: true}}}, 158 | {column: 1, Log: []*Ins{nil, {InsId: NewInsId(1, 1, 0), Val: &Cmd{Key: "y", Vi64: 2}, Deps: []int64{0, 0, 2}, Committed: true}}}, 159 | {column: 2, Log: []*Ins{nil, {InsId: NewInsId(2, 1, 0), Val: &Cmd{Key: "z", Vi64: 3}, Deps: []int64{2, 2, 0}, Committed: true}}}, 160 | }, 161 | nextCommits: []int64{2, 2, 2}, 162 | nextApply: []int64{1, 1, 1}, 163 | wantSnapshot: map[string]int64{"z": 3, "y": 2}, 164 | wantN: 3, 165 | }, 166 | { 167 | name: "no log to apply", 168 | fromColumn: []*Column{ 169 | {Log: []*Ins{nil, {Deps: []int64{0, 2, 0}, Committed: true}}}, 170 | {Log: []*Ins{nil, {Deps: []int64{0, 0, 2}, Committed: true}}}, 171 | {Log: []*Ins{nil, {Deps: []int64{0, 2, 0}, Committed: true}}}, 172 | }, 173 | nextCommits: []int64{0, 0, 0}, 174 | nextApply: []int64{2, 2, 2}, 175 | wantSnapshot: map[string]int64{}, 176 | wantN: 0, 177 | }, 178 | } 179 | 180 | for i, c := range cases { 181 | mes := fmt.Sprintf("%d-th: case: %+v", i+1, c) 182 | s := NewKVServer(1) 183 | s.log.columns = c.fromColumn 184 | s.log.nextCommits = c.nextCommits 185 | s.stateMachine.nextApplies = c.nextApply 186 | 187 | fmt.Println(c.name) 188 | 189 | h := NewHandler(s, nil) 190 | n, err := h.apply() 191 | _ = err 192 | 193 | st := s.stateMachine.getState() 194 | 195 | ta.Equal(c.wantN, n) 196 | ta.Equal(c.wantSnapshot, st, mes) 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /paxoskv/apply_vc.go: -------------------------------------------------------------------------------- 1 | package paxoskv 2 | 3 | import ( 4 | "math" 5 | ) 6 | 7 | // TODO: use TailBitmap to trace isCommitted status 8 | 9 | type ApplierVC struct{} 10 | 11 | func (a *ApplierVC) getColumnToApply(d *applyData, column int64) (int64, error) { 12 | 13 | if !d.isCommitted(column) { 14 | return 0, &UncommittedErr{Column: column} 15 | } 16 | 17 | minOrd, err := a.findMinOrd(d, column) 18 | dd(d, "found minOrd: %v err:%v", minOrd, err) 19 | if err != nil { 20 | return 0, err 21 | } 22 | 23 | minColumn := minOrd % 100 24 | dd(d, "choose column %d to apply", minColumn) 25 | return minColumn, nil 26 | } 27 | 28 | // findMinOrd walks the dependency graph and calculates the ord of every instance walked through. 29 | // It returns the minimal ord. 30 | func (a *ApplierVC) findMinOrd(d *applyData, column int64) (int64, error) { 31 | minOrd := int64(math.MaxInt64) 32 | accessed := map[int64]bool{} 33 | q := []int64{column} 34 | 35 | for i := 0; i < len(q); i++ { 36 | 37 | column := q[i] 38 | if accessed[column] { 39 | continue 40 | } 41 | accessed[column] = true 42 | 43 | deps, err := d.getDeps(column) 44 | dd(d, "found deps: %v, err:%v", deps, err) 45 | if err != nil { 46 | return 0, err 47 | } 48 | minOrd = min(minOrd, int64(len(deps)*100)+column) 49 | q = append(q, deps...) 50 | } 51 | dd(d, "minOrd: %v by walking from %s", minOrd, column) 52 | return minOrd, nil 53 | } 54 | -------------------------------------------------------------------------------- /paxoskv/apply_vc_test.go: -------------------------------------------------------------------------------- 1 | package paxoskv 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestApplierVC_getColumnToApply(t *testing.T) { 11 | 12 | ta := require.New(t) 13 | 14 | cases := []struct { 15 | name string 16 | columns []*Column 17 | nextCommits []int64 18 | nextApply []int64 19 | column int64 20 | wantFirst int64 21 | wantErr error 22 | }{ 23 | { 24 | name: "no deps, not committed", 25 | columns: []*Column{ 26 | {Log: []*Ins{nil, {Deps: []int64{1, 1, 1}}}}, 27 | {}, 28 | {}, 29 | }, 30 | nextCommits: []int64{1, 0, 0}, 31 | nextApply: []int64{1, 1, 1}, 32 | column: 0, 33 | wantFirst: 0, 34 | wantErr: &UncommittedErr{}, 35 | }, 36 | { 37 | name: "no deps, committed", 38 | columns: []*Column{ 39 | {Log: []*Ins{nil, {Deps: []int64{1, 1, 1}}}}, 40 | {}, 41 | {}, 42 | }, 43 | nextCommits: []int64{2, 0, 0}, 44 | nextApply: []int64{1, 1, 1}, 45 | column: 0, 46 | wantFirst: 0, 47 | wantErr: nil, 48 | }, 49 | { 50 | name: "depends on a nil log", 51 | columns: []*Column{ 52 | {Log: []*Ins{nil, {Deps: []int64{1, 0, 0}}}}, 53 | {}, 54 | {}, 55 | }, 56 | nextCommits: []int64{0, 0, 0}, 57 | nextApply: []int64{0, 1, 1}, 58 | column: 0, 59 | wantFirst: 0, 60 | wantErr: &UncommittedErr{}, 61 | }, 62 | { 63 | name: "none committed", 64 | columns: []*Column{ 65 | {Log: []*Ins{nil, {Deps: []int64{0, 2, 0}}}}, 66 | {}, 67 | {}, 68 | }, 69 | nextCommits: []int64{1, 0, 0}, 70 | nextApply: []int64{1, 1, 1}, 71 | column: 0, 72 | wantFirst: 0, 73 | wantErr: &UncommittedErr{}, 74 | }, 75 | { 76 | name: "committed, dep not committed", 77 | columns: []*Column{ 78 | {Log: []*Ins{nil, {Deps: []int64{0, 2, 0}}}}, 79 | {Log: []*Ins{nil, {Deps: []int64{0, 1, 0}}}}, 80 | {}, 81 | }, 82 | nextCommits: []int64{2, 1, 0}, 83 | nextApply: []int64{1, 1, 1}, 84 | column: 0, 85 | wantFirst: 0, 86 | wantErr: &UncommittedErr{}, 87 | }, 88 | { 89 | name: "not committed, dep committed", 90 | columns: []*Column{ 91 | {Log: []*Ins{nil, {Deps: []int64{0, 2, 0}}}}, 92 | {Log: []*Ins{nil, {Deps: []int64{0, 1, 0}}}}, 93 | {}, 94 | }, 95 | nextCommits: []int64{1, 2, 0}, 96 | nextApply: []int64{1, 1, 1}, 97 | column: 0, 98 | wantFirst: 0, 99 | wantErr: &UncommittedErr{}, 100 | }, 101 | { 102 | name: "not committed, dep committed apply the dep", 103 | columns: []*Column{ 104 | {Log: []*Ins{nil, {Deps: []int64{0, 2, 0}}}}, 105 | {Log: []*Ins{nil, {Deps: []int64{0, 1, 0}}}}, 106 | {}, 107 | }, 108 | nextCommits: []int64{1, 2, 0}, 109 | nextApply: []int64{1, 1, 1}, 110 | column: 1, 111 | wantFirst: 1, 112 | wantErr: nil, 113 | }, 114 | { 115 | name: "0->1 from 0", 116 | columns: []*Column{ 117 | {Log: []*Ins{nil, {Deps: []int64{0, 2, 0}}}}, 118 | {Log: []*Ins{nil, {Deps: []int64{0, 0, 0}}}}, 119 | {}, 120 | }, 121 | nextCommits: []int64{2, 2, 0}, 122 | nextApply: []int64{1, 1, 1}, 123 | column: 0, 124 | wantFirst: 1, 125 | wantErr: nil, 126 | }, 127 | { 128 | name: "0->1 from 1", 129 | columns: []*Column{ 130 | {Log: []*Ins{nil, {Deps: []int64{0, 2, 0}}}}, 131 | {Log: []*Ins{nil, {Deps: []int64{0, 0, 0}}}}, 132 | {}, 133 | }, 134 | nextCommits: []int64{2, 2, 0}, 135 | nextApply: []int64{1, 1, 1}, 136 | column: 1, 137 | wantFirst: 1, 138 | wantErr: nil, 139 | }, 140 | { 141 | name: "0->1<>2, 0->2", 142 | columns: []*Column{ 143 | {Log: []*Ins{nil, {Deps: []int64{0, 2, 2}}}}, 144 | {Log: []*Ins{nil, {Deps: []int64{0, 0, 2}}}}, 145 | {Log: []*Ins{nil, {Deps: []int64{0, 2, 0}}}}, 146 | }, 147 | nextCommits: []int64{2, 2, 2}, 148 | nextApply: []int64{1, 1, 1}, 149 | column: 0, 150 | wantFirst: 1, 151 | wantErr: nil, 152 | }, 153 | 154 | // 155 | // 0 after 1: 156 | // |.-----. 157 | // |v v 158 | // |0->1->2 159 | // | 160 | // | 02 C 161 | // |1 C 0 162 | // |21 C 163 | // | 164 | // | 1->2 165 | // | 0->1,2 166 | // | 2->0 167 | { 168 | name: "0->1->2<>0, from 0", 169 | columns: []*Column{ 170 | {Log: []*Ins{nil, {Deps: []int64{0, 2, 2}}}}, 171 | {Log: []*Ins{nil, {Deps: []int64{0, 0, 2}}}}, 172 | {Log: []*Ins{nil, {Deps: []int64{2, 0, 0}}}}, 173 | }, 174 | nextCommits: []int64{2, 2, 2}, 175 | nextApply: []int64{1, 1, 1}, 176 | column: 0, 177 | wantFirst: 1, 178 | wantErr: nil, 179 | }, 180 | 181 | { 182 | name: "0->1<>2->0, from 0", 183 | columns: []*Column{ 184 | {Log: []*Ins{nil, {Deps: []int64{0, 2, 1}}}}, 185 | {Log: []*Ins{nil, {Deps: []int64{0, 0, 2}}}}, 186 | {Log: []*Ins{nil, {Deps: []int64{2, 2, 0}}}}, 187 | }, 188 | nextCommits: []int64{2, 2, 2}, 189 | nextApply: []int64{1, 1, 1}, 190 | column: 0, 191 | wantFirst: 0, 192 | wantErr: nil, 193 | }, 194 | { 195 | name: "0->1<>2->0, from 1", 196 | columns: []*Column{ 197 | {Log: []*Ins{nil, {Deps: []int64{0, 2, 1}}}}, 198 | {Log: []*Ins{nil, {Deps: []int64{0, 0, 2}}}}, 199 | {Log: []*Ins{nil, {Deps: []int64{2, 2, 0}}}}, 200 | }, 201 | nextCommits: []int64{2, 2, 2}, 202 | nextApply: []int64{1, 1, 1}, 203 | column: 1, 204 | wantFirst: 0, 205 | wantErr: nil, 206 | }, 207 | { 208 | name: "0->1<>2->0, from 2", 209 | columns: []*Column{ 210 | {Log: []*Ins{nil, {Deps: []int64{0, 2, 1}}}}, 211 | {Log: []*Ins{nil, {Deps: []int64{0, 0, 2}}}}, 212 | {Log: []*Ins{nil, {Deps: []int64{2, 2, 0}}}}, 213 | }, 214 | nextCommits: []int64{2, 2, 2}, 215 | nextApply: []int64{1, 1, 1}, 216 | column: 2, 217 | wantFirst: 0, 218 | wantErr: nil, 219 | }, 220 | { 221 | name: "0->1->2->0, from 1", 222 | columns: []*Column{ 223 | {Log: []*Ins{{Deps: []int64{0, 1, 0}}}}, 224 | {Log: []*Ins{{Deps: []int64{0, 0, 1}}}}, 225 | {Log: []*Ins{{Deps: []int64{1, 0, 0}}}}, 226 | }, 227 | nextCommits: []int64{1, 1, 1}, 228 | nextApply: []int64{0, 0, 0}, 229 | column: 1, 230 | wantFirst: 0, 231 | wantErr: nil, 232 | }, 233 | { 234 | name: "0->1->2, 0->2, from 1, 1 has high vec", 235 | columns: []*Column{ 236 | {Log: []*Ins{{Deps: []int64{0, 1, 0}}}}, 237 | {Log: []*Ins{{Deps: []int64{0, 9, 1}}}}, 238 | {Log: []*Ins{{Deps: []int64{0, 0, 0}}}}, 239 | }, 240 | nextCommits: []int64{1, 1, 1}, 241 | nextApply: []int64{0, 0, 0}, 242 | column: 1, 243 | wantFirst: 2, 244 | wantErr: nil, 245 | }, 246 | { 247 | name: "0->1, from 0, 1 has high vec", 248 | columns: []*Column{ 249 | {Log: []*Ins{{Deps: []int64{0, 1, 0}}}}, 250 | {Log: []*Ins{{Deps: []int64{0, 9, 1}}}}, 251 | {Log: []*Ins{{Deps: []int64{0, 0, 0}}}}, 252 | }, 253 | nextCommits: []int64{1, 1, 1}, 254 | nextApply: []int64{0, 0, 1}, 255 | column: 0, 256 | wantFirst: 1, 257 | wantErr: nil, 258 | }, 259 | { 260 | name: "0<-1<-2, 0 not commit", 261 | columns: []*Column{ 262 | {Log: []*Ins{{Deps: []int64{0, 0, 0}}}}, 263 | {Log: []*Ins{{Deps: []int64{1, 0, 0}}}}, 264 | {Log: []*Ins{{Deps: []int64{0, 1, 0}}}}, 265 | }, 266 | nextCommits: []int64{0, 1, 1}, 267 | nextApply: []int64{0, 0, 0}, 268 | column: 0, 269 | wantFirst: 0, 270 | wantErr: &UncommittedErr{}, 271 | }, 272 | } 273 | 274 | for i, c := range cases { 275 | mes := fmt.Sprintf("%d-th: start from column: %d, case: %+v", i+1, c.column, c) 276 | s := NewKVServer(1) 277 | s.log.columns = c.columns 278 | s.log.nextCommits = c.nextCommits 279 | s.stateMachine.nextApplies = c.nextApply 280 | 281 | fmt.Println(c.name) 282 | 283 | a := &ApplierVC{} 284 | d := NewApplyData(s.log, s.stateMachine, nil) 285 | n, err := a.getColumnToApply(d, c.column) 286 | if c.wantErr != nil { 287 | ta.NotNil(err, mes) 288 | } else { 289 | ta.Nil(err, mes) 290 | } 291 | ta.Equal(c.wantFirst, n, mes) 292 | } 293 | } 294 | -------------------------------------------------------------------------------- /paxoskv/column.go: -------------------------------------------------------------------------------- 1 | package paxoskv 2 | 3 | import "fmt" 4 | 5 | // Column is the colLogs and states of leader-i 6 | type Column struct { 7 | // non nil if it is a leader. 8 | column int64 9 | Bal *BallotNum 10 | LastBal *BallotNum 11 | Log []*Ins 12 | } 13 | 14 | func NewColumn(id int64) *Column { 15 | return &Column{ 16 | column: id, 17 | LastBal: &BallotNum{N: 0, Id: id}, 18 | } 19 | } 20 | 21 | func (col *Column) getInstance(lsn int64) *Ins { 22 | if col.hasInstance(lsn) { 23 | return col.Log[lsn].Clone() 24 | } 25 | return nil 26 | } 27 | 28 | func (col *Column) addInstance(inst *Ins) { 29 | 30 | column, lsn := inst.getColLSN() 31 | for int(lsn) >= len(col.Log) { 32 | col.Log = append(col.Log, nil) 33 | } 34 | 35 | if col.Log[lsn] != nil { 36 | panic("add to non-nil:" + fmt.Sprintf("%d-%d", column, lsn)) 37 | } 38 | col.Log[lsn] = inst.Clone() 39 | } 40 | 41 | func (col *Column) hasInstance(lsn int64) bool { 42 | if lsn >= int64(len(col.Log)) { 43 | return false 44 | } 45 | 46 | return col.Log[lsn] != nil 47 | } 48 | 49 | func parseColLSN(x int64) (int64, int64) { 50 | m := int64(1000000000) 51 | return x / m, x % m 52 | } 53 | func colLSNIndentedStr(x int64) string { 54 | column, lsn := parseColLSN(x) 55 | return fmt.Sprintf("%[1]*d", column*5+3, lsn) 56 | } 57 | -------------------------------------------------------------------------------- /paxoskv/column_test.go: -------------------------------------------------------------------------------- 1 | package paxoskv 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestColumnT_hasInstance(t *testing.T) { 10 | 11 | ta := require.New(t) 12 | 13 | col := &Column{ 14 | Log: []*Ins{nil, {}, nil}, 15 | } 16 | 17 | ta.False(col.hasInstance(0)) 18 | ta.True(col.hasInstance(1)) 19 | ta.False(col.hasInstance(2)) 20 | ta.False(col.hasInstance(3)) 21 | } 22 | 23 | func TestColLSN(t *testing.T) { 24 | ta := require.New(t) 25 | 26 | column, lsn := int64(2), int64(5) 27 | 28 | packed := int64(2000000005) 29 | 30 | c, l := parseColLSN(packed) 31 | ta.Equal(column, c) 32 | ta.Equal(lsn, l) 33 | 34 | s := colLSNIndentedStr(packed) 35 | ta.Equal(" 5", s) 36 | } 37 | -------------------------------------------------------------------------------- /paxoskv/conf.go: -------------------------------------------------------------------------------- 1 | package paxoskv 2 | 3 | var ( 4 | AcceptorBasePort = int64(3333) 5 | 6 | sendErrorRate = float64(0) 7 | recvErrorRate = float64(0) 8 | ) 9 | -------------------------------------------------------------------------------- /paxoskv/derive.go: -------------------------------------------------------------------------------- 1 | package paxoskv 2 | 3 | import ( 4 | "github.com/gogo/protobuf/proto" 5 | ) 6 | 7 | func (b *BallotNum) Clone() *BallotNum { return proto.Clone(b).(*BallotNum) } 8 | func (b *Ins) Clone() *Ins { return proto.Clone(b).(*Ins) } 9 | func (b *Cmd) Clone() *Cmd { return proto.Clone(b).(*Cmd) } 10 | 11 | func (b *Cmd) isNoop() bool { 12 | return b.Key == "NOOP" 13 | } 14 | 15 | func NewBal(n, id int64) *BallotNum { 16 | return &BallotNum{ 17 | N: n, 18 | Id: id, 19 | } 20 | } 21 | func NewInsId(column, lsn, n int64) *InsId { 22 | return &InsId{ 23 | Column: column, 24 | LSN: lsn, 25 | ProposerId: n, 26 | } 27 | } 28 | 29 | func NewCmd(expr string, lsn int64) *Cmd { 30 | c := &Cmd{ 31 | Key: expr, 32 | Vi64: lsn, 33 | } 34 | 35 | return c 36 | } 37 | 38 | func (a *BallotNum) Less(b *BallotNum) bool { 39 | // Vbal == nil is a fast-accepted state 40 | // a == b == nil return false: not comparable 41 | if b == nil { 42 | return false 43 | } 44 | 45 | if a == nil { 46 | return true 47 | } 48 | 49 | // a!= nil && b != nil 50 | 51 | if a.N != b.N { 52 | return a.N < b.N 53 | } 54 | 55 | return a.Id < b.Id 56 | } 57 | 58 | func (a *BallotNum) LessEqual(b *BallotNum) bool { 59 | // two nil are incomparable 60 | return a.Less(b) || (a != nil && a.Equal(b)) 61 | } 62 | -------------------------------------------------------------------------------- /paxoskv/derive_test.go: -------------------------------------------------------------------------------- 1 | package paxoskv 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestBallotNum_Less(t *testing.T) { 11 | ta := require.New(t) 12 | 13 | cases := []struct { 14 | a, b *BallotNum 15 | want bool 16 | }{ 17 | {nil, nil, false}, 18 | {&BallotNum{}, nil, false}, 19 | {nil, &BallotNum{}, true}, 20 | {&BallotNum{N: 1}, &BallotNum{N: 1}, false}, 21 | {&BallotNum{N: 2}, &BallotNum{N: 1}, false}, 22 | {&BallotNum{N: 1}, &BallotNum{N: 2}, true}, 23 | {&BallotNum{N: 2, Id: 1}, &BallotNum{N: 2, Id: 1}, false}, 24 | {&BallotNum{N: 2, Id: 2}, &BallotNum{N: 2, Id: 1}, false}, 25 | {&BallotNum{N: 2, Id: 1}, &BallotNum{N: 2, Id: 2}, true}, 26 | } 27 | 28 | for i, c := range cases { 29 | mes := fmt.Sprintf("%d-th: case: %+v %s %s", i+1, c, c.a.str(), c.b.str()) 30 | ta.Equal(c.want, c.a.Less(c.b), mes) 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /paxoskv/error.go: -------------------------------------------------------------------------------- 1 | package paxoskv 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | var ( 9 | HigherBalErr = errors.New("seen a higher ballot") 10 | AlreadyPrepared = errors.New("already prepared") 11 | FakeErr = errors.New("fake error") 12 | ) 13 | 14 | type UncommittedErr struct { 15 | Column int64 16 | } 17 | 18 | func (e *UncommittedErr) Error() string { 19 | return fmt.Sprintf("not committed: %d", e.Column) 20 | } 21 | -------------------------------------------------------------------------------- /paxoskv/example_setget_kvapi_test.go: -------------------------------------------------------------------------------- 1 | package paxoskv 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "time" 7 | 8 | "golang.org/x/net/context" 9 | "google.golang.org/grpc" 10 | ) 11 | 12 | func Example_setAndGet_KVAPI() { 13 | 14 | serverIds := []int64{0, 1, 2} 15 | 16 | servers := serveKVServers(serverIds) 17 | defer func() { 18 | for _, s := range servers { 19 | s.grpcSrv.Stop() 20 | } 21 | }() 22 | 23 | var wg sync.WaitGroup 24 | input := make(chan *Cmd, 1000) 25 | 26 | // 5 concurrent proposers 27 | 28 | for i := 0; i < 5; i++ { 29 | wg.Add(1) 30 | go func(aid int64) { 31 | defer wg.Done() 32 | for req := range input { 33 | 34 | ctx, cancel := context.WithTimeout(context.Background(), time.Second) 35 | defer cancel() 36 | 37 | address := fmt.Sprintf("127.0.0.1:%d", 3333+int64(aid)) 38 | conn, err := grpc.Dial(address, grpc.WithInsecure()) 39 | if err != nil { 40 | panic(err.Error()) 41 | } 42 | defer conn.Close() 43 | 44 | c := NewPaxosKVClient(conn) 45 | 46 | _, err = c.Set(ctx, req) 47 | if err != nil { 48 | panic(err.Error()) 49 | } 50 | 51 | reply, err := c.Get(ctx, &Cmd{Key: req.Key}) 52 | if err != nil { 53 | panic(err.Error()) 54 | } 55 | 56 | // Get may got a different value since Set happens concurrently 57 | fmt.Println("Set:", req.Key, req.Vi64, "Get:", reply.Key, reply.Vi64) 58 | 59 | } 60 | }(serverIds[i%len(serverIds)]) 61 | } 62 | 63 | nreq := 10 64 | for i := 0; i < nreq; i++ { 65 | input <- &Cmd{ 66 | Key: string("abcd"[i%2]), 67 | Vi64: int64(i), 68 | } 69 | } 70 | close(input) 71 | wg.Wait() 72 | } 73 | -------------------------------------------------------------------------------- /paxoskv/handler.go: -------------------------------------------------------------------------------- 1 | package paxoskv 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "math/rand" 7 | "os" 8 | "time" 9 | 10 | "github.com/gogo/protobuf/proto" 11 | "golang.org/x/net/context" 12 | "google.golang.org/grpc" 13 | ) 14 | 15 | // Handler for one instance 16 | type Handler struct { 17 | kvServer *KVServer 18 | inst *Ins 19 | lg *log.Logger 20 | txId string 21 | } 22 | 23 | func NewHandler(s *KVServer, inst *Ins) *Handler { 24 | 25 | txId := fmt.Sprintf("R%d:tx:?-?-?", s.Id) 26 | if inst != nil { 27 | txId = fmt.Sprintf("R%d:tx:%s", s.Id, inst.InsId.str()) 28 | } 29 | 30 | h := &Handler{ 31 | kvServer: s, 32 | inst: inst, 33 | txId: txId, 34 | lg: log.New(os.Stderr, txId+" ", log.Ltime|log.Lmicroseconds|log.Lshortfile|log.Lmsgprefix), 35 | } 36 | return h 37 | } 38 | 39 | func (h *Handler) getLogger() *log.Logger { 40 | return h.lg 41 | } 42 | 43 | func (h *Handler) sendCommit(column int64, instances map[int64]*Ins) { 44 | s := h.kvServer 45 | 46 | req := &Request{ 47 | Op: Op_Commit, 48 | Column: column, 49 | Instances: instances, 50 | } 51 | for _, to := range s.other { 52 | go func(to int64) { 53 | for i := 0; i < 3; i++ { 54 | err := h.rpcTo(to, "HandlePaxos", req, &Reply{}) 55 | if err == nil { 56 | dd(h, "Commit done to %d column:%d %s", to, column, instsStr(instances)) 57 | return 58 | } 59 | dd(h, "Commit err: %s, column:%d %s", err.Error(), column, instsStr(instances)) 60 | time.Sleep(time.Millisecond * 10) 61 | } 62 | dd(h, "Commit fail to %d column:%d %s", to, column, instsStr(instances)) 63 | }(to) 64 | } 65 | dd(h, "Commit sent: column:%d %s", column, instsStr(instances)) 66 | } 67 | 68 | func (h *Handler) setInstance(inst *Ins) { 69 | s := h.kvServer 70 | column, lsn := inst.getColLSN() 71 | col := s.log.columns[column] 72 | 73 | for int(lsn) >= len(col.Log) { 74 | col.Log = append(col.Log, nil) 75 | } 76 | 77 | cc := col.Log[lsn] 78 | if cc != nil && cc.Committed { 79 | if !cc.Val.Equal(inst.Val) || !vecEq(cc.Deps, inst.Deps) { 80 | bug(h, "trying to set a committed instance with different value: %s %s", cc.str(), inst.str()) 81 | } 82 | } 83 | col.Log[lsn] = inst.Clone() 84 | dd(h, "setInstance: column:%d, inst:%s", column, inst.str()) 85 | } 86 | 87 | // prepare the instance on local server 88 | func (h *Handler) localPrepare(column, lsn int64) (*BallotNum, *Ins) { 89 | 90 | s := h.kvServer 91 | 92 | col := s.log.columns[column] 93 | 94 | s.Lock() 95 | defer s.Unlock() 96 | 97 | if col.Bal == nil { 98 | dd(h, "localPrepare: column: %d, incr lastBal: %s", column, col.LastBal.str()) 99 | 100 | // next ballot and prepare myself 101 | col.LastBal.N++ 102 | col.LastBal.Id = s.Id 103 | col.Bal = col.LastBal.Clone() 104 | } else { 105 | dd(h, "localPrepare: column: %d, use current bal: %s", column, col.Bal.str()) 106 | } 107 | 108 | // NOTE: after prepare, it must re-fetch the local latest value. 109 | return col.Bal.Clone(), col.Log[lsn].Clone() 110 | } 111 | 112 | func (h *Handler) runPaxosLoop(column, lsn int64, dsts []int64) *Ins { 113 | // this is the only goroutine to have a bal. 114 | // No two proposers are allowed to have the same bal 115 | for i := 0; ; i++ { 116 | bal, inst := h.localPrepare(column, lsn) 117 | // every time retry running paxos, choose a different candidate 118 | dst := dsts[i%len(dsts)] 119 | committed, err := h.runPaxos(bal, column, dst, inst) 120 | if err == nil { 121 | return committed 122 | } 123 | } 124 | } 125 | 126 | func (h *Handler) runPaxos(bal *BallotNum, column, to int64, inst *Ins) (*Ins, error) { 127 | 128 | s := h.kvServer 129 | dd(h, "runPaxos: %s", inst.str()) 130 | 131 | col := s.log.columns[column] 132 | lsn := inst.getLSN() 133 | req := &Request{ 134 | Op: Op_Accept, 135 | Bal: bal.Clone(), 136 | Column: column, 137 | Instances: map[int64]*Ins{lsn: inst}, 138 | } 139 | 140 | reply := new(Reply) 141 | err := h.rpcTo(to, "HandlePaxos", req, reply) 142 | if err != nil { 143 | s.invalidateLastBal(column, bal) 144 | return nil, HigherBalErr 145 | } 146 | 147 | if bal.Less(reply.LastBal) { 148 | dd(h, "bal < reply.LastBal: %s < %s", bal.str(), reply.LastBal.str()) 149 | s.invalidateLastBal(column, reply.LastBal) 150 | return nil, HigherBalErr 151 | } 152 | 153 | remote := reply.Instances[lsn] 154 | 155 | s.Lock() 156 | defer s.Unlock() 157 | 158 | if bal.Less(col.LastBal) { 159 | dd(h, "bal < col.LastBal: %s < %s", bal.str(), col.LastBal.str()) 160 | return nil, HigherBalErr 161 | } 162 | 163 | local := col.Log[lsn] 164 | if local.VBal.Less(remote.VBal) { 165 | h.setInstance(remote) 166 | } else { 167 | // local >= remote 168 | 169 | // replied instance.Vbal is the req.Bal; 170 | // thus there is no chance local >= remote. 171 | bug(h, "impossible: local >= remote: %s %s", local.str(), remote.str()) 172 | } 173 | 174 | local = col.Log[lsn] 175 | h.hdlCommit(local) 176 | h.sendCommit(column, 177 | map[int64]*Ins{ 178 | local.getLSN(): local, 179 | }) 180 | 181 | return local, nil 182 | } 183 | 184 | func (h *Handler) rpcTo(to int64, method string, req, reply proto.Message) error { 185 | 186 | // With heavy competition an operation takes longer time to finish. 187 | // There is still chance no leader is established before timeout. 188 | 189 | dd(h, "send %s-req to R%d %s", method, to, req.(strer).str()) 190 | 191 | if rand.Float64() < sendErrorRate { 192 | dd(h, "fake sendError to R%d, req: %s", to, req.(strer).str()) 193 | return FakeErr 194 | } 195 | 196 | ctx, cancel := context.WithTimeout(context.Background(), time.Second*3) 197 | defer cancel() 198 | 199 | address := fmt.Sprintf("127.0.0.1:%d", AcceptorBasePort+int64(to)) 200 | conn, err := grpc.Dial(address, grpc.WithInsecure()) 201 | if err != nil { 202 | dd(h, "did not connect: %s", err.Error()) 203 | return err 204 | } 205 | defer conn.Close() 206 | 207 | fakeRecvErr := rand.Float64() < recvErrorRate 208 | if fakeRecvErr { 209 | // do not let caller to receive the reply 210 | reply = proto.Clone(reply) 211 | } 212 | err = conn.Invoke(ctx, "/paxoskv.PaxosKV/"+method, req, reply) 213 | if err != nil { 214 | dd(h, "recv %s-reply from R%d err: %s", method, to, err) 215 | } else { 216 | dd(h, "recv %s-reply from R%d %s", method, to, reply.(strer).str()) 217 | } 218 | 219 | if fakeRecvErr { 220 | dd(h, "fake recvError from R%d, req: %s", to, req.(strer).str()) 221 | return FakeErr 222 | } 223 | return err 224 | } 225 | -------------------------------------------------------------------------------- /paxoskv/handler_test.go: -------------------------------------------------------------------------------- 1 | package paxoskv 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestKVServer_allocNewInst(t *testing.T) { 11 | 12 | ta := require.New(t) 13 | 14 | cases := []struct { 15 | name string 16 | column int64 17 | cmd *Cmd 18 | wantInst string 19 | wantLogs string 20 | }{ 21 | { 22 | name: "010", 23 | column: 1, 24 | cmd: NewCmd("x", 1), 25 | wantInst: "<1-0-1: vbal:nil c:false seen:0,1,0>", 26 | wantLogs: "<1-0-1: vbal:nil c:false seen:0,1,0>", 27 | }, 28 | { 29 | name: "110", 30 | column: 0, 31 | cmd: NewCmd("y", 1), 32 | wantInst: "<0-0-1: vbal:nil c:false seen:1,1,0>", 33 | wantLogs: "<0-0-1: vbal:nil c:false seen:1,1,0>", 34 | }, 35 | { 36 | name: "210", 37 | column: 0, 38 | cmd: NewCmd("z", 1), 39 | wantInst: "<0-1-1: vbal:nil c:false seen:2,1,0>", 40 | wantLogs: "<0-0-1: vbal:nil c:false seen:1,1,0>,<0-1-1: vbal:nil c:false seen:2,1,0>", 41 | }, 42 | { 43 | name: "211", 44 | column: 2, 45 | cmd: NewCmd("u", 1), 46 | wantInst: "<2-0-1: vbal:nil c:false seen:2,1,1>", 47 | wantLogs: "<2-0-1: vbal:nil c:false seen:2,1,1>", 48 | }, 49 | } 50 | 51 | s := NewKVServer(1) 52 | for i, c := range cases { 53 | mes := fmt.Sprintf("%d-th: case: %+v", i+1, c) 54 | 55 | inst := s.allocNewInst(c.column, c.cmd) 56 | 57 | ta.Equal(c.wantInst, inst.str(), mes) 58 | ta.Equal(c.wantLogs, logsStr(s.log.columns[c.column].Log), mes) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /paxoskv/instance.go: -------------------------------------------------------------------------------- 1 | package paxoskv 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func (inst *Ins) getColumn() int64 { 8 | return inst.InsId.Column 9 | } 10 | 11 | func (inst *Ins) getLSN() int64 { 12 | return inst.InsId.LSN 13 | } 14 | 15 | func (inst *Ins) getColLSN() (int64, int64) { 16 | return inst.getColumn(), inst.getLSN() 17 | } 18 | 19 | func (inst *Ins) updateDeps(u []int64) { 20 | for i := 0; i < 3; i++ { 21 | inst.Deps[i] = max(inst.Deps[i], u[i]) 22 | } 23 | } 24 | 25 | func (inst *Ins) packedPosition() int64 { 26 | column, lsn := inst.getColLSN() 27 | m := int64(1000000000) 28 | return column*m + lsn 29 | } 30 | func (inst *Ins) colLSNIndentedStr() string { 31 | column, lsn := inst.getColLSN() 32 | return fmt.Sprintf("%[1]*d", column*5+3, lsn) 33 | } 34 | -------------------------------------------------------------------------------- /paxoskv/instance_test.go: -------------------------------------------------------------------------------- 1 | package paxoskv 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestInstance_getColumn_LSN(t *testing.T) { 10 | ta := require.New(t) 11 | inst := &Ins{ 12 | InsId: NewInsId(10, 5, 1), 13 | Val: &Cmd{}} 14 | ta.Equal(int64(10), inst.getColumn()) 15 | 16 | ta.Equal(int64(5), inst.getLSN()) 17 | 18 | c, l := inst.getColLSN() 19 | ta.Equal(int64(10), c) 20 | ta.Equal(int64(5), l) 21 | 22 | } 23 | func TestInstance_packedPosition(t *testing.T) { 24 | ta := require.New(t) 25 | 26 | inst := &Ins{ 27 | InsId: NewInsId(2, 5, 0), 28 | Val: &Cmd{}} 29 | 30 | packed := inst.packedPosition() 31 | ta.Equal(int64(2000000005), packed, "packed") 32 | 33 | s := inst.colLSNIndentedStr() 34 | ta.Equal(" 5", s) 35 | } 36 | -------------------------------------------------------------------------------- /paxoskv/log.go: -------------------------------------------------------------------------------- 1 | package paxoskv 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | type Log struct { 9 | nextCommits []int64 10 | columns []*Column 11 | } 12 | 13 | func NewLog() *Log { 14 | return &Log{ 15 | nextCommits: []int64{0, 0, 0}, 16 | columns: []*Column{ 17 | NewColumn(0), 18 | NewColumn(1), 19 | NewColumn(2), 20 | }, 21 | } 22 | } 23 | 24 | func (l *Log) getNextCommits() []int64 { 25 | return dupI64s(l.nextCommits) 26 | } 27 | 28 | func (l *Log) refInstance(column, lsn int64) *Ins { 29 | return l.columns[column].Log[lsn] 30 | } 31 | 32 | func (s *KVServer) graphviz() string { 33 | l := s.log 34 | as := s.stateMachine.applySeq 35 | lines := []string{ 36 | "digraph x", 37 | "{", 38 | "node [shape=plaintext]", 39 | "rankdir=LR", 40 | } 41 | 42 | letters := "abc" 43 | 44 | for column := 0; column < 3; column++ { 45 | col := l.columns[column] 46 | 47 | allSymbols := []string{} 48 | for lsn, ins := range col.Log { 49 | label := fmt.Sprintf("%c%d", letters[column], lsn) 50 | symbol := fmt.Sprintf("X%dX%d", column, lsn) 51 | // Ins node 52 | lines = append(lines, fmt.Sprintf("%s [ label=\"%s\"]", symbol, label)) 53 | 54 | // deps 55 | for j := 0; j < 3; j++ { 56 | var seen int64 57 | if column == j { 58 | seen = int64(lsn) - 1 59 | } else { 60 | seen = ins.Deps[j] - 1 61 | } 62 | 63 | if seen >= 0 { 64 | s0 := fmt.Sprintf("X%dX%d", j, seen) 65 | lines = append(lines, fmt.Sprintf("%s -> %s [ color=\"#aaaadd\"]", symbol, s0)) 66 | 67 | } 68 | } 69 | 70 | allSymbols = append(allSymbols, symbol) 71 | } 72 | 73 | // keeps logs on one column 74 | lines = append(lines, fmt.Sprintf("{ rank=same %s }", strings.Join(allSymbols, " "))) 75 | } 76 | 77 | prev := "" 78 | for _, pp := range as { 79 | column, lsn := parseColLSN(pp) 80 | symbol := fmt.Sprintf("X%dX%d", column, lsn) 81 | if prev != "" { 82 | lines = append(lines, fmt.Sprintf("%s -> %s [ color=\"#444444\", penwidth=3]", symbol, prev)) 83 | } 84 | prev = symbol 85 | } 86 | 87 | lines = append(lines, "}") 88 | return strings.Join(lines, "\n") 89 | 90 | } 91 | -------------------------------------------------------------------------------- /paxoskv/logging.go: -------------------------------------------------------------------------------- 1 | package paxoskv 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | 8 | "github.com/kr/pretty" 9 | "github.com/openacid/mmp3/goid" 10 | ) 11 | 12 | var ( 13 | defaultLogger = log.New(os.Stderr, fmt.Sprintf("??: "), log.Ltime|log.Lmicroseconds|log.Lshortfile|log.Lmsgprefix) 14 | ) 15 | 16 | type loggerGetter interface { 17 | getLogger() *log.Logger 18 | } 19 | 20 | func dd(gg loggerGetter, f string, args ...interface{}) { 21 | p := fmt.Sprintf("%s ", goid.ID()) 22 | getLogger(gg).Output(2, p+pretty.Sprintf(f, args...)) 23 | } 24 | 25 | func bug(gg loggerGetter, f string, args ...interface{}) { 26 | p := fmt.Sprintf("%s ", goid.ID()) 27 | getLogger(gg).Output(2, p+pretty.Sprintf(f, args...)) 28 | panic("bug") 29 | } 30 | 31 | func getLogger(gg loggerGetter) *log.Logger { 32 | if gg == nil { 33 | return defaultLogger 34 | } else { 35 | lg := gg.getLogger() 36 | if lg == nil { 37 | lg = defaultLogger 38 | } 39 | return lg 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /paxoskv/mmp.go: -------------------------------------------------------------------------------- 1 | package paxoskv 2 | 3 | func (s *KVServer) hdlOps(req *Request, remote *Ins) *Ins { 4 | h := NewHandler(s, remote) 5 | 6 | if req.Op == Op_Commit { 7 | latest := h.hdlCommit(remote) 8 | return latest 9 | } 10 | 11 | // Op_Accept: Accept implies Prepare 12 | 13 | local, _ := h.hdlPrepare(remote) 14 | dd(h, "after prepare: local: %s", local.str()) 15 | 16 | if local.VBal == nil && remote.VBal == nil { 17 | // In case another value with VBal=nil is initialized. 18 | // hdlPrepare only update seen if local was nil 19 | // no accepted value, create one with merged `Deps` 20 | local.updateDeps(remote.Deps) 21 | dd(h, "merged seen: %v from local: %s remote: %s", local.Deps, local.str(), remote.str()) 22 | } 23 | 24 | localLERemote := local.VBal.LessEqual(remote.VBal) 25 | dd(h, "after prepare: local: %s <= remote: %s : %t", local.str(), remote.str(), localLERemote) 26 | 27 | latest := local 28 | if localLERemote { 29 | latest = remote 30 | } 31 | 32 | accepted := h.hdlAccept(req.Bal, latest) 33 | 34 | if localLERemote { 35 | // there is a quorum(the sender and this replica) that has the latest value. 36 | return h.hdlCommit(accepted) 37 | } 38 | 39 | return accepted 40 | } 41 | 42 | func (h *Handler) hdlPrepare(inst *Ins) (*Ins, error) { 43 | s := h.kvServer 44 | column, lsn := inst.getColLSN() 45 | col := s.log.columns[column] 46 | 47 | curr := col.getInstance(lsn) 48 | if curr != nil { 49 | return curr, AlreadyPrepared 50 | } 51 | 52 | inst = inst.Clone() 53 | 54 | // value with vbal=nil is a prepared value 55 | inst.VBal = nil 56 | inst.updateDeps(s.getLogLens()) 57 | 58 | col.addInstance(inst) 59 | return inst, nil 60 | } 61 | 62 | func (h *Handler) hdlAccept(bal *BallotNum, inst *Ins) *Ins { 63 | inst.VBal = bal.Clone() 64 | h.setInstance(inst) 65 | dd(h, "after accept: latest: %s", inst.str()) 66 | return inst 67 | } 68 | 69 | func (h *Handler) hdlCommit(inst *Ins) *Ins { 70 | 71 | s := h.kvServer 72 | dd(h, "hdlCommit: %s", inst.str()) 73 | 74 | column := inst.getColumn() 75 | col := s.log.columns[column] 76 | 77 | inst.Committed = true 78 | h.setInstance(inst) 79 | 80 | nc := s.log.nextCommits[column] 81 | for int(nc) < len(col.Log) && col.Log[nc] != nil && col.Log[nc].Committed { 82 | nc++ 83 | } 84 | s.log.nextCommits[column] = nc 85 | 86 | dd(s, "hdlCommit Committed: %s, nextCommit: %d", inst.str(), nc) 87 | 88 | _, err := h.apply() 89 | _ = err 90 | return inst 91 | } 92 | -------------------------------------------------------------------------------- /paxoskv/mmp_test.go: -------------------------------------------------------------------------------- 1 | package paxoskv 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestKVServer_hdlPrepare(t *testing.T) { 11 | ta := require.New(t) 12 | 13 | s := NewKVServer(1) 14 | s.log.columns[0] = &Column{ 15 | LastBal: NewBal(0, 0), 16 | Log: []*Ins{nil, {InsId: NewInsId(0, 1, 0), Val: &Cmd{Key: "foo", Vi64: 10}, Deps: []int64{3, 0, 3}}}, 17 | } 18 | 19 | { 20 | // prepare a nil instnace 0-0 21 | lsn := int64(0) 22 | inst := &Ins{InsId: NewInsId(0, lsn, 1), Val: &Cmd{}, Deps: []int64{1, 0, 5}} 23 | 24 | h := NewHandler(s, inst) 25 | gotInst, err := h.hdlPrepare(inst) 26 | ta.Equal("<0-0-1: <=0> vbal:nil c:false seen:2,0,5>", gotInst.str()) 27 | ta.Equal("<0-0-1: <=0> vbal:nil c:false seen:2,0,5>", s.log.columns[0].Log[lsn].str()) 28 | ta.Equal(nil, err) 29 | } 30 | 31 | { 32 | // prepare a non-nil instnace 0-1 33 | lsn := int64(1) 34 | inst := &Ins{InsId: NewInsId(0, lsn, 3), Val: &Cmd{}, Deps: []int64{1, 0, 5}} 35 | 36 | h := NewHandler(s, inst) 37 | gotInst, err := h.hdlPrepare(inst) 38 | ta.Equal("<0-1-0: vbal:nil c:false seen:3,0,3>", gotInst.str()) 39 | ta.Equal("<0-1-0: vbal:nil c:false seen:3,0,3>", s.log.columns[0].Log[lsn].str()) 40 | ta.Equal(AlreadyPrepared, err) 41 | } 42 | 43 | { 44 | // prepare a nil instnace 0-2 45 | lsn := int64(2) 46 | inst := &Ins{ 47 | InsId: NewInsId(0, lsn, 1), 48 | Val: &Cmd{}, 49 | Deps: []int64{1, 0, 5}, 50 | } 51 | 52 | h := NewHandler(s, inst) 53 | gotInst, err := h.hdlPrepare(inst) 54 | ta.Equal("<0-2-1: <=0> vbal:nil c:false seen:2,0,5>", gotInst.str()) 55 | ta.Equal("<0-2-1: <=0> vbal:nil c:false seen:2,0,5>", s.log.columns[0].Log[lsn].str()) 56 | ta.Equal(nil, err) 57 | } 58 | 59 | } 60 | func TestKVServer_hdlOps(t *testing.T) { 61 | ta := require.New(t) 62 | 63 | column := int64(1) 64 | lsn := int64(0) 65 | 66 | cmdV := &Cmd{Key: "V"} 67 | cmdW := &Cmd{Key: "W"} 68 | 69 | cases := []struct { 70 | name string 71 | inst *Ins 72 | op Op 73 | // server: 74 | logs []*Ins 75 | wantInst string 76 | wantLogs string 77 | }{ 78 | { 79 | name: "vnil->nil", 80 | inst: &Ins{InsId: NewInsId(column, lsn, 0), Val: cmdV.Clone(), VBal: nil, Deps: []int64{0, 1, 5}}, 81 | logs: []*Ins{}, 82 | 83 | wantInst: "<1-0-0: vbal:10,2 c:false seen:1,1,5>", 84 | wantLogs: "<1-0-0: vbal:10,2 c:false seen:1,1,5>", 85 | }, 86 | { 87 | name: "v1->nil, no seen updated", 88 | inst: &Ins{InsId: NewInsId(column, lsn, 0), Val: cmdV.Clone(), VBal: NewBal(1, 0), Deps: []int64{0, 1, 5}}, 89 | logs: []*Ins{}, 90 | 91 | wantInst: "<1-0-0: vbal:10,2 c:true seen:0,1,5>", 92 | wantLogs: "<1-0-0: vbal:10,2 c:true seen:0,1,5>", 93 | }, 94 | { 95 | name: "v0->w1", 96 | inst: &Ins{InsId: NewInsId(column, lsn, 0), Val: cmdV.Clone(), VBal: NewBal(0, 0), Deps: []int64{0, 1, 5}}, 97 | logs: []*Ins{ 98 | {InsId: NewInsId(column, lsn, 1), Val: cmdW.Clone(), VBal: NewBal(2, 1), Deps: []int64{3, 0, 3}}, 99 | }, 100 | wantInst: "<1-0-1: vbal:10,2 c:false seen:3,0,3>", 101 | wantLogs: "<1-0-1: vbal:10,2 c:false seen:3,0,3>", 102 | }, 103 | { 104 | name: "v2->w1", 105 | inst: &Ins{InsId: NewInsId(column, lsn, 0), Val: cmdV.Clone(), VBal: NewBal(2, 0), Deps: []int64{0, 1, 5}}, 106 | logs: []*Ins{ 107 | {InsId: NewInsId(column, lsn, 1), Val: cmdW.Clone(), VBal: NewBal(1, 1), Deps: []int64{3, 0, 3}}, 108 | }, 109 | wantInst: "<1-0-0: vbal:10,2 c:true seen:0,1,5>", 110 | wantLogs: "<1-0-0: vbal:10,2 c:true seen:0,1,5>", 111 | }, 112 | { 113 | name: "vnil->wnil, accept w, seens are merged", 114 | inst: &Ins{InsId: NewInsId(column, lsn, 0), Val: cmdV.Clone(), VBal: nil, Deps: []int64{0, 1, 5}}, 115 | logs: []*Ins{ 116 | {InsId: NewInsId(column, lsn, 1), Val: cmdW.Clone(), VBal: nil, Deps: []int64{3, 0, 3}}, 117 | }, 118 | wantInst: "<1-0-1: vbal:10,2 c:false seen:3,1,5>", 119 | wantLogs: "<1-0-1: vbal:10,2 c:false seen:3,1,5>", 120 | }, 121 | { 122 | name: "v1->nil, just commit", 123 | inst: &Ins{InsId: NewInsId(column, lsn, 0), Val: cmdV.Clone(), VBal: NewBal(1, 0), Deps: []int64{0, 1, 5}}, 124 | op: Op_Commit, 125 | logs: []*Ins{}, 126 | 127 | wantInst: "<1-0-0: vbal:1,0 c:true seen:0,1,5>", 128 | wantLogs: "<1-0-0: vbal:1,0 c:true seen:0,1,5>", 129 | }, 130 | { 131 | name: "v0->w1, just commit", 132 | inst: &Ins{InsId: NewInsId(column, lsn, 0), Val: cmdV.Clone(), VBal: NewBal(0, 0), Deps: []int64{0, 1, 5}}, 133 | op: Op_Commit, 134 | logs: []*Ins{ 135 | {InsId: NewInsId(column, lsn, 1), Val: cmdW.Clone(), VBal: NewBal(2, 1), Deps: []int64{3, 0, 3}}, 136 | }, 137 | wantInst: "<1-0-0: vbal:0,0 c:true seen:0,1,5>", 138 | wantLogs: "<1-0-0: vbal:0,0 c:true seen:0,1,5>", 139 | }, 140 | } 141 | 142 | s := NewKVServer(1) 143 | for i, c := range cases { 144 | mes := fmt.Sprintf("%d-th: case: %+v", i+1, c) 145 | 146 | // a log to let prepared instance update its Deps 147 | s.log.columns[0].Log = []*Ins{ 148 | {}, 149 | } 150 | s.log.columns[column].Log = c.logs 151 | 152 | req := &Request{ 153 | Instances: map[int64]*Ins{c.inst.getLSN(): c.inst}, 154 | Bal: NewBal(10, 2), 155 | } 156 | if c.op != Op_Noop { 157 | req.Op = c.op 158 | } 159 | inst := s.hdlOps(req, c.inst) 160 | 161 | ta.Equal(c.wantInst, inst.str(), mes) 162 | ta.Equal(c.wantLogs, logsStr(s.log.columns[column].Log), mes) 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /paxoskv/paxoskv.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-gogo. DO NOT EDIT. 2 | // source: paxoskv.proto 3 | 4 | package paxoskv 5 | 6 | import ( 7 | context "context" 8 | fmt "fmt" 9 | _ "github.com/gogo/protobuf/gogoproto" 10 | proto "github.com/gogo/protobuf/proto" 11 | grpc "google.golang.org/grpc" 12 | codes "google.golang.org/grpc/codes" 13 | status "google.golang.org/grpc/status" 14 | io "io" 15 | math "math" 16 | math_bits "math/bits" 17 | ) 18 | 19 | // Reference imports to suppress errors if they are not otherwise used. 20 | var _ = proto.Marshal 21 | var _ = fmt.Errorf 22 | var _ = math.Inf 23 | 24 | // This is a compile-time assertion to ensure that this generated file 25 | // is compatible with the proto package it is being compiled against. 26 | // A compilation error at this line likely means your copy of the 27 | // proto package needs to be updated. 28 | const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package 29 | 30 | type Op int32 31 | 32 | const ( 33 | Op_Noop Op = 0 34 | Op_Accept Op = 1 35 | Op_Commit Op = 2 36 | ) 37 | 38 | var Op_name = map[int32]string{ 39 | 0: "Noop", 40 | 1: "Accept", 41 | 2: "Commit", 42 | } 43 | 44 | var Op_value = map[string]int32{ 45 | "Noop": 0, 46 | "Accept": 1, 47 | "Commit": 2, 48 | } 49 | 50 | func (x Op) String() string { 51 | return proto.EnumName(Op_name, int32(x)) 52 | } 53 | 54 | func (Op) EnumDescriptor() ([]byte, []int) { 55 | return fileDescriptor_2fd9fc43023b527a, []int{0} 56 | } 57 | 58 | type Request struct { 59 | Op Op `protobuf:"varint,1,opt,name=Op,proto3,enum=paxoskv.Op" json:"Op,omitempty"` 60 | Bal *BallotNum `protobuf:"bytes,5,opt,name=Bal,proto3" json:"Bal,omitempty"` 61 | Column int64 `protobuf:"varint,10,opt,name=Column,proto3" json:"Column,omitempty"` 62 | Instances map[int64]*Ins `protobuf:"bytes,20,rep,name=Instances,proto3" json:"Instances,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` 63 | } 64 | 65 | func (m *Request) Reset() { *m = Request{} } 66 | func (m *Request) String() string { return proto.CompactTextString(m) } 67 | func (*Request) ProtoMessage() {} 68 | func (*Request) Descriptor() ([]byte, []int) { 69 | return fileDescriptor_2fd9fc43023b527a, []int{0} 70 | } 71 | func (m *Request) XXX_Unmarshal(b []byte) error { 72 | return m.Unmarshal(b) 73 | } 74 | func (m *Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 75 | if deterministic { 76 | return xxx_messageInfo_Request.Marshal(b, m, deterministic) 77 | } else { 78 | b = b[:cap(b)] 79 | n, err := m.MarshalToSizedBuffer(b) 80 | if err != nil { 81 | return nil, err 82 | } 83 | return b[:n], nil 84 | } 85 | } 86 | func (m *Request) XXX_Merge(src proto.Message) { 87 | xxx_messageInfo_Request.Merge(m, src) 88 | } 89 | func (m *Request) XXX_Size() int { 90 | return m.Size() 91 | } 92 | func (m *Request) XXX_DiscardUnknown() { 93 | xxx_messageInfo_Request.DiscardUnknown(m) 94 | } 95 | 96 | var xxx_messageInfo_Request proto.InternalMessageInfo 97 | 98 | type Reply struct { 99 | LastBal *BallotNum `protobuf:"bytes,5,opt,name=LastBal,proto3" json:"LastBal,omitempty"` 100 | Instances map[int64]*Ins `protobuf:"bytes,20,rep,name=Instances,proto3" json:"Instances,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` 101 | } 102 | 103 | func (m *Reply) Reset() { *m = Reply{} } 104 | func (m *Reply) String() string { return proto.CompactTextString(m) } 105 | func (*Reply) ProtoMessage() {} 106 | func (*Reply) Descriptor() ([]byte, []int) { 107 | return fileDescriptor_2fd9fc43023b527a, []int{1} 108 | } 109 | func (m *Reply) XXX_Unmarshal(b []byte) error { 110 | return m.Unmarshal(b) 111 | } 112 | func (m *Reply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 113 | if deterministic { 114 | return xxx_messageInfo_Reply.Marshal(b, m, deterministic) 115 | } else { 116 | b = b[:cap(b)] 117 | n, err := m.MarshalToSizedBuffer(b) 118 | if err != nil { 119 | return nil, err 120 | } 121 | return b[:n], nil 122 | } 123 | } 124 | func (m *Reply) XXX_Merge(src proto.Message) { 125 | xxx_messageInfo_Reply.Merge(m, src) 126 | } 127 | func (m *Reply) XXX_Size() int { 128 | return m.Size() 129 | } 130 | func (m *Reply) XXX_DiscardUnknown() { 131 | xxx_messageInfo_Reply.DiscardUnknown(m) 132 | } 133 | 134 | var xxx_messageInfo_Reply proto.InternalMessageInfo 135 | 136 | // BallotNum is the ballot number in paxos. It consists of a monotonically 137 | // incremental number and a universally unique ProposerId. 138 | type BallotNum struct { 139 | N int64 `protobuf:"varint,1,opt,name=N,proto3" json:"N,omitempty"` 140 | Id int64 `protobuf:"varint,2,opt,name=Id,proto3" json:"Id,omitempty"` 141 | } 142 | 143 | func (m *BallotNum) Reset() { *m = BallotNum{} } 144 | func (m *BallotNum) String() string { return proto.CompactTextString(m) } 145 | func (*BallotNum) ProtoMessage() {} 146 | func (*BallotNum) Descriptor() ([]byte, []int) { 147 | return fileDescriptor_2fd9fc43023b527a, []int{2} 148 | } 149 | func (m *BallotNum) XXX_Unmarshal(b []byte) error { 150 | return m.Unmarshal(b) 151 | } 152 | func (m *BallotNum) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 153 | if deterministic { 154 | return xxx_messageInfo_BallotNum.Marshal(b, m, deterministic) 155 | } else { 156 | b = b[:cap(b)] 157 | n, err := m.MarshalToSizedBuffer(b) 158 | if err != nil { 159 | return nil, err 160 | } 161 | return b[:n], nil 162 | } 163 | } 164 | func (m *BallotNum) XXX_Merge(src proto.Message) { 165 | xxx_messageInfo_BallotNum.Merge(m, src) 166 | } 167 | func (m *BallotNum) XXX_Size() int { 168 | return m.Size() 169 | } 170 | func (m *BallotNum) XXX_DiscardUnknown() { 171 | xxx_messageInfo_BallotNum.DiscardUnknown(m) 172 | } 173 | 174 | var xxx_messageInfo_BallotNum proto.InternalMessageInfo 175 | 176 | // Cmd is the value in this paxos impl, which is a command to set a key-value 177 | // record. 178 | // In this demo it is just string key and a int64 value. 179 | type Cmd struct { 180 | Key string `protobuf:"bytes,3,opt,name=Key,proto3" json:"Key,omitempty"` 181 | Vi64 int64 `protobuf:"varint,4,opt,name=Vi64,proto3" json:"Vi64,omitempty"` 182 | } 183 | 184 | func (m *Cmd) Reset() { *m = Cmd{} } 185 | func (m *Cmd) String() string { return proto.CompactTextString(m) } 186 | func (*Cmd) ProtoMessage() {} 187 | func (*Cmd) Descriptor() ([]byte, []int) { 188 | return fileDescriptor_2fd9fc43023b527a, []int{3} 189 | } 190 | func (m *Cmd) XXX_Unmarshal(b []byte) error { 191 | return m.Unmarshal(b) 192 | } 193 | func (m *Cmd) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 194 | if deterministic { 195 | return xxx_messageInfo_Cmd.Marshal(b, m, deterministic) 196 | } else { 197 | b = b[:cap(b)] 198 | n, err := m.MarshalToSizedBuffer(b) 199 | if err != nil { 200 | return nil, err 201 | } 202 | return b[:n], nil 203 | } 204 | } 205 | func (m *Cmd) XXX_Merge(src proto.Message) { 206 | xxx_messageInfo_Cmd.Merge(m, src) 207 | } 208 | func (m *Cmd) XXX_Size() int { 209 | return m.Size() 210 | } 211 | func (m *Cmd) XXX_DiscardUnknown() { 212 | xxx_messageInfo_Cmd.DiscardUnknown(m) 213 | } 214 | 215 | var xxx_messageInfo_Cmd proto.InternalMessageInfo 216 | 217 | // InsId is the id of an instance. 218 | // The tuple (column, lsn, proposer_id) identifies a proposed value. 219 | // Two proposers may propose a same Cmd, in which case 220 | // these two must be distinguishable, otherwise a Write operation may be 221 | // lost. 222 | type InsId struct { 223 | Column int64 `protobuf:"varint,1,opt,name=Column,proto3" json:"Column,omitempty"` 224 | // LSN: log-sequence-number 225 | LSN int64 `protobuf:"varint,5,opt,name=LSN,proto3" json:"LSN,omitempty"` 226 | // ProposerId is the server id that proposes an instance. 227 | ProposerId int64 `protobuf:"varint,10,opt,name=ProposerId,proto3" json:"ProposerId,omitempty"` 228 | } 229 | 230 | func (m *InsId) Reset() { *m = InsId{} } 231 | func (m *InsId) String() string { return proto.CompactTextString(m) } 232 | func (*InsId) ProtoMessage() {} 233 | func (*InsId) Descriptor() ([]byte, []int) { 234 | return fileDescriptor_2fd9fc43023b527a, []int{4} 235 | } 236 | func (m *InsId) XXX_Unmarshal(b []byte) error { 237 | return m.Unmarshal(b) 238 | } 239 | func (m *InsId) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 240 | if deterministic { 241 | return xxx_messageInfo_InsId.Marshal(b, m, deterministic) 242 | } else { 243 | b = b[:cap(b)] 244 | n, err := m.MarshalToSizedBuffer(b) 245 | if err != nil { 246 | return nil, err 247 | } 248 | return b[:n], nil 249 | } 250 | } 251 | func (m *InsId) XXX_Merge(src proto.Message) { 252 | xxx_messageInfo_InsId.Merge(m, src) 253 | } 254 | func (m *InsId) XXX_Size() int { 255 | return m.Size() 256 | } 257 | func (m *InsId) XXX_DiscardUnknown() { 258 | xxx_messageInfo_InsId.DiscardUnknown(m) 259 | } 260 | 261 | var xxx_messageInfo_InsId proto.InternalMessageInfo 262 | 263 | // Instance is the state of an Instance and is the log entry in a multi column logs paxos 264 | type Ins struct { 265 | InsId *InsId `protobuf:"bytes,1,opt,name=InsId,proto3" json:"InsId,omitempty"` 266 | // the value proposed on this Instance 267 | Val *Cmd `protobuf:"bytes,3,opt,name=Val,proto3" json:"Val,omitempty"` 268 | // at which ballot number the Instance voted it. 269 | VBal *BallotNum `protobuf:"bytes,5,opt,name=VBal,proto3" json:"VBal,omitempty"` 270 | // What other instance this instance sees. 271 | // This view is used to decide the order to apply instances. 272 | // Intuitively, the more instance one sees, the later it is applied. 273 | Deps []int64 `protobuf:"varint,6,rep,packed,name=Deps,proto3" json:"Deps,omitempty"` 274 | Committed bool `protobuf:"varint,7,opt,name=Committed,proto3" json:"Committed,omitempty"` 275 | } 276 | 277 | func (m *Ins) Reset() { *m = Ins{} } 278 | func (m *Ins) String() string { return proto.CompactTextString(m) } 279 | func (*Ins) ProtoMessage() {} 280 | func (*Ins) Descriptor() ([]byte, []int) { 281 | return fileDescriptor_2fd9fc43023b527a, []int{5} 282 | } 283 | func (m *Ins) XXX_Unmarshal(b []byte) error { 284 | return m.Unmarshal(b) 285 | } 286 | func (m *Ins) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 287 | if deterministic { 288 | return xxx_messageInfo_Ins.Marshal(b, m, deterministic) 289 | } else { 290 | b = b[:cap(b)] 291 | n, err := m.MarshalToSizedBuffer(b) 292 | if err != nil { 293 | return nil, err 294 | } 295 | return b[:n], nil 296 | } 297 | } 298 | func (m *Ins) XXX_Merge(src proto.Message) { 299 | xxx_messageInfo_Ins.Merge(m, src) 300 | } 301 | func (m *Ins) XXX_Size() int { 302 | return m.Size() 303 | } 304 | func (m *Ins) XXX_DiscardUnknown() { 305 | xxx_messageInfo_Ins.DiscardUnknown(m) 306 | } 307 | 308 | var xxx_messageInfo_Ins proto.InternalMessageInfo 309 | 310 | func init() { 311 | proto.RegisterEnum("paxoskv.Op", Op_name, Op_value) 312 | proto.RegisterType((*Request)(nil), "paxoskv.Request") 313 | proto.RegisterMapType((map[int64]*Ins)(nil), "paxoskv.Request.InstancesEntry") 314 | proto.RegisterType((*Reply)(nil), "paxoskv.Reply") 315 | proto.RegisterMapType((map[int64]*Ins)(nil), "paxoskv.Reply.InstancesEntry") 316 | proto.RegisterType((*BallotNum)(nil), "paxoskv.BallotNum") 317 | proto.RegisterType((*Cmd)(nil), "paxoskv.Cmd") 318 | proto.RegisterType((*InsId)(nil), "paxoskv.InsId") 319 | proto.RegisterType((*Ins)(nil), "paxoskv.Ins") 320 | } 321 | 322 | func init() { proto.RegisterFile("paxoskv.proto", fileDescriptor_2fd9fc43023b527a) } 323 | 324 | var fileDescriptor_2fd9fc43023b527a = []byte{ 325 | // 556 bytes of a gzipped FileDescriptorProto 326 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x53, 0xcd, 0x6e, 0xd3, 0x4c, 327 | 0x14, 0xf5, 0x78, 0xf2, 0xd3, 0xdc, 0xf4, 0x8b, 0xac, 0xab, 0xea, 0x93, 0x15, 0x60, 0xb0, 0x4c, 328 | 0x55, 0x99, 0x1f, 0x05, 0x91, 0x22, 0x84, 0xa8, 0x58, 0xd0, 0x80, 0xc0, 0xb4, 0x4a, 0xca, 0x54, 329 | 0xca, 0x82, 0x9d, 0x89, 0x47, 0x55, 0x55, 0xdb, 0x63, 0x62, 0xa7, 0x22, 0x2f, 0xc0, 0x9a, 0x97, 330 | 0x40, 0xea, 0x53, 0xb0, 0xee, 0x32, 0x4b, 0x96, 0x34, 0x79, 0x00, 0x5e, 0x01, 0xcd, 0xc4, 0x4d, 331 | 0x13, 0x90, 0xca, 0x8e, 0xdd, 0x99, 0x7b, 0xce, 0x9c, 0x7b, 0x8f, 0xef, 0x18, 0xfe, 0x4b, 0x83, 332 | 0x4f, 0x32, 0x3b, 0x39, 0x6d, 0xa5, 0x43, 0x99, 0x4b, 0xac, 0x16, 0xc7, 0xe6, 0xc6, 0x91, 0x3c, 333 | 0x92, 0xba, 0xf6, 0x50, 0xa1, 0x39, 0xed, 0xfe, 0x24, 0x50, 0xe5, 0xe2, 0xe3, 0x48, 0x64, 0x39, 334 | 0xde, 0x00, 0xb3, 0x97, 0xda, 0xc4, 0x21, 0x5e, 0xa3, 0x5d, 0x6f, 0x5d, 0xda, 0xf4, 0x52, 0x6e, 335 | 0xf6, 0x52, 0xdc, 0x04, 0xba, 0x1b, 0x44, 0x76, 0xd9, 0x21, 0x5e, 0xbd, 0x8d, 0x0b, 0x76, 0x37, 336 | 0x88, 0x22, 0x99, 0x77, 0x47, 0x31, 0x57, 0x34, 0xfe, 0x0f, 0x95, 0x8e, 0x8c, 0x46, 0x71, 0x62, 337 | 0x83, 0x43, 0x3c, 0xca, 0x8b, 0x13, 0x3e, 0x87, 0x9a, 0x9f, 0x64, 0x79, 0x90, 0x0c, 0x44, 0x66, 338 | 0x6f, 0x38, 0xd4, 0xab, 0xb7, 0x6f, 0x2f, 0x3c, 0x8a, 0xfe, 0xad, 0x85, 0xe2, 0x55, 0x92, 0x0f, 339 | 0xc7, 0xfc, 0xea, 0x46, 0xf3, 0x2d, 0x34, 0x56, 0x49, 0xb4, 0x80, 0x9e, 0x88, 0xb1, 0x1e, 0x96, 340 | 0x72, 0x05, 0xd1, 0x85, 0xf2, 0x69, 0x10, 0x8d, 0x84, 0x6d, 0xea, 0x11, 0xd7, 0x17, 0xf6, 0x7e, 341 | 0x92, 0xf1, 0x39, 0xf5, 0xcc, 0x7c, 0x4a, 0xdc, 0x6f, 0x04, 0xca, 0x5c, 0xa4, 0xd1, 0x18, 0x1f, 342 | 0x40, 0x75, 0x3f, 0xc8, 0xf2, 0xeb, 0x63, 0x5d, 0x4a, 0x70, 0xe7, 0xcf, 0x08, 0xb7, 0x96, 0x22, 343 | 0xa4, 0xd1, 0xf8, 0x1f, 0x05, 0xb8, 0x0b, 0xb5, 0xc5, 0x78, 0xb8, 0x0e, 0xa4, 0x5b, 0x98, 0x90, 344 | 0x2e, 0x36, 0xc0, 0xf4, 0x43, 0x7d, 0x9f, 0x72, 0xd3, 0x0f, 0xdd, 0xfb, 0x40, 0x3b, 0x71, 0xa8, 345 | 0x7a, 0xed, 0x89, 0xb1, 0x4d, 0x1d, 0xe2, 0xd5, 0xb8, 0x82, 0x88, 0x50, 0xea, 0x1f, 0x3f, 0x79, 346 | 0x6c, 0x97, 0xb4, 0x54, 0x63, 0xf7, 0x1d, 0x94, 0xfd, 0x24, 0xf3, 0xc3, 0xa5, 0x25, 0x92, 0x95, 347 | 0x25, 0x5a, 0x40, 0xf7, 0x0f, 0xbb, 0xfa, 0x5b, 0x51, 0xae, 0x20, 0x32, 0x80, 0x83, 0xa1, 0x4c, 348 | 0x65, 0x26, 0x86, 0x7e, 0x58, 0xac, 0x7c, 0xa9, 0xe2, 0x7e, 0x25, 0x40, 0xfd, 0x24, 0xc3, 0xcd, 349 | 0xc2, 0x5a, 0x1b, 0xd6, 0xdb, 0x8d, 0xe5, 0x68, 0x7e, 0xc8, 0x8b, 0xbe, 0x0c, 0x68, 0x3f, 0x88, 350 | 0xf4, 0x98, 0xcb, 0xf1, 0x3b, 0x71, 0xc8, 0x15, 0x81, 0x5b, 0x50, 0xea, 0x5f, 0xbf, 0x2c, 0xcd, 351 | 0xab, 0x70, 0x2f, 0x45, 0x9a, 0xd9, 0x15, 0x87, 0xaa, 0x70, 0x0a, 0xe3, 0x4d, 0xa8, 0x75, 0x64, 352 | 0x1c, 0x1f, 0xe7, 0xb9, 0x08, 0xed, 0xaa, 0x43, 0xbc, 0x35, 0x7e, 0x55, 0xb8, 0xb7, 0xa5, 0x5e, 353 | 0x3e, 0xae, 0x41, 0xa9, 0x2b, 0x65, 0x6a, 0x19, 0x08, 0x50, 0x79, 0x31, 0x18, 0x88, 0x34, 0xb7, 354 | 0x88, 0xc2, 0x73, 0xa1, 0x65, 0xb6, 0x3f, 0x13, 0xa8, 0x1e, 0xa8, 0xae, 0x7b, 0x7d, 0x7c, 0x04, 355 | 0xf5, 0x37, 0x41, 0x12, 0x46, 0x42, 0x17, 0xd0, 0xfa, 0xfd, 0x39, 0x37, 0x1b, 0xab, 0xaf, 0xc3, 356 | 0x35, 0xf0, 0x0e, 0xd0, 0x43, 0x91, 0xe3, 0x4a, 0xb4, 0xe6, 0xca, 0x69, 0x2e, 0x7a, 0xfd, 0x37, 357 | 0xd1, 0xee, 0xf6, 0xf9, 0x05, 0x33, 0x26, 0x17, 0x8c, 0x9c, 0x4d, 0x19, 0x39, 0x9f, 0x32, 0x32, 358 | 0x99, 0x32, 0xf2, 0x63, 0xca, 0xc8, 0x97, 0x19, 0x33, 0xce, 0x66, 0x8c, 0x4c, 0x66, 0xcc, 0xf8, 359 | 0x3e, 0x63, 0xc6, 0xfb, 0x5a, 0x6b, 0xa7, 0xb8, 0xfa, 0xa1, 0xa2, 0x7f, 0xf9, 0xed, 0x5f, 0x01, 360 | 0x00, 0x00, 0xff, 0xff, 0xc3, 0xf7, 0xf8, 0x81, 0x22, 0x04, 0x00, 0x00, 361 | } 362 | 363 | func (this *Request) Compare(that interface{}) int { 364 | if that == nil { 365 | if this == nil { 366 | return 0 367 | } 368 | return 1 369 | } 370 | 371 | that1, ok := that.(*Request) 372 | if !ok { 373 | that2, ok := that.(Request) 374 | if ok { 375 | that1 = &that2 376 | } else { 377 | return 1 378 | } 379 | } 380 | if that1 == nil { 381 | if this == nil { 382 | return 0 383 | } 384 | return 1 385 | } else if this == nil { 386 | return -1 387 | } 388 | if this.Op != that1.Op { 389 | if this.Op < that1.Op { 390 | return -1 391 | } 392 | return 1 393 | } 394 | if c := this.Bal.Compare(that1.Bal); c != 0 { 395 | return c 396 | } 397 | if this.Column != that1.Column { 398 | if this.Column < that1.Column { 399 | return -1 400 | } 401 | return 1 402 | } 403 | if len(this.Instances) != len(that1.Instances) { 404 | if len(this.Instances) < len(that1.Instances) { 405 | return -1 406 | } 407 | return 1 408 | } 409 | for i := range this.Instances { 410 | if c := this.Instances[i].Compare(that1.Instances[i]); c != 0 { 411 | return c 412 | } 413 | } 414 | return 0 415 | } 416 | func (this *Reply) Compare(that interface{}) int { 417 | if that == nil { 418 | if this == nil { 419 | return 0 420 | } 421 | return 1 422 | } 423 | 424 | that1, ok := that.(*Reply) 425 | if !ok { 426 | that2, ok := that.(Reply) 427 | if ok { 428 | that1 = &that2 429 | } else { 430 | return 1 431 | } 432 | } 433 | if that1 == nil { 434 | if this == nil { 435 | return 0 436 | } 437 | return 1 438 | } else if this == nil { 439 | return -1 440 | } 441 | if c := this.LastBal.Compare(that1.LastBal); c != 0 { 442 | return c 443 | } 444 | if len(this.Instances) != len(that1.Instances) { 445 | if len(this.Instances) < len(that1.Instances) { 446 | return -1 447 | } 448 | return 1 449 | } 450 | for i := range this.Instances { 451 | if c := this.Instances[i].Compare(that1.Instances[i]); c != 0 { 452 | return c 453 | } 454 | } 455 | return 0 456 | } 457 | func (this *BallotNum) Compare(that interface{}) int { 458 | if that == nil { 459 | if this == nil { 460 | return 0 461 | } 462 | return 1 463 | } 464 | 465 | that1, ok := that.(*BallotNum) 466 | if !ok { 467 | that2, ok := that.(BallotNum) 468 | if ok { 469 | that1 = &that2 470 | } else { 471 | return 1 472 | } 473 | } 474 | if that1 == nil { 475 | if this == nil { 476 | return 0 477 | } 478 | return 1 479 | } else if this == nil { 480 | return -1 481 | } 482 | if this.N != that1.N { 483 | if this.N < that1.N { 484 | return -1 485 | } 486 | return 1 487 | } 488 | if this.Id != that1.Id { 489 | if this.Id < that1.Id { 490 | return -1 491 | } 492 | return 1 493 | } 494 | return 0 495 | } 496 | func (this *Cmd) Compare(that interface{}) int { 497 | if that == nil { 498 | if this == nil { 499 | return 0 500 | } 501 | return 1 502 | } 503 | 504 | that1, ok := that.(*Cmd) 505 | if !ok { 506 | that2, ok := that.(Cmd) 507 | if ok { 508 | that1 = &that2 509 | } else { 510 | return 1 511 | } 512 | } 513 | if that1 == nil { 514 | if this == nil { 515 | return 0 516 | } 517 | return 1 518 | } else if this == nil { 519 | return -1 520 | } 521 | if this.Key != that1.Key { 522 | if this.Key < that1.Key { 523 | return -1 524 | } 525 | return 1 526 | } 527 | if this.Vi64 != that1.Vi64 { 528 | if this.Vi64 < that1.Vi64 { 529 | return -1 530 | } 531 | return 1 532 | } 533 | return 0 534 | } 535 | func (this *InsId) Compare(that interface{}) int { 536 | if that == nil { 537 | if this == nil { 538 | return 0 539 | } 540 | return 1 541 | } 542 | 543 | that1, ok := that.(*InsId) 544 | if !ok { 545 | that2, ok := that.(InsId) 546 | if ok { 547 | that1 = &that2 548 | } else { 549 | return 1 550 | } 551 | } 552 | if that1 == nil { 553 | if this == nil { 554 | return 0 555 | } 556 | return 1 557 | } else if this == nil { 558 | return -1 559 | } 560 | if this.Column != that1.Column { 561 | if this.Column < that1.Column { 562 | return -1 563 | } 564 | return 1 565 | } 566 | if this.LSN != that1.LSN { 567 | if this.LSN < that1.LSN { 568 | return -1 569 | } 570 | return 1 571 | } 572 | if this.ProposerId != that1.ProposerId { 573 | if this.ProposerId < that1.ProposerId { 574 | return -1 575 | } 576 | return 1 577 | } 578 | return 0 579 | } 580 | func (this *Ins) Compare(that interface{}) int { 581 | if that == nil { 582 | if this == nil { 583 | return 0 584 | } 585 | return 1 586 | } 587 | 588 | that1, ok := that.(*Ins) 589 | if !ok { 590 | that2, ok := that.(Ins) 591 | if ok { 592 | that1 = &that2 593 | } else { 594 | return 1 595 | } 596 | } 597 | if that1 == nil { 598 | if this == nil { 599 | return 0 600 | } 601 | return 1 602 | } else if this == nil { 603 | return -1 604 | } 605 | if c := this.InsId.Compare(that1.InsId); c != 0 { 606 | return c 607 | } 608 | if c := this.Val.Compare(that1.Val); c != 0 { 609 | return c 610 | } 611 | if c := this.VBal.Compare(that1.VBal); c != 0 { 612 | return c 613 | } 614 | if len(this.Deps) != len(that1.Deps) { 615 | if len(this.Deps) < len(that1.Deps) { 616 | return -1 617 | } 618 | return 1 619 | } 620 | for i := range this.Deps { 621 | if this.Deps[i] != that1.Deps[i] { 622 | if this.Deps[i] < that1.Deps[i] { 623 | return -1 624 | } 625 | return 1 626 | } 627 | } 628 | if this.Committed != that1.Committed { 629 | if !this.Committed { 630 | return -1 631 | } 632 | return 1 633 | } 634 | return 0 635 | } 636 | func (this *Request) Equal(that interface{}) bool { 637 | if that == nil { 638 | return this == nil 639 | } 640 | 641 | that1, ok := that.(*Request) 642 | if !ok { 643 | that2, ok := that.(Request) 644 | if ok { 645 | that1 = &that2 646 | } else { 647 | return false 648 | } 649 | } 650 | if that1 == nil { 651 | return this == nil 652 | } else if this == nil { 653 | return false 654 | } 655 | if this.Op != that1.Op { 656 | return false 657 | } 658 | if !this.Bal.Equal(that1.Bal) { 659 | return false 660 | } 661 | if this.Column != that1.Column { 662 | return false 663 | } 664 | if len(this.Instances) != len(that1.Instances) { 665 | return false 666 | } 667 | for i := range this.Instances { 668 | if !this.Instances[i].Equal(that1.Instances[i]) { 669 | return false 670 | } 671 | } 672 | return true 673 | } 674 | func (this *Reply) Equal(that interface{}) bool { 675 | if that == nil { 676 | return this == nil 677 | } 678 | 679 | that1, ok := that.(*Reply) 680 | if !ok { 681 | that2, ok := that.(Reply) 682 | if ok { 683 | that1 = &that2 684 | } else { 685 | return false 686 | } 687 | } 688 | if that1 == nil { 689 | return this == nil 690 | } else if this == nil { 691 | return false 692 | } 693 | if !this.LastBal.Equal(that1.LastBal) { 694 | return false 695 | } 696 | if len(this.Instances) != len(that1.Instances) { 697 | return false 698 | } 699 | for i := range this.Instances { 700 | if !this.Instances[i].Equal(that1.Instances[i]) { 701 | return false 702 | } 703 | } 704 | return true 705 | } 706 | func (this *BallotNum) Equal(that interface{}) bool { 707 | if that == nil { 708 | return this == nil 709 | } 710 | 711 | that1, ok := that.(*BallotNum) 712 | if !ok { 713 | that2, ok := that.(BallotNum) 714 | if ok { 715 | that1 = &that2 716 | } else { 717 | return false 718 | } 719 | } 720 | if that1 == nil { 721 | return this == nil 722 | } else if this == nil { 723 | return false 724 | } 725 | if this.N != that1.N { 726 | return false 727 | } 728 | if this.Id != that1.Id { 729 | return false 730 | } 731 | return true 732 | } 733 | func (this *Cmd) Equal(that interface{}) bool { 734 | if that == nil { 735 | return this == nil 736 | } 737 | 738 | that1, ok := that.(*Cmd) 739 | if !ok { 740 | that2, ok := that.(Cmd) 741 | if ok { 742 | that1 = &that2 743 | } else { 744 | return false 745 | } 746 | } 747 | if that1 == nil { 748 | return this == nil 749 | } else if this == nil { 750 | return false 751 | } 752 | if this.Key != that1.Key { 753 | return false 754 | } 755 | if this.Vi64 != that1.Vi64 { 756 | return false 757 | } 758 | return true 759 | } 760 | func (this *InsId) Equal(that interface{}) bool { 761 | if that == nil { 762 | return this == nil 763 | } 764 | 765 | that1, ok := that.(*InsId) 766 | if !ok { 767 | that2, ok := that.(InsId) 768 | if ok { 769 | that1 = &that2 770 | } else { 771 | return false 772 | } 773 | } 774 | if that1 == nil { 775 | return this == nil 776 | } else if this == nil { 777 | return false 778 | } 779 | if this.Column != that1.Column { 780 | return false 781 | } 782 | if this.LSN != that1.LSN { 783 | return false 784 | } 785 | if this.ProposerId != that1.ProposerId { 786 | return false 787 | } 788 | return true 789 | } 790 | func (this *Ins) Equal(that interface{}) bool { 791 | if that == nil { 792 | return this == nil 793 | } 794 | 795 | that1, ok := that.(*Ins) 796 | if !ok { 797 | that2, ok := that.(Ins) 798 | if ok { 799 | that1 = &that2 800 | } else { 801 | return false 802 | } 803 | } 804 | if that1 == nil { 805 | return this == nil 806 | } else if this == nil { 807 | return false 808 | } 809 | if !this.InsId.Equal(that1.InsId) { 810 | return false 811 | } 812 | if !this.Val.Equal(that1.Val) { 813 | return false 814 | } 815 | if !this.VBal.Equal(that1.VBal) { 816 | return false 817 | } 818 | if len(this.Deps) != len(that1.Deps) { 819 | return false 820 | } 821 | for i := range this.Deps { 822 | if this.Deps[i] != that1.Deps[i] { 823 | return false 824 | } 825 | } 826 | if this.Committed != that1.Committed { 827 | return false 828 | } 829 | return true 830 | } 831 | 832 | // Reference imports to suppress errors if they are not otherwise used. 833 | var _ context.Context 834 | var _ grpc.ClientConn 835 | 836 | // This is a compile-time assertion to ensure that this generated file 837 | // is compatible with the grpc package it is being compiled against. 838 | const _ = grpc.SupportPackageIsVersion4 839 | 840 | // PaxosKVClient is the client API for PaxosKV service. 841 | // 842 | // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. 843 | type PaxosKVClient interface { 844 | // paxos API: used internally 845 | HandlePaxos(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Reply, error) 846 | Set(ctx context.Context, in *Cmd, opts ...grpc.CallOption) (*Cmd, error) 847 | Get(ctx context.Context, in *Cmd, opts ...grpc.CallOption) (*Cmd, error) 848 | } 849 | 850 | type paxosKVClient struct { 851 | cc *grpc.ClientConn 852 | } 853 | 854 | func NewPaxosKVClient(cc *grpc.ClientConn) PaxosKVClient { 855 | return &paxosKVClient{cc} 856 | } 857 | 858 | func (c *paxosKVClient) HandlePaxos(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Reply, error) { 859 | out := new(Reply) 860 | err := c.cc.Invoke(ctx, "/paxoskv.PaxosKV/HandlePaxos", in, out, opts...) 861 | if err != nil { 862 | return nil, err 863 | } 864 | return out, nil 865 | } 866 | 867 | func (c *paxosKVClient) Set(ctx context.Context, in *Cmd, opts ...grpc.CallOption) (*Cmd, error) { 868 | out := new(Cmd) 869 | err := c.cc.Invoke(ctx, "/paxoskv.PaxosKV/Set", in, out, opts...) 870 | if err != nil { 871 | return nil, err 872 | } 873 | return out, nil 874 | } 875 | 876 | func (c *paxosKVClient) Get(ctx context.Context, in *Cmd, opts ...grpc.CallOption) (*Cmd, error) { 877 | out := new(Cmd) 878 | err := c.cc.Invoke(ctx, "/paxoskv.PaxosKV/Get", in, out, opts...) 879 | if err != nil { 880 | return nil, err 881 | } 882 | return out, nil 883 | } 884 | 885 | // PaxosKVServer is the server API for PaxosKV service. 886 | type PaxosKVServer interface { 887 | // paxos API: used internally 888 | HandlePaxos(context.Context, *Request) (*Reply, error) 889 | Set(context.Context, *Cmd) (*Cmd, error) 890 | Get(context.Context, *Cmd) (*Cmd, error) 891 | } 892 | 893 | // UnimplementedPaxosKVServer can be embedded to have forward compatible implementations. 894 | type UnimplementedPaxosKVServer struct { 895 | } 896 | 897 | func (*UnimplementedPaxosKVServer) HandlePaxos(ctx context.Context, req *Request) (*Reply, error) { 898 | return nil, status.Errorf(codes.Unimplemented, "method HandlePaxos not implemented") 899 | } 900 | func (*UnimplementedPaxosKVServer) Set(ctx context.Context, req *Cmd) (*Cmd, error) { 901 | return nil, status.Errorf(codes.Unimplemented, "method Set not implemented") 902 | } 903 | func (*UnimplementedPaxosKVServer) Get(ctx context.Context, req *Cmd) (*Cmd, error) { 904 | return nil, status.Errorf(codes.Unimplemented, "method Get not implemented") 905 | } 906 | 907 | func RegisterPaxosKVServer(s *grpc.Server, srv PaxosKVServer) { 908 | s.RegisterService(&_PaxosKV_serviceDesc, srv) 909 | } 910 | 911 | func _PaxosKV_HandlePaxos_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 912 | in := new(Request) 913 | if err := dec(in); err != nil { 914 | return nil, err 915 | } 916 | if interceptor == nil { 917 | return srv.(PaxosKVServer).HandlePaxos(ctx, in) 918 | } 919 | info := &grpc.UnaryServerInfo{ 920 | Server: srv, 921 | FullMethod: "/paxoskv.PaxosKV/HandlePaxos", 922 | } 923 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 924 | return srv.(PaxosKVServer).HandlePaxos(ctx, req.(*Request)) 925 | } 926 | return interceptor(ctx, in, info, handler) 927 | } 928 | 929 | func _PaxosKV_Set_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 930 | in := new(Cmd) 931 | if err := dec(in); err != nil { 932 | return nil, err 933 | } 934 | if interceptor == nil { 935 | return srv.(PaxosKVServer).Set(ctx, in) 936 | } 937 | info := &grpc.UnaryServerInfo{ 938 | Server: srv, 939 | FullMethod: "/paxoskv.PaxosKV/Set", 940 | } 941 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 942 | return srv.(PaxosKVServer).Set(ctx, req.(*Cmd)) 943 | } 944 | return interceptor(ctx, in, info, handler) 945 | } 946 | 947 | func _PaxosKV_Get_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 948 | in := new(Cmd) 949 | if err := dec(in); err != nil { 950 | return nil, err 951 | } 952 | if interceptor == nil { 953 | return srv.(PaxosKVServer).Get(ctx, in) 954 | } 955 | info := &grpc.UnaryServerInfo{ 956 | Server: srv, 957 | FullMethod: "/paxoskv.PaxosKV/Get", 958 | } 959 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 960 | return srv.(PaxosKVServer).Get(ctx, req.(*Cmd)) 961 | } 962 | return interceptor(ctx, in, info, handler) 963 | } 964 | 965 | var _PaxosKV_serviceDesc = grpc.ServiceDesc{ 966 | ServiceName: "paxoskv.PaxosKV", 967 | HandlerType: (*PaxosKVServer)(nil), 968 | Methods: []grpc.MethodDesc{ 969 | { 970 | MethodName: "HandlePaxos", 971 | Handler: _PaxosKV_HandlePaxos_Handler, 972 | }, 973 | { 974 | MethodName: "Set", 975 | Handler: _PaxosKV_Set_Handler, 976 | }, 977 | { 978 | MethodName: "Get", 979 | Handler: _PaxosKV_Get_Handler, 980 | }, 981 | }, 982 | Streams: []grpc.StreamDesc{}, 983 | Metadata: "paxoskv.proto", 984 | } 985 | 986 | func (m *Request) Marshal() (dAtA []byte, err error) { 987 | size := m.Size() 988 | dAtA = make([]byte, size) 989 | n, err := m.MarshalToSizedBuffer(dAtA[:size]) 990 | if err != nil { 991 | return nil, err 992 | } 993 | return dAtA[:n], nil 994 | } 995 | 996 | func (m *Request) MarshalTo(dAtA []byte) (int, error) { 997 | size := m.Size() 998 | return m.MarshalToSizedBuffer(dAtA[:size]) 999 | } 1000 | 1001 | func (m *Request) MarshalToSizedBuffer(dAtA []byte) (int, error) { 1002 | i := len(dAtA) 1003 | _ = i 1004 | var l int 1005 | _ = l 1006 | if len(m.Instances) > 0 { 1007 | for k := range m.Instances { 1008 | v := m.Instances[k] 1009 | baseI := i 1010 | if v != nil { 1011 | { 1012 | size, err := v.MarshalToSizedBuffer(dAtA[:i]) 1013 | if err != nil { 1014 | return 0, err 1015 | } 1016 | i -= size 1017 | i = encodeVarintPaxoskv(dAtA, i, uint64(size)) 1018 | } 1019 | i-- 1020 | dAtA[i] = 0x12 1021 | } 1022 | i = encodeVarintPaxoskv(dAtA, i, uint64(k)) 1023 | i-- 1024 | dAtA[i] = 0x8 1025 | i = encodeVarintPaxoskv(dAtA, i, uint64(baseI-i)) 1026 | i-- 1027 | dAtA[i] = 0x1 1028 | i-- 1029 | dAtA[i] = 0xa2 1030 | } 1031 | } 1032 | if m.Column != 0 { 1033 | i = encodeVarintPaxoskv(dAtA, i, uint64(m.Column)) 1034 | i-- 1035 | dAtA[i] = 0x50 1036 | } 1037 | if m.Bal != nil { 1038 | { 1039 | size, err := m.Bal.MarshalToSizedBuffer(dAtA[:i]) 1040 | if err != nil { 1041 | return 0, err 1042 | } 1043 | i -= size 1044 | i = encodeVarintPaxoskv(dAtA, i, uint64(size)) 1045 | } 1046 | i-- 1047 | dAtA[i] = 0x2a 1048 | } 1049 | if m.Op != 0 { 1050 | i = encodeVarintPaxoskv(dAtA, i, uint64(m.Op)) 1051 | i-- 1052 | dAtA[i] = 0x8 1053 | } 1054 | return len(dAtA) - i, nil 1055 | } 1056 | 1057 | func (m *Reply) Marshal() (dAtA []byte, err error) { 1058 | size := m.Size() 1059 | dAtA = make([]byte, size) 1060 | n, err := m.MarshalToSizedBuffer(dAtA[:size]) 1061 | if err != nil { 1062 | return nil, err 1063 | } 1064 | return dAtA[:n], nil 1065 | } 1066 | 1067 | func (m *Reply) MarshalTo(dAtA []byte) (int, error) { 1068 | size := m.Size() 1069 | return m.MarshalToSizedBuffer(dAtA[:size]) 1070 | } 1071 | 1072 | func (m *Reply) MarshalToSizedBuffer(dAtA []byte) (int, error) { 1073 | i := len(dAtA) 1074 | _ = i 1075 | var l int 1076 | _ = l 1077 | if len(m.Instances) > 0 { 1078 | for k := range m.Instances { 1079 | v := m.Instances[k] 1080 | baseI := i 1081 | if v != nil { 1082 | { 1083 | size, err := v.MarshalToSizedBuffer(dAtA[:i]) 1084 | if err != nil { 1085 | return 0, err 1086 | } 1087 | i -= size 1088 | i = encodeVarintPaxoskv(dAtA, i, uint64(size)) 1089 | } 1090 | i-- 1091 | dAtA[i] = 0x12 1092 | } 1093 | i = encodeVarintPaxoskv(dAtA, i, uint64(k)) 1094 | i-- 1095 | dAtA[i] = 0x8 1096 | i = encodeVarintPaxoskv(dAtA, i, uint64(baseI-i)) 1097 | i-- 1098 | dAtA[i] = 0x1 1099 | i-- 1100 | dAtA[i] = 0xa2 1101 | } 1102 | } 1103 | if m.LastBal != nil { 1104 | { 1105 | size, err := m.LastBal.MarshalToSizedBuffer(dAtA[:i]) 1106 | if err != nil { 1107 | return 0, err 1108 | } 1109 | i -= size 1110 | i = encodeVarintPaxoskv(dAtA, i, uint64(size)) 1111 | } 1112 | i-- 1113 | dAtA[i] = 0x2a 1114 | } 1115 | return len(dAtA) - i, nil 1116 | } 1117 | 1118 | func (m *BallotNum) Marshal() (dAtA []byte, err error) { 1119 | size := m.Size() 1120 | dAtA = make([]byte, size) 1121 | n, err := m.MarshalToSizedBuffer(dAtA[:size]) 1122 | if err != nil { 1123 | return nil, err 1124 | } 1125 | return dAtA[:n], nil 1126 | } 1127 | 1128 | func (m *BallotNum) MarshalTo(dAtA []byte) (int, error) { 1129 | size := m.Size() 1130 | return m.MarshalToSizedBuffer(dAtA[:size]) 1131 | } 1132 | 1133 | func (m *BallotNum) MarshalToSizedBuffer(dAtA []byte) (int, error) { 1134 | i := len(dAtA) 1135 | _ = i 1136 | var l int 1137 | _ = l 1138 | if m.Id != 0 { 1139 | i = encodeVarintPaxoskv(dAtA, i, uint64(m.Id)) 1140 | i-- 1141 | dAtA[i] = 0x10 1142 | } 1143 | if m.N != 0 { 1144 | i = encodeVarintPaxoskv(dAtA, i, uint64(m.N)) 1145 | i-- 1146 | dAtA[i] = 0x8 1147 | } 1148 | return len(dAtA) - i, nil 1149 | } 1150 | 1151 | func (m *Cmd) Marshal() (dAtA []byte, err error) { 1152 | size := m.Size() 1153 | dAtA = make([]byte, size) 1154 | n, err := m.MarshalToSizedBuffer(dAtA[:size]) 1155 | if err != nil { 1156 | return nil, err 1157 | } 1158 | return dAtA[:n], nil 1159 | } 1160 | 1161 | func (m *Cmd) MarshalTo(dAtA []byte) (int, error) { 1162 | size := m.Size() 1163 | return m.MarshalToSizedBuffer(dAtA[:size]) 1164 | } 1165 | 1166 | func (m *Cmd) MarshalToSizedBuffer(dAtA []byte) (int, error) { 1167 | i := len(dAtA) 1168 | _ = i 1169 | var l int 1170 | _ = l 1171 | if m.Vi64 != 0 { 1172 | i = encodeVarintPaxoskv(dAtA, i, uint64(m.Vi64)) 1173 | i-- 1174 | dAtA[i] = 0x20 1175 | } 1176 | if len(m.Key) > 0 { 1177 | i -= len(m.Key) 1178 | copy(dAtA[i:], m.Key) 1179 | i = encodeVarintPaxoskv(dAtA, i, uint64(len(m.Key))) 1180 | i-- 1181 | dAtA[i] = 0x1a 1182 | } 1183 | return len(dAtA) - i, nil 1184 | } 1185 | 1186 | func (m *InsId) Marshal() (dAtA []byte, err error) { 1187 | size := m.Size() 1188 | dAtA = make([]byte, size) 1189 | n, err := m.MarshalToSizedBuffer(dAtA[:size]) 1190 | if err != nil { 1191 | return nil, err 1192 | } 1193 | return dAtA[:n], nil 1194 | } 1195 | 1196 | func (m *InsId) MarshalTo(dAtA []byte) (int, error) { 1197 | size := m.Size() 1198 | return m.MarshalToSizedBuffer(dAtA[:size]) 1199 | } 1200 | 1201 | func (m *InsId) MarshalToSizedBuffer(dAtA []byte) (int, error) { 1202 | i := len(dAtA) 1203 | _ = i 1204 | var l int 1205 | _ = l 1206 | if m.ProposerId != 0 { 1207 | i = encodeVarintPaxoskv(dAtA, i, uint64(m.ProposerId)) 1208 | i-- 1209 | dAtA[i] = 0x50 1210 | } 1211 | if m.LSN != 0 { 1212 | i = encodeVarintPaxoskv(dAtA, i, uint64(m.LSN)) 1213 | i-- 1214 | dAtA[i] = 0x28 1215 | } 1216 | if m.Column != 0 { 1217 | i = encodeVarintPaxoskv(dAtA, i, uint64(m.Column)) 1218 | i-- 1219 | dAtA[i] = 0x8 1220 | } 1221 | return len(dAtA) - i, nil 1222 | } 1223 | 1224 | func (m *Ins) Marshal() (dAtA []byte, err error) { 1225 | size := m.Size() 1226 | dAtA = make([]byte, size) 1227 | n, err := m.MarshalToSizedBuffer(dAtA[:size]) 1228 | if err != nil { 1229 | return nil, err 1230 | } 1231 | return dAtA[:n], nil 1232 | } 1233 | 1234 | func (m *Ins) MarshalTo(dAtA []byte) (int, error) { 1235 | size := m.Size() 1236 | return m.MarshalToSizedBuffer(dAtA[:size]) 1237 | } 1238 | 1239 | func (m *Ins) MarshalToSizedBuffer(dAtA []byte) (int, error) { 1240 | i := len(dAtA) 1241 | _ = i 1242 | var l int 1243 | _ = l 1244 | if m.Committed { 1245 | i-- 1246 | if m.Committed { 1247 | dAtA[i] = 1 1248 | } else { 1249 | dAtA[i] = 0 1250 | } 1251 | i-- 1252 | dAtA[i] = 0x38 1253 | } 1254 | if len(m.Deps) > 0 { 1255 | dAtA6 := make([]byte, len(m.Deps)*10) 1256 | var j5 int 1257 | for _, num1 := range m.Deps { 1258 | num := uint64(num1) 1259 | for num >= 1<<7 { 1260 | dAtA6[j5] = uint8(uint64(num)&0x7f | 0x80) 1261 | num >>= 7 1262 | j5++ 1263 | } 1264 | dAtA6[j5] = uint8(num) 1265 | j5++ 1266 | } 1267 | i -= j5 1268 | copy(dAtA[i:], dAtA6[:j5]) 1269 | i = encodeVarintPaxoskv(dAtA, i, uint64(j5)) 1270 | i-- 1271 | dAtA[i] = 0x32 1272 | } 1273 | if m.VBal != nil { 1274 | { 1275 | size, err := m.VBal.MarshalToSizedBuffer(dAtA[:i]) 1276 | if err != nil { 1277 | return 0, err 1278 | } 1279 | i -= size 1280 | i = encodeVarintPaxoskv(dAtA, i, uint64(size)) 1281 | } 1282 | i-- 1283 | dAtA[i] = 0x2a 1284 | } 1285 | if m.Val != nil { 1286 | { 1287 | size, err := m.Val.MarshalToSizedBuffer(dAtA[:i]) 1288 | if err != nil { 1289 | return 0, err 1290 | } 1291 | i -= size 1292 | i = encodeVarintPaxoskv(dAtA, i, uint64(size)) 1293 | } 1294 | i-- 1295 | dAtA[i] = 0x1a 1296 | } 1297 | if m.InsId != nil { 1298 | { 1299 | size, err := m.InsId.MarshalToSizedBuffer(dAtA[:i]) 1300 | if err != nil { 1301 | return 0, err 1302 | } 1303 | i -= size 1304 | i = encodeVarintPaxoskv(dAtA, i, uint64(size)) 1305 | } 1306 | i-- 1307 | dAtA[i] = 0xa 1308 | } 1309 | return len(dAtA) - i, nil 1310 | } 1311 | 1312 | func encodeVarintPaxoskv(dAtA []byte, offset int, v uint64) int { 1313 | offset -= sovPaxoskv(v) 1314 | base := offset 1315 | for v >= 1<<7 { 1316 | dAtA[offset] = uint8(v&0x7f | 0x80) 1317 | v >>= 7 1318 | offset++ 1319 | } 1320 | dAtA[offset] = uint8(v) 1321 | return base 1322 | } 1323 | func (m *Request) Size() (n int) { 1324 | if m == nil { 1325 | return 0 1326 | } 1327 | var l int 1328 | _ = l 1329 | if m.Op != 0 { 1330 | n += 1 + sovPaxoskv(uint64(m.Op)) 1331 | } 1332 | if m.Bal != nil { 1333 | l = m.Bal.Size() 1334 | n += 1 + l + sovPaxoskv(uint64(l)) 1335 | } 1336 | if m.Column != 0 { 1337 | n += 1 + sovPaxoskv(uint64(m.Column)) 1338 | } 1339 | if len(m.Instances) > 0 { 1340 | for k, v := range m.Instances { 1341 | _ = k 1342 | _ = v 1343 | l = 0 1344 | if v != nil { 1345 | l = v.Size() 1346 | l += 1 + sovPaxoskv(uint64(l)) 1347 | } 1348 | mapEntrySize := 1 + sovPaxoskv(uint64(k)) + l 1349 | n += mapEntrySize + 2 + sovPaxoskv(uint64(mapEntrySize)) 1350 | } 1351 | } 1352 | return n 1353 | } 1354 | 1355 | func (m *Reply) Size() (n int) { 1356 | if m == nil { 1357 | return 0 1358 | } 1359 | var l int 1360 | _ = l 1361 | if m.LastBal != nil { 1362 | l = m.LastBal.Size() 1363 | n += 1 + l + sovPaxoskv(uint64(l)) 1364 | } 1365 | if len(m.Instances) > 0 { 1366 | for k, v := range m.Instances { 1367 | _ = k 1368 | _ = v 1369 | l = 0 1370 | if v != nil { 1371 | l = v.Size() 1372 | l += 1 + sovPaxoskv(uint64(l)) 1373 | } 1374 | mapEntrySize := 1 + sovPaxoskv(uint64(k)) + l 1375 | n += mapEntrySize + 2 + sovPaxoskv(uint64(mapEntrySize)) 1376 | } 1377 | } 1378 | return n 1379 | } 1380 | 1381 | func (m *BallotNum) Size() (n int) { 1382 | if m == nil { 1383 | return 0 1384 | } 1385 | var l int 1386 | _ = l 1387 | if m.N != 0 { 1388 | n += 1 + sovPaxoskv(uint64(m.N)) 1389 | } 1390 | if m.Id != 0 { 1391 | n += 1 + sovPaxoskv(uint64(m.Id)) 1392 | } 1393 | return n 1394 | } 1395 | 1396 | func (m *Cmd) Size() (n int) { 1397 | if m == nil { 1398 | return 0 1399 | } 1400 | var l int 1401 | _ = l 1402 | l = len(m.Key) 1403 | if l > 0 { 1404 | n += 1 + l + sovPaxoskv(uint64(l)) 1405 | } 1406 | if m.Vi64 != 0 { 1407 | n += 1 + sovPaxoskv(uint64(m.Vi64)) 1408 | } 1409 | return n 1410 | } 1411 | 1412 | func (m *InsId) Size() (n int) { 1413 | if m == nil { 1414 | return 0 1415 | } 1416 | var l int 1417 | _ = l 1418 | if m.Column != 0 { 1419 | n += 1 + sovPaxoskv(uint64(m.Column)) 1420 | } 1421 | if m.LSN != 0 { 1422 | n += 1 + sovPaxoskv(uint64(m.LSN)) 1423 | } 1424 | if m.ProposerId != 0 { 1425 | n += 1 + sovPaxoskv(uint64(m.ProposerId)) 1426 | } 1427 | return n 1428 | } 1429 | 1430 | func (m *Ins) Size() (n int) { 1431 | if m == nil { 1432 | return 0 1433 | } 1434 | var l int 1435 | _ = l 1436 | if m.InsId != nil { 1437 | l = m.InsId.Size() 1438 | n += 1 + l + sovPaxoskv(uint64(l)) 1439 | } 1440 | if m.Val != nil { 1441 | l = m.Val.Size() 1442 | n += 1 + l + sovPaxoskv(uint64(l)) 1443 | } 1444 | if m.VBal != nil { 1445 | l = m.VBal.Size() 1446 | n += 1 + l + sovPaxoskv(uint64(l)) 1447 | } 1448 | if len(m.Deps) > 0 { 1449 | l = 0 1450 | for _, e := range m.Deps { 1451 | l += sovPaxoskv(uint64(e)) 1452 | } 1453 | n += 1 + sovPaxoskv(uint64(l)) + l 1454 | } 1455 | if m.Committed { 1456 | n += 2 1457 | } 1458 | return n 1459 | } 1460 | 1461 | func sovPaxoskv(x uint64) (n int) { 1462 | return (math_bits.Len64(x|1) + 6) / 7 1463 | } 1464 | func sozPaxoskv(x uint64) (n int) { 1465 | return sovPaxoskv(uint64((x << 1) ^ uint64((int64(x) >> 63)))) 1466 | } 1467 | func (m *Request) Unmarshal(dAtA []byte) error { 1468 | l := len(dAtA) 1469 | iNdEx := 0 1470 | for iNdEx < l { 1471 | preIndex := iNdEx 1472 | var wire uint64 1473 | for shift := uint(0); ; shift += 7 { 1474 | if shift >= 64 { 1475 | return ErrIntOverflowPaxoskv 1476 | } 1477 | if iNdEx >= l { 1478 | return io.ErrUnexpectedEOF 1479 | } 1480 | b := dAtA[iNdEx] 1481 | iNdEx++ 1482 | wire |= uint64(b&0x7F) << shift 1483 | if b < 0x80 { 1484 | break 1485 | } 1486 | } 1487 | fieldNum := int32(wire >> 3) 1488 | wireType := int(wire & 0x7) 1489 | if wireType == 4 { 1490 | return fmt.Errorf("proto: Request: wiretype end group for non-group") 1491 | } 1492 | if fieldNum <= 0 { 1493 | return fmt.Errorf("proto: Request: illegal tag %d (wire type %d)", fieldNum, wire) 1494 | } 1495 | switch fieldNum { 1496 | case 1: 1497 | if wireType != 0 { 1498 | return fmt.Errorf("proto: wrong wireType = %d for field Op", wireType) 1499 | } 1500 | m.Op = 0 1501 | for shift := uint(0); ; shift += 7 { 1502 | if shift >= 64 { 1503 | return ErrIntOverflowPaxoskv 1504 | } 1505 | if iNdEx >= l { 1506 | return io.ErrUnexpectedEOF 1507 | } 1508 | b := dAtA[iNdEx] 1509 | iNdEx++ 1510 | m.Op |= Op(b&0x7F) << shift 1511 | if b < 0x80 { 1512 | break 1513 | } 1514 | } 1515 | case 5: 1516 | if wireType != 2 { 1517 | return fmt.Errorf("proto: wrong wireType = %d for field Bal", wireType) 1518 | } 1519 | var msglen int 1520 | for shift := uint(0); ; shift += 7 { 1521 | if shift >= 64 { 1522 | return ErrIntOverflowPaxoskv 1523 | } 1524 | if iNdEx >= l { 1525 | return io.ErrUnexpectedEOF 1526 | } 1527 | b := dAtA[iNdEx] 1528 | iNdEx++ 1529 | msglen |= int(b&0x7F) << shift 1530 | if b < 0x80 { 1531 | break 1532 | } 1533 | } 1534 | if msglen < 0 { 1535 | return ErrInvalidLengthPaxoskv 1536 | } 1537 | postIndex := iNdEx + msglen 1538 | if postIndex < 0 { 1539 | return ErrInvalidLengthPaxoskv 1540 | } 1541 | if postIndex > l { 1542 | return io.ErrUnexpectedEOF 1543 | } 1544 | if m.Bal == nil { 1545 | m.Bal = &BallotNum{} 1546 | } 1547 | if err := m.Bal.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { 1548 | return err 1549 | } 1550 | iNdEx = postIndex 1551 | case 10: 1552 | if wireType != 0 { 1553 | return fmt.Errorf("proto: wrong wireType = %d for field Column", wireType) 1554 | } 1555 | m.Column = 0 1556 | for shift := uint(0); ; shift += 7 { 1557 | if shift >= 64 { 1558 | return ErrIntOverflowPaxoskv 1559 | } 1560 | if iNdEx >= l { 1561 | return io.ErrUnexpectedEOF 1562 | } 1563 | b := dAtA[iNdEx] 1564 | iNdEx++ 1565 | m.Column |= int64(b&0x7F) << shift 1566 | if b < 0x80 { 1567 | break 1568 | } 1569 | } 1570 | case 20: 1571 | if wireType != 2 { 1572 | return fmt.Errorf("proto: wrong wireType = %d for field Instances", wireType) 1573 | } 1574 | var msglen int 1575 | for shift := uint(0); ; shift += 7 { 1576 | if shift >= 64 { 1577 | return ErrIntOverflowPaxoskv 1578 | } 1579 | if iNdEx >= l { 1580 | return io.ErrUnexpectedEOF 1581 | } 1582 | b := dAtA[iNdEx] 1583 | iNdEx++ 1584 | msglen |= int(b&0x7F) << shift 1585 | if b < 0x80 { 1586 | break 1587 | } 1588 | } 1589 | if msglen < 0 { 1590 | return ErrInvalidLengthPaxoskv 1591 | } 1592 | postIndex := iNdEx + msglen 1593 | if postIndex < 0 { 1594 | return ErrInvalidLengthPaxoskv 1595 | } 1596 | if postIndex > l { 1597 | return io.ErrUnexpectedEOF 1598 | } 1599 | if m.Instances == nil { 1600 | m.Instances = make(map[int64]*Ins) 1601 | } 1602 | var mapkey int64 1603 | var mapvalue *Ins 1604 | for iNdEx < postIndex { 1605 | entryPreIndex := iNdEx 1606 | var wire uint64 1607 | for shift := uint(0); ; shift += 7 { 1608 | if shift >= 64 { 1609 | return ErrIntOverflowPaxoskv 1610 | } 1611 | if iNdEx >= l { 1612 | return io.ErrUnexpectedEOF 1613 | } 1614 | b := dAtA[iNdEx] 1615 | iNdEx++ 1616 | wire |= uint64(b&0x7F) << shift 1617 | if b < 0x80 { 1618 | break 1619 | } 1620 | } 1621 | fieldNum := int32(wire >> 3) 1622 | if fieldNum == 1 { 1623 | for shift := uint(0); ; shift += 7 { 1624 | if shift >= 64 { 1625 | return ErrIntOverflowPaxoskv 1626 | } 1627 | if iNdEx >= l { 1628 | return io.ErrUnexpectedEOF 1629 | } 1630 | b := dAtA[iNdEx] 1631 | iNdEx++ 1632 | mapkey |= int64(b&0x7F) << shift 1633 | if b < 0x80 { 1634 | break 1635 | } 1636 | } 1637 | } else if fieldNum == 2 { 1638 | var mapmsglen int 1639 | for shift := uint(0); ; shift += 7 { 1640 | if shift >= 64 { 1641 | return ErrIntOverflowPaxoskv 1642 | } 1643 | if iNdEx >= l { 1644 | return io.ErrUnexpectedEOF 1645 | } 1646 | b := dAtA[iNdEx] 1647 | iNdEx++ 1648 | mapmsglen |= int(b&0x7F) << shift 1649 | if b < 0x80 { 1650 | break 1651 | } 1652 | } 1653 | if mapmsglen < 0 { 1654 | return ErrInvalidLengthPaxoskv 1655 | } 1656 | postmsgIndex := iNdEx + mapmsglen 1657 | if postmsgIndex < 0 { 1658 | return ErrInvalidLengthPaxoskv 1659 | } 1660 | if postmsgIndex > l { 1661 | return io.ErrUnexpectedEOF 1662 | } 1663 | mapvalue = &Ins{} 1664 | if err := mapvalue.Unmarshal(dAtA[iNdEx:postmsgIndex]); err != nil { 1665 | return err 1666 | } 1667 | iNdEx = postmsgIndex 1668 | } else { 1669 | iNdEx = entryPreIndex 1670 | skippy, err := skipPaxoskv(dAtA[iNdEx:]) 1671 | if err != nil { 1672 | return err 1673 | } 1674 | if (skippy < 0) || (iNdEx+skippy) < 0 { 1675 | return ErrInvalidLengthPaxoskv 1676 | } 1677 | if (iNdEx + skippy) > postIndex { 1678 | return io.ErrUnexpectedEOF 1679 | } 1680 | iNdEx += skippy 1681 | } 1682 | } 1683 | m.Instances[mapkey] = mapvalue 1684 | iNdEx = postIndex 1685 | default: 1686 | iNdEx = preIndex 1687 | skippy, err := skipPaxoskv(dAtA[iNdEx:]) 1688 | if err != nil { 1689 | return err 1690 | } 1691 | if (skippy < 0) || (iNdEx+skippy) < 0 { 1692 | return ErrInvalidLengthPaxoskv 1693 | } 1694 | if (iNdEx + skippy) > l { 1695 | return io.ErrUnexpectedEOF 1696 | } 1697 | iNdEx += skippy 1698 | } 1699 | } 1700 | 1701 | if iNdEx > l { 1702 | return io.ErrUnexpectedEOF 1703 | } 1704 | return nil 1705 | } 1706 | func (m *Reply) Unmarshal(dAtA []byte) error { 1707 | l := len(dAtA) 1708 | iNdEx := 0 1709 | for iNdEx < l { 1710 | preIndex := iNdEx 1711 | var wire uint64 1712 | for shift := uint(0); ; shift += 7 { 1713 | if shift >= 64 { 1714 | return ErrIntOverflowPaxoskv 1715 | } 1716 | if iNdEx >= l { 1717 | return io.ErrUnexpectedEOF 1718 | } 1719 | b := dAtA[iNdEx] 1720 | iNdEx++ 1721 | wire |= uint64(b&0x7F) << shift 1722 | if b < 0x80 { 1723 | break 1724 | } 1725 | } 1726 | fieldNum := int32(wire >> 3) 1727 | wireType := int(wire & 0x7) 1728 | if wireType == 4 { 1729 | return fmt.Errorf("proto: Reply: wiretype end group for non-group") 1730 | } 1731 | if fieldNum <= 0 { 1732 | return fmt.Errorf("proto: Reply: illegal tag %d (wire type %d)", fieldNum, wire) 1733 | } 1734 | switch fieldNum { 1735 | case 5: 1736 | if wireType != 2 { 1737 | return fmt.Errorf("proto: wrong wireType = %d for field LastBal", wireType) 1738 | } 1739 | var msglen int 1740 | for shift := uint(0); ; shift += 7 { 1741 | if shift >= 64 { 1742 | return ErrIntOverflowPaxoskv 1743 | } 1744 | if iNdEx >= l { 1745 | return io.ErrUnexpectedEOF 1746 | } 1747 | b := dAtA[iNdEx] 1748 | iNdEx++ 1749 | msglen |= int(b&0x7F) << shift 1750 | if b < 0x80 { 1751 | break 1752 | } 1753 | } 1754 | if msglen < 0 { 1755 | return ErrInvalidLengthPaxoskv 1756 | } 1757 | postIndex := iNdEx + msglen 1758 | if postIndex < 0 { 1759 | return ErrInvalidLengthPaxoskv 1760 | } 1761 | if postIndex > l { 1762 | return io.ErrUnexpectedEOF 1763 | } 1764 | if m.LastBal == nil { 1765 | m.LastBal = &BallotNum{} 1766 | } 1767 | if err := m.LastBal.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { 1768 | return err 1769 | } 1770 | iNdEx = postIndex 1771 | case 20: 1772 | if wireType != 2 { 1773 | return fmt.Errorf("proto: wrong wireType = %d for field Instances", wireType) 1774 | } 1775 | var msglen int 1776 | for shift := uint(0); ; shift += 7 { 1777 | if shift >= 64 { 1778 | return ErrIntOverflowPaxoskv 1779 | } 1780 | if iNdEx >= l { 1781 | return io.ErrUnexpectedEOF 1782 | } 1783 | b := dAtA[iNdEx] 1784 | iNdEx++ 1785 | msglen |= int(b&0x7F) << shift 1786 | if b < 0x80 { 1787 | break 1788 | } 1789 | } 1790 | if msglen < 0 { 1791 | return ErrInvalidLengthPaxoskv 1792 | } 1793 | postIndex := iNdEx + msglen 1794 | if postIndex < 0 { 1795 | return ErrInvalidLengthPaxoskv 1796 | } 1797 | if postIndex > l { 1798 | return io.ErrUnexpectedEOF 1799 | } 1800 | if m.Instances == nil { 1801 | m.Instances = make(map[int64]*Ins) 1802 | } 1803 | var mapkey int64 1804 | var mapvalue *Ins 1805 | for iNdEx < postIndex { 1806 | entryPreIndex := iNdEx 1807 | var wire uint64 1808 | for shift := uint(0); ; shift += 7 { 1809 | if shift >= 64 { 1810 | return ErrIntOverflowPaxoskv 1811 | } 1812 | if iNdEx >= l { 1813 | return io.ErrUnexpectedEOF 1814 | } 1815 | b := dAtA[iNdEx] 1816 | iNdEx++ 1817 | wire |= uint64(b&0x7F) << shift 1818 | if b < 0x80 { 1819 | break 1820 | } 1821 | } 1822 | fieldNum := int32(wire >> 3) 1823 | if fieldNum == 1 { 1824 | for shift := uint(0); ; shift += 7 { 1825 | if shift >= 64 { 1826 | return ErrIntOverflowPaxoskv 1827 | } 1828 | if iNdEx >= l { 1829 | return io.ErrUnexpectedEOF 1830 | } 1831 | b := dAtA[iNdEx] 1832 | iNdEx++ 1833 | mapkey |= int64(b&0x7F) << shift 1834 | if b < 0x80 { 1835 | break 1836 | } 1837 | } 1838 | } else if fieldNum == 2 { 1839 | var mapmsglen int 1840 | for shift := uint(0); ; shift += 7 { 1841 | if shift >= 64 { 1842 | return ErrIntOverflowPaxoskv 1843 | } 1844 | if iNdEx >= l { 1845 | return io.ErrUnexpectedEOF 1846 | } 1847 | b := dAtA[iNdEx] 1848 | iNdEx++ 1849 | mapmsglen |= int(b&0x7F) << shift 1850 | if b < 0x80 { 1851 | break 1852 | } 1853 | } 1854 | if mapmsglen < 0 { 1855 | return ErrInvalidLengthPaxoskv 1856 | } 1857 | postmsgIndex := iNdEx + mapmsglen 1858 | if postmsgIndex < 0 { 1859 | return ErrInvalidLengthPaxoskv 1860 | } 1861 | if postmsgIndex > l { 1862 | return io.ErrUnexpectedEOF 1863 | } 1864 | mapvalue = &Ins{} 1865 | if err := mapvalue.Unmarshal(dAtA[iNdEx:postmsgIndex]); err != nil { 1866 | return err 1867 | } 1868 | iNdEx = postmsgIndex 1869 | } else { 1870 | iNdEx = entryPreIndex 1871 | skippy, err := skipPaxoskv(dAtA[iNdEx:]) 1872 | if err != nil { 1873 | return err 1874 | } 1875 | if (skippy < 0) || (iNdEx+skippy) < 0 { 1876 | return ErrInvalidLengthPaxoskv 1877 | } 1878 | if (iNdEx + skippy) > postIndex { 1879 | return io.ErrUnexpectedEOF 1880 | } 1881 | iNdEx += skippy 1882 | } 1883 | } 1884 | m.Instances[mapkey] = mapvalue 1885 | iNdEx = postIndex 1886 | default: 1887 | iNdEx = preIndex 1888 | skippy, err := skipPaxoskv(dAtA[iNdEx:]) 1889 | if err != nil { 1890 | return err 1891 | } 1892 | if (skippy < 0) || (iNdEx+skippy) < 0 { 1893 | return ErrInvalidLengthPaxoskv 1894 | } 1895 | if (iNdEx + skippy) > l { 1896 | return io.ErrUnexpectedEOF 1897 | } 1898 | iNdEx += skippy 1899 | } 1900 | } 1901 | 1902 | if iNdEx > l { 1903 | return io.ErrUnexpectedEOF 1904 | } 1905 | return nil 1906 | } 1907 | func (m *BallotNum) Unmarshal(dAtA []byte) error { 1908 | l := len(dAtA) 1909 | iNdEx := 0 1910 | for iNdEx < l { 1911 | preIndex := iNdEx 1912 | var wire uint64 1913 | for shift := uint(0); ; shift += 7 { 1914 | if shift >= 64 { 1915 | return ErrIntOverflowPaxoskv 1916 | } 1917 | if iNdEx >= l { 1918 | return io.ErrUnexpectedEOF 1919 | } 1920 | b := dAtA[iNdEx] 1921 | iNdEx++ 1922 | wire |= uint64(b&0x7F) << shift 1923 | if b < 0x80 { 1924 | break 1925 | } 1926 | } 1927 | fieldNum := int32(wire >> 3) 1928 | wireType := int(wire & 0x7) 1929 | if wireType == 4 { 1930 | return fmt.Errorf("proto: BallotNum: wiretype end group for non-group") 1931 | } 1932 | if fieldNum <= 0 { 1933 | return fmt.Errorf("proto: BallotNum: illegal tag %d (wire type %d)", fieldNum, wire) 1934 | } 1935 | switch fieldNum { 1936 | case 1: 1937 | if wireType != 0 { 1938 | return fmt.Errorf("proto: wrong wireType = %d for field N", wireType) 1939 | } 1940 | m.N = 0 1941 | for shift := uint(0); ; shift += 7 { 1942 | if shift >= 64 { 1943 | return ErrIntOverflowPaxoskv 1944 | } 1945 | if iNdEx >= l { 1946 | return io.ErrUnexpectedEOF 1947 | } 1948 | b := dAtA[iNdEx] 1949 | iNdEx++ 1950 | m.N |= int64(b&0x7F) << shift 1951 | if b < 0x80 { 1952 | break 1953 | } 1954 | } 1955 | case 2: 1956 | if wireType != 0 { 1957 | return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) 1958 | } 1959 | m.Id = 0 1960 | for shift := uint(0); ; shift += 7 { 1961 | if shift >= 64 { 1962 | return ErrIntOverflowPaxoskv 1963 | } 1964 | if iNdEx >= l { 1965 | return io.ErrUnexpectedEOF 1966 | } 1967 | b := dAtA[iNdEx] 1968 | iNdEx++ 1969 | m.Id |= int64(b&0x7F) << shift 1970 | if b < 0x80 { 1971 | break 1972 | } 1973 | } 1974 | default: 1975 | iNdEx = preIndex 1976 | skippy, err := skipPaxoskv(dAtA[iNdEx:]) 1977 | if err != nil { 1978 | return err 1979 | } 1980 | if (skippy < 0) || (iNdEx+skippy) < 0 { 1981 | return ErrInvalidLengthPaxoskv 1982 | } 1983 | if (iNdEx + skippy) > l { 1984 | return io.ErrUnexpectedEOF 1985 | } 1986 | iNdEx += skippy 1987 | } 1988 | } 1989 | 1990 | if iNdEx > l { 1991 | return io.ErrUnexpectedEOF 1992 | } 1993 | return nil 1994 | } 1995 | func (m *Cmd) Unmarshal(dAtA []byte) error { 1996 | l := len(dAtA) 1997 | iNdEx := 0 1998 | for iNdEx < l { 1999 | preIndex := iNdEx 2000 | var wire uint64 2001 | for shift := uint(0); ; shift += 7 { 2002 | if shift >= 64 { 2003 | return ErrIntOverflowPaxoskv 2004 | } 2005 | if iNdEx >= l { 2006 | return io.ErrUnexpectedEOF 2007 | } 2008 | b := dAtA[iNdEx] 2009 | iNdEx++ 2010 | wire |= uint64(b&0x7F) << shift 2011 | if b < 0x80 { 2012 | break 2013 | } 2014 | } 2015 | fieldNum := int32(wire >> 3) 2016 | wireType := int(wire & 0x7) 2017 | if wireType == 4 { 2018 | return fmt.Errorf("proto: Cmd: wiretype end group for non-group") 2019 | } 2020 | if fieldNum <= 0 { 2021 | return fmt.Errorf("proto: Cmd: illegal tag %d (wire type %d)", fieldNum, wire) 2022 | } 2023 | switch fieldNum { 2024 | case 3: 2025 | if wireType != 2 { 2026 | return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType) 2027 | } 2028 | var stringLen uint64 2029 | for shift := uint(0); ; shift += 7 { 2030 | if shift >= 64 { 2031 | return ErrIntOverflowPaxoskv 2032 | } 2033 | if iNdEx >= l { 2034 | return io.ErrUnexpectedEOF 2035 | } 2036 | b := dAtA[iNdEx] 2037 | iNdEx++ 2038 | stringLen |= uint64(b&0x7F) << shift 2039 | if b < 0x80 { 2040 | break 2041 | } 2042 | } 2043 | intStringLen := int(stringLen) 2044 | if intStringLen < 0 { 2045 | return ErrInvalidLengthPaxoskv 2046 | } 2047 | postIndex := iNdEx + intStringLen 2048 | if postIndex < 0 { 2049 | return ErrInvalidLengthPaxoskv 2050 | } 2051 | if postIndex > l { 2052 | return io.ErrUnexpectedEOF 2053 | } 2054 | m.Key = string(dAtA[iNdEx:postIndex]) 2055 | iNdEx = postIndex 2056 | case 4: 2057 | if wireType != 0 { 2058 | return fmt.Errorf("proto: wrong wireType = %d for field Vi64", wireType) 2059 | } 2060 | m.Vi64 = 0 2061 | for shift := uint(0); ; shift += 7 { 2062 | if shift >= 64 { 2063 | return ErrIntOverflowPaxoskv 2064 | } 2065 | if iNdEx >= l { 2066 | return io.ErrUnexpectedEOF 2067 | } 2068 | b := dAtA[iNdEx] 2069 | iNdEx++ 2070 | m.Vi64 |= int64(b&0x7F) << shift 2071 | if b < 0x80 { 2072 | break 2073 | } 2074 | } 2075 | default: 2076 | iNdEx = preIndex 2077 | skippy, err := skipPaxoskv(dAtA[iNdEx:]) 2078 | if err != nil { 2079 | return err 2080 | } 2081 | if (skippy < 0) || (iNdEx+skippy) < 0 { 2082 | return ErrInvalidLengthPaxoskv 2083 | } 2084 | if (iNdEx + skippy) > l { 2085 | return io.ErrUnexpectedEOF 2086 | } 2087 | iNdEx += skippy 2088 | } 2089 | } 2090 | 2091 | if iNdEx > l { 2092 | return io.ErrUnexpectedEOF 2093 | } 2094 | return nil 2095 | } 2096 | func (m *InsId) Unmarshal(dAtA []byte) error { 2097 | l := len(dAtA) 2098 | iNdEx := 0 2099 | for iNdEx < l { 2100 | preIndex := iNdEx 2101 | var wire uint64 2102 | for shift := uint(0); ; shift += 7 { 2103 | if shift >= 64 { 2104 | return ErrIntOverflowPaxoskv 2105 | } 2106 | if iNdEx >= l { 2107 | return io.ErrUnexpectedEOF 2108 | } 2109 | b := dAtA[iNdEx] 2110 | iNdEx++ 2111 | wire |= uint64(b&0x7F) << shift 2112 | if b < 0x80 { 2113 | break 2114 | } 2115 | } 2116 | fieldNum := int32(wire >> 3) 2117 | wireType := int(wire & 0x7) 2118 | if wireType == 4 { 2119 | return fmt.Errorf("proto: InsId: wiretype end group for non-group") 2120 | } 2121 | if fieldNum <= 0 { 2122 | return fmt.Errorf("proto: InsId: illegal tag %d (wire type %d)", fieldNum, wire) 2123 | } 2124 | switch fieldNum { 2125 | case 1: 2126 | if wireType != 0 { 2127 | return fmt.Errorf("proto: wrong wireType = %d for field Column", wireType) 2128 | } 2129 | m.Column = 0 2130 | for shift := uint(0); ; shift += 7 { 2131 | if shift >= 64 { 2132 | return ErrIntOverflowPaxoskv 2133 | } 2134 | if iNdEx >= l { 2135 | return io.ErrUnexpectedEOF 2136 | } 2137 | b := dAtA[iNdEx] 2138 | iNdEx++ 2139 | m.Column |= int64(b&0x7F) << shift 2140 | if b < 0x80 { 2141 | break 2142 | } 2143 | } 2144 | case 5: 2145 | if wireType != 0 { 2146 | return fmt.Errorf("proto: wrong wireType = %d for field LSN", wireType) 2147 | } 2148 | m.LSN = 0 2149 | for shift := uint(0); ; shift += 7 { 2150 | if shift >= 64 { 2151 | return ErrIntOverflowPaxoskv 2152 | } 2153 | if iNdEx >= l { 2154 | return io.ErrUnexpectedEOF 2155 | } 2156 | b := dAtA[iNdEx] 2157 | iNdEx++ 2158 | m.LSN |= int64(b&0x7F) << shift 2159 | if b < 0x80 { 2160 | break 2161 | } 2162 | } 2163 | case 10: 2164 | if wireType != 0 { 2165 | return fmt.Errorf("proto: wrong wireType = %d for field ProposerId", wireType) 2166 | } 2167 | m.ProposerId = 0 2168 | for shift := uint(0); ; shift += 7 { 2169 | if shift >= 64 { 2170 | return ErrIntOverflowPaxoskv 2171 | } 2172 | if iNdEx >= l { 2173 | return io.ErrUnexpectedEOF 2174 | } 2175 | b := dAtA[iNdEx] 2176 | iNdEx++ 2177 | m.ProposerId |= int64(b&0x7F) << shift 2178 | if b < 0x80 { 2179 | break 2180 | } 2181 | } 2182 | default: 2183 | iNdEx = preIndex 2184 | skippy, err := skipPaxoskv(dAtA[iNdEx:]) 2185 | if err != nil { 2186 | return err 2187 | } 2188 | if (skippy < 0) || (iNdEx+skippy) < 0 { 2189 | return ErrInvalidLengthPaxoskv 2190 | } 2191 | if (iNdEx + skippy) > l { 2192 | return io.ErrUnexpectedEOF 2193 | } 2194 | iNdEx += skippy 2195 | } 2196 | } 2197 | 2198 | if iNdEx > l { 2199 | return io.ErrUnexpectedEOF 2200 | } 2201 | return nil 2202 | } 2203 | func (m *Ins) Unmarshal(dAtA []byte) error { 2204 | l := len(dAtA) 2205 | iNdEx := 0 2206 | for iNdEx < l { 2207 | preIndex := iNdEx 2208 | var wire uint64 2209 | for shift := uint(0); ; shift += 7 { 2210 | if shift >= 64 { 2211 | return ErrIntOverflowPaxoskv 2212 | } 2213 | if iNdEx >= l { 2214 | return io.ErrUnexpectedEOF 2215 | } 2216 | b := dAtA[iNdEx] 2217 | iNdEx++ 2218 | wire |= uint64(b&0x7F) << shift 2219 | if b < 0x80 { 2220 | break 2221 | } 2222 | } 2223 | fieldNum := int32(wire >> 3) 2224 | wireType := int(wire & 0x7) 2225 | if wireType == 4 { 2226 | return fmt.Errorf("proto: Ins: wiretype end group for non-group") 2227 | } 2228 | if fieldNum <= 0 { 2229 | return fmt.Errorf("proto: Ins: illegal tag %d (wire type %d)", fieldNum, wire) 2230 | } 2231 | switch fieldNum { 2232 | case 1: 2233 | if wireType != 2 { 2234 | return fmt.Errorf("proto: wrong wireType = %d for field InsId", wireType) 2235 | } 2236 | var msglen int 2237 | for shift := uint(0); ; shift += 7 { 2238 | if shift >= 64 { 2239 | return ErrIntOverflowPaxoskv 2240 | } 2241 | if iNdEx >= l { 2242 | return io.ErrUnexpectedEOF 2243 | } 2244 | b := dAtA[iNdEx] 2245 | iNdEx++ 2246 | msglen |= int(b&0x7F) << shift 2247 | if b < 0x80 { 2248 | break 2249 | } 2250 | } 2251 | if msglen < 0 { 2252 | return ErrInvalidLengthPaxoskv 2253 | } 2254 | postIndex := iNdEx + msglen 2255 | if postIndex < 0 { 2256 | return ErrInvalidLengthPaxoskv 2257 | } 2258 | if postIndex > l { 2259 | return io.ErrUnexpectedEOF 2260 | } 2261 | if m.InsId == nil { 2262 | m.InsId = &InsId{} 2263 | } 2264 | if err := m.InsId.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { 2265 | return err 2266 | } 2267 | iNdEx = postIndex 2268 | case 3: 2269 | if wireType != 2 { 2270 | return fmt.Errorf("proto: wrong wireType = %d for field Val", wireType) 2271 | } 2272 | var msglen int 2273 | for shift := uint(0); ; shift += 7 { 2274 | if shift >= 64 { 2275 | return ErrIntOverflowPaxoskv 2276 | } 2277 | if iNdEx >= l { 2278 | return io.ErrUnexpectedEOF 2279 | } 2280 | b := dAtA[iNdEx] 2281 | iNdEx++ 2282 | msglen |= int(b&0x7F) << shift 2283 | if b < 0x80 { 2284 | break 2285 | } 2286 | } 2287 | if msglen < 0 { 2288 | return ErrInvalidLengthPaxoskv 2289 | } 2290 | postIndex := iNdEx + msglen 2291 | if postIndex < 0 { 2292 | return ErrInvalidLengthPaxoskv 2293 | } 2294 | if postIndex > l { 2295 | return io.ErrUnexpectedEOF 2296 | } 2297 | if m.Val == nil { 2298 | m.Val = &Cmd{} 2299 | } 2300 | if err := m.Val.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { 2301 | return err 2302 | } 2303 | iNdEx = postIndex 2304 | case 5: 2305 | if wireType != 2 { 2306 | return fmt.Errorf("proto: wrong wireType = %d for field VBal", wireType) 2307 | } 2308 | var msglen int 2309 | for shift := uint(0); ; shift += 7 { 2310 | if shift >= 64 { 2311 | return ErrIntOverflowPaxoskv 2312 | } 2313 | if iNdEx >= l { 2314 | return io.ErrUnexpectedEOF 2315 | } 2316 | b := dAtA[iNdEx] 2317 | iNdEx++ 2318 | msglen |= int(b&0x7F) << shift 2319 | if b < 0x80 { 2320 | break 2321 | } 2322 | } 2323 | if msglen < 0 { 2324 | return ErrInvalidLengthPaxoskv 2325 | } 2326 | postIndex := iNdEx + msglen 2327 | if postIndex < 0 { 2328 | return ErrInvalidLengthPaxoskv 2329 | } 2330 | if postIndex > l { 2331 | return io.ErrUnexpectedEOF 2332 | } 2333 | if m.VBal == nil { 2334 | m.VBal = &BallotNum{} 2335 | } 2336 | if err := m.VBal.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { 2337 | return err 2338 | } 2339 | iNdEx = postIndex 2340 | case 6: 2341 | if wireType == 0 { 2342 | var v int64 2343 | for shift := uint(0); ; shift += 7 { 2344 | if shift >= 64 { 2345 | return ErrIntOverflowPaxoskv 2346 | } 2347 | if iNdEx >= l { 2348 | return io.ErrUnexpectedEOF 2349 | } 2350 | b := dAtA[iNdEx] 2351 | iNdEx++ 2352 | v |= int64(b&0x7F) << shift 2353 | if b < 0x80 { 2354 | break 2355 | } 2356 | } 2357 | m.Deps = append(m.Deps, v) 2358 | } else if wireType == 2 { 2359 | var packedLen int 2360 | for shift := uint(0); ; shift += 7 { 2361 | if shift >= 64 { 2362 | return ErrIntOverflowPaxoskv 2363 | } 2364 | if iNdEx >= l { 2365 | return io.ErrUnexpectedEOF 2366 | } 2367 | b := dAtA[iNdEx] 2368 | iNdEx++ 2369 | packedLen |= int(b&0x7F) << shift 2370 | if b < 0x80 { 2371 | break 2372 | } 2373 | } 2374 | if packedLen < 0 { 2375 | return ErrInvalidLengthPaxoskv 2376 | } 2377 | postIndex := iNdEx + packedLen 2378 | if postIndex < 0 { 2379 | return ErrInvalidLengthPaxoskv 2380 | } 2381 | if postIndex > l { 2382 | return io.ErrUnexpectedEOF 2383 | } 2384 | var elementCount int 2385 | var count int 2386 | for _, integer := range dAtA[iNdEx:postIndex] { 2387 | if integer < 128 { 2388 | count++ 2389 | } 2390 | } 2391 | elementCount = count 2392 | if elementCount != 0 && len(m.Deps) == 0 { 2393 | m.Deps = make([]int64, 0, elementCount) 2394 | } 2395 | for iNdEx < postIndex { 2396 | var v int64 2397 | for shift := uint(0); ; shift += 7 { 2398 | if shift >= 64 { 2399 | return ErrIntOverflowPaxoskv 2400 | } 2401 | if iNdEx >= l { 2402 | return io.ErrUnexpectedEOF 2403 | } 2404 | b := dAtA[iNdEx] 2405 | iNdEx++ 2406 | v |= int64(b&0x7F) << shift 2407 | if b < 0x80 { 2408 | break 2409 | } 2410 | } 2411 | m.Deps = append(m.Deps, v) 2412 | } 2413 | } else { 2414 | return fmt.Errorf("proto: wrong wireType = %d for field Deps", wireType) 2415 | } 2416 | case 7: 2417 | if wireType != 0 { 2418 | return fmt.Errorf("proto: wrong wireType = %d for field Committed", wireType) 2419 | } 2420 | var v int 2421 | for shift := uint(0); ; shift += 7 { 2422 | if shift >= 64 { 2423 | return ErrIntOverflowPaxoskv 2424 | } 2425 | if iNdEx >= l { 2426 | return io.ErrUnexpectedEOF 2427 | } 2428 | b := dAtA[iNdEx] 2429 | iNdEx++ 2430 | v |= int(b&0x7F) << shift 2431 | if b < 0x80 { 2432 | break 2433 | } 2434 | } 2435 | m.Committed = bool(v != 0) 2436 | default: 2437 | iNdEx = preIndex 2438 | skippy, err := skipPaxoskv(dAtA[iNdEx:]) 2439 | if err != nil { 2440 | return err 2441 | } 2442 | if (skippy < 0) || (iNdEx+skippy) < 0 { 2443 | return ErrInvalidLengthPaxoskv 2444 | } 2445 | if (iNdEx + skippy) > l { 2446 | return io.ErrUnexpectedEOF 2447 | } 2448 | iNdEx += skippy 2449 | } 2450 | } 2451 | 2452 | if iNdEx > l { 2453 | return io.ErrUnexpectedEOF 2454 | } 2455 | return nil 2456 | } 2457 | func skipPaxoskv(dAtA []byte) (n int, err error) { 2458 | l := len(dAtA) 2459 | iNdEx := 0 2460 | depth := 0 2461 | for iNdEx < l { 2462 | var wire uint64 2463 | for shift := uint(0); ; shift += 7 { 2464 | if shift >= 64 { 2465 | return 0, ErrIntOverflowPaxoskv 2466 | } 2467 | if iNdEx >= l { 2468 | return 0, io.ErrUnexpectedEOF 2469 | } 2470 | b := dAtA[iNdEx] 2471 | iNdEx++ 2472 | wire |= (uint64(b) & 0x7F) << shift 2473 | if b < 0x80 { 2474 | break 2475 | } 2476 | } 2477 | wireType := int(wire & 0x7) 2478 | switch wireType { 2479 | case 0: 2480 | for shift := uint(0); ; shift += 7 { 2481 | if shift >= 64 { 2482 | return 0, ErrIntOverflowPaxoskv 2483 | } 2484 | if iNdEx >= l { 2485 | return 0, io.ErrUnexpectedEOF 2486 | } 2487 | iNdEx++ 2488 | if dAtA[iNdEx-1] < 0x80 { 2489 | break 2490 | } 2491 | } 2492 | case 1: 2493 | iNdEx += 8 2494 | case 2: 2495 | var length int 2496 | for shift := uint(0); ; shift += 7 { 2497 | if shift >= 64 { 2498 | return 0, ErrIntOverflowPaxoskv 2499 | } 2500 | if iNdEx >= l { 2501 | return 0, io.ErrUnexpectedEOF 2502 | } 2503 | b := dAtA[iNdEx] 2504 | iNdEx++ 2505 | length |= (int(b) & 0x7F) << shift 2506 | if b < 0x80 { 2507 | break 2508 | } 2509 | } 2510 | if length < 0 { 2511 | return 0, ErrInvalidLengthPaxoskv 2512 | } 2513 | iNdEx += length 2514 | case 3: 2515 | depth++ 2516 | case 4: 2517 | if depth == 0 { 2518 | return 0, ErrUnexpectedEndOfGroupPaxoskv 2519 | } 2520 | depth-- 2521 | case 5: 2522 | iNdEx += 4 2523 | default: 2524 | return 0, fmt.Errorf("proto: illegal wireType %d", wireType) 2525 | } 2526 | if iNdEx < 0 { 2527 | return 0, ErrInvalidLengthPaxoskv 2528 | } 2529 | if depth == 0 { 2530 | return iNdEx, nil 2531 | } 2532 | } 2533 | return 0, io.ErrUnexpectedEOF 2534 | } 2535 | 2536 | var ( 2537 | ErrInvalidLengthPaxoskv = fmt.Errorf("proto: negative length found during unmarshaling") 2538 | ErrIntOverflowPaxoskv = fmt.Errorf("proto: integer overflow") 2539 | ErrUnexpectedEndOfGroupPaxoskv = fmt.Errorf("proto: unexpected end of group") 2540 | ) 2541 | -------------------------------------------------------------------------------- /paxoskv/recover.go: -------------------------------------------------------------------------------- 1 | package paxoskv 2 | 3 | import ( 4 | "math/rand" 5 | "time" 6 | ) 7 | 8 | // find out uncommitted instances and try to commit them, in case the leader crashes. 9 | func (s *KVServer) recoveryLoop(column int64) { 10 | s.wg.Add(1) 11 | 12 | prev := int64(0) 13 | next := int64(0) 14 | seen := int64(-1) 15 | for { 16 | 17 | select { 18 | case <-s.running: 19 | // closed 20 | s.wg.Done() 21 | return 22 | default: 23 | } 24 | 25 | prev = next 26 | 27 | time.Sleep(time.Millisecond * time.Duration(rand.Int()%10+10)) 28 | 29 | next, seen = s.getCommitState(column) 30 | dd(s, "recover: column: %d next:%d, prev:%d, seen: %d", column, next, prev, seen) 31 | if next == seen || next > prev { 32 | continue 33 | } 34 | 35 | s.recover(column, next) 36 | } 37 | } 38 | 39 | func (s *KVServer) recover(column, lsn int64) { 40 | if column == s.Id { 41 | panic("wtf") 42 | } 43 | 44 | dd(s, "start recover %d-%d", column, lsn) 45 | 46 | col := s.log.columns[column] 47 | 48 | var inst *Ins 49 | var h *Handler 50 | 51 | s.Lock() 52 | if col.getInstance(lsn) == nil { 53 | inst = s.NewNoop(column, lsn) 54 | h = NewHandler(s, inst) 55 | h.setInstance(inst) 56 | } else { 57 | inst = col.getInstance(lsn) 58 | h = NewHandler(s, inst) 59 | } 60 | s.Unlock() 61 | 62 | // repair with the other non leader column 63 | to := 3 - s.Id - column 64 | dd(h, "start recover: %s", inst.str()) 65 | recovered := h.runPaxosLoop(column, lsn, []int64{to}) 66 | dd(h, "recover-ed: column:%d, lsn:%d, %s", column, lsn, recovered.str()) 67 | } 68 | 69 | func (s *KVServer) NewNoop(column, lsn int64) *Ins { 70 | inst := &Ins{ 71 | InsId: &InsId{ 72 | Column: column, 73 | LSN: lsn, 74 | ProposerId: s.Id, 75 | }, 76 | Val: &Cmd{ 77 | Key: "NOOP", 78 | Vi64: 0, 79 | }, 80 | VBal: nil, 81 | Deps: s.getLogLens(), 82 | Committed: false, 83 | } 84 | 85 | return inst 86 | } 87 | -------------------------------------------------------------------------------- /paxoskv/recover_test.go: -------------------------------------------------------------------------------- 1 | package paxoskv 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestNewNOOP(t *testing.T) { 10 | ta := require.New(t) 11 | s := NewKVServer(2) 12 | s.log.columns = []*Column{ 13 | {Log: []*Ins{nil, nil}}, 14 | {Log: []*Ins{nil}}, 15 | {Log: []*Ins{nil, nil, nil}}, 16 | } 17 | inst := s.NewNoop(1, 5) 18 | ta.Equal("<1-5-2: vbal:nil c:false seen:2,1,3>", inst.str()) 19 | } 20 | -------------------------------------------------------------------------------- /paxoskv/server.go: -------------------------------------------------------------------------------- 1 | package paxoskv 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net" 7 | "os" 8 | "sync" 9 | "time" 10 | 11 | "github.com/gogo/protobuf/proto" 12 | "github.com/kr/pretty" 13 | "golang.org/x/net/context" 14 | "google.golang.org/grpc" 15 | "google.golang.org/grpc/reflection" 16 | ) 17 | 18 | // KVServer provides: a single Proposer with field Bal, multiple Instances with Log. 19 | type KVServer struct { 20 | sync.Mutex 21 | 22 | addr string 23 | 24 | Id int64 25 | cluster []int64 26 | other []int64 27 | 28 | log *Log 29 | 30 | applier applier 31 | 32 | stateMachine *StateMachine 33 | 34 | running chan bool 35 | wg sync.WaitGroup 36 | grpcSrv *grpc.Server 37 | 38 | lg *log.Logger 39 | } 40 | 41 | func NewKVServer(id int64) *KVServer { 42 | pkv := &KVServer{ 43 | Id: id, 44 | addr: fmt.Sprintf(":%d", AcceptorBasePort+int64(id)), 45 | cluster: []int64{0, 1, 2}, 46 | other: []int64{}, 47 | 48 | log: NewLog(), 49 | 50 | // A traditional apply algo is by finding the SCC and then apply the smallest in an SCC. 51 | // a simplified apply algo just apply the instance with least number of dependency. 52 | // SCC and VC may choose different instance to apply. Both guarantees consistency and linearizability. 53 | // 54 | // Leave one of them uncommented and go test to see the difference. 55 | // applier: &ApplierSCC{}, 56 | applier: &ApplierVC{}, 57 | 58 | stateMachine: NewStateMachine(), 59 | 60 | running: make(chan bool), 61 | grpcSrv: grpc.NewServer(), 62 | lg: log.New(os.Stderr, fmt.Sprintf("R%d: ", id), log.Ltime|log.Lmicroseconds|log.Lshortfile|log.Lmsgprefix), 63 | } 64 | 65 | for _, rid := range pkv.cluster { 66 | if id == rid { 67 | continue 68 | } 69 | pkv.other = append(pkv.other, rid) 70 | } 71 | 72 | RegisterPaxosKVServer(pkv.grpcSrv, pkv) 73 | reflection.Register(pkv.grpcSrv) 74 | 75 | return pkv 76 | } 77 | 78 | func (s *KVServer) Start() { 79 | 80 | lis, err := net.Listen("tcp", s.addr) 81 | if err != nil { 82 | panic(pretty.Sprintf("listen: %s %s", s.addr, err.Error())) 83 | } 84 | 85 | dd(s, "serving on %s ...", s.addr) 86 | go s.grpcSrv.Serve(lis) 87 | 88 | for _, column := range s.other { 89 | go s.recoveryLoop(column) 90 | } 91 | } 92 | 93 | func (s *KVServer) Stop() { 94 | close(s.running) 95 | s.grpcSrv.GracefulStop() 96 | s.wg.Wait() 97 | } 98 | 99 | func (s *KVServer) getLogger() *log.Logger { 100 | return s.lg 101 | } 102 | 103 | func (s *KVServer) waitForApplyAll() { 104 | for _, column := range s.cluster { 105 | dd(s, "start waitForApplyAll: %d", column) 106 | for { 107 | next, seen := s.getAppliedState(column) 108 | dd(s, "waitForApplyAll: column %d: next,seen: %d,%d", column, next, seen) 109 | if next == seen { 110 | break 111 | } 112 | time.Sleep(time.Millisecond * 500) 113 | } 114 | dd(s, "done waitForApplyAll: %d", column) 115 | } 116 | } 117 | func (s *KVServer) getCommitState(column int64) (int64, int64) { 118 | col := s.log.columns[column] 119 | 120 | s.Lock() 121 | defer s.Unlock() 122 | 123 | return s.log.getNextCommits()[column], int64(len(col.Log)) 124 | } 125 | 126 | func (s *KVServer) getAppliedState(column int64) (int64, int64) { 127 | col := s.log.columns[column] 128 | 129 | s.Lock() 130 | defer s.Unlock() 131 | 132 | return s.stateMachine.getNextApplies()[column], int64(len(col.Log)) 133 | } 134 | 135 | func (s *KVServer) getLogLens() []int64 { 136 | return []int64{ 137 | int64(len(s.log.columns[0].Log)), 138 | int64(len(s.log.columns[1].Log)), 139 | int64(len(s.log.columns[2].Log)), 140 | } 141 | } 142 | 143 | // allocNewInst allocates a log-sequence-number in local cmds. 144 | func (s *KVServer) allocNewInst(column int64, cmd *Cmd) *Ins { 145 | col := s.log.columns[column] 146 | 147 | lsn := int64(len(col.Log)) 148 | 149 | // VBal nil: state: prepared 150 | inst := &Ins{ 151 | Val: cmd, 152 | VBal: nil, 153 | InsId: NewInsId(column, lsn, s.Id), 154 | } 155 | col.Log = append(col.Log, inst) 156 | 157 | inst.Deps = s.getLogLens() 158 | 159 | dd(s, "allocated: %s", inst.str()) 160 | return inst.Clone() 161 | } 162 | func (s *KVServer) invalidateLastBal(column int64, bal *BallotNum) { 163 | col := s.log.columns[column] 164 | s.Lock() 165 | defer s.Unlock() 166 | 167 | col.Bal = nil 168 | 169 | if col.LastBal.Less(bal) { 170 | col.LastBal = bal.Clone() 171 | } 172 | } 173 | 174 | func serveKVServers(ids []int64) []*KVServer { 175 | 176 | var servers []*KVServer 177 | 178 | for _, aid := range ids { 179 | 180 | pkv := NewKVServer(aid) 181 | servers = append(servers, pkv) 182 | pkv.Start() 183 | } 184 | 185 | return servers 186 | } 187 | func rpcTo2(to int64, method string, req, reply proto.Message) error { 188 | 189 | ctx, cancel := context.WithTimeout(context.Background(), time.Second*30) 190 | defer cancel() 191 | 192 | address := fmt.Sprintf("127.0.0.1:%d", AcceptorBasePort+int64(to)) 193 | conn, err := grpc.Dial(address, grpc.WithInsecure()) 194 | if err != nil { 195 | return err 196 | } 197 | defer conn.Close() 198 | 199 | err = conn.Invoke(ctx, "/paxoskv.PaxosKV/"+method, req, reply) 200 | return err 201 | } 202 | -------------------------------------------------------------------------------- /paxoskv/setget_test.go: -------------------------------------------------------------------------------- 1 | package paxoskv 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "os" 7 | "sync" 8 | "testing" 9 | 10 | "github.com/stretchr/testify/require" 11 | ) 12 | 13 | func Test_set_get(t *testing.T) { 14 | 15 | ta := require.New(t) 16 | _ = ta 17 | 18 | acceptorIds := []int64{0, 1, 2} 19 | alive := []bool{ 20 | true, 21 | true, 22 | true, 23 | } 24 | 25 | sendErrorRate = 0.2 26 | recvErrorRate = 0.2 27 | 28 | servers := serveKVServers(acceptorIds) 29 | defer func() { 30 | for _, s := range servers { 31 | s.grpcSrv.Stop() 32 | } 33 | }() 34 | for i := range servers { 35 | if !alive[i] { 36 | servers[i].grpcSrv.Stop() 37 | } 38 | } 39 | 40 | letters := "abcdefghijklmnopqrst012"[:3] 41 | r := rand.New(rand.NewSource(555)) 42 | 43 | l := len(letters) 44 | ks := make([]string, 0) 45 | for i := 0; i < 100; i++ { 46 | key := string([]byte{letters[r.Int()%l], letters[r.Int()%l]}) 47 | ks = append(ks, key) 48 | } 49 | 50 | nworker := 5 51 | // nreq := 200 52 | nreq := 20 53 | 54 | var wg sync.WaitGroup 55 | ch := make(chan *Cmd, 1000) 56 | type outT struct { 57 | method string 58 | err error 59 | cmd *Cmd 60 | } 61 | outputCh := make(chan *outT, 1000) 62 | for i := 0; i < nworker; i++ { 63 | wg.Add(1) 64 | go func(aid int64) { 65 | 66 | r := rand.New(rand.NewSource(aid)) 67 | defer wg.Done() 68 | for { 69 | 70 | req := <-ch 71 | if req == nil { 72 | break 73 | } 74 | var err error 75 | var reply *Cmd 76 | for { 77 | aid = int64(r.Int() % 3) 78 | reply = new(Cmd) 79 | err = rpcTo2(aid, "Set", req, reply) 80 | if err == nil { 81 | break 82 | } 83 | } 84 | outputCh <- &outT{ 85 | method: "Set", 86 | err: err, 87 | cmd: reply, 88 | } 89 | 90 | reply = new(Cmd) 91 | err = rpcTo2(aid, "Get", req, reply) 92 | outputCh <- &outT{ 93 | method: "Get", 94 | err: err, 95 | cmd: reply, 96 | } 97 | // ta.Nil(err) 98 | // ta.Equal(req.Key, reply.Key) 99 | // ta.LessOrEqual(req.Vi64, reply.Vi64) 100 | } 101 | }(acceptorIds[i%len(acceptorIds)]) 102 | } 103 | 104 | for i := 0; i < nreq; i++ { 105 | req := &Cmd{ 106 | Key: ks[i%len(ks)], 107 | Vi64: 10000 + int64(i), 108 | } 109 | ch <- req 110 | } 111 | close(ch) 112 | 113 | for i := 0; i < nreq*2; i++ { 114 | out := <-outputCh 115 | fmt.Printf("output: %s %v %v\n", out.method, out.err, out.cmd) 116 | } 117 | 118 | wg.Wait() 119 | 120 | for _, s := range servers { 121 | s.waitForApplyAll() 122 | } 123 | 124 | for _, s := range servers { 125 | s.Stop() 126 | } 127 | for sIdx, s := range servers { 128 | fmt.Println("---") 129 | fmt.Println(s.stateMachine.getState()) 130 | for column := 0; column < 3; column++ { 131 | col := s.log.columns[column] 132 | fmt.Println("column:", column, "next:c/a", s.log.nextCommits[column], s.stateMachine.nextApplies[column]) 133 | for i := 0; i < len(col.Log); i++ { 134 | fmt.Printf("%d %d %s\n", sIdx, column, col.Log[i].str()) 135 | } 136 | } 137 | } 138 | 139 | s := servers[0] 140 | 141 | { 142 | fmt.Println("check every cmd present on s0") 143 | 144 | total := 0 145 | cnt := map[string]int{} 146 | for column, col := range s.log.columns { 147 | _ = column 148 | for i, inst := range col.Log { 149 | ta.EqualValues(i, inst.getLSN(), "lsn is identical to log index") 150 | if !inst.Val.isNoop() { 151 | total += 1 152 | 153 | k := fmt.Sprintf("%s=%d", inst.Val.Key, inst.Val.Vi64) 154 | cnt[k] = cnt[k] + 1 155 | 156 | } 157 | } 158 | } 159 | 160 | for k, v := range cnt { 161 | ta.Equal(1, v, "one log for key:%s", k) 162 | } 163 | 164 | ta.Equal(nreq, total, "one log entry for every Set operation") 165 | 166 | vals := make([]int, nreq) 167 | for column, col := range s.log.columns { 168 | _ = column 169 | for _, v := range col.Log { 170 | if !v.Val.isNoop() { 171 | vals[v.Val.Vi64-10000]++ 172 | } 173 | } 174 | } 175 | for i, v := range vals { 176 | ta.EqualValues(1, v, "every Set has a log entry: %d", i) 177 | } 178 | } 179 | 180 | { 181 | fmt.Println("check depedency: two instance has at least one relation") 182 | for a := 0; a < 3; a++ { 183 | for b := a + 1; b < 3; b++ { 184 | ca := s.log.columns[a].Log 185 | cb := s.log.columns[b].Log 186 | for i := 0; i < len(ca); i++ { 187 | for j := 0; j < len(cb); j++ { 188 | insta := ca[i] 189 | instb := cb[j] 190 | if insta.Deps[b] > int64(j) || instb.Deps[a] > int64(i) { 191 | // there is a relation 192 | } else { 193 | ta.Fail("no relation:", "%d-%d and %d-%d : seen: %v %v", a, i, b, j, insta.Deps, instb.Deps) 194 | } 195 | } 196 | } 197 | } 198 | } 199 | } 200 | 201 | { 202 | fmt.Println("check logs consistent") 203 | for column := 0; column < 3; column++ { 204 | for lsn := 0; lsn < len(s.log.columns[column].Log); lsn++ { 205 | i0 := servers[0].log.columns[column].Log[lsn] 206 | i1 := servers[1].log.columns[column].Log[lsn] 207 | i2 := servers[2].log.columns[column].Log[lsn] 208 | 209 | v0 := i0.Val.str() + " " + fmt.Sprintf("%d,%d,%d", i0.Deps[0], i0.Deps[1], i0.Deps[2]) 210 | v1 := i1.Val.str() + " " + fmt.Sprintf("%d,%d,%d", i1.Deps[0], i1.Deps[1], i1.Deps[2]) 211 | v2 := i2.Val.str() + " " + fmt.Sprintf("%d,%d,%d", i2.Deps[0], i2.Deps[1], i2.Deps[2]) 212 | fmt.Printf("s0 %d-%d: %s\n", column, lsn, v0) 213 | fmt.Printf("s1 %d-%d: %s\n", column, lsn, v1) 214 | fmt.Printf("s2 %d-%d: %s\n", column, lsn, v2) 215 | 216 | ta.Equal(v0, v1, "server 0:1, col-lsn:%d-%d", column, lsn) 217 | ta.Equal(v0, v2, "server 0:2, col-lsn:%d-%d", column, lsn) 218 | } 219 | } 220 | } 221 | 222 | { 223 | fmt.Println("check applySeq") 224 | for _, v := range s.stateMachine.applySeq { 225 | fmt.Println(colLSNIndentedStr(v)) 226 | } 227 | 228 | for i := range servers { 229 | if alive[i] { 230 | ta.Equal(s.stateMachine.applySeq, servers[i].stateMachine.applySeq, "server: %d", i) 231 | } 232 | } 233 | } 234 | 235 | { 236 | fmt.Println("check snapshot") 237 | shot := s.stateMachine.getState() 238 | fmt.Println(shot) 239 | 240 | for i := range servers { 241 | if alive[i] { 242 | ta.Equal(shot, servers[i].stateMachine.getState(), "server %d", i) 243 | } 244 | } 245 | 246 | } 247 | 248 | { 249 | fmt.Println("output graphviz") 250 | g := s.graphviz() 251 | // fmt.Println(g) 252 | pwd := os.Getenv("PWD") 253 | fmt.Println("pwd:", pwd) 254 | err := WriteFile(pwd+"/logs.dot", []byte(g), 0644) 255 | if err != nil { 256 | panic(err.Error()) 257 | } 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /paxoskv/state_machine.go: -------------------------------------------------------------------------------- 1 | package paxoskv 2 | 3 | import ( 4 | "sync" 5 | ) 6 | 7 | type StateMachine struct { 8 | sync.Mutex 9 | nextApplies []int64 10 | state map[string]*Ins 11 | applySeq []int64 12 | } 13 | 14 | func NewStateMachine() *StateMachine { 15 | return &StateMachine{ 16 | nextApplies: []int64{0, 0, 0}, 17 | state: make(map[string]*Ins), 18 | } 19 | } 20 | 21 | func (sm *StateMachine) applyInstance(h *Handler, inst *Ins) { 22 | dd(h, "curr nextApplies: %v, to apply: %s", sm.nextApplies, inst.str()) 23 | column, lsn := inst.getColLSN() 24 | sm.Lock() 25 | defer sm.Unlock() 26 | 27 | if sm.nextApplies[column] > lsn { 28 | // already applied 29 | return 30 | } 31 | 32 | if sm.nextApplies[column] != lsn { 33 | bug(h, "non continuous apply: nextApplies: %d-%d, inst:%s", column, sm.nextApplies[column], inst.str()) 34 | } 35 | 36 | dd(h, "applyInstance: applied: col-lsn=%d-%d: %s", column, lsn, inst.str()) 37 | sm.state[inst.Val.Key] = inst.Clone() 38 | sm.nextApplies[column]++ 39 | sm.applySeq = append(sm.applySeq, inst.packedPosition()) 40 | 41 | } 42 | 43 | func (sm *StateMachine) getNextApplies() []int64 { 44 | sm.Lock() 45 | defer sm.Unlock() 46 | 47 | return []int64{ 48 | sm.nextApplies[0], 49 | sm.nextApplies[1], 50 | sm.nextApplies[2], 51 | } 52 | } 53 | 54 | func (sm *StateMachine) getState() map[string]int64 { 55 | sm.Lock() 56 | defer sm.Unlock() 57 | 58 | rst := make(map[string]int64) 59 | 60 | for k, inst := range sm.state { 61 | rst[k] = inst.Val.Vi64 62 | } 63 | 64 | return rst 65 | } 66 | 67 | func (sm *StateMachine) get(key string) (*Cmd, error) { 68 | sm.Lock() 69 | defer sm.Unlock() 70 | 71 | inst, found := sm.state[key] 72 | dd(nil, "G: v: %s", inst.str()) 73 | if found { 74 | v := inst.Val.Clone() 75 | return v, nil 76 | } 77 | return &Cmd{}, nil 78 | } 79 | -------------------------------------------------------------------------------- /paxoskv/tostr.go: -------------------------------------------------------------------------------- 1 | package paxoskv 2 | 3 | import ( 4 | "fmt" 5 | "sort" 6 | "strings" 7 | ) 8 | 9 | type strer interface { 10 | str() string 11 | } 12 | 13 | func (c *BallotNum) str() string { 14 | if c == nil { 15 | return "nil" 16 | } 17 | 18 | return fmt.Sprintf("%d,%d", c.N, c.Id) 19 | 20 | } 21 | func (c *Cmd) str() string { 22 | if c == nil { 23 | return "nil" 24 | } 25 | return fmt.Sprintf("<%s=%d>", 26 | c.Key, 27 | c.Vi64, 28 | ) 29 | } 30 | 31 | func (a *InsId) str() string { 32 | if a == nil { 33 | return "nil" 34 | } 35 | return fmt.Sprintf("%d-%d-%d", a.Column, a.LSN, a.ProposerId) 36 | } 37 | 38 | func (a *Ins) str() string { 39 | if a == nil { 40 | return "nil" 41 | } 42 | 43 | v := a.Val.str() 44 | vb := a.VBal.str() 45 | c := fmt.Sprintf("%v", a.Committed) 46 | 47 | var seen string 48 | if a.Deps == nil { 49 | seen = "nil" 50 | } else { 51 | seen = fmt.Sprintf("%d,%d,%d", a.Deps[0], a.Deps[1], a.Deps[2]) 52 | } 53 | 54 | return fmt.Sprintf("<%s: %s vbal:%s c:%s seen:%s>", a.InsId.str(), v, vb, c, seen) 55 | } 56 | 57 | func instsStr(as map[int64]*Ins) string { 58 | 59 | lsns := make([]int64, 0) 60 | 61 | for lsn := range as { 62 | lsns = append(lsns, lsn) 63 | } 64 | sort.Slice(lsns, func(i, j int) bool { 65 | return lsns[i] < lsns[j] 66 | }) 67 | 68 | var ss []string 69 | for _, lsn := range lsns { 70 | inst := as[lsn] 71 | ss = append(ss, inst.str()) 72 | } 73 | return strings.Join(ss, ",") 74 | } 75 | 76 | func logsStr(logs []*Ins) string { 77 | 78 | var ss []string 79 | 80 | for _, inst := range logs { 81 | ss = append(ss, inst.str()) 82 | } 83 | return strings.Join(ss, ",") 84 | } 85 | 86 | func (a *Request) str() string { 87 | if a == nil { 88 | return "nil" 89 | } 90 | return fmt.Sprintf("", 91 | a.Op, 92 | a.Bal.str(), 93 | a.Column, 94 | instsStr(a.Instances), 95 | ) 96 | } 97 | 98 | func (a *Reply) str() string { 99 | if a == nil { 100 | return "nil" 101 | } 102 | return fmt.Sprintf("", 103 | a.LastBal.str(), 104 | instsStr(a.Instances), 105 | ) 106 | } 107 | -------------------------------------------------------------------------------- /paxoskv/tostr_test.go: -------------------------------------------------------------------------------- 1 | package paxoskv 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestInstance_str(t *testing.T) { 10 | 11 | ta := require.New(t) 12 | 13 | cases := []struct { 14 | acc *Ins 15 | want string 16 | }{ 17 | { 18 | acc: &Ins{ 19 | InsId: NewInsId(2, 3, 1), 20 | Val: NewCmd("yy", 3), 21 | VBal: &BallotNum{N: 3, Id: 4}, 22 | Deps: []int64{1, 2, 3}, 23 | Committed: true, 24 | }, 25 | want: "<2-3-1: vbal:3,4 c:true seen:1,2,3>", 26 | }, 27 | } 28 | 29 | for i, c := range cases { 30 | got := c.acc.str() 31 | ta.Equal(c.want, got, "%d-th: case: %+v", i+1, c) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /paxoskv/util.go: -------------------------------------------------------------------------------- 1 | package paxoskv 2 | 3 | import ( 4 | "os" 5 | ) 6 | 7 | func min(a, b int64) int64 { 8 | if a > b { 9 | return b 10 | } 11 | return a 12 | } 13 | 14 | func max(a, b int64) int64 { 15 | if a > b { 16 | return a 17 | } 18 | return b 19 | } 20 | 21 | func vecEq(a, b []int64) bool { 22 | if len(a) != len(b) { 23 | return false 24 | } 25 | for i := 0; i < len(a); i++ { 26 | if a[i] != b[i] { 27 | return false 28 | } 29 | } 30 | return true 31 | } 32 | 33 | func dupI64s(x []int64) []int64 { 34 | rst := make([]int64, len(x)) 35 | copy(rst, x) 36 | return rst 37 | 38 | } 39 | 40 | func WriteFile(filename string, data []byte, perm os.FileMode) error { 41 | f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) 42 | if err != nil { 43 | return err 44 | } 45 | _, err = f.Write(data) 46 | if err1 := f.Close(); err == nil { 47 | err = err1 48 | } 49 | return err 50 | } 51 | -------------------------------------------------------------------------------- /proto/paxoskv.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package paxoskv; 4 | option go_package = ".;paxoskv"; 5 | 6 | // Go Modules now includes the version in the filepath for packages within GOPATH/pkg/mode 7 | // Therefore unless we want to hardcode a version here like 8 | // github.com/gogo/protobuf@v1.3.0/gogoproto/gogo.proto then the only other choice is to 9 | // have a more relative import and pass the right import path to protoc. I don't like it 10 | // but its necessary. 11 | import "gogoproto/gogo.proto"; 12 | 13 | option (gogoproto.equal_all) = true; 14 | option (gogoproto.compare_all) = true; 15 | option (gogoproto.goproto_enum_prefix_all) = true; 16 | option (gogoproto.goproto_getters_all) = false; 17 | 18 | enum Op { 19 | Noop = 0; 20 | Accept = 1; 21 | Commit = 2; 22 | } 23 | 24 | // PaxosKV defines the paxos RPC and KV API. 25 | service PaxosKV { 26 | 27 | // paxos API: used internally 28 | rpc HandlePaxos (Request) returns (Reply) {} 29 | 30 | // KV API 31 | 32 | rpc Set (Cmd) returns (Cmd) {} 33 | rpc Get (Cmd) returns (Cmd) {} 34 | } 35 | 36 | message Request { 37 | Op Op = 1; 38 | 39 | BallotNum Bal = 5; 40 | int64 Column = 10; 41 | map Instances = 20; 42 | } 43 | 44 | message Reply { 45 | BallotNum LastBal = 5; 46 | map Instances = 20; 47 | 48 | } 49 | // BallotNum is the ballot number in paxos. It consists of a monotonically 50 | // incremental number and a universally unique ProposerId. 51 | message BallotNum { 52 | int64 N = 1; 53 | int64 Id = 2; 54 | } 55 | 56 | // Cmd is the value in this paxos impl, which is a command to set a key-value 57 | // record. 58 | // In this demo it is just string key and a int64 value. 59 | message Cmd { 60 | string Key = 3; 61 | int64 Vi64 = 4; 62 | } 63 | 64 | // InsId is the id of an instance. 65 | // The tuple (column, lsn, proposer_id) identifies a proposed value. 66 | // Two proposers may propose a same Cmd, in which case 67 | // these two must be distinguishable, otherwise a Write operation may be 68 | // lost. 69 | message InsId { 70 | int64 Column = 1; 71 | // LSN: log-sequence-number 72 | int64 LSN = 5; 73 | // ProposerId is the server id that proposes an instance. 74 | int64 ProposerId = 10; 75 | } 76 | 77 | // Instance is the state of an Instance and is the log entry in a multi column logs paxos 78 | message Ins { 79 | 80 | InsId InsId = 1; 81 | 82 | // the value proposed on this Instance 83 | Cmd Val = 3; 84 | 85 | // at which ballot number the Instance voted it. 86 | BallotNum VBal = 5; 87 | 88 | // What other instance this instance sees. 89 | // This view is used to decide the order to apply instances. 90 | // Intuitively, the more instance one sees, the later it is applied. 91 | repeated int64 Deps = 6; 92 | 93 | bool Committed = 7; 94 | } 95 | --------------------------------------------------------------------------------