[Tarantool-patches] [PATCH] box/memtx: support bitset indexes for binary fields
Mary Feofanova
m.feofanova at tarantool.org
Tue Oct 6 11:23:01 MSK 2020
Closes #5071
---
Branch: https://github.com/tarantool/tarantool/tree/mary3000/gh-5071-bitset-for-binary
Issue: https://github.com/tarantool/tarantool/issues/5071
src/box/memtx_bitset.c | 3 +
src/box/memtx_space.c | 6 +-
test/box/bitset.result | 2 +-
test/box/varbinary_type.result | 109 ++++++++++++++++++++++++++++---
test/box/varbinary_type.test.lua | 77 +++++++++++++++++++---
5 files changed, 176 insertions(+), 21 deletions(-)
diff --git a/src/box/memtx_bitset.c b/src/box/memtx_bitset.c
index 2283a471d..71160e4cb 100644
--- a/src/box/memtx_bitset.c
+++ b/src/box/memtx_bitset.c
@@ -271,6 +271,9 @@ make_key(const char *field, uint32_t *key_len)
case MP_STR:
return mp_decode_str(&field, key_len);
break;
+ case MP_BIN:
+ return mp_decode_bin(&field, key_len);
+ break;
default:
*key_len = 0;
unreachable();
diff --git a/src/box/memtx_space.c b/src/box/memtx_space.c
index d4b18d9b3..4c6f1454a 100644
--- a/src/box/memtx_space.c
+++ b/src/box/memtx_space.c
@@ -707,10 +707,12 @@ memtx_space_check_index_def(struct space *space, struct index_def *index_def)
return -1;
}
if (key_def->parts[0].type != FIELD_TYPE_UNSIGNED &&
- key_def->parts[0].type != FIELD_TYPE_STRING) {
+ key_def->parts[0].type != FIELD_TYPE_STRING &&
+ key_def->parts[0].type != FIELD_TYPE_VARBINARY) {
diag_set(ClientError, ER_MODIFY_INDEX,
index_def->name, space_name(space),
- "BITSET index field type must be NUM or STR");
+ "BITSET index field type must be "
+ "NUM or STR or VARBINARY");
return -1;
}
if (key_def->is_multikey) {
diff --git a/test/box/bitset.result b/test/box/bitset.result
index bf44773ef..4808eea5c 100644
--- a/test/box/bitset.result
+++ b/test/box/bitset.result
@@ -1869,7 +1869,7 @@ _ = space:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, uniq
_ = space:create_index('bitset', { type = 'bitset', parts = {2, 'number'}, unique = false })
---
- error: 'Can''t create or modify index ''bitset'' in space ''test'': BITSET index
- field type must be NUM or STR'
+ field type must be NUM or STR or VARBINARY'
...
space:drop()
---
diff --git a/test/box/varbinary_type.result b/test/box/varbinary_type.result
index c7cd5700c..e8f171c94 100644
--- a/test/box/varbinary_type.result
+++ b/test/box/varbinary_type.result
@@ -39,16 +39,29 @@ test_run:cmd("setopt delimiter ';'")
---
- true
...
+function encode_bin(bytes)
+ local tmpbuf = buffer.IBUF_SHARED
+ tmpbuf:reset()
+ local p = tmpbuf:alloc(3 + #bytes)
+ p[0] = 0x91
+ p[1] = 0xC4
+ p[2] = #bytes
+ for i, c in pairs(bytes) do
+ p[i + 3 - 1] = c
+ end
+ return tmpbuf
+end
+test_run:cmd("setopt delimiter ''");
+---
+...
+test_run:cmd("setopt delimiter ';'")
+---
+- true
+...
function bintuple_insert(space, bytes)
- local tmpbuf = buffer.IBUF_SHARED
- tmpbuf:reset()
- local p = tmpbuf:alloc(3 + #bytes)
- p[0] = 0x91
- p[1] = 0xC4
- p[2] = #bytes
- for i, c in pairs(bytes) do p[i + 3 - 1] = c end
- ffi.cdef[[int box_insert(uint32_t space_id, const char *tuple, const char *tuple_end, box_tuple_t **result);]]
- ffi.C.box_insert(space.id, tmpbuf.rpos, tmpbuf.wpos, nil)
+ local tmpbuf = encode_bin(bytes)
+ ffi.cdef[[int box_insert(uint32_t space_id, const char *tuple, const char *tuple_end, box_tuple_t **result);]]
+ ffi.C.box_insert(space.id, tmpbuf.rpos, tmpbuf.wpos, nil)
end
test_run:cmd("setopt delimiter ''");
---
@@ -147,6 +160,84 @@ s:select()
- [!!binary +t7erQ==]
- [!!binary /u36zg==]
...
+--
+-- gh-5071: bitset index for binary fields
+--
+bs = s:create_index('bitset', {type = 'bitset', parts = {1, "varbinary"}})
+---
+...
+bintuple_insert(s, {0xFF})
+---
+...
+ITER_BITS_ALL_SET = 7
+---
+...
+ITER_BITS_ANY_SET = 8
+---
+...
+ITER_BITS_ALL_NOT_SET = 9
+---
+...
+test_run:cmd("setopt delimiter ';'")
+---
+- true
+...
+function varbinary_select(space, idx, bytes, flag)
+ local tmpbuf = encode_bin(bytes)
+ ffi.cdef[[
+ box_iterator_t *box_index_iterator(uint32_t space_id, uint32_t index_id, int type,
+ const char *key, const char *key_end);//
+ int box_iterator_next(box_iterator_t *iterator, box_tuple_t **result);//
+ const char *box_tuple_field(box_tuple_t *tuple, uint32_t fieldno);//
+ ]]
+ local res = ffi.new("box_tuple_t*[1]")
+ local it = ffi.C.box_index_iterator(space.id, idx.id, flag, tmpbuf.rpos, tmpbuf.wpos)
+
+ ffi.C.box_iterator_next(it, res)
+
+ local output = ''
+
+ while res[0] ~= nil do
+ local field = ffi.C.box_tuple_field(res[0], 0)
+ assert(bit.band(field[0], 0xff) == 0xc4)
+ local len = field[1]
+ assert(len >= 0)
+
+ for i = 0, len - 1 do
+ output = output .. string.format("%x", bit.band(field[i+2], 0xff))
+ end
+ output = output .. '\n'
+
+ ffi.C.box_iterator_next(it, res)
+ end
+
+ return output
+end
+test_run:cmd("setopt delimiter ''");
+---
+...
+varbinary_select(s, bs, { 0xff }, ITER_BITS_ALL_SET)
+---
+- 'ff
+
+ '
+...
+varbinary_select(s, bs, { 0x04 }, ITER_BITS_ANY_SET)
+---
+- 'deadbeaf
+
+ feedface
+
+ ff
+
+ '
+...
+varbinary_select(s, bs, { 0x04 }, ITER_BITS_ALL_NOT_SET)
+---
+- 'fadedead
+
+ '
+...
s:drop()
---
...
diff --git a/test/box/varbinary_type.test.lua b/test/box/varbinary_type.test.lua
index 7895a1d22..d473d792f 100644
--- a/test/box/varbinary_type.test.lua
+++ b/test/box/varbinary_type.test.lua
@@ -14,17 +14,26 @@ pk = s:create_index('pk', {parts = {1, "varbinary"}})
buffer = require('buffer')
ffi = require('ffi')
+test_run:cmd("setopt delimiter ';'")
+function encode_bin(bytes)
+ local tmpbuf = buffer.IBUF_SHARED
+ tmpbuf:reset()
+ local p = tmpbuf:alloc(3 + #bytes)
+ p[0] = 0x91
+ p[1] = 0xC4
+ p[2] = #bytes
+ for i, c in pairs(bytes) do
+ p[i + 3 - 1] = c
+ end
+ return tmpbuf
+end
+test_run:cmd("setopt delimiter ''");
+
test_run:cmd("setopt delimiter ';'")
function bintuple_insert(space, bytes)
- local tmpbuf = buffer.IBUF_SHARED
- tmpbuf:reset()
- local p = tmpbuf:alloc(3 + #bytes)
- p[0] = 0x91
- p[1] = 0xC4
- p[2] = #bytes
- for i, c in pairs(bytes) do p[i + 3 - 1] = c end
- ffi.cdef[[int box_insert(uint32_t space_id, const char *tuple, const char *tuple_end, box_tuple_t **result);]]
- ffi.C.box_insert(space.id, tmpbuf.rpos, tmpbuf.wpos, nil)
+ local tmpbuf = encode_bin(bytes)
+ ffi.cdef[[int box_insert(uint32_t space_id, const char *tuple, const char *tuple_end, box_tuple_t **result);]]
+ ffi.C.box_insert(space.id, tmpbuf.rpos, tmpbuf.wpos, nil)
end
test_run:cmd("setopt delimiter ''");
@@ -48,4 +57,54 @@ s:delete({"22"})
bintuple_insert(s, {0xFA, 0xDE, 0xDE, 0xAD})
pk:alter({parts = {1, "varbinary"}})
s:select()
+
+--
+-- gh-5071: bitset index for binary fields
+--
+bs = s:create_index('bitset', {type = 'bitset', parts = {1, "varbinary"}})
+
+bintuple_insert(s, {0xFF})
+
+ITER_BITS_ALL_SET = 7
+ITER_BITS_ANY_SET = 8
+ITER_BITS_ALL_NOT_SET = 9
+
+test_run:cmd("setopt delimiter ';'")
+function varbinary_select(space, idx, bytes, flag)
+ local tmpbuf = encode_bin(bytes)
+ ffi.cdef[[
+ box_iterator_t *box_index_iterator(uint32_t space_id, uint32_t index_id, int type,
+ const char *key, const char *key_end);//
+ int box_iterator_next(box_iterator_t *iterator, box_tuple_t **result);//
+ const char *box_tuple_field(box_tuple_t *tuple, uint32_t fieldno);//
+ ]]
+ local res = ffi.new("box_tuple_t*[1]")
+ local it = ffi.C.box_index_iterator(space.id, idx.id, flag, tmpbuf.rpos, tmpbuf.wpos)
+
+ ffi.C.box_iterator_next(it, res)
+
+ local output = ''
+
+ while res[0] ~= nil do
+ local field = ffi.C.box_tuple_field(res[0], 0)
+ assert(bit.band(field[0], 0xff) == 0xc4)
+ local len = field[1]
+ assert(len >= 0)
+
+ for i = 0, len - 1 do
+ output = output .. string.format("%x", bit.band(field[i+2], 0xff))
+ end
+ output = output .. '\n'
+
+ ffi.C.box_iterator_next(it, res)
+ end
+
+ return output
+end
+test_run:cmd("setopt delimiter ''");
+
+varbinary_select(s, bs, { 0xff }, ITER_BITS_ALL_SET)
+varbinary_select(s, bs, { 0x04 }, ITER_BITS_ANY_SET)
+varbinary_select(s, bs, { 0x04 }, ITER_BITS_ALL_NOT_SET)
+
s:drop()
--
2.26.2
More information about the Tarantool-patches
mailing list