--[[ 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 worker process, and the kore parent process will restart with a fresh, empty cache ]] local sql = require("lsqlite3") local queries = require("queries") local util = require("util") local ret = {} local stmnt_cache, stmnt_insert_cache, stmnt_dirty_cache local oldconfigure = configure function configure(...) local cache = util.sqlassert(sql.open_memory()) --A cache table to store rendered pages that do not need to be --rerendered. In theory this could OOM the program eventually and start --swapping to disk. TODO: fixme assert(cache:exec([[ CREATE TABLE IF NOT EXISTS cache ( path TEXT PRIMARY KEY, data BLOB, updated INTEGER, dirty INTEGER ); ]])) stmnt_cache = assert(cache:prepare([[ SELECT data FROM cache WHERE path = :path AND ((dirty = 0) OR (strftime('%s','now') - updated) < 20) ; ]])) stmnt_insert_cache = assert(cache:prepare([[ INSERT OR REPLACE INTO cache ( path, data, updated, dirty ) VALUES ( :path, :data, strftime('%s','now'), 0 ); ]])) stmnt_dirty_cache = assert(cache:prepare([[ UPDATE OR IGNORE cache SET dirty = 1 WHERE path = :path; ]])) return oldconfigure(...) end --Render a page, with cacheing. If you need to dirty a cache, call dirty_cache() function ret.render(pagename,callback) stmnt_cache:bind_names{path=pagename} local err = util.do_sql(stmnt_cache) if err == sql.DONE then stmnt_cache:reset() --page is not cached elseif err == sql.ROW then local data = stmnt_cache:get_values() stmnt_cache:reset() return data[1] else --sql.ERROR or sql.MISUSE error("Failed to check cache for page " .. pagename) end --We didn't have the paged cached, render it local text = callback() --And save the data back into the cache stmnt_insert_cache:bind_names{ path=pagename, data=text, } err = util.do_sql(stmnt_insert_cache) if err == sql.ERROR or err == sql.MISUSE then error("Failed to update cache for page " .. pagename) end stmnt_insert_cache:reset() return text end function ret.dirty(url) stmnt_dirty_cache:bind_names{ path = url } util.do_sql(stmnt_dirty_cache) stmnt_dirty_cache:reset() end function ret.close() end return ret