天天看點

PostgreSQL資料庫index——Index Access Method

索引通路方法

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;      
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;
}      
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);
}