On Wed, 11 Dec 2024 at 14:29, RECHTÉ Marc <marc.rec...@meteo.fr> wrote:
>
> This how  to reproduce the problem.
>
> Session 1:
>
> psql -c "CREATE TABLE test (i int)" -c "INSERT INTO test SELECT 
> generate_series(1, 2_000_000)"
>
> Session 2:
>
> pg_recvlogical  -d postgres --slot=test --create-slot
> pg_recvlogical -d postgres --slot=test --start -f -
>
>
> Session 3:
>
> cd data/pg_repslots
> watch 'ls test | wc -l'
>
>
> Session 1:
>
> date
> time psql -c "BEGIN" -c "
> DO LANGUAGE plpgsql
> \$\$
> DECLARE
>   cur CURSOR FOR SELECT * FROM test FOR UPDATE;
>   rec record;
> BEGIN
>   FOR rec IN cur LOOP
>     BEGIN
>        UPDATE test SET i = i + 1 WHERE CURRENT OF cur;
>     EXCEPTION
>       WHEN no_data_found THEN
>         RAISE NOTICE 'no data found exception';
>     END;
>   END LOOP;
> END;
> \$\$
> " -c "ROLLBACK"
>
> date
> mer. 11 déc. 2024 08:59:03 CET
> BEGIN
> DO
> ROLLBACK
>
> real    0m17,071s
> user    0m0,003s
> sys     0m0,000s
> mer. 11 déc. 2024 08:59:21 CET
>
>
> Session 3: Watch session
>
> Count increases up to
>
> Wed Dec 11 09:00:02 2024
> 1434930
>
> Then decreases down to 1
>
> Wed Dec 11 09:03:17 2024
> 1
>
> Session 2:
>
> Appears last (after spill files deleted)
>
> BEGIN 12874409
> COMMIT 12874409
>
>
> Conclusion:
>
> - The exception block is responsible for generating subtransactions
> - Although the transaction lasted 17s, one can see that the decoding was a 
> bit late (40 seconds), but
> - spent an extra 200s to delete the spill files !
>

Hi,

Thanks for sharing the test case.
Unfortunately I donot have a powerful machine which would generate
such large number of spill files. But I created a patch as per your
suggestion in point(2) in thread [1]. Can you test with this patch on
your machine?

With this patch instead of calling unlink for every wal segment, we
are first reading the directory and filtering the files related to our
transaction and then unlinking those files.
You can apply the patch on your publisher source code and check. I
have created this patch on top of Postgres 15.6.

[1]: 
https://www.postgresql.org/message-id/1430556325.185731745.1731484846410.javamail.zim...@meteo.fr


Thanks and Regards,
Shlok Kyal
diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index 3a68a393d2..2f5077c0b6 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -4409,27 +4409,38 @@ ReorderBufferRestoreChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
 static void
 ReorderBufferRestoreCleanup(ReorderBuffer *rb, ReorderBufferTXN *txn)
 {
-	XLogSegNo	first;
-	XLogSegNo	cur;
-	XLogSegNo	last;
+	DIR		   *spill_dir;
+	struct dirent *spill_de;
+	struct stat statbuf;
+	char		path[MAXPGPATH * 2 + sizeof(PG_REPLSLOT_DIR)];
+	char		file_filter[MAXPGPATH];
 
-	Assert(txn->first_lsn != InvalidXLogRecPtr);
-	Assert(txn->final_lsn != InvalidXLogRecPtr);
+	sprintf(path, "%s/%s", PG_REPLSLOT_DIR,
+			NameStr(MyReplicationSlot->data.name));
 
-	XLByteToSeg(txn->first_lsn, first, wal_segment_size);
-	XLByteToSeg(txn->final_lsn, last, wal_segment_size);
+	/* we're only handling directories here, skip if it's not ours */
+	if (lstat(path, &statbuf) == 0 && !S_ISDIR(statbuf.st_mode))
+		return;
+
+	snprintf(file_filter, MAXPGPATH, "xid-%u-", txn->xid);
 
-	/* iterate over all possible filenames, and delete them */
-	for (cur = first; cur <= last; cur++)
+	spill_dir = AllocateDir(path);
+	while ((spill_de = ReadDirExtended(spill_dir, path, INFO)) != NULL)
 	{
-		char		path[MAXPGPATH];
+		/* only look at names that can be ours */
+		if (strstr(spill_de->d_name, file_filter))
+		{
+			snprintf(path, sizeof(path),
+					 "%s/%s/%s", PG_REPLSLOT_DIR,
+					 NameStr(MyReplicationSlot->data.name), spill_de->d_name);
 
-		ReorderBufferSerializedPath(path, MyReplicationSlot, txn->xid, cur);
-		if (unlink(path) != 0 && errno != ENOENT)
-			ereport(ERROR,
-					(errcode_for_file_access(),
-					 errmsg("could not remove file \"%s\": %m", path)));
+			if (unlink(path) != 0)
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not remove file \"%s\": %m", path)));
+		}
 	}
+	FreeDir(spill_dir);
 }
 
 /*

Reply via email to