⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cluster.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 2 页
字号:
			simple_heap_update(pg_index, &indexTuple->t_self, indexTuple);			CatalogUpdateIndexes(pg_index, indexTuple);			/* Ensure we see the update in the index's relcache entry */			CacheInvalidateRelcacheByRelid(thisIndexOid);		}		else if (thisIndexOid == indexOid)		{			indexForm->indisclustered = true;			simple_heap_update(pg_index, &indexTuple->t_self, indexTuple);			CatalogUpdateIndexes(pg_index, indexTuple);			/* Ensure we see the update in the index's relcache entry */			CacheInvalidateRelcacheByRelid(thisIndexOid);		}		heap_freetuple(indexTuple);	}	heap_close(pg_index, RowExclusiveLock);}/* * rebuild_relation: rebuild an existing relation in index order * * OldHeap: table to rebuild --- must be opened and exclusive-locked! * indexOid: index to cluster by * * NB: this routine closes OldHeap at the right time; caller should not. */static voidrebuild_relation(Relation OldHeap, Oid indexOid){	Oid			tableOid = RelationGetRelid(OldHeap);	Oid			tableSpace = OldHeap->rd_rel->reltablespace;	Oid			OIDNewHeap;	char		NewHeapName[NAMEDATALEN];	ObjectAddress object;	/* Mark the correct index as clustered */	mark_index_clustered(OldHeap, indexOid);	/* Close relcache entry, but keep lock until transaction commit */	heap_close(OldHeap, NoLock);	/*	 * Create the new heap, using a temporary name in the same namespace as	 * the existing table.	NOTE: there is some risk of collision with user	 * relnames.  Working around this seems more trouble than it's worth; in	 * particular, we can't create the new heap in a different namespace from	 * the old, or we will have problems with the TEMP status of temp tables.	 */	snprintf(NewHeapName, sizeof(NewHeapName), "pg_temp_%u", tableOid);	OIDNewHeap = make_new_heap(tableOid, NewHeapName, tableSpace);	/*	 * We don't need CommandCounterIncrement() because make_new_heap did it.	 */	/*	 * Copy the heap data into the new table in the desired order.	 */	copy_heap_data(OIDNewHeap, tableOid, indexOid);	/* To make the new heap's data visible (probably not needed?). */	CommandCounterIncrement();	/* Swap the physical files of the old and new heaps. */	swap_relation_files(tableOid, OIDNewHeap);	CommandCounterIncrement();	/* Destroy new heap with old filenode */	object.classId = RelationRelationId;	object.objectId = OIDNewHeap;	object.objectSubId = 0;	/*	 * The new relation is local to our transaction and we know nothing	 * depends on it, so DROP_RESTRICT should be OK.	 */	performDeletion(&object, DROP_RESTRICT);	/* performDeletion does CommandCounterIncrement at end */	/*	 * Rebuild each index on the relation (but not the toast table, which is	 * all-new at this point).	We do not need CommandCounterIncrement()	 * because reindex_relation does it.	 */	reindex_relation(tableOid, false);}/* * Create the new table that we will fill with correctly-ordered data. */Oidmake_new_heap(Oid OIDOldHeap, const char *NewName, Oid NewTableSpace){	TupleDesc	OldHeapDesc,				tupdesc;	Oid			OIDNewHeap;	Relation	OldHeap;	OldHeap = heap_open(OIDOldHeap, AccessExclusiveLock);	OldHeapDesc = RelationGetDescr(OldHeap);	/*	 * Need to make a copy of the tuple descriptor, since	 * heap_create_with_catalog modifies it.	 */	tupdesc = CreateTupleDescCopyConstr(OldHeapDesc);	OIDNewHeap = heap_create_with_catalog(NewName,										  RelationGetNamespace(OldHeap),										  NewTableSpace,										  InvalidOid,										  OldHeap->rd_rel->relowner,										  tupdesc,										  OldHeap->rd_rel->relkind,										  OldHeap->rd_rel->relisshared,										  true,										  0,										  ONCOMMIT_NOOP,										  allowSystemTableMods);	/*	 * Advance command counter so that the newly-created relation's catalog	 * tuples will be visible to heap_open.	 */	CommandCounterIncrement();	/*	 * If necessary, create a TOAST table for the new relation. Note that	 * AlterTableCreateToastTable ends with CommandCounterIncrement(), so that	 * the TOAST table will be visible for insertion.	 */	AlterTableCreateToastTable(OIDNewHeap, true);	heap_close(OldHeap, NoLock);	return OIDNewHeap;}/* * Do the physical copying of heap data. */static voidcopy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex){	Relation	NewHeap,				OldHeap,				OldIndex;	TupleDesc	oldTupDesc;	TupleDesc	newTupDesc;	int			natts;	Datum	   *values;	char	   *nulls;	IndexScanDesc scan;	HeapTuple	tuple;	/*	 * Open the relations we need.	 */	NewHeap = heap_open(OIDNewHeap, AccessExclusiveLock);	OldHeap = heap_open(OIDOldHeap, AccessExclusiveLock);	OldIndex = index_open(OIDOldIndex);	/*	 * Their tuple descriptors should be exactly alike, but here we only need	 * assume that they have the same number of columns.	 */	oldTupDesc = RelationGetDescr(OldHeap);	newTupDesc = RelationGetDescr(NewHeap);	Assert(newTupDesc->natts == oldTupDesc->natts);	/* Preallocate values/nulls arrays */	natts = newTupDesc->natts;	values = (Datum *) palloc0(natts * sizeof(Datum));	nulls = (char *) palloc(natts * sizeof(char));	memset(nulls, 'n', natts * sizeof(char));	/*	 * Scan through the OldHeap on the OldIndex and copy each tuple into the	 * NewHeap.	 */	scan = index_beginscan(OldHeap, OldIndex, SnapshotNow, 0, (ScanKey) NULL);	while ((tuple = index_getnext(scan, ForwardScanDirection)) != NULL)	{		/*		 * We cannot simply pass the tuple to heap_insert(), for several		 * reasons:		 *		 * 1. heap_insert() will overwrite the commit-status fields of the		 * tuple it's handed.  This would trash the source relation, which is		 * bad news if we abort later on.  (This was a bug in releases thru		 * 7.0)		 *		 * 2. We'd like to squeeze out the values of any dropped columns, both		 * to save space and to ensure we have no corner-case failures. (It's		 * possible for example that the new table hasn't got a TOAST table		 * and so is unable to store any large values of dropped cols.)		 *		 * 3. The tuple might not even be legal for the new table; this is		 * currently only known to happen as an after-effect of ALTER TABLE		 * SET WITHOUT OIDS.		 *		 * So, we must reconstruct the tuple from component Datums.		 */		HeapTuple	copiedTuple;		int			i;		heap_deformtuple(tuple, oldTupDesc, values, nulls);		/* Be sure to null out any dropped columns */		for (i = 0; i < natts; i++)		{			if (newTupDesc->attrs[i]->attisdropped)				nulls[i] = 'n';		}		copiedTuple = heap_formtuple(newTupDesc, values, nulls);		/* Preserve OID, if any */		if (NewHeap->rd_rel->relhasoids)			HeapTupleSetOid(copiedTuple, HeapTupleGetOid(tuple));		simple_heap_insert(NewHeap, copiedTuple);		heap_freetuple(copiedTuple);		CHECK_FOR_INTERRUPTS();	}	index_endscan(scan);	pfree(values);	pfree(nulls);	index_close(OldIndex);	heap_close(OldHeap, NoLock);	heap_close(NewHeap, NoLock);}/* * Swap the physical files of two given relations. * * We swap the physical identity (reltablespace and relfilenode) while * keeping the same logical identities of the two relations. * * Also swap any TOAST links, so that the toast data moves along with * the main-table data. */voidswap_relation_files(Oid r1, Oid r2){	Relation	relRelation;	HeapTuple	reltup1,				reltup2;	Form_pg_class relform1,				relform2;	Oid			swaptemp;	CatalogIndexState indstate;	/* We need writable copies of both pg_class tuples. */	relRelation = heap_open(RelationRelationId, RowExclusiveLock);	reltup1 = SearchSysCacheCopy(RELOID,								 ObjectIdGetDatum(r1),								 0, 0, 0);	if (!HeapTupleIsValid(reltup1))		elog(ERROR, "cache lookup failed for relation %u", r1);	relform1 = (Form_pg_class) GETSTRUCT(reltup1);	reltup2 = SearchSysCacheCopy(RELOID,								 ObjectIdGetDatum(r2),								 0, 0, 0);	if (!HeapTupleIsValid(reltup2))		elog(ERROR, "cache lookup failed for relation %u", r2);	relform2 = (Form_pg_class) GETSTRUCT(reltup2);	/*	 * Actually swap the fields in the two tuples	 */	swaptemp = relform1->relfilenode;	relform1->relfilenode = relform2->relfilenode;	relform2->relfilenode = swaptemp;	swaptemp = relform1->reltablespace;	relform1->reltablespace = relform2->reltablespace;	relform2->reltablespace = swaptemp;	swaptemp = relform1->reltoastrelid;	relform1->reltoastrelid = relform2->reltoastrelid;	relform2->reltoastrelid = swaptemp;	/* we should not swap reltoastidxid */	/* swap size statistics too, since new rel has freshly-updated stats */	{		int4		swap_pages;		float4		swap_tuples;		swap_pages = relform1->relpages;		relform1->relpages = relform2->relpages;		relform2->relpages = swap_pages;		swap_tuples = relform1->reltuples;		relform1->reltuples = relform2->reltuples;		relform2->reltuples = swap_tuples;	}	/* Update the tuples in pg_class */	simple_heap_update(relRelation, &reltup1->t_self, reltup1);	simple_heap_update(relRelation, &reltup2->t_self, reltup2);	/* Keep system catalogs current */	indstate = CatalogOpenIndexes(relRelation);	CatalogIndexInsert(indstate, reltup1);	CatalogIndexInsert(indstate, reltup2);	CatalogCloseIndexes(indstate);	/*	 * If we have toast tables associated with the relations being swapped,	 * change their dependency links to re-associate them with their new	 * owning relations.  Otherwise the wrong one will get dropped ...	 *	 * NOTE: it is possible that only one table has a toast table; this can	 * happen in CLUSTER if there were dropped columns in the old table, and	 * in ALTER TABLE when adding or changing type of columns.	 *	 * NOTE: at present, a TOAST table's only dependency is the one on its	 * owning table.  If more are ever created, we'd need to use something	 * more selective than deleteDependencyRecordsFor() to get rid of only the	 * link we want.	 */	if (relform1->reltoastrelid || relform2->reltoastrelid)	{		ObjectAddress baseobject,					toastobject;		long		count;		/* Delete old dependencies */		if (relform1->reltoastrelid)		{			count = deleteDependencyRecordsFor(RelationRelationId,											   relform1->reltoastrelid);			if (count != 1)				elog(ERROR, "expected one dependency record for TOAST table, found %ld",					 count);		}		if (relform2->reltoastrelid)		{			count = deleteDependencyRecordsFor(RelationRelationId,											   relform2->reltoastrelid);			if (count != 1)				elog(ERROR, "expected one dependency record for TOAST table, found %ld",					 count);		}		/* Register new dependencies */		baseobject.classId = RelationRelationId;		baseobject.objectSubId = 0;		toastobject.classId = RelationRelationId;		toastobject.objectSubId = 0;		if (relform1->reltoastrelid)		{			baseobject.objectId = r1;			toastobject.objectId = relform1->reltoastrelid;			recordDependencyOn(&toastobject, &baseobject, DEPENDENCY_INTERNAL);		}		if (relform2->reltoastrelid)		{			baseobject.objectId = r2;			toastobject.objectId = relform2->reltoastrelid;			recordDependencyOn(&toastobject, &baseobject, DEPENDENCY_INTERNAL);		}	}	/*	 * Blow away the old relcache entries now.	We need this kluge because	 * relcache.c keeps a link to the smgr relation for the physical file, and	 * that will be out of date as soon as we do CommandCounterIncrement.	 * Whichever of the rels is the second to be cleared during cache	 * invalidation will have a dangling reference to an already-deleted smgr	 * relation.  Rather than trying to avoid this by ordering operations just	 * so, it's easiest to not have the relcache entries there at all.	 * (Fortunately, since one of the entries is local in our transaction,	 * it's sufficient to clear out our own relcache this way; the problem	 * cannot arise for other backends when they see our update on the	 * non-local relation.)	 */	RelationForgetRelation(r1);	RelationForgetRelation(r2);	/* Clean up. */	heap_freetuple(reltup1);	heap_freetuple(reltup2);	heap_close(relRelation, RowExclusiveLock);}/* * Get a list of tables that the current user owns and * have indisclustered set.  Return the list in a List * of rvsToCluster * with the tableOid and the indexOid on which the table is already * clustered. */static List *get_tables_to_cluster(MemoryContext cluster_context){	Relation	indRelation;	HeapScanDesc scan;	ScanKeyData entry;	HeapTuple	indexTuple;	Form_pg_index index;	MemoryContext old_context;	RelToCluster *rvtc;	List	   *rvs = NIL;	/*	 * Get all indexes that have indisclustered set and are owned by	 * appropriate user. System relations or nailed-in relations cannot ever	 * have indisclustered set, because CLUSTER will refuse to set it when	 * called with one of them as argument.	 */	indRelation = heap_open(IndexRelationId, AccessShareLock);	ScanKeyInit(&entry,				Anum_pg_index_indisclustered,				BTEqualStrategyNumber, F_BOOLEQ,				BoolGetDatum(true));	scan = heap_beginscan(indRelation, SnapshotNow, 1, &entry);	while ((indexTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)	{		index = (Form_pg_index) GETSTRUCT(indexTuple);		if (!pg_class_ownercheck(index->indrelid, GetUserId()))			continue;		/*		 * We have to build the list in a different memory context so it will		 * survive the cross-transaction processing		 */		old_context = MemoryContextSwitchTo(cluster_context);		rvtc = (RelToCluster *) palloc(sizeof(RelToCluster));		rvtc->tableOid = index->indrelid;		rvtc->indexOid = index->indexrelid;		rvs = lcons(rvtc, rvs);		MemoryContextSwitchTo(old_context);	}	heap_endscan(scan);	relation_close(indRelation, AccessShareLock);	return rvs;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -