Mercurial > prosody-hg
comparison util/smqueue.lua @ 14017:1e01b91cf94d
util.smqueue: Backport changes to Teal source
| author | Kim Alvefur <zash@zash.se> |
|---|---|
| date | Sun, 07 Dec 2025 15:13:09 +0100 |
| parents | 21126415c8a0 |
| children | 73903352de86 |
comparison
equal
deleted
inserted
replaced
| 14016:1df1782ccdfe | 14017:1e01b91cf94d |
|---|---|
| 1 -- Represents an outgoing reliable stanza queue | 1 -- This file is generated from teal-src/prosody/util/smqueue.tl |
| 2 | |
| 3 local queue = require("prosody.util.queue"); | 2 local queue = require("prosody.util.queue"); |
| 4 | 3 |
| 5 -- SM queue methods | 4 local lib = { smqueue = {} } |
| 6 local smqueue = {}; | 5 |
| 6 local smqueue = lib.smqueue; | |
| 7 | 7 |
| 8 function smqueue:push(v) | 8 function smqueue:push(v) |
| 9 self._head = self._head + 1; | 9 self._head = self._head + 1; |
| 10 | 10 |
| 11 assert(self._queue:push(v)); | 11 assert(self._queue:push(v)); |
| 12 end | 12 end |
| 13 | 13 |
| 14 -- Call when receiver has acknowledged some stanzas | |
| 15 -- `h` (sent by the receiver) is the running count of | |
| 16 -- successfully received stanzas | |
| 17 function smqueue:ack(h) | 14 function smqueue:ack(h) |
| 18 if h < self._tail then | 15 if h < self._tail then |
| 19 -- h is less than a previous h | 16 |
| 20 return nil, "tail" | 17 return nil, "tail" |
| 21 elseif h > self._head then | 18 elseif h > self._head then |
| 22 -- h is greater than the number of stanzas we sent | 19 |
| 23 return nil, "head" | 20 return nil, "head" |
| 24 end | 21 end |
| 25 | 22 |
| 26 local acked = {}; | 23 local acked = {}; |
| 27 self._tail = h; | 24 self._tail = h; |
| 28 local expect = self._head - self._tail; | 25 local expect = self._head - self._tail; |
| 29 while expect < self._queue:count() do | 26 while expect < self._queue:count() do |
| 30 local v = self._queue:pop(); | 27 local v = self._queue:pop(); |
| 31 if not v then return nil, "pop" end | 28 if not v then |
| 29 return nil, "pop" | |
| 30 end | |
| 32 table.insert(acked, v); | 31 table.insert(acked, v); |
| 33 end | 32 end |
| 34 | 33 |
| 35 local c = self._next_checkpoint; | 34 local c = self._next_checkpoint; |
| 36 if c and h >= c then | 35 if c and h >= c then |
| 37 self:_call_checkpoints(h); | 36 self:_call_checkpoints(h); |
| 38 end | 37 end |
| 39 | |
| 40 return acked | 38 return acked |
| 41 end | 39 end |
| 42 | 40 |
| 43 function smqueue:count_unacked() return self._head - self._tail end | 41 function smqueue:count_unacked() |
| 42 return self._head - self._tail | |
| 43 end | |
| 44 | 44 |
| 45 function smqueue:count_acked() return self._tail end | 45 function smqueue:count_acked() |
| 46 return self._tail | |
| 47 end | |
| 46 | 48 |
| 47 function smqueue:resumable() return self._queue:count() >= (self._head - self._tail) end | 49 function smqueue:resumable() |
| 50 return self._queue:count() >= (self._head - self._tail) | |
| 51 end | |
| 48 | 52 |
| 49 function smqueue:resume() return self._queue:items() end | 53 function smqueue:resume() |
| 54 return self._queue:items() | |
| 55 end | |
| 50 | 56 |
| 51 function smqueue:consume() return self._queue:consume() end | 57 function smqueue:consume() |
| 58 return self._queue:consume() | |
| 59 end | |
| 52 | 60 |
| 53 function smqueue:table() | 61 function smqueue:table() |
| 54 local t = {}; | 62 local t = {}; |
| 55 for i, v in self:resume() do t[i] = v; end | 63 for i, v in self:resume() do |
| 64 t[i] = v; | |
| 65 end | |
| 56 return t | 66 return t |
| 57 end | 67 end |
| 58 | 68 |
| 59 -- Add a 'checkpoint' which will call a function when all the stanzas | |
| 60 -- currently in the queue have been successfully delivered and acknowledged | |
| 61 function smqueue:add_checkpoint(cb, ud) | 69 function smqueue:add_checkpoint(cb, ud) |
| 62 table.insert(self._checkpoints, { self._head, cb, ud }); | 70 table.insert(self._checkpoints, { self._head; cb; ud }); |
| 63 if not self._next_checkpoint then | 71 if not self._next_checkpoint then |
| 64 self._next_checkpoint = self._head; | 72 self._next_checkpoint = self._head; |
| 65 end | 73 end |
| 66 end | 74 end |
| 67 | 75 |
| 68 function smqueue:_call_checkpoints(h) | 76 function smqueue:_call_checkpoints(h) |
| 69 local checkpoints = self._checkpoints; | 77 local checkpoints = self._checkpoints; |
| 70 | 78 |
| 71 -- Pop the checkpoint info and update the next checkpoint info | |
| 72 local c = table.remove(checkpoints, 1); | 79 local c = table.remove(checkpoints, 1); |
| 73 self._next_checkpoint = checkpoints[1] and checkpoints[1][1] or nil; | 80 self._next_checkpoint = checkpoints[1] and checkpoints[1][1] or nil; |
| 74 | 81 |
| 75 -- Call the callback | |
| 76 local cb, ud = c[2], c[3]; | 82 local cb, ud = c[2], c[3]; |
| 77 cb(ud); | 83 cb(ud); |
| 78 | 84 |
| 79 -- In case we passed over multiple checkpoints, call them also | |
| 80 if h >= self._next_checkpoint then | 85 if h >= self._next_checkpoint then |
| 81 return self:_call_checkpoints(h); | 86 return self:_call_checkpoints(h) |
| 82 end | 87 end |
| 83 end | 88 end |
| 84 | 89 |
| 85 local smqueue_mt = { | 90 local function freeze(q) |
| 86 __name = "smqueue"; | 91 return { head = q._head; tail = q._tail } |
| 87 __index = smqueue; | 92 end |
| 88 __len = smqueue.count_unacked; | |
| 89 -- Return a simple object for serialization | |
| 90 __freeze = function (q) return { head = q._head; tail = q._tail } end; | |
| 91 }; | |
| 92 | 93 |
| 93 local lib = {}; | 94 local smqueue_mt = { __name = "smqueue"; __index = smqueue; __len = smqueue.count_unacked; __freeze = freeze } |
| 94 | 95 |
| 95 function lib.new(size) | 96 function lib.new(size) |
| 96 assert(size > 0); | 97 assert(size > 0); |
| 97 return setmetatable({ | 98 return setmetatable({ _head = 0; _tail = 0; _queue = queue.new(size, true); _checkpoints = {} }, smqueue_mt) |
| 98 _head = 0; | |
| 99 _tail = 0; | |
| 100 _queue = queue.new(size, true); | |
| 101 _checkpoints = {}; | |
| 102 }, smqueue_mt) | |
| 103 end | 99 end |
| 104 | 100 |
| 105 return lib | 101 return lib |
