📄 smgr.c
字号:
/* * It'd be nice to tell the stats collector to forget it immediately, too. * But we can't because we don't know the OID (and in cases involving * relfilenode swaps, it's not always clear which table OID to forget, * anyway). */ /* * And delete the physical files. * * Note: smgr_unlink must treat deletion failure as a WARNING, not an * ERROR, because we've already decided to commit or abort the current * xact. */ (*(smgrsw[which].smgr_unlink)) (rnode, isRedo);}/* * smgrextend() -- Add a new block to a file. * * The semantics are nearly the same as smgrwrite(): write at the * specified position. However, this is to be used for the case of * extending a relation (i.e., blocknum is at or beyond the current * EOF). Note that we assume writing a block beyond current EOF * causes intervening file space to become filled with zeroes. */voidsmgrextend(SMgrRelation reln, BlockNumber blocknum, char *buffer, bool isTemp){ (*(smgrsw[reln->smgr_which].smgr_extend)) (reln, blocknum, buffer, isTemp);}/* * smgrread() -- read a particular block from a relation into the supplied * buffer. * * This routine is called from the buffer manager in order to * instantiate pages in the shared buffer cache. All storage managers * return pages in the format that POSTGRES expects. */voidsmgrread(SMgrRelation reln, BlockNumber blocknum, char *buffer){ (*(smgrsw[reln->smgr_which].smgr_read)) (reln, blocknum, buffer);}/* * smgrwrite() -- Write the supplied buffer out. * * This is to be used only for updating already-existing blocks of a * relation (ie, those before the current EOF). To extend a relation, * use smgrextend(). * * This is not a synchronous write -- the block is not necessarily * on disk at return, only dumped out to the kernel. However, * provisions will be made to fsync the write before the next checkpoint. * * isTemp indicates that the relation is a temp table (ie, is managed * by the local-buffer manager). In this case no provisions need be * made to fsync the write before checkpointing. */voidsmgrwrite(SMgrRelation reln, BlockNumber blocknum, char *buffer, bool isTemp){ (*(smgrsw[reln->smgr_which].smgr_write)) (reln, blocknum, buffer, isTemp);}/* * smgrnblocks() -- Calculate the number of blocks in the * supplied relation. */BlockNumbersmgrnblocks(SMgrRelation reln){ return (*(smgrsw[reln->smgr_which].smgr_nblocks)) (reln);}/* * smgrtruncate() -- Truncate supplied relation to the specified number * of blocks */voidsmgrtruncate(SMgrRelation reln, BlockNumber nblocks, bool isTemp){ /* * Get rid of any buffers for the about-to-be-deleted blocks. bufmgr will * just drop them without bothering to write the contents. */ DropRelFileNodeBuffers(reln->smgr_rnode, isTemp, nblocks); /* * Tell the free space map to forget anything it may have stored for the * about-to-be-deleted blocks. We want to be sure it won't return bogus * block numbers later on. */ FreeSpaceMapTruncateRel(&reln->smgr_rnode, nblocks); /* Do the truncation */ (*(smgrsw[reln->smgr_which].smgr_truncate)) (reln, nblocks, isTemp); if (!isTemp) { /* * Make an XLOG entry showing the file truncation. */ XLogRecPtr lsn; XLogRecData rdata; xl_smgr_truncate xlrec; xlrec.blkno = nblocks; xlrec.rnode = reln->smgr_rnode; rdata.data = (char *) &xlrec; rdata.len = sizeof(xlrec); rdata.buffer = InvalidBuffer; rdata.next = NULL; lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_TRUNCATE, &rdata); }}/* * smgrimmedsync() -- Force the specified relation to stable storage. * * Synchronously force all previous writes to the specified relation * down to disk. * * This is useful for building completely new relations (eg, new * indexes). Instead of incrementally WAL-logging the index build * steps, we can just write completed index pages to disk with smgrwrite * or smgrextend, and then fsync the completed index file before * committing the transaction. (This is sufficient for purposes of * crash recovery, since it effectively duplicates forcing a checkpoint * for the completed index. But it is *not* sufficient if one wishes * to use the WAL log for PITR or replication purposes: in that case * we have to make WAL entries as well.) * * The preceding writes should specify isTemp = true to avoid * duplicative fsyncs. * * Note that you need to do FlushRelationBuffers() first if there is * any possibility that there are dirty buffers for the relation; * otherwise the sync is not very meaningful. */voidsmgrimmedsync(SMgrRelation reln){ (*(smgrsw[reln->smgr_which].smgr_immedsync)) (reln);}/* * PostPrepare_smgr -- Clean up after a successful PREPARE * * What we have to do here is throw away the in-memory state about pending * relation deletes. It's all been recorded in the 2PC state file and * it's no longer smgr's job to worry about it. */voidPostPrepare_smgr(void){ PendingRelDelete *pending; PendingRelDelete *next; for (pending = pendingDeletes; pending != NULL; pending = next) { next = pending->next; pendingDeletes = next; /* must explicitly free the list entry */ pfree(pending); }}/* * smgrDoPendingDeletes() -- Take care of relation deletes at end of xact. * * This also runs when aborting a subxact; we want to clean up a failed * subxact immediately. */voidsmgrDoPendingDeletes(bool isCommit){ int nestLevel = GetCurrentTransactionNestLevel(); PendingRelDelete *pending; PendingRelDelete *prev; PendingRelDelete *next; prev = NULL; for (pending = pendingDeletes; pending != NULL; pending = next) { next = pending->next; if (pending->nestLevel < nestLevel) { /* outer-level entries should not be processed yet */ prev = pending; } else { /* unlink list entry first, so we don't retry on failure */ if (prev) prev->next = next; else pendingDeletes = next; /* do deletion if called for */ if (pending->atCommit == isCommit) smgr_internal_unlink(pending->relnode, pending->which, pending->isTemp, false); /* must explicitly free the list entry */ pfree(pending); /* prev does not change */ } }}/* * smgrGetPendingDeletes() -- Get a list of relations to be deleted. * * The return value is the number of relations scheduled for termination. * *ptr is set to point to a freshly-palloc'd array of RelFileNodes. * If there are no relations to be deleted, *ptr is set to NULL. * * If haveNonTemp isn't NULL, the bool it points to gets set to true if * there is any non-temp table pending to be deleted; false if not. * * Note that the list does not include anything scheduled for termination * by upper-level transactions. */intsmgrGetPendingDeletes(bool forCommit, RelFileNode **ptr, bool *haveNonTemp){ int nestLevel = GetCurrentTransactionNestLevel(); int nrels; RelFileNode *rptr; PendingRelDelete *pending; nrels = 0; if (haveNonTemp) *haveNonTemp = false; for (pending = pendingDeletes; pending != NULL; pending = pending->next) { if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit) nrels++; } if (nrels == 0) { *ptr = NULL; return 0; } rptr = (RelFileNode *) palloc(nrels * sizeof(RelFileNode)); *ptr = rptr; for (pending = pendingDeletes; pending != NULL; pending = pending->next) { if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit) *rptr++ = pending->relnode; if (haveNonTemp && !pending->isTemp) *haveNonTemp = true; } return nrels;}/* * AtSubCommit_smgr() --- Take care of subtransaction commit. * * Reassign all items in the pending-deletes list to the parent transaction. */voidAtSubCommit_smgr(void){ int nestLevel = GetCurrentTransactionNestLevel(); PendingRelDelete *pending; for (pending = pendingDeletes; pending != NULL; pending = pending->next) { if (pending->nestLevel >= nestLevel) pending->nestLevel = nestLevel - 1; }}/* * AtSubAbort_smgr() --- Take care of subtransaction abort. * * Delete created relations and forget about deleted relations. * We can execute these operations immediately because we know this * subtransaction will not commit. */voidAtSubAbort_smgr(void){ smgrDoPendingDeletes(false);}/* * smgrcommit() -- Prepare to commit changes made during the current * transaction. * * This is called before we actually commit. */voidsmgrcommit(void){ int i; for (i = 0; i < NSmgr; i++) { if (smgrsw[i].smgr_commit) (*(smgrsw[i].smgr_commit)) (); }}/* * smgrabort() -- Clean up after transaction abort. */voidsmgrabort(void){ int i; for (i = 0; i < NSmgr; i++) { if (smgrsw[i].smgr_abort) (*(smgrsw[i].smgr_abort)) (); }}/* * smgrpreckpt() -- Prepare for checkpoint. */voidsmgrpreckpt(void){ int i; for (i = 0; i < NSmgr; i++) { if (smgrsw[i].smgr_pre_ckpt) (*(smgrsw[i].smgr_pre_ckpt)) (); }}/* * smgrsync() -- Sync files to disk during checkpoint. */voidsmgrsync(void){ int i; for (i = 0; i < NSmgr; i++) { if (smgrsw[i].smgr_sync) (*(smgrsw[i].smgr_sync)) (); }}/* * smgrpostckpt() -- Post-checkpoint cleanup. */voidsmgrpostckpt(void){ int i; for (i = 0; i < NSmgr; i++) { if (smgrsw[i].smgr_post_ckpt) (*(smgrsw[i].smgr_post_ckpt)) (); }}voidsmgr_redo(XLogRecPtr lsn, XLogRecord *record){ uint8 info = record->xl_info & ~XLR_INFO_MASK; if (info == XLOG_SMGR_CREATE) { xl_smgr_create *xlrec = (xl_smgr_create *) XLogRecGetData(record); SMgrRelation reln; reln = smgropen(xlrec->rnode); smgrcreate(reln, false, true); } else if (info == XLOG_SMGR_TRUNCATE) { xl_smgr_truncate *xlrec = (xl_smgr_truncate *) XLogRecGetData(record); SMgrRelation reln; reln = smgropen(xlrec->rnode); /* * Forcibly create relation if it doesn't exist (which suggests that * it was dropped somewhere later in the WAL sequence). As in * XLogOpenRelation, we prefer to recreate the rel and replay the log * as best we can until the drop is seen. */ smgrcreate(reln, false, true); /* Can't use smgrtruncate because it would try to xlog */ /* * First, force bufmgr to drop any buffers it has for the to-be- * truncated blocks. We must do this, else subsequent XLogReadBuffer * operations will not re-extend the file properly. */ DropRelFileNodeBuffers(xlrec->rnode, false, xlrec->blkno); /* * Tell the free space map to forget anything it may have stored for * the about-to-be-deleted blocks. We want to be sure it won't return * bogus block numbers later on. */ FreeSpaceMapTruncateRel(&reln->smgr_rnode, xlrec->blkno); /* Do the truncation */ (*(smgrsw[reln->smgr_which].smgr_truncate)) (reln, xlrec->blkno, false); /* Also tell xlogutils.c about it */ XLogTruncateRelation(xlrec->rnode, xlrec->blkno); } else elog(PANIC, "smgr_redo: unknown op code %u", info);}voidsmgr_desc(StringInfo buf, uint8 xl_info, char *rec){ uint8 info = xl_info & ~XLR_INFO_MASK; if (info == XLOG_SMGR_CREATE) { xl_smgr_create *xlrec = (xl_smgr_create *) rec; appendStringInfo(buf, "file create: %u/%u/%u", xlrec->rnode.spcNode, xlrec->rnode.dbNode, xlrec->rnode.relNode); } else if (info == XLOG_SMGR_TRUNCATE) { xl_smgr_truncate *xlrec = (xl_smgr_truncate *) rec; appendStringInfo(buf, "file truncate: %u/%u/%u to %u blocks", xlrec->rnode.spcNode, xlrec->rnode.dbNode, xlrec->rnode.relNode, xlrec->blkno); } else appendStringInfo(buf, "UNKNOWN");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -