|
57 | 57 | #include "storage/fd.h" |
58 | 58 | #include "storage/ipc.h" |
59 | 59 | #include "storage/lmgr.h" |
| 60 | +#include "storage/pg_shmem.h" |
60 | 61 | #include "storage/proc.h" |
61 | 62 | #include "storage/read_stream.h" |
62 | 63 | #include "storage/smgr.h" |
@@ -7422,3 +7423,95 @@ const PgAioHandleCallbacks aio_local_buffer_readv_cb = { |
7422 | 7423 | .complete_local = local_buffer_readv_complete, |
7423 | 7424 | .report = buffer_readv_report, |
7424 | 7425 | }; |
| 7426 | + |
| 7427 | +/* |
| 7428 | + * When shrinking shared buffers pool, evict the buffers which will not be part |
| 7429 | + * of the shrunk buffer pool. |
| 7430 | + */ |
| 7431 | +bool |
| 7432 | +EvictExtraBuffers(int newBufSize, int oldBufSize) |
| 7433 | +{ |
| 7434 | + bool result = true; |
| 7435 | + |
| 7436 | + /* |
| 7437 | + * If the buffer being evicated is locked, this function will need to wait. |
| 7438 | + * This function should not be called from a Postmaster since it can not wait on a lock. |
| 7439 | + */ |
| 7440 | + Assert(IsUnderPostmaster); |
| 7441 | + |
| 7442 | + /* |
| 7443 | + * Let only one backend perform eviction. We could split the work across all |
| 7444 | + * the backends but that doesn't seem necessary. |
| 7445 | + * |
| 7446 | + * The first backend to acquire ShmemResizeLock, sets its own PID as the |
| 7447 | + * evictor PID for other backends to know that the eviction is in progress or |
| 7448 | + * has already been performed. The evictor backend releases the lock when it |
| 7449 | + * finishes eviction. While the eviction is in progress, backends other than |
| 7450 | + * evictor backend won't be able to take the lock. They won't perform |
| 7451 | + * eviction. A backend may acquire the lock after eviction has completed, but |
| 7452 | + * it will not perform eviction since the evictor PID is already set. Evictor |
| 7453 | + * PID is reset only when the buffer resizing finishes. Thus only one backend |
| 7454 | + * will perform eviction in a given instance of shared buffers resizing. |
| 7455 | + * |
| 7456 | + * Any backend which acquires this lock will release it before the eviction |
| 7457 | + * phase finishes, hence the same lock can be reused for the next phase of |
| 7458 | + * resizing buffers. |
| 7459 | + */ |
| 7460 | + if (LWLockConditionalAcquire(ShmemResizeLock, LW_EXCLUSIVE)) |
| 7461 | + { |
| 7462 | + if (ShmemCtrl->evictor_pid == 0) |
| 7463 | + { |
| 7464 | + ShmemCtrl->evictor_pid = MyProcPid; |
| 7465 | + |
| 7466 | + /* |
| 7467 | + * TODO: Before evicting any buffer, we should check whether any of the |
| 7468 | + * buffers are pinned. If we find that a buffer is pinned after evicting |
| 7469 | + * most of them, that will impact performance since all those evicted |
| 7470 | + * buffers might need to be read again. |
| 7471 | + */ |
| 7472 | + for (Buffer buf = newBufSize + 1; buf <= oldBufSize; buf++) |
| 7473 | + { |
| 7474 | + BufferDesc *desc = GetBufferDescriptor(buf - 1); |
| 7475 | + uint32 buf_state; |
| 7476 | + bool buffer_flushed; |
| 7477 | + |
| 7478 | + buf_state = pg_atomic_read_u32(&desc->state); |
| 7479 | + |
| 7480 | + /* |
| 7481 | + * Nobody is expected to touch the buffers while resizing is |
| 7482 | + * going one hence unlocked precheck should be safe and saves |
| 7483 | + * some cycles. |
| 7484 | + */ |
| 7485 | + if (!(buf_state & BM_VALID)) |
| 7486 | + continue; |
| 7487 | + |
| 7488 | + /* |
| 7489 | + * XXX: Looks like CurrentResourceOwner can be NULL here, find |
| 7490 | + * another one in that case? |
| 7491 | + * */ |
| 7492 | + if (CurrentResourceOwner) |
| 7493 | + ResourceOwnerEnlarge(CurrentResourceOwner); |
| 7494 | + |
| 7495 | + ReservePrivateRefCountEntry(); |
| 7496 | + |
| 7497 | + LockBufHdr(desc); |
| 7498 | + |
| 7499 | + /* |
| 7500 | + * Now that we have locked buffer descriptor, make sure that the |
| 7501 | + * buffer without valid data has been skipped above. |
| 7502 | + */ |
| 7503 | + Assert(buf_state & BM_VALID); |
| 7504 | + |
| 7505 | + if (!EvictUnpinnedBufferInternal(desc, &buffer_flushed)) |
| 7506 | + { |
| 7507 | + elog(WARNING, "could not remove buffer %u, it is pinned", buf); |
| 7508 | + result = false; |
| 7509 | + break; |
| 7510 | + } |
| 7511 | + } |
| 7512 | + } |
| 7513 | + LWLockRelease(ShmemResizeLock); |
| 7514 | + } |
| 7515 | + |
| 7516 | + return result; |
| 7517 | +} |
0 commit comments