/* * 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); }
/* * Ensure that the visibility map fork is at least vm_nblocks long, extending * it if necessary with zeroed pages. */ static void vm_extend(Relation rel, BlockNumber vm_nblocks) { BlockNumber vm_nblocks_now; Page pg; pg = (Page) palloc(BLCKSZ); PageInit(pg, BLCKSZ, 0); /* * We use the relation extension lock to lock out other backends trying to * extend the visibility map at the same time. It also locks out extension * of the main fork, unnecessarily, but extending the visibility map * happens seldom enough that it doesn't seem worthwhile to have a * separate lock tag type for it. * * Note that another backend might have extended or created the relation * by the time we get the lock. */ LockRelationForExtension(rel, ExclusiveLock); /* Might have to re-open if a cache flush happened */ RelationOpenSmgr(rel); /* * Create the file first if it doesn't exist. If smgr_vm_nblocks is * positive then it must exist, no need for an smgrexists call. */ if ((rel->rd_smgr->smgr_vm_nblocks == 0 || rel->rd_smgr->smgr_vm_nblocks == InvalidBlockNumber) && !smgrexists(rel->rd_smgr, VISIBILITYMAP_FORKNUM)) smgrcreate(rel->rd_smgr, VISIBILITYMAP_FORKNUM, false); vm_nblocks_now = smgrnblocks(rel->rd_smgr, VISIBILITYMAP_FORKNUM); /* Now extend the file */ while (vm_nblocks_now < vm_nblocks) { smgrextend(rel->rd_smgr, VISIBILITYMAP_FORKNUM, vm_nblocks_now, (char *) pg, false); vm_nblocks_now++; } /* * Send a shared-inval message to force other backends to close any smgr * references they may have for this rel, which we are about to change. * This is a useful optimization because it means that backends don't have * to keep checking for creation or extension of the file, which happens * infrequently. */ CacheInvalidateSmgr(rel->rd_smgr->smgr_rnode); /* Update local cache with the up-to-date size */ rel->rd_smgr->smgr_vm_nblocks = vm_nblocks_now; UnlockRelationForExtension(rel, ExclusiveLock); pfree(pg); }
/* * smgrdounlink() -- Immediately unlink all forks of a relation. * * All forks of the relation are 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(s) to be gone * already. * * This is equivalent to calling smgrdounlinkfork for each fork, but * it's significantly quicker so should be preferred when possible. */ void smgrdounlink(SMgrRelation reln, bool isRedo) { RelFileNodeBackend rnode = reln->smgr_rnode; int which = reln->smgr_which; ForkNumber forknum; /* Close the forks at smgr level */ for (forknum = 0; forknum <= MAX_FORKNUM; forknum++) (*(smgrsw[which].smgr_close)) (reln, forknum); /* * Get rid of any remaining buffers for the relation. bufmgr will just * drop them without bothering to write the contents. */ DropRelFileNodesAllBuffers(&rnode, 1); /* * 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, InvalidForkNumber, isRedo); }
/* * smgrdounlinkall() -- Immediately unlink all forks of all given relations * * All forks of all given relations are 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(s) to be gone * already. * * This is equivalent to calling smgrdounlink for each relation, but it's * significantly quicker so should be preferred when possible. */ void smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo) { int i = 0; RelFileNodeBackend *rnodes; ForkNumber forknum; if (nrels == 0) return; /* * create an array which contains all relations to be dropped, and * close each relation's forks at the smgr level while at it */ rnodes = palloc(sizeof(RelFileNodeBackend) * nrels); for (i = 0; i < nrels; i++) { RelFileNodeBackend rnode = rels[i]->smgr_rnode; int which = rels[i]->smgr_which; rnodes[i] = rnode; /* Close the forks at smgr level */ for (forknum = 0; forknum <= MAX_FORKNUM; forknum++) (*(smgrsw[which].smgr_close)) (rels[i], forknum); } /* * Get rid of any remaining buffers for the relations. bufmgr will just * drop them without bothering to write the contents. */ DropRelFileNodesAllBuffers(rnodes, nrels); /* * It'd be nice to tell the stats collector to forget them immediately, too. * But we can't because we don't know the OIDs. */ /* * Send a shared-inval message to force other backends to close any * dangling smgr references they may have for these rels. We should do * this before starting the actual unlinking, in case we fail partway * through that step. Note that the sinval messages will eventually come * back to this backend, too, and thereby provide a backstop that we closed * our own smgr rel. */ for (i = 0; i < nrels; i++) CacheInvalidateSmgr(rnodes[i]); /* * 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. */ for (i = 0; i < nrels; i++) { int which = rels[i]->smgr_which; for (forknum = 0; forknum <= MAX_FORKNUM; forknum++) (*(smgrsw[which].smgr_unlink)) (rnodes[i], forknum, isRedo); } pfree(rnodes); }