Annotate

util/cache.lua @ 13652:a08065207ef0

net.server_epoll: Call :shutdown() on TLS sockets when supported Comment from Matthew: This fixes a potential issue where the Prosody process gets blocked on sockets waiting for them to close. Unlike non-TLS sockets, closing a TLS socket sends layer 7 data, and this can cause problems for sockets which are in the process of being cleaned up. This depends on LuaSec changes which are not yet upstream. From Martijn's original email: So first my analysis of luasec. in ssl.c the socket is put into blocking mode right before calling SSL_shutdown() inside meth_destroy(). My best guess to why this is is because meth_destroy is linked to the __close and __gc methods, which can't exactly be called multiple times and luasec does want to make sure that a tls session is shutdown as clean as possible. I can't say I disagree with this reasoning and don't want to change this behaviour. My solution to this without changing the current behaviour is to introduce a shutdown() method. I am aware that this overlaps in a conflicting way with tcp's shutdown method, but it stays close to the OpenSSL name. This method calls SSL_shutdown() in the current (non)blocking mode of the underlying socket and returns a boolean whether or not the shutdown is completed (matching SSL_shutdown()'s 0 or 1 return values), and returns the familiar ssl_ioerror() strings on error with a false for completion. This error can then be used to determine if we have wantread/wantwrite to finalize things. Once meth_shutdown() has been called once a shutdown flag will be set, which indicates to meth_destroy() that the SSL_shutdown() has been handled by the application and it shouldn't be needed to set the socket to blocking mode. I've left the SSL_shutdown() call in the LSEC_STATE_CONNECTED to prevent TOCTOU if the application reaches a timeout for the shutdown code, which might allow SSL_shutdown() to clean up anyway at the last possible moment. Another thing I've changed to luasec is the call to socket_setblocking() right before calling close(2) in socket_destroy() in usocket.c. According to the latest POSIX[0]: Note that the requirement for close() on a socket to block for up to the current linger interval is not conditional on the O_NONBLOCK setting. Which I read to mean that removing O_NONBLOCK on the socket before close doesn't impact the behaviour and only causes noise in system call tracers. I didn't touch the windows bits of this, since I don't do windows. For the prosody side of things I've made the TLS shutdown bits resemble interface:onwritable(), and put it under a combined guard of self._tls and self.conn.shutdown. The self._tls bit is there to prevent getting stuck on this condition, and self.conn.shutdown is there to prevent the code being called by instances where the patched luasec isn't deployed. The destroy() method can be called from various places and is read by me as the "we give up" error path. To accommodate for these unexpected entrypoints I've added a single call to self.conn:shutdown() to prevent the socket being put into blocking mode. I have no expectations that there is any other use here. Same as previous, the self.conn.shutdown check is there to make sure it's not called on unpatched luasec deployments and self._tls is there to make sure we don't call shutdown() on tcp sockets. I wouldn't recommend logging of the conn:shutdown() error inside close(), since a lot of clients simply close the connection before SSL_shutdown() is done.
author Martijn van Duren <martijn@openbsd.org>
date Thu, 06 Feb 2025 15:04:38 +0000
parent 13175:bbdaa770b955
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
6933
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
1
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
2 local function _remove(list, m)
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
3 if m.prev then
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
4 m.prev.next = m.next;
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
5 end
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
6 if m.next then
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
7 m.next.prev = m.prev;
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
8 end
6945
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
9 if list._tail == m then
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
10 list._tail = m.prev;
6933
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
11 end
6945
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
12 if list._head == m then
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
13 list._head = m.next;
6933
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
14 end
6945
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
15 list._count = list._count - 1;
6933
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
16 end
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
17
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
18 local function _insert(list, m)
6945
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
19 if list._head then
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
20 list._head.prev = m;
6933
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
21 end
6945
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
22 m.prev, m.next = nil, list._head;
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
23 list._head = m;
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
24 if not list._tail then
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
25 list._tail = m;
6933
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
26 end
6945
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
27 list._count = list._count + 1;
6933
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
28 end
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
29
6945
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
30 local cache_methods = {};
11198
c4c06fbb7d87 util.cache: Add __name to metatable
Matthew Wild <mwild1@gmail.com>
parents: 8398
diff changeset
31 local cache_mt = { __name = "cache", __index = cache_methods };
6945
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
32
6933
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
33 function cache_methods:set(k, v)
6945
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
34 local m = self._data[k];
6933
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
35 if m then
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
36 -- Key already exists
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
37 if v ~= nil then
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
38 -- Bump to head of list
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
39 _remove(self, m);
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
40 _insert(self, m);
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
41 m.value = v;
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
42 else
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
43 -- Remove from list
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
44 _remove(self, m);
6945
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
45 self._data[k] = nil;
6933
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
46 end
6945
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
47 return true;
6933
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
48 end
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
49 -- New key
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
50 if v == nil then
6945
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
51 return true;
6933
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
52 end
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
53 -- Check whether we need to remove oldest k/v
6945
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
54 if self._count == self.size then
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
55 local tail = self._tail;
7290
70ab13e81cf5 util.cache: Change behaviour of on_evict (and tests). Now accepts false instead of a function (never evict), or on_evict can return false to prevent eviction.
Matthew Wild <mwild1@gmail.com>
parents: 7289
diff changeset
56 local on_evict, evicted_key, evicted_value = self._on_evict, tail.key, tail.value;
13174
8ec7b7d6556f util.cache: Keep eviction candidate if callback resized to make room
Kim Alvefur <zash@zash.se>
parents: 11198
diff changeset
57
13175
bbdaa770b955 util.cache: Pass cache itself to eviction callback
Kim Alvefur <zash@zash.se>
parents: 13174
diff changeset
58 local do_evict = on_evict and on_evict(evicted_key, evicted_value, self);
13174
8ec7b7d6556f util.cache: Keep eviction candidate if callback resized to make room
Kim Alvefur <zash@zash.se>
parents: 11198
diff changeset
59
8ec7b7d6556f util.cache: Keep eviction candidate if callback resized to make room
Kim Alvefur <zash@zash.se>
parents: 11198
diff changeset
60 if do_evict == false then
7290
70ab13e81cf5 util.cache: Change behaviour of on_evict (and tests). Now accepts false instead of a function (never evict), or on_evict can return false to prevent eviction.
Matthew Wild <mwild1@gmail.com>
parents: 7289
diff changeset
61 -- Cache is full, and we're not allowed to evict
70ab13e81cf5 util.cache: Change behaviour of on_evict (and tests). Now accepts false instead of a function (never evict), or on_evict can return false to prevent eviction.
Matthew Wild <mwild1@gmail.com>
parents: 7289
diff changeset
62 return false;
13174
8ec7b7d6556f util.cache: Keep eviction candidate if callback resized to make room
Kim Alvefur <zash@zash.se>
parents: 11198
diff changeset
63 elseif self._count == self.size then
8ec7b7d6556f util.cache: Keep eviction candidate if callback resized to make room
Kim Alvefur <zash@zash.se>
parents: 11198
diff changeset
64 -- Cache wasn't grown
8ec7b7d6556f util.cache: Keep eviction candidate if callback resized to make room
Kim Alvefur <zash@zash.se>
parents: 11198
diff changeset
65 _remove(self, tail);
8ec7b7d6556f util.cache: Keep eviction candidate if callback resized to make room
Kim Alvefur <zash@zash.se>
parents: 11198
diff changeset
66 self._data[evicted_key] = nil;
7290
70ab13e81cf5 util.cache: Change behaviour of on_evict (and tests). Now accepts false instead of a function (never evict), or on_evict can return false to prevent eviction.
Matthew Wild <mwild1@gmail.com>
parents: 7289
diff changeset
67 end
6933
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
68 end
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
69
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
70 m = { key = k, value = v, prev = nil, next = nil };
6945
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
71 self._data[k] = m;
6933
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
72 _insert(self, m);
6945
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
73 return true;
6933
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
74 end
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
75
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
76 function cache_methods:get(k)
6945
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
77 local m = self._data[k];
6933
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
78 if m then
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
79 return m.value;
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
80 end
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
81 return nil;
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
82 end
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
83
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
84 function cache_methods:items()
6945
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
85 local m = self._head;
6933
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
86 return function ()
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
87 if not m then
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
88 return;
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
89 end
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
90 local k, v = m.key, m.value;
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
91 m = m.next;
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
92 return k, v;
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
93 end
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
94 end
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
95
7354
8ca7f1c2c660 util.cache: Add method for iterating over values
Kim Alvefur <zash@zash.se>
parents: 7290
diff changeset
96 function cache_methods:values()
8ca7f1c2c660 util.cache: Add method for iterating over values
Kim Alvefur <zash@zash.se>
parents: 7290
diff changeset
97 local m = self._head;
8ca7f1c2c660 util.cache: Add method for iterating over values
Kim Alvefur <zash@zash.se>
parents: 7290
diff changeset
98 return function ()
8ca7f1c2c660 util.cache: Add method for iterating over values
Kim Alvefur <zash@zash.se>
parents: 7290
diff changeset
99 if not m then
8ca7f1c2c660 util.cache: Add method for iterating over values
Kim Alvefur <zash@zash.se>
parents: 7290
diff changeset
100 return;
8ca7f1c2c660 util.cache: Add method for iterating over values
Kim Alvefur <zash@zash.se>
parents: 7290
diff changeset
101 end
8ca7f1c2c660 util.cache: Add method for iterating over values
Kim Alvefur <zash@zash.se>
parents: 7290
diff changeset
102 local v = m.value;
8ca7f1c2c660 util.cache: Add method for iterating over values
Kim Alvefur <zash@zash.se>
parents: 7290
diff changeset
103 m = m.next;
8ca7f1c2c660 util.cache: Add method for iterating over values
Kim Alvefur <zash@zash.se>
parents: 7290
diff changeset
104 return v;
8ca7f1c2c660 util.cache: Add method for iterating over values
Kim Alvefur <zash@zash.se>
parents: 7290
diff changeset
105 end
8ca7f1c2c660 util.cache: Add method for iterating over values
Kim Alvefur <zash@zash.se>
parents: 7290
diff changeset
106 end
8ca7f1c2c660 util.cache: Add method for iterating over values
Kim Alvefur <zash@zash.se>
parents: 7290
diff changeset
107
6945
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
108 function cache_methods:count()
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
109 return self._count;
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
110 end
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
111
7289
42e7545d5ae3 util.cache: Add head() and tail() methods (and tests)
Matthew Wild <mwild1@gmail.com>
parents: 7016
diff changeset
112 function cache_methods:head()
42e7545d5ae3 util.cache: Add head() and tail() methods (and tests)
Matthew Wild <mwild1@gmail.com>
parents: 7016
diff changeset
113 local head = self._head;
42e7545d5ae3 util.cache: Add head() and tail() methods (and tests)
Matthew Wild <mwild1@gmail.com>
parents: 7016
diff changeset
114 if not head then return nil, nil; end
42e7545d5ae3 util.cache: Add head() and tail() methods (and tests)
Matthew Wild <mwild1@gmail.com>
parents: 7016
diff changeset
115 return head.key, head.value;
42e7545d5ae3 util.cache: Add head() and tail() methods (and tests)
Matthew Wild <mwild1@gmail.com>
parents: 7016
diff changeset
116 end
42e7545d5ae3 util.cache: Add head() and tail() methods (and tests)
Matthew Wild <mwild1@gmail.com>
parents: 7016
diff changeset
117
42e7545d5ae3 util.cache: Add head() and tail() methods (and tests)
Matthew Wild <mwild1@gmail.com>
parents: 7016
diff changeset
118 function cache_methods:tail()
42e7545d5ae3 util.cache: Add head() and tail() methods (and tests)
Matthew Wild <mwild1@gmail.com>
parents: 7016
diff changeset
119 local tail = self._tail;
42e7545d5ae3 util.cache: Add head() and tail() methods (and tests)
Matthew Wild <mwild1@gmail.com>
parents: 7016
diff changeset
120 if not tail then return nil, nil; end
42e7545d5ae3 util.cache: Add head() and tail() methods (and tests)
Matthew Wild <mwild1@gmail.com>
parents: 7016
diff changeset
121 return tail.key, tail.value;
42e7545d5ae3 util.cache: Add head() and tail() methods (and tests)
Matthew Wild <mwild1@gmail.com>
parents: 7016
diff changeset
122 end
42e7545d5ae3 util.cache: Add head() and tail() methods (and tests)
Matthew Wild <mwild1@gmail.com>
parents: 7016
diff changeset
123
8397
99d85731e3ee util.cache: Add a method to resize the cache
Kim Alvefur <zash@zash.se>
parents: 8396
diff changeset
124 function cache_methods:resize(new_size)
99d85731e3ee util.cache: Add a method to resize the cache
Kim Alvefur <zash@zash.se>
parents: 8396
diff changeset
125 new_size = assert(tonumber(new_size), "cache size must be a number");
99d85731e3ee util.cache: Add a method to resize the cache
Kim Alvefur <zash@zash.se>
parents: 8396
diff changeset
126 new_size = math.floor(new_size);
99d85731e3ee util.cache: Add a method to resize the cache
Kim Alvefur <zash@zash.se>
parents: 8396
diff changeset
127 assert(new_size > 0, "cache size must be greater than zero");
8398
3eff1b60269a util.cache: Call on-eviction callback when shrinking
Kim Alvefur <zash@zash.se>
parents: 8397
diff changeset
128 local on_evict = self._on_evict;
8397
99d85731e3ee util.cache: Add a method to resize the cache
Kim Alvefur <zash@zash.se>
parents: 8396
diff changeset
129 while self._count > new_size do
99d85731e3ee util.cache: Add a method to resize the cache
Kim Alvefur <zash@zash.se>
parents: 8396
diff changeset
130 local tail = self._tail;
8398
3eff1b60269a util.cache: Call on-eviction callback when shrinking
Kim Alvefur <zash@zash.se>
parents: 8397
diff changeset
131 local evicted_key, evicted_value = tail.key, tail.value;
13175
bbdaa770b955 util.cache: Pass cache itself to eviction callback
Kim Alvefur <zash@zash.se>
parents: 13174
diff changeset
132 if on_evict ~= nil and (on_evict == false or on_evict(evicted_key, evicted_value, self) == false) then
8398
3eff1b60269a util.cache: Call on-eviction callback when shrinking
Kim Alvefur <zash@zash.se>
parents: 8397
diff changeset
133 -- Cache is full, and we're not allowed to evict
3eff1b60269a util.cache: Call on-eviction callback when shrinking
Kim Alvefur <zash@zash.se>
parents: 8397
diff changeset
134 return false;
3eff1b60269a util.cache: Call on-eviction callback when shrinking
Kim Alvefur <zash@zash.se>
parents: 8397
diff changeset
135 end
8397
99d85731e3ee util.cache: Add a method to resize the cache
Kim Alvefur <zash@zash.se>
parents: 8396
diff changeset
136 _remove(self, tail);
99d85731e3ee util.cache: Add a method to resize the cache
Kim Alvefur <zash@zash.se>
parents: 8396
diff changeset
137 self._data[evicted_key] = nil;
99d85731e3ee util.cache: Add a method to resize the cache
Kim Alvefur <zash@zash.se>
parents: 8396
diff changeset
138 end
99d85731e3ee util.cache: Add a method to resize the cache
Kim Alvefur <zash@zash.se>
parents: 8396
diff changeset
139 self.size = new_size;
99d85731e3ee util.cache: Add a method to resize the cache
Kim Alvefur <zash@zash.se>
parents: 8396
diff changeset
140 return true;
99d85731e3ee util.cache: Add a method to resize the cache
Kim Alvefur <zash@zash.se>
parents: 8396
diff changeset
141 end
99d85731e3ee util.cache: Add a method to resize the cache
Kim Alvefur <zash@zash.se>
parents: 8396
diff changeset
142
7435
8603b16e85c7 util.cache: Add support for creating a proxy table to a cache, that looks and acts (mostly) like a normal table. No tests yet.
Matthew Wild <mwild1@gmail.com>
parents: 7354
diff changeset
143 function cache_methods:table()
7702
9385c367e920 util.cache: Ignore unused argument [luacheck]
Kim Alvefur <zash@zash.se>
parents: 7435
diff changeset
144 --luacheck: ignore 212/t
7435
8603b16e85c7 util.cache: Add support for creating a proxy table to a cache, that looks and acts (mostly) like a normal table. No tests yet.
Matthew Wild <mwild1@gmail.com>
parents: 7354
diff changeset
145 if not self.proxy_table then
8603b16e85c7 util.cache: Add support for creating a proxy table to a cache, that looks and acts (mostly) like a normal table. No tests yet.
Matthew Wild <mwild1@gmail.com>
parents: 7354
diff changeset
146 self.proxy_table = setmetatable({}, {
8603b16e85c7 util.cache: Add support for creating a proxy table to a cache, that looks and acts (mostly) like a normal table. No tests yet.
Matthew Wild <mwild1@gmail.com>
parents: 7354
diff changeset
147 __index = function (t, k)
8603b16e85c7 util.cache: Add support for creating a proxy table to a cache, that looks and acts (mostly) like a normal table. No tests yet.
Matthew Wild <mwild1@gmail.com>
parents: 7354
diff changeset
148 return self:get(k);
8603b16e85c7 util.cache: Add support for creating a proxy table to a cache, that looks and acts (mostly) like a normal table. No tests yet.
Matthew Wild <mwild1@gmail.com>
parents: 7354
diff changeset
149 end;
8603b16e85c7 util.cache: Add support for creating a proxy table to a cache, that looks and acts (mostly) like a normal table. No tests yet.
Matthew Wild <mwild1@gmail.com>
parents: 7354
diff changeset
150 __newindex = function (t, k, v)
8603b16e85c7 util.cache: Add support for creating a proxy table to a cache, that looks and acts (mostly) like a normal table. No tests yet.
Matthew Wild <mwild1@gmail.com>
parents: 7354
diff changeset
151 if not self:set(k, v) then
8603b16e85c7 util.cache: Add support for creating a proxy table to a cache, that looks and acts (mostly) like a normal table. No tests yet.
Matthew Wild <mwild1@gmail.com>
parents: 7354
diff changeset
152 error("failed to insert key into cache - full");
8603b16e85c7 util.cache: Add support for creating a proxy table to a cache, that looks and acts (mostly) like a normal table. No tests yet.
Matthew Wild <mwild1@gmail.com>
parents: 7354
diff changeset
153 end
8603b16e85c7 util.cache: Add support for creating a proxy table to a cache, that looks and acts (mostly) like a normal table. No tests yet.
Matthew Wild <mwild1@gmail.com>
parents: 7354
diff changeset
154 end;
8603b16e85c7 util.cache: Add support for creating a proxy table to a cache, that looks and acts (mostly) like a normal table. No tests yet.
Matthew Wild <mwild1@gmail.com>
parents: 7354
diff changeset
155 __pairs = function (t)
8603b16e85c7 util.cache: Add support for creating a proxy table to a cache, that looks and acts (mostly) like a normal table. No tests yet.
Matthew Wild <mwild1@gmail.com>
parents: 7354
diff changeset
156 return self:items();
8603b16e85c7 util.cache: Add support for creating a proxy table to a cache, that looks and acts (mostly) like a normal table. No tests yet.
Matthew Wild <mwild1@gmail.com>
parents: 7354
diff changeset
157 end;
8603b16e85c7 util.cache: Add support for creating a proxy table to a cache, that looks and acts (mostly) like a normal table. No tests yet.
Matthew Wild <mwild1@gmail.com>
parents: 7354
diff changeset
158 __len = function (t)
8603b16e85c7 util.cache: Add support for creating a proxy table to a cache, that looks and acts (mostly) like a normal table. No tests yet.
Matthew Wild <mwild1@gmail.com>
parents: 7354
diff changeset
159 return self:count();
8603b16e85c7 util.cache: Add support for creating a proxy table to a cache, that looks and acts (mostly) like a normal table. No tests yet.
Matthew Wild <mwild1@gmail.com>
parents: 7354
diff changeset
160 end;
8603b16e85c7 util.cache: Add support for creating a proxy table to a cache, that looks and acts (mostly) like a normal table. No tests yet.
Matthew Wild <mwild1@gmail.com>
parents: 7354
diff changeset
161 });
8603b16e85c7 util.cache: Add support for creating a proxy table to a cache, that looks and acts (mostly) like a normal table. No tests yet.
Matthew Wild <mwild1@gmail.com>
parents: 7354
diff changeset
162 end
8603b16e85c7 util.cache: Add support for creating a proxy table to a cache, that looks and acts (mostly) like a normal table. No tests yet.
Matthew Wild <mwild1@gmail.com>
parents: 7354
diff changeset
163 return self.proxy_table;
8603b16e85c7 util.cache: Add support for creating a proxy table to a cache, that looks and acts (mostly) like a normal table. No tests yet.
Matthew Wild <mwild1@gmail.com>
parents: 7354
diff changeset
164 end
8603b16e85c7 util.cache: Add support for creating a proxy table to a cache, that looks and acts (mostly) like a normal table. No tests yet.
Matthew Wild <mwild1@gmail.com>
parents: 7354
diff changeset
165
8396
fbe1f99fb245 util.cache: Add method for removing all data (does not call eviction callback)
Kim Alvefur <zash@zash.se>
parents: 7702
diff changeset
166 function cache_methods:clear()
fbe1f99fb245 util.cache: Add method for removing all data (does not call eviction callback)
Kim Alvefur <zash@zash.se>
parents: 7702
diff changeset
167 self._data = {};
fbe1f99fb245 util.cache: Add method for removing all data (does not call eviction callback)
Kim Alvefur <zash@zash.se>
parents: 7702
diff changeset
168 self._count = 0;
fbe1f99fb245 util.cache: Add method for removing all data (does not call eviction callback)
Kim Alvefur <zash@zash.se>
parents: 7702
diff changeset
169 self._head = nil;
fbe1f99fb245 util.cache: Add method for removing all data (does not call eviction callback)
Kim Alvefur <zash@zash.se>
parents: 7702
diff changeset
170 self._tail = nil;
fbe1f99fb245 util.cache: Add method for removing all data (does not call eviction callback)
Kim Alvefur <zash@zash.se>
parents: 7702
diff changeset
171 end
fbe1f99fb245 util.cache: Add method for removing all data (does not call eviction callback)
Kim Alvefur <zash@zash.se>
parents: 7702
diff changeset
172
6945
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
173 local function new(size, on_evict)
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
174 size = assert(tonumber(size), "cache size must be a number");
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
175 size = math.floor(size);
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
176 assert(size > 0, "cache size must be greater than zero");
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
177 local data = {};
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
178 return setmetatable({ _data = data, _count = 0, size = size, _head = nil, _tail = nil, _on_evict = on_evict }, cache_mt);
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
179 end
d779c55058c6 util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
Matthew Wild <mwild1@gmail.com>
parents: 6943
diff changeset
180
6933
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
181 return {
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
182 new = new;
d636815d81c3 util.cache: Ordered key->value data structure, with size limit (same as pubsub)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
183 }