/* * smgrtruncate() -- Truncate supplied relation to the specified number * of blocks * * The truncation is done immediately, so this can't be rolled back. */ void smgrtruncate(SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks) { /* * 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, forknum, nblocks); /* * Send a shared-inval message to force other backends to close any smgr * references they may have for this rel. This is useful because they * might have open file pointers to segments that got removed, and/or * smgr_targblock variables pointing past the new rel end. (The inval * message will come back to our backend, too, causing a * probably-unnecessary local smgr flush. But we don't expect that this * is a performance-critical path.) As in the unlink code, we want to be * sure the message is sent before we start changing things on-disk. */ CacheInvalidateSmgr(reln->smgr_rnode); /* * Do the truncation. */ (*(smgrsw[reln->smgr_which].smgr_truncate)) (reln, forknum, nblocks); }
/* * Shared subroutine that actually does the unlink ... */ static void smgr_internal_unlink(RelFileNode rnode, int which, bool isTemp, bool isRedo) { /* * Get rid of any remaining buffers for the relation. bufmgr will just * drop them without bothering to write the contents. */ DropRelFileNodeBuffers(rnode, isTemp, 0); /* * Tell the free space map to forget this relation. It won't be accessed * any more anyway, but we may as well recycle the map space quickly. */ FreeSpaceMapForgetRel(&rnode); /* * And delete the physical files. * * Note: we treat deletion failure as a WARNING, not an error, because * we've already decided to commit or abort the current xact. */ if (!(*(smgrsw[which].smgr_unlink)) (rnode, isRedo)) ereport(WARNING, (errcode_for_file_access(), errmsg("could not remove relation %u/%u/%u: %m", rnode.spcNode, rnode.dbNode, rnode.relNode))); }
void smgr_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; BlockNumber newblks; reln = smgropen(xlrec->rnode); /* 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 */ newblks = (*(smgrsw[reln->smgr_which].smgr_truncate)) (reln, xlrec->blkno, false); if (newblks == InvalidBlockNumber) ereport(WARNING, (errcode_for_file_access(), errmsg("could not truncate relation %u/%u/%u to %u blocks: %m", reln->smgr_rnode.spcNode, reln->smgr_rnode.dbNode, reln->smgr_rnode.relNode, xlrec->blkno))); /* Also tell xlogutils.c about it */ XLogTruncateRelation(xlrec->rnode, xlrec->blkno); } else elog(PANIC, "smgr_redo: unknown op code %u", info); }
/* * smgrtruncate() -- Truncate supplied relation to the specified number * of blocks * * Returns the number of blocks on success, aborts the current * transaction on failure. */ BlockNumber smgrtruncate(SMgrRelation reln, BlockNumber nblocks, bool isTemp) { BlockNumber newblks; /* * 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 */ newblks = (*(smgrsw[reln->smgr_which].smgr_truncate)) (reln, nblocks, isTemp); if (newblks == InvalidBlockNumber) ereport(ERROR, (errcode_for_file_access(), errmsg("could not truncate relation %u/%u/%u to %u blocks: %m", reln->smgr_rnode.spcNode, reln->smgr_rnode.dbNode, reln->smgr_rnode.relNode, nblocks))); if (!isTemp) { /* * Make a non-transactional XLOG entry showing the file truncation. * It's non-transactional because we should replay it whether the * transaction commits or not; the underlying file change is certainly * not reversible. */ XLogRecPtr lsn; XLogRecData rdata; xl_smgr_truncate xlrec; xlrec.blkno = newblks; 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 | XLOG_NO_TRAN, &rdata); } return newblks; }
/* * smgrdounlinkfork() -- Immediately unlink one fork of a relation. * * The specified fork of the relation is removed from the store. This * should not be used during transactional operations, since it can't be * undone. * * If isRedo is true, it is okay for the underlying file to be gone * already. */ void smgrdounlinkfork(SMgrRelation reln, ForkNumber forknum, bool isRedo) { RelFileNodeBackend rnode = reln->smgr_rnode; int which = reln->smgr_which; /* Close the fork at smgr level */ (*(smgrsw[which].smgr_close)) (reln, forknum); /* * Get rid of any remaining buffers for the fork. bufmgr will just drop * them without bothering to write the contents. */ DropRelFileNodeBuffers(rnode, forknum, 0); /* * 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). */ /* * Send a shared-inval message to force other backends to close any * dangling smgr references they may have for this rel. We should do this * before starting the actual unlinking, in case we fail partway through * that step. Note that the sinval message will eventually come back to * this backend, too, and thereby provide a backstop that we closed our * own smgr rel. */ CacheInvalidateSmgr(rnode); /* * Delete the physical file(s). * * 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, forknum, isRedo); }
/* * Shared subroutine that actually does the unlink ... */ static void smgr_internal_unlink(RelFileNode rnode, int which, bool isTemp, bool isRedo) { /* * Get rid of any remaining buffers for the relation. bufmgr will just * drop them without bothering to write the contents. */ DropRelFileNodeBuffers(rnode, isTemp, 0); /* * Tell the free space map to forget this relation. It won't be accessed * any more anyway, but we may as well recycle the map space quickly. */ FreeSpaceMapForgetRel(&rnode); /* * Tell the stats collector to forget it immediately, too. Skip this in * recovery mode, since the stats collector likely isn't running (and if * it is, pgstat.c will get confused because we aren't a real backend * process). */ if (!InRecovery) pgstat_drop_relation(rnode.relNode); /* * And delete the physical files. * * Note: we treat deletion failure as a WARNING, not an error, because * we've already decided to commit or abort the current xact. */ if (!(*(smgrsw[which].smgr_unlink)) (rnode, isRedo)) ereport(WARNING, (errcode_for_file_access(), errmsg("could not remove relation %u/%u/%u: %m", rnode.spcNode, rnode.dbNode, rnode.relNode))); }