diff options
Diffstat (limited to 'src/include/access/htup.h')
-rw-r--r-- | src/include/access/htup.h | 118 |
1 files changed, 65 insertions, 53 deletions
diff --git a/src/include/access/htup.h b/src/include/access/htup.h index eecc6959e89..31de835d290 100644 --- a/src/include/access/htup.h +++ b/src/include/access/htup.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/access/htup.h,v 1.90 2007/02/05 04:22:18 tgl Exp $ + * $PostgreSQL: pgsql/src/include/access/htup.h,v 1.91 2007/02/09 03:35:34 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -45,7 +45,7 @@ /* * Heap tuple header. To avoid wasting space, the fields should be - * layed out in such a way to avoid structure padding. + * laid out in such a way as to avoid structure padding. * * Datums of composite types (row types) share the same general structure * as on-disk tuples, so that the same routines can be used to build and @@ -65,17 +65,18 @@ * object ID (if HEAP_HASOID is set in t_infomask) * user data fields * - * We store five "virtual" fields Xmin, Cmin, Xmax, Cmax, and Xvac in four - * physical fields. Xmin, Cmin and Xmax are always really stored, but - * Cmax and Xvac share a field. This works because we know that there are - * only a limited number of states that a tuple can be in, and that Cmax - * is only interesting for the lifetime of the deleting transaction. - * This assumes that VACUUM FULL never tries to move a tuple whose Cmax - * is still interesting (ie, delete-in-progress). - * - * Note that in 7.3 and 7.4 a similar idea was applied to Xmax and Cmin. - * However, with the advent of subtransactions, a tuple may need both Xmax - * and Cmin simultaneously, so this is no longer possible. + * We store five "virtual" fields Xmin, Cmin, Xmax, Cmax, and Xvac in three + * physical fields. Xmin and Xmax are always really stored, but Cmin, Cmax + * and Xvac share a field. This works because we know that Cmin and Cmax + * are only interesting for the lifetime of the inserting and deleting + * transaction respectively. If a tuple is inserted and deleted in the same + * transaction, we store a "combo" command id that can be mapped to the real + * cmin and cmax, but only by use of local state within the originating + * backend. See combocid.c for more details. Meanwhile, Xvac is only set + * by VACUUM FULL, which does not have any command sub-structure and so does + * not need either Cmin or Cmax. (This requires that VACUUM FULL never try + * to move a tuple whose Cmin or Cmax is still interesting, ie, an insert- + * in-progress or delete-in-progress tuple.) * * A word about t_ctid: whenever a new tuple is stored on disk, its t_ctid * is initialized with its own TID (location). If the tuple is ever updated, @@ -103,14 +104,13 @@ typedef struct HeapTupleFields { TransactionId t_xmin; /* inserting xact ID */ - CommandId t_cmin; /* inserting command ID */ TransactionId t_xmax; /* deleting or locking xact ID */ union { - CommandId t_cmax; /* deleting or locking command ID */ + CommandId t_cid; /* inserting or deleting command ID, or both */ TransactionId t_xvac; /* VACUUM FULL xact ID */ - } t_field4; + } t_field3; } HeapTupleFields; typedef struct DatumTupleFields @@ -145,7 +145,7 @@ typedef struct HeapTupleHeaderData uint8 t_hoff; /* sizeof header incl. bitmap, padding */ - /* ^ - 27 bytes - ^ */ + /* ^ - 23 bytes - ^ */ bits8 t_bits[1]; /* bitmap of NULLs -- VARIABLE LENGTH */ @@ -163,7 +163,7 @@ typedef HeapTupleHeaderData *HeapTupleHeader; #define HEAP_HASCOMPRESSED 0x0008 /* has compressed stored attribute(s) */ #define HEAP_HASEXTENDED 0x000C /* the two above combined */ #define HEAP_HASOID 0x0010 /* has an object-id field */ -/* 0x0020 is presently unused */ +#define HEAP_COMBOCID 0x0020 /* t_cid is a combo cid */ #define HEAP_XMAX_EXCL_LOCK 0x0040 /* xmax is exclusive locker */ #define HEAP_XMAX_SHARED_LOCK 0x0080 /* xmax is shared locker */ /* if either LOCK bit is set, xmax hasn't deleted the tuple, only locked it */ @@ -180,17 +180,13 @@ typedef HeapTupleHeaderData *HeapTupleHeader; * FULL */ #define HEAP_MOVED (HEAP_MOVED_OFF | HEAP_MOVED_IN) -#define HEAP_XACT_MASK 0xFFC0 /* visibility-related bits */ +#define HEAP_XACT_MASK 0xFFE0 /* visibility-related bits */ -/* information stored in t_infomask2, and accessor macros */ +/* + * information stored in t_infomask2: + */ #define HEAP_NATTS_MASK 0x7FF /* 11 bits for number of attributes */ -/* bits 0xF800 are unused */ - -#define HeapTupleHeaderGetNatts(tup) ((tup)->t_infomask2 & HEAP_NATTS_MASK) -#define HeapTupleHeaderSetNatts(tup, natts) \ -( \ - (tup)->t_infomask2 = ((tup)->t_infomask2 & ~HEAP_NATTS_MASK) | (natts) \ -) +/* bits 0xF800 are currently unused */ /* * HeapTupleHeader accessor macros @@ -219,39 +215,40 @@ typedef HeapTupleHeaderData *HeapTupleHeader; TransactionIdStore((xid), &(tup)->t_choice.t_heap.t_xmax) \ ) -#define HeapTupleHeaderGetCmin(tup) \ -( \ - (tup)->t_choice.t_heap.t_cmin \ -) - -#define HeapTupleHeaderSetCmin(tup, cid) \ -( \ - (tup)->t_choice.t_heap.t_cmin = (cid) \ -) - /* - * Note: GetCmax will produce wrong answers after SetXvac has been executed - * by a transaction other than the inserting one. We could check - * HEAP_XMAX_INVALID and return FirstCommandId if it's clear, but since that - * bit will be set again if the deleting transaction aborts, there'd be no - * real gain in safety from the extra test. So, just rely on the caller not - * to trust the value unless it's meaningful. + * HeapTupleHeaderGetRawCommandId will give you what's in the header whether + * it is useful or not. Most code should use HeapTupleHeaderGetCmin or + * HeapTupleHeaderGetCmax instead, but note that those Assert that you can + * get a legitimate result, ie you are in the originating transaction! */ -#define HeapTupleHeaderGetCmax(tup) \ +#define HeapTupleHeaderGetRawCommandId(tup) \ ( \ - (tup)->t_choice.t_heap.t_field4.t_cmax \ + (tup)->t_choice.t_heap.t_field3.t_cid \ ) -#define HeapTupleHeaderSetCmax(tup, cid) \ +/* SetCmin is reasonably simple since we never need a combo CID */ +#define HeapTupleHeaderSetCmin(tup, cid) \ do { \ Assert(!((tup)->t_infomask & HEAP_MOVED)); \ - (tup)->t_choice.t_heap.t_field4.t_cmax = (cid); \ + (tup)->t_choice.t_heap.t_field3.t_cid = (cid); \ + (tup)->t_infomask &= ~HEAP_COMBOCID; \ +} while (0) + +/* SetCmax must be used after HeapTupleHeaderAdjustCmax; see combocid.c */ +#define HeapTupleHeaderSetCmax(tup, cid, iscombo) \ +do { \ + Assert(!((tup)->t_infomask & HEAP_MOVED)); \ + (tup)->t_choice.t_heap.t_field3.t_cid = (cid); \ + if (iscombo) \ + (tup)->t_infomask |= HEAP_COMBOCID; \ + else \ + (tup)->t_infomask &= ~HEAP_COMBOCID; \ } while (0) #define HeapTupleHeaderGetXvac(tup) \ ( \ ((tup)->t_infomask & HEAP_MOVED) ? \ - (tup)->t_choice.t_heap.t_field4.t_xvac \ + (tup)->t_choice.t_heap.t_field3.t_xvac \ : \ InvalidTransactionId \ ) @@ -259,7 +256,7 @@ do { \ #define HeapTupleHeaderSetXvac(tup, xid) \ do { \ Assert((tup)->t_infomask & HEAP_MOVED); \ - TransactionIdStore((xid), &(tup)->t_choice.t_heap.t_field4.t_xvac); \ + TransactionIdStore((xid), &(tup)->t_choice.t_heap.t_field3.t_xvac); \ } while (0) #define HeapTupleHeaderGetDatumLength(tup) \ @@ -306,6 +303,14 @@ do { \ *((Oid *) ((char *)(tup) + (tup)->t_hoff - sizeof(Oid))) = (oid); \ } while (0) +#define HeapTupleHeaderGetNatts(tup) \ + ((tup)->t_infomask2 & HEAP_NATTS_MASK) + +#define HeapTupleHeaderSetNatts(tup, natts) \ +( \ + (tup)->t_infomask2 = ((tup)->t_infomask2 & ~HEAP_NATTS_MASK) | (natts) \ +) + /* * BITMAPLEN(NATTS) - @@ -374,9 +379,9 @@ do { \ * and thereby prevent accidental use of the nonexistent fields. * * MinimalTupleData contains a length word, some padding, and fields matching - * HeapTupleHeaderData beginning with t_infomask2. The padding is chosen so that - * offsetof(t_infomask2) is the same modulo MAXIMUM_ALIGNOF in both structs. - * This makes data alignment rules equivalent in both cases. + * HeapTupleHeaderData beginning with t_infomask2. The padding is chosen so + * that offsetof(t_infomask2) is the same modulo MAXIMUM_ALIGNOF in both + * structs. This makes data alignment rules equivalent in both cases. * * When a minimal tuple is accessed via a HeapTupleData pointer, t_data is * set to point MINIMAL_TUPLE_OFFSET bytes before the actual start of the @@ -405,7 +410,7 @@ typedef struct MinimalTupleData uint8 t_hoff; /* sizeof header incl. bitmap, padding */ - /* ^ - 27 bytes - ^ */ + /* ^ - 23 bytes - ^ */ bits8 t_bits[1]; /* bitmap of NULLs -- VARIABLE LENGTH */ @@ -638,4 +643,11 @@ typedef struct xl_heap_freeze #define SizeOfHeapFreeze (offsetof(xl_heap_freeze, cutoff_xid) + sizeof(TransactionId)) +/* HeapTupleHeader functions implemented in utils/time/combocid.c */ +extern CommandId HeapTupleHeaderGetCmin(HeapTupleHeader tup); +extern CommandId HeapTupleHeaderGetCmax(HeapTupleHeader tup); +extern void HeapTupleHeaderAdjustCmax(HeapTupleHeader tup, + CommandId *cmax, + bool *iscombo); + #endif /* HTUP_H */ |