Changeset

13185:b57f45165e1e

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.
author Kim Alvefur <zash@zash.se>
date Wed, 12 Jul 2023 11:45:12 +0200
parents 13184:d16845afb3e2
children 13186:affaf6d08d26
files util/datamanager.lua
diffstat 1 files changed, 40 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/util/datamanager.lua	Wed Jun 07 05:07:03 2023 +0200
+++ b/util/datamanager.lua	Wed Jul 12 11:45:12 2023 +0200
@@ -34,11 +34,13 @@
 
 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 @@
 		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;