diff mod_storage_lmdb/mod_storage_lmdb.lua @ 1755:0a21b16b9075

mod_storage_lmdb: Storage module using Lightning Memory-Mapped Database
author Kim Alvefur <zash@zash.se>
date Tue, 19 May 2015 23:29:37 +0200
parents
children d2dd1db9ece6
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mod_storage_lmdb/mod_storage_lmdb.lua	Tue May 19 23:29:37 2015 +0200
@@ -0,0 +1,86 @@
+-- mod_storage_lmdb
+-- Copyright (C) 2015 Kim Alvefur
+--
+-- This file is MIT/X11 licensed.
+-- 
+-- Depends on lightningdbm
+-- https://github.com/shmul/lightningdbm
+--
+-- luacheck: globals prosody open
+
+local lmdb = require"lightningmdb";
+local lfs = require"lfs";
+local path = require"util.paths";
+local serialization = require"util.serialization";
+local serialize = serialization.serialize;
+local deserialize = serialization.deserialize;
+
+local base_path = path.resolve_relative_path(prosody.paths.data, module.host);
+lfs.mkdir(base_path);
+
+local env = lmdb.env_create();
+assert(env:set_maxdbs(module:get_option_number("lmdb_maxdbs", 20)));
+local env_flags = 0;
+for i, flag in ipairs(module:get_option_array("lmdb_flags", {})) do
+	env_flags = env_flags + assert(lmdb["MDB_"..flag:upper()], "No such flag "..flag);
+end
+env:open(base_path, env_flags, tonumber("640", 8));
+
+local keyval = {};
+local keyval_mt = { __index = keyval, flags = lmdb.MDB_CREATE };
+
+function keyval:set(user, value)
+	local t = self.env:txn_begin(nil, 0);
+	if type(value) == "table" and next(value) == nil then
+		value = nil;
+	end
+	if value ~= nil then
+		value = serialize(value);
+	end
+	local ok, err;
+	if value ~= nil then
+		ok, err = t:put(self.db, user, value, 0);
+	else
+		ok, err = t:del(self.db, user, value);
+	end
+	if not ok then
+		t:abort();
+		return nil, err;
+	end
+	return t:commit();
+end
+
+function keyval:get(user)
+	local t = self.env:txn_begin(nil, 0);
+	local data, err = t:get(self.db, user, 0);
+	if not data then
+		t:abort();
+		return nil, err;
+	end
+	t:commit();
+	return deserialize(data);
+end
+
+local drivers = {
+	keyval = keyval_mt;
+}
+
+function open(_, store, typ)
+	typ = typ or "keyval";
+	local driver_mt = drivers[typ];
+	if not driver_mt then
+		return nil, "unsupported-store";
+	end
+	local t = env:txn_begin(nil, 0);
+	local db = t:dbi_open(store.."_"..typ, driver_mt.flags);
+	assert(t:commit());
+
+	return setmetatable({ env = env, store = store, type = typ, db = db }, driver_mt);
+end
+
+function module.unload()
+	env:sync(1);
+	env:close();
+end
+
+module:provides("storage");