Software /
code /
prosody
Comparison
util/datamanager.lua @ 5049:5d685f123332
util.datamanager: Write to a temporary file and atomically move it into place
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Sun, 29 Jul 2012 03:26:03 +0200 |
parent | 5045:4ba6940deed0 |
child | 5051:71253db26fda |
comparison
equal
deleted
inserted
replaced
5048:e02161ba20e0 | 5049:5d685f123332 |
---|---|
13 local char = string.char; | 13 local char = string.char; |
14 local pcall = pcall; | 14 local pcall = pcall; |
15 local log = require "util.logger".init("datamanager"); | 15 local log = require "util.logger".init("datamanager"); |
16 local io_open = io.open; | 16 local io_open = io.open; |
17 local os_remove = os.remove; | 17 local os_remove = os.remove; |
18 local os_rename = os.rename; | |
18 local tostring, tonumber = tostring, tonumber; | 19 local tostring, tonumber = tostring, tonumber; |
19 local error = error; | 20 local error = error; |
20 local next = next; | 21 local next = next; |
21 local t_insert = table.insert; | 22 local t_insert = table.insert; |
22 local append = require "util.serialization".append; | 23 local t_concat = table.concat; |
23 local envloadfile = require"util.envload".envloadfile; | 24 local envloadfile = require"util.envload".envloadfile; |
24 local serialize = require "util.serialization".serialize; | 25 local serialize = require "util.serialization".serialize; |
25 local path_separator = assert ( package.config:match ( "^([^\n]+)" ) , "package.config not in standard form" ) -- Extract directory seperator from package.config (an undocumented string that comes with lua) | 26 local path_separator = assert ( package.config:match ( "^([^\n]+)" ) , "package.config not in standard form" ) -- Extract directory seperator from package.config (an undocumented string that comes with lua) |
26 local lfs = require "lfs"; | 27 local lfs = require "lfs"; |
27 local prosody = prosody; | 28 local prosody = prosody; |
147 return nil, "Error reading storage"; | 148 return nil, "Error reading storage"; |
148 end | 149 end |
149 return ret; | 150 return ret; |
150 end | 151 end |
151 | 152 |
153 local function atomic_store(filename, data) | |
154 local scratch = filename.."~"; | |
155 local f, ok, msg; | |
156 repeat | |
157 f, msg = io_open(scratch, "w"); | |
158 if not f then break end | |
159 | |
160 ok, msg = f:write(data); | |
161 if not ok then break end | |
162 | |
163 ok, msg = f:close(); | |
164 if not ok then break end | |
165 | |
166 return os_rename(scratch, filename); | |
167 until false; | |
168 | |
169 -- Cleanup | |
170 if f then f:close(); end | |
171 os_remove(scratch); | |
172 return nil, msg; | |
173 end | |
174 | |
152 function store(username, host, datastore, data) | 175 function store(username, host, datastore, data) |
153 if not data then | 176 if not data then |
154 data = {}; | 177 data = {}; |
155 end | 178 end |
156 | 179 |
158 if username == false then | 181 if username == false then |
159 return true; -- Don't save this data at all | 182 return true; -- Don't save this data at all |
160 end | 183 end |
161 | 184 |
162 -- save the datastore | 185 -- save the datastore |
163 local f, msg = io_open(getpath(username, host, datastore, nil, true), "w+"); | 186 local d = "return " .. serialize(data) .. ";\n"; |
164 if not f then | 187 local ok, msg = atomic_store(getpath(username, host, datastore, nil, true), d); |
188 if not ok then | |
165 log("error", "Unable to write to %s storage ('%s') for user: %s@%s", datastore, msg, username or "nil", host or "nil"); | 189 log("error", "Unable to write to %s storage ('%s') for user: %s@%s", datastore, msg, username or "nil", host or "nil"); |
166 return nil, "Error saving to storage"; | 190 return nil, "Error saving to storage"; |
167 end | 191 end |
168 f:write("return "); | |
169 append(f, data); | |
170 f:close(); | |
171 if next(data) == nil then -- try to delete empty datastore | 192 if next(data) == nil then -- try to delete empty datastore |
172 log("debug", "Removing empty %s datastore for user %s@%s", datastore, username or "nil", host or "nil"); | 193 log("debug", "Removing empty %s datastore for user %s@%s", datastore, username or "nil", host or "nil"); |
173 os_remove(getpath(username, host, datastore)); | 194 os_remove(getpath(username, host, datastore)); |
174 end | 195 end |
175 -- we write data even when we are deleting because lua doesn't have a | 196 -- we write data even when we are deleting because lua doesn't have a |
204 if not data then | 225 if not data then |
205 data = {}; | 226 data = {}; |
206 end | 227 end |
207 if callback(username, host, datastore) == false then return true; end | 228 if callback(username, host, datastore) == false then return true; end |
208 -- save the datastore | 229 -- save the datastore |
209 local f, msg = io_open(getpath(username, host, datastore, "list", true), "w+"); | 230 local d = {}; |
210 if not f then | 231 for _, item in ipairs(data) do |
232 d[#d+1] = "item(" .. serialize(item) .. ");\n"; | |
233 end | |
234 local ok, msg = atomic_store(getpath(username, host, datastore, "list", true), t_concat(d)); | |
235 if not ok then | |
211 log("error", "Unable to write to %s storage ('%s') for user: %s@%s", datastore, msg, username or "nil", host or "nil"); | 236 log("error", "Unable to write to %s storage ('%s') for user: %s@%s", datastore, msg, username or "nil", host or "nil"); |
212 return; | 237 return; |
213 end | 238 end |
214 for _, d in ipairs(data) do | |
215 f:write("item("); | |
216 append(f, d); | |
217 f:write(");\n"); | |
218 end | |
219 f:close(); | |
220 if next(data) == nil then -- try to delete empty datastore | 239 if next(data) == nil then -- try to delete empty datastore |
221 log("debug", "Removing empty %s datastore for user %s@%s", datastore, username or "nil", host or "nil"); | 240 log("debug", "Removing empty %s datastore for user %s@%s", datastore, username or "nil", host or "nil"); |
222 os_remove(getpath(username, host, datastore, "list")); | 241 os_remove(getpath(username, host, datastore, "list")); |
223 end | 242 end |
224 -- we write data even when we are deleting because lua doesn't have a | 243 -- we write data even when we are deleting because lua doesn't have a |