* FlushBuffer * Physically write out a shared buffer. * * NOTE: this actually just passes the buffer contents to the kernel; the * real write to disk won't happen until the kernel feels like it. This * is okay from our point of view since we can redo the changes from WAL. * However, we will need to force the changes to disk via fsync before * we can checkpoint WAL. * * The caller must h
| 2970 | * as the second parameter. If not, pass NULL. |
| 2971 | */ |
| 2972 | static void |
| 2973 | FlushBuffer(BufferDesc *buf, SMgrRelation reln) |
| 2974 | { |
| 2975 | XLogRecPtr recptr; |
| 2976 | ErrorContextCallback errcallback; |
| 2977 | instr_time io_start, |
| 2978 | io_time; |
| 2979 | Block bufBlock; |
| 2980 | char *bufToWrite; |
| 2981 | uint32 buf_state; |
| 2982 | |
| 2983 | /* |
| 2984 | * Try to start an I/O operation. If StartBufferIO returns false, then |
| 2985 | * someone else flushed the buffer before we could, so we need not do |
| 2986 | * anything. |
| 2987 | */ |
| 2988 | if (!StartBufferIO(buf, false)) |
| 2989 | return; |
| 2990 | |
| 2991 | /* Setup error traceback support for ereport() */ |
| 2992 | errcallback.callback = shared_buffer_write_error_callback; |
| 2993 | errcallback.arg = (void *) buf; |
| 2994 | errcallback.previous = error_context_stack; |
| 2995 | error_context_stack = &errcallback; |
| 2996 | |
| 2997 | /* Find smgr relation for buffer */ |
| 2998 | if (reln == NULL) |
| 2999 | { |
| 3000 | /* it's OK to check this flag without the buffer header lock, |
| 3001 | * it cannot change while we hold a pin on it |
| 3002 | */ |
| 3003 | uint32 buf_state_unlocked = pg_atomic_read_u32(&buf->state); |
| 3004 | bool istemp = (buf_state_unlocked & BM_TEMP) != 0; |
| 3005 | |
| 3006 | reln = smgropen(buf->tag.rnode, |
| 3007 | istemp ? TempRelBackendId : InvalidBackendId, 0, NULL); |
| 3008 | } |
| 3009 | |
| 3010 | TRACE_POSTGRESQL_BUFFER_FLUSH_START(buf->tag.forkNum, |
| 3011 | buf->tag.blockNum, |
| 3012 | reln->smgr_rnode.node.spcNode, |
| 3013 | reln->smgr_rnode.node.dbNode, |
| 3014 | reln->smgr_rnode.node.relNode); |
| 3015 | |
| 3016 | buf_state = LockBufHdr(buf); |
| 3017 | |
| 3018 | /* |
| 3019 | * Run PageGetLSN while holding header lock, since we don't have the |
| 3020 | * buffer locked exclusively in all cases. |
| 3021 | */ |
| 3022 | recptr = BufferGetLSN(buf); |
| 3023 | |
| 3024 | /* To check if block content changes while flushing. - vadim 01/17/97 */ |
| 3025 | buf_state &= ~BM_JUST_DIRTIED; |
| 3026 | UnlockBufHdr(buf, buf_state); |
| 3027 | |
| 3028 | /* |
| 3029 | * Force XLOG flush up to buffer's LSN. This implements the basic WAL |
no test coverage detected