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

📄 index.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 4 页
字号:
 * unable to store NULLs. */doubleIndexBuildHeapScan(Relation heapRelation,				   Relation indexRelation,				   IndexInfo *indexInfo,				   IndexBuildCallback callback,				   void *callback_state){	HeapScanDesc scan;	HeapTuple	heapTuple;	TupleDesc	heapDescriptor;	Datum		attdata[INDEX_MAX_KEYS];	char		nulls[INDEX_MAX_KEYS];	double		reltuples;	List	   *predicate;	TupleTable	tupleTable;	TupleTableSlot *slot;	EState	   *estate;	ExprContext *econtext;	Snapshot	snapshot;	TransactionId OldestXmin;	/*	 * sanity checks	 */	Assert(OidIsValid(indexRelation->rd_rel->relam));	heapDescriptor = RelationGetDescr(heapRelation);	/*	 * Need an EState for evaluation of index expressions and	 * partial-index predicates.	 */	estate = CreateExecutorState();	econtext = GetPerTupleExprContext(estate);	/*	 * If this is a predicate (partial) index, we will need to evaluate	 * the predicate using ExecQual, which requires the current tuple to	 * be in a slot of a TupleTable.  Likewise if there are any	 * expressions.	 */	if (indexInfo->ii_Predicate != NIL || indexInfo->ii_Expressions != NIL)	{		tupleTable = ExecCreateTupleTable(1);		slot = ExecAllocTableSlot(tupleTable);		ExecSetSlotDescriptor(slot, heapDescriptor, false);		/* Arrange for econtext's scan tuple to be the tuple under test */		econtext->ecxt_scantuple = slot;		/* Set up execution state for predicate. */		predicate = (List *)			ExecPrepareExpr((Expr *) indexInfo->ii_Predicate,							estate);	}	else	{		tupleTable = NULL;		slot = NULL;		predicate = NIL;	}	/*	 * Ok, begin our scan of the base relation.  We use SnapshotAny	 * because we must retrieve all tuples and do our own time qual	 * checks.	 */	if (IsBootstrapProcessingMode())	{		snapshot = SnapshotNow;		OldestXmin = InvalidTransactionId;	}	else	{		snapshot = SnapshotAny;		OldestXmin = GetOldestXmin(heapRelation->rd_rel->relisshared);	}	scan = heap_beginscan(heapRelation, /* relation */						  snapshot,		/* seeself */						  0,	/* number of keys */						  (ScanKey) NULL);		/* scan key */	reltuples = 0;	/*	 * Scan all tuples in the base relation.	 */	while ((heapTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)	{		bool		tupleIsAlive;		CHECK_FOR_INTERRUPTS();		if (snapshot == SnapshotAny)		{			/* do our own time qual check */			bool		indexIt;			uint16		sv_infomask;			/*			 * HeapTupleSatisfiesVacuum may update tuple's hint status			 * bits. We could possibly get away with not locking the			 * buffer here, since caller should hold ShareLock on the			 * relation, but let's be conservative about it.			 */			LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);			sv_infomask = heapTuple->t_data->t_infomask;			switch (HeapTupleSatisfiesVacuum(heapTuple->t_data, OldestXmin))			{				case HEAPTUPLE_DEAD:					indexIt = false;					tupleIsAlive = false;					break;				case HEAPTUPLE_LIVE:					indexIt = true;					tupleIsAlive = true;					break;				case HEAPTUPLE_RECENTLY_DEAD:					/*					 * If tuple is recently deleted then we must index it					 * anyway to keep VACUUM from complaining.					 */					indexIt = true;					tupleIsAlive = false;					break;				case HEAPTUPLE_INSERT_IN_PROGRESS:					/*					 * Since caller should hold ShareLock or better, we					 * should not see any tuples inserted by open					 * transactions --- unless it's our own transaction.					 * (Consider INSERT followed by CREATE INDEX within a					 * transaction.)  An exception occurs when reindexing					 * a system catalog, because we often release lock on					 * system catalogs before committing.					 */					if (!TransactionIdIsCurrentTransactionId(							  HeapTupleHeaderGetXmin(heapTuple->t_data))						&& !IsSystemRelation(heapRelation))						elog(ERROR, "concurrent insert in progress");					indexIt = true;					tupleIsAlive = true;					break;				case HEAPTUPLE_DELETE_IN_PROGRESS:					/*					 * Since caller should hold ShareLock or better, we					 * should not see any tuples deleted by open					 * transactions --- unless it's our own transaction.					 * (Consider DELETE followed by CREATE INDEX within a					 * transaction.)  An exception occurs when reindexing					 * a system catalog, because we often release lock on					 * system catalogs before committing.					 */					if (!TransactionIdIsCurrentTransactionId(							  HeapTupleHeaderGetXmax(heapTuple->t_data))						&& !IsSystemRelation(heapRelation))						elog(ERROR, "concurrent delete in progress");					indexIt = true;					tupleIsAlive = false;					break;				default:					elog(ERROR, "unexpected HeapTupleSatisfiesVacuum result");					indexIt = tupleIsAlive = false;		/* keep compiler quiet */					break;			}			/* check for hint-bit update by HeapTupleSatisfiesVacuum */			if (sv_infomask != heapTuple->t_data->t_infomask)				SetBufferCommitInfoNeedsSave(scan->rs_cbuf);			LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK);			if (!indexIt)				continue;		}		else		{			/* heap_getnext did the time qual check */			tupleIsAlive = true;		}		reltuples += 1;		MemoryContextReset(econtext->ecxt_per_tuple_memory);		/* Set up for predicate or expression evaluation */		if (slot)			ExecStoreTuple(heapTuple, slot, InvalidBuffer, false);		/*		 * In a partial index, discard tuples that don't satisfy the		 * predicate.  We can also discard recently-dead tuples, since		 * VACUUM doesn't complain about tuple count mismatch for partial		 * indexes.		 */		if (predicate != NIL)		{			if (!tupleIsAlive)				continue;			if (!ExecQual(predicate, econtext, false))				continue;		}		/*		 * For the current heap tuple, extract all the attributes we use		 * in this index, and note which are null.	This also performs		 * evaluation of any expressions needed.		 */		FormIndexDatum(indexInfo,					   heapTuple,					   heapDescriptor,					   estate,					   attdata,					   nulls);		/*		 * You'd think we should go ahead and build the index tuple here,		 * but some index AMs want to do further processing on the data		 * first.  So pass the attdata and nulls arrays, instead.		 */		/* Call the AM's callback routine to process the tuple */		callback(indexRelation, heapTuple, attdata, nulls, tupleIsAlive,				 callback_state);	}	heap_endscan(scan);	if (tupleTable)		ExecDropTupleTable(tupleTable, true);	FreeExecutorState(estate);	/* These may have been pointing to the now-gone estate */	indexInfo->ii_ExpressionsState = NIL;	indexInfo->ii_PredicateState = NIL;	return reltuples;}/* * IndexGetRelation: given an index's relation OID, get the OID of the * relation it is an index on.	Uses the system cache. */static OidIndexGetRelation(Oid indexId){	HeapTuple	tuple;	Form_pg_index index;	Oid			result;	tuple = SearchSysCache(INDEXRELID,						   ObjectIdGetDatum(indexId),						   0, 0, 0);	if (!HeapTupleIsValid(tuple))		elog(ERROR, "cache lookup failed for index %u", indexId);	index = (Form_pg_index) GETSTRUCT(tuple);	Assert(index->indexrelid == indexId);	result = index->indrelid;	ReleaseSysCache(tuple);	return result;}/* * reindex_index - This routine is used to recreate a single index */voidreindex_index(Oid indexId){	Relation	iRel,				heapRelation;	IndexInfo  *indexInfo;	Oid			heapId;	bool		inplace;	/*	 * Open our index relation and get an exclusive lock on it.	 *	 * Note: for REINDEX INDEX, doing this before opening the parent heap	 * relation means there's a possibility for deadlock failure against	 * another xact that is doing normal accesses to the heap and index.	 * However, it's not real clear why you'd be wanting to do REINDEX INDEX	 * on a table that's in active use, so I'd rather have the protection of	 * making sure the index is locked down.  In the REINDEX TABLE and	 * REINDEX DATABASE cases, there is no problem because caller already	 * holds exclusive lock on the parent table.	 */	iRel = index_open(indexId);	LockRelation(iRel, AccessExclusiveLock);	/* Get OID of index's parent table */	heapId = iRel->rd_index->indrelid;	/* Open and lock the parent heap relation */	heapRelation = heap_open(heapId, AccessExclusiveLock);	SetReindexProcessing(heapId, indexId);	/*	 * If it's a shared index, we must do inplace processing (because we	 * have no way to update relfilenode in other databases).  Otherwise	 * we can do it the normal transaction-safe way.	 *	 * Since inplace processing isn't crash-safe, we only allow it in a	 * standalone backend.  (In the REINDEX TABLE and REINDEX DATABASE cases,	 * the caller should have detected this.)	 */	inplace = iRel->rd_rel->relisshared;	if (inplace && IsUnderPostmaster)		ereport(ERROR,				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),				 errmsg("shared index \"%s\" can only be reindexed in stand-alone mode",						RelationGetRelationName(iRel))));	/* Fetch info needed for index_build */	indexInfo = BuildIndexInfo(iRel);	if (inplace)	{		/*		 * Release any buffers associated with this index.	If they're		 * dirty, they're just dropped without bothering to flush to disk.		 */		DropRelationBuffers(iRel);		/* Now truncate the actual data and set blocks to zero */		smgrtruncate(DEFAULT_SMGR, iRel, 0);		iRel->rd_nblocks = 0;		iRel->rd_targblock = InvalidBlockNumber;	}	else	{		/*		 * We'll build a new physical relation for the index.		 */		setNewRelfilenode(iRel);	}	/* Initialize the index and rebuild */	index_build(heapRelation, iRel, indexInfo);	/*	 * index_build will close both the heap and index relations (but not	 * give up the locks we hold on them).	So we're done.	 */	SetReindexProcessing(InvalidOid, InvalidOid);}/* * reindex_relation - This routine is used to recreate all indexes * of a relation (and its toast relation too, if any). * * Returns true if any indexes were rebuilt. */boolreindex_relation(Oid relid){	Relation	rel;	Oid			toast_relid;	bool		is_pg_class;	bool		result;	List	   *indexIds,			   *doneIndexes,			   *indexId;	/*	 * Ensure to hold an exclusive lock throughout the transaction. The	 * lock could perhaps be less intensive (in the non-overwrite case)	 * but for now it's AccessExclusiveLock for simplicity.	 */	rel = heap_open(relid, AccessExclusiveLock);	toast_relid = rel->rd_rel->reltoastrelid;	/*	 * Get the list of index OIDs for this relation.  (We trust to the	 * relcache to get this with a sequential scan if ignoring system	 * indexes.)	 */	indexIds = RelationGetIndexList(rel);	/*	 * reindex_index will attempt to update the pg_class rows for the	 * relation and index.  If we are processing pg_class itself, we	 * want to make sure that the updates do not try to insert index	 * entries into indexes we have not processed yet.  (When we are	 * trying to recover from corrupted indexes, that could easily	 * cause a crash.)  We can accomplish this because CatalogUpdateIndexes	 * will use the relcache's index list to know which indexes to update.	 * We just force the index list to be only the stuff we've processed.	 *	 * It is okay to not insert entries into the indexes we have not	 * processed yet because all of this is transaction-safe.  If we fail	 * partway through, the updated rows are dead and it doesn't matter	 * whether they have index entries.  Also, a new pg_class index will	 * be created with an entry for its own pg_class row because we do	 * setNewRelfilenode() before we do index_build().	 */	is_pg_class = (RelationGetRelid(rel) == RelOid_pg_class);	doneIndexes = NIL;	/* Reindex all the indexes. */	foreach(indexId, indexIds)	{		Oid		indexOid = lfirsto(indexId);		if (is_pg_class)			RelationSetIndexList(rel, doneIndexes);		reindex_index(indexOid);		CommandCounterIncrement();		if (is_pg_class)			doneIndexes = lappendo(doneIndexes, indexOid);	}	if (is_pg_class)		RelationSetIndexList(rel, indexIds);	/*	 * Close rel, but continue to hold the lock.	 */	heap_close(rel, NoLock);	result = (indexIds != NIL);	/*	 * If the relation has a secondary toast rel, reindex that too while we	 * still hold the lock on the master table.	 */	if (toast_relid != InvalidOid)		result |= reindex_relation(toast_relid);	return result;}

⌨️ 快捷键说明

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