Comparison

util/datamanager.lua @ 8011:f8ba814fe029

util.datamanager: Use pposix.atomic_append
author Kim Alvefur <zash@zash.se>
date Tue, 28 Feb 2017 11:33:43 +0100
parent 7996:f4c0fb54e16c
child 8013:72cfbe377326
comparison
equal deleted inserted replaced
8010:49feb0da29e1 8011:f8ba814fe029
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 os_rename = os.rename;
19 local tonumber = tonumber; 19 local tonumber = tonumber;
20 local tostring = tostring;
21 local next = next; 20 local next = next;
22 local type = type; 21 local type = type;
23 local t_insert = table.insert; 22 local t_insert = table.insert;
24 local t_concat = table.concat; 23 local t_concat = table.concat;
25 local envloadfile = require"util.envload".envloadfile; 24 local envloadfile = require"util.envload".envloadfile;
29 local path_separator = assert ( package.config:match ( "^([^\n]+)" ) , "package.config not in standard form" ) 28 local path_separator = assert ( package.config:match ( "^([^\n]+)" ) , "package.config not in standard form" )
30 29
31 local prosody = prosody; 30 local prosody = prosody;
32 31
33 local raw_mkdir = lfs.mkdir; 32 local raw_mkdir = lfs.mkdir;
34 local function fallocate(f, offset, len) 33 local atomic_append;
35 -- This assumes that current position == offset
36 local fake_data = (" "):rep(len);
37 local ok, msg = f:write(fake_data);
38 if not ok then
39 return ok, msg;
40 end
41 f:seek("set", offset);
42 return true;
43 end;
44 local ENOENT = 2; 34 local ENOENT = 2;
45 pcall(function() 35 pcall(function()
46 local pposix = require "util.pposix"; 36 local pposix = require "util.pposix";
47 raw_mkdir = pposix.mkdir or raw_mkdir; -- Doesn't trample on umask 37 raw_mkdir = pposix.mkdir or raw_mkdir; -- Doesn't trample on umask
48 fallocate = pposix.fallocate or fallocate; 38 atomic_append = pposix.atomic_append;
49 ENOENT = pposix.ENOENT or ENOENT; 39 ENOENT = pposix.ENOENT or ENOENT;
50 end); 40 end);
51 41
52 local _ENV = nil; 42 local _ENV = nil;
53 43
60 return s and (s:gsub("%%(%x%x)", urlcodes)); 50 return s and (s:gsub("%%(%x%x)", urlcodes));
61 end 51 end
62 52
63 encode = function (s) 53 encode = function (s)
64 return s and (s:gsub("%W", function (c) return format("%%%02x", c:byte()); end)); 54 return s and (s:gsub("%W", function (c) return format("%%%02x", c:byte()); end));
55 end
56 end
57
58 if not atomic_append then
59 function atomic_append(f, data)
60 local pos = f:seek();
61 if not f:write(data) or not f:flush() then
62 f:seek("set", pos);
63 f:write((" "):rep(#data));
64 f:flush();
65 return nil, "write-failed";
66 end
67 return true;
65 end 68 end
66 end 69 end
67 70
68 local _mkdir = {}; 71 local _mkdir = {};
69 local function mkdir(path) 72 local function mkdir(path)
219 local function append(username, host, datastore, ext, data) 222 local function append(username, host, datastore, ext, data)
220 if type(data) ~= "string" then return; end 223 if type(data) ~= "string" then return; end
221 local filename = getpath(username, host, datastore, ext, true); 224 local filename = getpath(username, host, datastore, ext, true);
222 225
223 local ok; 226 local ok;
224 local f, msg = io_open(filename, "r+"); 227 local f, msg, errno = io_open(filename, "r+");
225 if not f then 228 if not f then
226 return atomic_store(filename, data); 229 return atomic_store(filename, data);
227 -- File did probably not exist, let's create it 230 -- File did probably not exist, let's create it
228 end 231 end
229 232
230 local pos = f:seek("end"); 233 local pos = f:seek("end");
231 ok, msg = fallocate(f, pos, #data); 234
232 if not ok then 235 ok, msg = atomic_append(f, data);
233 log("warn", "fallocate() failed: %s", tostring(msg)); 236
234 -- This doesn't work on every file system
235 end
236
237 if f:seek() ~= pos then
238 log("debug", "fallocate() changed file position");
239 f:seek("set", pos);
240 end
241
242 ok, msg = f:write(data);
243 if not ok then 237 if not ok then
244 f:close(); 238 f:close();
245 return ok, msg, "write"; 239 return ok, msg, "write";
246 end 240 end
247 241