## Design 1. Flatten binary key-value space 2. Keep the event history until compaction - access to old version of keys - user controlled history compaction 3. Support range query - Pagination support with limit argument - Support consistency guarantee across multiple range queries 4. Replace TTL key with Lease - more efficient/ low cost keep alive - a logical group of TTL keys 5. Replace CAS/CAD with multi-object Tnx - MUCH MORE powerful and flexible 6. Support efficient watching with multiple ranges 7. RPC API supports the completed set of APIs. - more efficient than JSON/HTTP - additional tnx/lease support 8. HTTP API supports a subset of APIs. - easy for people to try out etcd - easy for people to write simple etcd application ## Protobuf Defined API [protobuf](./v3api.proto) ### Examples #### Put a key (foo=bar) ``` // A put is always successful Put( PutRequest { key = foo, value = bar } ) PutResponse { cluster_id = 0x1000, member_id = 0x1, index = 1, raft_term = 0x1, } ``` #### Get a key (assume we have foo=bar) ``` Get ( RangeRequest { key = foo } ) RangeResponse { cluster_id = 0x1000, member_id = 0x1, index = 1, raft_term = 0x1, kvs = { { key = foo, value = bar, create_index = 1, mod_index = 1, version = 1; }, }, } ``` #### Range over a key space (assume we have foo0=bar0… foo100=bar100) ``` Range ( RangeRequest { key = foo, end_key = foo80, limit = 30 } ) RangeResponse { cluster_id = 0x1000, member_id = 0x1, index = 100, raft_term = 0x1, kvs = { { key = foo0, value = bar0, create_index = 1, mod_index = 1, version = 1; }, ..., { key = foo30, value = bar30, create_index = 30, mod_index = 30, version = 1; }, }, } ``` #### Finish a tnx (assume we have foo0=bar0, foo1=bar1) ``` Tnx(TnxRequest { // mod_index of foo0 is equal to 1, mod_index of foo1 is greater than 1 compare = { {compareType = equal, key = foo0, mod_index = 1}, {compareType = greater, key = foo1, mod_index = 1}} }, // if the comparison succeeds, put foo2 = bar2 success = {PutRequest { key = foo2, value = success }}, // if the comparison fails, put foo2=fail failure = {PutRequest { key = foo2, value = failure }}, ) TnxResponse { cluster_id = 0x1000, member_id = 0x1, index = 3, raft_term = 0x1, succeeded = true, responses = { // response of PUT foo2=success { cluster_id = 0x1000, member_id = 0x1, index = 3, raft_term = 0x1, } } } ``` #### Watch on a key/range ``` Watch( WatchRequest{ key = foo, end_key = fop, // prefix foo start_index = 20, end_index = 10000, // server decided notification frequency progress_notification = true, } … // this can be a watch request stream ) // put (foo0=bar0) event at 3 WatchResponse { cluster_id = 0x1000, member_id = 0x1, index = 3, raft_term = 0x1, event_type = put, kv = { key = foo0, value = bar0, create_index = 1, mod_index = 1, version = 1; }, } … // a notification at 2000 WatchResponse { cluster_id = 0x1000, member_id = 0x1, index = 2000, raft_term = 0x1, // nil event as notification } … // put (foo0=bar3000) event at 3000 WatchResponse { cluster_id = 0x1000, member_id = 0x1, index = 3000, raft_term = 0x1, event_type = put, kv = { key = foo0, value = bar3000, create_index = 1, mod_index = 3000, version = 2; }, } … ```