From c00ef5461e5e416be8e53a5785e7b0c2d50b7290 Mon Sep 17 00:00:00 2001 From: Alexandr <a.lyapunov@corp.mail.ru> Date: Wed, 20 Aug 2014 17:25:06 +0400 Subject: [PATCH] added version control to lua iterators --- src/box/index.cc | 3 +++ src/box/index.h | 6 ++++++ src/box/lua/index.cc | 20 ++++++++++++++++++++ src/box/lua/index.h | 3 +++ src/box/lua/schema.lua | 7 ++++++- src/box/schema.cc | 1 + test/big/iterator.result | 15 +++++++++++++++ test/big/iterator.test.lua | 7 +++++++ 8 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/box/index.cc b/src/box/index.cc index 4c4c45d81b..874c93df84 100644 --- a/src/box/index.cc +++ b/src/box/index.cc @@ -34,6 +34,7 @@ #include "tuple.h" #include "say.h" #include "exception.h" +#include "schema.h" STRS(iterator_type, ITERATOR_TYPE); @@ -102,6 +103,7 @@ primary_key_validate(struct key_def *key_def, const char *key, Index::Index(struct key_def *key_def_arg) :key_def(key_def_dup(key_def_arg)), + sc_version(::sc_version++), m_position(NULL) {} @@ -128,6 +130,7 @@ Index::~Index() if (m_position != NULL) m_position->free(m_position); key_def_delete(key_def); + ::sc_version++; } struct tuple * diff --git a/src/box/index.h b/src/box/index.h index 6adb062361..739021102a 100644 --- a/src/box/index.h +++ b/src/box/index.h @@ -84,6 +84,10 @@ struct iterator { struct tuple *(*next)(struct iterator *); void (*free)(struct iterator *); void (*close)(struct iterator *); + /* optional parameters used in lua */ + int sc_version; + uint32_t space_id; + uint32_t index_id; }; static inline void @@ -140,6 +144,8 @@ class Index: public Object { public: /* Description of a possibly multipart key. */ struct key_def *key_def; + /* Schema version on index construction moment */ + int sc_version; protected: /** diff --git a/src/box/lua/index.cc b/src/box/lua/index.cc index 0371fd0990..16efa9f966 100644 --- a/src/box/lua/index.cc +++ b/src/box/lua/index.cc @@ -95,6 +95,9 @@ boxffi_index_iterator(uint32_t space_id, uint32_t index_id, int type, key_validate(index->key_def, itype, key, part_count); it = index->allocIterator(); index->initIterator(it, itype, key, part_count); + it->sc_version = sc_version; + it->space_id = space_id; + it->index_id = index_id; return it; } catch (Exception *) { if (it) @@ -104,6 +107,23 @@ boxffi_index_iterator(uint32_t space_id, uint32_t index_id, int type, } } +struct tuple* +boxffi_iterator_next(struct iterator *itr) +{ + if (itr->sc_version != sc_version) { + try { + Index *index = check_index(itr->space_id, itr->index_id); + if (index->sc_version > itr->sc_version) + return NULL; + itr->sc_version = sc_version; + } catch (Exception *) { + /* will be hanled by box.error() in Lua */ + return NULL; + } + } + return itr->next(itr); +} + /* }}} */ void diff --git a/src/box/lua/index.h b/src/box/lua/index.h index 2ea1a53e68..d442f00160 100644 --- a/src/box/lua/index.h +++ b/src/box/lua/index.h @@ -52,6 +52,9 @@ struct iterator * boxffi_index_iterator(uint32_t space_id, uint32_t index_id, int type, const char *key); +struct tuple* +boxffi_iterator_next(struct iterator *itr); + #if defined(__cplusplus) } /* extern "C" */ #endif /* defined(__cplusplus) */ diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua index 7e6798a1c9..fb877f8a9b 100644 --- a/src/box/lua/schema.lua +++ b/src/box/lua/schema.lua @@ -16,6 +16,9 @@ ffi.cdef[[ struct tuple *(*next)(struct iterator *); void (*free)(struct iterator *); void (*close)(struct iterator *); + int sc_version; + uint32_t space_id; + uint32_t index_id; }; size_t boxffi_index_len(uint32_t space_id, uint32_t index_id); @@ -24,6 +27,8 @@ ffi.cdef[[ struct iterator * boxffi_index_iterator(uint32_t space_id, uint32_t index_id, int type, const char *key); + struct tuple * + boxffi_iterator_next(struct iterator *itr); struct port; struct port_ffi @@ -319,7 +324,7 @@ local iterator_gen = function(param, state) error('usage gen(param, state)') end -- next() modifies state in-place - local tuple = state.next(state) + local tuple = builtin.boxffi_iterator_next(state) if tuple ~= nil then return state, box.tuple.bless(tuple) -- new state, value else diff --git a/src/box/schema.cc b/src/box/schema.cc index a1b5c2e819..5ad3637e0f 100644 --- a/src/box/schema.cc +++ b/src/box/schema.cc @@ -153,6 +153,7 @@ space_cache_replace(struct space *space) panic_syserror("Out of memory for the data " "dictionary cache."); } + sc_version++; /* * Must be after the space is put into the hash, since * box.schema.space.bless() uses hash look up to find the diff --git a/test/big/iterator.result b/test/big/iterator.result index b8f720cbd9..8bd1e9c92f 100644 --- a/test/big/iterator.result +++ b/test/big/iterator.result @@ -893,6 +893,21 @@ space.index['primary']:pairs(function() end, { iterator = box.index.EQ }) --- - error: 'builtin/msgpackffi.lua:258: can not encode Lua type: ''function''' ... +-- Check that iterators successfully invalidated when index deleted +gen, param, state = space.index['i1']:pairs(nil, { iterator = box.index.GE }) +--- +... +index_space = box.space[box.schema.INDEX_ID] +--- +... +index_space:delete{space.id, space.index['i1'].id} +--- +- [512, 1, 'i1', 'tree', 0, 1, 1, 'str'] +... +gen(param, state) +--- +- null +... space:drop() --- ... diff --git a/test/big/iterator.test.lua b/test/big/iterator.test.lua index 9dd7822af5..4271ad50f1 100644 --- a/test/big/iterator.test.lua +++ b/test/big/iterator.test.lua @@ -161,4 +161,11 @@ iterate('tweedledum', 'i5', 1, 3, box.index.EQ, 'sid_005', 'tid_995', 'a') space.index['primary']:pairs({}, {iterator = -666 }) -- Test cases for #123: box.index.count does not check arguments properly space.index['primary']:pairs(function() end, { iterator = box.index.EQ }) + +-- Check that iterators successfully invalidated when index deleted +gen, param, state = space.index['i1']:pairs(nil, { iterator = box.index.GE }) +index_space = box.space[box.schema.INDEX_ID] +index_space:delete{space.id, space.index['i1'].id} +gen(param, state) + space:drop() -- GitLab