BITFIELD

用法
BITFIELD key [ GET encoding offset | [ OVERFLOW WRAP | SAT | FAIL ] 〈 SET encoding offset value | INCRBY encoding offset increment 〉 ] [ [ GET encoding offset | [ OVERFLOW WRAP | SAT | FAIL ] 〈 SET encoding offset value | INCRBY encoding offset increment 〉 ] ... ]
复杂度
每个子命令 O(1)
始于
3.2.0
ACL 类别
@bitmap, @write, @slow

该命令将字符串视为位数组,能够寻址具有不同位宽和任意非(必要)对齐偏移量的特定整数域。实际上,使用此命令,您可以设置例如在位偏移量 1234 处设置一个有符号的 5 位整数到特定值,或从偏移量 4567 处检索一个 31 位无符号整数。同样,该命令处理指定整数的增量和减量,提供用户可配置的、有保证且明确定义的溢出和下溢行为。

BITFIELD 能够在同一命令调用中操作多个位字段。它接受要执行的操作列表,并返回一个回复数组,其中每个数组都与参数列表中对应的操作匹配。

例如,以下命令将位偏移量 100 处的 5 位有符号整数递增 1,并获取位偏移量 0 处的 4 位无符号整数的值:

> BITFIELD mykey INCRBY i5 100 1 GET u4 0
1) (integer) 1
2) (integer) 0

请注意

  1. 使用 !GET 寻址当前字符串长度之外的位(包括键根本不存在的情况),操作会像缺失部分全部由设置为 0 的位组成一样执行。
  2. 使用 !SET!INCRBY 寻址当前字符串长度之外的位会根据最远的触及位,按所需最小长度来扩大字符串并用零填充。

支持的子命令和整数编码

以下是支持的命令列表。

  • GET <encoding> <offset> -- 返回指定的位域。
  • SET <encoding> <offset> <value> -- 设置指定的位域并返回其旧值。
  • INCRBY <encoding> <offset> <increment> -- 增加或减少(如果给定负增量)指定的位域并返回新值。

还有另一个子命令,它仅通过设置溢出行为来改变后续 !INCRBY!SET 子命令调用的行为

  • OVERFLOW [WRAP|SAT|FAIL]

当预期整数编码时,它可以通过为有符号整数加上 i 前缀和为无符号整数加上 u 前缀以及整数编码的位数组成。因此,例如 u8 是一个 8 位的无符号整数,i16 是一个 16 位的有符号整数。

支持的编码有符号整数最高可达 64 位,无符号整数最高可达 63 位。无符号整数的这个限制是由于目前 Valkey 协议无法返回 64 位无符号整数作为回复。

位和位置偏移量

在 bitfield 命令中指定偏移量有两种方式。如果指定了一个没有前缀的数字,它就直接用作字符串内基于零的位偏移量。

然而,如果偏移量前面加上了 # 字符,则指定的偏移量会乘以整数编码的宽度,例如

BITFIELD mystring SET i8 #0 100 SET i8 #1 200

将在偏移量 0 处设置第一个 i8 整数,在偏移量 8 处设置第二个 i8 整数。这样,如果您想要的是给定大小的普通整数数组,就不必在客户端中自己进行计算了。

溢出控制

使用 OVERFLOW 命令,用户可以通过指定以下行为之一来微调增量或减量溢出(或下溢)的行为:

  • WRAP: 环绕,适用于有符号和无符号整数。对于无符号整数,环绕就像执行操作对整数能包含的最大值取模(C 标准行为)。而对于有符号整数,环绕意味着溢出重新开始朝向最负值,下溢重新开始朝向最正值。例如,如果一个 i8 整数被设置为值 127,将其加 1 将得到 -128
  • SAT: 使用饱和算术,即在下溢时将值设置为最小整数值,在溢出时设置为最大整数值。例如,将一个 i8 整数从 120 开始,增量为 10,结果将是 127,并且进一步的增量将始终使值保持在 127。下溢时也发生同样的情况,但是值会被限制在最负值。
  • FAIL: 在此模式下,检测到溢出或下溢时不会执行任何操作。相应的返回值被设置为 NULL 以向调用者发出条件信号。

请注意,每个 OVERFLOW 语句仅影响其后在子命令列表中出现的 !INCRBY!SET 命令,直到下一个 OVERFLOW 语句。

默认情况下,如果未另行指定,则使用 WRAP

> BITFIELD mykey incrby u2 100 1 OVERFLOW SAT incrby u2 102 1
1) (integer) 1
2) (integer) 1
> BITFIELD mykey incrby u2 100 1 OVERFLOW SAT incrby u2 102 1
1) (integer) 2
2) (integer) 2
> BITFIELD mykey incrby u2 100 1 OVERFLOW SAT incrby u2 102 1
1) (integer) 3
2) (integer) 3
> BITFIELD mykey incrby u2 100 1 OVERFLOW SAT incrby u2 102 1
1) (integer) 0
2) (integer) 3

以下是 OVERFLOW FAIL 返回 NULL 的示例。

> BITFIELD mykey OVERFLOW FAIL incrby u2 102 1
1) (nil)

动机

此命令的动机是,能够将许多小整数存储为单个大位图(或通过少数键分段以避免大键)可以极大提高内存效率,并为 Valkey 开启新的应用场景,尤其是在实时分析领域。这些用例得到了以受控方式指定溢出的能力的支持。

趣闻:Reddit 2017 年愚人节项目 r/place使用 BITFIELD 命令构建的,用于存储协作画布的内存表示。

性能考量

通常 BITFIELD 是一个快速命令,但请注意,寻址当前短字符串的远端位会触发一次分配,这可能比在已存在位上执行命令更耗时。

位的顺序

BITFIELD 使用的表示方式将位图的第 0 位视为第一个字节的最高有效位,依此类推。因此,例如将一个 5 位无符号整数在偏移量 7 处设置为值 23,在先前全部置零的位图中,将产生以下表示:

+--------+--------+
|00000001|01110000|
+--------+--------+

当偏移量和整数大小与字节边界对齐时,这与大端序相同,但是当不存在这种对齐时,理解字节内部位的排序也很重要。

RESP2 回复

以下之一

  • 数组回复: 每个条目是对应位置的子命令结果。

  • Nil 回复: 如果给定了 OVERFLOW FAIL 并且检测到溢出或下溢。

RESP3 回复

以下之一

  • 数组回复: 每个条目是对应位置的子命令结果。

  • Null 回复: 如果给定了 OVERFLOW FAIL 并且检测到溢出或下溢。