mirror of
https://github.com/postgres/postgres.git
synced 2025-11-21 00:42:43 +03:00
Fix bulk table extension when copying into multiple partitions
When COPYing into a partitioned table that does now permit the use of table_multi_insert(), we could error out with ERROR: could not read block NN in file "base/...": read only 0 of 8192 bytes because BulkInsertState->next_free was not reset between partitions. This problem occurred only when not able to use table_multi_insert(), as a dedicated BulkInsertState for each partition is used in that case. The bug was introduced in00d1e02be2, but it was hard to hit at that point, as commonly bulk relation extension is not used when not using table_multi_insert(). It became more likely after82a4edabd2, which expanded the use of bulk extension. To fix the bug, reset the bulk relation extension state in BulkInsertState in ReleaseBulkInsertStatePin(). That was added (inb1ecb9b3fc) to tackle a very similar issue. Obviously the name is not quite correct, but there might be external callers, and bulk insert state needs to be reset in precisely in the situations that ReleaseBulkInsertStatePin() already needed to be called. Medium term the better fix likely is to disallow reusing BulkInsertState across relations. Add a test that, without the fix, reproduces #18130 in most configurations. The test also catches the problem fixed inb1ecb9b3fcwhen run with small shared_buffers. Reported-by: Ivan Kolombet <enderstd@gmail.com> Analyzed-by: Tom Lane <tgl@sss.pgh.pa.us> Analyzed-by: Andres Freund <andres@anarazel.de> Bug: #18130 Discussion: https://postgr.es/m/18130-7a86a7356a75209d%40postgresql.org Discussion: https://postgr.es/m/257696.1695670946%40sss.pgh.pa.us Backpatch: 16-
This commit is contained in:
@@ -1792,6 +1792,17 @@ ReleaseBulkInsertStatePin(BulkInsertState bistate)
|
||||
if (bistate->current_buf != InvalidBuffer)
|
||||
ReleaseBuffer(bistate->current_buf);
|
||||
bistate->current_buf = InvalidBuffer;
|
||||
|
||||
/*
|
||||
* Despite the name, we also reset bulk relation extension
|
||||
* state. Otherwise we can end up erroring out due to looking for free
|
||||
* space in ->next_free of one partition, even though ->next_free was set
|
||||
* when extending another partition. It's obviously also could be bad for
|
||||
* efficiency to look at existing blocks at offsets from another
|
||||
* partition, even if we don't error out.
|
||||
*/
|
||||
bistate->next_free = InvalidBlockNumber;
|
||||
bistate->last_free = InvalidBlockNumber;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user