@@ -245,6 +245,7 @@ function M.upgrade(space,opts,depth)
245245 self .bysid = space .xq .bysid
246246 self ._lock = space .xq ._lock
247247 self .take_wait = space .xq .take_wait
248+ self .take_chans = space .xq .take_chans or {}
248249 self ._on_repl = space .xq ._on_repl
249250 self ._on_dis = space .xq ._on_dis
250251 else
@@ -253,6 +254,7 @@ function M.upgrade(space,opts,depth)
253254 -- byfid = {};
254255 self ._lock = {}
255256 self .take_wait = fiber .channel (0 )
257+ self .take_chans = setmetatable ({}, { __mode = ' v' })
256258 end
257259 setmetatable (self .bysid , {
258260 __serialize = ' map' ,
@@ -808,6 +810,15 @@ function M.upgrade(space,opts,depth)
808810
809811 function self :wakeup (t )
810812 if t [self .fieldmap .status ] ~= ' R' then return end
813+ if self .fieldmap .tube then
814+ -- we may have consumers in the tubes:
815+ local tube_chan = self .take_chans [t [self .fieldmap .tube ]]
816+ if tube_chan and tube_chan :has_readers () and tube_chan :put (true , 0 ) then
817+ -- we have successfully notified consumer
818+ return
819+ end
820+ -- otherwise fallback to default channel:
821+ end
811822 if self .take_wait :has_readers () then
812823 self .take_wait :put (true ,0 )
813824 end
953964 * if set, task will become `W` instead of `R` for `delay` seconds
954965 + `ttl` - number of seconds
955966 * if set, task will be discarded after ttl seconds unless was taken
967+ + `wait` - number of seconds
968+ * if set, callee fiber will be blocked up to `wait` seconds until task won't
969+ be processed or timeout reached.
956970
957971```lua
958972box.space.myqueue:put{ name="xxx"; data="yyy"; }
@@ -1002,6 +1016,10 @@ function methods:put(t, opts)
10021016 end
10031017 t [ xq .fieldmap .status ] = ' W'
10041018 t [ xq .fieldmap .runat ] = xq .timeoffset (opts .delay )
1019+
1020+ if opts .wait then
1021+ error (" Are you crazy? Call of :put({...}, { wait = <>, delay = <> }) looks weird" , 2 )
1022+ end
10051023 elseif opts .ttl then
10061024 if not xq .features .ttl then
10071025 error (" Feature ttl is not enabled" ,2 )
@@ -1021,11 +1039,23 @@ function methods:put(t, opts)
10211039 local tuple = xq .tuple (t )
10221040 local key = tuple [ xq .key .no ]
10231041
1024- xq ._lock [ key ] = true
1025- t = self :insert ( tuple )
1026- xq ._lock [ key ] = nil
1042+ local chan
1043+ if opts .wait then
1044+ chan = fiber .channel (1 )
1045+ xq .put_wait [key ] = chan
1046+ end
10271047
1048+ xq :atomic (key , function ()
1049+ t = self :insert (tuple )
1050+ end )
10281051 xq :wakeup (t )
1052+
1053+ if chan then
1054+ local res = chan :get (opts .wait )
1055+ if res then
1056+ return xq .retwrap (res ), true
1057+ end
1058+ end
10291059 return xq .retwrap (t )
10301060end
10311061
@@ -1036,6 +1066,7 @@ end
10361066 - `timeout` - number of seconds to wait for new task
10371067 + choose reasonable time
10381068 + beware of **readahead** size (see tarantool docs)
1069+ - `tube` - name of the tube worker wants to take task from (feature tube must be enabled)
10391070 - returns task tuple or table (see retval) or nothing on timeout
10401071 - *TODO*: ttr must be there
10411072]]
@@ -1065,12 +1096,18 @@ function methods:take(timeout, opts)
10651096 local index
10661097 local start_with
10671098
1099+ local tube_chan
10681100 if opts .tube then
10691101 if not xq .features .tube then
10701102 error (" Feature tube is not enabled" , 2 )
10711103 end
1104+
1105+ assert (type (opts .tube ) == ' string' , " opts.tube must be a string" )
1106+
10721107 index = xq .tube_index
10731108 start_with = {opts .tube , ' R' }
1109+ tube_chan = xq .take_chans [opts .tube ] or fiber .channel ()
1110+ xq .take_chans [opts .tube ] = tube_chan
10741111 else
10751112 index = xq .index
10761113 start_with = {' R' }
@@ -1082,9 +1119,7 @@ function methods:take(timeout, opts)
10821119 while not found do
10831120 for _ ,t in index :pairs (start_with , { iterator = box .index .EQ }) do
10841121 key = t [ xq .key .no ]
1085- if xq ._lock [ key ] then
1086- -- continue
1087- else
1122+ if not xq ._lock [ key ] then
10881123 -- found key
10891124 xq ._lock [ key ] = true
10901125 found = t
@@ -1093,13 +1128,22 @@ function methods:take(timeout, opts)
10931128 end
10941129 if not found then
10951130 local left = (now + timeout ) - fiber .time ()
1096- if left <= 0 then return end
1097- xq .take_wait :get (left )
1098- if box .session .storage .destroyed then return end
1099- else
1100- break
1131+ if left <= 0 then goto finish end
1132+
1133+ (tube_chan or xq .take_wait ):get (left )
1134+ if box .session .storage .destroyed then goto finish end
11011135 end
11021136 end
1137+ :: finish::
1138+
1139+ -- If we were last reader from the tube
1140+ -- we remove channel. Writers will get false
1141+ -- on :put if they exists.
1142+ if tube_chan and not tube_chan :has_readers () then
1143+ tube_chan :close ()
1144+ xq .take_chans [opts .tube ] = nil
1145+ end
1146+ if not found then return end
11031147
11041148 local r ,e = pcall (function ()
11051149 local sid = box .session .id ()
0 commit comments