diff --git a/src/box/index.cc b/src/box/index.cc index 4c4c45d81bc27156417604b805acfd2a514b50a5..874c93df84ea465e8c4c310777cd2e6d5284e15a 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 6adb06236138fd1ba60e85e684329b81bfb26f32..739021102aa6b8924e2be9f809ec7fd83303d61c 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 0371fd0990de3d0659b61b0a3292cc32d9e467b9..543647fadf87779b634a498d114d7ae6ecbdcfd7 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 *) { + /* space or index does not exist, nothing to fetch */ + return NULL; + } + } + return itr->next(itr); +} + /* }}} */ void diff --git a/src/box/lua/index.h b/src/box/lua/index.h index 2ea1a53e68237d1815a6a921171f153bd0c73658..d442f0016044c06c806956730160ba75a43ea9b0 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 7e6798a1c9bad38380145a3c553fd68a7659fc39..fb877f8a9bf2b8638e3c8e41a2eaf35b38c68338 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 a1b5c2e819a7b16ea615d77d1993da66b4353ea9..5ad3637e0f39e394a6a8fb2582759588666cbc47 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 b8f720cbd9bb8fff2fb062a0e0e06e3d0199a64d..8bd1e9c92faf0ee52eb75e576bf673d56996fe93 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 9dd7822af522d1561f8c7e702917bc0dbcdbf486..4271ad50f1d8f1d2aebeea0b0fe69e638a961410 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()