/* * ResourceOwnerDelete * Delete an owner object and its descendants. * * The caller must have already released all resources in the object tree. */ void ResourceOwnerDelete(ResourceOwner owner) { /* We had better not be deleting CurrentResourceOwner ... */ Assert(owner != CurrentResourceOwner); /* And it better not own any resources, either */ Assert(owner->nbuffers == 0); Assert(owner->nlocks == 0 || owner->nlocks == MAX_RESOWNER_LOCKS + 1); Assert(owner->ncatrefs == 0); Assert(owner->ncatlistrefs == 0); Assert(owner->nrelrefs == 0); Assert(owner->ndsms == 0); Assert(owner->nplanrefs == 0); Assert(owner->ntupdescs == 0); Assert(owner->nsnapshots == 0); Assert(owner->nfiles == 0); /* * Delete children. The recursive call will delink the child from me, so * just iterate as long as there is a child. */ while (owner->firstchild != NULL) ResourceOwnerDelete(owner->firstchild); /* * We delink the owner from its parent before deleting it, so that if * there's an error we won't have deleted/busted owners still attached to * the owner tree. Better a leak than a crash. */ ResourceOwnerNewParent(owner, NULL); /* And free the object. */ if (owner->buffers) pfree(owner->buffers); if (owner->catrefs) pfree(owner->catrefs); if (owner->catlistrefs) pfree(owner->catlistrefs); if (owner->relrefs) pfree(owner->relrefs); if (owner->planrefs) pfree(owner->planrefs); if (owner->tupdescs) pfree(owner->tupdescs); if (owner->snapshots) pfree(owner->snapshots); if (owner->files) pfree(owner->files); if (owner->dsms) pfree(owner->dsms); pfree(owner); }
/* * Pre-subcommit processing for portals. * * Reassign the portals created in the current subtransaction to the parent * subtransaction. */ void AtSubCommit_Portals(SubTransactionId mySubid, SubTransactionId parentSubid, ResourceOwner parentXactOwner) { HASH_SEQ_STATUS status; PortalHashEnt *hentry; hash_seq_init(&status, PortalHashTable); while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL) { Portal portal = hentry->portal; if (portal->createSubid == mySubid) { portal->createSubid = parentSubid; if (portal->resowner) ResourceOwnerNewParent(portal->resowner, parentXactOwner); } } }
/* * Subtransaction abort handling for portals. * * Deactivate portals created during the failed subtransaction. * Note that per AtSubCommit_Portals, this will catch portals created * in descendants of the subtransaction too. * * We don't destroy any portals here; that's done in AtSubCleanup_Portals. */ void AtSubAbort_Portals(SubTransactionId mySubid, SubTransactionId parentSubid, ResourceOwner parentXactOwner) { HASH_SEQ_STATUS status; PortalHashEnt *hentry; hash_seq_init(&status, PortalHashTable); while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL) { Portal portal = hentry->portal; if (portal->createSubid != mySubid) continue; /* * Force any active portals of my own transaction into FAILED state. * This is mostly to ensure that a portal running a FETCH will go * FAILED if the underlying cursor fails. (Note we do NOT want to do * this to upper-level portals, since they may be able to continue.) * * This is only needed to dodge the sanity check in PortalDrop. */ if (portal->status == PORTAL_ACTIVE) portal->status = PORTAL_FAILED; /* * If the portal is READY then allow it to survive into the parent * transaction; otherwise shut it down. * * Currently, we can't actually support that because the portal's * query might refer to objects created or changed in the failed * subtransaction, leading to crashes if execution is resumed. So, * even READY portals are deleted. It would be nice to detect whether * the query actually depends on any such object, instead. */ #ifdef NOT_USED if (portal->status == PORTAL_READY) { portal->createSubid = parentSubid; if (portal->resowner) ResourceOwnerNewParent(portal->resowner, parentXactOwner); } else #endif { /* let portalcmds.c clean up the state it knows about */ if (PointerIsValid(portal->cleanup)) { (*portal->cleanup) (portal); portal->cleanup = NULL; } /* * Any resources belonging to the portal will be released in the * upcoming transaction-wide cleanup; they will be gone before we * run PortalDrop. */ portal->resowner = NULL; } } }