Mercurial > prosody-hg
changeset 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 | 1df1782ccdfe |
| children | 625372ca6bfe |
| files | teal-src/prosody/util/smqueue.tl util/smqueue.lua |
| diffstat | 2 files changed, 84 insertions(+), 43 deletions(-) [+] |
line wrap: on
line diff
--- a/teal-src/prosody/util/smqueue.tl Fri Dec 19 15:32:26 2025 +0000 +++ b/teal-src/prosody/util/smqueue.tl Sun Dec 07 15:13:09 2025 +0100 @@ -6,6 +6,9 @@ _queue : queue.queue<T> _head : integer _tail : integer + _next_checkpoint : integer + type checkpoint = { integer, function(any), any } + _checkpoints : { checkpoint } enum ack_errors "tail" @@ -17,6 +20,7 @@ resumable : function (smqueue<T>) : boolean resume : function (smqueue<T>) : queue.queue.iterator, any, integer consume : function (smqueue<T>) : function() : T + _call_checkpoints : function(smqueue<T>, integer) table : function (smqueue<T>) : { T } end @@ -31,10 +35,15 @@ assert(self._queue:push(v)); end +-- Call when receiver has acknowledged some stanzas +-- `h` (sent by the receiver) is the running count of +-- successfully received stanzas function smqueue:ack(h : integer) : { T }, smqueue.ack_errors if h < self._tail then + -- h is less than a previous h return nil, "tail" elseif h > self._head then + -- h is greater than the number of stanzas we sent return nil, "head" end -- TODO optimize? cache table fields @@ -43,11 +52,14 @@ local expect = self._head - self._tail; while expect < self._queue:count() do local v = self._queue:pop(); - if not v then - return nil, "pop" - end + if not v then return nil, "pop" end table.insert(acked, v); end + + local c = self._next_checkpoint; + if c and h >= c then + self:_call_checkpoints(h); + end return acked end @@ -80,21 +92,54 @@ return t end +-- Add a 'checkpoint' which will call a function when all the stanzas +-- currently in the queue have been successfully delivered and acknowledged +function smqueue:add_checkpoint(cb : function (any), ud : any) + table.insert(self._checkpoints, { self._head, cb, ud }); + if not self._next_checkpoint then + self._next_checkpoint = self._head; + end +end + +function smqueue:_call_checkpoints(h : integer) + local checkpoints = self._checkpoints; + + -- Pop the checkpoint info and update the next checkpoint info + local c = table.remove(checkpoints, 1); + self._next_checkpoint = checkpoints[1] and checkpoints[1][1] or nil; + + -- Call the callback + local cb, ud = c[2], c[3]; + cb(ud); + + -- In case we passed over multiple checkpoints, call them also + if h >= self._next_checkpoint then + return self:_call_checkpoints(h) + end +end + local function freeze(q : smqueue<any>) : { string:integer } return { head = q._head, tail = q._tail } end -local queue_mt = { +local smqueue_mt = { -- __name = "smqueue"; __index = smqueue; __len = smqueue.count_unacked; + -- Return a simple object for serialization + -- This is forbidden by Teal. Thanks Teal! __freeze = freeze; } function lib.new<T>(size : integer) : smqueue<T> assert(size>0); - return setmetatable({ _head = 0; _tail = 0; _queue = queue.new(size, true) }, queue_mt) + return setmetatable({ + _head = 0; + _tail = 0; + _queue = queue.new(size, true); + _checkpoints = {}; + }, smqueue_mt) end return lib
--- a/util/smqueue.lua Fri Dec 19 15:32:26 2025 +0000 +++ b/util/smqueue.lua Sun Dec 07 15:13:09 2025 +0100 @@ -1,9 +1,9 @@ --- Represents an outgoing reliable stanza queue - +-- This file is generated from teal-src/prosody/util/smqueue.tl local queue = require("prosody.util.queue"); --- SM queue methods -local smqueue = {}; +local lib = { smqueue = {} } + +local smqueue = lib.smqueue; function smqueue:push(v) self._head = self._head + 1; @@ -11,15 +11,12 @@ assert(self._queue:push(v)); end --- Call when receiver has acknowledged some stanzas --- `h` (sent by the receiver) is the running count of --- successfully received stanzas function smqueue:ack(h) if h < self._tail then - -- h is less than a previous h + return nil, "tail" elseif h > self._head then - -- h is greater than the number of stanzas we sent + return nil, "head" end @@ -28,7 +25,9 @@ local expect = self._head - self._tail; while expect < self._queue:count() do local v = self._queue:pop(); - if not v then return nil, "pop" end + if not v then + return nil, "pop" + end table.insert(acked, v); end @@ -36,30 +35,39 @@ if c and h >= c then self:_call_checkpoints(h); end - return acked end -function smqueue:count_unacked() return self._head - self._tail end +function smqueue:count_unacked() + return self._head - self._tail +end -function smqueue:count_acked() return self._tail end +function smqueue:count_acked() + return self._tail +end -function smqueue:resumable() return self._queue:count() >= (self._head - self._tail) end +function smqueue:resumable() + return self._queue:count() >= (self._head - self._tail) +end -function smqueue:resume() return self._queue:items() end +function smqueue:resume() + return self._queue:items() +end -function smqueue:consume() return self._queue:consume() end +function smqueue:consume() + return self._queue:consume() +end function smqueue:table() local t = {}; - for i, v in self:resume() do t[i] = v; end + for i, v in self:resume() do + t[i] = v; + end return t end --- Add a 'checkpoint' which will call a function when all the stanzas --- currently in the queue have been successfully delivered and acknowledged function smqueue:add_checkpoint(cb, ud) - table.insert(self._checkpoints, { self._head, cb, ud }); + table.insert(self._checkpoints, { self._head; cb; ud }); if not self._next_checkpoint then self._next_checkpoint = self._head; end @@ -68,38 +76,26 @@ function smqueue:_call_checkpoints(h) local checkpoints = self._checkpoints; - -- Pop the checkpoint info and update the next checkpoint info local c = table.remove(checkpoints, 1); self._next_checkpoint = checkpoints[1] and checkpoints[1][1] or nil; - -- Call the callback local cb, ud = c[2], c[3]; cb(ud); - -- In case we passed over multiple checkpoints, call them also if h >= self._next_checkpoint then - return self:_call_checkpoints(h); + return self:_call_checkpoints(h) end end -local smqueue_mt = { - __name = "smqueue"; - __index = smqueue; - __len = smqueue.count_unacked; - -- Return a simple object for serialization - __freeze = function (q) return { head = q._head; tail = q._tail } end; -}; +local function freeze(q) + return { head = q._head; tail = q._tail } +end -local lib = {}; +local smqueue_mt = { __name = "smqueue"; __index = smqueue; __len = smqueue.count_unacked; __freeze = freeze } function lib.new(size) assert(size > 0); - return setmetatable({ - _head = 0; - _tail = 0; - _queue = queue.new(size, true); - _checkpoints = {}; - }, smqueue_mt) + return setmetatable({ _head = 0; _tail = 0; _queue = queue.new(size, true); _checkpoints = {} }, smqueue_mt) end return lib
