Иван Стрелков, OZON
message RangeRequest {
bytes key = 1;
bytes range_end = 2;
int64 limit = 3;
int64 revision = 4;
SortOrder sort_order = 5; // NONE | ASCEND | DESCEND
SortTarget sort_target = 6; // KEY | VERSION | CREATE | MOD | VALUE
bool serializable = 7;
bool keys_only = 8;
bool count_only = 9;
int64 min_mod_revision = 10;
int64 max_mod_revision = 11;
int64 min_create_revision = 12;
int64 max_create_revision = 13;
}
{ key: 'ab', range_end: 'b' }
{ key: 'ab', range_end: 'b' }
{ key: 'sc/', range_end: ? }
{ key: 'sc/', range_end: 'sc0' }
message KeyValue {
bytes key = 1;
int64 create_revision = 2;
int64 mod_revision = 3;
int64 version = 4;
bytes value = 5;
int64 lease = 6;
}
message KeyValue {
bytes key = 1;
int64 create_revision = 2;
int64 mod_revision = 3;
int64 version = 4;
bytes value = 5;
int64 lease = 6;
}
message KeyValue {
bytes key = 1;
int64 create_revision = 2;
int64 mod_revision = 3;
int64 version = 4;
bytes value = 5;
int64 lease = 6;
}
OP | rev | sc create_rev | sc mod_rev | sc version |
---|---|---|---|---|
- (beginning) | 1 | 0 | 0 | 0 |
put spam test | 2 | 0 | 0 | 0 |
put sc val1 | 3 | 3 | 3 | 1 |
put sc val2 | 4 | 3 | 4 | 2 |
del sc | 5 | 0 | 0 | 0 |
message PutRequest {
bytes key = 1;
bytes value = 2;
int64 lease = 3;
bool prev_kv = 4;
bool ignore_value = 5;
bool ignore_lease = 6;
}
etcdctl put --write-out=json foo bar
etcdctl put bar baz --prev-kv
message DeleteRangeRequest {
bytes key = 1;
bytes range_end = 2;
bool prev_kv = 3;
}
etcdctl del --prefix f
etcdctl del f g # delete every key starting with f
etcdctl del foo --prev-kv # return prev value
message RangeRequest {
bytes key = 1;
bytes range_end = 2;
int64 limit = 3;
int64 revision = 4;
SortOrder sort_order = 5; // NONE | ASCEND | DESCEND
SortTarget sort_target = 6; // KEY | VERSION | CREATE | MOD | VALUE
bool serializable = 7;
bool keys_only = 8;
bool count_only = 9;
int64 min_mod_revision = 10;
int64 max_mod_revision = 11;
int64 min_create_revision = 12;
int64 max_create_revision = 13;
}
message RangeRequest {
bytes key = 1;
bytes range_end = 2;
int64 limit = 3;
int64 revision = 4;
SortOrder sort_order = 5; // NONE | ASCEND | DESCEND
SortTarget sort_target = 6; // KEY | VERSION | CREATE | MOD | VALUE
bool serializable = 7;
bool keys_only = 8;
bool count_only = 9;
int64 min_mod_revision = 10;
int64 max_mod_revision = 11;
int64 min_create_revision = 12;
int64 max_create_revision = 13;
}
message RangeRequest {
bytes key = 1;
bytes range_end = 2;
int64 limit = 3;
int64 revision = 4;
SortOrder sort_order = 5; // NONE | ASCEND | DESCEND
SortTarget sort_target = 6; // KEY | VERSION | CREATE | MOD | VALUE
bool serializable = 7;
bool keys_only = 8;
bool count_only = 9;
int64 min_mod_revision = 10;
int64 max_mod_revision = 11;
int64 min_create_revision = 12;
int64 max_create_revision = 13;
}
message RangeRequest {
bytes key = 1;
bytes range_end = 2;
int64 limit = 3;
int64 revision = 4;
SortOrder sort_order = 5; // NONE | ASCEND | DESCEND
SortTarget sort_target = 6; // KEY | VERSION | CREATE | MOD | VALUE
bool serializable = 7;
bool keys_only = 8;
bool count_only = 9;
int64 min_mod_revision = 10;
int64 max_mod_revision = 11;
int64 min_create_revision = 12;
int64 max_create_revision = 13;
}
etcdctl get foo
etcdctl get f g # get range of every key starting with f
etcdctl get --prefix f # the same as the previous
etcdctl get --rev=1 foo # get key from some specific revision
etcdctl watch foo # watch for key
etcdctl watch --prefix sc/ # watch for every change in the prefix
etcdctl watch f h # watch for range
etcdctl watch --rev=1 --prefix "" # display whole history since the beginning
if conditions {
return success();
} else {
return failure();
}
message TxnRequest {
repeated Compare compare = 1;
repeated RequestOp success = 2;
repeated RequestOp failure = 3;
}
message Compare {
CompareResult result = 1 // EQUAL | GREATER | LESS | NOT_EQUAL
CompareTarget target = 2; // VERSION | CREATE | MOD | VALUE
bytes key = 3;
oneof target_union {
int64 version = 4;
int64 create_revision = 5;
int64 mod_revision = 6;
bytes value = 7;
}
}
message RequestOp {
oneof request {
RangeRequest request_range = 1;
PutRequest request_put = 2;
DeleteRangeRequest request_delete_range = 3;
}
}
$ etcdctl txn --interactive
compares:
mod("some-value") = "0"
mod("different-value") = "0"
success requests (get, put, del):
put some-value a
get --prefix ""
put different-value c
del foo
failure requests (get, put, del):
get some-value
message PutRequest {
bytes key = 1;
bytes value = 2;
int64 lease = 3;
bool prev_kv = 4;
bool ignore_value = 5;
bool ignore_lease = 6;
}
message PutRequest {
bytes key = 1;
bytes value = 2;
int64 lease = 3;
bool prev_kv = 4;
bool ignore_value = 5;
bool ignore_lease = 6;
}
$ etcdctl lease grant 60 # lease for 60 seconds
lease 694d74c1abd2ce10 granted with TTL(60s)
$ etcdctl lease keepalive 694d74c1abd2ce10 # prolong
$ etcdctl put --lease=694d74c1abd2ce10 foo bar # put with lease
$ etcdctl put --lease=0 --ignore-value foo # drop lease
$ etcdctl put --lease=694d74c1abd2ce10 --ignore-value foo # attach lease
$ etcdctl lease revoke 694d74c1abd2ce10 # revoke lease
mutex := concurrency.NewMutex(s, "seller/235")
if err := mutex.Lock(ctx); err != nil {
return err
}
doSomeCriticalWork();
if err := mutex.Unlock(context.TODO()); err != nil {
return err
}
rwMutex := recipe.NewRWMutex(s, "seller/432")
if err := rwMutex.RLock(ctx); err != nil {
return err
}
doSomelWorkWhileEntityIsUnchanged();
if err := rwMutex.RUnlock(context.TODO()); err != nil {
return err
}
rwMutex := recipe.NewRWMutex(s, "seller/432")
if err := rwMutex.Lock(ctx); err != nil {
return err
}
doSomeCriticalWork();
if err := rwMutex.Unlock(context.TODO()); err != nil {
return err
}
e := concurrency.NewElection(s, "my-db-leader")
if err := e.Campaign(ctx, myProposal); err != nil {
log.Fatal(err)
}
doSomethingAsALeader()
if err := e.Resign(ctx); err != nil {
log.Fatal(err)
}