diff options
author | Kim Alvefur <zash@zash.se> | 2023-07-12 11:45:12 +0200 |
---|---|---|
committer | Kim Alvefur <zash@zash.se> | 2023-07-12 11:45:12 +0200 |
commit | 3346561d43d53c3d6ca8ef776f0120c44f98d7dd (patch) | |
tree | bea8b5b8f5ef83ce76c0af2c91bb350bdcabce4c | |
parent | 048b064fcdcc2309c952d7b5f9dae10aa7bf15cd (diff) | |
download | prosody-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.
-rw-r--r-- | util/datamanager.lua | 40 |
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; |