Index: doc/src/sgml/catalogs.sgml =================================================================== RCS file: /home/hlinnaka/pgcvsrepository/pgsql/doc/src/sgml/catalogs.sgml,v retrieving revision 2.137 diff -c -r2.137 catalogs.sgml *** doc/src/sgml/catalogs.sgml 12 Nov 2006 06:25:37 -0000 2.137 --- doc/src/sgml/catalogs.sgml 27 Nov 2006 14:27:40 -0000 *************** *** 499,504 **** --- 499,511 ---- Function to parse and validate reloptions for an index + + amsuggestblock + regproc + pg_proc.oid + Get the best place in the heap to put a new tuple + + Index: doc/src/sgml/indexam.sgml =================================================================== RCS file: /home/hlinnaka/pgcvsrepository/pgsql/doc/src/sgml/indexam.sgml,v retrieving revision 2.18 diff -c -r2.18 indexam.sgml *** doc/src/sgml/indexam.sgml 16 Sep 2006 00:30:14 -0000 2.18 --- doc/src/sgml/indexam.sgml 27 Nov 2006 14:27:40 -0000 *************** *** 391,396 **** --- 391,414 ---- amoptions to test validity of options settings. + + + BlockNumber + amsuggestblock (Relation indexRelation, + Datum *values, + bool *isnull, + Relation heapRelation); + + Gets the optimal place in the heap for a new tuple. The parameters + correspond the parameters for aminsert. + This function is called on the clustered index before a new tuple + is inserted to the heap, and it should choose the optimal insertion + target page on the heap in such manner that the heap stays as close + as possible to the index order. + amsuggestblock can return InvalidBlockNumber if + the index am doesn't have a suggestion. + + Index: src/backend/access/heap/heapam.c =================================================================== RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/backend/access/heap/heapam.c,v retrieving revision 1.222 diff -c -r1.222 heapam.c *** src/backend/access/heap/heapam.c 17 Nov 2006 18:00:14 -0000 1.222 --- src/backend/access/heap/heapam.c 27 Nov 2006 14:27:40 -0000 *************** *** 1363,1368 **** --- 1363,1373 ---- * use_fsm is passed directly to RelationGetBufferForTuple, which see for * more info. * + * suggested_blk can be set by the caller to hint heap_insert which + * block would be the best place to put the new tuple in. heap_insert can + * ignore the suggestion, if there's not enough room on that block. + * InvalidBlockNumber means no preference. + * * The return value is the OID assigned to the tuple (either here or by the * caller), or InvalidOid if no OID. The header fields of *tup are updated * to match the stored tuple; in particular tup->t_self receives the actual *************** *** 1371,1377 **** */ Oid heap_insert(Relation relation, HeapTuple tup, CommandId cid, ! bool use_wal, bool use_fsm) { TransactionId xid = GetCurrentTransactionId(); HeapTuple heaptup; --- 1376,1382 ---- */ Oid heap_insert(Relation relation, HeapTuple tup, CommandId cid, ! bool use_wal, bool use_fsm, BlockNumber suggested_blk) { TransactionId xid = GetCurrentTransactionId(); HeapTuple heaptup; *************** *** 1424,1430 **** /* Find buffer to insert this tuple into */ buffer = RelationGetBufferForTuple(relation, heaptup->t_len, ! InvalidBuffer, use_fsm); /* NO EREPORT(ERROR) from here till changes are logged */ START_CRIT_SECTION(); --- 1429,1435 ---- /* Find buffer to insert this tuple into */ buffer = RelationGetBufferForTuple(relation, heaptup->t_len, ! InvalidBuffer, use_fsm, suggested_blk); /* NO EREPORT(ERROR) from here till changes are logged */ START_CRIT_SECTION(); *************** *** 1532,1538 **** Oid simple_heap_insert(Relation relation, HeapTuple tup) { ! return heap_insert(relation, tup, GetCurrentCommandId(), true, true); } /* --- 1537,1544 ---- Oid simple_heap_insert(Relation relation, HeapTuple tup) { ! return heap_insert(relation, tup, GetCurrentCommandId(), true, ! true, InvalidBlockNumber); } /* *************** *** 2117,2123 **** { /* Assume there's no chance to put heaptup on same page. */ newbuf = RelationGetBufferForTuple(relation, heaptup->t_len, ! buffer, true); } else { --- 2123,2130 ---- { /* Assume there's no chance to put heaptup on same page. */ newbuf = RelationGetBufferForTuple(relation, heaptup->t_len, ! buffer, true, ! InvalidBlockNumber); } else { *************** *** 2134,2140 **** */ LockBuffer(buffer, BUFFER_LOCK_UNLOCK); newbuf = RelationGetBufferForTuple(relation, heaptup->t_len, ! buffer, true); } else { --- 2141,2148 ---- */ LockBuffer(buffer, BUFFER_LOCK_UNLOCK); newbuf = RelationGetBufferForTuple(relation, heaptup->t_len, ! buffer, true, ! InvalidBlockNumber); } else { Index: src/backend/access/heap/hio.c =================================================================== RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/backend/access/heap/hio.c,v retrieving revision 1.63 diff -c -r1.63 hio.c *** src/backend/access/heap/hio.c 3 Jul 2006 22:45:37 -0000 1.63 --- src/backend/access/heap/hio.c 27 Nov 2006 14:27:40 -0000 *************** *** 93,98 **** --- 93,100 ---- * any committed data of other transactions. (See heap_insert's comments * for additional constraints needed for safe usage of this behavior.) * + * If the caller has a suggestion, it's passed in suggestedBlock. + * * We always try to avoid filling existing pages further than the fillfactor. * This is OK since this routine is not consulted when updating a tuple and * keeping it on the same page, which is the scenario fillfactor is meant *************** *** 103,109 **** */ Buffer RelationGetBufferForTuple(Relation relation, Size len, ! Buffer otherBuffer, bool use_fsm) { Buffer buffer = InvalidBuffer; Page pageHeader; --- 105,112 ---- */ Buffer RelationGetBufferForTuple(Relation relation, Size len, ! Buffer otherBuffer, bool use_fsm, ! BlockNumber suggestedBlock) { Buffer buffer = InvalidBuffer; Page pageHeader; *************** *** 135,142 **** otherBlock = InvalidBlockNumber; /* just to keep compiler quiet */ /* ! * We first try to put the tuple on the same page we last inserted a tuple ! * on, as cached in the relcache entry. If that doesn't work, we ask the * shared Free Space Map to locate a suitable page. Since the FSM's info * might be out of date, we have to be prepared to loop around and retry * multiple times. (To insure this isn't an infinite loop, we must update --- 138,147 ---- otherBlock = InvalidBlockNumber; /* just to keep compiler quiet */ /* ! * We first try to put the tuple on the page suggested by the caller, if ! * any. Then we try to put the tuple on the same page we last inserted a ! * tuple on, as cached in the relcache entry. If that doesn't work, we ! * ask the * shared Free Space Map to locate a suitable page. Since the FSM's info * might be out of date, we have to be prepared to loop around and retry * multiple times. (To insure this isn't an infinite loop, we must update *************** *** 144,152 **** * not to be suitable.) If the FSM has no record of a page with enough * free space, we give up and extend the relation. * ! * When use_fsm is false, we either put the tuple onto the existing target ! * page or extend the relation. */ if (len + saveFreeSpace <= MaxTupleSize) targetBlock = relation->rd_targblock; else --- 149,167 ---- * not to be suitable.) If the FSM has no record of a page with enough * free space, we give up and extend the relation. * ! * When use_fsm is false, we skip the fsm lookup if neither the suggested ! * nor the cached last insertion page has enough room, and extend the ! * relation. ! * ! * The fillfactor is taken into account when calculating the free space ! * on the cached target block, and when using the FSM. The suggested page ! * is used whenever there's enough room in it, regardless of the fillfactor, ! * because that's exactly the purpose the space is reserved for in the ! * first place. */ + if (suggestedBlock != InvalidBlockNumber) + targetBlock = suggestedBlock; + else if (len + saveFreeSpace <= MaxTupleSize) targetBlock = relation->rd_targblock; else *************** *** 219,224 **** --- 234,244 ---- */ pageHeader = (Page) BufferGetPage(buffer); pageFreeSpace = PageGetFreeSpace(pageHeader); + + /* If we're trying the suggested block, don't care about fillfactor */ + if (targetBlock == suggestedBlock && len <= pageFreeSpace) + return buffer; + if (len + saveFreeSpace <= pageFreeSpace) { /* use this page as future insert target, too */ *************** *** 241,246 **** --- 261,275 ---- ReleaseBuffer(buffer); } + /* If we just tried the suggested block, try the cached target + * block next, before consulting the FSM. */ + if(suggestedBlock == targetBlock) + { + targetBlock = relation->rd_targblock; + suggestedBlock = InvalidBlockNumber; + continue; + } + /* Without FSM, always fall out of the loop and extend */ if (!use_fsm) break; Index: src/backend/access/index/genam.c =================================================================== RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/backend/access/index/genam.c,v retrieving revision 1.59 diff -c -r1.59 genam.c *** src/backend/access/index/genam.c 4 Oct 2006 00:29:48 -0000 1.59 --- src/backend/access/index/genam.c 27 Nov 2006 14:27:40 -0000 *************** *** 259,261 **** --- 259,275 ---- pfree(sysscan); } + + /* + * This is a dummy implementation of amsuggestblock, to be used for index + * access methods that don't or can't support it. It just returns + * InvalidBlockNumber, which means "no preference". + * + * This is probably not a good best place for this function, but it doesn't + * fit naturally anywhere else either. + */ + Datum + dummysuggestblock(PG_FUNCTION_ARGS) + { + PG_RETURN_UINT32(InvalidBlockNumber); + } Index: src/backend/access/index/indexam.c =================================================================== RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/backend/access/index/indexam.c,v retrieving revision 1.95 diff -c -r1.95 indexam.c *** src/backend/access/index/indexam.c 4 Oct 2006 00:29:48 -0000 1.95 --- src/backend/access/index/indexam.c 27 Nov 2006 14:27:40 -0000 *************** *** 18,23 **** --- 18,24 ---- * index_rescan - restart a scan of an index * index_endscan - end a scan * index_insert - insert an index tuple into a relation + * index_suggestblock - get desired insert location for a heap tuple * index_markpos - mark a scan position * index_restrpos - restore a scan position * index_getnext - get the next tuple from a scan *************** *** 202,207 **** --- 203,237 ---- BoolGetDatum(check_uniqueness))); } + /* ---------------- + * index_suggestblock - get desired insert location for a heap tuple + * + * The returned BlockNumber is the *heap* page that is the best place + * to insert the given tuple to, according to the index am. The best + * place is usually one that maintains the cluster order. + * ---------------- + */ + BlockNumber + index_suggestblock(Relation indexRelation, + Datum *values, + bool *isnull, + Relation heapRelation) + { + FmgrInfo *procedure; + + RELATION_CHECKS; + GET_REL_PROCEDURE(amsuggestblock); + + /* + * have the am's suggestblock proc do all the work. + */ + return DatumGetUInt32(FunctionCall4(procedure, + PointerGetDatum(indexRelation), + PointerGetDatum(values), + PointerGetDatum(isnull), + PointerGetDatum(heapRelation))); + } + /* * index_beginscan - start a scan of an index with amgettuple * Index: src/backend/access/nbtree/nbtinsert.c =================================================================== RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/backend/access/nbtree/nbtinsert.c,v retrieving revision 1.146 diff -c -r1.146 nbtinsert.c *** src/backend/access/nbtree/nbtinsert.c 11 Nov 2006 01:14:18 -0000 1.146 --- src/backend/access/nbtree/nbtinsert.c 27 Nov 2006 14:27:40 -0000 *************** *** 146,151 **** --- 146,221 ---- } /* + * _bt_suggestblock() -- Find the heap block of the closest index tuple. + * + * The logic to find the target should match _bt_doinsert, otherwise + * we'll be making bad suggestions. + */ + BlockNumber + _bt_suggestblock(Relation rel, IndexTuple itup, Relation heapRel) + { + int natts = rel->rd_rel->relnatts; + OffsetNumber offset; + Page page; + BTPageOpaque opaque; + + ScanKey itup_scankey; + BTStack stack; + Buffer buf; + IndexTuple curitup; + BlockNumber suggestion = InvalidBlockNumber; + + /* we need an insertion scan key to do our search, so build one */ + itup_scankey = _bt_mkscankey(rel, itup); + + /* find the first page containing this key */ + stack = _bt_search(rel, natts, itup_scankey, false, &buf, BT_READ); + if(!BufferIsValid(buf)) + { + /* The index was completely empty. No suggestion then. */ + return InvalidBlockNumber; + } + /* we don't need the stack, so free it right away */ + _bt_freestack(stack); + + page = BufferGetPage(buf); + opaque = (BTPageOpaque) PageGetSpecialPointer(page); + + /* Find the location in the page where the new index tuple would go to. */ + + offset = _bt_binsrch(rel, buf, natts, itup_scankey, false); + if (offset > PageGetMaxOffsetNumber(page)) + { + /* _bt_binsrch returned pointer to end-of-page. It means that + * there was no equal items on the page, and the new item should + * be inserted as the last tuple of the page. There could be equal + * items on the next page, however. + * + * At the moment, we just ignore the potential equal items on the + * right, and pretend there isn't any. We could instead walk right + * to the next page to check that, but let's keep it simple for now. + */ + offset = OffsetNumberPrev(offset); + } + if(offset < P_FIRSTDATAKEY(opaque)) + { + /* We landed on an empty page. We could step left or right until + * we find some items, but let's keep it simple for now. + */ + } else { + /* We're now positioned at the index tuple that we're interested in. */ + + curitup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offset)); + suggestion = ItemPointerGetBlockNumber(&curitup->t_tid); + } + + _bt_relbuf(rel, buf); + _bt_freeskey(itup_scankey); + + return suggestion; + } + + /* * _bt_check_unique() -- Check for violation of unique index constraint * * Returns InvalidTransactionId if there is no conflict, else an xact ID Index: src/backend/access/nbtree/nbtree.c =================================================================== RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/backend/access/nbtree/nbtree.c,v retrieving revision 1.153 diff -c -r1.153 nbtree.c *** src/backend/access/nbtree/nbtree.c 1 Nov 2006 19:43:17 -0000 1.153 --- src/backend/access/nbtree/nbtree.c 27 Nov 2006 14:27:40 -0000 *************** *** 229,234 **** --- 229,266 ---- } /* + * btsuggestblock() -- find the best place in the heap to put a new tuple. + * + * This uses the same logic as btinsert to find the place where the index + * tuple would go if this was a btinsert call. + * + * There's room for improvement here. An insert operation will descend + * the tree twice, first by btsuggestblock, then by btinsert. Things + * might have changed in between, so that the heap tuple is actually + * not inserted in the optimal page, but since this is just an + * optimization, it's ok if it happens sometimes. + */ + Datum + btsuggestblock(PG_FUNCTION_ARGS) + { + Relation rel = (Relation) PG_GETARG_POINTER(0); + Datum *values = (Datum *) PG_GETARG_POINTER(1); + bool *isnull = (bool *) PG_GETARG_POINTER(2); + Relation heapRel = (Relation) PG_GETARG_POINTER(3); + IndexTuple itup; + BlockNumber suggestion; + + /* generate an index tuple */ + itup = index_form_tuple(RelationGetDescr(rel), values, isnull); + + suggestion =_bt_suggestblock(rel, itup, heapRel); + + pfree(itup); + + PG_RETURN_UINT32(suggestion); + } + + /* * btgettuple() -- Get the next tuple in the scan. */ Datum Index: src/backend/executor/execMain.c =================================================================== RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/backend/executor/execMain.c,v retrieving revision 1.280 diff -c -r1.280 execMain.c *** src/backend/executor/execMain.c 4 Oct 2006 00:29:52 -0000 1.280 --- src/backend/executor/execMain.c 27 Nov 2006 17:10:27 -0000 *************** *** 53,58 **** --- 53,59 ---- #include "utils/lsyscache.h" #include "utils/memutils.h" + bool cluster_inserts = true; /* GUC */ typedef struct evalPlanQual { *************** *** 846,851 **** --- 847,853 ---- resultRelInfo->ri_RangeTableIndex = resultRelationIndex; resultRelInfo->ri_RelationDesc = resultRelationDesc; resultRelInfo->ri_NumIndices = 0; + resultRelInfo->ri_ClusterIndex = -1; resultRelInfo->ri_IndexRelationDescs = NULL; resultRelInfo->ri_IndexRelationInfo = NULL; /* make a copy so as not to depend on relcache info not changing... */ *************** *** 1330,1335 **** --- 1332,1338 ---- ResultRelInfo *resultRelInfo; Relation resultRelationDesc; Oid newId; + BlockNumber suggestedBlock; /* * get the heap tuple out of the tuple table slot, making sure we have a *************** *** 1378,1383 **** --- 1381,1393 ---- if (resultRelationDesc->rd_att->constr) ExecConstraints(resultRelInfo, slot, estate); + /* Ask the index am of the clustered index for the + * best place to put it */ + if(cluster_inserts) + suggestedBlock = ExecSuggestBlock(slot, estate); + else + suggestedBlock = InvalidBlockNumber; + /* * insert the tuple * *************** *** 1386,1392 **** */ newId = heap_insert(resultRelationDesc, tuple, estate->es_snapshot->curcid, ! true, true); IncrAppended(); (estate->es_processed)++; --- 1396,1402 ---- */ newId = heap_insert(resultRelationDesc, tuple, estate->es_snapshot->curcid, ! true, true, suggestedBlock); IncrAppended(); (estate->es_processed)++; *************** *** 2549,2555 **** tuple, estate->es_snapshot->curcid, estate->es_into_relation_use_wal, ! false); /* never any point in using FSM */ /* We know this is a newly created relation, so there are no indexes */ --- 2559,2566 ---- tuple, estate->es_snapshot->curcid, estate->es_into_relation_use_wal, ! false, /* never any point in using FSM */ ! InvalidBlockNumber); /* We know this is a newly created relation, so there are no indexes */ Index: src/backend/executor/execUtils.c =================================================================== RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/backend/executor/execUtils.c,v retrieving revision 1.140 diff -c -r1.140 execUtils.c *** src/backend/executor/execUtils.c 4 Oct 2006 00:29:52 -0000 1.140 --- src/backend/executor/execUtils.c 27 Nov 2006 14:27:40 -0000 *************** *** 31,36 **** --- 31,37 ---- * ExecOpenIndices \ * ExecCloseIndices | referenced by InitPlan, EndPlan, * ExecInsertIndexTuples / ExecInsert, ExecUpdate + * ExecSuggestBlock Referenced by ExecInsert * * RegisterExprContextCallback Register function shutdown callback * UnregisterExprContextCallback Deregister function shutdown callback *************** *** 874,879 **** --- 875,881 ---- IndexInfo **indexInfoArray; resultRelInfo->ri_NumIndices = 0; + resultRelInfo->ri_ClusterIndex = -1; /* fast path if no indexes */ if (!RelationGetForm(resultRelation)->relhasindex) *************** *** 913,918 **** --- 915,925 ---- /* extract index key information from the index's pg_index info */ ii = BuildIndexInfo(indexDesc); + /* Remember which index is the clustered one. + * It's used to call the suggestblock-method on inserts */ + if(indexDesc->rd_index->indisclustered) + resultRelInfo->ri_ClusterIndex = i; + relationDescs[i] = indexDesc; indexInfoArray[i] = ii; i++; *************** *** 1062,1067 **** --- 1069,1137 ---- } } + /* ---------------------------------------------------------------- + * ExecSuggestBlock + * + * This routine asks the index am where a new heap tuple + * should be placed. + * ---------------------------------------------------------------- + */ + BlockNumber + ExecSuggestBlock(TupleTableSlot *slot, + EState *estate) + { + ResultRelInfo *resultRelInfo; + int i; + Relation relationDesc; + Relation heapRelation; + ExprContext *econtext; + Datum values[INDEX_MAX_KEYS]; + bool isnull[INDEX_MAX_KEYS]; + IndexInfo *indexInfo; + + /* + * Get information from the result relation info structure. + */ + resultRelInfo = estate->es_result_relation_info; + i = resultRelInfo->ri_ClusterIndex; + if(i == -1) + return InvalidBlockNumber; /* there was no clustered index */ + + heapRelation = resultRelInfo->ri_RelationDesc; + relationDesc = resultRelInfo->ri_IndexRelationDescs[i]; + indexInfo = resultRelInfo->ri_IndexRelationInfo[i]; + + /* You can't cluster on a partial index */ + Assert(indexInfo->ii_Predicate == NIL); + + /* + * We will use the EState's per-tuple context for evaluating + * index expressions (creating it if it's not already there). + */ + econtext = GetPerTupleExprContext(estate); + + /* Arrange for econtext's scan tuple to be the tuple under test */ + econtext->ecxt_scantuple = slot; + + /* + * FormIndexDatum fills in its values and isnull parameters with the + * appropriate values for the column(s) of the index. + */ + FormIndexDatum(indexInfo, + slot, + estate, + values, + isnull); + + /* + * The index AM does the rest. + */ + return index_suggestblock(relationDesc, /* index relation */ + values, /* array of index Datums */ + isnull, /* null flags */ + heapRelation); + } + /* * UpdateChangedParamSet * Add changed parameters to a plan node's chgParam set Index: src/backend/utils/misc/guc.c =================================================================== RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/backend/utils/misc/guc.c,v retrieving revision 1.358 diff -c -r1.358 guc.c *** src/backend/utils/misc/guc.c 5 Nov 2006 22:42:09 -0000 1.358 --- src/backend/utils/misc/guc.c 27 Nov 2006 17:08:50 -0000 *************** *** 92,97 **** --- 92,98 ---- #define MS_PER_D (1000 * 60 * 60 * 24) /* XXX these should appear in other modules' header files */ + extern bool cluster_inserts; extern bool Log_disconnections; extern int CommitDelay; extern int CommitSiblings; *************** *** 402,407 **** --- 403,416 ---- static struct config_bool ConfigureNamesBool[] = { { + {"cluster_inserts", PGC_USERSET, DEVELOPER_OPTIONS, + gettext_noop("Tries to maintain cluster order on inserts."), + NULL + }, + &cluster_inserts, + true, NULL, NULL + }, + { {"enable_seqscan", PGC_USERSET, QUERY_TUNING_METHOD, gettext_noop("Enables the planner's use of sequential-scan plans."), NULL Index: src/include/access/genam.h =================================================================== RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/include/access/genam.h,v retrieving revision 1.65 diff -c -r1.65 genam.h *** src/include/access/genam.h 31 Jul 2006 20:09:05 -0000 1.65 --- src/include/access/genam.h 27 Nov 2006 14:27:40 -0000 *************** *** 93,98 **** --- 93,101 ---- ItemPointer heap_t_ctid, Relation heapRelation, bool check_uniqueness); + extern BlockNumber index_suggestblock(Relation indexRelation, + Datum *values, bool *isnull, + Relation heapRelation); extern IndexScanDesc index_beginscan(Relation heapRelation, Relation indexRelation, *************** *** 123,128 **** --- 126,133 ---- extern FmgrInfo *index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum); + extern Datum dummysuggestblock(PG_FUNCTION_ARGS); + /* * index access method support routines (in genam.c) */ Index: src/include/access/heapam.h =================================================================== RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/include/access/heapam.h,v retrieving revision 1.117 diff -c -r1.117 heapam.h *** src/include/access/heapam.h 5 Nov 2006 22:42:10 -0000 1.117 --- src/include/access/heapam.h 27 Nov 2006 14:27:40 -0000 *************** *** 157,163 **** extern void setLastTid(const ItemPointer tid); extern Oid heap_insert(Relation relation, HeapTuple tup, CommandId cid, ! bool use_wal, bool use_fsm); extern HTSU_Result heap_delete(Relation relation, ItemPointer tid, ItemPointer ctid, TransactionId *update_xmax, CommandId cid, Snapshot crosscheck, bool wait); --- 157,163 ---- extern void setLastTid(const ItemPointer tid); extern Oid heap_insert(Relation relation, HeapTuple tup, CommandId cid, ! bool use_wal, bool use_fsm, BlockNumber suggestedblk); extern HTSU_Result heap_delete(Relation relation, ItemPointer tid, ItemPointer ctid, TransactionId *update_xmax, CommandId cid, Snapshot crosscheck, bool wait); Index: src/include/access/hio.h =================================================================== RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/include/access/hio.h,v retrieving revision 1.33 diff -c -r1.33 hio.h *** src/include/access/hio.h 4 Oct 2006 00:30:07 -0000 1.33 --- src/include/access/hio.h 27 Nov 2006 14:27:57 -0000 *************** *** 21,26 **** extern void RelationPutHeapTuple(Relation relation, Buffer buffer, HeapTuple tuple); extern Buffer RelationGetBufferForTuple(Relation relation, Size len, ! Buffer otherBuffer, bool use_fsm); #endif /* HIO_H */ --- 21,27 ---- extern void RelationPutHeapTuple(Relation relation, Buffer buffer, HeapTuple tuple); extern Buffer RelationGetBufferForTuple(Relation relation, Size len, ! Buffer otherBuffer, bool use_fsm, ! BlockNumber suggestedblk); #endif /* HIO_H */ Index: src/include/access/nbtree.h =================================================================== RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/include/access/nbtree.h,v retrieving revision 1.106 diff -c -r1.106 nbtree.h *** src/include/access/nbtree.h 1 Nov 2006 19:43:17 -0000 1.106 --- src/include/access/nbtree.h 27 Nov 2006 14:28:23 -0000 *************** *** 479,488 **** --- 479,491 ---- extern Datum btbulkdelete(PG_FUNCTION_ARGS); extern Datum btvacuumcleanup(PG_FUNCTION_ARGS); extern Datum btoptions(PG_FUNCTION_ARGS); + extern Datum btsuggestblock(PG_FUNCTION_ARGS); /* * prototypes for functions in nbtinsert.c */ + extern BlockNumber _bt_suggestblock(Relation rel, IndexTuple itup, + Relation heapRel); extern void _bt_doinsert(Relation rel, IndexTuple itup, bool index_is_unique, Relation heapRel); extern Buffer _bt_getstackbuf(Relation rel, BTStack stack, int access); Index: src/include/catalog/pg_am.h =================================================================== RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/include/catalog/pg_am.h,v retrieving revision 1.46 diff -c -r1.46 pg_am.h *** src/include/catalog/pg_am.h 31 Jul 2006 20:09:05 -0000 1.46 --- src/include/catalog/pg_am.h 27 Nov 2006 14:27:40 -0000 *************** *** 65,70 **** --- 65,71 ---- regproc amvacuumcleanup; /* post-VACUUM cleanup function */ regproc amcostestimate; /* estimate cost of an indexscan */ regproc amoptions; /* parse AM-specific parameters */ + regproc amsuggestblock; /* suggest a block where to put heap tuple */ } FormData_pg_am; /* ---------------- *************** *** 78,84 **** * compiler constants for pg_am * ---------------- */ ! #define Natts_pg_am 23 #define Anum_pg_am_amname 1 #define Anum_pg_am_amstrategies 2 #define Anum_pg_am_amsupport 3 --- 79,85 ---- * compiler constants for pg_am * ---------------- */ ! #define Natts_pg_am 24 #define Anum_pg_am_amname 1 #define Anum_pg_am_amstrategies 2 #define Anum_pg_am_amsupport 3 *************** *** 102,123 **** #define Anum_pg_am_amvacuumcleanup 21 #define Anum_pg_am_amcostestimate 22 #define Anum_pg_am_amoptions 23 /* ---------------- * initial contents of pg_am * ---------------- */ ! DATA(insert OID = 403 ( btree 5 1 1 t t t t f t btinsert btbeginscan btgettuple btgetmulti btrescan btendscan btmarkpos btrestrpos btbuild btbulkdelete btvacuumcleanup btcostestimate btoptions )); DESCR("b-tree index access method"); #define BTREE_AM_OID 403 ! DATA(insert OID = 405 ( hash 1 1 0 f f f f f f hashinsert hashbeginscan hashgettuple hashgetmulti hashrescan hashendscan hashmarkpos hashrestrpos hashbuild hashbulkdelete hashvacuumcleanup hashcostestimate hashoptions )); DESCR("hash index access method"); #define HASH_AM_OID 405 ! DATA(insert OID = 783 ( gist 100 7 0 f t t t t t gistinsert gistbeginscan gistgettuple gistgetmulti gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbulkdelete gistvacuumcleanup gistcostestimate gistoptions )); DESCR("GiST index access method"); #define GIST_AM_OID 783 ! DATA(insert OID = 2742 ( gin 100 4 0 f f f f t f gininsert ginbeginscan gingettuple gingetmulti ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbulkdelete ginvacuumcleanup gincostestimate ginoptions )); DESCR("GIN index access method"); #define GIN_AM_OID 2742 --- 103,125 ---- #define Anum_pg_am_amvacuumcleanup 21 #define Anum_pg_am_amcostestimate 22 #define Anum_pg_am_amoptions 23 + #define Anum_pg_am_amsuggestblock 24 /* ---------------- * initial contents of pg_am * ---------------- */ ! DATA(insert OID = 403 ( btree 5 1 1 t t t t f t btinsert btbeginscan btgettuple btgetmulti btrescan btendscan btmarkpos btrestrpos btbuild btbulkdelete btvacuumcleanup btcostestimate btoptions btsuggestblock)); DESCR("b-tree index access method"); #define BTREE_AM_OID 403 ! DATA(insert OID = 405 ( hash 1 1 0 f f f f f f hashinsert hashbeginscan hashgettuple hashgetmulti hashrescan hashendscan hashmarkpos hashrestrpos hashbuild hashbulkdelete hashvacuumcleanup hashcostestimate hashoptions dummysuggestblock)); DESCR("hash index access method"); #define HASH_AM_OID 405 ! DATA(insert OID = 783 ( gist 100 7 0 f t t t t t gistinsert gistbeginscan gistgettuple gistgetmulti gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbulkdelete gistvacuumcleanup gistcostestimate gistoptions dummysuggestblock)); DESCR("GiST index access method"); #define GIST_AM_OID 783 ! DATA(insert OID = 2742 ( gin 100 4 0 f f f f t f gininsert ginbeginscan gingettuple gingetmulti ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbulkdelete ginvacuumcleanup gincostestimate ginoptions dummysuggestblock )); DESCR("GIN index access method"); #define GIN_AM_OID 2742 Index: src/include/catalog/pg_proc.h =================================================================== RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/include/catalog/pg_proc.h,v retrieving revision 1.427 diff -c -r1.427 pg_proc.h *** src/include/catalog/pg_proc.h 4 Oct 2006 00:30:07 -0000 1.427 --- src/include/catalog/pg_proc.h 27 Nov 2006 14:27:40 -0000 *************** *** 682,687 **** --- 682,689 ---- DESCR("btree(internal)"); DATA(insert OID = 2785 ( btoptions PGNSP PGUID 12 f f t f s 2 17 "1009 16" _null_ _null_ _null_ btoptions - _null_ )); DESCR("btree(internal)"); + DATA(insert OID = 2858 ( btsuggestblock PGNSP PGUID 12 f f t f v 4 23 "2281 2281 2281 2281" _null_ _null_ _null_ btsuggestblock - _null_ )); + DESCR("btree(internal)"); DATA(insert OID = 339 ( poly_same PGNSP PGUID 12 f f t f i 2 16 "604 604" _null_ _null_ _null_ poly_same - _null_ )); DESCR("same as?"); *************** *** 3974,3979 **** --- 3976,3984 ---- DATA(insert OID = 2892 ( pg_advisory_unlock_all PGNSP PGUID 12 f f t f v 0 2278 "" _null_ _null_ _null_ pg_advisory_unlock_all - _null_ )); DESCR("release all advisory locks"); + DATA(insert OID = 2857 ( dummysuggestblock PGNSP PGUID 12 f f t f v 4 23 "2281 2281 2281 2281" _null_ _null_ _null_ dummysuggestblock - _null_ )); + DESCR("dummy amsuggestblock implementation (internal)"); + /* * Symbolic values for provolatile column: these indicate whether the result * of a function is dependent *only* on the values of its explicit arguments, Index: src/include/executor/executor.h =================================================================== RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/include/executor/executor.h,v retrieving revision 1.130 diff -c -r1.130 executor.h *** src/include/executor/executor.h 4 Oct 2006 00:30:08 -0000 1.130 --- src/include/executor/executor.h 27 Nov 2006 14:27:40 -0000 *************** *** 272,277 **** --- 272,278 ---- extern void ExecCloseIndices(ResultRelInfo *resultRelInfo); extern void ExecInsertIndexTuples(TupleTableSlot *slot, ItemPointer tupleid, EState *estate, bool is_vacuum); + extern BlockNumber ExecSuggestBlock(TupleTableSlot *slot, EState *estate); extern void RegisterExprContextCallback(ExprContext *econtext, ExprContextCallbackFunction function, Index: src/include/nodes/execnodes.h =================================================================== RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/include/nodes/execnodes.h,v retrieving revision 1.161 diff -c -r1.161 execnodes.h *** src/include/nodes/execnodes.h 28 Sep 2006 20:51:42 -0000 1.161 --- src/include/nodes/execnodes.h 27 Nov 2006 14:27:40 -0000 *************** *** 259,264 **** --- 259,266 ---- * NumIndices # of indices existing on result relation * IndexRelationDescs array of relation descriptors for indices * IndexRelationInfo array of key/attr info for indices + * ClusterIndex index to the IndexRelationInfo array of the + * clustered index, or -1 if there's none * TrigDesc triggers to be fired, if any * TrigFunctions cached lookup info for trigger functions * TrigInstrument optional runtime measurements for triggers *************** *** 275,280 **** --- 277,283 ---- int ri_NumIndices; RelationPtr ri_IndexRelationDescs; IndexInfo **ri_IndexRelationInfo; + int ri_ClusterIndex; TriggerDesc *ri_TrigDesc; FmgrInfo *ri_TrigFunctions; struct Instrumentation *ri_TrigInstrument; Index: src/include/utils/rel.h =================================================================== RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/include/utils/rel.h,v retrieving revision 1.92 diff -c -r1.92 rel.h *** src/include/utils/rel.h 4 Oct 2006 00:30:10 -0000 1.92 --- src/include/utils/rel.h 27 Nov 2006 14:27:40 -0000 *************** *** 116,121 **** --- 116,122 ---- FmgrInfo amvacuumcleanup; FmgrInfo amcostestimate; FmgrInfo amoptions; + FmgrInfo amsuggestblock; } RelationAmInfo;