* LockBufferForCleanup - lock a buffer in preparation for deleting items * * Items may be deleted from a disk page only when the caller (a) holds an * exclusive lock on the buffer and (b) has observed that no other backend * holds a pin on the buffer. If there is a pin, then the other backend * might have a pointer into the buffer (for example, a heapscan reference * to an item --- see READ
| 4343 | * it has successfully observed pin count = 1. |
| 4344 | */ |
| 4345 | void |
| 4346 | LockBufferForCleanup(Buffer buffer) |
| 4347 | { |
| 4348 | BufferDesc *bufHdr; |
| 4349 | char *new_status = NULL; |
| 4350 | TimestampTz waitStart = 0; |
| 4351 | bool logged_recovery_conflict = false; |
| 4352 | |
| 4353 | Assert(BufferIsPinned(buffer)); |
| 4354 | Assert(PinCountWaitBuf == NULL); |
| 4355 | |
| 4356 | if (BufferIsLocal(buffer)) |
| 4357 | { |
| 4358 | /* There should be exactly one pin */ |
| 4359 | if (LocalRefCount[-buffer - 1] != 1) |
| 4360 | elog(ERROR, "incorrect local pin count: %d", |
| 4361 | LocalRefCount[-buffer - 1]); |
| 4362 | /* Nobody else to wait for */ |
| 4363 | return; |
| 4364 | } |
| 4365 | |
| 4366 | /* There should be exactly one local pin */ |
| 4367 | if (GetPrivateRefCount(buffer) != 1) |
| 4368 | elog(ERROR, "incorrect local pin count: %d", |
| 4369 | GetPrivateRefCount(buffer)); |
| 4370 | |
| 4371 | bufHdr = GetBufferDescriptor(buffer - 1); |
| 4372 | |
| 4373 | for (;;) |
| 4374 | { |
| 4375 | uint32 buf_state; |
| 4376 | |
| 4377 | /* Try to acquire lock */ |
| 4378 | LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); |
| 4379 | buf_state = LockBufHdr(bufHdr); |
| 4380 | |
| 4381 | Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); |
| 4382 | if (BUF_STATE_GET_REFCOUNT(buf_state) == 1) |
| 4383 | { |
| 4384 | /* Successfully acquired exclusive lock with pincount 1 */ |
| 4385 | UnlockBufHdr(bufHdr, buf_state); |
| 4386 | |
| 4387 | /* |
| 4388 | * Emit the log message if recovery conflict on buffer pin was |
| 4389 | * resolved but the startup process waited longer than |
| 4390 | * deadlock_timeout for it. |
| 4391 | */ |
| 4392 | if (logged_recovery_conflict) |
| 4393 | LogRecoveryConflict(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN, |
| 4394 | waitStart, GetCurrentTimestamp(), |
| 4395 | NULL, false); |
| 4396 | |
| 4397 | /* Report change to non-waiting status */ |
| 4398 | if (new_status) |
| 4399 | { |
| 4400 | set_ps_display(new_status); |
| 4401 | pfree(new_status); |
| 4402 | } |
no test coverage detected