static void gp_statistics_estimate_reltuples_relpages_ao_cs(Relation rel, float4 *reltuples, float4 *relpages) { AOCSFileSegInfo **aocsInfo = NULL; int nsegs = 0; double totalBytes = 0; AppendOnlyEntry *aoEntry; int64 hidden_tupcount; AppendOnlyVisimap visimap; /** * Ensure that the right kind of relation with the right type of storage is passed to us. */ Assert(rel->rd_rel->relkind == RELKIND_RELATION); Assert(RelationIsAoCols(rel)); *reltuples = 0.0; *relpages = 0.0; /* get table level statistics from the pg_aoseg table */ aoEntry = GetAppendOnlyEntry(RelationGetRelid(rel), SnapshotNow); aocsInfo = GetAllAOCSFileSegInfo(rel, aoEntry, SnapshotNow, &nsegs); if (aocsInfo) { int i = 0; int j = 0; for(i = 0; i < nsegs; i++) { for(j = 0; j < RelationGetNumberOfAttributes(rel); j++) { AOCSVPInfoEntry *e = getAOCSVPEntry(aocsInfo[i], j); Assert(e); totalBytes += e->eof_uncompressed; } /* Do not include tuples from an awaiting drop segment file */ if (aocsInfo[i]->state != AOSEG_STATE_AWAITING_DROP) { *reltuples += aocsInfo[i]->total_tupcount; } } /** * The planner doesn't understand AO's blocks, so need this method to try to fudge up a number for * the planner. */ *relpages = RelationGuessNumberOfBlocks(totalBytes); } AppendOnlyVisimap_Init(&visimap, aoEntry->visimaprelid, aoEntry->visimapidxid, AccessShareLock, SnapshotNow); hidden_tupcount = AppendOnlyVisimap_GetRelationHiddenTupleCount(&visimap); AppendOnlyVisimap_Finish(&visimap, AccessShareLock); (*reltuples) -= hidden_tupcount; pfree(aoEntry); return; }
/* * Performs a compaction of an append-only relation in column-orientation. * * In non-utility mode, all compaction segment files should be * marked as in-use/in-compaction in the appendonlywriter.c code. If * set, the insert_segno should also be marked as in-use. * When the insert segno is negative, only truncate to eof operations * can be executed. * * The caller is required to hold either an AccessExclusiveLock (vacuum full) * or a ShareLock on the relation. */ void AOCSCompact(Relation aorel, List *compaction_segno, int insert_segno, bool isFull) { const char *relname; int total_segfiles; AOCSFileSegInfo **segfile_array; AOCSInsertDesc insertDesc = NULL; int i, segno; LockAcquireResult acquireResult; AOCSFileSegInfo *fsinfo; Snapshot appendOnlyMetaDataSnapshot = RegisterSnapshot(GetCatalogSnapshot(InvalidOid)); Assert(RelationIsAoCols(aorel)); Assert(Gp_role == GP_ROLE_EXECUTE || Gp_role == GP_ROLE_UTILITY); Assert(insert_segno >= 0); relname = RelationGetRelationName(aorel); elogif(Debug_appendonly_print_compaction, LOG, "Compact AO relation %s", relname); /* Get information about all the file segments we need to scan */ segfile_array = GetAllAOCSFileSegInfo(aorel, appendOnlyMetaDataSnapshot, &total_segfiles); if (insert_segno >= 0) { insertDesc = aocs_insert_init(aorel, insert_segno, false); } for (i = 0; i < total_segfiles; i++) { segno = segfile_array[i]->segno; if (!list_member_int(compaction_segno, segno)) { continue; } if (segno == insert_segno) { /* We cannot compact the segment file we are inserting to. */ continue; } /* * Try to get the transaction write-lock for the Append-Only segment * file. * * NOTE: This is a transaction scope lock that must be held until * commit / abort. */ acquireResult = LockRelationAppendOnlySegmentFile( &aorel->rd_node, segfile_array[i]->segno, AccessExclusiveLock, /* dontWait */ true); if (acquireResult == LOCKACQUIRE_NOT_AVAIL) { elog(DEBUG5, "compaction skips AOCS segfile %d, " "relation %s", segfile_array[i]->segno, relname); continue; } /* Re-fetch under the write lock to get latest committed eof. */ fsinfo = GetAOCSFileSegInfo(aorel, appendOnlyMetaDataSnapshot, segno); /* * This should not occur since this segfile info was found by the * "all" method, but better to catch for trouble shooting (possibly * index corruption?) */ if (fsinfo == NULL) elog(ERROR, "file seginfo for AOCS relation %s %u/%u/%u (segno=%u) is missing", relname, aorel->rd_node.spcNode, aorel->rd_node.dbNode, aorel->rd_node.relNode, segno); if (AppendOnlyCompaction_ShouldCompact(aorel, fsinfo->segno, fsinfo->total_tupcount, isFull, appendOnlyMetaDataSnapshot)) { AOCSSegmentFileFullCompaction(aorel, insertDesc, fsinfo, appendOnlyMetaDataSnapshot); } pfree(fsinfo); } if (insertDesc != NULL) aocs_insert_finish(insertDesc); if (segfile_array) { FreeAllAOCSSegFileInfo(segfile_array, total_segfiles); pfree(segfile_array); } UnregisterSnapshot(appendOnlyMetaDataSnapshot); }
/* * Performs a compaction of an append-only AOCS relation. * * In non-utility mode, all compaction segment files should be * marked as in-use/in-compaction in the appendonlywriter.c code. * */ void AOCSDrop(Relation aorel, List *compaction_segno) { const char *relname; int total_segfiles; AOCSFileSegInfo **segfile_array; int i, segno; LockAcquireResult acquireResult; AOCSFileSegInfo *fsinfo; Snapshot appendOnlyMetaDataSnapshot = RegisterSnapshot(GetCatalogSnapshot(InvalidOid)); Assert(Gp_role == GP_ROLE_EXECUTE || Gp_role == GP_ROLE_UTILITY); Assert(RelationIsAoCols(aorel)); relname = RelationGetRelationName(aorel); elogif(Debug_appendonly_print_compaction, LOG, "Drop AOCS relation %s", relname); /* Get information about all the file segments we need to scan */ segfile_array = GetAllAOCSFileSegInfo(aorel, appendOnlyMetaDataSnapshot, &total_segfiles); for (i = 0; i < total_segfiles; i++) { segno = segfile_array[i]->segno; if (!list_member_int(compaction_segno, segno)) { continue; } /* * Try to get the transaction write-lock for the Append-Only segment * file. * * NOTE: This is a transaction scope lock that must be held until * commit / abort. */ acquireResult = LockRelationAppendOnlySegmentFile( &aorel->rd_node, segfile_array[i]->segno, AccessExclusiveLock, /* dontWait */ true); if (acquireResult == LOCKACQUIRE_NOT_AVAIL) { elog(DEBUG5, "drop skips AOCS segfile %d, " "relation %s", segfile_array[i]->segno, relname); continue; } /* Re-fetch under the write lock to get latest committed eof. */ fsinfo = GetAOCSFileSegInfo(aorel, appendOnlyMetaDataSnapshot, segno); if (fsinfo->state == AOSEG_STATE_AWAITING_DROP) { Assert(HasLockForSegmentFileDrop(aorel)); AOCSCompaction_DropSegmentFile(aorel, segno); ClearAOCSFileSegInfo(aorel, segno, AOSEG_STATE_DEFAULT); } pfree(fsinfo); } if (segfile_array) { FreeAllAOCSSegFileInfo(segfile_array, total_segfiles); pfree(segfile_array); } UnregisterSnapshot(appendOnlyMetaDataSnapshot); }
/* * Truncates each segment file to the AOCS relation to its EOF. * If we cannot get a lock on the segment file (because e.g. a concurrent insert) * the segment file is skipped. */ void AOCSTruncateToEOF(Relation aorel) { const char *relname; int total_segfiles; AOCSFileSegInfo **segfile_array; int i, segno; LockAcquireResult acquireResult; AOCSFileSegInfo *fsinfo; Snapshot appendOnlyMetaDataSnapshot = RegisterSnapshot(GetCatalogSnapshot(InvalidOid)); Assert(RelationIsAoCols(aorel)); relname = RelationGetRelationName(aorel); elogif(Debug_appendonly_print_compaction, LOG, "Compact AO relation %s", relname); /* Get information about all the file segments we need to scan */ segfile_array = GetAllAOCSFileSegInfo(aorel, appendOnlyMetaDataSnapshot, &total_segfiles); for (i = 0; i < total_segfiles; i++) { segno = segfile_array[i]->segno; /* * Try to get the transaction write-lock for the Append-Only segment * file. * * NOTE: This is a transaction scope lock that must be held until * commit / abort. */ acquireResult = LockRelationAppendOnlySegmentFile( &aorel->rd_node, segfile_array[i]->segno, AccessExclusiveLock, /* dontWait */ true); if (acquireResult == LOCKACQUIRE_NOT_AVAIL) { elog(DEBUG5, "truncate skips AO segfile %d, " "relation %s", segfile_array[i]->segno, relname); continue; } /* Re-fetch under the write lock to get latest committed eof. */ fsinfo = GetAOCSFileSegInfo(aorel, appendOnlyMetaDataSnapshot, segno); /* * This should not occur since this segfile info was found by the * "all" method, but better to catch for trouble shooting (possibly * index corruption?) */ if (fsinfo == NULL) elog(ERROR, "file seginfo for AOCS relation %s %u/%u/%u (segno=%u) is missing", relname, aorel->rd_node.spcNode, aorel->rd_node.dbNode, aorel->rd_node.relNode, segno); AOCSSegmentFileTruncateToEOF(aorel, fsinfo); pfree(fsinfo); } if (segfile_array) { FreeAllAOCSSegFileInfo(segfile_array, total_segfiles); pfree(segfile_array); } UnregisterSnapshot(appendOnlyMetaDataSnapshot); }
static Datum gp_aovisimap_hidden_info_internal(PG_FUNCTION_ARGS, Oid aoRelOid) { Datum values[3]; bool nulls[3]; HeapTuple tuple; Datum result; typedef struct Context { AppendOnlyVisimap visiMap; Relation parentRelation; FileSegInfo **appendonlySegfileInfo; AOCSFileSegInfo **aocsSegfileInfo; int segfile_info_total; int i; } Context; FuncCallContext *funcctx; Context *context; if (SRF_IS_FIRSTCALL()) { TupleDesc tupdesc; MemoryContext oldcontext; /* create a function context for cross-call persistence */ funcctx = SRF_FIRSTCALL_INIT(); /* * switch to memory context appropriate for multiple function * calls */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); /* build tupdesc for result tuples */ tupdesc = CreateTemplateTupleDesc(3, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "segno", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "hidden_tupcount", INT8OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "total_tupcount", INT8OID, -1, 0); funcctx->tuple_desc = BlessTupleDesc(tupdesc); /* * Collect all the locking information that we will format and send * out as a result set. */ context = (Context *) palloc0(sizeof(Context)); context->parentRelation = heap_open(aoRelOid, AccessShareLock); if (!(RelationIsAoRows(context->parentRelation) || RelationIsAoCols(context->parentRelation))) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("Function not supported on relation"))); } if (RelationIsAoRows(context->parentRelation)) { context->appendonlySegfileInfo = GetAllFileSegInfo( context->parentRelation, SnapshotNow, &context->segfile_info_total); } else { Assert(RelationIsAoCols(context->parentRelation)); context->aocsSegfileInfo = GetAllAOCSFileSegInfo(context->parentRelation, SnapshotNow, &context->segfile_info_total); } context->i = 0; AppendOnlyVisimap_Init(&context->visiMap, context->parentRelation->rd_appendonly->visimaprelid, context->parentRelation->rd_appendonly->visimapidxid, AccessShareLock, SnapshotNow); funcctx->user_fctx = (void *) context; MemoryContextSwitchTo(oldcontext); } funcctx = SRF_PERCALL_SETUP(); context = (Context *) funcctx->user_fctx; while (context->i < context->segfile_info_total) { int64 tupcount; int segno; if (context->appendonlySegfileInfo) { FileSegInfo *fsinfo = context->appendonlySegfileInfo[context->i]; tupcount = fsinfo->total_tupcount; segno = fsinfo->segno; } else if (context->aocsSegfileInfo) { AOCSFileSegInfo *fsinfo = context->aocsSegfileInfo[context->i]; tupcount = fsinfo->total_tupcount; segno = fsinfo->segno; } else { Insist(false); } MemSet(values, 0, sizeof(values)); MemSet(nulls, false, sizeof(nulls)); values[0] = Int32GetDatum(segno); values[1] = Int64GetDatum(AppendOnlyVisimap_GetSegmentFileHiddenTupleCount( &context->visiMap, segno)); values[2] = Int64GetDatum(tupcount); tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); context->i++; SRF_RETURN_NEXT(funcctx, result); } AppendOnlyVisimap_Finish(&context->visiMap, AccessShareLock); if (context->appendonlySegfileInfo) { FreeAllSegFileInfo(context->appendonlySegfileInfo, context->segfile_info_total); pfree(context->appendonlySegfileInfo); context->appendonlySegfileInfo = NULL; } if (context->aocsSegfileInfo) { FreeAllAOCSSegFileInfo(context->aocsSegfileInfo, context->segfile_info_total); pfree(context->aocsSegfileInfo); context->aocsSegfileInfo = NULL; } heap_close(context->parentRelation, AccessShareLock); pfree(context); funcctx->user_fctx = NULL; SRF_RETURN_DONE(funcctx); }