mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
Add shared memory hit counter example to redbean
This commit is contained in:
parent
38e3ab57a6
commit
8aca94f951
6 changed files with 114 additions and 29 deletions
|
@ -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')
|
||||
|
||||
|
|
22
third_party/lua/lunix.c
vendored
22
third_party/lua/lunix.c
vendored
|
@ -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");
|
||||
s = luaL_checklstring(L, 2, &n);
|
||||
i = luaL_optinteger(L, 3, 0);
|
||||
if (!lua_isnumber(L, 2)) {
|
||||
// unix.Memory:write(data:str[, bytes:int])
|
||||
i = 0;
|
||||
s = luaL_checklstring(L, 2, &n);
|
||||
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;
|
||||
|
|
|
@ -20,35 +20,73 @@ 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
|
||||
unix.setsockopt(fd, unix.SOL_TCP, unix.TCP_SAVE_SYN, true)
|
||||
return false
|
||||
end
|
||||
|
||||
function OnClientConnection(ip, port, serverip, serverport)
|
||||
syn, synerr = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_SAVED_SYN)
|
||||
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()
|
||||
if GetHeader('User-Agent') then
|
||||
Log(kLogInfo, "client is running %s and reports %s" % {
|
||||
finger.GetSynFingerOs(finger.FingerSyn(syn)),
|
||||
VisualizeControlCodes(GetHeader('User-Agent'))})
|
||||
end
|
||||
if HasParam('magic') then
|
||||
Write('<p>\r\n')
|
||||
Write('OnHttpRequest() has intercepted your request<br>\r\n')
|
||||
Write('because you specified the magic parameter\r\n')
|
||||
Write('<pre>\r\n')
|
||||
Write(EscapeHtml(LoadAsset('/.init.lua')))
|
||||
Write('</pre>\r\n')
|
||||
else
|
||||
Route() -- this asks redbean to do the default thing
|
||||
end
|
||||
SetHeader('Server', 'redbean!')
|
||||
UpdateHitCounter()
|
||||
if GetHeader('User-Agent') then
|
||||
Log(kLogInfo, "client is running %s and reports %s" % {
|
||||
finger.GetSynFingerOs(finger.FingerSyn(syn)),
|
||||
VisualizeControlCodes(GetHeader('User-Agent'))})
|
||||
end
|
||||
if HasParam('magic') then
|
||||
Write('<p>\r\n')
|
||||
Write('OnHttpRequest() has intercepted your request<br>\r\n')
|
||||
Write('because you specified the magic parameter\r\n')
|
||||
Write('<pre>\r\n')
|
||||
Write(EscapeHtml(LoadAsset('/.init.lua')))
|
||||
Write('</pre>\r\n')
|
||||
else
|
||||
Route() -- this asks redbean to do the default thing
|
||||
end
|
||||
SetHeader('Server', 'redbean!')
|
||||
end
|
||||
|
||||
function Adder(x, y)
|
||||
return x + y
|
||||
return x + y
|
||||
end
|
||||
|
|
35
tool/net/demo/hitcounter.lua
Normal file
35
tool/net/demo/hitcounter.lua
Normal 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>')
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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 \
|
||||
|
|
Loading…
Reference in a new issue