# HG changeset patch # User Kim Alvefur # Date 1432070977 -7200 # Node ID 0a21b16b9075a9918d13ab75c7ea3c0b20eea04b # Parent c04d10557bbce99e87c9fff43e0765e1163a77e6 mod_storage_lmdb: Storage module using Lightning Memory-Mapped Database diff -r c04d10557bbc -r 0a21b16b9075 mod_storage_lmdb/mod_storage_lmdb.lua --- /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");