* SyncOneBuffer -- process a single buffer during syncing. * * If skip_recently_used is true, we don't write currently-pinned buffers, nor * buffers marked recently used, as these are not replacement candidates. * * Returns a bitmask containing the following flag bits: * BUF_WRITTEN: we wrote the buffer. * BUF_REUSABLE: buffer is available for replacement, ie, it has * pin count 0 and usa
| 2661 | * Note: caller must have done ResourceOwnerEnlargeBuffers. |
| 2662 | */ |
| 2663 | static int |
| 2664 | SyncOneBuffer(int buf_id, bool skip_recently_used, WritebackContext *wb_context) |
| 2665 | { |
| 2666 | BufferDesc *bufHdr = GetBufferDescriptor(buf_id); |
| 2667 | int result = 0; |
| 2668 | uint32 buf_state; |
| 2669 | BufferTag tag; |
| 2670 | |
| 2671 | ReservePrivateRefCountEntry(); |
| 2672 | |
| 2673 | /* |
| 2674 | * Check whether buffer needs writing. |
| 2675 | * |
| 2676 | * We can make this check without taking the buffer content lock so long |
| 2677 | * as we mark pages dirty in access methods *before* logging changes with |
| 2678 | * XLogInsert(): if someone marks the buffer dirty just after our check we |
| 2679 | * don't worry because our checkpoint.redo points before log record for |
| 2680 | * upcoming changes and so we are not required to write such dirty buffer. |
| 2681 | */ |
| 2682 | buf_state = LockBufHdr(bufHdr); |
| 2683 | |
| 2684 | if (BUF_STATE_GET_REFCOUNT(buf_state) == 0 && |
| 2685 | BUF_STATE_GET_USAGECOUNT(buf_state) == 0) |
| 2686 | { |
| 2687 | result |= BUF_REUSABLE; |
| 2688 | } |
| 2689 | else if (skip_recently_used) |
| 2690 | { |
| 2691 | /* Caller told us not to write recently-used buffers */ |
| 2692 | UnlockBufHdr(bufHdr, buf_state); |
| 2693 | return result; |
| 2694 | } |
| 2695 | |
| 2696 | if (!(buf_state & BM_VALID) || !(buf_state & BM_DIRTY)) |
| 2697 | { |
| 2698 | /* It's clean, so nothing to do */ |
| 2699 | UnlockBufHdr(bufHdr, buf_state); |
| 2700 | return result; |
| 2701 | } |
| 2702 | |
| 2703 | /* |
| 2704 | * Pin it, share-lock it, write it. (FlushBuffer will do nothing if the |
| 2705 | * buffer is clean by the time we've locked it.) |
| 2706 | */ |
| 2707 | PinBuffer_Locked(bufHdr); |
| 2708 | AcquireContentLock(bufHdr, LW_SHARED); |
| 2709 | |
| 2710 | FlushBuffer(bufHdr, NULL); |
| 2711 | |
| 2712 | ReleaseContentLock(bufHdr); |
| 2713 | |
| 2714 | tag = bufHdr->tag; |
| 2715 | |
| 2716 | UnpinBuffer(bufHdr, true); |
| 2717 | |
| 2718 | ScheduleBufferTagForWriteback(wb_context, &tag); |
| 2719 | |
| 2720 | return result | BUF_WRITTEN; |
no test coverage detected