diff --git a/index_adviser/index_adviser.c b/index_adviser/index_adviser.c index 9b591ab..bda9ab2 100644 --- a/index_adviser/index_adviser.c +++ b/index_adviser/index_adviser.c @@ -134,17 +134,20 @@ static void save_advice( List* candidates ); static void log_candidates( const char* text, List* candidates ); /* function used for estimating the size of virtual indexes */ -static int4 estimate_index_pages(Oid rel_oid, Oid ind_oid ); +static int32 estimate_index_pages(Oid rel_oid, Oid ind_oid ); -static PlannedStmt* planner_callback( Query* query, - int cursorOptions, - ParamListInfo boundParams); +static PlannedStmt* planner_callback( Query *query, + const char *query_string, + int cursorOptions, + ParamListInfo boundParams); -static void ExplainOneQuery_callback( Query* query, - ExplainStmt* stmt, - const char* queryString, - ParamListInfo params, - TupOutputState* tstate); +static void ExplainOneQuery_callback( Query *query, + int cursorOptions, + IntoClause *into, + ExplainState *es, + const char *queryString, + ParamListInfo params, + QueryEnvironment *queryEnv); static void get_relation_info_callback( PlannerInfo* root, Oid relationObjectId, @@ -154,6 +157,7 @@ static void get_relation_info_callback( PlannerInfo* root, static const char* explain_get_index_name_callback( Oid indexId ); static PlannedStmt* index_adviser( Query* query, + const char* query_string, int cursorOptions, ParamListInfo boundParams, PlannedStmt* actual_plan, @@ -278,7 +282,7 @@ _PG_fini(void) } /* Make sure that Cost datatype can represent negative values */ -compile_assert( ((Cost)-1) < 0 ); +// compile_assert( ((Cost)-1) < 0 ); /* As of now the order-by and group-by clauses use the same C-struct. * A rudimentary check to confirm this: @@ -305,6 +309,7 @@ static int8 SuppressRecursion = 0; /* suppress recursive calls */ static PlannedStmt* index_adviser( Query* queryCopy, + const char* query_string, int cursorOptions, ParamListInfo boundParams, PlannedStmt *actual_plan, @@ -380,9 +385,9 @@ index_adviser( Query* queryCopy, * into an array. */ /* TODO: find out if the memory of opnosResult is ever freed. */ - for( opnosResult = OpernameGetCandidates( btreeop, '\0' ); + for( opnosResult = OpernameGetCandidates( btreeop, '\0', false ); opnosResult != NULL; - opnosResult = lnext(opnosResult) ) + opnosResult = opnosResult->next ) { opnos = lappend_oid( opnos, opnosResult->oid ); } @@ -452,7 +457,7 @@ index_adviser( Query* queryCopy, #endif /* update the global var */ index_candidates = candidates; - + /* * Setup the hook in the planner that injects information into base-tables * as they are prepared @@ -462,7 +467,7 @@ index_adviser( Query* queryCopy, /* do re-planning using virtual indexes */ /* TODO: is the plan ever freed? */ t_start( tRePlan ); - new_plan = standard_planner(queryCopy, cursorOptions, boundParams); + new_plan = standard_planner(queryCopy, query_string, cursorOptions, boundParams); t_stop( tRePlan ); /* reset the hook */ @@ -489,14 +494,13 @@ index_adviser( Query* queryCopy, totalCostSaved = actualTotalCost - newTotalCost; + if( startupCostSaved >0 || totalCostSaved > 0 ) { /* scan the plan for virtual indexes used */ t_start( tMarkUsedCands ); plannedStmtGlobal = new_plan; - mark_used_candidates( (Node*)new_plan->planTree, candidates ); - plannedStmtGlobal = NULL; t_stop( tMarkUsedCands ); } @@ -508,17 +512,18 @@ index_adviser( Query* queryCopy, { IndexCandidate *cand = (IndexCandidate*)lfirst( cell ); - next = lnext( cell ); + next = lnext( candidates, cell ); if( !cand->idxused ) { pfree( cand ); - candidates = list_delete_cell( candidates, cell, prev ); + candidates = list_delete_cell( candidates, cell ); } else prev = cell; } + /* update the global var */ index_candidates = candidates; @@ -531,7 +536,7 @@ index_adviser( Query* queryCopy, /* calculate the share of cost saved by each index */ if( saveCandidates ) { - int4 totalSize = 0; + int32 totalSize = 0; IndexCandidate *cand; foreach( cell, candidates ) @@ -546,6 +551,7 @@ index_adviser( Query* queryCopy, } } + /* Print the new plan if debugging. */ if( saveCandidates && Debug_print_plan ) elog_node_display( DEBUG1, "plan (using Index Adviser)", @@ -565,6 +571,8 @@ index_adviser( Query* queryCopy, /* TODO: try to free the new plan node */ new_plan = NULL; } + + #if CREATE_V_INDEXES /* * Undo the metadata changes; for eg. pg_depends entries will be removed @@ -574,6 +582,7 @@ index_adviser( Query* queryCopy, * transaction, after the ROLLBACK! All the memory allocated after BEGIN is * freed in ROLLBACK. */ + RollbackAndReleaseCurrentSubTransaction(); /* restore the resource-owner */ @@ -583,6 +592,7 @@ index_adviser( Query* queryCopy, elog( WARNING, "IND ADV: SPI_finish failed." ); #endif /* save the advise into the table */ + if( saveCandidates ) { t_start( tSaveAdvise ); @@ -613,20 +623,22 @@ index_adviser( Query* queryCopy, t_stop( tSaveAdvise ); } + /* free the candidate-list */ elog( DEBUG1, "IND ADV: Deleting candidate list." ); if( !saveCandidates || !doingExplain ) { - foreach( cell, index_candidates ) + /*foreach( cell, index_candidates ) pfree( (IndexCandidate*)lfirst( cell ) ); list_free( index_candidates ); - index_candidates = NIL; + index_candidates = NIL;*/ } t_stop( tAdviser ); + /* emit debug info */ elog( DEBUG1, "IND ADV: old cost %.2f..%.2f", actualStartupCost, actualTotalCost ); @@ -637,6 +649,7 @@ index_adviser( Query* queryCopy, (unsigned long)startupGainPerc, (unsigned long)totalGainPerc ); + /* print profiler information */ elog( DEBUG2, "IND ADV: [Prof] * Query String : %s", debug_query_string ); @@ -665,6 +678,7 @@ index_adviser( Query* queryCopy, elog( DEBUG3, "IND ADV: EXIT" ); + return doingExplain && saveCandidates ? new_plan : NULL; } @@ -677,9 +691,10 @@ index_adviser( Query* queryCopy, * hypothetical indexes. */ static PlannedStmt* -planner_callback( Query* query, - int cursorOptions, - ParamListInfo boundParams) +planner_callback( Query *query, + const char *query_string, + int cursorOptions, + ParamListInfo boundParams) { Query *queryCopy; PlannedStmt *actual_plan; @@ -697,14 +712,13 @@ planner_callback( Query* query, queryCopy = copyObject( query ); /* Generate a plan using the standard planner */ - actual_plan = standard_planner( query, cursorOptions, boundParams ); + actual_plan = standard_planner( query, query_string, cursorOptions, boundParams ); /* send the actual plan for comparison with a hypothetical plan */ - new_plan = index_adviser( queryCopy, cursorOptions, boundParams, + new_plan = index_adviser( queryCopy, query_string, cursorOptions, boundParams, actual_plan, false ); /* TODO: try to free the redundant new_plan */ - return actual_plan; } @@ -721,16 +735,27 @@ planner_callback( Query* query, * hook can send it to the log. */ static void -ExplainOneQuery_callback( Query *query, - ExplainStmt *stmt, - const char *queryString, - ParamListInfo params, - TupOutputState *tstate) +ExplainOneQuery_callback( Query *query, + int cursorOptions, + IntoClause *into, + ExplainState *es, + const char *queryString, + ParamListInfo params, + QueryEnvironment *queryEnv) { Query *queryCopy; PlannedStmt *actual_plan; PlannedStmt *new_plan; ListCell *cell; + instr_time planstart; + instr_time planduration; + BufferUsage bufusage_start, + bufusage; + + + /*if (es->buffers) + bufusage_start = pgBufferUsage;*/ + INSTR_TIME_SET_CURRENT(planstart); resetSecondaryHooks(); @@ -738,39 +763,54 @@ ExplainOneQuery_callback( Query *query, queryCopy = copyObject( query ); /* plan the query */ - actual_plan = standard_planner( query, 0, params ); + actual_plan = standard_planner( query, queryString, cursorOptions, params ); + + INSTR_TIME_SET_CURRENT(planduration); + INSTR_TIME_SUBTRACT(planduration, planstart); + + + /* calc differences of buffer counters. */ + if (es->buffers) + { + memset(&bufusage, 0, sizeof(BufferUsage)); + // BufferUsageAccumDiff(&bufusage, &pgBufferUsage, &bufusage_start); + } /* run it (if needed) and produce output */ - ExplainOnePlan( actual_plan, params, stmt, tstate ); + ExplainOnePlan(actual_plan, into, es, queryString, params, queryEnv, + &planduration, (es->buffers ? &bufusage : NULL)); /* re-plan the query */ - new_plan = index_adviser( queryCopy, 0, params, actual_plan, true ); + new_plan = index_adviser( queryCopy, queryString, cursorOptions, params, + actual_plan, true ); if ( new_plan ) { - bool analyze = stmt->analyze; + bool analyze = es->analyze; - stmt->analyze = false; + es->analyze = false; explain_get_index_name_hook = explain_get_index_name_callback; - do_text_output_oneline(tstate, ""); /* separator line */ - do_text_output_oneline(tstate, "** Plan with hypothetical indexes **"); - ExplainOnePlan( new_plan, params, stmt, tstate ); + // do_text_output_oneline(tstate, ""); /* separator line */ + // do_text_output_oneline(tstate, "** Plan with hypothetical indexes **"); + ExplainOnePlan(new_plan, into, es, queryString, params, queryEnv, + &planduration, (es->buffers ? &bufusage : NULL)); + explain_get_index_name_hook = NULL; - stmt->analyze = analyze; + es->analyze = analyze; } /* The candidates might not have been destroyed by the Index Adviser, do it * now. FIXME: this block belongs inside the 'if ( new_plan )' block above. */ - foreach( cell, index_candidates ) + /*foreach( cell, index_candidates ) pfree( (IndexCandidate*)lfirst( cell ) ); list_free( index_candidates ); - index_candidates = NIL; + index_candidates = NIL;*/ /* TODO: try to free the now-redundant new_plan */ } @@ -807,7 +847,6 @@ get_relation_info_callback( PlannerInfo *root, { /* estimate the size */ cand->pages = estimate_index_pages(cand->reloid, cand->idxoid); - info->pages = cand->pages; } } @@ -842,12 +881,12 @@ get_relation_info_callback( PlannerInfo *root, * the opfamily array needs an extra, terminating zero at the end. * We pre-zero the ordering info in case the index is unordered. */ - info->indexkeys = (int *) palloc(sizeof(int) * ncolumns); - info->opfamily = (Oid *) palloc0(sizeof(Oid) * (4 * ncolumns + 1)); + info->indexkeys = (int *) palloc_array(int, ncolumns); + info->opfamily = (Oid *) palloc0_array(Oid, (4 * ncolumns + 1)); info->opcintype = info->opfamily + (ncolumns + 1); info->fwdsortop = info->opcintype + ncolumns; info->revsortop = info->fwdsortop + ncolumns; - info->nulls_first = (bool *) palloc0(sizeof(bool) * ncolumns); + info->nulls_first = (bool *) palloc0_array(bool, ncolumns); for (i = 0; i < ncolumns; i++) { @@ -1027,16 +1066,16 @@ save_advice( List* candidates ) relation_close(advise_rel, AccessShareLock); #else /* - * heap_open() makes sure that the oid does not represent an INDEX or a + * relation_open() makes sure that the oid does not represent an INDEX or a * COMPOSITE type, else it will raise an ERROR, which is exactly what we - * want. The comments above heap_open() ask the caller not to assume any + * want. The comments above relation_open() ask the caller not to assume any * storage since the returned relation may be a VIEW; but we don't mind, * since the user may have defined some rules on it to make the INSERTs * work smoothly! If not, we leave it upto the executor to raise ERROR. */ PG_TRY(); { - heap_close(heap_open(advise_oid, AccessShareLock), AccessShareLock); + relation_close(relation_open(advise_oid, AccessShareLock), AccessShareLock); } PG_CATCH(); { @@ -1064,7 +1103,7 @@ save_advice( List* candidates ) if( !idxcd->idxused ) continue; - + /* pfree() the memory allocated for the previous candidate. FIXME: Avoid * meddling with the internals of a StringInfo, and try to use an API. */ @@ -1138,13 +1177,13 @@ remove_irrelevant_candidates( List* candidates ) ListCell *old_cell = cell; Oid base_rel_oid = ((IndexCandidate*)lfirst( cell ))->reloid; - Relation base_rel = heap_open( base_rel_oid, AccessShareLock ); + Relation base_rel = relation_open( base_rel_oid, AccessShareLock ); /* decide if the relation is unsupported. This check is now done before * creating a candidate in scan_generic_node(); but still keeping the * code here. */ - if((base_rel->rd_istemp == true) + if((base_rel->rd_islocaltemp == true) || IsSystemRelation(base_rel)) { ListCell *cell2; @@ -1159,12 +1198,12 @@ remove_irrelevant_candidates( List* candidates ) /* Remove all candidates with same unsupported relation */ for(cell2 = cell, prev2 = prev; cell2 != NULL; cell2 = next) { - next = lnext(cell2); + next = lnext(candidates, cell2); if(((IndexCandidate*)lfirst(cell2))->reloid == base_rel_oid) { pfree((IndexCandidate*)lfirst(cell2)); - candidates = list_delete_cell( candidates, cell2, prev2 ); + candidates = list_delete_cell( candidates, cell2 ); if(cell2 == cell) cell = next; @@ -1209,7 +1248,7 @@ remove_irrelevant_candidates( List* candidates ) for(cell2 = cell, prev2 = prev; cell2 != NULL; cell2 = next) - {next = lnext(cell2);{ /* FIXME: move this line to the block below; it doesn't need to be here. */ + {next = lnext(candidates, cell2);{ /* FIXME: move this line to the block below; it doesn't need to be here. */ IndexCandidate* cand = (IndexCandidate*)lfirst(cell2); @@ -1223,7 +1262,7 @@ remove_irrelevant_candidates( List* candidates ) { cmp = cand->varattno[i] - - old_index_info->ii_KeyAttrNumbers[i]; + - old_index_info->ii_IndexAttrNumbers[i]; ++i; /* FIXME: should this while condition be: cmp==0&&(irtekind == RTE_RELATION ) { - Relation base_rel = heap_open( rte->relid, AccessShareLock ); + Relation base_rel = relation_open( rte->relid, AccessShareLock ); /* We do not support catalog tables and temporary tables */ - if( base_rel->rd_istemp != true + if( base_rel->rd_islocaltemp != true && !IsSystemRelation(base_rel) /* and don't recommend indexes on hidden/system columns */ && expr->varattno > 0 @@ -1756,8 +1795,7 @@ scan_generic_node( const Node* const root, { /* create index-candidate and build a new list */ int i; - IndexCandidate *cand = (IndexCandidate*)palloc0( - sizeof(IndexCandidate)); + IndexCandidate *cand = (IndexCandidate*)palloc0_object(IndexCandidate); cand->varno = expr->varno; cand->varlevelsup = expr->varlevelsup; @@ -1777,7 +1815,7 @@ scan_generic_node( const Node* const root, candidates = list_make1( cand ); } - heap_close( base_rel, AccessShareLock ); + relation_close( base_rel, AccessShareLock ); } } break; @@ -1914,7 +1952,7 @@ log_candidates( const char* prefix, List* list ) for( i = 0; i < cand->ncols; ++i ) appendStringInfo( &str, "%s%d", (i>0?",":""), cand->varattno[ i ] ); - appendStringInfo( &str, ")%c", ((lnext( cell ) != NULL)?',':' ') ); + appendStringInfo( &str, ")%c", ((lnext( list, cell ) != NULL)?',':' ') ); } elog( DEBUG1, "IND ADV: %s: |%d| {%s}", prefix, list_length(list), @@ -1971,17 +2009,17 @@ merge_candidates( List* list1, List* list2 ) /* next candidate comes from list 1 */ ret = lappend( ret, lfirst( cell1 ) ); - cell1 = lnext( cell1 ); + cell1 = lnext( list1, cell1 ); /* if we have found two identical candidates then we remove the * candidate from list 2 */ if( cmp == 0 ) { - ListCell *next = lnext( cell2 ); + ListCell *next = lnext( list2, cell2 ); pfree( (IndexCandidate*)lfirst( cell2 ) ); - list2 = list_delete_cell( list2, cell2, prev2 ); + list2 = list_delete_cell( list2, cell2 ); cell2 = next; } @@ -1992,15 +2030,15 @@ merge_candidates( List* list1, List* list2 ) ret = lappend( ret, lfirst( cell2 ) ); prev2 = cell2; - cell2 = lnext( cell2 ); + cell2 = lnext( list2, cell2 ); } } /* Now append the leftovers from both the lists; only one of them should have any elements left */ - for( ; cell1; cell1 = lnext(cell1) ) + for( ; cell1; cell1 = lnext(list1, cell1) ) ret = lappend( ret, lfirst(cell1) ); - for( ; cell2; cell2 = lnext(cell2) ) + for( ; cell2; cell2 = lnext(list2, cell2) ) ret = lappend( ret, lfirst(cell2) ); list_free( list1 ); @@ -2060,7 +2098,7 @@ build_composite_candidates( List* list1, List* list2 ) relOid = cand2->reloid; do - cell1 = lnext( cell1 ); + cell1 = lnext( list1, cell1 ); while( cell1 != NULL && (relOid > cand1->reloid)); } else @@ -2069,7 +2107,7 @@ build_composite_candidates( List* list1, List* list2 ) relOid = cand1->reloid; do - cell2 = lnext( cell2 ); + cell2 = lnext( list2, cell2 ); while( cell2 != NULL && ( relOid > cand2->reloid )); } } @@ -2116,11 +2154,9 @@ build_composite_candidates( List* list1, List* list2 ) * candidates 2,1 */ IndexCandidate* cic1 - = (IndexCandidate*)palloc( - sizeof(IndexCandidate)); + = (IndexCandidate*)palloc_object(IndexCandidate); IndexCandidate* cic2 - = (IndexCandidate*)palloc( - sizeof(IndexCandidate)); + = (IndexCandidate*)palloc_object(IndexCandidate); /* init some members of composite candidate 1 */ cic1->varno = -1; @@ -2198,12 +2234,12 @@ build_composite_candidates( List* list1, List* list2 ) } } - l1b = lnext( l1b ); + l1b = lnext( list1, l1b ); } while( ( l1b != NULL ) && ( relationOid == ((IndexCandidate*)lfirst( l1b ))->reloid)); - cell2 = lnext( cell2 ); + cell2 = lnext( list2, cell2 ); } while( ( cell2 != NULL ) && ( relationOid == ((IndexCandidate*)lfirst( cell2 ))->reloid ) ); @@ -2226,92 +2262,125 @@ build_composite_candidates( List* list1, List* list2 ) * * It may delete some candidates from the list passed in to it. */ -static List* -create_virtual_indexes( List* candidates ) + +static List * +create_virtual_indexes(List *candidates) { - ListCell *cell; /* an entry from the candidate-list */ - ListCell *prev, *next; /* for list manipulation */ - char idx_name[ 16 ]; /* contains the name of the current index */ - int idx_count = 0; /* number of the current index */ - IndexInfo* indexInfo; - Oid op_class[INDEX_MAX_KEYS];/* needed for creating indexes */ - - elog( DEBUG3, "IND ADV: create_virtual_indexes: ENTER" ); - - /* fill index-info */ - indexInfo = makeNode( IndexInfo ); - - indexInfo->ii_Expressions = NIL; - indexInfo->ii_ExpressionsState = NIL; - indexInfo->ii_Predicate = NIL; - indexInfo->ii_PredicateState = NIL; - indexInfo->ii_Unique = false; - indexInfo->ii_Concurrent = true; - - /* create index for every list entry */ - /* TODO: simplify the check condition of the loop; it is basically - * advancing the 'next' pointer, so maybe this will work - * (next=lnext(), cell()); Also, advance the 'prev' pointer in the loop - */ - for( prev = NULL, cell = list_head(candidates); - (cell && (next = lnext(cell))) || cell != NULL; - cell = next) - { - int i; - - IndexCandidate* const cand = (IndexCandidate*)lfirst( cell ); + ListCell *cell; /* an entry from the candidate-list */ + ListCell *prev, *next; /* for list manipulation */ + char idx_name[16]; /* contains the name of the current index */ + int idx_count = 0; /* number of the current index */ + + elog(DEBUG3, "IND ADV: create_virtual_indexes: ENTER"); + + for (prev = NULL, cell = list_head(candidates); + (cell && (next = lnext(candidates, cell))) || cell != NULL; + cell = next) + { + int i; + IndexCandidate *cand = (IndexCandidate *) lfirst(cell); + Relation rel = relation_open(cand->reloid, AccessShareLock); + TupleDesc tupDesc = RelationGetDescr(rel); + List *indexColNames = NIL; + Oid collationObjectId[INDEX_MAX_KEYS]; + Oid classObjectId[INDEX_MAX_KEYS]; + int16 coloptions[INDEX_MAX_KEYS]; + + IndexInfo *indexInfo = makeNode(IndexInfo); + indexInfo->ii_Expressions = NIL; + indexInfo->ii_ExpressionsState = NIL; + indexInfo->ii_Predicate = NIL; + indexInfo->ii_PredicateState = NULL; + indexInfo->ii_ExclusionOps = NULL; + indexInfo->ii_ExclusionProcs = NULL; + indexInfo->ii_ExclusionStrats = NULL; + indexInfo->ii_Unique = false; + indexInfo->ii_NullsNotDistinct = false; + indexInfo->ii_ReadyForInserts = false; + indexInfo->ii_CheckedUnchanged = false; + indexInfo->ii_IndexUnchanged = false; + indexInfo->ii_Concurrent = true; + indexInfo->ii_BrokenHotChain = false; + indexInfo->ii_ParallelWorkers = 0; + indexInfo->ii_Am = BTREE_AM_OID; + indexInfo->ii_AmCache = NULL; + indexInfo->ii_Context = CurrentMemoryContext; indexInfo->ii_NumIndexAttrs = cand->ncols; + indexInfo->ii_NumIndexKeyAttrs = cand->ncols; + indexInfo->ii_OpclassOptions = NULL; - for( i = 0; i < cand->ncols; ++i ) + for (i = 0; i < cand->ncols; ++i) { - /* prepare op_class[] */ - op_class[i] = GetDefaultOpClass( cand->vartype[ i ], BTREE_AM_OID ); + Form_pg_attribute attr = TupleDescAttr(tupDesc, cand->varattno[i] - 1); + indexColNames = lappend(indexColNames, NameStr(attr->attname)); + indexInfo->ii_IndexAttrNumbers[i] = cand->varattno[i]; - if( op_class[i] == InvalidOid ) - /* don't create this index if couldn't find a default operator*/ - break; + Oid typeOid = attr->atttypid; + Oid opClassOid; - /* ... and set indexed attribute number */ - indexInfo->ii_KeyAttrNumbers[i] = cand->varattno[i]; - } + opClassOid = GetDefaultOpClass(typeOid, BTREE_AM_OID); + if (!OidIsValid(opClassOid)) + { + elog(ERROR, "Default operator class not found for column type OID %u", typeOid); + } - /* if we decided not to create the index above, try next candidate */ - if( i < cand->ncols ) - { - candidates = list_delete_cell( candidates, cell, prev ); - continue; + collationObjectId[i] = InvalidOid; + coloptions[i] = 0; + classObjectId[i] = opClassOid; } - /* generate indexname */ - /* FIXME: This index name can very easily collide with any other index - * being created simultaneously by other backend running index adviser. - */ - sprintf( idx_name, "idx_adv_%d", idx_count ); - - /* create the index without data */ - cand->idxoid = index_create( cand->reloid, idx_name, - InvalidOid, indexInfo, BTREE_AM_OID, - InvalidOid, op_class, NULL, (Datum)0, - false, false, false, true, false ); - elog( DEBUG1, "IND ADV: virtual index created: oid=%d name=%s size=%d", - cand->idxoid, idx_name, cand->pages ); - - /* increase count for the next index */ - ++idx_count; - prev = cell; - } - - pfree( indexInfo ); - - /* do CCI to make the new metadata changes "visible" */ - CommandCounterIncrement(); - - elog( DEBUG3, "IND ADV: create_virtual_indexes: EXIT" ); - - return candidates; + /* if we couldn't find default operators for all columns, skip this index */ + if (i < cand->ncols) + { + candidates = list_delete_cell(candidates, cell); + pfree(indexInfo); + continue; + } + + /* generate index name */ + sprintf(idx_name, "idx_adv_%d", idx_count); + + /* create the index without data */ + cand->idxoid = index_create(rel, /* heapRelation */ + idx_name, /* indexRelationName */ + InvalidOid, /* indexRelationId */ + InvalidOid, /* parentIndexRelid */ + InvalidOid, /* parentConstraintId */ + InvalidOid, /* relFileNode */ + indexInfo, /* indexInfo */ + indexColNames, /* indexColNames */ + BTREE_AM_OID, /* accessMethodObjectId */ + InvalidOid, /* tableSpaceId */ + collationObjectId, /* collationObjectId */ + classObjectId, /* classObjectId */ + coloptions, /* coloptions */ + (Datum) 0, /* reloptions */ + INDEX_CREATE_SKIP_BUILD, /* flags */ + 0, /* constr_flags */ + true, /* allow_system_table_mods */ + true, /* is_internal */ + NULL); /* constraintId */ + + elog(DEBUG1, "IND ADV: virtual index created: oid=%d name=%s size=%d", + cand->idxoid, idx_name, cand->pages); + + /* increase count for the next index */ + ++idx_count; + prev = cell; + + pfree(indexInfo); + } + + /* do CCI to make the new metadata changes "visible" */ + CommandCounterIncrement(); + + elog(DEBUG3, "IND ADV: create_virtual_indexes: EXIT"); + + return candidates; } + #endif #if CREATE_V_INDEXES @@ -2352,14 +2421,14 @@ drop_virtual_indexes( List* candidates ) } #endif -static int4 +static int32 estimate_index_pages(Oid rel_oid, Oid ind_oid ) { Size data_length; int i; int natts; - int2 var_att_count; - int4 rel_pages; /* diskpages of heap relation */ + int16 var_att_count; + int32 rel_pages; /* diskpages of heap relation */ float4 rel_tuples; /* tupes in the heap relation */ double idx_pages; /* diskpages in index relation */ @@ -2368,7 +2437,7 @@ estimate_index_pages(Oid rel_oid, Oid ind_oid ) Relation index_rel; Form_pg_attribute *atts; - base_rel = heap_open( rel_oid, AccessShareLock ); + base_rel = relation_open( rel_oid, AccessShareLock ); index_rel = index_open( ind_oid, AccessShareLock ); rel_pages = base_rel->rd_rel->relpages; @@ -2394,21 +2463,22 @@ estimate_index_pages(Oid rel_oid, Oid ind_oid ) data_length = 0; for( i = 0; i < natts; ++i) { + Form_pg_attribute attr = TupleDescAttr(ind_tup_desc, i); + /* the following is based on att_addlength() macro */ - if( atts[i]->attlen > 0 ) + if( attr->attlen > 0 ) { /* No need to do +=; RHS is incrementing data_length by including it in the sum */ - data_length = att_align_nominal(data_length, atts[i]->attalign); - - data_length += atts[i]->attlen; + data_length = att_align_nominal(data_length, attr->attalign); + data_length += attr->attlen; } - else if( atts[i]->attlen == -1 ) + else if( attr->attlen == -1 ) { - data_length += atts[i]->atttypmod + VARHDRSZ; + data_length += attr->atttypmod + VARHDRSZ; } else { /* null terminated data */ - Assert( atts[i]->attlen == -2 ); + Assert( attr->attlen == -2 ); ++var_att_count; } } @@ -2444,8 +2514,8 @@ estimate_index_pages(Oid rel_oid, Oid ind_oid ) idx_pages = ceil( idx_pages ); - heap_close( base_rel, AccessShareLock ); + relation_close( base_rel, AccessShareLock ); index_close( index_rel, AccessShareLock ); - return (int4)idx_pages; -} + return (int32)idx_pages; +} \ No newline at end of file diff --git a/index_adviser/index_adviser.h b/index_adviser/index_adviser.h index e45ce05..9c4935a 100644 --- a/index_adviser/index_adviser.h +++ b/index_adviser/index_adviser.h @@ -21,7 +21,7 @@ typedef struct { Index varno; /* index into the rangetable */ Index varlevelsup; /* points to the correct rangetable */ - int2 ncols; /* number of indexed columns */ + int16 ncols; /* number of indexed columns */ Oid vartype[INDEX_MAX_KEYS];/* type of the column(s) */ AttrNumber varattno[INDEX_MAX_KEYS];/* attribute number of the column(s) */ Oid reloid; /* the table oid */