Documentation
Document various methods in db.lua and cache.lua
This commit is contained in:
parent
e430d9b512
commit
677f05d69c
|
@ -1,8 +1,11 @@
|
||||||
--[[
|
--[[ md
|
||||||
Implements a simple in-memory cache. The cache has no upper size limit, and
|
|
||||||
may cause out-of-memory errors. When this happens, the OS will kill the kore
|
@name lua/cache
|
||||||
worker process, and the kore parent process will restart with a fresh, empty
|
|
||||||
cache
|
Implements a simple in memory read through cache.
|
||||||
|
The cache has no upper size limit, and may cause out-of-memory errors.
|
||||||
|
When this happens, the OS will kill the kore worker process,
|
||||||
|
and the kore parent process will restart with a fresh, empty cache.
|
||||||
]]
|
]]
|
||||||
|
|
||||||
local sql = require("lsqlite3")
|
local sql = require("lsqlite3")
|
||||||
|
@ -15,6 +18,68 @@ local ret = {}
|
||||||
|
|
||||||
local stmnt_cache, stmnt_insert_cache, stmnt_dirty_cache
|
local stmnt_cache, stmnt_insert_cache, stmnt_dirty_cache
|
||||||
|
|
||||||
|
--[[ cat
|
||||||
|
@name lua/cache
|
||||||
|
<h3>Schema for Cache</h3>
|
||||||
|
<p>The cache mechanism is a in-memeory sqlite3 database behind the scenes, it
|
||||||
|
can ensure consistency and atomic updates & dirtying, though it doesn't today.</p>
|
||||||
|
<table>
|
||||||
|
<caption>cache</caption>
|
||||||
|
<tr>
|
||||||
|
<th>Attributes</th>
|
||||||
|
<th>Field</th>
|
||||||
|
<th>Type</th>
|
||||||
|
<th>Description</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Primary Key</td>
|
||||||
|
<td>path</td>
|
||||||
|
<td>TEXT</td>
|
||||||
|
<td>
|
||||||
|
The logical path this text was rendered at,
|
||||||
|
before browser-specific headers (like accept-encoding)
|
||||||
|
are applied
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td></td>
|
||||||
|
<td>data</td>
|
||||||
|
<td>BLOB</td>
|
||||||
|
<td>
|
||||||
|
The returned result from the function passed into
|
||||||
|
cache.render(), the result must be a string, and
|
||||||
|
may contain nulls.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td></td>
|
||||||
|
<td>updated</td>
|
||||||
|
<td>INTEGER</td>
|
||||||
|
<td>
|
||||||
|
The time this item was rendered at, can be used to set
|
||||||
|
a minimum update frequency. This is used so that web
|
||||||
|
scrapers don't constantly trigger re-renders of the
|
||||||
|
index page.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td></td>
|
||||||
|
<td>dirty</td>
|
||||||
|
<td>INTEGER</td>
|
||||||
|
<td>
|
||||||
|
Does this page need to be re-rendered the next time it
|
||||||
|
is called? For example, an author's story could have
|
||||||
|
multiple hits, which would require rerendering their
|
||||||
|
author page to show the new hit count, but we don't
|
||||||
|
actually need to do it until someone requests the
|
||||||
|
author page. In this case, we keep the old page around
|
||||||
|
to save time trying to clear it and potentially hit
|
||||||
|
sqlite's garbage collector.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
]]
|
||||||
|
|
||||||
local oldconfigure = configure
|
local oldconfigure = configure
|
||||||
function configure(...)
|
function configure(...)
|
||||||
ret.cache = db.sqlassert(sql.open_memory())-- Expose db for testing
|
ret.cache = db.sqlassert(sql.open_memory())-- Expose db for testing
|
||||||
|
@ -52,7 +117,40 @@ function configure(...)
|
||||||
return oldconfigure(...)
|
return oldconfigure(...)
|
||||||
end
|
end
|
||||||
|
|
||||||
--Render a page, with cacheing. If you need to dirty a cache, call dirty_cache()
|
--[[ md
|
||||||
|
@name lua/cache
|
||||||
|
|
||||||
|
### cache.render
|
||||||
|
|
||||||
|
Render a page with cacheing.
|
||||||
|
The callback will be called with no arguments, and must return a string.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
0. pagename - {{lua/string}} - A logical string to associate with this
|
||||||
|
rendered page, this must be passed exactly into render() in order
|
||||||
|
to (potentially) retrive the cached page.
|
||||||
|
0. callback - {{lua/function}} - A function that may be called,
|
||||||
|
if it is called, it is called with no arguments, and must return a string.
|
||||||
|
The returned string may have embedded nulls.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
0. {{lua/string}} - Either the return of the passed function, or the cached
|
||||||
|
string.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
cache = require("cache")
|
||||||
|
func = function()
|
||||||
|
print("Called")
|
||||||
|
return "Hello, world!"
|
||||||
|
end
|
||||||
|
print(cache.render("/test",func)) -- prints "Called", then "Hello, world!"
|
||||||
|
print(cache.render("/test",func)) -- prints "Hello, world!"
|
||||||
|
print(cache.render("/test",func)) -- prints "Hello, world!"
|
||||||
|
|
||||||
|
]]
|
||||||
function ret.render(pagename,callback)
|
function ret.render(pagename,callback)
|
||||||
stmnt_cache:bind_names{path=pagename}
|
stmnt_cache:bind_names{path=pagename}
|
||||||
local err = db.do_sql(stmnt_cache)
|
local err = db.do_sql(stmnt_cache)
|
||||||
|
@ -81,8 +179,37 @@ function ret.render(pagename,callback)
|
||||||
return text
|
return text
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Dirty a cached page, causing it to be re-rendered the next time it's
|
--[[ md
|
||||||
-- requested. Doesn't actually delete it or anything, just sets it's dirty bit
|
@name lua/cache
|
||||||
|
|
||||||
|
### cache.dirty
|
||||||
|
|
||||||
|
Dirty a cached page, causing it to be re-rendered the next time it's
|
||||||
|
requested. Doesn't actually delete it or free memory, just sets its dirty bit.
|
||||||
|
If the page does not exists or has not been rendered yet, this function does
|
||||||
|
not error.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
0. url - {{lua/string}} - `pagename` from the render function, the logical
|
||||||
|
string associcated with this rendered page.
|
||||||
|
|
||||||
|
No returns
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
cache = require("cache")
|
||||||
|
func = function()
|
||||||
|
print("Called")
|
||||||
|
return "Hello, world!"
|
||||||
|
end
|
||||||
|
print(cache.render("/test",func)) -- prints "Called", then "Hello, world!"
|
||||||
|
print(cache.render("/test",func)) -- prints "Hello, world!")
|
||||||
|
cache.dirty("/test")
|
||||||
|
print(cache.render("/test",func)) -- prints "Called", then "Hello, world!"
|
||||||
|
print(cache.render("/test",func)) -- prints "Hello, world!"
|
||||||
|
]]
|
||||||
|
|
||||||
function ret.dirty(url)
|
function ret.dirty(url)
|
||||||
stmnt_dirty_cache:bind_names{
|
stmnt_dirty_cache:bind_names{
|
||||||
path = url
|
path = url
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
--[[ md
|
--[[ md
|
||||||
@name lua/db
|
@name lua/db
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
Does most of the database interaction.
|
Does most of the database interaction.
|
||||||
|
Creates default empty database during configure()
|
||||||
Notably, holds a connection to the open sqlite3 database in .conn
|
Notably, holds a connection to the open sqlite3 database in .conn
|
||||||
]]
|
]]
|
||||||
local sql = require("lsqlite3")
|
local sql = require("lsqlite3")
|
||||||
|
@ -11,7 +15,9 @@ local config = require("config")
|
||||||
local db = {}
|
local db = {}
|
||||||
|
|
||||||
--[[ md
|
--[[ md
|
||||||
@name lua/db/sqlassert
|
@name lua/db
|
||||||
|
|
||||||
|
### db.sqlassert
|
||||||
|
|
||||||
Runs an sql query and receives the 3 arguments back, prints a nice error
|
Runs an sql query and receives the 3 arguments back, prints a nice error
|
||||||
message on fail, and returns true on success.
|
message on fail, and returns true on success.
|
||||||
|
@ -36,8 +42,8 @@ that error checking and assignment can all be done on a single line.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
> db = require("db")
|
db = require("db")
|
||||||
> query = db.sqlassert(db.conn:parepare("SELECT 'Hello, world!'"))
|
query = db.sqlassert(db.conn:parepare("SELECT 'Hello, world!'"))
|
||||||
]]
|
]]
|
||||||
function db.sqlassert(r, errcode, err)
|
function db.sqlassert(r, errcode, err)
|
||||||
if not r then
|
if not r then
|
||||||
|
@ -51,7 +57,9 @@ function db.sqlassert(r, errcode, err)
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[ md
|
--[[ md
|
||||||
@name lua/db/do_sql
|
@name lua/db
|
||||||
|
|
||||||
|
### db.do_sql
|
||||||
|
|
||||||
Continuously tries to perform an sql statement until it goes through. This function may call {{lua/coroutine/yield}}
|
Continuously tries to perform an sql statement until it goes through. This function may call {{lua/coroutine/yield}}
|
||||||
|
|
||||||
|
@ -65,12 +73,12 @@ Returns:
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
> sql = require("lsqlite3")
|
sql = require("lsqlite3")
|
||||||
> configure = function(...) end -- Mock smr environment
|
configure = function(...) end -- Mock smr environment
|
||||||
> db = require("db")
|
db = require("db")
|
||||||
> configure()
|
configure()
|
||||||
> query = db.conn:prepare("SELECT 'Hello, world!';")
|
query = db.conn:prepare("SELECT 'Hello, world!';")
|
||||||
> assert(db.do_sql(query))
|
assert(db.do_sql(query))
|
||||||
]]
|
]]
|
||||||
function db.do_sql(stmnt)
|
function db.do_sql(stmnt)
|
||||||
if not stmnt then error("No statement",2) end
|
if not stmnt then error("No statement",2) end
|
||||||
|
@ -88,7 +96,9 @@ function db.do_sql(stmnt)
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[ md
|
--[[ md
|
||||||
@name lua/db/sql_rows
|
@name lua/db
|
||||||
|
|
||||||
|
### db.sql_rows
|
||||||
|
|
||||||
Provides an iterator that loops over results in an sql statement or throws an
|
Provides an iterator that loops over results in an sql statement or throws an
|
||||||
error, then resets the statement after the loop is done.
|
error, then resets the statement after the loop is done.
|
||||||
|
@ -107,12 +117,11 @@ Returns:
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
> db = require("db")
|
db = require("db")
|
||||||
> query = db.conn:prepare("SELECT 'Hello, world!';")
|
query = db.conn:prepare("SELECT 'Hello, world!';")
|
||||||
> for row in db.sql_rows(query) do
|
for row in db.sql_rows(query) do
|
||||||
> print(row)
|
print(row) -- prints 'Hello, world!'
|
||||||
> end
|
end
|
||||||
Hello, world!
|
|
||||||
|
|
||||||
]]
|
]]
|
||||||
function db.sql_rows(stmnt)
|
function db.sql_rows(stmnt)
|
||||||
|
@ -141,14 +150,24 @@ function db.sql_rows(stmnt)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[
|
--[[ md
|
||||||
@name lua/db/sqlbind
|
@name lua/db
|
||||||
|
|
||||||
Binds an argument to as statement with nice error reporting on failure. Approximatly the same as {{lsqlite/stmt/bind_names}}, but with better error reporting.
|
### db.sqlbind
|
||||||
stmnt :: sql.stmnt - the prepared sql statemnet
|
|
||||||
call :: string - a string "bind" or "bind_blob"
|
Binds an argument to a prepared statement,
|
||||||
position :: number - the argument position to bind to
|
with nice error reporting on failure.
|
||||||
data :: string - The data to bind
|
Wraps {{lsqlite/stmnt/bind_name}}
|
||||||
|
with better error reporting.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
0. stmnt - {{lsqlite/stmnt}} - The prepared statement from {{sqlite/db/prepare}}
|
||||||
|
0. call - {{lua/string}} - Literal string, options are `bind` for most types, or `bind_blob` for strings that may contain embedded nulls
|
||||||
|
0. position - {{lua/number}} - The argument position to bind to, does not support named parameters
|
||||||
|
0. data - Any - the data to bind
|
||||||
|
|
||||||
|
Returns nothing
|
||||||
]]
|
]]
|
||||||
function db.sqlbind(stmnt,call,position,data)
|
function db.sqlbind(stmnt,call,position,data)
|
||||||
assert(call == "bind" or call == "bind_blob","Bad bind call, call was:" .. call)
|
assert(call == "bind" or call == "bind_blob","Bad bind call, call was:" .. call)
|
||||||
|
@ -166,8 +185,6 @@ function db.sqlbind(stmnt,call,position,data)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
local oldconfigure = configure
|
local oldconfigure = configure
|
||||||
db.conn = db.sqlassert(sql.open(config.db))
|
db.conn = db.sqlassert(sql.open(config.db))
|
||||||
function configure(...)
|
function configure(...)
|
||||||
|
@ -191,6 +208,18 @@ function configure(...)
|
||||||
return oldconfigure(...)
|
return oldconfigure(...)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--[[ md
|
||||||
|
|
||||||
|
### db.close()
|
||||||
|
|
||||||
|
Closes the database connection. Not called during normal operation, used to
|
||||||
|
assist in unit testing.
|
||||||
|
|
||||||
|
No parameters
|
||||||
|
|
||||||
|
No returns
|
||||||
|
]]
|
||||||
|
|
||||||
function db.close()
|
function db.close()
|
||||||
db.conn:close()
|
db.conn:close()
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue