Software /
code /
prosody-modules
Changeset
2061:b84284144e21
mod_storage_appendmap: Experimental storage module optimized for map stores
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Sun, 06 Mar 2016 17:03:19 +0100 |
parents | 2060:bd0c5d546bf8 |
children | 2062:8f7083b980cf |
files | mod_storage_appendmap/README.markdown mod_storage_appendmap/mod_storage_appendmap.lua |
diffstat | 2 files changed, 110 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_storage_appendmap/README.markdown Sun Mar 06 17:03:19 2016 +0100 @@ -0,0 +1,16 @@ +--- +labels: +- 'Stage-Alpha' +- 'Type-Storage' +summary: Experimental map store optimized for small incremental changes +... + +This is an experimental storage driver where changed data is appended. +Data is simply written as `key = value` pairs to the end of the file. +This allows changes to individual keys to be written without needing to +write out the entire object again, but reads would grow gradually larger +as it still needs to read old overwritten keys. This may be suitable for +eg rosters where individual contacts are changed at a time. In theory, +this could also allow rolling back changes. + +Requires 0.10
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_storage_appendmap/mod_storage_appendmap.lua Sun Mar 06 17:03:19 2016 +0100 @@ -0,0 +1,94 @@ +local dump = require "util.serialization".serialize; +local load = require "util.envload".envloadfile; +local dm = require "core.storagemanager".olddm; + +local driver = {}; + +local map = {}; +local map_mt = { __index = map }; +map.remove = {}; + +function map:get(user, key) + module:log("debug", "map:get(%s, %s)", tostring(user), tostring(key)) + local filename = dm.getpath(user, module.host, self.store, "map"); + module:log("debug", "File is %s", filename); + local env = {}; + if _VERSION == "Lua 5.1" then -- HACK + env._ENV = env; -- HACK + end -- SO MANY HACKS + local chunk, err = load(filename, env); + if not chunk then return chunk, err; end + local ok, err = pcall(chunk); + if not ok then return ok, err; end + if _VERSION == "Lua 5.1" then -- HACK + env._ENV = nil; -- HACK + end -- HACKS EVERYWHERE + if key == nil then + return env; + end + return env[key]; +end + +function map:set_keys(user, keyvalues) + local keys, values = {}, {}; + if _VERSION == "Lua 5.1" then + assert(not keyvalues._ENV, "'_ENV' is a restricted key"); + end + for key, value in pairs(keyvalues) do + module:log("debug", "user %s sets %q to %s", user, key, tostring(value)) + if type(key) ~= "string" or not key:find("^[%w_][%w%d_]*$") or key == "_ENV" then + key = "_ENV[" .. dump(key) .. "]"; + end + table.insert(keys, key); + if value == self.remove then + table.insert(values, "nil") + else + table.insert(values, dump(value)) + end + end + local data = table.concat(keys, ", ") .. " = " .. table.concat(values, ", ") .. ";\n"; + return dm.append_raw(user, module.host, self.store, "map", data); +end + +function map:set(user, key, value) + if _VERSION == "Lua 5.1" then + assert(key ~= "_ENV", "'_ENV' is a restricted key"); + end + if key == nil then + local filename = dm.getpath(user, module.host, self.store, "map"); + os.remove(filename); + return true; + end + if type(key) ~= "string" or not key:find("^[%w_][%w%d_]*$") or key == "_ENV" then + key = "_ENV[" .. dump(key) .. "]"; + end + local data = key .. " = " .. dump(value) .. ";\n"; + return dm.append_raw(user, module.host, self.store, "map", data); +end + +local keyval = {}; +local keyval_mt = { __index = keyval }; + +function keyval:get(user) + return map.get(self, user); +end + +keyval.set = map.set_keys; + +-- TODO some kind of periodic compaction thing? +function map:_compact(user) + local data = self:get(user); + return keyval.set(self, user, data); +end + +function driver:open(store, typ) + if typ == "map" then + return setmetatable({ store = store, }, map_mt); + elseif typ == nil or typ == "keyval" then + return setmetatable({ store = store, }, keyval_mt); + end + return nil, "unsupported-store"; +end + +module:provides("storage", driver); +