/* * FreeQueryDesc */ void FreeQueryDesc(QueryDesc *qdesc) { /* Can't be a live query */ Assert(qdesc->estate == NULL); /* forget our snapshots */ UnregisterSnapshot(qdesc->snapshot); UnregisterSnapshot(qdesc->crosscheck_snapshot); /* Only the QueryDesc itself need be freed */ pfree(qdesc); }
Datum currtid_byrelname(PG_FUNCTION_ARGS) { text *relname = PG_GETARG_TEXT_P(0); ItemPointer tid = PG_GETARG_ITEMPOINTER(1); ItemPointer result; RangeVar *relrv; Relation rel; AclResult aclresult; Snapshot snapshot; relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); rel = heap_openrv(relrv, AccessShareLock); aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(), ACL_SELECT); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_CLASS, RelationGetRelationName(rel)); if (rel->rd_rel->relkind == RELKIND_VIEW || rel->rd_rel->relkind == RELKIND_CONTVIEW) return currtid_for_view(rel, tid); result = (ItemPointer) palloc(sizeof(ItemPointerData)); ItemPointerCopy(tid, result); snapshot = RegisterSnapshot(GetLatestSnapshot()); heap_get_latest_tid(rel, snapshot, result); UnregisterSnapshot(snapshot); heap_close(rel, AccessShareLock); PG_RETURN_ITEMPOINTER(result); }
/* ---------------- * index_endscan - end a scan * ---------------- */ void index_endscan(IndexScanDesc scan) { SCAN_CHECKS; CHECK_SCAN_PROCEDURE(amendscan); /* Release any held pin on a heap page */ if (BufferIsValid(scan->xs_cbuf)) { ReleaseBuffer(scan->xs_cbuf); scan->xs_cbuf = InvalidBuffer; } /* End the AM's scan */ scan->indexRelation->rd_amroutine->amendscan(scan); /* Release index refcount acquired by index_beginscan */ RelationDecrementReferenceCount(scan->indexRelation); if (scan->xs_temp_snap) UnregisterSnapshot(scan->xs_snapshot); /* Release the scan data structure itself */ IndexScanEnd(scan); }
/* * systable_endscan_ordered --- close scan, release resources */ void systable_endscan_ordered(SysScanDesc sysscan) { Assert(sysscan->irel); index_endscan(sysscan->iscan); if (sysscan->snapshot) UnregisterSnapshot(sysscan->snapshot); pfree(sysscan); }
/* * Frees the data allocated by the visimap store * * No function using the visibility map store should be called * after this function call. */ void AppendOnlyVisimapStore_Finish(AppendOnlyVisimapStore *visiMapStore, LOCKMODE lockmode) { if (visiMapStore->scanKeys) { pfree(visiMapStore->scanKeys); visiMapStore->scanKeys = NULL; } UnregisterSnapshot(visiMapStore->snapshot); index_close(visiMapStore->visimapIndex, lockmode); heap_close(visiMapStore->visimapRelation, lockmode); }
/* * systable_endscan --- close scan, release resources * * Note that it's still up to the caller to close the heap relation. */ void systable_endscan(SysScanDesc sysscan) { if (sysscan->irel) { index_endscan(sysscan->iscan); index_close(sysscan->irel, AccessShareLock); } else heap_endscan(sysscan->scan); if (sysscan->snapshot) UnregisterSnapshot(sysscan->snapshot); pfree(sysscan); }
Datum currtid_byreloid(PG_FUNCTION_ARGS) { Oid reloid = PG_GETARG_OID(0); ItemPointer tid = PG_GETARG_ITEMPOINTER(1); ItemPointer result; Relation rel; AclResult aclresult; Snapshot snapshot; result = (ItemPointer) palloc(sizeof(ItemPointerData)); if (!reloid) { *result = Current_last_tid; PG_RETURN_ITEMPOINTER(result); } rel = heap_open(reloid, AccessShareLock); aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(), ACL_SELECT); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_CLASS, RelationGetRelationName(rel)); if (rel->rd_rel->relkind == RELKIND_VIEW || rel->rd_rel->relkind == RELKIND_CONTVIEW) return currtid_for_view(rel, tid); ItemPointerCopy(tid, result); snapshot = RegisterSnapshot(GetLatestSnapshot()); heap_get_latest_tid(rel, snapshot, result); UnregisterSnapshot(snapshot); heap_close(rel, AccessShareLock); PG_RETURN_ITEMPOINTER(result); }
/* * Load GUC settings from pg_db_role_setting. * * We try specific settings for the database/role combination, as well as * general for this database and for this user. */ static void process_settings(Oid databaseid, Oid roleid) { Relation relsetting; Snapshot snapshot; if (!IsUnderPostmaster) return; relsetting = heap_open(DbRoleSettingRelationId, AccessShareLock); /* read all the settings under the same snapsot for efficiency */ snapshot = RegisterSnapshot(GetCatalogSnapshot(DbRoleSettingRelationId)); /* Later settings are ignored if set earlier. */ ApplySetting(snapshot, databaseid, roleid, relsetting, PGC_S_DATABASE_USER); ApplySetting(snapshot, InvalidOid, roleid, relsetting, PGC_S_USER); ApplySetting(snapshot, databaseid, InvalidOid, relsetting, PGC_S_DATABASE); ApplySetting(snapshot, InvalidOid, InvalidOid, relsetting, PGC_S_GLOBAL); UnregisterSnapshot(snapshot); heap_close(relsetting, AccessShareLock); }
static void ResourceOwnerReleaseInternal(ResourceOwner owner, ResourceReleasePhase phase, bool isCommit, bool isTopLevel) { ResourceOwner child; ResourceOwner save; ResourceReleaseCallbackItem *item; /* Recurse to handle descendants */ for (child = owner->firstchild; child != NULL; child = child->nextchild) ResourceOwnerReleaseInternal(child, phase, isCommit, isTopLevel); /* * Make CurrentResourceOwner point to me, so that ReleaseBuffer etc don't * get confused. We needn't PG_TRY here because the outermost level will * fix it on error abort. */ save = CurrentResourceOwner; CurrentResourceOwner = owner; if (phase == RESOURCE_RELEASE_BEFORE_LOCKS) { /* * Release buffer pins. Note that ReleaseBuffer will remove the * buffer entry from my list, so I just have to iterate till there are * none. * * During a commit, there shouldn't be any remaining pins --- that * would indicate failure to clean up the executor correctly --- so * issue warnings. In the abort case, just clean up quietly. * * We are careful to do the releasing back-to-front, so as to avoid * O(N^2) behavior in ResourceOwnerForgetBuffer(). */ while (owner->nbuffers > 0) { if (isCommit) PrintBufferLeakWarning(owner->buffers[owner->nbuffers - 1]); ReleaseBuffer(owner->buffers[owner->nbuffers - 1]); } /* * Release relcache references. Note that RelationClose will remove * the relref entry from my list, so I just have to iterate till there * are none. * * As with buffer pins, warn if any are left at commit time, and * release back-to-front for speed. */ while (owner->nrelrefs > 0) { if (isCommit) PrintRelCacheLeakWarning(owner->relrefs[owner->nrelrefs - 1]); RelationClose(owner->relrefs[owner->nrelrefs - 1]); } } else if (phase == RESOURCE_RELEASE_LOCKS) { if (isTopLevel) { /* * For a top-level xact we are going to release all locks (or at * least all non-session locks), so just do a single lmgr call at * the top of the recursion. */ if (owner == TopTransactionResourceOwner) { ProcReleaseLocks(isCommit); ReleasePredicateLocks(isCommit); } } else { /* * Release locks retail. Note that if we are committing a * subtransaction, we do NOT release its locks yet, but transfer * them to the parent. */ LOCALLOCK **locks; int nlocks; Assert(owner->parent != NULL); /* * Pass the list of locks owned by this resource owner to the lock * manager, unless it has overflowed. */ if (owner->nlocks > MAX_RESOWNER_LOCKS) { locks = NULL; nlocks = 0; } else { locks = owner->locks; nlocks = owner->nlocks; } if (isCommit) LockReassignCurrentOwner(locks, nlocks); else LockReleaseCurrentOwner(locks, nlocks); } } else if (phase == RESOURCE_RELEASE_AFTER_LOCKS) { /* * Release catcache references. Note that ReleaseCatCache will remove * the catref entry from my list, so I just have to iterate till there * are none. * * As with buffer pins, warn if any are left at commit time, and * release back-to-front for speed. */ while (owner->ncatrefs > 0) { if (isCommit) PrintCatCacheLeakWarning(owner->catrefs[owner->ncatrefs - 1]); ReleaseCatCache(owner->catrefs[owner->ncatrefs - 1]); } /* Ditto for catcache lists */ while (owner->ncatlistrefs > 0) { if (isCommit) PrintCatCacheListLeakWarning(owner->catlistrefs[owner->ncatlistrefs - 1]); ReleaseCatCacheList(owner->catlistrefs[owner->ncatlistrefs - 1]); } /* Ditto for plancache references */ while (owner->nplanrefs > 0) { if (isCommit) PrintPlanCacheLeakWarning(owner->planrefs[owner->nplanrefs - 1]); ReleaseCachedPlan(owner->planrefs[owner->nplanrefs - 1], true); } /* Ditto for tupdesc references */ while (owner->ntupdescs > 0) { if (isCommit) PrintTupleDescLeakWarning(owner->tupdescs[owner->ntupdescs - 1]); DecrTupleDescRefCount(owner->tupdescs[owner->ntupdescs - 1]); } /* Ditto for snapshot references */ while (owner->nsnapshots > 0) { if (isCommit) PrintSnapshotLeakWarning(owner->snapshots[owner->nsnapshots - 1]); UnregisterSnapshot(owner->snapshots[owner->nsnapshots - 1]); } /* Ditto for temporary files */ while (owner->nfiles > 0) { if (isCommit) PrintFileLeakWarning(owner->files[owner->nfiles - 1]); FileClose(owner->files[owner->nfiles - 1]); } /* Clean up index scans too */ ReleaseResources_hash(); } /* Let add-on modules get a chance too */ for (item = ResourceRelease_callbacks; item; item = item->next) (*item->callback) (phase, isCommit, isTopLevel, item->arg); CurrentResourceOwner = save; }
static void ResourceOwnerReleaseInternal(ResourceOwner owner, ResourceReleasePhase phase, bool isCommit, bool isTopLevel) { ResourceOwner child; ResourceOwner save; ResourceReleaseCallbackItem *item; Datum foundres; /* Recurse to handle descendants */ for (child = owner->firstchild; child != NULL; child = child->nextchild) ResourceOwnerReleaseInternal(child, phase, isCommit, isTopLevel); /* * Make CurrentResourceOwner point to me, so that ReleaseBuffer etc don't * get confused. */ save = CurrentResourceOwner; CurrentResourceOwner = owner; if (phase == RESOURCE_RELEASE_BEFORE_LOCKS) { /* * Release buffer pins. Note that ReleaseBuffer will remove the * buffer entry from our array, so we just have to iterate till there * are none. * * During a commit, there shouldn't be any remaining pins --- that * would indicate failure to clean up the executor correctly --- so * issue warnings. In the abort case, just clean up quietly. */ while (ResourceArrayGetAny(&(owner->bufferarr), &foundres)) { Buffer res = DatumGetBuffer(foundres); if (isCommit) PrintBufferLeakWarning(res); ReleaseBuffer(res); } /* Ditto for relcache references */ while (ResourceArrayGetAny(&(owner->relrefarr), &foundres)) { Relation res = (Relation) DatumGetPointer(foundres); if (isCommit) PrintRelCacheLeakWarning(res); RelationClose(res); } /* Ditto for dynamic shared memory segments */ while (ResourceArrayGetAny(&(owner->dsmarr), &foundres)) { dsm_segment *res = (dsm_segment *) DatumGetPointer(foundres); if (isCommit) PrintDSMLeakWarning(res); dsm_detach(res); } /* Ditto for JIT contexts */ while (ResourceArrayGetAny(&(owner->jitarr), &foundres)) { JitContext *context = (JitContext *) PointerGetDatum(foundres); jit_release_context(context); } } else if (phase == RESOURCE_RELEASE_LOCKS) { if (isTopLevel) { /* * For a top-level xact we are going to release all locks (or at * least all non-session locks), so just do a single lmgr call at * the top of the recursion. */ if (owner == TopTransactionResourceOwner) { ProcReleaseLocks(isCommit); ReleasePredicateLocks(isCommit); } } else { /* * Release locks retail. Note that if we are committing a * subtransaction, we do NOT release its locks yet, but transfer * them to the parent. */ LOCALLOCK **locks; int nlocks; Assert(owner->parent != NULL); /* * Pass the list of locks owned by this resource owner to the lock * manager, unless it has overflowed. */ if (owner->nlocks > MAX_RESOWNER_LOCKS) { locks = NULL; nlocks = 0; } else { locks = owner->locks; nlocks = owner->nlocks; } if (isCommit) LockReassignCurrentOwner(locks, nlocks); else LockReleaseCurrentOwner(locks, nlocks); } } else if (phase == RESOURCE_RELEASE_AFTER_LOCKS) { /* * Release catcache references. Note that ReleaseCatCache will remove * the catref entry from our array, so we just have to iterate till * there are none. * * As with buffer pins, warn if any are left at commit time. */ while (ResourceArrayGetAny(&(owner->catrefarr), &foundres)) { HeapTuple res = (HeapTuple) DatumGetPointer(foundres); if (isCommit) PrintCatCacheLeakWarning(res); ReleaseCatCache(res); } /* Ditto for catcache lists */ while (ResourceArrayGetAny(&(owner->catlistrefarr), &foundres)) { CatCList *res = (CatCList *) DatumGetPointer(foundres); if (isCommit) PrintCatCacheListLeakWarning(res); ReleaseCatCacheList(res); } /* Ditto for plancache references */ while (ResourceArrayGetAny(&(owner->planrefarr), &foundres)) { CachedPlan *res = (CachedPlan *) DatumGetPointer(foundres); if (isCommit) PrintPlanCacheLeakWarning(res); ReleaseCachedPlan(res, true); } /* Ditto for tupdesc references */ while (ResourceArrayGetAny(&(owner->tupdescarr), &foundres)) { TupleDesc res = (TupleDesc) DatumGetPointer(foundres); if (isCommit) PrintTupleDescLeakWarning(res); DecrTupleDescRefCount(res); } /* Ditto for snapshot references */ while (ResourceArrayGetAny(&(owner->snapshotarr), &foundres)) { Snapshot res = (Snapshot) DatumGetPointer(foundres); if (isCommit) PrintSnapshotLeakWarning(res); UnregisterSnapshot(res); } /* Ditto for temporary files */ while (ResourceArrayGetAny(&(owner->filearr), &foundres)) { File res = DatumGetFile(foundres); if (isCommit) PrintFileLeakWarning(res); FileClose(res); } } /* Let add-on modules get a chance too */ for (item = ResourceRelease_callbacks; item; item = item->next) item->callback(phase, isCommit, isTopLevel, item->arg); CurrentResourceOwner = save; }
/* * Performs a compaction of an append-only relation in column-orientation. * * In non-utility mode, all compaction segment files should be * marked as in-use/in-compaction in the appendonlywriter.c code. If * set, the insert_segno should also be marked as in-use. * When the insert segno is negative, only truncate to eof operations * can be executed. * * The caller is required to hold either an AccessExclusiveLock (vacuum full) * or a ShareLock on the relation. */ void AOCSCompact(Relation aorel, List *compaction_segno, int insert_segno, bool isFull) { const char *relname; int total_segfiles; AOCSFileSegInfo **segfile_array; AOCSInsertDesc insertDesc = NULL; int i, segno; LockAcquireResult acquireResult; AOCSFileSegInfo *fsinfo; Snapshot appendOnlyMetaDataSnapshot = RegisterSnapshot(GetCatalogSnapshot(InvalidOid)); Assert(RelationIsAoCols(aorel)); Assert(Gp_role == GP_ROLE_EXECUTE || Gp_role == GP_ROLE_UTILITY); Assert(insert_segno >= 0); relname = RelationGetRelationName(aorel); elogif(Debug_appendonly_print_compaction, LOG, "Compact AO relation %s", relname); /* Get information about all the file segments we need to scan */ segfile_array = GetAllAOCSFileSegInfo(aorel, appendOnlyMetaDataSnapshot, &total_segfiles); if (insert_segno >= 0) { insertDesc = aocs_insert_init(aorel, insert_segno, false); } for (i = 0; i < total_segfiles; i++) { segno = segfile_array[i]->segno; if (!list_member_int(compaction_segno, segno)) { continue; } if (segno == insert_segno) { /* We cannot compact the segment file we are inserting to. */ continue; } /* * Try to get the transaction write-lock for the Append-Only segment * file. * * NOTE: This is a transaction scope lock that must be held until * commit / abort. */ acquireResult = LockRelationAppendOnlySegmentFile( &aorel->rd_node, segfile_array[i]->segno, AccessExclusiveLock, /* dontWait */ true); if (acquireResult == LOCKACQUIRE_NOT_AVAIL) { elog(DEBUG5, "compaction skips AOCS segfile %d, " "relation %s", segfile_array[i]->segno, relname); continue; } /* Re-fetch under the write lock to get latest committed eof. */ fsinfo = GetAOCSFileSegInfo(aorel, appendOnlyMetaDataSnapshot, segno); /* * This should not occur since this segfile info was found by the * "all" method, but better to catch for trouble shooting (possibly * index corruption?) */ if (fsinfo == NULL) elog(ERROR, "file seginfo for AOCS relation %s %u/%u/%u (segno=%u) is missing", relname, aorel->rd_node.spcNode, aorel->rd_node.dbNode, aorel->rd_node.relNode, segno); if (AppendOnlyCompaction_ShouldCompact(aorel, fsinfo->segno, fsinfo->total_tupcount, isFull, appendOnlyMetaDataSnapshot)) { AOCSSegmentFileFullCompaction(aorel, insertDesc, fsinfo, appendOnlyMetaDataSnapshot); } pfree(fsinfo); } if (insertDesc != NULL) aocs_insert_finish(insertDesc); if (segfile_array) { FreeAllAOCSSegFileInfo(segfile_array, total_segfiles); pfree(segfile_array); } UnregisterSnapshot(appendOnlyMetaDataSnapshot); }
/* * Performs a compaction of an append-only AOCS relation. * * In non-utility mode, all compaction segment files should be * marked as in-use/in-compaction in the appendonlywriter.c code. * */ void AOCSDrop(Relation aorel, List *compaction_segno) { const char *relname; int total_segfiles; AOCSFileSegInfo **segfile_array; int i, segno; LockAcquireResult acquireResult; AOCSFileSegInfo *fsinfo; Snapshot appendOnlyMetaDataSnapshot = RegisterSnapshot(GetCatalogSnapshot(InvalidOid)); Assert(Gp_role == GP_ROLE_EXECUTE || Gp_role == GP_ROLE_UTILITY); Assert(RelationIsAoCols(aorel)); relname = RelationGetRelationName(aorel); elogif(Debug_appendonly_print_compaction, LOG, "Drop AOCS relation %s", relname); /* Get information about all the file segments we need to scan */ segfile_array = GetAllAOCSFileSegInfo(aorel, appendOnlyMetaDataSnapshot, &total_segfiles); for (i = 0; i < total_segfiles; i++) { segno = segfile_array[i]->segno; if (!list_member_int(compaction_segno, segno)) { continue; } /* * Try to get the transaction write-lock for the Append-Only segment * file. * * NOTE: This is a transaction scope lock that must be held until * commit / abort. */ acquireResult = LockRelationAppendOnlySegmentFile( &aorel->rd_node, segfile_array[i]->segno, AccessExclusiveLock, /* dontWait */ true); if (acquireResult == LOCKACQUIRE_NOT_AVAIL) { elog(DEBUG5, "drop skips AOCS segfile %d, " "relation %s", segfile_array[i]->segno, relname); continue; } /* Re-fetch under the write lock to get latest committed eof. */ fsinfo = GetAOCSFileSegInfo(aorel, appendOnlyMetaDataSnapshot, segno); if (fsinfo->state == AOSEG_STATE_AWAITING_DROP) { Assert(HasLockForSegmentFileDrop(aorel)); AOCSCompaction_DropSegmentFile(aorel, segno); ClearAOCSFileSegInfo(aorel, segno, AOSEG_STATE_DEFAULT); } pfree(fsinfo); } if (segfile_array) { FreeAllAOCSSegFileInfo(segfile_array, total_segfiles); pfree(segfile_array); } UnregisterSnapshot(appendOnlyMetaDataSnapshot); }
/* * Truncates each segment file to the AOCS relation to its EOF. * If we cannot get a lock on the segment file (because e.g. a concurrent insert) * the segment file is skipped. */ void AOCSTruncateToEOF(Relation aorel) { const char *relname; int total_segfiles; AOCSFileSegInfo **segfile_array; int i, segno; LockAcquireResult acquireResult; AOCSFileSegInfo *fsinfo; Snapshot appendOnlyMetaDataSnapshot = RegisterSnapshot(GetCatalogSnapshot(InvalidOid)); Assert(RelationIsAoCols(aorel)); relname = RelationGetRelationName(aorel); elogif(Debug_appendonly_print_compaction, LOG, "Compact AO relation %s", relname); /* Get information about all the file segments we need to scan */ segfile_array = GetAllAOCSFileSegInfo(aorel, appendOnlyMetaDataSnapshot, &total_segfiles); for (i = 0; i < total_segfiles; i++) { segno = segfile_array[i]->segno; /* * Try to get the transaction write-lock for the Append-Only segment * file. * * NOTE: This is a transaction scope lock that must be held until * commit / abort. */ acquireResult = LockRelationAppendOnlySegmentFile( &aorel->rd_node, segfile_array[i]->segno, AccessExclusiveLock, /* dontWait */ true); if (acquireResult == LOCKACQUIRE_NOT_AVAIL) { elog(DEBUG5, "truncate skips AO segfile %d, " "relation %s", segfile_array[i]->segno, relname); continue; } /* Re-fetch under the write lock to get latest committed eof. */ fsinfo = GetAOCSFileSegInfo(aorel, appendOnlyMetaDataSnapshot, segno); /* * This should not occur since this segfile info was found by the * "all" method, but better to catch for trouble shooting (possibly * index corruption?) */ if (fsinfo == NULL) elog(ERROR, "file seginfo for AOCS relation %s %u/%u/%u (segno=%u) is missing", relname, aorel->rd_node.spcNode, aorel->rd_node.dbNode, aorel->rd_node.relNode, segno); AOCSSegmentFileTruncateToEOF(aorel, fsinfo); pfree(fsinfo); } if (segfile_array) { FreeAllAOCSSegFileInfo(segfile_array, total_segfiles); pfree(segfile_array); } UnregisterSnapshot(appendOnlyMetaDataSnapshot); }