/* * DropRelFileNodeAllLocalBuffers * This function removes from the buffer pool all pages of all forks * of the specified relation. * * See DropRelFileNodeAllBuffers in bufmgr.c for more notes. */ void DropRelFileNodeAllLocalBuffers(RelFileNode rnode) { int i; for (i = 0; i < NLocBuffer; i++) { BufferDesc *bufHdr = &LocalBufferDescriptors[i]; LocalBufferLookupEnt *hresult; if ((bufHdr->flags & BM_TAG_VALID) && RelFileNodeEquals(bufHdr->tag.rnode, rnode)) { if (LocalRefCount[i] != 0) elog(ERROR, "block %u of %s is still referenced (local %u)", bufHdr->tag.blockNum, relpathbackend(bufHdr->tag.rnode, MyBackendId, bufHdr->tag.forkNum), LocalRefCount[i]); /* Remove entry from hashtable */ hresult = (LocalBufferLookupEnt *) hash_search(LocalBufHash, (void *) &bufHdr->tag, HASH_REMOVE, NULL); if (!hresult) /* shouldn't happen */ elog(ERROR, "local buffer hash table corrupted"); /* Mark buffer invalid */ CLEAR_BUFFERTAG(bufHdr->tag); bufHdr->flags = 0; bufHdr->usage_count = 0; } } }
/* Forget any invalid pages >= minblkno, because they've been dropped */ static void forget_invalid_pages(RelFileNode node, BlockNumber minblkno) { HASH_SEQ_STATUS status; xl_invalid_page *hentry; if (invalid_page_tab == NULL) return; /* nothing to do */ hash_seq_init(&status, invalid_page_tab); while ((hentry = (xl_invalid_page *) hash_seq_search(&status)) != NULL) { if (RelFileNodeEquals(hentry->key.node, node) && hentry->key.blkno >= minblkno) { elog(DEBUG2, "page %u of relation %u/%u/%u has been dropped", hentry->key.blkno, hentry->key.node.spcNode, hentry->key.node.dbNode, hentry->key.node.relNode); if (hash_search(invalid_page_tab, (void *) &hentry->key, HASH_REMOVE, NULL) == NULL) elog(ERROR, "hash table corrupted"); } } }
/* * RelationPreserveStorage * Mark a relation as not to be deleted after all. * * We need this function because relation mapping changes are committed * separately from commit of the whole transaction, so it's still possible * for the transaction to abort after the mapping update is done. * When a new physical relation is installed in the map, it would be * scheduled for delete-on-abort, so we'd delete it, and be in trouble. * The relation mapper fixes this by telling us to not delete such relations * after all as part of its commit. * * We also use this to reuse an old build of an index during ALTER TABLE, this * time removing the delete-at-commit entry. * * No-op if the relation is not among those scheduled for deletion. */ void RelationPreserveStorage(RelFileNode rnode, bool atCommit) { PendingRelDelete *pending; PendingRelDelete *prev; PendingRelDelete *next; prev = NULL; for (pending = pendingDeletes; pending != NULL; pending = next) { next = pending->next; if (RelFileNodeEquals(rnode, pending->relnode) && pending->atCommit == atCommit) { /* unlink and delete list entry */ if (prev) prev->next = next; else pendingDeletes = next; pfree(pending); /* prev does not change */ } else { /* unrelated entry, don't touch it */ prev = pending; } } }
/* Forget any invalid pages >= minblkno, because they've been dropped */ static void forget_invalid_pages(RelFileNode node, ForkNumber forkno, BlockNumber minblkno) { HASH_SEQ_STATUS status; xl_invalid_page *hentry; if (invalid_page_tab == NULL) return; /* nothing to do */ hash_seq_init(&status, invalid_page_tab); while ((hentry = (xl_invalid_page *) hash_seq_search(&status)) != NULL) { if (RelFileNodeEquals(hentry->key.node, node) && hentry->key.forkno == forkno && hentry->key.blkno >= minblkno) { if (log_min_messages <= DEBUG2 || client_min_messages <= DEBUG2) { char *path = relpathperm(hentry->key.node, forkno); elog(DEBUG2, "page %u of relation %s has been dropped", hentry->key.blkno, path); pfree(path); } if (hash_search(invalid_page_tab, (void *) &hentry->key, HASH_REMOVE, NULL) == NULL) elog(ERROR, "hash table corrupted"); } } }
static void forget_matching_split(Relation reln, RelFileNode node, BlockNumber insertblk, OffsetNumber offnum, bool is_root) { Buffer buffer; Page page; BTItem btitem; BlockNumber rightblk; List *l; /* Get downlink TID from page */ buffer = XLogReadBuffer(false, reln, insertblk); if (!BufferIsValid(buffer)) elog(PANIC, "forget_matching_split: block unfound"); page = (Page) BufferGetPage(buffer); btitem = (BTItem) PageGetItem(page, PageGetItemId(page, offnum)); rightblk = ItemPointerGetBlockNumber(&(btitem->bti_itup.t_tid)); Assert(ItemPointerGetOffsetNumber(&(btitem->bti_itup.t_tid)) == P_HIKEY); UnlockAndReleaseBuffer(buffer); foreach(l, incomplete_splits) { bt_incomplete_split *split = (bt_incomplete_split *) lfirst(l); if (RelFileNodeEquals(node, split->node) && rightblk == split->rightblk) { if (is_root != split->is_root) elog(LOG, "forget_matching_split: fishy is_root data"); incomplete_splits = lremove(split, incomplete_splits); break; /* need not look further */ } }
/* * ss_search --- search the scan_locations structure for an entry with the * given relfilenode. * * If "set" is true, the location is updated to the given location. If no * entry for the given relfilenode is found, it will be created at the head * of the list with the given location, even if "set" is false. * * In any case, the location after possible update is returned. * * Caller is responsible for having acquired suitable lock on the shared * data structure. */ static BlockNumber ss_search(RelFileNode relfilenode, BlockNumber location, bool set) { ss_lru_item_t *item; item = scan_locations->head; for (;;) { bool match; match = RelFileNodeEquals(item->location.relfilenode, relfilenode); if (match || item->next == NULL) { /* * If we reached the end of list and no match was found, take over * the last entry */ if (!match) { item->location.relfilenode = relfilenode; item->location.location = location; } else if (set) item->location.location = location; /* Move the entry to the front of the LRU list */ if (item != scan_locations->head) { /* unlink */ if (item == scan_locations->tail) scan_locations->tail = item->prev; item->prev->next = item->next; if (item->next) item->next->prev = item->prev; /* link */ item->prev = NULL; item->next = scan_locations->head; scan_locations->head->prev = item; scan_locations->head = item; } return item->location.location; } item = item->next; } /* not reached */ }
/* * Like XLogRegisterBuffer, but for registering a block that's not in the * shared buffer pool (i.e. when you don't have a Buffer for it). */ void XLogRegisterBlock(uint8 block_id, RelFileNode *rnode, ForkNumber forknum, BlockNumber blknum, Page page, uint8 flags) { registered_buffer *regbuf; /* This is currently only used to WAL-log a full-page image of a page */ Assert(flags & REGBUF_FORCE_IMAGE); Assert(begininsert_called); if (block_id >= max_registered_block_id) max_registered_block_id = block_id + 1; if (block_id >= max_registered_buffers) elog(ERROR, "too many registered buffers"); regbuf = ®istered_buffers[block_id]; regbuf->rnode = *rnode; regbuf->forkno = forknum; regbuf->block = blknum; regbuf->page = page; regbuf->flags = flags; regbuf->rdata_tail = (XLogRecData *) ®buf->rdata_head; regbuf->rdata_len = 0; /* * Check that this page hasn't already been registered with some other * block_id. */ #ifdef USE_ASSERT_CHECKING { int i; for (i = 0; i < max_registered_block_id; i++) { registered_buffer *regbuf_old = ®istered_buffers[i]; if (i == block_id || !regbuf_old->in_use) continue; Assert(!RelFileNodeEquals(regbuf_old->rnode, regbuf->rnode) || regbuf_old->forkno != regbuf->forkno || regbuf_old->block != regbuf->block); } } #endif regbuf->in_use = true; }
static void forgetIncompleteSplit(RelFileNode node, BlockNumber leftBlkno, BlockNumber updateBlkno) { ListCell *l; foreach(l, incomplete_splits) { ginIncompleteSplit *split = (ginIncompleteSplit *) lfirst(l); if (RelFileNodeEquals(node, split->node) && leftBlkno == split->leftBlkno && updateBlkno == split->rightBlkno) { incomplete_splits = list_delete_ptr(incomplete_splits, split); break; } }
/* * Register a reference to a buffer with the WAL record being constructed. * This must be called for every page that the WAL-logged operation modifies. */ void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags) { registered_buffer *regbuf; /* NO_IMAGE doesn't make sense with FORCE_IMAGE */ Assert(!((flags & REGBUF_FORCE_IMAGE) && (flags & (REGBUF_NO_IMAGE)))); Assert(begininsert_called); if (block_id >= max_registered_block_id) { if (block_id >= max_registered_buffers) elog(ERROR, "too many registered buffers"); max_registered_block_id = block_id + 1; } regbuf = ®istered_buffers[block_id]; BufferGetTag(buffer, ®buf->rnode, ®buf->forkno, ®buf->block); regbuf->page = BufferGetPage(buffer); regbuf->flags = flags; regbuf->rdata_tail = (XLogRecData *) ®buf->rdata_head; regbuf->rdata_len = 0; /* * Check that this page hasn't already been registered with some other * block_id. */ #ifdef USE_ASSERT_CHECKING { int i; for (i = 0; i < max_registered_block_id; i++) { registered_buffer *regbuf_old = ®istered_buffers[i]; if (i == block_id || !regbuf_old->in_use) continue; Assert(!RelFileNodeEquals(regbuf_old->rnode, regbuf->rnode) || regbuf_old->forkno != regbuf->forkno || regbuf_old->block != regbuf->block); } } #endif regbuf->in_use = true; }
/* * Add an smgr inval entry */ static void AddSmgrInvalidationMessage(InvalidationListHeader *hdr, RelFileNode rnode) { SharedInvalidationMessage msg; /* Don't add a duplicate item */ ProcessMessageList(hdr->rclist, if (msg->sm.id == SHAREDINVALSMGR_ID && RelFileNodeEquals(msg->sm.rnode, rnode)) return); /* OK, add the item */ msg.sm.id = SHAREDINVALSMGR_ID; msg.sm.rnode = rnode; AddInvalidationMessage(&hdr->rclist, &msg); }
static void forget_matching_split(RelFileNode node, BlockNumber downlink, bool is_root) { ListCell *l; foreach(l, incomplete_actions) { bt_incomplete_action *action = (bt_incomplete_action *) lfirst(l); if (RelFileNodeEquals(node, action->node) && action->is_split && downlink == action->rightblk) { if (is_root != action->is_root) elog(LOG, "forget_matching_split: fishy is_root data (expected %d, got %d)", action->is_root, is_root); incomplete_actions = list_delete_ptr(incomplete_actions, action); pfree(action); break; /* need not look further */ } }
/* * DropRelFileNodeLocalBuffers * This function removes from the buffer pool all the pages of the * specified relation that have block numbers >= firstDelBlock. * (In particular, with firstDelBlock = 0, all pages are removed.) * Dirty pages are simply dropped, without bothering to write them * out first. Therefore, this is NOT rollback-able, and so should be * used only with extreme caution! * * See DropRelFileNodeBuffers in bufmgr.c for more notes. */ void DropRelFileNodeLocalBuffers(RelFileNode rnode, ForkNumber forkNum, BlockNumber firstDelBlock) { int i; for (i = 0; i < NLocBuffer; i++) { BufferDesc *bufHdr = GetLocalBufferDescriptor(i); LocalBufferLookupEnt *hresult; uint32 buf_state; buf_state = pg_atomic_read_u32(&bufHdr->state); if ((buf_state & BM_TAG_VALID) && RelFileNodeEquals(bufHdr->tag.rnode, rnode) && bufHdr->tag.forkNum == forkNum && bufHdr->tag.blockNum >= firstDelBlock) { if (LocalRefCount[i] != 0) elog(ERROR, "block %u of %s is still referenced (local %u)", bufHdr->tag.blockNum, relpathbackend(bufHdr->tag.rnode, MyBackendId, bufHdr->tag.forkNum), LocalRefCount[i]); /* Remove entry from hashtable */ hresult = (LocalBufferLookupEnt *) hash_search(LocalBufHash, (void *) &bufHdr->tag, HASH_REMOVE, NULL); if (!hresult) /* shouldn't happen */ elog(ERROR, "local buffer hash table corrupted"); /* Mark buffer invalid */ CLEAR_BUFFERTAG(bufHdr->tag); buf_state &= ~BUF_FLAG_MASK; buf_state &= ~BUF_USAGECOUNT_MASK; pg_atomic_write_u32(&bufHdr->state, buf_state); } } }
static void forget_incomplete_insert_bitmapwords(RelFileNode node, xl_bm_bitmapwords* newWords) { ListCell* l; foreach (l, incomplete_actions) { bm_incomplete_action *action = (bm_incomplete_action *) lfirst(l); if (RelFileNodeEquals(node, action->bm_node) && (action->bm_lov_blkno == newWords->bm_lov_blkno && action->bm_lov_offset == newWords->bm_lov_offset && action->bm_last_setbit == newWords->bm_last_setbit) && !action->bm_is_last) { Assert(action->bm_blkno == newWords->bm_blkno); incomplete_actions = list_delete_ptr(incomplete_actions, action); pfree(action); break; } }
static void forgetIncompleteInsert(RelFileNode node, ItemPointerData key) { ListCell *l; if (!ItemPointerIsValid(&key)) return; if (incomplete_inserts == NIL) return; foreach(l, incomplete_inserts) { gistIncompleteInsert *insert = (gistIncompleteInsert *) lfirst(l); if (RelFileNodeEquals(node, insert->node) && ItemPointerEQ(&(insert->key), &(key))) { /* found */ incomplete_inserts = list_delete_ptr(incomplete_inserts, insert); pfree(insert->blkno); pfree(insert); break; } }
/* * Assemble a WAL record from the registered data and buffers into an * XLogRecData chain, ready for insertion with XLogInsertRecord(). * * The record header fields are filled in, except for the xl_prev field. The * calculated CRC does not include the record header yet. * * If there are any registered buffers, and a full-page image was not taken * of all of them, *fpw_lsn is set to the lowest LSN among such pages. This * signals that the assembled record is only good for insertion on the * assumption that the RedoRecPtr and doPageWrites values were up-to-date. */ static XLogRecData * XLogRecordAssemble(RmgrId rmid, uint8 info, XLogRecPtr RedoRecPtr, bool doPageWrites, XLogRecPtr *fpw_lsn) { XLogRecData *rdt; uint32 total_len = 0; int block_id; pg_crc32c rdata_crc; registered_buffer *prev_regbuf = NULL; XLogRecData *rdt_datas_last; XLogRecord *rechdr; char *scratch = hdr_scratch; /* * Note: this function can be called multiple times for the same record. * All the modifications we do to the rdata chains below must handle that. */ /* The record begins with the fixed-size header */ rechdr = (XLogRecord *) scratch; scratch += SizeOfXLogRecord; hdr_rdt.next = NULL; rdt_datas_last = &hdr_rdt; hdr_rdt.data = hdr_scratch; /* * Make an rdata chain containing all the data portions of all block * references. This includes the data for full-page images. Also append * the headers for the block references in the scratch buffer. */ *fpw_lsn = InvalidXLogRecPtr; for (block_id = 0; block_id < max_registered_block_id; block_id++) { registered_buffer *regbuf = ®istered_buffers[block_id]; bool needs_backup; bool needs_data; XLogRecordBlockHeader bkpb; XLogRecordBlockImageHeader bimg; XLogRecordBlockCompressHeader cbimg = {0}; bool samerel; bool is_compressed = false; if (!regbuf->in_use) continue; /* Determine if this block needs to be backed up */ if (regbuf->flags & REGBUF_FORCE_IMAGE) needs_backup = true; else if (regbuf->flags & REGBUF_NO_IMAGE) needs_backup = false; else if (!doPageWrites) needs_backup = false; else { /* * We assume page LSN is first data on *every* page that can be * passed to XLogInsert, whether it has the standard page layout * or not. */ XLogRecPtr page_lsn = PageGetLSN(regbuf->page); needs_backup = (page_lsn <= RedoRecPtr); if (!needs_backup) { if (*fpw_lsn == InvalidXLogRecPtr || page_lsn < *fpw_lsn) *fpw_lsn = page_lsn; } } /* Determine if the buffer data needs to included */ if (regbuf->rdata_len == 0) needs_data = false; else if ((regbuf->flags & REGBUF_KEEP_DATA) != 0) needs_data = true; else needs_data = !needs_backup; bkpb.id = block_id; bkpb.fork_flags = regbuf->forkno; bkpb.data_length = 0; if ((regbuf->flags & REGBUF_WILL_INIT) == REGBUF_WILL_INIT) bkpb.fork_flags |= BKPBLOCK_WILL_INIT; if (needs_backup) { Page page = regbuf->page; uint16 compressed_len; /* * The page needs to be backed up, so calculate its hole length * and offset. */ if (regbuf->flags & REGBUF_STANDARD) { /* Assume we can omit data between pd_lower and pd_upper */ uint16 lower = ((PageHeader) page)->pd_lower; uint16 upper = ((PageHeader) page)->pd_upper; if (lower >= SizeOfPageHeaderData && upper > lower && upper <= BLCKSZ) { bimg.hole_offset = lower; cbimg.hole_length = upper - lower; } else { /* No "hole" to compress out */ bimg.hole_offset = 0; cbimg.hole_length = 0; } } else { /* Not a standard page header, don't try to eliminate "hole" */ bimg.hole_offset = 0; cbimg.hole_length = 0; } /* * Try to compress a block image if wal_compression is enabled */ if (wal_compression) { is_compressed = XLogCompressBackupBlock(page, bimg.hole_offset, cbimg.hole_length, regbuf->compressed_page, &compressed_len); } /* * Fill in the remaining fields in the XLogRecordBlockHeader * struct */ bkpb.fork_flags |= BKPBLOCK_HAS_IMAGE; /* * Construct XLogRecData entries for the page content. */ rdt_datas_last->next = ®buf->bkp_rdatas[0]; rdt_datas_last = rdt_datas_last->next; bimg.bimg_info = (cbimg.hole_length == 0) ? 0 : BKPIMAGE_HAS_HOLE; if (is_compressed) { bimg.length = compressed_len; bimg.bimg_info |= BKPIMAGE_IS_COMPRESSED; rdt_datas_last->data = regbuf->compressed_page; rdt_datas_last->len = compressed_len; } else { bimg.length = BLCKSZ - cbimg.hole_length; if (cbimg.hole_length == 0) { rdt_datas_last->data = page; rdt_datas_last->len = BLCKSZ; } else { /* must skip the hole */ rdt_datas_last->data = page; rdt_datas_last->len = bimg.hole_offset; rdt_datas_last->next = ®buf->bkp_rdatas[1]; rdt_datas_last = rdt_datas_last->next; rdt_datas_last->data = page + (bimg.hole_offset + cbimg.hole_length); rdt_datas_last->len = BLCKSZ - (bimg.hole_offset + cbimg.hole_length); } } total_len += bimg.length; } if (needs_data) { /* * Link the caller-supplied rdata chain for this buffer to the * overall list. */ bkpb.fork_flags |= BKPBLOCK_HAS_DATA; bkpb.data_length = regbuf->rdata_len; total_len += regbuf->rdata_len; rdt_datas_last->next = regbuf->rdata_head; rdt_datas_last = regbuf->rdata_tail; } if (prev_regbuf && RelFileNodeEquals(regbuf->rnode, prev_regbuf->rnode)) { samerel = true; bkpb.fork_flags |= BKPBLOCK_SAME_REL; } else samerel = false; prev_regbuf = regbuf; /* Ok, copy the header to the scratch buffer */ memcpy(scratch, &bkpb, SizeOfXLogRecordBlockHeader); scratch += SizeOfXLogRecordBlockHeader; if (needs_backup) { memcpy(scratch, &bimg, SizeOfXLogRecordBlockImageHeader); scratch += SizeOfXLogRecordBlockImageHeader; if (cbimg.hole_length != 0 && is_compressed) { memcpy(scratch, &cbimg, SizeOfXLogRecordBlockCompressHeader); scratch += SizeOfXLogRecordBlockCompressHeader; } } if (!samerel) { memcpy(scratch, ®buf->rnode, sizeof(RelFileNode)); scratch += sizeof(RelFileNode); } memcpy(scratch, ®buf->block, sizeof(BlockNumber)); scratch += sizeof(BlockNumber); } /* followed by the record's origin, if any */ if (include_origin && replorigin_sesssion_origin != InvalidRepOriginId) { *(scratch++) = XLR_BLOCK_ID_ORIGIN; memcpy(scratch, &replorigin_sesssion_origin, sizeof(replorigin_sesssion_origin)); scratch += sizeof(replorigin_sesssion_origin); } /* followed by main data, if any */ if (mainrdata_len > 0) { if (mainrdata_len > 255) { *(scratch++) = XLR_BLOCK_ID_DATA_LONG; memcpy(scratch, &mainrdata_len, sizeof(uint32)); scratch += sizeof(uint32); } else { *(scratch++) = XLR_BLOCK_ID_DATA_SHORT; *(scratch++) = (uint8) mainrdata_len; } rdt_datas_last->next = mainrdata_head; rdt_datas_last = mainrdata_last; total_len += mainrdata_len; } rdt_datas_last->next = NULL; hdr_rdt.len = (scratch - hdr_scratch); total_len += hdr_rdt.len; /* * Calculate CRC of the data * * Note that the record header isn't added into the CRC initially since we * don't know the prev-link yet. Thus, the CRC will represent the CRC of * the whole record in the order: rdata, then backup blocks, then record * header. */ INIT_CRC32C(rdata_crc); COMP_CRC32C(rdata_crc, hdr_scratch + SizeOfXLogRecord, hdr_rdt.len - SizeOfXLogRecord); for (rdt = hdr_rdt.next; rdt != NULL; rdt = rdt->next) COMP_CRC32C(rdata_crc, rdt->data, rdt->len); /* * Fill in the fields in the record header. Prev-link is filled in later, * once we know where in the WAL the record will be inserted. The CRC does * not include the record header yet. */ rechdr->xl_xid = GetCurrentTransactionIdIfAny(); rechdr->xl_tot_len = total_len; rechdr->xl_info = info; rechdr->xl_rmid = rmid; rechdr->xl_prev = InvalidXLogRecPtr; rechdr->xl_crc = rdata_crc; return &hdr_rdt; }
/* * RememberFsyncRequest() -- callback from bgwriter side of fsync request * * We stuff the fsync request into the local hash table for execution * during the bgwriter's next checkpoint. * * The range of possible segment numbers is way less than the range of * BlockNumber, so we can reserve high values of segno for special purposes. * We define two: FORGET_RELATION_FSYNC means to cancel pending fsyncs for * a relation, and FORGET_DATABASE_FSYNC means to cancel pending fsyncs for * a whole database. (These are a tad slow because the hash table has to be * searched linearly, but it doesn't seem worth rethinking the table structure * for them.) */ void RememberFsyncRequest(RelFileNode rnode, BlockNumber segno) { Assert(pendingOpsTable); if (segno == FORGET_RELATION_FSYNC) { /* Remove any pending requests for the entire relation */ HASH_SEQ_STATUS hstat; PendingOperationEntry *entry; hash_seq_init(&hstat, pendingOpsTable); while ((entry = (PendingOperationEntry *) hash_seq_search(&hstat)) != NULL) { if (RelFileNodeEquals(entry->tag.rnode, rnode)) { /* Okay, cancel this entry */ entry->canceled = true; } } } else if (segno == FORGET_DATABASE_FSYNC) { /* Remove any pending requests for the entire database */ HASH_SEQ_STATUS hstat; PendingOperationEntry *entry; hash_seq_init(&hstat, pendingOpsTable); while ((entry = (PendingOperationEntry *) hash_seq_search(&hstat)) != NULL) { if (entry->tag.rnode.dbNode == rnode.dbNode) { /* Okay, cancel this entry */ entry->canceled = true; } } } else { /* Normal case: enter a request to fsync this segment */ PendingOperationTag key; PendingOperationEntry *entry; bool found; /* ensure any pad bytes in the hash key are zeroed */ MemSet(&key, 0, sizeof(key)); key.rnode = rnode; key.segno = segno; entry = (PendingOperationEntry *) hash_search(pendingOpsTable, &key, HASH_ENTER, &found); /* if new or previously canceled entry, initialize it */ if (!found || entry->canceled) { entry->canceled = false; entry->cycle_ctr = mdsync_cycle_ctr; } /* * NB: it's intentional that we don't change cycle_ctr if the entry * already exists. The fsync request must be treated as old, even * though the new request will be satisfied too by any subsequent * fsync. * * However, if the entry is present but is marked canceled, we should * act just as though it wasn't there. The only case where this could * happen would be if a file had been deleted, we received but did not * yet act on the cancel request, and the same relfilenode was then * assigned to a new file. We mustn't lose the new request, but * it should be considered new not old. */ } }
//void DropRelFileNodeBuffers(RelFileNode rnode, bool istemp, BlockNumber firstDelBlock) void body() { if (istemp==1) { for (i = 0; i < NLocBuffer; i++) { bufHdr = &LocalBufferDescriptors_i; if (RelFileNodeEquals(bufHdr_tag_rnode, rnode) && bufHdr_tag_blockNum >= firstDelBlock) { if (LocalRefCount_i != 0) ; /* elog(ERROR, "block %u of %u/%u/%u is still referenced (local %u)", */ /* bufHdr_tag_blockNum, */ /* bufHdr_tag_rnode_spcNode, */ /* bufHdr_tag_rnode_dbNode, */ /* bufHdr_tag_rnode_relNode, */ /* LocalRefCount_i); */ bufHdr_flags &= ~(BM_DIRTY | BM_JUST_DIRTIED); bufHdr_cntxDirty = 0; bufHdr_tag_rnode_relNode = 1; // InvalidOid; } } /* goto my_exit; */ while(1) { int zzz;zzz=zzz;} } A = 1; A = 0; // LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); for (i = 1; i <= NBuffers; i++) { bufHdr = nondet(); // &BufferDescriptors[i - 1]; recheck: if (RelFileNodeEquals(bufHdr_tag_rnode, rnode) && bufHdr_tag_blockNum >= firstDelBlock) { /* * If there is I/O in progress, better wait till it's done; * don't want to delete the relation out from under someone * who's just trying to flush the buffer! */ if (bufHdr_flags & BM_IO_IN_PROGRESS) { WaitIO(bufHdr); /* * By now, the buffer very possibly belongs to some other * rel, so check again before proceeding. */ goto recheck; } /* * There should be no pin on the buffer. */ if (bufHdr_refcount != 0) ; /* elog(ERROR, "block %u of %u/%u/%u is still referenced (private %d, global %u)", */ /* bufHdr_tag_blockNum, */ /* bufHdr_tag_rnode_spcNode, */ /* bufHdr_tag_rnode_dbNode, */ /* bufHdr_tag_rnode_relNode, */ /* PrivateRefCount[i - 1], bufHdr_refcount); */ /* Now we can do what we came for */ bufHdr_flags &= ~(BM_DIRTY | BM_JUST_DIRTIED); bufHdr_cntxDirty = 0; /* * And mark the buffer as no longer occupied by this rel. */ StrategyInvalidateBuffer(bufHdr); } } R = 1; R = 0; //LWLockRelease(BufMgrLock); /* my_exit: */ while(1) { int yyy;yyy=yyy;} }