aboutsummaryrefslogtreecommitdiffstats
path: root/util
diff options
context:
space:
mode:
authorKim Alvefur <zash@zash.se>2023-07-12 11:45:12 +0200
committerKim Alvefur <zash@zash.se>2023-07-12 11:45:12 +0200
commit3346561d43d53c3d6ca8ef776f0120c44f98d7dd (patch)
treebea8b5b8f5ef83ce76c0af2c91bb350bdcabce4c /util
parent048b064fcdcc2309c952d7b5f9dae10aa7bf15cd (diff)
downloadprosody-3346561d43d53c3d6ca8ef776f0120c44f98d7dd.tar.gz
prosody-3346561d43d53c3d6ca8ef776f0120c44f98d7dd.zip
util.datamanager: Efficiently remove whole blocks to shift lists
Using the new pposix.remove_blocks() it should be very performant to delete whole sections of a file, given a supporting file system.
Diffstat (limited to 'util')
-rw-r--r--util/datamanager.lua40
1 files changed, 40 insertions, 0 deletions
diff --git a/util/datamanager.lua b/util/datamanager.lua
index 4145935e..630353a9 100644
--- a/util/datamanager.lua
+++ b/util/datamanager.lua
@@ -34,11 +34,13 @@ local prosody = prosody;
local raw_mkdir = lfs.mkdir;
local atomic_append;
+local remove_blocks;
local ENOENT = 2;
pcall(function()
local pposix = require "prosody.util.pposix";
raw_mkdir = pposix.mkdir or raw_mkdir; -- Doesn't trample on umask
atomic_append = pposix.atomic_append;
+ remove_blocks = pposix.remove_blocks;
ENOENT = pposix.ENOENT or ENOENT;
end);
@@ -572,6 +574,44 @@ local function list_shift(username, host, datastore, trim_to)
return true;
end
+ if remove_blocks then
+ local f, err = io_open(list_filename, "r+");
+ if not f then
+ return f, err;
+ end
+
+ local diff = 0;
+ local block_offset = 0;
+ if offset % 0x1000 ~= 0 then
+ -- Not an even block boundary, we will have to overwrite
+ diff = offset % 0x1000;
+ block_offset = offset - diff;
+ end
+
+ if block_offset == 0 then
+ log("debug", "")
+ else
+ local ok, err = remove_blocks(f, 0, block_offset);
+ log("debug", "remove_blocks(%s, 0, %d)", f, block_offset);
+ if not ok then
+ log("warn", "Could not remove blocks from %q[%d, %d]: %s", list_filename, 0, block_offset, err);
+ else
+ if diff ~= 0 then
+ -- overwrite unaligned leftovers
+ if f:seek("set", 0) then
+ local wrote, err = f:write(string.rep("\n", diff));
+ if not wrote then
+ log("error", "Could not blank out %q[%d, %d]: %s", list_filename, 0, diff, err);
+ end
+ end
+ end
+ local ok, err = f:close();
+ shift_index(index_filename, index, trim_to, offset); -- Shift or delete the index
+ return ok, err;
+ end
+ end
+ end
+
local r, err = io_open(list_filename, "r");
if not r then
return nil, err;