diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2011-12-19 14:58:41 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2011-12-19 14:58:41 -0500 |
commit | 92203624934095163f8b57b5b3d7bbd2645da2c8 (patch) | |
tree | 8570ad85adefe211f46f295b86aaf05d461f3e8a /src/backend/access/spgist/spgutils.c | |
parent | 3695a555136a6d179cac8ae48d5f90171d5b30e9 (diff) | |
download | postgresql-92203624934095163f8b57b5b3d7bbd2645da2c8.tar.gz postgresql-92203624934095163f8b57b5b3d7bbd2645da2c8.zip |
Teach SP-GiST to do index-only scans.
Operator classes can specify whether or not they support this; this
preserves the flexibility to use lossy representations within an index.
In passing, move constant data about a given index into the rd_amcache
cache area, instead of doing fresh lookups each time we start an index
operation. This is mainly to try to make sure that spgcanreturn() has
insignificant cost; I still don't have any proof that it matters for
actual index accesses. Also, get rid of useless copying of FmgrInfo
pointers; we can perfectly well use the relcache's versions in-place.
Diffstat (limited to 'src/backend/access/spgist/spgutils.c')
-rw-r--r-- | src/backend/access/spgist/spgutils.c | 166 |
1 files changed, 82 insertions, 84 deletions
diff --git a/src/backend/access/spgist/spgutils.c b/src/backend/access/spgist/spgutils.c index c6bf07a9424..aced35c8441 100644 --- a/src/backend/access/spgist/spgutils.c +++ b/src/backend/access/spgist/spgutils.c @@ -34,51 +34,88 @@ fillTypeDesc(SpGistTypeDesc *desc, Oid type) get_typlenbyval(type, &desc->attlen, &desc->attbyval); } +/* + * Fetch local cache of AM-specific info about the index, initializing it + * if necessary + */ +SpGistCache * +spgGetCache(Relation index) +{ + SpGistCache *cache; + + if (index->rd_amcache == NULL) + { + Oid atttype; + spgConfigIn in; + FmgrInfo *procinfo; + Buffer metabuffer; + SpGistMetaPageData *metadata; + + cache = MemoryContextAllocZero(index->rd_indexcxt, + sizeof(SpGistCache)); + + /* SPGiST doesn't support multi-column indexes */ + Assert(index->rd_att->natts == 1); + + /* + * Get the actual data type of the indexed column from the index + * tupdesc. We pass this to the opclass config function so that + * polymorphic opclasses are possible. + */ + atttype = index->rd_att->attrs[0]->atttypid; + + /* Call the config function to get config info for the opclass */ + in.attType = atttype; + + procinfo = index_getprocinfo(index, 1, SPGIST_CONFIG_PROC); + FunctionCall2Coll(procinfo, + index->rd_indcollation[0], + PointerGetDatum(&in), + PointerGetDatum(&cache->config)); + + /* Get the information we need about each relevant datatype */ + fillTypeDesc(&cache->attType, atttype); + fillTypeDesc(&cache->attPrefixType, cache->config.prefixType); + fillTypeDesc(&cache->attLabelType, cache->config.labelType); + + /* Last, get the lastUsedPages data from the metapage */ + metabuffer = ReadBuffer(index, SPGIST_METAPAGE_BLKNO); + LockBuffer(metabuffer, BUFFER_LOCK_SHARE); + + metadata = SpGistPageGetMeta(BufferGetPage(metabuffer)); + + if (metadata->magicNumber != SPGIST_MAGIC_NUMBER) + elog(ERROR, "index \"%s\" is not an SP-GiST index", + RelationGetRelationName(index)); + + cache->lastUsedPages = metadata->lastUsedPages; + + UnlockReleaseBuffer(metabuffer); + + index->rd_amcache = (void *) cache; + } + else + { + /* assume it's up to date */ + cache = (SpGistCache *) index->rd_amcache; + } + + return cache; +} + /* Initialize SpGistState for working with the given index */ void initSpGistState(SpGistState *state, Relation index) { - Oid atttype; - spgConfigIn in; + SpGistCache *cache; - /* SPGiST doesn't support multi-column indexes */ - Assert(index->rd_att->natts == 1); + /* Get cached static information about index */ + cache = spgGetCache(index); - /* - * Get the actual data type of the indexed column from the index tupdesc. - * We pass this to the opclass config function so that polymorphic - * opclasses are possible. - */ - atttype = index->rd_att->attrs[0]->atttypid; - - /* Get the config info for the opclass */ - in.attType = atttype; - - memset(&state->config, 0, sizeof(state->config)); - - FunctionCall2Coll(index_getprocinfo(index, 1, SPGIST_CONFIG_PROC), - index->rd_indcollation[0], - PointerGetDatum(&in), - PointerGetDatum(&state->config)); - - /* Get the information we need about each relevant datatype */ - fillTypeDesc(&state->attType, atttype); - fillTypeDesc(&state->attPrefixType, state->config.prefixType); - fillTypeDesc(&state->attLabelType, state->config.labelType); - - /* Get lookup info for opclass support procs */ - fmgr_info_copy(&(state->chooseFn), - index_getprocinfo(index, 1, SPGIST_CHOOSE_PROC), - CurrentMemoryContext); - fmgr_info_copy(&(state->picksplitFn), - index_getprocinfo(index, 1, SPGIST_PICKSPLIT_PROC), - CurrentMemoryContext); - fmgr_info_copy(&(state->innerConsistentFn), - index_getprocinfo(index, 1, SPGIST_INNER_CONSISTENT_PROC), - CurrentMemoryContext); - fmgr_info_copy(&(state->leafConsistentFn), - index_getprocinfo(index, 1, SPGIST_LEAF_CONSISTENT_PROC), - CurrentMemoryContext); + state->config = cache->config; + state->attType = cache->attType; + state->attPrefixType = cache->attPrefixType; + state->attLabelType = cache->attLabelType; /* Make workspace for constructing dead tuples */ state->deadTupleStorage = palloc0(SGDTSIZE); @@ -86,6 +123,7 @@ initSpGistState(SpGistState *state, Relation index) /* Set XID to use in redirection tuples */ state->myXid = GetTopTransactionIdIfAny(); + /* Assume we're not in an index build (spgbuild will override) */ state->isBuild = false; } @@ -154,46 +192,6 @@ SpGistNewBuffer(Relation index) } /* - * Fetch local cache of lastUsedPages info, initializing it from the metapage - * if necessary - */ -static SpGistCache * -spgGetCache(Relation index) -{ - SpGistCache *cache; - - if (index->rd_amcache == NULL) - { - Buffer metabuffer; - SpGistMetaPageData *metadata; - - cache = MemoryContextAlloc(index->rd_indexcxt, - sizeof(SpGistCache)); - - metabuffer = ReadBuffer(index, SPGIST_METAPAGE_BLKNO); - LockBuffer(metabuffer, BUFFER_LOCK_SHARE); - - metadata = SpGistPageGetMeta(BufferGetPage(metabuffer)); - - if (metadata->magicNumber != SPGIST_MAGIC_NUMBER) - elog(ERROR, "index \"%s\" is not an SP-GiST index", - RelationGetRelationName(index)); - - *cache = metadata->lastUsedPages; - - UnlockReleaseBuffer(metabuffer); - - index->rd_amcache = cache; - } - else - { - cache = (SpGistCache *) index->rd_amcache; - } - - return cache; -} - -/* * Update index metapage's lastUsedPages info from local cache, if possible * * Updating meta page isn't critical for index working, so @@ -215,7 +213,7 @@ SpGistUpdateMetaPage(Relation index) if (ConditionalLockBuffer(metabuffer)) { metadata = SpGistPageGetMeta(BufferGetPage(metabuffer)); - metadata->lastUsedPages = *cache; + metadata->lastUsedPages = cache->lastUsedPages; MarkBufferDirty(metabuffer); UnlockReleaseBuffer(metabuffer); @@ -229,8 +227,8 @@ SpGistUpdateMetaPage(Relation index) /* Macro to select proper element of lastUsedPages cache depending on flags */ #define GET_LUP(c, f) (((f) & GBUF_LEAF) ? \ - &(c)->leafPage : \ - &(c)->innerPage[(f) & GBUF_PARITY_MASK]) + &(c)->lastUsedPages.leafPage : \ + &(c)->lastUsedPages.innerPage[(f) & GBUF_PARITY_MASK]) /* * Allocate and initialize a new buffer of the type and parity specified by @@ -282,8 +280,8 @@ allocNewBuffer(Relation index, int flags) else { /* Page has wrong parity, record it in cache and try again */ - cache->innerPage[blkParity].blkno = blkno; - cache->innerPage[blkParity].freeSpace = + cache->lastUsedPages.innerPage[blkParity].blkno = blkno; + cache->lastUsedPages.innerPage[blkParity].freeSpace = PageGetExactFreeSpace(BufferGetPage(buffer)); UnlockReleaseBuffer(buffer); } |