client/v3/leasing: clear RangeResponse.Count after deleting a cached key
Bug report criteria
- This bug report is not security related, security issues should be disclosed privately via the report form.
- This is not a support request or question, support requests or questions should be raised in the etcd discussion forums.
- You have read the etcd bug reporting guidelines.
- Existing open issues along with etcd frequently asked questions have been checked and this is not a duplicate.
What happened?
The client-side leasing cache clears GetResponse.Kvs when a cached key is deleted, but it does not clear GetResponse.Count.
Because cached responses copy the original response metadata, a key can be returned as deleted while retaining the previous count:
Put("k", "v")
leasing.Get("k") -> Kvs=[k], Count=1
leasing.Delete("k")
leasing.Get("k") -> Kvs=[], Count=1
This affects the response semantics for cached reads. Count should represent the number of keys in the range response, so it should be zero when the key no longer exists.
What did you expect to happen?
After deleting a cached key, a subsequent leasing.Get should return:
Kvs=[]
Count=0
How can we reproduce it (as minimally and precisely as possible)?
_, err := lkv.Put(ctx, "k", "v")
require.NoError(t, err)
resp, err := lkv.Get(ctx, "k")
require.NoError(t, err)
require.Equal(t, int64(1), resp.Count)
_, err = lkv.Delete(ctx, "k")
require.NoError(t, err)
resp, err = lkv.Get(ctx, "k")
require.NoError(t, err)
require.Empty(t, resp.Kvs)
require.Zero(t, resp.Count)
The final assertion fails before the fix because resp.Count remains 1.
Anything else we need to know?
The issue is in client/v3/leasing/cache.go, in the cached delete path. The fix is to set li.response.Count = 0 together with clearing li.response.Kvs.
Etcd version (please run commands below)
$ etcd --version
main @ e041c4fa2
$ etcdctl version
v3.8.0-alpha.0-309-ge041c4fa2
Etcd configuration (command line flags or environment variables)
Default client-side leasing configuration.
Etcd debug information (please run commands below, feel free to obfuscate the IP address or FQDN in the output)
$ etcdctl member list -w table
Not applicable. This is a client-side cache response issue.
$ etcdctl --endpoints=<member list> endpoint status -w table
# paste output here
Relevant log output
None.
Source: etcd-io/etcd