summaryrefslogtreecommitdiff
path: root/src/keeper.lua
diff options
context:
space:
mode:
Diffstat (limited to 'src/keeper.lua')
-rw-r--r--src/keeper.lua225
1 files changed, 134 insertions, 91 deletions
diff --git a/src/keeper.lua b/src/keeper.lua
index 4bb181a..828932e 100644
--- a/src/keeper.lua
+++ b/src/keeper.lua
@@ -34,30 +34,27 @@ THE SOFTWARE.
34=============================================================================== 34===============================================================================
35]]-- 35]]--
36 36
37-- unique key instead of 'nil' in queues
38--
39assert( nil_sentinel )
40
41-- We only need to have base and table libraries (and io for debugging) 37-- We only need to have base and table libraries (and io for debugging)
42-- 38--
43local table_concat = assert( table.concat) 39local table_concat = assert( table.concat)
44local table_insert = assert( table.insert) 40local table_insert = assert( table.insert)
45local table_remove = assert( table.remove) 41local table_remove = assert( table.remove)
42local select, unpack = assert( select), assert( unpack)
46 43
47--[[ 44--[[
48local function WR(...) 45local function WR(...)
49 if io then 46 if io then
50 io.stderr:write( table_concat({...},'\t').."\n" ) 47 io.stderr:write( table_concat({...},'\t').."\n" )
51 end 48 end
52end 49end
53 50
54local function DEBUG(title,ud,key) 51local function DEBUG(title,ud,key)
55 assert( title and ud and key ) 52 assert( title and ud and key )
56 53
57 local data,incoming,_= tables(ud) 54 local data,_= tables(ud)
58 55
59 local s= tostring(data[key]) 56 local s= tostring(data[key])
60 for _,v in ipairs( incoming[key] or {} ) do 57 for _,v in ipairs( data[key] or {} ) do
61 s= s..", "..tostring(v) 58 s= s..", "..tostring(v)
62 end 59 end
63 WR( "*** "..title.." ("..tostring(key).."): ", s ) 60 WR( "*** "..title.." ("..tostring(key).."): ", s )
@@ -65,34 +62,64 @@ end
65--]] 62--]]
66 63
67----- 64-----
68-- Actual data store 65-- FIFO for a key
69--
70-- { [linda_deep_ud]= { key= val [, ...] }
71-- ...
72-- }
73-- 66--
74local _data= {} 67
68local fifo_new = function()
69 return { first = 1, count = 0}
70end
71
72local fifo_push = function( fifo, ...)
73 local first, count, added = fifo.first, fifo.count, select( '#', ...)
74 local start = first + count - 1
75 for i = 1, added do
76 fifo[start + i] = select( i, ...)
77 end
78 fifo.count = count + added
79end
80
81local fifo_peek = function( fifo, count)
82 if count <= fifo.count then
83 local first = fifo.first
84 local last = first + count - 1
85 return unpack( fifo, first, last)
86 end
87end
88
89local fifo_pop = function( fifo, count)
90 if count > fifo.count then error("list is too short") end
91 local first = fifo.first
92 local last = first + count - 1
93 local out = { unpack( fifo, first, last)}
94 for i = first, last do
95 fifo[i] = nil
96 end
97 fifo.first = first + count
98 fifo.count = fifo.count - count
99 return unpack( out)
100end
101
75 102
76----- 103-----
77-- Entries queued for use when the existing 'data[ud][key]' entry is consumed. 104-- Actual data store
78-- 105--
79-- { [linda_deep_ud]= { key= { val [, ... } [, ...] } 106-- { [linda_deep_ud]= { key= { val [, ... ] } [, ...] }
80-- ... 107-- ...
81-- } 108-- }
82-- 109--
83local _incoming= {} 110local _data= {}
84 111
85----- 112-----
86-- Length limits (if any) for queues 113-- Length limits (if any) for queues
87-- 114--
88-- 0: don't queue values at all; ':send()' waits if the slot is not vacant 115-- 0: don't queue values at all; ':send()' waits if the slot is not vacant
89-- N: allow N values to be queued (slot itself + N-1); wait if full 116-- N: allow N values to be queued (slot itself + N-1); wait if full
90-- nil: no limits, '_incoming' may grow endlessly 117-- nil: no limits, '_data' may grow endlessly
91-- 118--
92local _limits= {} 119local _limits= {}
93 120
94----- 121-----
95-- data_tbl, incoming_tbl, limits_tbl = tables( linda_deep_ud ) 122-- data_tbl, limits_tbl = tables( linda_deep_ud )
96-- 123--
97-- Gives appropriate tables for a certain Linda (creates them if needed) 124-- Gives appropriate tables for a certain Linda (creates them if needed)
98-- 125--
@@ -101,14 +128,13 @@ local function tables( ud )
101 -- 128 --
102 if not _data[ud] then 129 if not _data[ud] then
103 _data[ud]= {} 130 _data[ud]= {}
104 _incoming[ud]= {}
105 _limits[ud]= {} 131 _limits[ud]= {}
106 end 132 end
107 return _data[ud], _incoming[ud], _limits[ud] 133 return _data[ud], _limits[ud]
108end 134end
109 135
110----- 136-----
111-- bool= send( linda_deep_ud, key, ... ) 137-- bool= send( linda_deep_ud, key, ...)
112-- 138--
113-- Send new data (1..N) to 'key' slot. This send is atomic; all the values 139-- Send new data (1..N) to 'key' slot. This send is atomic; all the values
114-- end up one after each other (this is why having possibility for sending 140-- end up one after each other (this is why having possibility for sending
@@ -119,42 +145,28 @@ end
119-- Returns: 'true' if all the values were placed 145-- Returns: 'true' if all the values were placed
120-- 'false' if sending would exceed the queue limit (wait & retry) 146-- 'false' if sending would exceed the queue limit (wait & retry)
121-- 147--
122function send( ud, key, ... ) 148function send( ud, key, ...)
123 149
124 local data,incoming,limits= tables(ud) 150 local data, limits = tables( ud)
125 151
126 local n= select('#',...) 152 local n = select( '#', ...)
127 if n==0 then return true end -- nothing to send 153 if n == 0 then return true end -- nothing to send
128 154
129 -- Initialize queue for all keys that have been used with ':send()' 155 -- Initialize queue for all keys that have been used with ':send()'
130 -- 156 --
131 if incoming[key]==nil then 157 if data[key] == nil then
132 incoming[key]= {} 158 data[key] = fifo_new()
133 end 159 end
160 local fifo = data[key]
134 161
135 local len= data[key] and 1+#incoming[key] or 0 162 local len = fifo.count
136 local m= limits[key] 163 local m = limits[key]
137 164
138 if m and len+n > m then 165 if m and len+n > m then
139 return false -- would exceed the limit; try again later 166 return false -- would exceed the limit; try again later
140 end 167 end
141 168
142 for i=1,n do 169 fifo_push( fifo, ...)
143 local val= select(i,...)
144
145 -- 'nil' in the data replaced by sentinel
146 if val==nil then
147 val= nil_sentinel
148 end
149
150 if len==0 then
151 data[key]= val
152 len= 1
153 else
154 incoming[key][len]= val
155 len= len+1
156 end
157 end
158 return true 170 return true
159end 171end
160 172
@@ -165,94 +177,125 @@ end
165-- Read any of the given keys, consuming the data found. Keys are read in 177-- Read any of the given keys, consuming the data found. Keys are read in
166-- order. 178-- order.
167-- 179--
168function receive( ud, ... ) 180function receive( ud, ...)
169 181
170 local data,incoming,_= tables(ud) 182 local data, _ = tables( ud)
171 183
172 for i=1,select('#',...) do 184 for i = 1, select( '#', ...) do
173 local key= select(i,...) 185 local key = select( i, ...)
174 local val= data[key] 186 local fifo = data[key]
175 187 if fifo and fifo.count > 0 then
176 if val~=nil then 188 local val = fifo_pop( fifo, 1)
177 if incoming[key] and incoming[key][1]~=nil then 189 if val ~= nil then
178 -- pop [1] from 'incoming[key]' into the actual slot 190 return val, key
179 data[key]= table_remove( incoming[key], 1 )
180 else
181 data[key]= nil -- empty the slot
182 end
183 if val==nil_sentinel then
184 val= nil
185 end 191 end
186 return val, key
187 end 192 end
188 end 193 end
189 --return nil 194end
195
196
197-----
198-- [val1, ... valCOUNT]= receive_batched( linda_deep_ud, batch_sentinel, key , COUNT)
199--
200-- Read any of the given keys, consuming the data found. Keys are read in
201-- order.
202--
203receive_batched = function( ud, batch_sentinel, key, count)
204 if count > 0 then
205 local data, _ = tables( ud)
206 local fifo = data[key]
207 if fifo and fifo.count >= count then
208 return fifo_pop( fifo, count)
209 end
210 end
190end 211end
191 212
192 213
193----- 214-----
194-- = limit( linda_deep_ud, key, uint ) 215-- = limit( linda_deep_ud, key, uint )
195-- 216--
196function limit( ud, key, n ) 217function limit( ud, key, n)
197 218
198 local _,_,limits= tables(ud) 219 local _, limits = tables( ud)
199 220
200 limits[key]= n 221 limits[key] = n
201end 222end
202 223
203 224
204----- 225-----
205-- void= set( linda_deep_ud, key, [val] ) 226-- void= set( linda_deep_ud, key, [val] )
206-- 227--
207function set( ud, key, val ) 228function set( ud, key, val)
208 229
209 local data,incoming,_= tables(ud) 230 local data, _ = tables( ud)
210 231
211 -- Setting a key to 'nil' really clears it; only queing uses sentinels. 232 -- Setting a key to 'nil' really clears it; only queing uses sentinels.
212 -- 233 --
213 data[key]= val 234 if val ~= nil then
214 incoming[key]= nil 235 local fifo = fifo_new()
236 fifo_push( fifo, val)
237 data[key] = fifo
238 else
239 data[key] = nil
240 end
215end 241end
216 242
217 243
218----- 244-----
219-- [val]= get( linda_deep_ud, key ) 245-- [val]= get( linda_deep_ud, key )
220-- 246--
221function get( ud, key ) 247function get( ud, key)
222 248 local data, _ = tables( ud)
223 local data,_,_= tables(ud) 249 local fifo = data[key]
224 250 return fifo and fifo_peek( fifo, 1)
225 local val= data[key]
226 if val==nil_sentinel then
227 val= nil
228 end
229 return val
230end 251end
231 252
232 253
233----- 254-----
234-- [val]= keys( linda_deep_ud) 255-- [val]= count( linda_deep_ud, ...)
235-- 256--
236function keys( ud) 257-- 3 modes of operation
237 258-- linda:count() -> returns a table of key/count pairs
238 local data,_,_= tables(ud) 259-- linda:count(key) returns the number of items waiting in the key
239 260-- linda:count(key,...) -> returns a table telling, for each key, the number of items
240 local out = {} 261function count( ud, ...)
241 for key, v in pairs( data) do 262 local data, _ = tables( ud)
242 table_insert( out, key) 263 local n = select( '#', ...)
264 if n == 0 then
265 local out
266 for key, _ in pairs( data) do
267 local fifo = data[key]
268 local count = fifo and fifo.count or 0
269 out = out or {}
270 out[key] = count
271 found = true
272 end
273 return out
274 elseif n == 1 then
275 local key = ...
276 local fifo = data[key]
277 return fifo and fifo.count or nil
278 else -- more than 1 key
279 local out
280 for i = 1, n do
281 local key = select( i, ...)
282 local fifo = data[key]
283 local count = fifo and fifo.count or nil
284 out = out or {}
285 out[key] = count
286 end
287 return out
243 end 288 end
244 return (#out > 0) and out or nil
245end 289end
246 290
247 291
248----- 292-----
249-- void= clear( linda_deep_ud ) 293-- void= clear( linda_deep_ud)
250-- 294--
251-- Clear the data structures used for a Linda (at its destructor) 295-- Clear the data structures used for a Linda (at its destructor)
252-- 296--
253function clear( ud ) 297function clear( ud)
254 298
255 _data[ud]= nil 299 _data[ud]= nil
256 _incoming[ud]= nil
257 _limits[ud]= nil 300 _limits[ud]= nil
258end 301end