From 58aa911e66a5509fd9e4d6ff3b36c76745b3db7f Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Fri, 20 Feb 2015 16:42:28 +0900 Subject: [PATCH 2/4] Switch HeapTupleHeaderData and MinimalTupleData to use flexible arrays This is some more hacking related to FLEXIBLE_ARRAY_MEMBER. --- contrib/file_fdw/file_fdw.c | 2 +- contrib/postgres_fdw/postgres_fdw.c | 3 ++- src/backend/access/heap/heapam.c | 12 ++++++------ src/backend/executor/nodeHash.c | 2 +- src/backend/optimizer/path/costsize.c | 7 ++++--- src/backend/optimizer/plan/planner.c | 6 ++++-- src/backend/optimizer/plan/subselect.c | 9 +++++---- src/backend/optimizer/prep/prepunion.c | 3 ++- src/backend/optimizer/util/plancat.c | 2 +- src/backend/replication/logical/decode.c | 24 +++++++++++------------ src/backend/replication/logical/reorderbuffer.c | 26 +++++++++++-------------- src/include/access/htup_details.h | 4 ++-- src/include/replication/reorderbuffer.h | 7 +++++-- 13 files changed, 56 insertions(+), 51 deletions(-) diff --git a/contrib/file_fdw/file_fdw.c b/contrib/file_fdw/file_fdw.c index d569760..4cc168f 100644 --- a/contrib/file_fdw/file_fdw.c +++ b/contrib/file_fdw/file_fdw.c @@ -932,7 +932,7 @@ estimate_size(PlannerInfo *root, RelOptInfo *baserel, int tuple_width; tuple_width = MAXALIGN(baserel->width) + - MAXALIGN(sizeof(HeapTupleHeaderData)); + MAXALIGN(offsetof(HeapTupleHeaderData, t_bits)); ntuples = clamp_row_est((double) stat_buf.st_size / (double) tuple_width); } diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index d76e739..f94d54a 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -519,7 +519,8 @@ postgresGetForeignRelSize(PlannerInfo *root, { baserel->pages = 10; baserel->tuples = - (10 * BLCKSZ) / (baserel->width + sizeof(HeapTupleHeaderData)); + (10 * BLCKSZ) / + (baserel->width + offsetof(HeapTupleHeaderData, t_bits)); } /* Estimate baserel size as best we can with local statistics. */ diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 46060bc1..15fff73 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -7351,7 +7351,7 @@ heap_xlog_insert(XLogReaderState *record) xl_heap_insert *xlrec = (xl_heap_insert *) XLogRecGetData(record); Buffer buffer; Page page; - struct + union { HeapTupleHeaderData hdr; char data[MaxHeapTupleSize]; @@ -7415,7 +7415,7 @@ heap_xlog_insert(XLogReaderState *record) data += SizeOfHeapHeader; htup = &tbuf.hdr; - MemSet((char *) htup, 0, sizeof(HeapTupleHeaderData)); + MemSet((char *) htup, 0, offsetof(HeapTupleHeaderData, t_bits)); /* PG73FORMAT: get bitmap [+ padding] [+ oid] + data */ memcpy((char *) htup + offsetof(HeapTupleHeaderData, t_bits), data, @@ -7469,7 +7469,7 @@ heap_xlog_multi_insert(XLogReaderState *record) BlockNumber blkno; Buffer buffer; Page page; - struct + union { HeapTupleHeaderData hdr; char data[MaxHeapTupleSize]; @@ -7548,7 +7548,7 @@ heap_xlog_multi_insert(XLogReaderState *record) newlen = xlhdr->datalen; Assert(newlen <= MaxHeapTupleSize); htup = &tbuf.hdr; - MemSet((char *) htup, 0, sizeof(HeapTupleHeaderData)); + MemSet((char *) htup, 0, offsetof(HeapTupleHeaderData, t_bits)); /* PG73FORMAT: get bitmap [+ padding] [+ oid] + data */ memcpy((char *) htup + offsetof(HeapTupleHeaderData, t_bits), (char *) tupdata, @@ -7618,7 +7618,7 @@ heap_xlog_update(XLogReaderState *record, bool hot_update) uint16 prefixlen = 0, suffixlen = 0; char *newp; - struct + union { HeapTupleHeaderData hdr; char data[MaxHeapTupleSize]; @@ -7780,7 +7780,7 @@ heap_xlog_update(XLogReaderState *record, bool hot_update) Assert(tuplen <= MaxHeapTupleSize); htup = &tbuf.hdr; - MemSet((char *) htup, 0, sizeof(HeapTupleHeaderData)); + MemSet((char *) htup, 0, offsetof(HeapTupleHeaderData, t_bits)); /* * Reconstruct the new tuple using the prefix and/or suffix from the diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c index abd70b3..4b922b9 100644 --- a/src/backend/executor/nodeHash.c +++ b/src/backend/executor/nodeHash.c @@ -439,7 +439,7 @@ ExecChooseHashTableSize(double ntuples, int tupwidth, bool useskew, * don't count palloc overhead either. */ tupsize = HJTUPLE_OVERHEAD + - MAXALIGN(sizeof(MinimalTupleData)) + + MAXALIGN(offsetof(MinimalTupleData, t_bits)) + MAXALIGN(tupwidth); inner_rel_bytes = ntuples * tupsize; diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 020558b..dea45c0 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -4036,11 +4036,11 @@ set_rel_width(PlannerInfo *root, RelOptInfo *rel) /* * If we have a whole-row reference, estimate its width as the sum of - * per-column widths plus sizeof(HeapTupleHeaderData). + * per-column widths plus offsetof(HeapTupleHeaderData, t_bits). */ if (have_wholerow_var) { - int32 wholerow_width = sizeof(HeapTupleHeaderData); + int32 wholerow_width = offsetof(HeapTupleHeaderData, t_bits); if (reloid != InvalidOid) { @@ -4078,7 +4078,8 @@ set_rel_width(PlannerInfo *root, RelOptInfo *rel) static double relation_byte_size(double tuples, int width) { - return tuples * (MAXALIGN(width) + MAXALIGN(sizeof(HeapTupleHeaderData))); + return tuples * (MAXALIGN(width) + + MAXALIGN(offsetof(HeapTupleHeaderData, t_bits))); } /* diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 5c4884f..1e6680c 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -2755,7 +2755,8 @@ choose_hashed_grouping(PlannerInfo *root, */ /* Estimate per-hash-entry space at tuple width... */ - hashentrysize = MAXALIGN(path_width) + MAXALIGN(sizeof(MinimalTupleData)); + hashentrysize = MAXALIGN(path_width) + + MAXALIGN(offsetof(MinimalTupleData, t_bits)); /* plus space for pass-by-ref transition values... */ hashentrysize += agg_costs->transitionSpace; /* plus the per-hash-entry overhead */ @@ -2923,7 +2924,8 @@ choose_hashed_distinct(PlannerInfo *root, */ /* Estimate per-hash-entry space at tuple width... */ - hashentrysize = MAXALIGN(path_width) + MAXALIGN(sizeof(MinimalTupleData)); + hashentrysize = MAXALIGN(path_width) + + MAXALIGN(offsetof(MinimalTupleData, t_bits)); /* plus the per-hash-entry overhead */ hashentrysize += hash_agg_entry_size(0); diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 78fb6b1..918a5cf 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -974,12 +974,13 @@ subplan_is_hashable(Plan *plan) /* * The estimated size of the subquery result must fit in work_mem. (Note: - * we use sizeof(HeapTupleHeaderData) here even though the tuples will - * actually be stored as MinimalTuples; this provides some fudge factor - * for hashtable overhead.) + * we use offsetof(HeapTupleHeaderData, t_bits) here even though the tuples + * will actually be stored as MinimalTuples; this provides some fudge + * factor for hashtable overhead.) */ subquery_size = plan->plan_rows * - (MAXALIGN(plan->plan_width) + MAXALIGN(sizeof(HeapTupleHeaderData))); + (MAXALIGN(plan->plan_width) + + MAXALIGN(offsetof(HeapTupleHeaderData, t_bits))); if (subquery_size > work_mem * 1024L) return false; diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index 05f601e..b290a08 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -832,7 +832,8 @@ choose_hashed_setop(PlannerInfo *root, List *groupClauses, * Don't do it if it doesn't look like the hashtable will fit into * work_mem. */ - hashentrysize = MAXALIGN(input_plan->plan_width) + MAXALIGN(sizeof(MinimalTupleData)); + hashentrysize = MAXALIGN(input_plan->plan_width) + + MAXALIGN(offsetof(MinimalTupleData, t_bits)); if (hashentrysize * dNumGroups > work_mem * 1024L) return false; diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index fb7db6d..4a0a377 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -508,7 +508,7 @@ estimate_rel_size(Relation rel, int32 *attr_widths, int32 tuple_width; tuple_width = get_rel_data_width(rel, attr_widths); - tuple_width += sizeof(HeapTupleHeaderData); + tuple_width += offsetof(HeapTupleHeaderData, t_bits); tuple_width += sizeof(ItemIdData); /* note: integer division is intentional here */ density = (BLCKSZ - SizeOfPageHeaderData) / tuple_width; diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c index 77c02ba..574f63b 100644 --- a/src/backend/replication/logical/decode.c +++ b/src/backend/replication/logical/decode.c @@ -765,21 +765,21 @@ DecodeMultiInsert(LogicalDecodingContext *ctx, XLogRecordBuffer *buf) * transactions. */ tuple->tuple.t_tableOid = InvalidOid; - tuple->tuple.t_data = &tuple->header; + tuple->tuple.t_data = &tuple->t_data.header; tuple->tuple.t_len = datalen + offsetof(HeapTupleHeaderData, t_bits); - memset(&tuple->header, 0, sizeof(HeapTupleHeaderData)); + memset(&tuple->t_data.header, 0, offsetof(HeapTupleHeaderData, t_bits)); - memcpy((char *) &tuple->header + memcpy((char *) &tuple->t_data.header + offsetof(HeapTupleHeaderData, t_bits), (char *) data, datalen); data += datalen; - tuple->header.t_infomask = xlhdr->t_infomask; - tuple->header.t_infomask2 = xlhdr->t_infomask2; - tuple->header.t_hoff = xlhdr->t_hoff; + tuple->t_data.header.t_infomask = xlhdr->t_infomask; + tuple->t_data.header.t_infomask2 = xlhdr->t_infomask2; + tuple->t_data.header.t_hoff = xlhdr->t_hoff; } /* @@ -822,20 +822,20 @@ DecodeXLogTuple(char *data, Size len, ReorderBufferTupleBuf *tuple) /* we can only figure this out after reassembling the transactions */ tuple->tuple.t_tableOid = InvalidOid; - tuple->tuple.t_data = &tuple->header; + tuple->tuple.t_data = &tuple->t_data.header; /* data is not stored aligned, copy to aligned storage */ memcpy((char *) &xlhdr, data, SizeOfHeapHeader); - memset(&tuple->header, 0, sizeof(HeapTupleHeaderData)); + memset(&tuple->t_data.header, 0, offsetof(HeapTupleHeaderData, t_bits)); - memcpy((char *) &tuple->header + offsetof(HeapTupleHeaderData, t_bits), + memcpy((char *) &tuple->t_data.header + offsetof(HeapTupleHeaderData, t_bits), data + SizeOfHeapHeader, datalen); - tuple->header.t_infomask = xlhdr.t_infomask; - tuple->header.t_infomask2 = xlhdr.t_infomask2; - tuple->header.t_hoff = xlhdr.t_hoff; + tuple->t_data.header.t_infomask = xlhdr.t_infomask; + tuple->t_data.header.t_infomask2 = xlhdr.t_infomask2; + tuple->t_data.header.t_hoff = xlhdr.t_hoff; } diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c index bcd5896..3226405 100644 --- a/src/backend/replication/logical/reorderbuffer.c +++ b/src/backend/replication/logical/reorderbuffer.c @@ -2014,14 +2014,12 @@ ReorderBufferSerializeChange(ReorderBuffer *rb, ReorderBufferTXN *txn, newtup = change->data.tp.newtuple; if (oldtup) - oldlen = offsetof(ReorderBufferTupleBuf, data) - +oldtup->tuple.t_len - - offsetof(HeapTupleHeaderData, t_bits); + oldlen = offsetof(ReorderBufferTupleBuf, t_data) + + oldtup->tuple.t_len; if (newtup) - newlen = offsetof(ReorderBufferTupleBuf, data) - +newtup->tuple.t_len - - offsetof(HeapTupleHeaderData, t_bits); + newlen = offsetof(ReorderBufferTupleBuf, t_data) + + newtup->tuple.t_len; sz += oldlen; sz += newlen; @@ -2262,27 +2260,25 @@ ReorderBufferRestoreChange(ReorderBuffer *rb, ReorderBufferTXN *txn, case REORDER_BUFFER_CHANGE_DELETE: if (change->data.tp.newtuple) { - Size len = offsetof(ReorderBufferTupleBuf, data) - +((ReorderBufferTupleBuf *) data)->tuple.t_len - - offsetof(HeapTupleHeaderData, t_bits); + Size len = offsetof(ReorderBufferTupleBuf, t_data) + + ((ReorderBufferTupleBuf *) data)->tuple.t_len; change->data.tp.newtuple = ReorderBufferGetTupleBuf(rb); memcpy(change->data.tp.newtuple, data, len); change->data.tp.newtuple->tuple.t_data = - &change->data.tp.newtuple->header; + &change->data.tp.newtuple->t_data.header; data += len; } if (change->data.tp.oldtuple) { - Size len = offsetof(ReorderBufferTupleBuf, data) - +((ReorderBufferTupleBuf *) data)->tuple.t_len - - offsetof(HeapTupleHeaderData, t_bits); + Size len = offsetof(ReorderBufferTupleBuf, t_data) + + ((ReorderBufferTupleBuf *) data)->tuple.t_len; change->data.tp.oldtuple = ReorderBufferGetTupleBuf(rb); memcpy(change->data.tp.oldtuple, data, len); change->data.tp.oldtuple->tuple.t_data = - &change->data.tp.oldtuple->header; + &change->data.tp.oldtuple->t_data.header; data += len; } break; @@ -2660,7 +2656,7 @@ ReorderBufferToastReplace(ReorderBuffer *rb, ReorderBufferTXN *txn, */ tmphtup = heap_form_tuple(desc, attrs, isnull); Assert(newtup->tuple.t_len <= MaxHeapTupleSize); - Assert(&newtup->header == newtup->tuple.t_data); + Assert(&newtup->t_data.header == newtup->tuple.t_data); memcpy(newtup->tuple.t_data, tmphtup->t_data, tmphtup->t_len); newtup->tuple.t_len = tmphtup->t_len; diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h index d2ad910..475377c 100644 --- a/src/include/access/htup_details.h +++ b/src/include/access/htup_details.h @@ -150,7 +150,7 @@ struct HeapTupleHeaderData /* ^ - 23 bytes - ^ */ - bits8 t_bits[1]; /* bitmap of NULLs -- VARIABLE LENGTH */ + bits8 t_bits[FLEXIBLE_ARRAY_MEMBER]; /* bitmap of NULLs */ /* MORE DATA FOLLOWS AT END OF STRUCT */ }; @@ -579,7 +579,7 @@ struct MinimalTupleData /* ^ - 23 bytes - ^ */ - bits8 t_bits[1]; /* bitmap of NULLs -- VARIABLE LENGTH */ + bits8 t_bits[FLEXIBLE_ARRAY_MEMBER]; /* bitmap of NULLs */ /* MORE DATA FOLLOWS AT END OF STRUCT */ }; diff --git a/src/include/replication/reorderbuffer.h b/src/include/replication/reorderbuffer.h index 5a1d9a0..dcfe2b3 100644 --- a/src/include/replication/reorderbuffer.h +++ b/src/include/replication/reorderbuffer.h @@ -28,8 +28,11 @@ typedef struct ReorderBufferTupleBuf /* tuple, stored sequentially */ HeapTupleData tuple; - HeapTupleHeaderData header; - char data[MaxHeapTupleSize]; + union + { + HeapTupleHeaderData header; + char data[MaxHeapTupleSize]; + } t_data; } ReorderBufferTupleBuf; /* -- 2.3.0