diff --git a/src/box/box.cc b/src/box/box.cc index 0ea01a9a2e913e50e149194c763ee91211fa8bdb..8ed0ce4e505b057c40dcb416b89019cf8e0f90a8 100644 --- a/src/box/box.cc +++ b/src/box/box.cc @@ -659,6 +659,22 @@ box_replace(uint32_t space_id, const char *tuple, const char *tuple_end, return box_process1(request, result); } + +int +box_truncate(uint32_t space_id) { + try { + struct space *space = space_cache_find(space_id); + int rc = 0; + if (space) { + rc = space_truncate(space); + } + return rc; + } + catch (Exception *exc) { + return -1; + } +} + int box_delete(uint32_t space_id, uint32_t index_id, const char *key, const char *key_end, box_tuple_t **result) diff --git a/src/box/box.h b/src/box/box.h index 8c329892496ab4c671537aadf55778046b9fc249..556caa2448deaa133a79c23cb55186cdd2657e10 100644 --- a/src/box/box.h +++ b/src/box/box.h @@ -270,6 +270,14 @@ box_upsert(uint32_t space_id, uint32_t index_id, const char *tuple, const char *tuple_end, const char *ops, const char *ops_end, int index_base, box_tuple_t **result); +/** + * Truncate space. + * + * \param space_id space identifier + */ +API_EXPORT int +box_truncate(uint32_t space_id); + /** \endcond public */ /** diff --git a/src/box/lua/index.c b/src/box/lua/index.c index 83e62181df1eba7c785dd3d0a4af512250f73be8..47029becf6bcc106a432b774f31f2bdb2e06a6fa 100644 --- a/src/box/lua/index.c +++ b/src/box/lua/index.c @@ -29,7 +29,6 @@ * SUCH DAMAGE. */ #include "box/lua/index.h" - #include "lua/utils.h" #include "box/box.h" #include "box/index.h" @@ -284,6 +283,20 @@ lbox_iterator_next(lua_State *L) return lbox_pushtupleornil(L, tuple); } +/** Truncate a given space */ +static int +lbox_truncate(struct lua_State *L) +{ + if (lua_gettop(L) != 1 || lua_type(L, -1) != LUA_TTABLE) + return luaL_error(L, "usage: index:truncate()"); + lua_getfield(L, -1, "id"); /* stack: id */ + uint32_t space_id = lua_tointeger(L, -1); /* get id */ + lua_pop(L, 1); + if (box_truncate(space_id) != 0) + return lbox_error(L); + return 0; +} + /* }}} */ void @@ -318,6 +331,7 @@ box_lua_index_init(struct lua_State *L) {"count", lbox_index_count}, {"iterator", lbox_index_iterator}, {"iterator_next", lbox_iterator_next}, + {"truncate", lbox_truncate}, {NULL, NULL} }; diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua index 84cc2ea34bbe037219e4dabadf352f4a4a382ccf..5cbe02e7bb4c5c05c3248703d140e6da410135e0 100644 --- a/src/box/lua/schema.lua +++ b/src/box/lua/schema.lua @@ -991,21 +991,7 @@ function box.schema.space.bless(space) end space_mt.__pairs = space_mt.pairs -- Lua 5.2 compatibility space_mt.__ipairs = space_mt.pairs -- Lua 5.2 compatibility - space_mt.truncate = function(space) - if space.index[0] == nil then - return -- empty space without indexes, nothing to truncate - end - local _index = box.space[box.schema.INDEX_ID] - -- drop and create all indexes - local keys = _index:select(space.id) - for i = #keys, 1, -1 do - local v = keys[i] - _index:delete{v[1], v[2]} - end - for i = 1, #keys, 1 do - _index:insert(keys[i]) - end - end + space_mt.truncate = internal.truncate space_mt.format = function(space, format) return box.schema.space.format(space.id, format) end diff --git a/src/box/space.cc b/src/box/space.cc index 69d0c4ee5a5a3accd5ce393c156e9448fecbb278..7ab23a6ddf7316211602673a400bfb0374151a28 100644 --- a/src/box/space.cc +++ b/src/box/space.cc @@ -29,6 +29,7 @@ * SUCH DAMAGE. */ #include "space.h" +#include "index.h" #include <stdlib.h> #include <string.h> #include "tuple.h" @@ -37,6 +38,8 @@ #include "user_def.h" #include "user.h" #include "session.h" +#include "schema.h" +#include "box.h" void access_check_space(struct space *space, uint8_t access) @@ -232,4 +235,75 @@ space_check_update(struct space *space, index_name(index), space_name(space)); } +int +space_truncate(struct space *space) +{ + assert(space); + + if (!space_index(space, 0)) { + /* empty space without indexes, nothing to truncate */ + return 0; + } + + char key_buf_begin[20]; + char *key_buf_end = key_buf_begin; + const char *key_curr, *record_end, *record_begin; + int rc = 0; + key_buf_end = mp_encode_uint(key_buf_end, space_id(space)); + + /* BOX_INDEX_ID is id of _index space, we need 0 index of that space */ + struct space *space_index = space_cache_find(BOX_INDEX_ID); + Index *index = index_find(space_index, 0); + struct iterator *it = index->allocIterator(); + auto guard_it_free = make_scoped_guard([=]{ + it->free(it); + }); + index->initIterator(it, ITER_EQ, key_buf_begin, 1); + it->space_id = BOX_INDEX_ID; + it->index_id = 0; + it->index = index; + it->sc_version = sc_version; + int cp = 0; + struct tuple *tpl[BOX_INDEX_MAX], *tmp_tpl; /* max count of idexes*/ + memset(tpl, 0, sizeof(tpl)); + /* select all indexes of given space */ + auto guard_tpl_unref = make_scoped_guard([=]{ + for (int cp = BOX_INDEX_MAX - 1; cp >= 0; --cp) { + if (tpl[cp]) { + box_tuple_unref(tpl[cp]); + } + } + }); + while (cp < BOX_INDEX_MAX && (tmp_tpl = it->next(it))) { + box_tuple_ref(tmp_tpl); + tpl[cp] = tmp_tpl; + cp++; + } + + /* drop all selected indexes */ + for (int i = cp - 1; i >= 0; --i) { + key_curr = tpl[i]->data; + mp_decode_array(&key_curr); + key_buf_end = mp_encode_array(key_buf_begin, 2); + key_buf_end = mp_encode_uint(key_buf_end, mp_decode_uint(&key_curr)); + key_buf_end = mp_encode_uint(key_buf_end, mp_decode_uint(&key_curr)); + + rc = box_delete(BOX_INDEX_ID, 0, key_buf_begin, key_buf_end, NULL); + if (rc != 0) { + return rc; + } + } + + /* create all indexes again, now they are empty */ + for (int i = 0; i < cp; ++i) { + record_begin = tpl[i]->data; + record_end = tpl[i]->data + tpl[i]->bsize; + rc = box_insert(BOX_INDEX_ID, record_begin, record_end, NULL); + if (rc != 0) { + return rc; + } + } + return rc; +} + /* vim: set fm=marker */ diff --git a/src/box/space.h b/src/box/space.h index 8b71bdc4f2d5bd455a10ceb3ea0208f035617655..a7bfa890e0b1588eebe04a11f49c39ee6a08b6c5 100644 --- a/src/box/space.h +++ b/src/box/space.h @@ -228,4 +228,8 @@ space_check_update(struct space *space, struct tuple *old_tuple, struct tuple *new_tuple); +/** Truncate given index. **/ +int +space_truncate(struct space *space); + #endif /* TARANTOOL_BOX_SPACE_H_INCLUDED */