В письме от четверг, 4 июля 2019 г. 19:44:42 MSK пользователь Dent John написал: > Hi Nikolay, > > I have had a crack at re-basing the current patch against 12b2, but I didn’t > trivially succeed. > > It’s probably more my bodged fixing of the rejections than a fundamental > problem. But I now get compile fails in — and seems like only — vacuum.c.
I am really sorry for such big delay. Two new relation options were added, it needed careful checking while importing them back to the patch. I did not find proper timeslot for doing this quick enough. Hope I am not terribly late. Here goes an updated version.
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 5773021..5483378 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -22,7 +22,7 @@ #include "access/htup_details.h" #include "access/nbtree.h" #include "access/reloptions.h" -#include "access/spgist.h" +#include "access/spgist_private.h" #include "access/tuptoaster.h" #include "catalog/pg_type.h" #include "commands/defrem.h" @@ -46,9 +46,8 @@ * upper and lower bounds (if applicable); for strings, consider a validation * routine. * (ii) add a record below (or use add_<type>_reloption). - * (iii) add it to the appropriate options struct (perhaps StdRdOptions) - * (iv) add it to the appropriate handling routine (perhaps - * default_reloptions) + * (iii) add it to the appropriate options struct + * (iv) add it to the appropriate handling routine * (v) make sure the lock level is set correctly for that operation * (vi) don't forget to document the option * @@ -1030,7 +1029,7 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, case RELKIND_TOASTVALUE: case RELKIND_MATVIEW: case RELKIND_PARTITIONED_TABLE: - options = heap_reloptions(classForm->relkind, datum, false); + options = relation_reloptions(classForm->relkind, datum, false); break; case RELKIND_VIEW: options = view_reloptions(datum, false); @@ -1363,67 +1362,73 @@ fillRelOptions(void *rdopts, Size basesize, /* - * Option parser for anything that uses StdRdOptions. + * Option parsing definition for autovacuum. Used in toast and heap options. + */ + +#define AUTOVACUUM_RELOPTIONS(OFFSET) \ + {"autovacuum_enabled", RELOPT_TYPE_BOOL, \ + OFFSET + offsetof(AutoVacOpts, enabled)}, \ + {"autovacuum_vacuum_threshold", RELOPT_TYPE_INT, \ + OFFSET + offsetof(AutoVacOpts, vacuum_threshold)}, \ + {"autovacuum_analyze_threshold", RELOPT_TYPE_INT, \ + OFFSET + offsetof(AutoVacOpts, analyze_threshold)}, \ + {"autovacuum_vacuum_cost_delay", RELOPT_TYPE_REAL, \ + OFFSET + offsetof(AutoVacOpts, vacuum_cost_delay)}, \ + {"autovacuum_vacuum_cost_limit", RELOPT_TYPE_INT, \ + OFFSET + offsetof(AutoVacOpts, vacuum_cost_limit)}, \ + {"autovacuum_freeze_min_age", RELOPT_TYPE_INT, \ + OFFSET + offsetof(AutoVacOpts, freeze_min_age)}, \ + {"autovacuum_freeze_max_age", RELOPT_TYPE_INT, \ + OFFSET + offsetof(AutoVacOpts, freeze_max_age)}, \ + {"autovacuum_freeze_table_age", RELOPT_TYPE_INT, \ + OFFSET + offsetof(AutoVacOpts, freeze_table_age)}, \ + {"autovacuum_multixact_freeze_min_age", RELOPT_TYPE_INT, \ + OFFSET + offsetof(AutoVacOpts, multixact_freeze_min_age)}, \ + {"autovacuum_multixact_freeze_max_age", RELOPT_TYPE_INT, \ + OFFSET + offsetof(AutoVacOpts, multixact_freeze_max_age)}, \ + {"autovacuum_multixact_freeze_table_age", RELOPT_TYPE_INT, \ + OFFSET + offsetof(AutoVacOpts, multixact_freeze_table_age)}, \ + {"log_autovacuum_min_duration", RELOPT_TYPE_INT, \ + OFFSET + offsetof(AutoVacOpts, log_min_duration)}, \ + {"autovacuum_vacuum_scale_factor", RELOPT_TYPE_REAL, \ + OFFSET + offsetof(AutoVacOpts, vacuum_scale_factor)}, \ + {"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL, \ + OFFSET + offsetof(AutoVacOpts, analyze_scale_factor)} + +/* + * Option parser for heap */ bytea * -default_reloptions(Datum reloptions, bool validate, relopt_kind kind) +heap_reloptions(Datum reloptions, bool validate) { relopt_value *options; - StdRdOptions *rdopts; + HeapRelOptions *rdopts; int numoptions; static const relopt_parse_elt tab[] = { - {"fillfactor", RELOPT_TYPE_INT, offsetof(StdRdOptions, fillfactor)}, - {"autovacuum_enabled", RELOPT_TYPE_BOOL, - offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, enabled)}, - {"autovacuum_vacuum_threshold", RELOPT_TYPE_INT, - offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_threshold)}, - {"autovacuum_analyze_threshold", RELOPT_TYPE_INT, - offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_threshold)}, - {"autovacuum_vacuum_cost_limit", RELOPT_TYPE_INT, - offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_limit)}, - {"autovacuum_freeze_min_age", RELOPT_TYPE_INT, - offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_min_age)}, - {"autovacuum_freeze_max_age", RELOPT_TYPE_INT, - offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_max_age)}, - {"autovacuum_freeze_table_age", RELOPT_TYPE_INT, - offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_table_age)}, - {"autovacuum_multixact_freeze_min_age", RELOPT_TYPE_INT, - offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_min_age)}, - {"autovacuum_multixact_freeze_max_age", RELOPT_TYPE_INT, - offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_max_age)}, - {"autovacuum_multixact_freeze_table_age", RELOPT_TYPE_INT, - offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_table_age)}, - {"log_autovacuum_min_duration", RELOPT_TYPE_INT, - offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, log_min_duration)}, + {"fillfactor", RELOPT_TYPE_INT, offsetof(HeapRelOptions, fillfactor)}, + AUTOVACUUM_RELOPTIONS(offsetof(HeapRelOptions, autovacuum)), {"toast_tuple_target", RELOPT_TYPE_INT, - offsetof(StdRdOptions, toast_tuple_target)}, - {"autovacuum_vacuum_cost_delay", RELOPT_TYPE_REAL, - offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_delay)}, - {"autovacuum_vacuum_scale_factor", RELOPT_TYPE_REAL, - offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_scale_factor)}, - {"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL, - offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_scale_factor)}, + offsetof(HeapRelOptions, toast_tuple_target)}, {"user_catalog_table", RELOPT_TYPE_BOOL, - offsetof(StdRdOptions, user_catalog_table)}, + offsetof(HeapRelOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, - offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_cleanup_index_scale_factor", RELOPT_TYPE_REAL, - offsetof(StdRdOptions, vacuum_cleanup_index_scale_factor)}, + offsetof(HeapRelOptions, parallel_workers)}, {"vacuum_index_cleanup", RELOPT_TYPE_BOOL, - offsetof(StdRdOptions, vacuum_index_cleanup)}, + offsetof(HeapRelOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_BOOL, - offsetof(StdRdOptions, vacuum_truncate)} + offsetof(HeapRelOptions, vacuum_truncate)} }; - options = parseRelOptions(reloptions, validate, kind, &numoptions); + options = parseRelOptions(reloptions, validate, RELOPT_KIND_HEAP, + &numoptions); /* if none set, we're done */ if (numoptions == 0) return NULL; - rdopts = allocateReloptStruct(sizeof(StdRdOptions), options, numoptions); + rdopts = allocateReloptStruct(sizeof(HeapRelOptions), options, numoptions); - fillRelOptions((void *) rdopts, sizeof(StdRdOptions), options, numoptions, + fillRelOptions((void *) rdopts, sizeof(HeapRelOptions), options, numoptions, validate, tab, lengthof(tab)); pfree(options); @@ -1432,6 +1437,64 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) } /* + * Option parser for toast + */ +bytea * +toast_reloptions(Datum reloptions, bool validate) +{ + relopt_value *options; + ToastRelOptions *rdopts; + int numoptions; + static const relopt_parse_elt tab[] = { + AUTOVACUUM_RELOPTIONS(offsetof(ToastRelOptions, autovacuum)), + {"vacuum_index_cleanup", RELOPT_TYPE_BOOL, + offsetof(ToastRelOptions, vacuum_index_cleanup)}, + {"vacuum_truncate", RELOPT_TYPE_BOOL, + offsetof(ToastRelOptions, vacuum_truncate)} + }; + + options = parseRelOptions(reloptions, validate, RELOPT_KIND_TOAST, + &numoptions); + + /* if none set, we're done */ + if (numoptions == 0) + return NULL; + + rdopts = allocateReloptStruct(sizeof(ToastRelOptions), options, numoptions); + + fillRelOptions((void *) rdopts, sizeof(ToastRelOptions), options, + numoptions, validate, tab, lengthof(tab)); + + /* adjust default-only parameters for TOAST relations */ + rdopts->autovacuum.analyze_threshold = -1; + rdopts->autovacuum.analyze_scale_factor = -1; + + pfree(options); + + return (bytea *) rdopts; +} + +/* + * Option parser for partitioned relations + */ +bytea * +partitioned_reloptions(Datum reloptions, bool validate) +{ + int numoptions; + + /* + * Since there is no options for patitioned table for now, we just do + * validation to report incorrect option error and leave. + */ + + if (validate) + parseRelOptions(reloptions, validate, RELOPT_KIND_PARTITIONED, + &numoptions); + + return NULL; +} + +/* * Option parser for views */ bytea * @@ -1464,39 +1527,26 @@ view_reloptions(Datum reloptions, bool validate) } /* - * Parse options for heaps, views and toast tables. + * Parse options for heaps, toast, views and partitioned tables. */ bytea * -heap_reloptions(char relkind, Datum reloptions, bool validate) +relation_reloptions(char relkind, Datum reloptions, bool validate) { - StdRdOptions *rdopts; - switch (relkind) { case RELKIND_TOASTVALUE: - rdopts = (StdRdOptions *) - default_reloptions(reloptions, validate, RELOPT_KIND_TOAST); - if (rdopts != NULL) - { - /* adjust default-only parameters for TOAST relations */ - rdopts->fillfactor = 100; - rdopts->autovacuum.analyze_threshold = -1; - rdopts->autovacuum.analyze_scale_factor = -1; - } - return (bytea *) rdopts; + return toast_reloptions(reloptions, validate); case RELKIND_RELATION: case RELKIND_MATVIEW: - return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP); + return heap_reloptions(reloptions, validate); case RELKIND_PARTITIONED_TABLE: - return default_reloptions(reloptions, validate, - RELOPT_KIND_PARTITIONED); + return partitioned_reloptions(reloptions, validate); default: /* other relkinds are not supported */ return NULL; } } - /* * Parse options for indexes. * diff --git a/src/backend/access/hash/hashpage.c b/src/backend/access/hash/hashpage.c index 376ee2a..e8f933f 100644 --- a/src/backend/access/hash/hashpage.c +++ b/src/backend/access/hash/hashpage.c @@ -359,7 +359,7 @@ _hash_init(Relation rel, double num_tuples, ForkNumber forkNum) data_width = sizeof(uint32); item_width = MAXALIGN(sizeof(IndexTupleData)) + MAXALIGN(data_width) + sizeof(ItemIdData); /* include the line pointer */ - ffactor = RelationGetTargetPageUsage(rel, HASH_DEFAULT_FILLFACTOR) / item_width; + ffactor = (BLCKSZ * HashGetFillFactor(rel) / 100) / item_width; /* keep to a sane range */ if (ffactor < 10) ffactor = 10; diff --git a/src/backend/access/hash/hashutil.c b/src/backend/access/hash/hashutil.c index 3fb92ea..5170634 100644 --- a/src/backend/access/hash/hashutil.c +++ b/src/backend/access/hash/hashutil.c @@ -289,7 +289,28 @@ _hash_checkpage(Relation rel, Buffer buf, int flags) bytea * hashoptions(Datum reloptions, bool validate) { - return default_reloptions(reloptions, validate, RELOPT_KIND_HASH); + relopt_value *options; + HashRelOptions *rdopts; + int numoptions; + static const relopt_parse_elt tab[] = { + {"fillfactor", RELOPT_TYPE_INT, offsetof(HashRelOptions, fillfactor)}, + }; + + options = parseRelOptions(reloptions, validate, RELOPT_KIND_HASH, + &numoptions); + + /* if none set, we're done */ + if (numoptions == 0) + return NULL; + + rdopts = allocateReloptStruct(sizeof(HashRelOptions), options, numoptions); + + fillRelOptions((void *) rdopts, sizeof(HashRelOptions), options, numoptions, + validate, tab, lengthof(tab)); + + pfree(options); + + return (bytea *) rdopts; } /* diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index d768b9b..819176a 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -2125,8 +2125,10 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples, AssertArg(!(options & HEAP_INSERT_NO_LOGICAL)); needwal = !(options & HEAP_INSERT_SKIP_WAL) && RelationNeedsWAL(relation); - saveFreeSpace = RelationGetTargetPageFreeSpace(relation, - HEAP_DEFAULT_FILLFACTOR); + if (IsToastRelation(relation)) + saveFreeSpace = ToastGetTargetPageFreeSpace(); + else + saveFreeSpace = HeapGetTargetPageFreeSpace(relation); /* Toast and set header data in all the slots */ heaptuples = palloc(ntuples * sizeof(HeapTuple)); diff --git a/src/backend/access/heap/hio.c b/src/backend/access/heap/hio.c index d41d318..dad8c0d 100644 --- a/src/backend/access/heap/hio.c +++ b/src/backend/access/heap/hio.c @@ -19,6 +19,7 @@ #include "access/hio.h" #include "access/htup_details.h" #include "access/visibilitymap.h" +#include "catalog/catalog.h" #include "storage/bufmgr.h" #include "storage/freespace.h" #include "storage/lmgr.h" @@ -346,8 +347,10 @@ RelationGetBufferForTuple(Relation relation, Size len, len, MaxHeapTupleSize))); /* Compute desired extra freespace due to fillfactor option */ - saveFreeSpace = RelationGetTargetPageFreeSpace(relation, - HEAP_DEFAULT_FILLFACTOR); + if (IsToastRelation(relation)) + saveFreeSpace = ToastGetTargetPageFreeSpace(); + else + saveFreeSpace = HeapGetTargetPageFreeSpace(relation); if (otherBuffer != InvalidBuffer) otherBlock = BufferGetBlockNumber(otherBuffer); diff --git a/src/backend/access/heap/pruneheap.c b/src/backend/access/heap/pruneheap.c index 0efe3ce..92240e3 100644 --- a/src/backend/access/heap/pruneheap.c +++ b/src/backend/access/heap/pruneheap.c @@ -129,8 +129,11 @@ heap_page_prune_opt(Relation relation, Buffer buffer) * important than sometimes getting a wrong answer in what is after all * just a heuristic estimate. */ - minfree = RelationGetTargetPageFreeSpace(relation, - HEAP_DEFAULT_FILLFACTOR); + + if (IsToastRelation(relation)) + minfree = ToastGetTargetPageFreeSpace(); + else + minfree = HeapGetTargetPageFreeSpace(relation); minfree = Max(minfree, BLCKSZ / 10); if (PageIsFull(page) || PageGetHeapFreeSpace(page) < minfree) diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c index 72a448a..418d6b4 100644 --- a/src/backend/access/heap/rewriteheap.c +++ b/src/backend/access/heap/rewriteheap.c @@ -682,8 +682,10 @@ raw_heap_insert(RewriteState state, HeapTuple tup) len, MaxHeapTupleSize))); /* Compute desired extra freespace due to fillfactor option */ - saveFreeSpace = RelationGetTargetPageFreeSpace(state->rs_new_rel, - HEAP_DEFAULT_FILLFACTOR); + if (IsToastRelation(state->rs_new_rel)) + saveFreeSpace = ToastGetTargetPageFreeSpace(); + else + saveFreeSpace = HeapGetTargetPageFreeSpace(state->rs_new_rel); /* Now we can check to see if there's enough free space already. */ if (state->rs_buffer_valid) diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c index 4cfd528..b460d13 100644 --- a/src/backend/access/nbtree/nbtree.c +++ b/src/backend/access/nbtree/nbtree.c @@ -816,7 +816,7 @@ _bt_vacuum_needs_cleanup(IndexVacuumInfo *info) } else { - StdRdOptions *relopts; + BTRelOptions *relopts; float8 cleanup_scale_factor; float8 prev_num_heap_tuples; @@ -827,7 +827,7 @@ _bt_vacuum_needs_cleanup(IndexVacuumInfo *info) * tuples exceeds vacuum_cleanup_index_scale_factor fraction of * original tuples count. */ - relopts = (StdRdOptions *) info->index->rd_options; + relopts = (BTRelOptions *) info->index->rd_options; cleanup_scale_factor = (relopts && relopts->vacuum_cleanup_index_scale_factor >= 0) ? relopts->vacuum_cleanup_index_scale_factor diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c index d0b9013..6ba27ab 100644 --- a/src/backend/access/nbtree/nbtsort.c +++ b/src/backend/access/nbtree/nbtsort.c @@ -725,8 +725,9 @@ _bt_pagestate(BTWriteState *wstate, uint32 level) if (level > 0) state->btps_full = (BLCKSZ * (100 - BTREE_NONLEAF_FILLFACTOR) / 100); else - state->btps_full = RelationGetTargetPageFreeSpace(wstate->index, - BTREE_DEFAULT_FILLFACTOR); + state->btps_full = (BLCKSZ * (100 - BTGetFillFactor(wstate->index)) + / 100); + /* no parent level, yet */ state->btps_next = NULL; diff --git a/src/backend/access/nbtree/nbtsplitloc.c b/src/backend/access/nbtree/nbtsplitloc.c index f43ec67..4ba82ab 100644 --- a/src/backend/access/nbtree/nbtsplitloc.c +++ b/src/backend/access/nbtree/nbtsplitloc.c @@ -167,7 +167,7 @@ _bt_findsplitloc(Relation rel, /* Count up total space in data items before actually scanning 'em */ olddataitemstotal = rightspace - (int) PageGetExactFreeSpace(page); - leaffillfactor = RelationGetFillFactor(rel, BTREE_DEFAULT_FILLFACTOR); + leaffillfactor = BTGetFillFactor(rel); /* Passed-in newitemsz is MAXALIGNED but does not include line pointer */ newitemsz += sizeof(ItemIdData); diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c index 93fab26..75b151a 100644 --- a/src/backend/access/nbtree/nbtutils.c +++ b/src/backend/access/nbtree/nbtutils.c @@ -2027,7 +2027,31 @@ BTreeShmemInit(void) bytea * btoptions(Datum reloptions, bool validate) { - return default_reloptions(reloptions, validate, RELOPT_KIND_BTREE); + relopt_value *options; + BTRelOptions *rdopts; + int numoptions; + static const relopt_parse_elt tab[] = { + {"fillfactor", RELOPT_TYPE_INT, offsetof(BTRelOptions, fillfactor)}, + {"vacuum_cleanup_index_scale_factor", RELOPT_TYPE_REAL, + offsetof(BTRelOptions, vacuum_cleanup_index_scale_factor)} + + }; + + options = parseRelOptions(reloptions, validate, RELOPT_KIND_BTREE, + &numoptions); + + /* if none set, we're done */ + if (numoptions == 0) + return NULL; + + rdopts = allocateReloptStruct(sizeof(BTRelOptions), options, numoptions); + + fillRelOptions((void *) rdopts, sizeof(BTRelOptions), options, numoptions, + validate, tab, lengthof(tab)); + + pfree(options); + + return (bytea *) rdopts; } /* diff --git a/src/backend/access/spgist/spgutils.c b/src/backend/access/spgist/spgutils.c index 45472db..99dee1d 100644 --- a/src/backend/access/spgist/spgutils.c +++ b/src/backend/access/spgist/spgutils.c @@ -408,8 +408,7 @@ SpGistGetBuffer(Relation index, int flags, int needSpace, bool *isNew) * related to the ones already on it. But fillfactor mustn't cause an * error for requests that would otherwise be legal. */ - needSpace += RelationGetTargetPageFreeSpace(index, - SPGIST_DEFAULT_FILLFACTOR); + needSpace += (BLCKSZ * (100 - SpGistGetFillFactor(index)) / 100); needSpace = Min(needSpace, SPGIST_PAGE_CAPACITY); /* Get the cache entry for this flags setting */ @@ -586,7 +585,29 @@ SpGistInitMetapage(Page page) bytea * spgoptions(Datum reloptions, bool validate) { - return default_reloptions(reloptions, validate, RELOPT_KIND_SPGIST); + relopt_value *options; + SpGistRelOptions *rdopts; + int numoptions; + static const relopt_parse_elt tab[] = { + {"fillfactor", RELOPT_TYPE_INT, offsetof(SpGistRelOptions, fillfactor)}, + }; + + options = parseRelOptions(reloptions, validate, RELOPT_KIND_SPGIST, + &numoptions); + + /* if none set, we're done */ + if (numoptions == 0) + return NULL; + + rdopts = allocateReloptStruct(sizeof(SpGistRelOptions), options, + numoptions); + + fillRelOptions((void *) rdopts, sizeof(SpGistRelOptions), options, + numoptions, validate, tab, lengthof(tab)); + + pfree(options); + + return (bytea *) rdopts; } /* diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c index 4c1d909..3e4f16e 100644 --- a/src/backend/commands/createas.c +++ b/src/backend/commands/createas.c @@ -131,7 +131,7 @@ create_ctas_internal(List *attrList, IntoClause *into) validnsps, true, false); - (void) heap_reloptions(RELKIND_TOASTVALUE, toast_options, true); + (void) relation_reloptions(RELKIND_TOASTVALUE, toast_options, true); NewRelationCreateToastTable(intoRelationAddr.objectId, toast_options); diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 0f1a9f0..219ea50 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -722,7 +722,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, if (relkind == RELKIND_VIEW) (void) view_reloptions(reloptions, true); else - (void) heap_reloptions(relkind, reloptions, true); + (void) relation_reloptions(relkind, reloptions, true); if (stmt->ofTypename) { @@ -12105,7 +12105,7 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation, case RELKIND_TOASTVALUE: case RELKIND_MATVIEW: case RELKIND_PARTITIONED_TABLE: - (void) heap_reloptions(rel->rd_rel->relkind, newOptions, true); + (void) relation_reloptions(rel->rd_rel->relkind, newOptions, true); break; case RELKIND_VIEW: (void) view_reloptions(newOptions, true); @@ -12214,7 +12214,7 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation, defList, "toast", validnsps, false, operation == AT_ResetRelOptions); - (void) heap_reloptions(RELKIND_TOASTVALUE, newOptions, true); + (void) relation_reloptions(RELKIND_TOASTVALUE, newOptions, true); memset(repl_val, 0, sizeof(repl_val)); memset(repl_null, false, sizeof(repl_null)); diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index e7b379d..c0e4ff4 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -31,6 +31,7 @@ #include "access/tableam.h" #include "access/transam.h" #include "access/xact.h" +#include "catalog/catalog.h" #include "catalog/namespace.h" #include "catalog/pg_database.h" #include "catalog/pg_inherits.h" @@ -1758,7 +1759,10 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params) if (params->index_cleanup == VACOPT_TERNARY_DEFAULT) { if (onerel->rd_options == NULL || - ((StdRdOptions *) onerel->rd_options)->vacuum_index_cleanup) + (!IsToastRelation(onerel) && + ((HeapRelOptions *) onerel->rd_options)->vacuum_index_cleanup) || + (IsToastRelation(onerel) && + ((ToastRelOptions *) onerel->rd_options)->vacuum_index_cleanup)) params->index_cleanup = VACOPT_TERNARY_ENABLED; else params->index_cleanup = VACOPT_TERNARY_DISABLED; @@ -1768,7 +1772,10 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params) if (params->truncate == VACOPT_TERNARY_DEFAULT) { if (onerel->rd_options == NULL || - ((StdRdOptions *) onerel->rd_options)->vacuum_truncate) + (!IsToastRelation(onerel) && + ((HeapRelOptions *) onerel->rd_options)->vacuum_truncate) || + (IsToastRelation(onerel) && + ((ToastRelOptions *) onerel->rd_options)->vacuum_truncate)) params->truncate = VACOPT_TERNARY_ENABLED; else params->truncate = VACOPT_TERNARY_DISABLED; diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index 40f4976..efa8fc3 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -148,8 +148,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent, estimate_rel_size(relation, rel->attr_widths - rel->min_attr, &rel->pages, &rel->tuples, &rel->allvisfrac); - /* Retrieve the parallel_workers reloption, or -1 if not set. */ - rel->rel_parallel_workers = RelationGetParallelWorkers(relation, -1); + /* + * Retrieve the parallel_workers for heap and mat.view relations. + * Use -1 if not set, or if we are dealing with other relation kinds + */ + if (relation->rd_rel->relkind == RELKIND_RELATION || + relation->rd_rel->relkind == RELKIND_MATVIEW) + rel->rel_parallel_workers = RelationGetParallelWorkers(relation, -1); + else + rel->rel_parallel_workers = -1; /* * Make list of indexes. Ignore indexes on system catalogs if told to. diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index 073f313..d111d4d 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -2719,6 +2719,7 @@ extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc) { bytea *relopts; AutoVacOpts *av; + AutoVacOpts *src; Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION || ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW || @@ -2728,8 +2729,13 @@ extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc) if (relopts == NULL) return NULL; + if (((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE) + src = &(((ToastRelOptions *) relopts)->autovacuum); + else + src = &(((HeapRelOptions *) relopts)->autovacuum); + av = palloc(sizeof(AutoVacOpts)); - memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts)); + memcpy(av, src, sizeof(AutoVacOpts)); pfree(relopts); return av; diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 05ec7f3..67ed763 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -1035,7 +1035,7 @@ ProcessUtilitySlow(ParseState *pstate, validnsps, true, false); - (void) heap_reloptions(RELKIND_TOASTVALUE, + (void) relation_reloptions(RELKIND_TOASTVALUE, toast_options, true); diff --git a/src/include/access/hash.h b/src/include/access/hash.h index 107c3d0..561ac3d 100644 --- a/src/include/access/hash.h +++ b/src/include/access/hash.h @@ -264,6 +264,17 @@ typedef struct HashMetaPageData typedef HashMetaPageData *HashMetaPage; +typedef struct HashRelOptions +{ + int32 varlena_header_; /* varlena header (do not touch directly!) */ + int fillfactor; /* page fill factor in percent (0..100) */ +} HashRelOptions; + +#define HashGetFillFactor(relation) \ + ((relation)->rd_options ? \ + ((HashRelOptions *) (relation)->rd_options)->fillfactor : \ + HASH_DEFAULT_FILLFACTOR) + /* * Maximum size of a hash index item (it's okay to have only one per page) */ diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h index a3583f2..fcf7349 100644 --- a/src/include/access/nbtree.h +++ b/src/include/access/nbtree.h @@ -681,6 +681,19 @@ typedef BTScanOpaqueData *BTScanOpaque; #define SK_BT_DESC (INDOPTION_DESC << SK_BT_INDOPTION_SHIFT) #define SK_BT_NULLS_FIRST (INDOPTION_NULLS_FIRST << SK_BT_INDOPTION_SHIFT) +typedef struct BTRelOptions +{ + int32 varlena_header_; /* varlena header (do not touch directly!) */ + int fillfactor; /* page fill factor in percent (0..100) */ + /* fraction of newly inserted tuples prior to trigger index cleanup */ + float8 vacuum_cleanup_index_scale_factor; +} BTRelOptions; + +#define BTGetFillFactor(relation) \ + ((relation)->rd_options ? \ + ((BTRelOptions *) (relation)->rd_options)->fillfactor : \ + BTREE_DEFAULT_FILLFACTOR) + /* * Constant definition for progress reporting. Phase numbers must match * btbuildphasename. diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a1912f4..bb85b31 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -270,9 +270,11 @@ extern void fillRelOptions(void *rdopts, Size basesize, bool validate, const relopt_parse_elt *elems, int nelems); -extern bytea *default_reloptions(Datum reloptions, bool validate, - relopt_kind kind); -extern bytea *heap_reloptions(char relkind, Datum reloptions, bool validate); +extern bytea *toast_reloptions(Datum reloptions, bool validate); +extern bytea *partitioned_reloptions(Datum reloptions, bool validate); +extern bytea *heap_reloptions(Datum reloptions, bool validate); +extern bytea *relation_reloptions(char relkind, Datum reloptions, + bool validate); extern bytea *view_reloptions(Datum reloptions, bool validate); extern bytea *index_reloptions(amoptions_function amoptions, Datum reloptions, bool validate); diff --git a/src/include/access/spgist.h b/src/include/access/spgist.h index 02c8794..6eedaf9 100644 --- a/src/include/access/spgist.h +++ b/src/include/access/spgist.h @@ -20,10 +20,6 @@ #include "lib/stringinfo.h" -/* reloption parameters */ -#define SPGIST_MIN_FILLFACTOR 10 -#define SPGIST_DEFAULT_FILLFACTOR 80 - /* SPGiST opclass support function numbers */ #define SPGIST_CONFIG_PROC 1 #define SPGIST_CHOOSE_PROC 2 diff --git a/src/include/access/spgist_private.h b/src/include/access/spgist_private.h index 4a38938..953bbdb 100644 --- a/src/include/access/spgist_private.h +++ b/src/include/access/spgist_private.h @@ -22,6 +22,17 @@ #include "utils/relcache.h" +typedef struct SpGistRelOptions +{ + int32 varlena_header_; /* varlena header (do not touch directly!) */ + int fillfactor; /* page fill factor in percent (0..100) */ +} SpGistRelOptions; + +#define SpGistGetFillFactor(relation) \ + ((relation)->rd_options ? \ + ((SpGistRelOptions *) (relation)->rd_options)->fillfactor : \ + SPGIST_DEFAULT_FILLFACTOR) + /* Page numbers of fixed-location pages */ #define SPGIST_METAPAGE_BLKNO (0) /* metapage */ #define SPGIST_ROOT_BLKNO (1) /* root for normal entries */ @@ -417,6 +428,11 @@ typedef SpGistDeadTupleData *SpGistDeadTuple; #define GBUF_REQ_NULLS(flags) ((flags) & GBUF_NULLS) /* spgutils.c */ + +/* reloption parameters */ +#define SPGIST_MIN_FILLFACTOR 10 +#define SPGIST_DEFAULT_FILLFACTOR 80 + extern SpGistCache *spgGetCache(Relation index); extern void initSpGistState(SpGistState *state, Relation index); extern Buffer SpGistNewBuffer(Relation index); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index d35b4a5..6929636 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -231,15 +231,11 @@ typedef struct ForeignKeyCacheInfo } ForeignKeyCacheInfo; + /* - * StdRdOptions - * Standard contents of rd_options for heaps and generic indexes. - * - * RelationGetFillFactor() and RelationGetTargetPageFreeSpace() can only - * be applied to relations that use this format or a superset for - * private options data. + * AutoVacOpts + * Auto Vacuum options used both in Heap and Toast relations */ - /* autovacuum-related reloptions. */ typedef struct AutoVacOpts { bool enabled; @@ -258,52 +254,86 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -typedef struct StdRdOptions +/* + * HeapRelOptions + * Binary representation of relation options for Heap relations. + */ +typedef struct HeapRelOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - /* fraction of newly inserted tuples prior to trigger index cleanup */ - float8 vacuum_cleanup_index_scale_factor; int toast_tuple_target; /* target for tuple toasting */ - AutoVacOpts autovacuum; /* autovacuum-related options */ + AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - bool vacuum_index_cleanup; /* enables index vacuuming and cleanup */ + bool vacuum_index_cleanup; /* enables index vacuuming and cleanup */ bool vacuum_truncate; /* enables vacuum to truncate a relation */ -} StdRdOptions; +} HeapRelOptions; + +/* + * ToastRelOptions + * Binary representation of relation options for Toast relations. + */ +typedef struct ToastRelOptions +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + AutoVacOpts autovacuum; /* autovacuum-related options */ + bool vacuum_index_cleanup; /* enables index vacuuming and cleanup */ + bool vacuum_truncate; /* enables vacuum to truncate a relation */ +} ToastRelOptions; + + +/* + * PartitionedRelOptions + * Binary representation of relation options for Partitioned relations. + */ +typedef struct PartitionedRelOptions +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + /* No options defined yet */ +} PartitionedRelOptions; #define HEAP_MIN_FILLFACTOR 10 #define HEAP_DEFAULT_FILLFACTOR 100 +#define TOAST_DEFAULT_FILLFACTOR 100 /* Only default is actually used */ + + /* * RelationGetToastTupleTarget - * Returns the relation's toast_tuple_target. Note multiple eval of argument! + * Returns the heap's toast_tuple_target. Note multiple eval of argument! */ -#define RelationGetToastTupleTarget(relation, defaulttarg) \ - ((relation)->rd_options ? \ - ((StdRdOptions *) (relation)->rd_options)->toast_tuple_target : (defaulttarg)) +#define RelationGetToastTupleTarget(relation, defaulttarg) \ + (AssertMacro(relation->rd_rel->relkind == RELKIND_RELATION || \ + relation->rd_rel->relkind == RELKIND_MATVIEW), \ + ((relation)->rd_options ? \ + ((HeapRelOptions *) (relation)->rd_options)->toast_tuple_target : \ + (defaulttarg))) /* - * RelationGetFillFactor - * Returns the relation's fillfactor. Note multiple eval of argument! + * HeapGetFillFactor + * Returns the heap's fillfactor. Note multiple eval of argument! */ -#define RelationGetFillFactor(relation, defaultff) \ - ((relation)->rd_options ? \ - ((StdRdOptions *) (relation)->rd_options)->fillfactor : (defaultff)) +#define HeapGetFillFactor(relation) \ + (AssertMacro(relation->rd_rel->relkind == RELKIND_RELATION || \ + relation->rd_rel->relkind == RELKIND_MATVIEW), \ + ((relation)->rd_options ? \ + ((HeapRelOptions *) (relation)->rd_options)->fillfactor : \ + (HEAP_DEFAULT_FILLFACTOR))) /* - * RelationGetTargetPageUsage - * Returns the relation's desired space usage per page in bytes. + * HeapGetTargetPageUsage + * Returns the heap's desired space usage per page in bytes. */ -#define RelationGetTargetPageUsage(relation, defaultff) \ - (BLCKSZ * RelationGetFillFactor(relation, defaultff) / 100) +#define HeapGetTargetPageUsage(relation) \ + (BLCKSZ * HeapGetFillFactor(relation) / 100) /* - * RelationGetTargetPageFreeSpace - * Returns the relation's desired freespace per page in bytes. + * HeapGetTargetPageFreeSpace + * Returns the heap's desired freespace per page in bytes. */ -#define RelationGetTargetPageFreeSpace(relation, defaultff) \ - (BLCKSZ * (100 - RelationGetFillFactor(relation, defaultff)) / 100) +#define HeapGetTargetPageFreeSpace(relation) \ + (BLCKSZ * (100 - HeapGetFillFactor(relation)) / 100) /* * RelationIsUsedAsCatalogTable @@ -314,17 +344,27 @@ typedef struct StdRdOptions ((relation)->rd_options && \ ((relation)->rd_rel->relkind == RELKIND_RELATION || \ (relation)->rd_rel->relkind == RELKIND_MATVIEW) ? \ - ((StdRdOptions *) (relation)->rd_options)->user_catalog_table : false) + ((HeapRelOptions *) (relation)->rd_options)->user_catalog_table : false) /* * RelationGetParallelWorkers - * Returns the relation's parallel_workers reloption setting. + * Returns the heap's parallel_workers reloption setting. * Note multiple eval of argument! */ -#define RelationGetParallelWorkers(relation, defaultpw) \ - ((relation)->rd_options ? \ - ((StdRdOptions *) (relation)->rd_options)->parallel_workers : (defaultpw)) +#define RelationGetParallelWorkers(relation, defaultpw) \ + (AssertMacro(relation->rd_rel->relkind == RELKIND_RELATION || \ + relation->rd_rel->relkind == RELKIND_MATVIEW), \ + ((relation)->rd_options ? \ + ((HeapRelOptions *) (relation)->rd_options)->parallel_workers : \ + (defaultpw))) +/* + * ToastGetTargetPageFreeSpace + * Returns the TOAST relation's desired freespace per page in bytes. + * Always calculated using default fillfactor value. + */ +#define ToastGetTargetPageFreeSpace() \ + (BLCKSZ * (100 - TOAST_DEFAULT_FILLFACTOR) / 100) /* * ViewOptions @@ -342,9 +382,10 @@ typedef struct ViewOptions * Returns whether the relation is security view, or not. Note multiple * eval of argument! */ -#define RelationIsSecurityView(relation) \ - ((relation)->rd_options ? \ - ((ViewOptions *) (relation)->rd_options)->security_barrier : false) +#define RelationIsSecurityView(relation) \ + (AssertMacro(relation->rd_rel->relkind == RELKIND_VIEW), \ + ((relation)->rd_options ? \ + ((ViewOptions *) (relation)->rd_options)->security_barrier : false)) /* * RelationHasCheckOption @@ -352,8 +393,9 @@ typedef struct ViewOptions * or the cascaded check option. Note multiple eval of argument! */ #define RelationHasCheckOption(relation) \ + (AssertMacro(relation->rd_rel->relkind == RELKIND_VIEW), \ ((relation)->rd_options && \ - ((ViewOptions *) (relation)->rd_options)->check_option_offset != 0) + ((ViewOptions *) (relation)->rd_options)->check_option_offset != 0)) /* * RelationHasLocalCheckOption @@ -361,11 +403,12 @@ typedef struct ViewOptions * option. Note multiple eval of argument! */ #define RelationHasLocalCheckOption(relation) \ - ((relation)->rd_options && \ - ((ViewOptions *) (relation)->rd_options)->check_option_offset != 0 ? \ - strcmp((char *) (relation)->rd_options + \ - ((ViewOptions *) (relation)->rd_options)->check_option_offset, \ - "local") == 0 : false) + (AssertMacro(relation->rd_rel->relkind == RELKIND_VIEW), \ + ((relation)->rd_options && \ + ((ViewOptions *) (relation)->rd_options)->check_option_offset != 0 ? \ + strcmp((char *) (relation)->rd_options + \ + ((ViewOptions *) (relation)->rd_options)->check_option_offset, \ + "local") == 0 : false)) /* * RelationHasCascadedCheckOption @@ -373,11 +416,12 @@ typedef struct ViewOptions * option. Note multiple eval of argument! */ #define RelationHasCascadedCheckOption(relation) \ + (AssertMacro(relation->rd_rel->relkind == RELKIND_VIEW), \ ((relation)->rd_options && \ ((ViewOptions *) (relation)->rd_options)->check_option_offset != 0 ? \ strcmp((char *) (relation)->rd_options + \ ((ViewOptions *) (relation)->rd_options)->check_option_offset, \ - "cascaded") == 0 : false) + "cascaded") == 0 : false)) /*