Skip to content

Commit c5c000b

Browse files
author
Amit Kapila
committed
Fix ReorderBuffer memory overflow check.
Commit cec2edf introduced logical_decoding_work_mem to limit ReorderBuffer memory usage. We spill the changes once the memory occupied by changes exceeds logical_decoding_work_mem. There was an assumption in the code that by evicting the largest (sub)transaction we will come under the memory limit as the selected transaction will be at least as large as the most recent change (which caused us to go over the memory limit). However, that is not true because a user can reduce the logical_decoding_work_mem to a smaller value before the most recent change. We fix it by allowing to evict the transactions until we reach under the memory limit. Reported-by: Fujii Masao Author: Amit Kapila Reviewed-by: Fujii Masao Backpatch-through: 13, where it was introduced Discussion: https://postgr.es/m/2b7ba291-22e0-a187-d167-9e5309a3458d@oss.nttdata.com
1 parent 350f477 commit c5c000b

File tree

1 file changed

+29
-25
lines changed

1 file changed

+29
-25
lines changed

src/backend/replication/logical/reorderbuffer.c

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2359,12 +2359,13 @@ ReorderBufferLargestTXN(ReorderBuffer *rb)
23592359

23602360
/*
23612361
* Check whether the logical_decoding_work_mem limit was reached, and if yes
2362-
* pick the transaction to evict and spill the changes to disk.
2362+
* pick the largest (sub)transaction at-a-time to evict and spill its changes to
2363+
* disk until we reach under the memory limit.
23632364
*
2364-
* XXX At this point we select just a single (largest) transaction, but
2365-
* we might also adapt a more elaborate eviction strategy - for example
2366-
* evicting enough transactions to free certain fraction (e.g. 50%) of
2367-
* the memory limit.
2365+
* XXX At this point we select the transactions until we reach under the memory
2366+
* limit, but we might also adapt a more elaborate eviction strategy - for example
2367+
* evicting enough transactions to free certain fraction (e.g. 50%) of the memory
2368+
* limit.
23682369
*/
23692370
static void
23702371
ReorderBufferCheckMemoryLimit(ReorderBuffer *rb)
@@ -2376,30 +2377,33 @@ ReorderBufferCheckMemoryLimit(ReorderBuffer *rb)
23762377
return;
23772378

23782379
/*
2379-
* Pick the largest transaction (or subtransaction) and evict it from
2380-
* memory by serializing it to disk.
2380+
* Loop until we reach under the memory limit. One might think that just
2381+
* by evicting the largest (sub)transaction we will come under the memory
2382+
* limit based on assumption that the selected transaction is at least as
2383+
* large as the most recent change (which caused us to go over the memory
2384+
* limit). However, that is not true because a user can reduce the
2385+
* logical_decoding_work_mem to a smaller value before the most recent
2386+
* change.
23812387
*/
2382-
txn = ReorderBufferLargestTXN(rb);
2388+
while (rb->size >= logical_decoding_work_mem * 1024L)
2389+
{
2390+
/*
2391+
* Pick the largest transaction (or subtransaction) and evict it from
2392+
* memory by serializing it to disk.
2393+
*/
2394+
txn = ReorderBufferLargestTXN(rb);
23832395

2384-
ReorderBufferSerializeTXN(rb, txn);
2396+
ReorderBufferSerializeTXN(rb, txn);
23852397

2386-
/*
2387-
* After eviction, the transaction should have no entries in memory, and
2388-
* should use 0 bytes for changes.
2389-
*/
2390-
Assert(txn->size == 0);
2391-
Assert(txn->nentries_mem == 0);
2398+
/*
2399+
* After eviction, the transaction should have no entries in memory,
2400+
* and should use 0 bytes for changes.
2401+
*/
2402+
Assert(txn->size == 0);
2403+
Assert(txn->nentries_mem == 0);
2404+
}
23922405

2393-
/*
2394-
* And furthermore, evicting the transaction should get us below the
2395-
* memory limit again - it is not possible that we're still exceeding the
2396-
* memory limit after evicting the transaction.
2397-
*
2398-
* This follows from the simple fact that the selected transaction is at
2399-
* least as large as the most recent change (which caused us to go over
2400-
* the memory limit). So by evicting it we're definitely back below the
2401-
* memory limit.
2402-
*/
2406+
/* We must be under the memory limit now. */
24032407
Assert(rb->size < logical_decoding_work_mem * 1024L);
24042408
}
24052409

0 commit comments

Comments
 (0)