索引访问方法

src/backend/access/index/indexam.c 索引访问方法集合

  • INTERFACE ROUTINES
 index_open   - open an index relation by relation OID
 index_close    - close an index relation
 index_beginscan - start a scan of an index with amgettuple
 index_beginscan_bitmap - start a scan of an index with amgetbitmap
 index_rescan - restart a scan of an index
 index_endscan  - end a scan
 index_insert - insert an index tuple into a relation
 index_markpos  - mark a scan position
 index_restrpos - restore a scan position
 index_parallelscan_estimate - estimate shared memory for parallel scan
 index_parallelscan_initialize - initialize parallel scan
 index_parallelrescan  - (re)start a parallel scan of an index
 index_beginscan_parallel - join parallel index scan
 index_getnext_tid  - get the next TID from a scan
 index_fetch_heap   - get the scan's next heap tuple
 index_getnext_slot - get the next tuple from a scan
 index_getbitmap - get all tuples from a scan
 index_bulk_delete  - bulk deletion of index tuples
 index_vacuum_cleanup - post-deletion cleanup of an index
 index_can_return - does index support index-only scans?
 index_getprocid - get a support procedure OID
 index_getprocinfo - get a support procedure's lookup info

index_open函数通过relation OID打开一个index relation,主要是通过调用relation.c中函数获取RelationData结构体,​​PostgreSQL数据库RelationAM——relation related routines​​。

Relation index_open(Oid relationId, LOCKMODE lockmode) {
Relation r;
r = relation_open(relationId, lockmode);
if (r->rd_rel->relkind != RELKIND_INDEX &&
r->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
ereport(ERROR,(errcode(ERRCODE_WRONG_OBJECT_TYPE),errmsg("\"%s\" is not an index",RelationGetRelationName(r))));
return r;
}
void index_close(Relation relation, LOCKMODE lockmode) {
LockRelId relid = relation->rd_lockInfo.lockRelId;
Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
/* The relcache does the real work... */
RelationClose(relation);
if (lockmode != NoLock) UnlockRelationId(&relid, lockmode);
}

index_insert函数想relation中插入一个Index元组

bool index_insert(Relation indexRelation, Datum *values, bool *isnull, ItemPointer heap_t_ctid, Relation heapRelation, IndexUniqueCheck checkUnique, IndexInfo *indexInfo) {
RELATION_CHECKS;
CHECK_REL_PROCEDURE(aminsert);
if (!(indexRelation->rd_indam->ampredlocks))
CheckForSerializableConflictIn(indexRelation, (HeapTuple) NULL, InvalidBuffer);
return indexRelation->rd_indam->aminsert(indexRelation, values, isnull, heap_t_ctid, heapRelation, checkUnique, indexInfo);
}

IndexAmRoutine

src/include/access/amapi.h

/* API struct for an index AM.  Note this must be stored in a single palloc'd chunk of memory. */
typedef struct IndexAmRoutine {
NodeTag type;
/* Total number of strategies (operators) by which we can traverse/search this AM. Zero if AM does not have a fixed set of strategy assignments. */
uint16 amstrategies;
/* total number of support functions that this AM uses */
uint16 amsupport;
/* does AM support ORDER BY indexed column's value? */
bool amcanorder;
/* does AM support ORDER BY result of an operator on indexed column? */
bool amcanorderbyop;
/* does AM support backward scanning? */
bool amcanbackward;
/* does AM support UNIQUE indexes? */
bool amcanunique;
/* does AM support multi-column indexes? */
bool amcanmulticol;
/* does AM require scans to have a constraint on the first index column? */
bool amoptionalkey;
/* does AM handle ScalarArrayOpExpr quals? */
bool amsearcharray;
/* does AM handle IS NULL/IS NOT NULL quals? */
bool amsearchnulls;
/* can index storage data type differ from column data type? */
bool amstorage;
/* can an index of this type be clustered on? */
bool amclusterable;
/* does AM handle predicate locks? */
bool ampredlocks;
/* does AM support parallel scan? */
bool amcanparallel;
/* does AM support columns included with clause INCLUDE? */
bool amcaninclude;
/* type of data stored in index, or InvalidOid if variable */
Oid amkeytype;
/* If you add new properties to either the above or the below lists, then they should also (usually) be exposed via the property API (see IndexAMProperty at the top of the file, and utils/adt/amutils.c). */
/* interface functions */
ambuild_function ambuild;
ambuildempty_function ambuildempty;
aminsert_function aminsert;
ambulkdelete_function ambulkdelete;
amvacuumcleanup_function amvacuumcleanup;
amcanreturn_function amcanreturn; /* can be NULL */
amcostestimate_function amcostestimate;
amoptions_function amoptions;
amproperty_function amproperty; /* can be NULL */
ambuildphasename_function ambuildphasename; /* can be NULL */
amvalidate_function amvalidate;
ambeginscan_function ambeginscan;
amrescan_function amrescan;
amgettuple_function amgettuple; /* can be NULL */
amgetbitmap_function amgetbitmap; /* can be NULL */
amendscan_function amendscan;
ammarkpos_function ammarkpos; /* can be NULL */
amrestrpos_function amrestrpos; /* can be NULL */
/* interface functions to support parallel index scans */
amestimateparallelscan_function amestimateparallelscan; /* can be NULL */
aminitparallelscan_function aminitparallelscan; /* can be NULL */
amparallelrescan_function amparallelrescan; /* can be NULL */
} IndexAmRoutine;

src/backend/access/index/amapi.c
GetIndexAmRoutine函数调用指定的access method handler routine获取IndexAmRoutine结构体。

IndexAmRoutine *GetIndexAmRoutine(Oid amhandler) {
Datum datum;
IndexAmRoutine *routine;
datum = OidFunctionCall0(amhandler);
routine = (IndexAmRoutine *) DatumGetPointer(datum);
if (routine == NULL || !IsA(routine, IndexAmRoutine))
elog(ERROR, "index access method handler function %u did not return an IndexAmRoutine struct", amhandler);
return routine;
}

GetIndexAmRoutineByAmId函数通过OID查找索引访问方法handler并获取其IndexAmRoutine结构体。

IndexAmRoutine *GetIndexAmRoutineByAmId(Oid amoid, bool noerror){
HeapTuple tuple;
Form_pg_am amform;
regproc amhandler;
/* Get handler function OID for the access method */
tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
if (!HeapTupleIsValid(tuple)){
if (noerror)
return NULL;
elog(ERROR, "cache lookup failed for access method %u",amoid);
}
amform = (Form_pg_am) GETSTRUCT(tuple);
/* Check if it's an index access method as opposed to some other AM */
if (amform->amtype != AMTYPE_INDEX){
if (noerror){
ReleaseSysCache(tuple);
return NULL;
}
ereport(ERROR,(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),errmsg("access method \"%s\" is not of type %s",NameStr(amform->amname), "INDEX")));
}

amhandler = amform->amhandler;
/* Complain if handler OID is invalid */
if (!RegProcedureIsValid(amhandler)){
if (noerror){
ReleaseSysCache(tuple);
return NULL;
}
ereport(ERROR,(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),errmsg("index access method \"%s\" does not have a handler",NameStr(amform->amname))));
}

ReleaseSysCache(tuple);

/* And finally, call the handler function to get the API struct. */
return GetIndexAmRoutine(amhandler);
}