在 etcd v3.0.x 中,我如何请求具有给定前缀的所有键?

In etcd v3.0.x, how do I request all keys with a given prefix?

在 etcd 3.0.x 中,引入了一个新的 API,我正在阅读它。在 RangeRequest 对象中,我不清楚一件事。在 description of the property range_end 中,它表示:

If the range_end is one bit larger than the given key, then the range requests get the all keys with the prefix (the given key).

这是完整的文本,以提供一些上下文:

// key is the first key for the range. If range_end is not given, the request only looks up key.
bytes key = 1;
// range_end is the upper bound on the requested range [key, range_end).
// If range_end is '[=11=]', the range is all keys >= key.
// If the range_end is one bit larger than the given key,
// then the range requests get the all keys with the prefix (the given key).
// If both key and range_end are '[=11=]', then range requests returns all keys.
bytes range_end = 2;

我的问题是:

是什么意思

If the range_end is one bit larger than the given key

?这是否意味着 range_endkey 长 1 位?这是否意味着当解释为整数时它必须是 key+1?如果是后者,采用哪种编码方式?

key的最后一个字节大一位。
例如,如果 key 是“09903x”,那么 range_end 应该是“09903y”。
发送到etcd服务器时只有字节流,所以要关心驱动的序列化,确定range_end.

的值

有一个 PR 解决了这个困惑。

If range_end is key plus one (e.g., "aa"+1 == "ab", "a\xff"+1 == "b"), then the range request gets all keys prefixed with key.

更新:

var key = "/aaa"
var range_end = "/aa" + String.fromCharCode("a".charCodeAt(2) + 1);

这里有一个很棒的 TypeScript 示例:https://github.com/mixer/etcd3/blob/7691f9bf227841e268c3aeeb7461ad71872df878/src/util.ts#L25

工作 js 示例 TextEncoder/TextDecoder:

function endRangeForPrefix(value) {
    let textEncoder = new TextEncoder();
    let encodeValue = textEncoder.encode(value);

    for (let i = encodeValue.length - 1; i >= 0; i--) {
        if (encodeValue[i] < 0xff) {
            encodeValue[i]++;
            encodeValue = encodeValue.slice(0, i + 1);

            let textDecoder = new TextDecoder();
            let decode = textDecoder.decode(encodeValue);
            return decode;
        }
    }

    return '';
}

我正在使用 python aioetcd3。我也遇到了同样的问题,不过在他的源码里找到了方法

aioetcd3/utils.py 第 14 行

def increment_last_byte(byte_string):
    s = bytearray(to_bytes(byte_string))
    for i in range(len(s) - 1, -1, -1):
        if s[i] < 0xff:
            s[i] += 1
            return bytes(s[:i+1])
    else:
        return b'\x00'

用法:

await Client().delete([db_key, increment_last_byte(db_key)], prev_kv=True)