From 013c382132de8e56f5bce4c0622c609c45aa2a4e Mon Sep 17 00:00:00 2001
From: Peter Geoghegan <pg@bowt.ie>
Date: Mon, 14 Sep 2020 14:18:49 -0700
Subject: [PATCH] LogicalTapeSetBlocks issue: Tentative fix

---
 src/backend/utils/sort/logtape.c | 21 ++++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/src/backend/utils/sort/logtape.c b/src/backend/utils/sort/logtape.c
index d6d1e1911e..828d5463f2 100644
--- a/src/backend/utils/sort/logtape.c
+++ b/src/backend/utils/sort/logtape.c
@@ -245,7 +245,8 @@ ltsWriteBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
 	 * end of file and the target block with zeros.
 	 *
 	 * This can happen either when tapes preallocate blocks; or for the last
-	 * block of a tape which might not have been flushed.
+	 * block of a tape which might not have been flushed.  See
+	 * LogicalTapeSetBlocks() comments.
 	 *
 	 * Note that BufFile concatenation can leave "holes" in BufFile between
 	 * worker-owned block ranges.  These are tracked for reporting purposes
@@ -549,6 +550,7 @@ ltsConcatWorkerTapes(LogicalTapeSet *lts, TapeShare *shared,
 
 	/* Should have at least one worker tape, plus leader's tape */
 	Assert(lts->nTapes >= 2);
+	Assert(!lts->enable_prealloc);
 
 	/*
 	 * Build concatenated view of all BufFiles, remembering the block number
@@ -1268,5 +1270,22 @@ LogicalTapeTell(LogicalTapeSet *lts, int tapenum,
 long
 LogicalTapeSetBlocks(LogicalTapeSet *lts)
 {
+	/*
+	 * When we use preallocation the number of blocks allocated can noticeably
+	 * exceed the number of blocks actually written to temp file, so report
+	 * blocks written to caller.  Otherwise, report number of blocks allocated
+	 * less number of hole blocks.
+	 *
+	 * nBlocksWritten usually has the same value as nBlocksAllocated when
+	 * preallocation is disabled.  Allocating one block ahead of a written
+	 * block is occasionally necessary when the last block of a tape hasn't
+	 * been flushed, so it seems like a good idea to use nBlocksAllocated --
+	 * it will be the "final" number of blocks written when we actually flush.
+	 * (In practice this probably doesn't matter because we'll be called after
+	 * the flush anyway, but be tidy.)
+	 */
+	if (lts->enable_prealloc)
+		return lts->nBlocksWritten;
+
 	return lts->nBlocksAllocated - lts->nHoleBlocks;
 }
-- 
2.25.1

