/* * 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); }
/* * SetResQueueId -- set the cached value for the current resource queue. * * Notes * Needs to be called at session initialization and after (or in) SET ROLE. */ void SetResQueueId(void) { /* to cave the code of cache part, we provide a resource owner here if no * existing */ ResourceOwner owner = NULL; if (CurrentResourceOwner == NULL) { owner = ResourceOwnerCreate(NULL, "SetResQueueId"); CurrentResourceOwner = owner; } MyQueueId = GetResQueueForRole(GetUserId()); if (owner) { CurrentResourceOwner = NULL; ResourceOwnerDelete(owner); } return; }
/* attach worker to the shared memory segment, read the job structure */ static void initialize_worker(uint32 segment) { dsm_segment *seg; ResourceOwner old, tmp; /* Connect to dynamic shared memory segment. * * In order to attach a dynamic shared memory segment, we need a * resource owner. We cannot to StartTransactionCommand here, since * we haven't yet attached to the database: to do this, we need to * fetch information about connection properties from the shared * memory segment. */ old = CurrentResourceOwner; CurrentResourceOwner = ResourceOwnerCreate(NULL, "Background Worker"); seg = dsm_attach(segment); if (seg == NULL) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("unable to map dynamic shared memory segment"))); dsm_pin_mapping(seg); tmp = CurrentResourceOwner; CurrentResourceOwner = old; ResourceOwnerDelete(tmp); job = palloc(sizeof(JobDesc)); /* copy the arguments from shared memory segment */ memcpy(job, dsm_segment_address(seg), sizeof(JobDesc)); /* and detach it right away */ dsm_detach(seg); Assert(job->magic == JOB_MAGIC); job_run_function.schema = quote_identifier(job->schemaname); job_run_function.name = quote_identifier("run_job"); }
/* * PortalDrop * Destroy the portal. */ void PortalDrop(Portal portal, bool isTopCommit) { AssertArg(PortalIsValid(portal)); /* Not sure if this case can validly happen or not... */ if (portal->status == PORTAL_ACTIVE) elog(ERROR, "cannot drop active portal"); /* * Remove portal from hash table. Because we do this first, we will not * come back to try to remove the portal again if there's any error in the * subsequent steps. Better to leak a little memory than to get into an * infinite error-recovery loop. */ PortalHashTableDelete(portal); /* let portalcmds.c clean up the state it knows about */ if (PointerIsValid(portal->cleanup)) (*portal->cleanup) (portal); /* * Release any resources still attached to the portal. There are several * cases being covered here: * * Top transaction commit (indicated by isTopCommit): normally we should * do nothing here and let the regular end-of-transaction resource * releasing mechanism handle these resources too. However, if we have a * FAILED portal (eg, a cursor that got an error), we'd better clean up * its resources to avoid resource-leakage warning messages. * * Sub transaction commit: never comes here at all, since we don't kill * any portals in AtSubCommit_Portals(). * * Main or sub transaction abort: we will do nothing here because * portal->resowner was already set NULL; the resources were already * cleaned up in transaction abort. * * Ordinary portal drop: must release resources. However, if the portal * is not FAILED then we do not release its locks. The locks become the * responsibility of the transaction's ResourceOwner (since it is the * parent of the portal's owner) and will be released when the transaction * eventually ends. */ if (portal->resowner && (!isTopCommit || portal->status == PORTAL_FAILED)) { bool isCommit = (portal->status != PORTAL_FAILED); ResourceOwnerRelease(portal->resowner, RESOURCE_RELEASE_BEFORE_LOCKS, isCommit, false); ResourceOwnerRelease(portal->resowner, RESOURCE_RELEASE_LOCKS, isCommit, false); ResourceOwnerRelease(portal->resowner, RESOURCE_RELEASE_AFTER_LOCKS, isCommit, false); ResourceOwnerDelete(portal->resowner); } portal->resowner = NULL; /* * Delete tuplestore if present. We should do this even under error * conditions; since the tuplestore would have been using cross- * transaction storage, its temp files need to be explicitly deleted. */ if (portal->holdStore) { MemoryContext oldcontext; oldcontext = MemoryContextSwitchTo(portal->holdContext); tuplestore_end(portal->holdStore); MemoryContextSwitchTo(oldcontext); portal->holdStore = NULL; } /* delete tuplestore storage, if any */ if (portal->holdContext) MemoryContextDelete(portal->holdContext); /* release subsidiary storage */ MemoryContextDelete(PortalGetHeapMemory(portal)); /* release portal struct (it's in PortalMemory) */ pfree(portal); }
void InitResQueues(void) { HeapTuple tuple; int numQueues = 0; bool queuesok = true; cqContext *pcqCtx; cqContext cqc; Assert(ResScheduler); /* * Need a resource owner to keep the heapam code happy. */ Assert(CurrentResourceOwner == NULL); ResourceOwner owner = ResourceOwnerCreate(NULL, "InitQueues"); CurrentResourceOwner = owner; /** * The resqueue shared mem initialization must be serialized. Only the first session * should do the init. * Serialization is done the ResQueueLock LW_EXCLUSIVE. However, we must obtain all DB * lock before obtaining LWlock. * So, we must have obtained ResQueueRelationId and ResQueueCapabilityRelationId lock * first. */ Relation relResqueue = heap_open(ResQueueRelationId, AccessShareLock); LockRelationOid(ResQueueCapabilityRelationId, RowExclusiveLock); LWLockAcquire(ResQueueLock, LW_EXCLUSIVE); if (ResScheduler->num_queues > 0) { /* Hash table has already been loaded */ LWLockRelease(ResQueueLock); UnlockRelationOid(ResQueueCapabilityRelationId, RowExclusiveLock); heap_close(relResqueue, AccessShareLock); CurrentResourceOwner = NULL; ResourceOwnerDelete(owner); return; } /* XXX XXX: should this be rowexclusive ? */ pcqCtx = caql_beginscan( caql_indexOK( caql_addrel(cqclr(&cqc), relResqueue), false), cql("SELECT * FROM pg_resqueue ", NULL)); while (HeapTupleIsValid(tuple = caql_getnext(pcqCtx))) { Form_pg_resqueue queueform; Oid queueid; bool overcommit; float4 ignorelimit; Cost thresholds[NUM_RES_LIMIT_TYPES]; char *queuename; numQueues++; queueform = (Form_pg_resqueue) GETSTRUCT(tuple); queueid = HeapTupleGetOid(tuple); queuename = NameStr(queueform->rsqname); thresholds[RES_COUNT_LIMIT] = queueform->rsqcountlimit; thresholds[RES_COST_LIMIT] = queueform->rsqcostlimit; thresholds[RES_MEMORY_LIMIT] = ResourceQueueGetMemoryLimit(queueid); overcommit = queueform->rsqovercommit; ignorelimit = queueform->rsqignorecostlimit; queuesok = ResCreateQueue(queueid, thresholds, overcommit, ignorelimit); if (!queuesok) { /** Break out of loop. Close relations, relinquish LWLock and then error out */ break; } } caql_endscan(pcqCtx); LWLockRelease(ResQueueLock); UnlockRelationOid(ResQueueCapabilityRelationId, RowExclusiveLock); heap_close(relResqueue, AccessShareLock); if (!queuesok) ereport(PANIC, (errcode(ERRCODE_INSUFFICIENT_RESOURCES), errmsg("insufficient resource queues available"), errhint("Increase max_resource_queues to %d.", numQueues))); elog(LOG,"initialized %d resource queues", numQueues); CurrentResourceOwner = NULL; ResourceOwnerDelete(owner); return; }