📄 gist.c
字号:
GISTENTRY entry, identry[INDEX_MAX_KEYS]; bool IsNull, decompvec[INDEX_MAX_KEYS], isnull[INDEX_MAX_KEYS]; int j; maxoff = PageGetMaxOffsetNumber(p); *which_grow = -1.0; which = -1; sum_grow = 1; gistDeCompressAtt(giststate, r, it, (Page) NULL, (OffsetNumber) 0, identry, decompvec, isnull); for (i = FirstOffsetNumber; i <= maxoff && sum_grow; i = OffsetNumberNext(i)) { IndexTuple itup = (IndexTuple) PageGetItem(p, PageGetItemId(p, i)); sum_grow = 0; for (j = 0; j < r->rd_att->natts; j++) { datum = index_getattr(itup, j + 1, giststate->tupdesc, &IsNull); gistdentryinit(giststate, j, &entry, datum, r, p, i, ATTSIZE(datum, giststate->tupdesc, j + 1, IsNull), FALSE, IsNull); gistpenalty(giststate, j, &entry, IsNull, &identry[j], isnull[j], &usize); if ((!isAttByVal(giststate, j)) && entry.key != datum) pfree(DatumGetPointer(entry.key)); if (which_grow[j] < 0 || usize < which_grow[j]) { which = i; which_grow[j] = usize; if (j < r->rd_att->natts - 1 && i == FirstOffsetNumber) which_grow[j + 1] = -1; sum_grow += which_grow[j]; } else if (which_grow[j] == usize) sum_grow += usize; else { sum_grow = 1; break; } } } gistFreeAtt(r, identry, decompvec); return which;}voidgistfreestack(GISTSTACK *s){ GISTSTACK *p; while (s != (GISTSTACK *) NULL) { p = s->gs_parent; pfree(s); s = p; }}/* * Retail deletion of a single tuple. * * NB: this is no longer called externally, but is still needed by * gistlayerinsert(). That dependency will have to be fixed if GIST * is ever going to allow concurrent insertions. */static voidgistdelete(Relation r, ItemPointer tid){ BlockNumber blkno; OffsetNumber offnum; Buffer buf; Page page; /* * Since GIST is not marked "amconcurrent" in pg_am, caller should * have acquired exclusive lock on index relation. We need no locking * here. */ blkno = ItemPointerGetBlockNumber(tid); offnum = ItemPointerGetOffsetNumber(tid); /* adjust any scans that will be affected by this deletion */ /* NB: this works only for scans in *this* backend! */ gistadjscans(r, GISTOP_DEL, blkno, offnum); /* delete the index tuple */ buf = ReadBuffer(r, blkno); page = BufferGetPage(buf); PageIndexTupleDelete(page, offnum); WriteBuffer(buf);}/* * Bulk deletion of all index entries pointing to a set of heap tuples. * The set of target tuples is specified via a callback routine that tells * whether any given heap tuple (identified by ItemPointer) is being deleted. * * Result: a palloc'd struct containing statistical info for VACUUM displays. */Datumgistbulkdelete(PG_FUNCTION_ARGS){ Relation rel = (Relation) PG_GETARG_POINTER(0); IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(1); void *callback_state = (void *) PG_GETARG_POINTER(2); IndexBulkDeleteResult *result; BlockNumber num_pages; double tuples_removed; double num_index_tuples; IndexScanDesc iscan; tuples_removed = 0; num_index_tuples = 0; /* * Since GIST is not marked "amconcurrent" in pg_am, caller should * have acquired exclusive lock on index relation. We need no locking * here. */ /* * XXX generic implementation --- should be improved! */ /* walk through the entire index */ iscan = index_beginscan(NULL, rel, SnapshotAny, 0, (ScanKey) NULL); /* including killed tuples */ iscan->ignore_killed_tuples = false; while (index_getnext_indexitem(iscan, ForwardScanDirection)) { if (callback(&iscan->xs_ctup.t_self, callback_state)) { ItemPointerData indextup = iscan->currentItemData; BlockNumber blkno; OffsetNumber offnum; Buffer buf; Page page; blkno = ItemPointerGetBlockNumber(&indextup); offnum = ItemPointerGetOffsetNumber(&indextup); /* adjust any scans that will be affected by this deletion */ gistadjscans(rel, GISTOP_DEL, blkno, offnum); /* delete the index tuple */ buf = ReadBuffer(rel, blkno); page = BufferGetPage(buf); PageIndexTupleDelete(page, offnum); WriteBuffer(buf); tuples_removed += 1; } else num_index_tuples += 1; } index_endscan(iscan); /* return statistics */ num_pages = RelationGetNumberOfBlocks(rel); result = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult)); result->num_pages = num_pages; result->num_index_tuples = num_index_tuples; result->tuples_removed = tuples_removed; PG_RETURN_POINTER(result);}voidinitGISTstate(GISTSTATE *giststate, Relation index){ int i; if (index->rd_att->natts > INDEX_MAX_KEYS) elog(ERROR, "numberOfAttributes %d > %d", index->rd_att->natts, INDEX_MAX_KEYS); giststate->tupdesc = index->rd_att; for (i = 0; i < index->rd_att->natts; i++) { fmgr_info_copy(&(giststate->consistentFn[i]), index_getprocinfo(index, i + 1, GIST_CONSISTENT_PROC), CurrentMemoryContext); fmgr_info_copy(&(giststate->unionFn[i]), index_getprocinfo(index, i + 1, GIST_UNION_PROC), CurrentMemoryContext); fmgr_info_copy(&(giststate->compressFn[i]), index_getprocinfo(index, i + 1, GIST_COMPRESS_PROC), CurrentMemoryContext); fmgr_info_copy(&(giststate->decompressFn[i]), index_getprocinfo(index, i + 1, GIST_DECOMPRESS_PROC), CurrentMemoryContext); fmgr_info_copy(&(giststate->penaltyFn[i]), index_getprocinfo(index, i + 1, GIST_PENALTY_PROC), CurrentMemoryContext); fmgr_info_copy(&(giststate->picksplitFn[i]), index_getprocinfo(index, i + 1, GIST_PICKSPLIT_PROC), CurrentMemoryContext); fmgr_info_copy(&(giststate->equalFn[i]), index_getprocinfo(index, i + 1, GIST_EQUAL_PROC), CurrentMemoryContext); }}voidfreeGISTstate(GISTSTATE *giststate){ /* no work */}#ifdef GIST_PAGEADDITEM/*** Given an IndexTuple to be inserted on a page, this routine replaces** the key with another key, which may involve generating a new IndexTuple** if the sizes don't match or if the null status changes.**** XXX this only works for a single-column index tuple!*/static IndexTuplegist_tuple_replacekey(Relation r, GISTENTRY entry, IndexTuple t){ bool IsNull; Datum datum = index_getattr(t, 1, r->rd_att, &IsNull); /* * If new entry fits in index tuple, copy it in. To avoid worrying * about null-value bitmask, pass it off to the general * index_formtuple routine if either the previous or new value is * NULL. */ if (!IsNull && DatumGetPointer(entry.key) != NULL && (Size) entry.bytes <= ATTSIZE(datum, r, 1, IsNull)) { memcpy(DatumGetPointer(datum), DatumGetPointer(entry.key), entry.bytes); /* clear out old size */ t->t_info &= ~INDEX_SIZE_MASK; /* or in new size */ t->t_info |= MAXALIGN(entry.bytes + sizeof(IndexTupleData)); return t; } else { /* generate a new index tuple for the compressed entry */ TupleDesc tupDesc = r->rd_att; IndexTuple newtup; char isnull; isnull = DatumGetPointer(entry.key) != NULL ? ' ' : 'n'; newtup = (IndexTuple) index_formtuple(tupDesc, &(entry.key), &isnull); newtup->t_tid = t->t_tid; return newtup; }}#endif/*** initialize a GiST entry with a decompressed version of key*/voidgistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e, Datum k, Relation r, Page pg, OffsetNumber o, int b, bool l, bool isNull){ if (b && !isNull) { GISTENTRY *dep; gistentryinit(*e, k, r, pg, o, b, l); dep = (GISTENTRY *) DatumGetPointer(FunctionCall1(&giststate->decompressFn[nkey], PointerGetDatum(e))); /* decompressFn may just return the given pointer */ if (dep != e) { gistentryinit(*e, dep->key, dep->rel, dep->page, dep->offset, dep->bytes, dep->leafkey); pfree(dep); } } else gistentryinit(*e, (Datum) 0, r, pg, o, 0, l);}/*** initialize a GiST entry with a compressed version of key*/static voidgistcentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e, Datum k, Relation r, Page pg, OffsetNumber o, int b, bool l, bool isNull){ if (!isNull) { GISTENTRY *cep; gistentryinit(*e, k, r, pg, o, b, l); cep = (GISTENTRY *) DatumGetPointer(FunctionCall1(&giststate->compressFn[nkey], PointerGetDatum(e))); /* compressFn may just return the given pointer */ if (cep != e) { gistentryinit(*e, cep->key, cep->rel, cep->page, cep->offset, cep->bytes, cep->leafkey); pfree(cep); } } else gistentryinit(*e, (Datum) 0, r, pg, o, 0, l);}static IndexTuplegistFormTuple(GISTSTATE *giststate, Relation r, Datum attdata[], int datumsize[], bool isnull[]){ IndexTuple tup; char isnullchar[INDEX_MAX_KEYS]; bool whatfree[INDEX_MAX_KEYS]; GISTENTRY centry[INDEX_MAX_KEYS]; Datum compatt[INDEX_MAX_KEYS]; int j; for (j = 0; j < r->rd_att->natts; j++) { if (isnull[j]) { isnullchar[j] = 'n'; compatt[j] = (Datum) 0; whatfree[j] = FALSE; } else { gistcentryinit(giststate, j, ¢ry[j], attdata[j], (Relation) NULL, (Page) NULL, (OffsetNumber) NULL, datumsize[j], FALSE, FALSE); isnullchar[j] = ' '; compatt[j] = centry[j].key; if (!isAttByVal(giststate, j)) { whatfree[j] = TRUE; if (centry[j].key != attdata[j]) pfree(DatumGetPointer(attdata[j])); } else whatfree[j] = FALSE; } } tup = (IndexTuple) index_formtuple(giststate->tupdesc, compatt, isnullchar); for (j = 0; j < r->rd_att->natts; j++) if (whatfree[j]) pfree(DatumGetPointer(compatt[j])); return tup;}static voidgistDeCompressAtt(GISTSTATE *giststate, Relation r, IndexTuple tuple, Page p, OffsetNumber o, GISTENTRY attdata[], bool decompvec[], bool isnull[]){ int i; Datum datum; for (i = 0; i < r->rd_att->natts; i++) { datum = index_getattr(tuple, i + 1, giststate->tupdesc, &isnull[i]); gistdentryinit(giststate, i, &attdata[i], datum, r, p, o, ATTSIZE(datum, giststate->tupdesc, i + 1, isnull[i]), FALSE, isnull[i]); if (isAttByVal(giststate, i)) decompvec[i] = FALSE; else { if (attdata[i].key == datum || isnull[i]) decompvec[i] = FALSE; else decompvec[i] = TRUE; } }}static voidgistFreeAtt(Relation r, GISTENTRY attdata[], bool decompvec[]){ int i; for (i = 0; i < r->rd_att->natts; i++) if (decompvec[i]) pfree(DatumGetPointer(attdata[i].key));}static voidgistpenalty(GISTSTATE *giststate, int attno, GISTENTRY *key1, bool isNull1, GISTENTRY *key2, bool isNull2, float *penalty){ if (giststate->penaltyFn[attno].fn_strict && (isNull1 || isNull2)) *penalty = 0.0; else FunctionCall3(&giststate->penaltyFn[attno], PointerGetDatum(key1), PointerGetDatum(key2), PointerGetDatum(penalty));}#ifdef GISTDEBUGstatic voidgist_dumptree(Relation r, int level, BlockNumber blk, OffsetNumber coff){ Buffer buffer; Page page; GISTPageOpaque opaque; IndexTuple which; ItemId iid; OffsetNumber i, maxoff; BlockNumber cblk; char *pred; pred = (char *) palloc(sizeof(char) * level + 1); MemSet(pred, '\t', level); pred[level] = '\0'; buffer = ReadBuffer(r, blk); page = (Page) BufferGetPage(buffer); opaque = (GISTPageOpaque) PageGetSpecialPointer(page); maxoff = PageGetMaxOffsetNumber(page); elog(DEBUG4, "%sPage: %d %s blk: %d maxoff: %d free: %d", pred, coff, (opaque->flags & F_LEAF) ? "LEAF" : "INTE", (int) blk, (int) maxoff, PageGetFreeSpace(page)); for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) { iid = PageGetItemId(page, i); which = (IndexTuple) PageGetItem(page, iid); cblk = ItemPointerGetBlockNumber(&(which->t_tid));#ifdef PRINTTUPLE elog(DEBUG4, "%s Tuple. blk: %d size: %d", pred, (int) cblk, IndexTupleSize(which));#endif if (!(opaque->flags & F_LEAF)) gist_dumptree(r, level + 1, cblk, i); } ReleaseBuffer(buffer); pfree(pred);}#endif /* defined GISTDEBUG */voidgist_redo(XLogRecPtr lsn, XLogRecord *record){ elog(PANIC, "gist_redo: unimplemented");}voidgist_undo(XLogRecPtr lsn, XLogRecord *record){ elog(PANIC, "gist_undo: unimplemented");}voidgist_desc(char *buf, uint8 xl_info, char *rec){}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -