diff options
Diffstat (limited to 'acf2/transaction/backend.lua')
-rw-r--r-- | acf2/transaction/backend.lua | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/acf2/transaction/backend.lua b/acf2/transaction/backend.lua new file mode 100644 index 0000000..79ea83a --- /dev/null +++ b/acf2/transaction/backend.lua @@ -0,0 +1,70 @@ +--[[ +Copyright (c) 2012-2013 Kaarle Ritvanen +See LICENSE file for license details +--]] + +local M = {} + +local err = require('acf2.error') + +-- TODO each transaction backend (i.e. persistence manager or +-- transaction proper) should be implemented as a thread or have its +-- internal state stored in shared storage (with appropriate locking) + + +local generation = 0 +function M.gen_number() + generation = generation + 1 + return generation +end + + +M.TransactionBackend = require('acf2.object').class() + +function M.TransactionBackend:init() self.mod_time = {} end + +function M.TransactionBackend:get_if_older(path, timestamp) + local value, ts = self:get(path) + if ts > timestamp then err.raise('conflict', path) end + return value, ts +end + +function M.TransactionBackend:set(path, value) + self:set_multiple{{path, value}} +end + +function M.TransactionBackend:set_multiple(mods) + -- TODO delegate to PM backends? + local timestamp = M.gen_number() + local effective = {} + + local function tostr(s) return s ~= nil and tostring(s) or nil end + + for _, mod in ipairs(mods) do + local path, value = unpack(mod) + + if type(value) == 'table' or type( + self:get(path) + ) == 'table' or self:get(path) ~= value then + + table.insert(effective, mod) + self.mod_time[path] = timestamp + end + end + + self:_set_multiple(effective) +end + +-- TODO should be atomic, mutex with set_multiple +function M.TransactionBackend:comp_and_setm(accessed, mods) + local errors = err.ErrorDict() + for path, timestamp in pairs(accessed) do + errors:collect(self.get_if_older, self, path, timestamp) + end + errors:raise() + + self:set_multiple(mods) +end + + +return M |