/* * InitCatCachePhase2 -- external interface for CatalogCacheInitializeCache * * One reason to call this routine is to ensure that the relcache has * created entries for all the catalogs and indexes referenced by catcaches. * Therefore, provide an option to open the index as well as fixing the * cache itself. An exception is the indexes on pg_am, which we don't use * (cf. IndexScanOK). */ void InitCatCachePhase2(CatCache *cache, bool touch_index) { if (cache->cc_tupdesc == NULL) CatalogCacheInitializeCache(cache); if (touch_index && cache->id != AMOID && cache->id != AMNAME) { Relation idesc; /* * We must lock the underlying catalog before opening the index to * avoid deadlock, since index_open could possibly result in reading * this same catalog, and if anyone else is exclusive-locking this * catalog and index they'll be doing it in that order. */ LockRelationOid(cache->cc_reloid, AccessShareLock); idesc = index_open(cache->cc_indexoid, AccessShareLock); index_close(idesc, AccessShareLock); UnlockRelationOid(cache->cc_reloid, AccessShareLock); } }
/* * find_inheritance_children * * Returns a list containing the OIDs of all relations which * inherit *directly* from the relation with OID 'parentrelId'. * * The specified lock type is acquired on each child relation (but not on the * given rel; caller should already have locked it). If lockmode is NoLock * then no locks are acquired, but caller must beware of race conditions * against possible DROPs of child relations. */ List * find_inheritance_children(Oid parentrelId, LOCKMODE lockmode) { List *list = NIL; Relation relation; SysScanDesc scan; ScanKeyData key[1]; HeapTuple inheritsTuple; Oid inhrelid; Oid *oidarr; int maxoids, numoids, i; /* * Can skip the scan if pg_class shows the relation has never had a * subclass. */ if (!has_subclass(parentrelId)) return NIL; /* * Scan pg_inherits and build a working array of subclass OIDs. */ maxoids = 32; oidarr = (Oid *) palloc(maxoids * sizeof(Oid)); numoids = 0; relation = heap_open(InheritsRelationId, AccessShareLock); ScanKeyInit(&key[0], Anum_pg_inherits_inhparent, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(parentrelId)); scan = systable_beginscan(relation, InheritsParentIndexId, true, NULL, 1, key); while ((inheritsTuple = systable_getnext(scan)) != NULL) { inhrelid = ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhrelid; if (numoids >= maxoids) { maxoids *= 2; oidarr = (Oid *) repalloc(oidarr, maxoids * sizeof(Oid)); } oidarr[numoids++] = inhrelid; } systable_endscan(scan); heap_close(relation, AccessShareLock); /* * If we found more than one child, sort them by OID. This ensures * reasonably consistent behavior regardless of the vagaries of an * indexscan. This is important since we need to be sure all backends * lock children in the same order to avoid needless deadlocks. */ if (numoids > 1) qsort(oidarr, numoids, sizeof(Oid), oid_cmp); /* * Acquire locks and build the result list. */ for (i = 0; i < numoids; i++) { inhrelid = oidarr[i]; if (lockmode != NoLock) { /* Get the lock to synchronize against concurrent drop */ LockRelationOid(inhrelid, lockmode); /* * Now that we have the lock, double-check to see if the relation * really exists or not. If not, assume it was dropped while we * waited to acquire lock, and ignore it. */ if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(inhrelid))) { /* Release useless lock */ UnlockRelationOid(inhrelid, lockmode); /* And ignore this relation */ continue; } } list = lappend_oid(list, inhrelid); } pfree(oidarr); return list; }
/* * Create append-only auxiliary relations for target relation rel. * Returns true if they are newly created. If pg_appendonly has already * known those tables, don't create them and returns false. */ bool CreateAOAuxiliaryTable( Relation rel, const char *auxiliaryNamePrefix, char relkind, TupleDesc tupledesc, IndexInfo *indexInfo, Oid *classObjectId, int16 *coloptions) { char aoauxiliary_relname[NAMEDATALEN]; char aoauxiliary_idxname[NAMEDATALEN]; bool shared_relation; Oid relOid, aoauxiliary_relid = InvalidOid; Oid aoauxiliary_idxid = InvalidOid; ObjectAddress baseobject; ObjectAddress aoauxiliaryobject; Assert(RelationIsValid(rel)); Assert(RelationIsAoRows(rel) || RelationIsAoCols(rel)); Assert(auxiliaryNamePrefix); Assert(tupledesc); Assert(classObjectId); if (relkind != RELKIND_AOSEGMENTS) Assert(indexInfo); shared_relation = rel->rd_rel->relisshared; /* * We cannot allow creating an auxiliary table for a shared relation * after initdb (because there's no way to let other databases know * this visibility map. */ if (shared_relation && !IsBootstrapProcessingMode()) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("shared tables cannot have append-only auxiliary relations after initdb"))); relOid = RelationGetRelid(rel); switch(relkind) { case RELKIND_AOVISIMAP: GetAppendOnlyEntryAuxOids(relOid, SnapshotNow, NULL, NULL, NULL, &aoauxiliary_relid, &aoauxiliary_idxid); break; case RELKIND_AOBLOCKDIR: GetAppendOnlyEntryAuxOids(relOid, SnapshotNow, NULL, &aoauxiliary_relid, &aoauxiliary_idxid, NULL, NULL); break; case RELKIND_AOSEGMENTS: GetAppendOnlyEntryAuxOids(relOid, SnapshotNow, &aoauxiliary_relid, NULL, NULL, NULL, NULL); break; default: elog(ERROR, "unsupported auxiliary relkind '%c'", relkind); } /* * Does it have the auxiliary relation? */ if (OidIsValid(aoauxiliary_relid)) { return false; } snprintf(aoauxiliary_relname, sizeof(aoauxiliary_relname), "%s_%u", auxiliaryNamePrefix, relOid); snprintf(aoauxiliary_idxname, sizeof(aoauxiliary_idxname), "%s_%u_index", auxiliaryNamePrefix, relOid); /* * We place auxiliary relation in the pg_aoseg namespace * even if its master relation is a temp table. There cannot be * any naming collision, and the auxiliary relation will be * destroyed when its master is, so there is no need to handle * the aovisimap relation as temp. */ aoauxiliary_relid = heap_create_with_catalog(aoauxiliary_relname, PG_AOSEGMENT_NAMESPACE, rel->rd_rel->reltablespace, InvalidOid, rel->rd_rel->relowner, tupledesc, /* relam */ InvalidOid, relkind, RELSTORAGE_HEAP, shared_relation, true, /* bufferPoolBulkLoad */ false, 0, ONCOMMIT_NOOP, NULL, /* GP Policy */ (Datum) 0, true, /* valid_opts */ false, /* persistentTid */ NULL, /* persistentSerialNum */ NULL); /* Make this table visible, else index creation will fail */ CommandCounterIncrement(); /* Create an index on AO auxiliary tables (like visimap) except for pg_aoseg table */ if (relkind != RELKIND_AOSEGMENTS) { aoauxiliary_idxid = index_create(aoauxiliary_relid, aoauxiliary_idxname, InvalidOid, indexInfo, BTREE_AM_OID, rel->rd_rel->reltablespace, classObjectId, coloptions, (Datum) 0, true, false, true, false, false, NULL); /* Unlock target table -- no one can see it */ UnlockRelationOid(aoauxiliary_relid, ShareLock); /* Unlock the index -- no one can see it anyway */ UnlockRelationOid(aoauxiliary_idxid, AccessExclusiveLock); } /* * Store the auxiliary table's OID in the parent relation's pg_appendonly row. * TODO (How to generalize this?) */ switch (relkind) { case RELKIND_AOVISIMAP: UpdateAppendOnlyEntryAuxOids(relOid, InvalidOid, InvalidOid, InvalidOid, aoauxiliary_relid, aoauxiliary_idxid); break; case RELKIND_AOBLOCKDIR: UpdateAppendOnlyEntryAuxOids(relOid, InvalidOid, aoauxiliary_relid, aoauxiliary_idxid, InvalidOid, InvalidOid); break; case RELKIND_AOSEGMENTS: UpdateAppendOnlyEntryAuxOids(relOid, aoauxiliary_relid, InvalidOid, InvalidOid, InvalidOid, InvalidOid); break; default: elog(ERROR, "unsupported auxiliary relkind '%c'", relkind); } /* * Register dependency from the auxiliary table to the master, so that the * aoseg table will be deleted if the master is. */ baseobject.classId = RelationRelationId; baseobject.objectId = relOid; baseobject.objectSubId = 0; aoauxiliaryobject.classId = RelationRelationId; aoauxiliaryobject.objectId = aoauxiliary_relid; aoauxiliaryobject.objectSubId = 0; recordDependencyOn(&aoauxiliaryobject, &baseobject, DEPENDENCY_INTERNAL); /* * Make changes visible */ CommandCounterIncrement(); return true; }
/* * create_toast_table --- internal workhorse * * rel is already opened and exclusive-locked * toastOid and toastIndexOid are normally InvalidOid, but during * bootstrap they can be nonzero to specify hand-assigned OIDs */ static bool create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, bool is_part_child) { Oid relOid = RelationGetRelid(rel); HeapTuple reltup; TupleDesc tupdesc; bool shared_relation; Relation class_rel; Oid toast_relid; Oid toast_idxid; Oid namespaceid; char toast_relname[NAMEDATALEN]; char toast_idxname[NAMEDATALEN]; IndexInfo *indexInfo; Oid classObjectId[2]; int16 coloptions[2]; ObjectAddress baseobject, toastobject; /* * Is it already toasted? */ if (rel->rd_rel->reltoastrelid != InvalidOid) return false; /* * Check to see whether the table actually needs a TOAST table. */ if (!RelationNeedsToastTable(rel)) return false; /* * Toast table is shared if and only if its parent is. * * We cannot allow toasting a shared relation after initdb (because * there's no way to mark it toasted in other databases' pg_class). */ shared_relation = rel->rd_rel->relisshared; if (shared_relation && !IsBootstrapProcessingMode()) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("shared tables cannot be toasted after initdb"))); /* * Create the toast table and its index */ snprintf(toast_relname, sizeof(toast_relname), "pg_toast_%u", relOid); snprintf(toast_idxname, sizeof(toast_idxname), "pg_toast_%u_index", relOid); /* this is pretty painful... need a tuple descriptor */ tupdesc = CreateTemplateTupleDesc(3, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "chunk_id", OIDOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "chunk_seq", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "chunk_data", BYTEAOID, -1, 0); /* * Ensure that the toast table doesn't itself get toasted, or we'll be * toast :-(. This is essential for chunk_data because type bytea is * toastable; hit the other two just to be sure. */ tupdesc->attrs[0]->attstorage = 'p'; tupdesc->attrs[1]->attstorage = 'p'; tupdesc->attrs[2]->attstorage = 'p'; /* * Toast tables for regular relations go in pg_toast; those for temp * relations go into the per-backend temp-toast-table namespace. */ if (rel->rd_istemp) namespaceid = GetTempToastNamespace(); else namespaceid = PG_TOAST_NAMESPACE; /* * XXX would it make sense to apply the master's reloptions to the toast * table? Or maybe some toast-specific reloptions? */ toast_relid = heap_create_with_catalog(toast_relname, namespaceid, rel->rd_rel->reltablespace, toastOid, rel->rd_rel->relowner, tupdesc, /* relam */ InvalidOid, RELKIND_TOASTVALUE, RELSTORAGE_HEAP, shared_relation, true, /* bufferPoolBulkLoad */ false, 0, ONCOMMIT_NOOP, NULL, /* CDB POLICY */ (Datum) 0, true, /* valid_opts */ false, /* persistentTid */ NULL, /* persistentSerialNum */ NULL); /* make the toast relation visible, else index creation will fail */ CommandCounterIncrement(); /* * Create unique index on chunk_id, chunk_seq. * * NOTE: the normal TOAST access routines could actually function with a * single-column index on chunk_id only. However, the slice access * routines use both columns for faster access to an individual chunk. In * addition, we want it to be unique as a check against the possibility of * duplicate TOAST chunk OIDs. The index might also be a little more * efficient this way, since btree isn't all that happy with large numbers * of equal keys. */ indexInfo = makeNode(IndexInfo); indexInfo->ii_NumIndexAttrs = 2; indexInfo->ii_KeyAttrNumbers[0] = 1; indexInfo->ii_KeyAttrNumbers[1] = 2; indexInfo->ii_Expressions = NIL; indexInfo->ii_ExpressionsState = NIL; indexInfo->ii_Predicate = NIL; indexInfo->ii_PredicateState = NIL; indexInfo->ii_Unique = true; indexInfo->ii_ReadyForInserts = true; indexInfo->ii_Concurrent = false; indexInfo->ii_BrokenHotChain = false; classObjectId[0] = OID_BTREE_OPS_OID; classObjectId[1] = INT4_BTREE_OPS_OID; coloptions[0] = 0; coloptions[1] = 0; toast_idxid = index_create(toast_relid, toast_idxname, toastIndexOid, indexInfo, BTREE_AM_OID, rel->rd_rel->reltablespace, classObjectId, coloptions, (Datum) 0, true, false, true, false, false, NULL); /* * If this is a partitioned child, we can unlock since the master is * already locked. */ if (is_part_child) { UnlockRelationOid(toast_relid, ShareLock); UnlockRelationOid(toast_idxid, AccessExclusiveLock); } /* * Store the toast table's OID in the parent relation's pg_class row */ class_rel = heap_open(RelationRelationId, RowExclusiveLock); reltup = SearchSysCacheCopy(RELOID, ObjectIdGetDatum(relOid), 0, 0, 0); if (!HeapTupleIsValid(reltup)) elog(ERROR, "cache lookup failed for relation %u", relOid); ((Form_pg_class) GETSTRUCT(reltup))->reltoastrelid = toast_relid; if (!IsBootstrapProcessingMode()) { /* normal case, use a transactional update */ simple_heap_update(class_rel, &reltup->t_self, reltup); /* Keep catalog indexes current */ CatalogUpdateIndexes(class_rel, reltup); } else { /* While bootstrapping, we cannot UPDATE, so overwrite in-place */ heap_inplace_update(class_rel, reltup); } heap_freetuple(reltup); heap_close(class_rel, RowExclusiveLock); /* * Register dependency from the toast table to the master, so that the * toast table will be deleted if the master is. Skip this in bootstrap * mode. */ if (!IsBootstrapProcessingMode()) { baseobject.classId = RelationRelationId; baseobject.objectId = relOid; baseobject.objectSubId = 0; toastobject.classId = RelationRelationId; toastobject.objectId = toast_relid; toastobject.objectSubId = 0; recordDependencyOn(&toastobject, &baseobject, DEPENDENCY_INTERNAL); } /* * Make changes visible */ CommandCounterIncrement(); return true; }
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; }
/* * create_aoblkdir_table * * rel is already opened and exclusive-locked. * comptypeOid is InvalidOid. */ static bool create_aoblkdir_table(Relation rel, Oid aoblkdirOid, Oid aoblkdirIndexOid, Oid *comptypeOid) { Oid relOid = RelationGetRelid(rel); Oid aoblkdir_relid; Oid aoblkdir_idxid; bool shared_relation = rel->rd_rel->relisshared; char aoblkdir_relname[NAMEDATALEN]; char aoblkdir_idxname[NAMEDATALEN]; TupleDesc tupdesc; IndexInfo *indexInfo; Oid classObjectId[3]; ObjectAddress baseobject; ObjectAddress aoblkdirobject; Oid tablespaceOid = ChooseTablespaceForLimitedObject(rel->rd_rel->reltablespace); if (!RelationIsAoRows(rel)) return false; /* * We cannot allow creating a block directory for a shared relation * after initdb (because there's no way to let other databases know * this block directory. */ if (shared_relation && !IsBootstrapProcessingMode()) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("shared tables cannot have block directory after initdb"))); GetAppendOnlyEntryAuxOids(relOid, SnapshotNow, NULL,NULL, &aoblkdir_relid, &aoblkdir_idxid); /* * Does it have a block directory? */ if (aoblkdir_relid != InvalidOid) { return false; } snprintf(aoblkdir_relname, sizeof(aoblkdir_relname), "pg_aoblkdir_%u", relOid); snprintf(aoblkdir_idxname, sizeof(aoblkdir_idxname), "pg_aoblkdir_%u_index", relOid); /* Create a tuple descriptor */ tupdesc = CreateTemplateTupleDesc(4, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "segno", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "columngroup_no", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "first_row_no", INT8OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 4, "minipage", VARBITOID, -1, 0); /* * We don't want any toast columns here. */ tupdesc->attrs[0]->attstorage = 'p'; tupdesc->attrs[1]->attstorage = 'p'; tupdesc->attrs[2]->attstorage = 'p'; tupdesc->attrs[2]->attstorage = 'p'; /* * We place aoblkdir relation in the pg_aoseg namespace * even if its master relation is a temp table. There cannot be * any naming collision, and the aoblkdir relation will be * destroyed when its master is, so there is no need to handle * the aoblkdir relation as temp. */ aoblkdir_relid = heap_create_with_catalog(aoblkdir_relname, PG_AOSEGMENT_NAMESPACE, tablespaceOid, aoblkdirOid, rel->rd_rel->relowner, tupdesc, /* relam */ InvalidOid, RELKIND_AOBLOCKDIR, RELSTORAGE_HEAP, shared_relation, true, /* bufferPoolBulkLoad */ false, 0, ONCOMMIT_NOOP, NULL, /* GP Policy */ (Datum) 0, true, comptypeOid, /* persistentTid */ NULL, /* persistentSerialNum */ NULL); /* Make this table visible, else index creation will fail */ CommandCounterIncrement(); /* * Create index on segno, first_row_no. */ indexInfo = makeNode(IndexInfo); indexInfo->ii_NumIndexAttrs = 3; indexInfo->ii_KeyAttrNumbers[0] = 1; indexInfo->ii_KeyAttrNumbers[1] = 2; indexInfo->ii_KeyAttrNumbers[2] = 3; indexInfo->ii_Expressions = NIL; indexInfo->ii_ExpressionsState = NIL; indexInfo->ii_Predicate = NIL; indexInfo->ii_PredicateState = NIL; indexInfo->ii_Unique = false; indexInfo->ii_Concurrent = false; classObjectId[0] = INT4_BTREE_OPS_OID; classObjectId[1] = INT4_BTREE_OPS_OID; classObjectId[2] = INT8_BTREE_OPS_OID; aoblkdir_idxid = index_create(aoblkdirOid, aoblkdir_idxname, aoblkdirIndexOid, indexInfo, BTREE_AM_OID, tablespaceOid, classObjectId, (Datum) 0, true, false, (Oid *) NULL, true, false, false, NULL); /* Unlock target table -- no one can see it */ UnlockRelationOid(aoblkdirOid, ShareLock); /* Unlock the index -- no one can see it anyway */ UnlockRelationOid(aoblkdirIndexOid, AccessExclusiveLock); /* * Store the aoblkdir table's OID in the parent relation's pg_appendonly row. */ UpdateAppendOnlyEntryAuxOids(relOid, InvalidOid, InvalidOid, aoblkdir_relid, aoblkdir_idxid); /* * Register dependency from the aoseg table to the master, so that the * aoseg table will be deleted if the master is. */ baseobject.classId = RelationRelationId; baseobject.objectId = relOid; baseobject.objectSubId = 0; aoblkdirobject.classId = RelationRelationId; aoblkdirobject.objectId = aoblkdirOid; aoblkdirobject.objectSubId = 0; recordDependencyOn(&aoblkdirobject, &baseobject, DEPENDENCY_INTERNAL); /* * Make changes visible */ CommandCounterIncrement(); return true; }