From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtp32.i.mail.ru (smtp32.i.mail.ru [94.100.177.92]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 5718F469719 for ; Tue, 6 Oct 2020 11:23:43 +0300 (MSK) From: Mary Feofanova Date: Tue, 6 Oct 2020 11:23:01 +0300 Message-Id: <20201006082301.228809-1-m.feofanova@tarantool.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: [Tarantool-patches] [PATCH] box/memtx: support bitset indexes for binary fields List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: tarantool-patches@dev.tarantool.org 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