├── .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 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/dictionaries/drdrxp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | paxos
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
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 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
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 | 
4 | [](https://travis-ci.com/openacid/mmp3)
5 |
6 | 
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 | 
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 |
--------------------------------------------------------------------------------