mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
Formatted source code for go 1.19.6.
Signed-off-by: James Blair <mail@jamesblair.net>
This commit is contained in:
parent
7318f5dd0c
commit
a91bacf567
@ -2,16 +2,18 @@
|
|||||||
// source: auth.proto
|
// source: auth.proto
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Package authpb is a generated protocol buffer package.
|
Package authpb is a generated protocol buffer package.
|
||||||
|
|
||||||
It is generated from these files:
|
It is generated from these files:
|
||||||
auth.proto
|
|
||||||
|
|
||||||
It has these top-level messages:
|
auth.proto
|
||||||
UserAddOptions
|
|
||||||
User
|
It has these top-level messages:
|
||||||
Permission
|
|
||||||
Role
|
UserAddOptions
|
||||||
|
User
|
||||||
|
Permission
|
||||||
|
Role
|
||||||
*/
|
*/
|
||||||
package authpb
|
package authpb
|
||||||
|
|
||||||
|
@ -68,6 +68,5 @@ Use a custom context to set timeouts on your operations:
|
|||||||
// handle error
|
// handle error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
*/
|
||||||
package client
|
package client
|
||||||
|
@ -57,9 +57,9 @@ func (rc *recorder) GetCurrentState() (state connectivity.State) {
|
|||||||
// RecordTransition records state change happening in subConn and based on that
|
// RecordTransition records state change happening in subConn and based on that
|
||||||
// it evaluates what aggregated state should be.
|
// it evaluates what aggregated state should be.
|
||||||
//
|
//
|
||||||
// - If at least one SubConn in Ready, the aggregated state is Ready;
|
// - If at least one SubConn in Ready, the aggregated state is Ready;
|
||||||
// - Else if at least one SubConn in Connecting, the aggregated state is Connecting;
|
// - Else if at least one SubConn in Connecting, the aggregated state is Connecting;
|
||||||
// - Else the aggregated state is TransientFailure.
|
// - Else the aggregated state is TransientFailure.
|
||||||
//
|
//
|
||||||
// Idle and Shutdown are not considered.
|
// Idle and Shutdown are not considered.
|
||||||
//
|
//
|
||||||
|
@ -102,5 +102,4 @@
|
|||||||
// The grpc load balancer is registered statically and is shared across etcd clients.
|
// The grpc load balancer is registered statically and is shared across etcd clients.
|
||||||
// To enable detailed load balancer logging, set the ETCD_CLIENT_DEBUG environment
|
// To enable detailed load balancer logging, set the ETCD_CLIENT_DEBUG environment
|
||||||
// variable. E.g. "ETCD_CLIENT_DEBUG=1".
|
// variable. E.g. "ETCD_CLIENT_DEBUG=1".
|
||||||
//
|
|
||||||
package clientv3
|
package clientv3
|
||||||
|
@ -1016,12 +1016,12 @@ func TestWatchCancelOnServer(t *testing.T) {
|
|||||||
// TestWatchOverlapContextCancel stresses the watcher stream teardown path by
|
// TestWatchOverlapContextCancel stresses the watcher stream teardown path by
|
||||||
// creating/canceling watchers to ensure that new watchers are not taken down
|
// creating/canceling watchers to ensure that new watchers are not taken down
|
||||||
// by a torn down watch stream. The sort of race that's being detected:
|
// by a torn down watch stream. The sort of race that's being detected:
|
||||||
// 1. create w1 using a cancelable ctx with %v as "ctx"
|
// 1. create w1 using a cancelable ctx with %v as "ctx"
|
||||||
// 2. cancel ctx
|
// 2. cancel ctx
|
||||||
// 3. watcher client begins tearing down watcher grpc stream since no more watchers
|
// 3. watcher client begins tearing down watcher grpc stream since no more watchers
|
||||||
// 3. start creating watcher w2 using a new "ctx" (not canceled), attaches to old grpc stream
|
// 3. start creating watcher w2 using a new "ctx" (not canceled), attaches to old grpc stream
|
||||||
// 4. watcher client finishes tearing down stream on "ctx"
|
// 4. watcher client finishes tearing down stream on "ctx"
|
||||||
// 5. w2 comes back canceled
|
// 5. w2 comes back canceled
|
||||||
func TestWatchOverlapContextCancel(t *testing.T) {
|
func TestWatchOverlapContextCancel(t *testing.T) {
|
||||||
f := func(clus *integration.ClusterV3) {}
|
f := func(clus *integration.ClusterV3) {}
|
||||||
testWatchOverlapContextCancel(t, f)
|
testWatchOverlapContextCancel(t, f)
|
||||||
|
@ -19,28 +19,27 @@
|
|||||||
//
|
//
|
||||||
// First, create a leasing KV from a clientv3.Client 'cli':
|
// First, create a leasing KV from a clientv3.Client 'cli':
|
||||||
//
|
//
|
||||||
// lkv, err := leasing.NewKV(cli, "leasing-prefix")
|
// lkv, err := leasing.NewKV(cli, "leasing-prefix")
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// // handle error
|
// // handle error
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// A range request for a key "abc" tries to acquire a leasing key so it can cache the range's
|
// A range request for a key "abc" tries to acquire a leasing key so it can cache the range's
|
||||||
// key locally. On the server, the leasing key is stored to "leasing-prefix/abc":
|
// key locally. On the server, the leasing key is stored to "leasing-prefix/abc":
|
||||||
//
|
//
|
||||||
// resp, err := lkv.Get(context.TODO(), "abc")
|
// resp, err := lkv.Get(context.TODO(), "abc")
|
||||||
//
|
//
|
||||||
// Future linearized read requests using 'lkv' will be served locally for the lease's lifetime:
|
// Future linearized read requests using 'lkv' will be served locally for the lease's lifetime:
|
||||||
//
|
//
|
||||||
// resp, err = lkv.Get(context.TODO(), "abc")
|
// resp, err = lkv.Get(context.TODO(), "abc")
|
||||||
//
|
//
|
||||||
// If another leasing client writes to a leased key, then the owner relinquishes its exclusive
|
// If another leasing client writes to a leased key, then the owner relinquishes its exclusive
|
||||||
// access, permitting the writer to modify the key:
|
// access, permitting the writer to modify the key:
|
||||||
//
|
//
|
||||||
// lkv2, err := leasing.NewKV(cli, "leasing-prefix")
|
// lkv2, err := leasing.NewKV(cli, "leasing-prefix")
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// // handle error
|
// // handle error
|
||||||
// }
|
// }
|
||||||
// lkv2.Put(context.TODO(), "abc", "456")
|
// lkv2.Put(context.TODO(), "abc", "456")
|
||||||
// resp, err = lkv.Get("abc")
|
// resp, err = lkv.Get("abc")
|
||||||
//
|
|
||||||
package leasing
|
package leasing
|
||||||
|
@ -39,5 +39,4 @@
|
|||||||
// resp, _ = cli.Get(context.TODO(), "abc")
|
// resp, _ = cli.Get(context.TODO(), "abc")
|
||||||
// fmt.Printf("%s\n", resp.Kvs[0].Value)
|
// fmt.Printf("%s\n", resp.Kvs[0].Value)
|
||||||
// // Output: 456
|
// // Output: 456
|
||||||
//
|
|
||||||
package namespace
|
package namespace
|
||||||
|
@ -52,5 +52,4 @@
|
|||||||
// r := &etcdnaming.GRPCResolver{Client: c}
|
// r := &etcdnaming.GRPCResolver{Client: c}
|
||||||
// return r.Update(c.Ctx(), service, naming.Update{Op: naming.Add, Addr: addr}, clientv3.WithLease(lid))
|
// return r.Update(c.Ctx(), service, naming.Update{Op: naming.Add, Addr: addr}, clientv3.WithLease(lid))
|
||||||
// }
|
// }
|
||||||
//
|
|
||||||
package naming
|
package naming
|
||||||
|
@ -38,5 +38,4 @@
|
|||||||
// cli.KV = ordering.NewKV(cli.KV, vf)
|
// cli.KV = ordering.NewKV(cli.KV, vf)
|
||||||
//
|
//
|
||||||
// Now calls using 'cli' will reject order violations with an error.
|
// Now calls using 'cli' will reject order violations with an error.
|
||||||
//
|
|
||||||
package ordering
|
package ordering
|
||||||
|
@ -25,15 +25,14 @@ import (
|
|||||||
|
|
||||||
// Txn is the interface that wraps mini-transactions.
|
// Txn is the interface that wraps mini-transactions.
|
||||||
//
|
//
|
||||||
// Txn(context.TODO()).If(
|
// Txn(context.TODO()).If(
|
||||||
// Compare(Value(k1), ">", v1),
|
// Compare(Value(k1), ">", v1),
|
||||||
// Compare(Version(k1), "=", 2)
|
// Compare(Version(k1), "=", 2)
|
||||||
// ).Then(
|
// ).Then(
|
||||||
// OpPut(k2,v2), OpPut(k3,v3)
|
// OpPut(k2,v2), OpPut(k3,v3)
|
||||||
// ).Else(
|
// ).Else(
|
||||||
// OpPut(k4,v4), OpPut(k5,v5)
|
// OpPut(k4,v4), OpPut(k5,v5)
|
||||||
// ).Commit()
|
// ).Commit()
|
||||||
//
|
|
||||||
type Txn interface {
|
type Txn interface {
|
||||||
// If takes a list of comparison. If all comparisons passed in succeed,
|
// If takes a list of comparison. If all comparisons passed in succeed,
|
||||||
// the operations passed into Then() will be executed. Or the operations
|
// the operations passed into Then() will be executed. Or the operations
|
||||||
|
@ -2,13 +2,15 @@
|
|||||||
// source: snap.proto
|
// source: snap.proto
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Package snappb is a generated protocol buffer package.
|
Package snappb is a generated protocol buffer package.
|
||||||
|
|
||||||
It is generated from these files:
|
It is generated from these files:
|
||||||
snap.proto
|
|
||||||
|
|
||||||
It has these top-level messages:
|
snap.proto
|
||||||
Snapshot
|
|
||||||
|
It has these top-level messages:
|
||||||
|
|
||||||
|
Snapshot
|
||||||
*/
|
*/
|
||||||
package snappb
|
package snappb
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ func TestStoreStatsDeleteFail(t *testing.T) {
|
|||||||
testutil.AssertEqual(t, uint64(1), s.Stats.DeleteFail, "")
|
testutil.AssertEqual(t, uint64(1), s.Stats.DeleteFail, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
//Ensure that the number of expirations is recorded in the stats.
|
// Ensure that the number of expirations is recorded in the stats.
|
||||||
func TestStoreStatsExpireCount(t *testing.T) {
|
func TestStoreStatsExpireCount(t *testing.T) {
|
||||||
s := newStore()
|
s := newStore()
|
||||||
fc := newFakeClock()
|
fc := newFakeClock()
|
||||||
|
@ -41,5 +41,4 @@
|
|||||||
// if err != nil {
|
// if err != nil {
|
||||||
// // handle error!
|
// // handle error!
|
||||||
// }
|
// }
|
||||||
//
|
|
||||||
package v3client
|
package v3client
|
||||||
|
@ -2,21 +2,23 @@
|
|||||||
// source: v3election.proto
|
// source: v3election.proto
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Package v3electionpb is a generated protocol buffer package.
|
Package v3electionpb is a generated protocol buffer package.
|
||||||
|
|
||||||
It is generated from these files:
|
It is generated from these files:
|
||||||
v3election.proto
|
|
||||||
|
|
||||||
It has these top-level messages:
|
v3election.proto
|
||||||
CampaignRequest
|
|
||||||
CampaignResponse
|
It has these top-level messages:
|
||||||
LeaderKey
|
|
||||||
LeaderRequest
|
CampaignRequest
|
||||||
LeaderResponse
|
CampaignResponse
|
||||||
ResignRequest
|
LeaderKey
|
||||||
ResignResponse
|
LeaderRequest
|
||||||
ProclaimRequest
|
LeaderResponse
|
||||||
ProclaimResponse
|
ResignRequest
|
||||||
|
ResignResponse
|
||||||
|
ProclaimRequest
|
||||||
|
ProclaimResponse
|
||||||
*/
|
*/
|
||||||
package v3electionpb
|
package v3electionpb
|
||||||
|
|
||||||
|
@ -2,16 +2,18 @@
|
|||||||
// source: v3lock.proto
|
// source: v3lock.proto
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Package v3lockpb is a generated protocol buffer package.
|
Package v3lockpb is a generated protocol buffer package.
|
||||||
|
|
||||||
It is generated from these files:
|
It is generated from these files:
|
||||||
v3lock.proto
|
|
||||||
|
|
||||||
It has these top-level messages:
|
v3lock.proto
|
||||||
LockRequest
|
|
||||||
LockResponse
|
It has these top-level messages:
|
||||||
UnlockRequest
|
|
||||||
UnlockResponse
|
LockRequest
|
||||||
|
LockResponse
|
||||||
|
UnlockRequest
|
||||||
|
UnlockResponse
|
||||||
*/
|
*/
|
||||||
package v3lockpb
|
package v3lockpb
|
||||||
|
|
||||||
|
@ -2,111 +2,113 @@
|
|||||||
// source: etcdserver.proto
|
// source: etcdserver.proto
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Package etcdserverpb is a generated protocol buffer package.
|
Package etcdserverpb is a generated protocol buffer package.
|
||||||
|
|
||||||
It is generated from these files:
|
It is generated from these files:
|
||||||
etcdserver.proto
|
|
||||||
raft_internal.proto
|
|
||||||
rpc.proto
|
|
||||||
|
|
||||||
It has these top-level messages:
|
etcdserver.proto
|
||||||
Request
|
raft_internal.proto
|
||||||
Metadata
|
rpc.proto
|
||||||
RequestHeader
|
|
||||||
InternalRaftRequest
|
It has these top-level messages:
|
||||||
EmptyResponse
|
|
||||||
InternalAuthenticateRequest
|
Request
|
||||||
ResponseHeader
|
Metadata
|
||||||
RangeRequest
|
RequestHeader
|
||||||
RangeResponse
|
InternalRaftRequest
|
||||||
PutRequest
|
EmptyResponse
|
||||||
PutResponse
|
InternalAuthenticateRequest
|
||||||
DeleteRangeRequest
|
ResponseHeader
|
||||||
DeleteRangeResponse
|
RangeRequest
|
||||||
RequestOp
|
RangeResponse
|
||||||
ResponseOp
|
PutRequest
|
||||||
Compare
|
PutResponse
|
||||||
TxnRequest
|
DeleteRangeRequest
|
||||||
TxnResponse
|
DeleteRangeResponse
|
||||||
CompactionRequest
|
RequestOp
|
||||||
CompactionResponse
|
ResponseOp
|
||||||
HashRequest
|
Compare
|
||||||
HashKVRequest
|
TxnRequest
|
||||||
HashKVResponse
|
TxnResponse
|
||||||
HashResponse
|
CompactionRequest
|
||||||
SnapshotRequest
|
CompactionResponse
|
||||||
SnapshotResponse
|
HashRequest
|
||||||
WatchRequest
|
HashKVRequest
|
||||||
WatchCreateRequest
|
HashKVResponse
|
||||||
WatchCancelRequest
|
HashResponse
|
||||||
WatchProgressRequest
|
SnapshotRequest
|
||||||
WatchResponse
|
SnapshotResponse
|
||||||
LeaseGrantRequest
|
WatchRequest
|
||||||
LeaseGrantResponse
|
WatchCreateRequest
|
||||||
LeaseRevokeRequest
|
WatchCancelRequest
|
||||||
LeaseRevokeResponse
|
WatchProgressRequest
|
||||||
LeaseCheckpoint
|
WatchResponse
|
||||||
LeaseCheckpointRequest
|
LeaseGrantRequest
|
||||||
LeaseCheckpointResponse
|
LeaseGrantResponse
|
||||||
LeaseKeepAliveRequest
|
LeaseRevokeRequest
|
||||||
LeaseKeepAliveResponse
|
LeaseRevokeResponse
|
||||||
LeaseTimeToLiveRequest
|
LeaseCheckpoint
|
||||||
LeaseTimeToLiveResponse
|
LeaseCheckpointRequest
|
||||||
LeaseLeasesRequest
|
LeaseCheckpointResponse
|
||||||
LeaseStatus
|
LeaseKeepAliveRequest
|
||||||
LeaseLeasesResponse
|
LeaseKeepAliveResponse
|
||||||
Member
|
LeaseTimeToLiveRequest
|
||||||
MemberAddRequest
|
LeaseTimeToLiveResponse
|
||||||
MemberAddResponse
|
LeaseLeasesRequest
|
||||||
MemberRemoveRequest
|
LeaseStatus
|
||||||
MemberRemoveResponse
|
LeaseLeasesResponse
|
||||||
MemberUpdateRequest
|
Member
|
||||||
MemberUpdateResponse
|
MemberAddRequest
|
||||||
MemberListRequest
|
MemberAddResponse
|
||||||
MemberListResponse
|
MemberRemoveRequest
|
||||||
MemberPromoteRequest
|
MemberRemoveResponse
|
||||||
MemberPromoteResponse
|
MemberUpdateRequest
|
||||||
DefragmentRequest
|
MemberUpdateResponse
|
||||||
DefragmentResponse
|
MemberListRequest
|
||||||
MoveLeaderRequest
|
MemberListResponse
|
||||||
MoveLeaderResponse
|
MemberPromoteRequest
|
||||||
AlarmRequest
|
MemberPromoteResponse
|
||||||
AlarmMember
|
DefragmentRequest
|
||||||
AlarmResponse
|
DefragmentResponse
|
||||||
StatusRequest
|
MoveLeaderRequest
|
||||||
StatusResponse
|
MoveLeaderResponse
|
||||||
AuthEnableRequest
|
AlarmRequest
|
||||||
AuthDisableRequest
|
AlarmMember
|
||||||
AuthenticateRequest
|
AlarmResponse
|
||||||
AuthUserAddRequest
|
StatusRequest
|
||||||
AuthUserGetRequest
|
StatusResponse
|
||||||
AuthUserDeleteRequest
|
AuthEnableRequest
|
||||||
AuthUserChangePasswordRequest
|
AuthDisableRequest
|
||||||
AuthUserGrantRoleRequest
|
AuthenticateRequest
|
||||||
AuthUserRevokeRoleRequest
|
AuthUserAddRequest
|
||||||
AuthRoleAddRequest
|
AuthUserGetRequest
|
||||||
AuthRoleGetRequest
|
AuthUserDeleteRequest
|
||||||
AuthUserListRequest
|
AuthUserChangePasswordRequest
|
||||||
AuthRoleListRequest
|
AuthUserGrantRoleRequest
|
||||||
AuthRoleDeleteRequest
|
AuthUserRevokeRoleRequest
|
||||||
AuthRoleGrantPermissionRequest
|
AuthRoleAddRequest
|
||||||
AuthRoleRevokePermissionRequest
|
AuthRoleGetRequest
|
||||||
AuthEnableResponse
|
AuthUserListRequest
|
||||||
AuthDisableResponse
|
AuthRoleListRequest
|
||||||
AuthenticateResponse
|
AuthRoleDeleteRequest
|
||||||
AuthUserAddResponse
|
AuthRoleGrantPermissionRequest
|
||||||
AuthUserGetResponse
|
AuthRoleRevokePermissionRequest
|
||||||
AuthUserDeleteResponse
|
AuthEnableResponse
|
||||||
AuthUserChangePasswordResponse
|
AuthDisableResponse
|
||||||
AuthUserGrantRoleResponse
|
AuthenticateResponse
|
||||||
AuthUserRevokeRoleResponse
|
AuthUserAddResponse
|
||||||
AuthRoleAddResponse
|
AuthUserGetResponse
|
||||||
AuthRoleGetResponse
|
AuthUserDeleteResponse
|
||||||
AuthRoleListResponse
|
AuthUserChangePasswordResponse
|
||||||
AuthUserListResponse
|
AuthUserGrantRoleResponse
|
||||||
AuthRoleDeleteResponse
|
AuthUserRevokeRoleResponse
|
||||||
AuthRoleGrantPermissionResponse
|
AuthRoleAddResponse
|
||||||
AuthRoleRevokePermissionResponse
|
AuthRoleGetResponse
|
||||||
|
AuthRoleListResponse
|
||||||
|
AuthUserListResponse
|
||||||
|
AuthRoleDeleteResponse
|
||||||
|
AuthRoleGrantPermissionResponse
|
||||||
|
AuthRoleRevokePermissionResponse
|
||||||
*/
|
*/
|
||||||
package etcdserverpb
|
package etcdserverpb
|
||||||
|
|
||||||
|
@ -364,8 +364,9 @@ func (r *raftNode) start(rh *raftReadyHandler) {
|
|||||||
// the applying workflow. But when the client receives the response,
|
// the applying workflow. But when the client receives the response,
|
||||||
// it doesn't mean etcd has already successfully saved the data,
|
// it doesn't mean etcd has already successfully saved the data,
|
||||||
// including BoltDB and WAL, because:
|
// including BoltDB and WAL, because:
|
||||||
// 1. etcd commits the boltDB transaction periodically instead of on each request;
|
// 1. etcd commits the boltDB transaction periodically instead of on each request;
|
||||||
// 2. etcd saves WAL entries in parallel with applying the committed entries.
|
// 2. etcd saves WAL entries in parallel with applying the committed entries.
|
||||||
|
//
|
||||||
// Accordingly, it might run into a situation of data loss when the etcd crashes
|
// Accordingly, it might run into a situation of data loss when the etcd crashes
|
||||||
// immediately after responding to the client and before the boltDB and WAL
|
// immediately after responding to the client and before the boltDB and WAL
|
||||||
// successfully save the data to disk.
|
// successfully save the data to disk.
|
||||||
|
@ -41,7 +41,8 @@ x and y of GCD 1 are coprime to each other
|
|||||||
x1 = ( coprime of n * idx1 + offset ) % n
|
x1 = ( coprime of n * idx1 + offset ) % n
|
||||||
x2 = ( coprime of n * idx2 + offset ) % n
|
x2 = ( coprime of n * idx2 + offset ) % n
|
||||||
(x2 - x1) = coprime of n * (idx2 - idx1) % n
|
(x2 - x1) = coprime of n * (idx2 - idx1) % n
|
||||||
= (idx2 - idx1) = 1
|
|
||||||
|
= (idx2 - idx1) = 1
|
||||||
|
|
||||||
Consecutive x's are guaranteed to be distinct
|
Consecutive x's are guaranteed to be distinct
|
||||||
*/
|
*/
|
||||||
|
@ -202,7 +202,6 @@ func TestElectionSessionRecampaign(t *testing.T) {
|
|||||||
// candidate can be elected on a new key that is a prefix
|
// candidate can be elected on a new key that is a prefix
|
||||||
// of an existing key. To wit, check for regression
|
// of an existing key. To wit, check for regression
|
||||||
// of bug #6278. https://github.com/etcd-io/etcd/issues/6278
|
// of bug #6278. https://github.com/etcd-io/etcd/issues/6278
|
||||||
//
|
|
||||||
func TestElectionOnPrefixOfExistingKey(t *testing.T) {
|
func TestElectionOnPrefixOfExistingKey(t *testing.T) {
|
||||||
clus := NewClusterV3(t, &ClusterConfig{Size: 1})
|
clus := NewClusterV3(t, &ClusterConfig{Size: 1})
|
||||||
defer clus.Terminate(t)
|
defer clus.Terminate(t)
|
||||||
|
@ -2,15 +2,17 @@
|
|||||||
// source: lease.proto
|
// source: lease.proto
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Package leasepb is a generated protocol buffer package.
|
Package leasepb is a generated protocol buffer package.
|
||||||
|
|
||||||
It is generated from these files:
|
It is generated from these files:
|
||||||
lease.proto
|
|
||||||
|
|
||||||
It has these top-level messages:
|
lease.proto
|
||||||
Lease
|
|
||||||
LeaseInternalRequest
|
It has these top-level messages:
|
||||||
LeaseInternalResponse
|
|
||||||
|
Lease
|
||||||
|
LeaseInternalRequest
|
||||||
|
LeaseInternalResponse
|
||||||
*/
|
*/
|
||||||
package leasepb
|
package leasepb
|
||||||
|
|
||||||
|
1
main.go
1
main.go
@ -19,7 +19,6 @@
|
|||||||
//
|
//
|
||||||
// This package should NOT be extended or modified in any way; to modify the
|
// This package should NOT be extended or modified in any way; to modify the
|
||||||
// etcd binary, work in the `go.etcd.io/etcd/etcdmain` package.
|
// etcd binary, work in the `go.etcd.io/etcd/etcdmain` package.
|
||||||
//
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "go.etcd.io/etcd/etcdmain"
|
import "go.etcd.io/etcd/etcdmain"
|
||||||
|
@ -39,9 +39,10 @@ var (
|
|||||||
// key: "foo"
|
// key: "foo"
|
||||||
// rev: 5
|
// rev: 5
|
||||||
// generations:
|
// generations:
|
||||||
// {empty}
|
//
|
||||||
// {4.0, 5.0(t)}
|
// {empty}
|
||||||
// {1.0, 2.0, 3.0(t)}
|
// {4.0, 5.0(t)}
|
||||||
|
// {1.0, 2.0, 3.0(t)}
|
||||||
//
|
//
|
||||||
// Compact a keyIndex removes the versions with smaller or equal to
|
// Compact a keyIndex removes the versions with smaller or equal to
|
||||||
// rev except the largest one. If the generation becomes empty
|
// rev except the largest one. If the generation becomes empty
|
||||||
@ -51,22 +52,26 @@ var (
|
|||||||
// For example:
|
// For example:
|
||||||
// compact(2) on the previous example
|
// compact(2) on the previous example
|
||||||
// generations:
|
// generations:
|
||||||
// {empty}
|
//
|
||||||
// {4.0, 5.0(t)}
|
// {empty}
|
||||||
// {2.0, 3.0(t)}
|
// {4.0, 5.0(t)}
|
||||||
|
// {2.0, 3.0(t)}
|
||||||
//
|
//
|
||||||
// compact(4)
|
// compact(4)
|
||||||
// generations:
|
// generations:
|
||||||
// {empty}
|
//
|
||||||
// {4.0, 5.0(t)}
|
// {empty}
|
||||||
|
// {4.0, 5.0(t)}
|
||||||
//
|
//
|
||||||
// compact(5):
|
// compact(5):
|
||||||
// generations:
|
// generations:
|
||||||
// {empty} -> key SHOULD be removed.
|
//
|
||||||
|
// {empty} -> key SHOULD be removed.
|
||||||
//
|
//
|
||||||
// compact(6):
|
// compact(6):
|
||||||
// generations:
|
// generations:
|
||||||
// {empty} -> key SHOULD be removed.
|
//
|
||||||
|
// {empty} -> key SHOULD be removed.
|
||||||
type keyIndex struct {
|
type keyIndex struct {
|
||||||
key []byte
|
key []byte
|
||||||
modified revision // the main rev of the last modification
|
modified revision // the main rev of the last modification
|
||||||
|
@ -2,14 +2,16 @@
|
|||||||
// source: kv.proto
|
// source: kv.proto
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Package mvccpb is a generated protocol buffer package.
|
Package mvccpb is a generated protocol buffer package.
|
||||||
|
|
||||||
It is generated from these files:
|
It is generated from these files:
|
||||||
kv.proto
|
|
||||||
|
|
||||||
It has these top-level messages:
|
kv.proto
|
||||||
KeyValue
|
|
||||||
Event
|
It has these top-level messages:
|
||||||
|
|
||||||
|
KeyValue
|
||||||
|
Event
|
||||||
*/
|
*/
|
||||||
package mvccpb
|
package mvccpb
|
||||||
|
|
||||||
|
@ -325,10 +325,10 @@ func (s *watchableStore) moveVictims() (moved int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// syncWatchers syncs unsynced watchers by:
|
// syncWatchers syncs unsynced watchers by:
|
||||||
// 1. choose a set of watchers from the unsynced watcher group
|
// 1. choose a set of watchers from the unsynced watcher group
|
||||||
// 2. iterate over the set to get the minimum revision and remove compacted watchers
|
// 2. iterate over the set to get the minimum revision and remove compacted watchers
|
||||||
// 3. use minimum revision to get all key-value pairs and send those events to watchers
|
// 3. use minimum revision to get all key-value pairs and send those events to watchers
|
||||||
// 4. remove synced watchers in set from unsynced group and move to synced group
|
// 4. remove synced watchers in set from unsynced group and move to synced group
|
||||||
func (s *watchableStore) syncWatchers() int {
|
func (s *watchableStore) syncWatchers() int {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
|
@ -341,11 +341,11 @@ func TestWatchRestore(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TestWatchRestoreSyncedWatcher tests such a case that:
|
// TestWatchRestoreSyncedWatcher tests such a case that:
|
||||||
// 1. watcher is created with a future revision "math.MaxInt64 - 2"
|
// 1. watcher is created with a future revision "math.MaxInt64 - 2"
|
||||||
// 2. watcher with a future revision is added to "synced" watcher group
|
// 2. watcher with a future revision is added to "synced" watcher group
|
||||||
// 3. restore/overwrite storage with snapshot of a higher lasat revision
|
// 3. restore/overwrite storage with snapshot of a higher lasat revision
|
||||||
// 4. restore operation moves "synced" to "unsynced" watcher group
|
// 4. restore operation moves "synced" to "unsynced" watcher group
|
||||||
// 5. choose the watcher from step 1, without panic
|
// 5. choose the watcher from step 1, without panic
|
||||||
func TestWatchRestoreSyncedWatcher(t *testing.T) {
|
func TestWatchRestoreSyncedWatcher(t *testing.T) {
|
||||||
b1, b1Path := backend.NewDefaultTmpBackend()
|
b1, b1Path := backend.NewDefaultTmpBackend()
|
||||||
s1 := newWatchableStore(zap.NewExample(), b1, &lease.FakeLessor{}, nil, nil, StoreConfig{})
|
s1 := newWatchableStore(zap.NewExample(), b1, &lease.FakeLessor{}, nil, nil, StoreConfig{})
|
||||||
|
@ -241,34 +241,34 @@ type intervalTree struct {
|
|||||||
//
|
//
|
||||||
// "Introduction to Algorithms" (Cormen et al, 3rd ed.), chapter 13.4, p324
|
// "Introduction to Algorithms" (Cormen et al, 3rd ed.), chapter 13.4, p324
|
||||||
//
|
//
|
||||||
// 0. RB-DELETE(T, z)
|
// RB-DELETE(T, z)
|
||||||
// 1.
|
//
|
||||||
// 2. y = z
|
// y = z
|
||||||
// 3. y-original-color = y.color
|
// y-original-color = y.color
|
||||||
// 4.
|
//
|
||||||
// 5. if z.left == T.nil
|
// if z.left == T.nil
|
||||||
// 6. x = z.right
|
// x = z.right
|
||||||
// 7. RB-TRANSPLANT(T, z, z.right)
|
// RB-TRANSPLANT(T, z, z.right)
|
||||||
// 8. else if z.right == T.nil
|
// else if z.right == T.nil
|
||||||
// 9. x = z.left
|
// x = z.left
|
||||||
// 10. RB-TRANSPLANT(T, z, z.left)
|
// RB-TRANSPLANT(T, z, z.left)
|
||||||
// 11. else
|
// else
|
||||||
// 12. y = TREE-MINIMUM(z.right)
|
// y = TREE-MINIMUM(z.right)
|
||||||
// 13. y-original-color = y.color
|
// y-original-color = y.color
|
||||||
// 14. x = y.right
|
// x = y.right
|
||||||
// 15. if y.p == z
|
// if y.p == z
|
||||||
// 16. x.p = y
|
// x.p = y
|
||||||
// 17. else
|
// else
|
||||||
// 18. RB-TRANSPLANT(T, y, y.right)
|
// RB-TRANSPLANT(T, y, y.right)
|
||||||
// 19. y.right = z.right
|
// y.right = z.right
|
||||||
// 20. y.right.p = y
|
// y.right.p = y
|
||||||
// 21. RB-TRANSPLANT(T, z, y)
|
// RB-TRANSPLANT(T, z, y)
|
||||||
// 22. y.left = z.left
|
// y.left = z.left
|
||||||
// 23. y.left.p = y
|
// y.left.p = y
|
||||||
// 24. y.color = z.color
|
// y.color = z.color
|
||||||
// 25.
|
//
|
||||||
// 26. if y-original-color == BLACK
|
// if y-original-color == BLACK
|
||||||
// 27. RB-DELETE-FIXUP(T, x)
|
// RB-DELETE-FIXUP(T, x)
|
||||||
|
|
||||||
// Delete removes the node with the given interval from the tree, returning
|
// Delete removes the node with the given interval from the tree, returning
|
||||||
// true if a node is in fact removed.
|
// true if a node is in fact removed.
|
||||||
@ -317,48 +317,47 @@ func (ivt *intervalTree) Delete(ivl Interval) bool {
|
|||||||
|
|
||||||
// "Introduction to Algorithms" (Cormen et al, 3rd ed.), chapter 13.4, p326
|
// "Introduction to Algorithms" (Cormen et al, 3rd ed.), chapter 13.4, p326
|
||||||
//
|
//
|
||||||
// 0. RB-DELETE-FIXUP(T, z)
|
// RB-DELETE-FIXUP(T, z)
|
||||||
// 1.
|
|
||||||
// 2. while x ≠ T.root and x.color == BLACK
|
|
||||||
// 3. if x == x.p.left
|
|
||||||
// 4. w = x.p.right
|
|
||||||
// 5. if w.color == RED
|
|
||||||
// 6. w.color = BLACK
|
|
||||||
// 7. x.p.color = RED
|
|
||||||
// 8. LEFT-ROTATE(T, x, p)
|
|
||||||
// 9. if w.left.color == BLACK and w.right.color == BLACK
|
|
||||||
// 10. w.color = RED
|
|
||||||
// 11. x = x.p
|
|
||||||
// 12. else if w.right.color == BLACK
|
|
||||||
// 13. w.left.color = BLACK
|
|
||||||
// 14. w.color = RED
|
|
||||||
// 15. RIGHT-ROTATE(T, w)
|
|
||||||
// 16. w = w.p.right
|
|
||||||
// 17. w.color = x.p.color
|
|
||||||
// 18. x.p.color = BLACK
|
|
||||||
// 19. LEFT-ROTATE(T, w.p)
|
|
||||||
// 20. x = T.root
|
|
||||||
// 21. else
|
|
||||||
// 22. w = x.p.left
|
|
||||||
// 23. if w.color == RED
|
|
||||||
// 24. w.color = BLACK
|
|
||||||
// 25. x.p.color = RED
|
|
||||||
// 26. RIGHT-ROTATE(T, x, p)
|
|
||||||
// 27. if w.right.color == BLACK and w.left.color == BLACK
|
|
||||||
// 28. w.color = RED
|
|
||||||
// 29. x = x.p
|
|
||||||
// 30. else if w.left.color == BLACK
|
|
||||||
// 31. w.right.color = BLACK
|
|
||||||
// 32. w.color = RED
|
|
||||||
// 33. LEFT-ROTATE(T, w)
|
|
||||||
// 34. w = w.p.left
|
|
||||||
// 35. w.color = x.p.color
|
|
||||||
// 36. x.p.color = BLACK
|
|
||||||
// 37. RIGHT-ROTATE(T, w.p)
|
|
||||||
// 38. x = T.root
|
|
||||||
// 39.
|
|
||||||
// 40. x.color = BLACK
|
|
||||||
//
|
//
|
||||||
|
// while x ≠ T.root and x.color == BLACK
|
||||||
|
// if x == x.p.left
|
||||||
|
// w = x.p.right
|
||||||
|
// if w.color == RED
|
||||||
|
// w.color = BLACK
|
||||||
|
// x.p.color = RED
|
||||||
|
// LEFT-ROTATE(T, x, p)
|
||||||
|
// if w.left.color == BLACK and w.right.color == BLACK
|
||||||
|
// w.color = RED
|
||||||
|
// x = x.p
|
||||||
|
// else if w.right.color == BLACK
|
||||||
|
// w.left.color = BLACK
|
||||||
|
// w.color = RED
|
||||||
|
// RIGHT-ROTATE(T, w)
|
||||||
|
// w = w.p.right
|
||||||
|
// w.color = x.p.color
|
||||||
|
// x.p.color = BLACK
|
||||||
|
// LEFT-ROTATE(T, w.p)
|
||||||
|
// x = T.root
|
||||||
|
// else
|
||||||
|
// w = x.p.left
|
||||||
|
// if w.color == RED
|
||||||
|
// w.color = BLACK
|
||||||
|
// x.p.color = RED
|
||||||
|
// RIGHT-ROTATE(T, x, p)
|
||||||
|
// if w.right.color == BLACK and w.left.color == BLACK
|
||||||
|
// w.color = RED
|
||||||
|
// x = x.p
|
||||||
|
// else if w.left.color == BLACK
|
||||||
|
// w.right.color = BLACK
|
||||||
|
// w.color = RED
|
||||||
|
// LEFT-ROTATE(T, w)
|
||||||
|
// w = w.p.left
|
||||||
|
// w.color = x.p.color
|
||||||
|
// x.p.color = BLACK
|
||||||
|
// RIGHT-ROTATE(T, w.p)
|
||||||
|
// x = T.root
|
||||||
|
//
|
||||||
|
// x.color = BLACK
|
||||||
func (ivt *intervalTree) deleteFixup(x *intervalNode) {
|
func (ivt *intervalTree) deleteFixup(x *intervalNode) {
|
||||||
for x != ivt.root && x.color(ivt.sentinel) == black {
|
for x != ivt.root && x.color(ivt.sentinel) == black {
|
||||||
if x == x.parent.left { // line 3-20
|
if x == x.parent.left { // line 3-20
|
||||||
@ -439,32 +438,32 @@ func (ivt *intervalTree) createIntervalNode(ivl Interval, val interface{}) *inte
|
|||||||
//
|
//
|
||||||
// "Introduction to Algorithms" (Cormen et al, 3rd ed.), chapter 13.3, p315
|
// "Introduction to Algorithms" (Cormen et al, 3rd ed.), chapter 13.3, p315
|
||||||
//
|
//
|
||||||
// 0. RB-INSERT(T, z)
|
// RB-INSERT(T, z)
|
||||||
// 1.
|
//
|
||||||
// 2. y = T.nil
|
// y = T.nil
|
||||||
// 3. x = T.root
|
// x = T.root
|
||||||
// 4.
|
//
|
||||||
// 5. while x ≠ T.nil
|
// while x ≠ T.nil
|
||||||
// 6. y = x
|
// y = x
|
||||||
// 7. if z.key < x.key
|
// if z.key < x.key
|
||||||
// 8. x = x.left
|
// x = x.left
|
||||||
// 9. else
|
// else
|
||||||
// 10. x = x.right
|
// x = x.right
|
||||||
// 11.
|
//
|
||||||
// 12. z.p = y
|
// z.p = y
|
||||||
// 13.
|
//
|
||||||
// 14. if y == T.nil
|
// if y == T.nil
|
||||||
// 15. T.root = z
|
// T.root = z
|
||||||
// 16. else if z.key < y.key
|
// else if z.key < y.key
|
||||||
// 17. y.left = z
|
// y.left = z
|
||||||
// 18. else
|
// else
|
||||||
// 19. y.right = z
|
// y.right = z
|
||||||
// 20.
|
//
|
||||||
// 21. z.left = T.nil
|
// z.left = T.nil
|
||||||
// 22. z.right = T.nil
|
// z.right = T.nil
|
||||||
// 23. z.color = RED
|
// z.color = RED
|
||||||
// 24.
|
//
|
||||||
// 25. RB-INSERT-FIXUP(T, z)
|
// RB-INSERT-FIXUP(T, z)
|
||||||
|
|
||||||
// Insert adds a node with the given interval into the tree.
|
// Insert adds a node with the given interval into the tree.
|
||||||
func (ivt *intervalTree) Insert(ivl Interval, val interface{}) {
|
func (ivt *intervalTree) Insert(ivl Interval, val interface{}) {
|
||||||
@ -499,38 +498,37 @@ func (ivt *intervalTree) Insert(ivl Interval, val interface{}) {
|
|||||||
|
|
||||||
// "Introduction to Algorithms" (Cormen et al, 3rd ed.), chapter 13.3, p316
|
// "Introduction to Algorithms" (Cormen et al, 3rd ed.), chapter 13.3, p316
|
||||||
//
|
//
|
||||||
// 0. RB-INSERT-FIXUP(T, z)
|
// RB-INSERT-FIXUP(T, z)
|
||||||
// 1.
|
|
||||||
// 2. while z.p.color == RED
|
|
||||||
// 3. if z.p == z.p.p.left
|
|
||||||
// 4. y = z.p.p.right
|
|
||||||
// 5. if y.color == RED
|
|
||||||
// 6. z.p.color = BLACK
|
|
||||||
// 7. y.color = BLACK
|
|
||||||
// 8. z.p.p.color = RED
|
|
||||||
// 9. z = z.p.p
|
|
||||||
// 10. else if z == z.p.right
|
|
||||||
// 11. z = z.p
|
|
||||||
// 12. LEFT-ROTATE(T, z)
|
|
||||||
// 13. z.p.color = BLACK
|
|
||||||
// 14. z.p.p.color = RED
|
|
||||||
// 15. RIGHT-ROTATE(T, z.p.p)
|
|
||||||
// 16. else
|
|
||||||
// 17. y = z.p.p.left
|
|
||||||
// 18. if y.color == RED
|
|
||||||
// 19. z.p.color = BLACK
|
|
||||||
// 20. y.color = BLACK
|
|
||||||
// 21. z.p.p.color = RED
|
|
||||||
// 22. z = z.p.p
|
|
||||||
// 23. else if z == z.p.right
|
|
||||||
// 24. z = z.p
|
|
||||||
// 25. RIGHT-ROTATE(T, z)
|
|
||||||
// 26. z.p.color = BLACK
|
|
||||||
// 27. z.p.p.color = RED
|
|
||||||
// 28. LEFT-ROTATE(T, z.p.p)
|
|
||||||
// 29.
|
|
||||||
// 30. T.root.color = BLACK
|
|
||||||
//
|
//
|
||||||
|
// while z.p.color == RED
|
||||||
|
// if z.p == z.p.p.left
|
||||||
|
// y = z.p.p.right
|
||||||
|
// if y.color == RED
|
||||||
|
// z.p.color = BLACK
|
||||||
|
// y.color = BLACK
|
||||||
|
// z.p.p.color = RED
|
||||||
|
// z = z.p.p
|
||||||
|
// else if z == z.p.right
|
||||||
|
// z = z.p
|
||||||
|
// LEFT-ROTATE(T, z)
|
||||||
|
// z.p.color = BLACK
|
||||||
|
// z.p.p.color = RED
|
||||||
|
// RIGHT-ROTATE(T, z.p.p)
|
||||||
|
// else
|
||||||
|
// y = z.p.p.left
|
||||||
|
// if y.color == RED
|
||||||
|
// z.p.color = BLACK
|
||||||
|
// y.color = BLACK
|
||||||
|
// z.p.p.color = RED
|
||||||
|
// z = z.p.p
|
||||||
|
// else if z == z.p.right
|
||||||
|
// z = z.p
|
||||||
|
// RIGHT-ROTATE(T, z)
|
||||||
|
// z.p.color = BLACK
|
||||||
|
// z.p.p.color = RED
|
||||||
|
// LEFT-ROTATE(T, z.p.p)
|
||||||
|
//
|
||||||
|
// T.root.color = BLACK
|
||||||
func (ivt *intervalTree) insertFixup(z *intervalNode) {
|
func (ivt *intervalTree) insertFixup(z *intervalNode) {
|
||||||
for z.parent.color(ivt.sentinel) == red {
|
for z.parent.color(ivt.sentinel) == red {
|
||||||
if z.parent == z.parent.parent.left { // line 3-15
|
if z.parent == z.parent.parent.left { // line 3-15
|
||||||
@ -578,26 +576,25 @@ func (ivt *intervalTree) insertFixup(z *intervalNode) {
|
|||||||
//
|
//
|
||||||
// "Introduction to Algorithms" (Cormen et al, 3rd ed.), chapter 13.2, p313
|
// "Introduction to Algorithms" (Cormen et al, 3rd ed.), chapter 13.2, p313
|
||||||
//
|
//
|
||||||
// 0. LEFT-ROTATE(T, x)
|
// LEFT-ROTATE(T, x)
|
||||||
// 1.
|
|
||||||
// 2. y = x.right
|
|
||||||
// 3. x.right = y.left
|
|
||||||
// 4.
|
|
||||||
// 5. if y.left ≠ T.nil
|
|
||||||
// 6. y.left.p = x
|
|
||||||
// 7.
|
|
||||||
// 8. y.p = x.p
|
|
||||||
// 9.
|
|
||||||
// 10. if x.p == T.nil
|
|
||||||
// 11. T.root = y
|
|
||||||
// 12. else if x == x.p.left
|
|
||||||
// 13. x.p.left = y
|
|
||||||
// 14. else
|
|
||||||
// 15. x.p.right = y
|
|
||||||
// 16.
|
|
||||||
// 17. y.left = x
|
|
||||||
// 18. x.p = y
|
|
||||||
//
|
//
|
||||||
|
// y = x.right
|
||||||
|
// x.right = y.left
|
||||||
|
//
|
||||||
|
// if y.left ≠ T.nil
|
||||||
|
// y.left.p = x
|
||||||
|
//
|
||||||
|
// y.p = x.p
|
||||||
|
//
|
||||||
|
// if x.p == T.nil
|
||||||
|
// T.root = y
|
||||||
|
// else if x == x.p.left
|
||||||
|
// x.p.left = y
|
||||||
|
// else
|
||||||
|
// x.p.right = y
|
||||||
|
//
|
||||||
|
// y.left = x
|
||||||
|
// x.p = y
|
||||||
func (ivt *intervalTree) rotateLeft(x *intervalNode) {
|
func (ivt *intervalTree) rotateLeft(x *intervalNode) {
|
||||||
// rotateLeft x must have right child
|
// rotateLeft x must have right child
|
||||||
if x.right == ivt.sentinel {
|
if x.right == ivt.sentinel {
|
||||||
@ -624,26 +621,25 @@ func (ivt *intervalTree) rotateLeft(x *intervalNode) {
|
|||||||
|
|
||||||
// rotateRight moves x so it is right of its left child
|
// rotateRight moves x so it is right of its left child
|
||||||
//
|
//
|
||||||
// 0. RIGHT-ROTATE(T, x)
|
// RIGHT-ROTATE(T, x)
|
||||||
// 1.
|
|
||||||
// 2. y = x.left
|
|
||||||
// 3. x.left = y.right
|
|
||||||
// 4.
|
|
||||||
// 5. if y.right ≠ T.nil
|
|
||||||
// 6. y.right.p = x
|
|
||||||
// 7.
|
|
||||||
// 8. y.p = x.p
|
|
||||||
// 9.
|
|
||||||
// 10. if x.p == T.nil
|
|
||||||
// 11. T.root = y
|
|
||||||
// 12. else if x == x.p.right
|
|
||||||
// 13. x.p.right = y
|
|
||||||
// 14. else
|
|
||||||
// 15. x.p.left = y
|
|
||||||
// 16.
|
|
||||||
// 17. y.right = x
|
|
||||||
// 18. x.p = y
|
|
||||||
//
|
//
|
||||||
|
// y = x.left
|
||||||
|
// x.left = y.right
|
||||||
|
//
|
||||||
|
// if y.right ≠ T.nil
|
||||||
|
// y.right.p = x
|
||||||
|
//
|
||||||
|
// y.p = x.p
|
||||||
|
//
|
||||||
|
// if x.p == T.nil
|
||||||
|
// T.root = y
|
||||||
|
// else if x == x.p.right
|
||||||
|
// x.p.right = y
|
||||||
|
// else
|
||||||
|
// x.p.left = y
|
||||||
|
//
|
||||||
|
// y.right = x
|
||||||
|
// x.p = y
|
||||||
func (ivt *intervalTree) rotateRight(x *intervalNode) {
|
func (ivt *intervalTree) rotateRight(x *intervalNode) {
|
||||||
// rotateRight x must have left child
|
// rotateRight x must have left child
|
||||||
if x.left == ivt.sentinel {
|
if x.left == ivt.sentinel {
|
||||||
|
@ -63,27 +63,28 @@ func TestIntervalTreeInsert(t *testing.T) {
|
|||||||
// Use https://www.cs.usfca.edu/~galles/visualization/RedBlack.html for test case creation.
|
// Use https://www.cs.usfca.edu/~galles/visualization/RedBlack.html for test case creation.
|
||||||
//
|
//
|
||||||
// Regular Binary Search Tree
|
// Regular Binary Search Tree
|
||||||
// [0,1]
|
//
|
||||||
// \
|
// [0,1]
|
||||||
// [1,2]
|
// \
|
||||||
// \
|
// [1,2]
|
||||||
// [3,4]
|
// \
|
||||||
// \
|
// [3,4]
|
||||||
// [5,6]
|
// \
|
||||||
// \
|
// [5,6]
|
||||||
// [7,8]
|
// \
|
||||||
// \
|
// [7,8]
|
||||||
// [8,9]
|
// \
|
||||||
|
// [8,9]
|
||||||
//
|
//
|
||||||
// Self-Balancing Binary Search Tree
|
// Self-Balancing Binary Search Tree
|
||||||
// [1,2]
|
|
||||||
// / \
|
|
||||||
// [0,1] [5,6]
|
|
||||||
// / \
|
|
||||||
// [3,4] [7,8]
|
|
||||||
// \
|
|
||||||
// [8,9]
|
|
||||||
//
|
//
|
||||||
|
// [1,2]
|
||||||
|
// / \
|
||||||
|
// [0,1] [5,6]
|
||||||
|
// / \
|
||||||
|
// [3,4] [7,8]
|
||||||
|
// \
|
||||||
|
// [8,9]
|
||||||
func TestIntervalTreeSelfBalanced(t *testing.T) {
|
func TestIntervalTreeSelfBalanced(t *testing.T) {
|
||||||
ivt := NewIntervalTree()
|
ivt := NewIntervalTree()
|
||||||
ivt.Insert(NewInt64Interval(0, 1), 0)
|
ivt.Insert(NewInt64Interval(0, 1), 0)
|
||||||
@ -120,58 +121,56 @@ func TestIntervalTreeSelfBalanced(t *testing.T) {
|
|||||||
// Use https://www.cs.usfca.edu/~galles/visualization/RedBlack.html for test case creation.
|
// Use https://www.cs.usfca.edu/~galles/visualization/RedBlack.html for test case creation.
|
||||||
// See https://github.com/etcd-io/etcd/issues/10877 for more detail.
|
// See https://github.com/etcd-io/etcd/issues/10877 for more detail.
|
||||||
//
|
//
|
||||||
//
|
|
||||||
// After insertion:
|
// After insertion:
|
||||||
// [510,511]
|
|
||||||
// / \
|
|
||||||
// ---------- -----------------------
|
|
||||||
// / \
|
|
||||||
// [82,83] [830,831]
|
|
||||||
// / \ / \
|
|
||||||
// / \ / \
|
|
||||||
// [11,12] [383,384](red) [647,648] [899,900](red)
|
|
||||||
// / \ / \ / \
|
|
||||||
// / \ / \ / \
|
|
||||||
// [261,262] [410,411] [514,515](red) [815,816](red) [888,889] [972,973]
|
|
||||||
// / \ /
|
|
||||||
// / \ /
|
|
||||||
// [238,239](red) [292,293](red) [953,954](red)
|
|
||||||
//
|
//
|
||||||
|
// [510,511]
|
||||||
|
// / \
|
||||||
|
// ---------- -----------------------
|
||||||
|
// / \
|
||||||
|
// [82,83] [830,831]
|
||||||
|
// / \ / \
|
||||||
|
// / \ / \
|
||||||
|
// [11,12] [383,384](red) [647,648] [899,900](red)
|
||||||
|
// / \ / \ / \
|
||||||
|
// / \ / \ / \
|
||||||
|
// [261,262] [410,411] [514,515](red) [815,816](red) [888,889] [972,973]
|
||||||
|
// / \ /
|
||||||
|
// / \ /
|
||||||
|
// [238,239](red) [292,293](red) [953,954](red)
|
||||||
//
|
//
|
||||||
// After deleting 514 (no rebalance):
|
// After deleting 514 (no rebalance):
|
||||||
// [510,511]
|
|
||||||
// / \
|
|
||||||
// ---------- -----------------------
|
|
||||||
// / \
|
|
||||||
// [82,83] [830,831]
|
|
||||||
// / \ / \
|
|
||||||
// / \ / \
|
|
||||||
// [11,12] [383,384](red) [647,648] [899,900](red)
|
|
||||||
// / \ \ / \
|
|
||||||
// / \ \ / \
|
|
||||||
// [261,262] [410,411] [815,816](red) [888,889] [972,973]
|
|
||||||
// / \ /
|
|
||||||
// / \ /
|
|
||||||
// [238,239](red) [292,293](red) [953,954](red)
|
|
||||||
//
|
//
|
||||||
|
// [510,511]
|
||||||
|
// / \
|
||||||
|
// ---------- -----------------------
|
||||||
|
// / \
|
||||||
|
// [82,83] [830,831]
|
||||||
|
// / \ / \
|
||||||
|
// / \ / \
|
||||||
|
// [11,12] [383,384](red) [647,648] [899,900](red)
|
||||||
|
// / \ \ / \
|
||||||
|
// / \ \ / \
|
||||||
|
// [261,262] [410,411] [815,816](red) [888,889] [972,973]
|
||||||
|
// / \ /
|
||||||
|
// / \ /
|
||||||
|
// [238,239](red) [292,293](red) [953,954](red)
|
||||||
//
|
//
|
||||||
// After deleting 11 (requires rebalancing):
|
// After deleting 11 (requires rebalancing):
|
||||||
// [510,511]
|
|
||||||
// / \
|
|
||||||
// ---------- --------------------------
|
|
||||||
// / \
|
|
||||||
// [383,384] [830,831]
|
|
||||||
// / \ / \
|
|
||||||
// / \ / \
|
|
||||||
// [261,262](red) [410,411] [647,648] [899,900](red)
|
|
||||||
// / \ \ / \
|
|
||||||
// / \ \ / \
|
|
||||||
// [82,83] [292,293] [815,816](red) [888,889] [972,973]
|
|
||||||
// \ /
|
|
||||||
// \ /
|
|
||||||
// [238,239](red) [953,954](red)
|
|
||||||
//
|
|
||||||
//
|
//
|
||||||
|
// [510,511]
|
||||||
|
// / \
|
||||||
|
// ---------- --------------------------
|
||||||
|
// / \
|
||||||
|
// [383,384] [830,831]
|
||||||
|
// / \ / \
|
||||||
|
// / \ / \
|
||||||
|
// [261,262](red) [410,411] [647,648] [899,900](red)
|
||||||
|
// / \ \ / \
|
||||||
|
// / \ \ / \
|
||||||
|
// [82,83] [292,293] [815,816](red) [888,889] [972,973]
|
||||||
|
// \ /
|
||||||
|
// \ /
|
||||||
|
// [238,239](red) [953,954](red)
|
||||||
func TestIntervalTreeDelete(t *testing.T) {
|
func TestIntervalTreeDelete(t *testing.T) {
|
||||||
ivt := NewIntervalTree()
|
ivt := NewIntervalTree()
|
||||||
ivt.Insert(NewInt64Interval(510, 511), 0)
|
ivt.Insert(NewInt64Interval(510, 511), 0)
|
||||||
|
@ -33,10 +33,9 @@ var _ Logger = &defaultLogger{}
|
|||||||
//
|
//
|
||||||
// For example:
|
// For example:
|
||||||
//
|
//
|
||||||
// var defaultLogger Logger
|
// var defaultLogger Logger
|
||||||
// g := grpclog.NewLoggerV2WithVerbosity(os.Stderr, os.Stderr, os.Stderr, 4)
|
// g := grpclog.NewLoggerV2WithVerbosity(os.Stderr, os.Stderr, os.Stderr, 4)
|
||||||
// defaultLogger = NewLogger(g)
|
// defaultLogger = NewLogger(g)
|
||||||
//
|
|
||||||
func NewLogger(g grpclog.LoggerV2) Logger { return &defaultLogger{g: g} }
|
func NewLogger(g grpclog.LoggerV2) Logger { return &defaultLogger{g: g} }
|
||||||
|
|
||||||
type defaultLogger struct {
|
type defaultLogger struct {
|
||||||
|
@ -26,9 +26,8 @@ var _ Logger = &packageLogger{}
|
|||||||
//
|
//
|
||||||
// For example:
|
// For example:
|
||||||
//
|
//
|
||||||
// var defaultLogger Logger
|
// var defaultLogger Logger
|
||||||
// defaultLogger = NewPackageLogger("go.etcd.io/etcd", "snapshot")
|
// defaultLogger = NewPackageLogger("go.etcd.io/etcd", "snapshot")
|
||||||
//
|
|
||||||
func NewPackageLogger(repo, pkg string) Logger {
|
func NewPackageLogger(repo, pkg string) Logger {
|
||||||
return &packageLogger{p: capnslog.NewPackageLogger(repo, pkg)}
|
return &packageLogger{p: capnslog.NewPackageLogger(repo, pkg)}
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,6 @@ running(leaking) after all tests.
|
|||||||
defer testutil.AfterTest(t)
|
defer testutil.AfterTest(t)
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
*/
|
||||||
func CheckLeakedGoroutine() bool {
|
func CheckLeakedGoroutine() bool {
|
||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
|
@ -235,8 +235,8 @@ func SelfCert(lg *zap.Logger, dirpath string, hosts []string, additionalUsages .
|
|||||||
// Previously,
|
// Previously,
|
||||||
// 1. Server has non-empty (*tls.Config).Certificates on client hello
|
// 1. Server has non-empty (*tls.Config).Certificates on client hello
|
||||||
// 2. Server calls (*tls.Config).GetCertificate iff:
|
// 2. Server calls (*tls.Config).GetCertificate iff:
|
||||||
// - Server's (*tls.Config).Certificates is not empty, or
|
// - Server's (*tls.Config).Certificates is not empty, or
|
||||||
// - Client supplies SNI; non-empty (*tls.ClientHelloInfo).ServerName
|
// - Client supplies SNI; non-empty (*tls.ClientHelloInfo).ServerName
|
||||||
//
|
//
|
||||||
// When (*tls.Config).Certificates is always populated on initial handshake,
|
// When (*tls.Config).Certificates is always populated on initial handshake,
|
||||||
// client is expected to provide a valid matching SNI to pass the TLS
|
// client is expected to provide a valid matching SNI to pass the TLS
|
||||||
|
@ -37,9 +37,11 @@ type Changer struct {
|
|||||||
// config is empty and initializes it with a copy of the incoming (=left)
|
// config is empty and initializes it with a copy of the incoming (=left)
|
||||||
// majority config. That is, it transitions from
|
// majority config. That is, it transitions from
|
||||||
//
|
//
|
||||||
// (1 2 3)&&()
|
// (1 2 3)&&()
|
||||||
|
//
|
||||||
// to
|
// to
|
||||||
// (1 2 3)&&(1 2 3).
|
//
|
||||||
|
// (1 2 3)&&(1 2 3).
|
||||||
//
|
//
|
||||||
// The supplied changes are then applied to the incoming majority config,
|
// The supplied changes are then applied to the incoming majority config,
|
||||||
// resulting in a joint configuration that in terms of the Raft thesis[1]
|
// resulting in a joint configuration that in terms of the Raft thesis[1]
|
||||||
|
107
raft/doc.go
107
raft/doc.go
@ -25,46 +25,46 @@ A simple example application, _raftexample_, is also available to help illustrat
|
|||||||
how to use this package in practice:
|
how to use this package in practice:
|
||||||
https://github.com/etcd-io/etcd/tree/master/contrib/raftexample
|
https://github.com/etcd-io/etcd/tree/master/contrib/raftexample
|
||||||
|
|
||||||
Usage
|
# Usage
|
||||||
|
|
||||||
The primary object in raft is a Node. You either start a Node from scratch
|
The primary object in raft is a Node. You either start a Node from scratch
|
||||||
using raft.StartNode or start a Node from some initial state using raft.RestartNode.
|
using raft.StartNode or start a Node from some initial state using raft.RestartNode.
|
||||||
|
|
||||||
To start a node from scratch:
|
To start a node from scratch:
|
||||||
|
|
||||||
storage := raft.NewMemoryStorage()
|
storage := raft.NewMemoryStorage()
|
||||||
c := &Config{
|
c := &Config{
|
||||||
ID: 0x01,
|
ID: 0x01,
|
||||||
ElectionTick: 10,
|
ElectionTick: 10,
|
||||||
HeartbeatTick: 1,
|
HeartbeatTick: 1,
|
||||||
Storage: storage,
|
Storage: storage,
|
||||||
MaxSizePerMsg: 4096,
|
MaxSizePerMsg: 4096,
|
||||||
MaxInflightMsgs: 256,
|
MaxInflightMsgs: 256,
|
||||||
}
|
}
|
||||||
n := raft.StartNode(c, []raft.Peer{{ID: 0x02}, {ID: 0x03}})
|
n := raft.StartNode(c, []raft.Peer{{ID: 0x02}, {ID: 0x03}})
|
||||||
|
|
||||||
To restart a node from previous state:
|
To restart a node from previous state:
|
||||||
|
|
||||||
storage := raft.NewMemoryStorage()
|
storage := raft.NewMemoryStorage()
|
||||||
|
|
||||||
// recover the in-memory storage from persistent
|
// recover the in-memory storage from persistent
|
||||||
// snapshot, state and entries.
|
// snapshot, state and entries.
|
||||||
storage.ApplySnapshot(snapshot)
|
storage.ApplySnapshot(snapshot)
|
||||||
storage.SetHardState(state)
|
storage.SetHardState(state)
|
||||||
storage.Append(entries)
|
storage.Append(entries)
|
||||||
|
|
||||||
c := &Config{
|
c := &Config{
|
||||||
ID: 0x01,
|
ID: 0x01,
|
||||||
ElectionTick: 10,
|
ElectionTick: 10,
|
||||||
HeartbeatTick: 1,
|
HeartbeatTick: 1,
|
||||||
Storage: storage,
|
Storage: storage,
|
||||||
MaxSizePerMsg: 4096,
|
MaxSizePerMsg: 4096,
|
||||||
MaxInflightMsgs: 256,
|
MaxInflightMsgs: 256,
|
||||||
}
|
}
|
||||||
|
|
||||||
// restart raft without peer information.
|
// restart raft without peer information.
|
||||||
// peer information is already included in the storage.
|
// peer information is already included in the storage.
|
||||||
n := raft.RestartNode(c)
|
n := raft.RestartNode(c)
|
||||||
|
|
||||||
Now that you are holding onto a Node you have a few responsibilities:
|
Now that you are holding onto a Node you have a few responsibilities:
|
||||||
|
|
||||||
@ -120,29 +120,29 @@ represented by an abstract "tick".
|
|||||||
|
|
||||||
The total state machine handling loop will look something like this:
|
The total state machine handling loop will look something like this:
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-s.Ticker:
|
case <-s.Ticker:
|
||||||
n.Tick()
|
n.Tick()
|
||||||
case rd := <-s.Node.Ready():
|
case rd := <-s.Node.Ready():
|
||||||
saveToStorage(rd.State, rd.Entries, rd.Snapshot)
|
saveToStorage(rd.State, rd.Entries, rd.Snapshot)
|
||||||
send(rd.Messages)
|
send(rd.Messages)
|
||||||
if !raft.IsEmptySnap(rd.Snapshot) {
|
if !raft.IsEmptySnap(rd.Snapshot) {
|
||||||
processSnapshot(rd.Snapshot)
|
processSnapshot(rd.Snapshot)
|
||||||
}
|
}
|
||||||
for _, entry := range rd.CommittedEntries {
|
for _, entry := range rd.CommittedEntries {
|
||||||
process(entry)
|
process(entry)
|
||||||
if entry.Type == raftpb.EntryConfChange {
|
if entry.Type == raftpb.EntryConfChange {
|
||||||
var cc raftpb.ConfChange
|
var cc raftpb.ConfChange
|
||||||
cc.Unmarshal(entry.Data)
|
cc.Unmarshal(entry.Data)
|
||||||
s.Node.ApplyConfChange(cc)
|
s.Node.ApplyConfChange(cc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.Node.Advance()
|
s.Node.Advance()
|
||||||
case <-s.done:
|
case <-s.done:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
To propose changes to the state machine from your node take your application
|
To propose changes to the state machine from your node take your application
|
||||||
data, serialize it into a byte slice and call:
|
data, serialize it into a byte slice and call:
|
||||||
@ -169,7 +169,7 @@ given ID MUST be used only once even if the old node has been removed.
|
|||||||
This means that for example IP addresses make poor node IDs since they
|
This means that for example IP addresses make poor node IDs since they
|
||||||
may be reused. Node IDs must be non-zero.
|
may be reused. Node IDs must be non-zero.
|
||||||
|
|
||||||
Implementation notes
|
# Implementation notes
|
||||||
|
|
||||||
This implementation is up to date with the final Raft thesis
|
This implementation is up to date with the final Raft thesis
|
||||||
(https://github.com/ongardie/dissertation/blob/master/stanford.pdf), although our
|
(https://github.com/ongardie/dissertation/blob/master/stanford.pdf), although our
|
||||||
@ -194,7 +194,7 @@ cannot be removed any more since the cluster cannot make progress.
|
|||||||
For this reason it is highly recommended to use three or more nodes in
|
For this reason it is highly recommended to use three or more nodes in
|
||||||
every cluster.
|
every cluster.
|
||||||
|
|
||||||
MessageType
|
# MessageType
|
||||||
|
|
||||||
Package raft sends and receives message in Protocol Buffer format (defined
|
Package raft sends and receives message in Protocol Buffer format (defined
|
||||||
in raftpb package). Each state (follower, candidate, leader) implements its
|
in raftpb package). Each state (follower, candidate, leader) implements its
|
||||||
@ -295,6 +295,5 @@ stale log entries:
|
|||||||
that the follower that sent this 'MsgUnreachable' is not reachable, often
|
that the follower that sent this 'MsgUnreachable' is not reachable, often
|
||||||
indicating 'MsgApp' is lost. When follower's progress state is replicate,
|
indicating 'MsgApp' is lost. When follower's progress state is replicate,
|
||||||
the leader sets it back to probe.
|
the leader sets it back to probe.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
package raft
|
package raft
|
||||||
|
@ -146,12 +146,14 @@ func TestAppend(t *testing.T) {
|
|||||||
|
|
||||||
// TestLogMaybeAppend ensures:
|
// TestLogMaybeAppend ensures:
|
||||||
// If the given (index, term) matches with the existing log:
|
// If the given (index, term) matches with the existing log:
|
||||||
// 1. If an existing entry conflicts with a new one (same index
|
// 1. If an existing entry conflicts with a new one (same index
|
||||||
// but different terms), delete the existing entry and all that
|
// but different terms), delete the existing entry and all that
|
||||||
// follow it
|
// follow it
|
||||||
// 2.Append any new entries not already in the log
|
// 2.Append any new entries not already in the log
|
||||||
|
//
|
||||||
// If the given (index, term) does not match with the existing log:
|
// If the given (index, term) does not match with the existing log:
|
||||||
// return false
|
//
|
||||||
|
// return false
|
||||||
func TestLogMaybeAppend(t *testing.T) {
|
func TestLogMaybeAppend(t *testing.T) {
|
||||||
previousEnts := []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}, {Index: 3, Term: 3}}
|
previousEnts := []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}, {Index: 3, Term: 3}}
|
||||||
lastindex := uint64(3)
|
lastindex := uint64(3)
|
||||||
@ -528,7 +530,7 @@ func TestStableToWithSnap(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TestCompaction ensures that the number of log entries is correct after compactions.
|
// TestCompaction ensures that the number of log entries is correct after compactions.
|
||||||
func TestCompaction(t *testing.T) {
|
func TestCompaction(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
lastIndex uint64
|
lastIndex uint64
|
||||||
|
@ -958,14 +958,14 @@ func (s *ignoreSizeHintMemStorage) Entries(lo, hi uint64, maxSize uint64) ([]raf
|
|||||||
// Storage's Entries size limitation is slightly more permissive than Raft's
|
// Storage's Entries size limitation is slightly more permissive than Raft's
|
||||||
// internal one. The original bug was the following:
|
// internal one. The original bug was the following:
|
||||||
//
|
//
|
||||||
// - node learns that index 11 (or 100, doesn't matter) is committed
|
// - node learns that index 11 (or 100, doesn't matter) is committed
|
||||||
// - nextEnts returns index 1..10 in CommittedEntries due to size limiting. However,
|
// - nextEnts returns index 1..10 in CommittedEntries due to size limiting. However,
|
||||||
// index 10 already exceeds maxBytes, due to a user-provided impl of Entries.
|
// index 10 already exceeds maxBytes, due to a user-provided impl of Entries.
|
||||||
// - Commit index gets bumped to 10
|
// - Commit index gets bumped to 10
|
||||||
// - the node persists the HardState, but crashes before applying the entries
|
// - the node persists the HardState, but crashes before applying the entries
|
||||||
// - upon restart, the storage returns the same entries, but `slice` takes a different code path
|
// - upon restart, the storage returns the same entries, but `slice` takes a different code path
|
||||||
// (since it is now called with an upper bound of 10) and removes the last entry.
|
// (since it is now called with an upper bound of 10) and removes the last entry.
|
||||||
// - Raft emits a HardState with a regressing commit index.
|
// - Raft emits a HardState with a regressing commit index.
|
||||||
//
|
//
|
||||||
// A simpler version of this test would have the storage return a lot less entries than dictated
|
// A simpler version of this test would have the storage return a lot less entries than dictated
|
||||||
// by maxSize (for example, exactly one entry) after the restart, resulting in a larger regression.
|
// by maxSize (for example, exactly one entry) after the restart, resulting in a larger regression.
|
||||||
|
@ -1212,10 +1212,10 @@ func TestStepIgnoreOldTermMsg(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TestHandleMsgApp ensures:
|
// TestHandleMsgApp ensures:
|
||||||
// 1. Reply false if log doesn’t contain an entry at prevLogIndex whose term matches prevLogTerm.
|
// 1. Reply false if log doesn’t contain an entry at prevLogIndex whose term matches prevLogTerm.
|
||||||
// 2. If an existing entry conflicts with a new one (same index but different terms),
|
// 2. If an existing entry conflicts with a new one (same index but different terms),
|
||||||
// delete the existing entry and all that follow it; append any new entries not already in the log.
|
// delete the existing entry and all that follow it; append any new entries not already in the log.
|
||||||
// 3. If leaderCommit > commitIndex, set commitIndex = min(leaderCommit, index of last new entry).
|
// 3. If leaderCommit > commitIndex, set commitIndex = min(leaderCommit, index of last new entry).
|
||||||
func TestHandleMsgApp(t *testing.T) {
|
func TestHandleMsgApp(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
m pb.Message
|
m pb.Message
|
||||||
|
@ -2,21 +2,23 @@
|
|||||||
// source: raft.proto
|
// source: raft.proto
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Package raftpb is a generated protocol buffer package.
|
Package raftpb is a generated protocol buffer package.
|
||||||
|
|
||||||
It is generated from these files:
|
It is generated from these files:
|
||||||
raft.proto
|
|
||||||
|
|
||||||
It has these top-level messages:
|
raft.proto
|
||||||
Entry
|
|
||||||
SnapshotMetadata
|
It has these top-level messages:
|
||||||
Snapshot
|
|
||||||
Message
|
Entry
|
||||||
HardState
|
SnapshotMetadata
|
||||||
ConfState
|
Snapshot
|
||||||
ConfChange
|
Message
|
||||||
ConfChangeSingle
|
HardState
|
||||||
ConfChangeV2
|
ConfState
|
||||||
|
ConfChange
|
||||||
|
ConfChangeSingle
|
||||||
|
ConfChangeV2
|
||||||
*/
|
*/
|
||||||
package raftpb
|
package raftpb
|
||||||
|
|
||||||
|
@ -723,17 +723,17 @@ func TestRawNodeStatus(t *testing.T) {
|
|||||||
// TestNodeCommitPaginationAfterRestart. The anomaly here was even worse as the
|
// TestNodeCommitPaginationAfterRestart. The anomaly here was even worse as the
|
||||||
// Raft group would forget to apply entries:
|
// Raft group would forget to apply entries:
|
||||||
//
|
//
|
||||||
// - node learns that index 11 is committed
|
// - node learns that index 11 is committed
|
||||||
// - nextEnts returns index 1..10 in CommittedEntries (but index 10 already
|
// - nextEnts returns index 1..10 in CommittedEntries (but index 10 already
|
||||||
// exceeds maxBytes), which isn't noticed internally by Raft
|
// exceeds maxBytes), which isn't noticed internally by Raft
|
||||||
// - Commit index gets bumped to 10
|
// - Commit index gets bumped to 10
|
||||||
// - the node persists the HardState, but crashes before applying the entries
|
// - the node persists the HardState, but crashes before applying the entries
|
||||||
// - upon restart, the storage returns the same entries, but `slice` takes a
|
// - upon restart, the storage returns the same entries, but `slice` takes a
|
||||||
// different code path and removes the last entry.
|
// different code path and removes the last entry.
|
||||||
// - Raft does not emit a HardState, but when the app calls Advance(), it bumps
|
// - Raft does not emit a HardState, but when the app calls Advance(), it bumps
|
||||||
// its internal applied index cursor to 10 (when it should be 9)
|
// its internal applied index cursor to 10 (when it should be 9)
|
||||||
// - the next Ready asks the app to apply index 11 (omitting index 10), losing a
|
// - the next Ready asks the app to apply index 11 (omitting index 10), losing a
|
||||||
// write.
|
// write.
|
||||||
func TestRawNodeCommitPaginationAfterRestart(t *testing.T) {
|
func TestRawNodeCommitPaginationAfterRestart(t *testing.T) {
|
||||||
s := &ignoreSizeHintMemStorage{
|
s := &ignoreSizeHintMemStorage{
|
||||||
MemoryStorage: NewMemoryStorage(),
|
MemoryStorage: NewMemoryStorage(),
|
||||||
|
@ -300,7 +300,7 @@ IRRCompaction, IRRLeaseGrant, IRRLeaseRevoke, IRRLeaseCheckpoint`, et)
|
|||||||
return filters
|
return filters
|
||||||
}
|
}
|
||||||
|
|
||||||
// listEntriesType filters and prints entries based on the entry-type flag,
|
// listEntriesType filters and prints entries based on the entry-type flag,
|
||||||
func listEntriesType(entrytype string, streamdecoder string, ents []raftpb.Entry) {
|
func listEntriesType(entrytype string, streamdecoder string, ents []raftpb.Entry) {
|
||||||
entryFilters := evaluateEntrytypeFlag(entrytype)
|
entryFilters := evaluateEntrytypeFlag(entrytype)
|
||||||
printerMap := map[string]EntryPrinter{"InternalRaftRequest": printInternalRaftRequest,
|
printerMap := map[string]EntryPrinter{"InternalRaftRequest": printInternalRaftRequest,
|
||||||
|
@ -70,6 +70,5 @@ snapshot to the end of the WAL are read first:
|
|||||||
|
|
||||||
This will give you the metadata, the last raft.State and the slice of
|
This will give you the metadata, the last raft.State and the slice of
|
||||||
raft.Entry items in the log.
|
raft.Entry items in the log.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
package wal
|
package wal
|
||||||
|
@ -2,14 +2,16 @@
|
|||||||
// source: record.proto
|
// source: record.proto
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Package walpb is a generated protocol buffer package.
|
Package walpb is a generated protocol buffer package.
|
||||||
|
|
||||||
It is generated from these files:
|
It is generated from these files:
|
||||||
record.proto
|
|
||||||
|
|
||||||
It has these top-level messages:
|
record.proto
|
||||||
Record
|
|
||||||
Snapshot
|
It has these top-level messages:
|
||||||
|
|
||||||
|
Record
|
||||||
|
Snapshot
|
||||||
*/
|
*/
|
||||||
package walpb
|
package walpb
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user