Add shared memory hit counter example to redbean

This commit is contained in:
Justine Tunney 2022-10-08 08:39:13 -07:00
parent 38e3ab57a6
commit 8aca94f951
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
6 changed files with 114 additions and 29 deletions

View file

@ -29,7 +29,7 @@ assert(mem:read() == 'hello')
mem:write('hi')
assert(mem:read() == 'hi')
assert(mem:read(0, 5) == 'hi\0lo')
mem:write('H', 0, 1)
mem:write(0, 'H', 1)
assert(mem:read(0, 5) == 'Hi\0lo')
assert(mem:read(1, 1) == 'i')

View file

@ -2696,19 +2696,29 @@ static int LuaUnixMemoryRead(lua_State *L) {
return 1;
}
// unix.Memory:write(data:str[, offset:int[, bytes:int]])
// unix.Memory:write([offset:int,] data:str[, bytes:int])
static int LuaUnixMemoryWrite(lua_State *L) {
int b;
const char *s;
size_t i, n, j;
struct Memory *m;
m = luaL_checkudata(L, 1, "unix.Memory");
if (!lua_isnumber(L, 2)) {
// unix.Memory:write(data:str[, bytes:int])
i = 0;
s = luaL_checklstring(L, 2, &n);
i = luaL_optinteger(L, 3, 0);
b = 3;
} else {
// unix.Memory:write(offset:int, data:str[, bytes:int])
i = luaL_checkinteger(L, 2);
s = luaL_checklstring(L, 3, &n);
b = 4;
}
if (i > m->size) {
luaL_error(L, "out of range");
unreachable;
}
if (lua_isnoneornil(L, 4)) {
if (lua_isnoneornil(L, b)) {
// unix.Memory:write(data:str[, offset:int])
// writes binary data, plus a nul terminator
if (i < n < m->size) {
@ -2723,9 +2733,9 @@ static int LuaUnixMemoryWrite(lua_State *L) {
} else {
// unix.Memory:write(data:str, offset:int, bytes:int])
// writes binary data without including nul-terminator
j = luaL_checkinteger(L, 4);
j = luaL_checkinteger(L, b);
if (j > n) {
luaL_argerror(L, 4, "bytes is more than what's in data");
luaL_argerror(L, b, "bytes is more than what's in data");
unreachable;
}
n = j;

View file

@ -20,6 +20,30 @@ db:exec[[
INSERT INTO test (content) VALUES ('Hello Sqlite3');
]]
-- shared memory hit counter
SHM_LOCK = 0 -- index zero (first eight bytes) will hold mutex
SHM_JSON = 8 -- store json payload starting at the index eight
shm = unix.mapshared(65520)
function Lock()
local ok, old = shm:cmpxchg(SHM_LOCK, 0, 1)
if not ok then
if old == 1 then
old = shm:xchg(SHM_LOCK, 2)
end
while old > 0 do
shm:wait(SHM_LOCK, 2)
old = shm:xchg(SHM_LOCK, 2)
end
end
end
function Unlock()
old = shm:fetch_add(SHM_LOCK, -1)
if old == 2 then
shm:store(SHM_LOCK, 0)
shm:wake(SHM_LOCK, 1)
end
end
function OnServerListen(fd, ip, port)
unix.setsockopt(fd, unix.SOL_TCP, unix.TCP_SAVE_SYN, true)
return false
@ -29,8 +53,22 @@ function OnClientConnection(ip, port, serverip, serverport)
syn, synerr = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_SAVED_SYN)
end
function UpdateHitCounter()
local s, t, k
Lock()
s = shm:read(SHM_JSON)
if s == '' then s = '{}' end
t = DecodeJson(s)
k = GetPath()
if not t[k] then t[k] = 0 end
t[k] = t[k] + 1
shm:write(SHM_JSON, EncodeJson(t))
Unlock()
end
-- this intercepts all requests if it's defined
function OnHttpRequest()
UpdateHitCounter()
if GetHeader('User-Agent') then
Log(kLogInfo, "client is running %s and reports %s" % {
finger.GetSynFingerOs(finger.FingerSyn(syn)),

View file

@ -0,0 +1,35 @@
Write([[<!doctype html>
<title>redbean mapshared demo</title>
<style>
body { padding: 1em; }
h1 a { color: inherit; text-decoration: none; }
h1 img { border: none; vertical-align: middle; }
input { margin: 1em; padding: .5em; }
pre { margin-left: 2em; }
p { word-break: break-word; max-width: 650px; }
dt { font-weight: bold; }
dd { margin-top: 1em; margin-bottom: 1em; }
.hdr { text-indent: -1em; padding-left: 1em; }
</style>
<h1>
<a href="/"><img src="/redbean.png"></a>
<a href="fetch.lua">redbean mapshared demo</a>
</h1>
<p>
This page displays a <code>unix.mapshared()</code> hit counter of
the <code>GetPath()</code>.
</p>
<dl>
]])
Lock()
s = shm:read(SHM_JSON)
if s == '' then s = '{}' end
t = DecodeJson(s)
Unlock()
for k,v in pairs(t) do
Write('<dt>%s<dd>%d\n' % {EscapeHtml(k), v})
end
Write('</dl>')

View file

@ -4509,7 +4509,7 @@ UNIX MODULE
end
end
function Unlock()
old = mem:add(LOCK, -1)
old = mem:fetch_add(LOCK, -1)
if old == 2 then
mem:store(LOCK, 0)
mem:wake(LOCK, 1)
@ -4568,7 +4568,7 @@ UNIX MODULE
single lock which is used to synchronize reads and writes to
that specific map. To make it scale, create additional maps.
unix.Memory:write(data:str[, offset:int[, bytes:int]])
unix.Memory:write([offset:int,] data:str[, bytes:int]])
Writes bytes to memory region.

View file

@ -154,6 +154,7 @@ o/$(MODE)/tool/net/demo/store-asset.lua.zip.o \
o/$(MODE)/tool/net/demo/maxmind.lua.zip.o \
o/$(MODE)/tool/net/demo/redbean.lua.zip.o \
o/$(MODE)/tool/net/demo/opensource.lua.zip.o \
o/$(MODE)/tool/net/demo/hitcounter.lua.zip.o \
o/$(MODE)/tool/net/demo/binarytrees.lua.zip.o \
o/$(MODE)/tool/net/demo/crashreport.lua.zip.o \
o/$(MODE)/tool/net/demo/closedsource.lua.zip.o \
@ -205,6 +206,7 @@ o/$(MODE)/tool/net/redbean-demo.com.dbg: \
o/$(MODE)/tool/net/demo/redbean.lua.zip.o \
o/$(MODE)/tool/net/demo/maxmind.lua.zip.o \
o/$(MODE)/tool/net/demo/opensource.lua.zip.o \
o/$(MODE)/tool/net/demo/hitcounter.lua.zip.o \
o/$(MODE)/tool/net/demo/binarytrees.lua.zip.o \
o/$(MODE)/tool/net/demo/crashreport.lua.zip.o \
o/$(MODE)/tool/net/demo/closedsource.lua.zip.o \