SETBIT key offset value
@write
@bitmap
@slow
Sets or clears the bit at offset in the string value stored at key.
The bit is either set or cleared depending on value, which can be either 0 or 1.
When key does not exist, a new string value is created. The string is grown to make sure it can hold a bit at offset. The offset argument is required to be greater than or equal to 0, and smaller than 2^32 (this limits bitmaps to 512MB). When the string at key is grown, added bits are set to 0.
Warning: When setting the last possible bit (offset equal to 2^32 -1) and
the string value stored at key does not yet hold a string value, or holds a
small string value, Redis needs to allocate all intermediate memory which can
block the server for some time.
On a 2010 MacBook Pro, setting bit number 2^32 -1 (512MB allocation) takes
~300ms, setting bit number 2^30 -1 (128MB allocation) takes ~80ms, setting bit
number 2^28 -1 (32MB allocation) takes ~30ms and setting bit number 2^26 -1 (8MB
allocation) takes ~8ms.
Note that once this first allocation is done, subsequent calls to SETBIT
for
the same key will not have the allocation overhead.
@return
@integer-reply: the original bit value stored at offset.
@examples
redis> SETBIT mykey 7 1
TBD
redis> SETBIT mykey 7 0
TBD
redis> GET mykey
TBD
redis> ```
TBD
redis> ## Pattern: accessing the entire bitmap
TBD
redis> There are cases when you need to set all the bits of single bitmap at once, for
TBD
redis> example when initializing it to a default non-zero value. It is possible to do
TBD
redis> this with multiple calls to the [`SETBIT`](/commands/setbit) command, one for each bit that needs to
TBD
redis> be set. However, so as an optimization you can use a single [`SET`](/commands/set) command to set
TBD
redis> the entire bitmap.
TBD
redis> Bitmaps are not an actual data type, but a set of bit-oriented operations
TBD
redis> defined on the String type (for more information refer to the
TBD
redis> [Bitmaps section of the Data Types Introduction page][ti]). This means that
TBD
redis> bitmaps can be used with string commands, and most importantly with [`SET`](/commands/set) and
TBD
redis> [`GET`](/commands/get).
TBD
redis> Because Redis' strings are binary-safe, a bitmap is trivially encoded as a bytes
TBD
redis> stream. The first byte of the string corresponds to offsets 0..7 of
TBD
redis> the bitmap, the second byte to the 8..15 range, and so forth.
TBD
redis> For example, after setting a few bits, getting the string value of the bitmap
TBD
redis> would look like this:
TBD
redis> ```
TBD
redis> > SETBIT bitmapsarestrings 2 1
TBD
redis> > SETBIT bitmapsarestrings 3 1
TBD
redis> > SETBIT bitmapsarestrings 5 1
TBD
redis> > SETBIT bitmapsarestrings 10 1
TBD
redis> > SETBIT bitmapsarestrings 11 1
TBD
redis> > SETBIT bitmapsarestrings 14 1
TBD
redis> > GET bitmapsarestrings
TBD
redis> "42"
TBD
redis> ```
TBD
redis> By getting the string representation of a bitmap, the client can then parse the
TBD
redis> response's bytes by extracting the bit values using native bit operations in its
TBD
redis> native programming language. Symmetrically, it is also possible to set an entire
TBD
redis> bitmap by performing the bits-to-bytes encoding in the client and calling [`SET`](/commands/set)
TBD
redis> with the resultant string.
TBD
redis> [ti]: /topics/data-types-intro#bitmaps
TBD
redis> ## Pattern: setting multiple bits
TBD
redis> [`SETBIT`](/commands/setbit) excels at setting single bits, and can be called several times when
TBD
redis> multiple bits need to be set. To optimize this operation you can replace
TBD
redis> multiple [`SETBIT`](/commands/setbit) calls with a single call to the variadic [`BITFIELD`](/commands/bitfield) command
TBD
redis> and the use of fields of type `u1`.
TBD
redis> For example, the example above could be replaced by:
TBD
redis> ```
TBD
redis> > BITFIELD bitsinabitmap SET u1 2 1 SET u1 3 1 SET u1 5 1 SET u1 10 1 SET u1 11 1 SET u1 14 1
TBD
redis> ```
TBD
redis> ## Advanced Pattern: accessing bitmap ranges
TBD
redis> It is also possible to use the [`GETRANGE`](/commands/getrange) and [`SETRANGE`](/commands/setrange) string commands to
TBD
redis> efficiently access a range of bit offsets in a bitmap. Below is a sample
TBD
redis> implementation in idiomatic Redis Lua scripting that can be run with the [`EVAL`](/commands/eval)
TBD
redis> command:
TBD
redis> ```
TBD
redis> --[[
TBD
redis> Sets a bitmap range
TBD
redis> Bitmaps are stored as Strings in Redis. A range spans one or more bytes,
TBD
redis> so we can call [`SETRANGE`](/commands/setrange) when entire bytes need to be set instead of flipping
TBD
redis> individual bits. Also, to avoid multiple internal memory allocations in
TBD
redis> Redis, we traverse in reverse.
TBD
redis> Expected input:
TBD
redis> KEYS[1] - bitfield key
TBD
redis> ARGV[1] - start offset (0-based, inclusive)
TBD
redis> ARGV[2] - end offset (same, should be bigger than start, no error checking)
TBD
redis> ARGV[3] - value (should be 0 or 1, no error checking)
TBD
redis> ]]--
TBD
redis> -- A helper function to stringify a binary string to semi-binary format
TBD
redis> local function tobits(str)
TBD
redis> local r = ''
TBD
redis> for i = 1, string.len(str) do
TBD
redis> local c = string.byte(str, i)
TBD
redis> local b = ' '
TBD
redis> for j = 0, 7 do
TBD
redis> b = tostring(bit.band(c, 1)) .. b
TBD
redis> c = bit.rshift(c, 1)
TBD
redis> end
TBD
redis> r = r .. b
TBD
redis> end
TBD
redis> return r
TBD
redis> end
TBD
redis> -- Main
TBD
redis> local k = KEYS[1]
TBD
redis> local s, e, v = tonumber(ARGV[1]), tonumber(ARGV[2]), tonumber(ARGV[3])
TBD
redis> -- First treat the dangling bits in the last byte
TBD
redis> local ms, me = s % 8, (e + 1) % 8
TBD
redis> if me > 0 then
TBD
redis> local t = math.max(e - me + 1, s)
TBD
redis> for i = e, t, -1 do
TBD
redis> redis.call('SETBIT', k, i, v)
TBD
redis> end
TBD
redis> e = t
TBD
redis> end
TBD
redis> -- Then the danglings in the first byte
TBD
redis> if ms > 0 then
TBD
redis> local t = math.min(s - ms + 7, e)
TBD
redis> for i = s, t, 1 do
TBD
redis> redis.call('SETBIT', k, i, v)
TBD
redis> end
TBD
redis> s = t + 1
TBD
redis> end
TBD
redis> -- Set a range accordingly, if at all
TBD
redis> local rs, re = s / 8, (e + 1) / 8
TBD
redis> local rl = re - rs
TBD
redis> if rl > 0 then
TBD
redis> local b = '\255'
TBD
redis> if 0 == v then
TBD
redis> b = '\0'
TBD
redis> end
TBD
redis> redis.call('SETRANGE', k, rs, string.rep(b, rl))
TBD
redis> end
Note: the implementation for getting a range of bit offsets from a bitmap is left as an exercise to the reader.