I analyzed possible ways to call index.next method in current API:
#1 next(index) => allocIterator => return initIterator(type = next), value
#2 next(index, iterator) => return iterator, value
#3 next(index, key) => allocIterator => return initIteratorByKey(type = next, 
key), value
#4 next(index, key1, key2, ...) => allocIterator => return 
initIteratorByKey(type = next, key = {key1, key2, ...}), value
#5 next(index, tuple) => allocIterator => return initIterator(type = next, 
tuple->data), value

Compound key in #4 {key1, key2, key3, ..} and tuple->data #5 have
similar binary representation and, therefore, parsed by same code in
initIterator.  As we can see here, next can be used for creating new
iterator as well as for iterating over existing iterator.

Problems here:
1. Implicit overcomplicated call behaviour of next (it can create new iterator 
and return a value for first call or just iterate over existing iterator for 
next calls).
2. Compound key problems. Do we actually need #4 implemented in such way? may 
be it should look like "next(index, {key1, key2, ...}")? Do we need #5 at all ?
3. Next/prev actually do not iterate forward/reverse.  A direction of iteration 
in the current implementation can only be choosed in initIterator. So, first 
call to next would create ITER_FORWARD iterator and first call to prev would 
create INIT_REVERSE (if supported). Second call to next/prev will iterate in 
the selected direction (without making difference between next/prev).
Example:
iter, value = box.space[0].index[0]:next()
box.space[0].index[0]:next(iter) - will iterate forward
box.space[0].index[0]:prev(iter) - also will iterate forward

4. I need more complicated initialization logic which would take more arguments 
(like expressions for bitmap indexes).
I do not know how to fit it in the current API.

Proposed solution for 1-4 is to split "create iterator" and "get next
value from iterator" logics into two methods.

5. next_equal/prev_equals are hacks and only can be used for solving someone 
specific problem.
The main difference between next_equal and next is that next_equals returns 
NULL if a key of next entry is not equal to user's key (index's comparator). So 
each iterator in each index should implmeneted this method or provide error 
stub for that.
I have no idea why we should support this hacks in next major releases. I think 
it should be implemented somewhere in users code.

Proposed solution for 5 is to remove this methods at all in next major
release.

-- 
You received this bug notification because you are a member of Tarantool
Development Team, which is subscribed to tarantool.
https://bugs.launchpad.net/bugs/1073476

Title:
  box.select_range and box.select_reverse_range only use first part of
  compound keys  / index.next API is weird

Status in Tarantool - an efficient in-memory data store:
  New

Bug description:
  This bug is related to
  https://bugs.launchpad.net/tarantool/+bug/1073457 , but have another
  roots of the problem.

  space[0].enabled = 1
  space[0].index[0].type = "TREE"
  space[0].index[0].unique = 1
  space[0].index[0].key_field[0].fieldno = 0
  space[0].index[0].key_field[0].type = "NUM"
  space[0].index[0].key_field[1].fieldno = 1
  space[0].index[0].key_field[1].type = "NUM"

   INSERT INTO t0 VALUES(2,1)
   INSERT INTO t0 VALUES(2,3)
   INSERT INTO t0 VALUES(2,4)
   INSERT INTO t0 VALUES(2,5)
   INSERT INTO t0 VALUES(2,6)
   INSERT INTO t0 VALUES(2,7)
   INSERT INTO t0 VALUES(2,8)

  localhost> lua box.select_range(0, 0, 100, 2)
  ---
  - 2: {1}
   - 2: {3}
   - 2: {4}
   - 2: {5}
   - 2: {6}
   - 2: {7}
   - 2: {8}

  Incorrect, works like box.select bug (see
  https://bugs.launchpad.net/tarantool/+bug/1073457).

  localhost> lua box.select_range(0, 0, 100, 2, 3)
  ---
   - 2: {1}
   - 2: {3}
   - 2: {4}
   - 2: {5}
   - 2: {6}
   - 2: {7}
   - 2: {8}

  Also incorrect, should select entries starting from 2: {3} (box.select
  works properly).

  box.select_range and box.select_reverse_range are implemented entirely
  in Lua, based on box.index methods.

  01    index_mt.select_range = function(index, limit, ...)
  02       local range = {}
  03        for k, v in index.idx.next, index.idx, ... do
  04           if #range >= limit then
  05                break
  06           end
  07            table.insert(range, v)
  08        end
  09       return unpack(range)
  10    end

  I am not Lua guru, but seems that expression in line 10 with params like 
  "box.select_range(space_no, index_no, key0, key1, key2)" will be expanded to
  "for k, v in index.idx.next, index.idx, key0, key1, key2 do".

  According to lua manual, a for statement like
       for var_1, ···, var_n in explist do block end

  is equivalent to the code:

       do
         local f, s, var = explist
         while true do
           local var_1, ···, var_n = f(s, var)
           var = var_1
           if var == nil then break end
           block
         end
       end

  for our case "for" is evaluated like this
         "local f, s, var = index.idx.next, index.idx, key0, key1, key2"

  As result, all keys begin from second will be ignored.
  I have no idea how to fix it, because current the index iteration API is 
definetly weird (will post another bug for that).

To manage notifications about this bug go to:
https://bugs.launchpad.net/tarantool/+bug/1073476/+subscriptions

_______________________________________________
Mailing list: https://launchpad.net/~tarantool-developers
Post to     : [email protected]
Unsubscribe : https://launchpad.net/~tarantool-developers
More help   : https://help.launchpad.net/ListHelp

Reply via email to