[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