Re: Upgrading rant. - Mailing list pgsql-hackers
| From | Manfred Koizar |
|---|---|
| Subject | Re: Upgrading rant. |
| Date | |
| Msg-id | jq7l1vgiqv6no36u0855hub66imubcg1l5@4ax.com Whole thread Raw |
| In response to | Re: Upgrading rant. (Tom Lane <tgl@sss.pgh.pa.us>) |
| Responses |
Re: Upgrading rant.
|
| List | pgsql-hackers |
On Fri, 03 Jan 2003 15:37:56 -0500, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>The system tables are not the problem. [...]
>
>Changes in the on-disk representation of user tables would be harder to
>deal with, but they are also much rarer (AFAIR we've only done that
>twice: WAL required additions to page and tuple headers, and then there
>were Manfred's space-saving changes in 7.3).
So I'm the bad guy? ;-) AFAICS handling the page and tuple format
changes doesn't need much more than what I have hacked together
yesterday afternoon:
#include <access/htup.h>
typedef struct HeapTupleHeader72Data
{Oid t_oid; /* OID of this tuple -- 4 bytes */CommandId t_cmin; /* insert CID stamp
--4 bytes each */CommandId t_cmax; /* delete CommandId stamp */TransactionId t_xmin; /* insert XID
stamp-- 4 bytes each */TransactionId t_xmax; /* delete XID stamp */ItemPointerData t_ctid; /* current TID
ofthis or newer tuple */int16 t_natts; /* number of attributes */uint16 t_infomask; /*
variousinfos */uint8 t_hoff; /* sizeof() tuple header *//* ^ - 31 bytes - ^ */bits8
t_bits[1];/*bit map of NULLs */
} HeapTupleHeader72Data;
typedef HeapTupleHeader72Data *HeapTupleHeader72;
/*
** Convert a pre-7.3 heap tuple header to 7.3 format.
**
** On entry ht points to a heap tuple header in 7.2 format,
** which will be converted to the new format in place.
** If compact is true, the size of the heap tuple header
** (t_hoff) is reduced, otherwise enough padding bytes are
** inserted to keep the old length.
**
** The return value is the new size.
*/
Size
HeapTupleHeader_To73Format(HeapTupleHeader ht, bool compact)
{HeapTupleHeaderData newdata;Oid oid;HeapTupleHeader72 ht72;int len;
ht72 = (HeapTupleHeader72) ht;oid = ht72->t_oid;MemSet(&newdata, 0, sizeof(HeapTupleHeaderData));
/* copy fixed fields */ItemPointerCopy(&ht72->t_ctid, &newdata.t_ctid);newdata.t_natts =
ht72->t_natts;newdata.t_infomask= ht72->t_infomask;
HeapTupleHeaderSetXmin(&newdata, ht72->t_xmin);if (newdata.t_infomask & HEAP_XMAX_INVALID) {
HeapTupleHeaderSetCmin(&newdata,ht72->t_cmin);}/*if*/else { HeapTupleHeaderSetXmax(&newdata,
ht72->t_xmax);}/*else*/
if (newdata.t_infomask & HEAP_MOVED) { HeapTupleHeaderSetXvac(&newdata, ht72->t_cmin);}/*if*/else {
HeapTupleHeaderSetCmax(&newdata,ht72->t_cmax);}/*else*/
/* move new structure into original position */len = offsetof(HeapTupleHeaderData, t_bits);memcpy(ht, &newdata, len);
/* copy bitmap (if there is one) */if (ht->t_infomask & HEAP_HASNULL) { int bitmaplen = BITMAPLEN(ht->t_natts);
intoff = offsetof(HeapTupleHeader72Data, t_bits); char *p = (char *) ht; int i;
Assert(len < off); for (i = 0; i < bitmaplen; ++i) { p[len + i] = p[off + i]; }/*for*/
len += bitmaplen;}/*if*/
/* pad rest with 0 */Assert(len < ht->t_hoff);memset((char *)ht + len, 0, ht->t_hoff - len);
/* change length, if requested */if (compact) { if (oid != 0) { len += sizeof(Oid); }/*if*/
ht->t_hoff = MAXALIGN(len);}/*if*/
/* copy oid (if there is one) */if (oid != 0) { ht->t_infomask |= HEAP_HASOID; HeapTupleHeaderSetOid(ht,
oid);}/*if*/
return ht->t_hoff;
}
#include <storage/bufpage.h>
#include <access/htup.h>
/*
** Convert a pre 7.3 heap page to 7.3 format,
** or leave the page alone, if it is already in 7.3 format.
**
** The page is converted in place.
**
** We should have exclusive access to the page, either per
** LockBufferForCleanup() or because we a running in a standalone
** tool.
*/
void
HeapPage_To73Format(Page page, bool compact)
{PageHeader phdr = (PageHeader)page;int version = PageGetPageLayoutVersion(page);Size size = PageGetPageSize(page);int
maxoff= PageGetMaxOffsetNumber(page);int i;
if (version == PG_PAGE_LAYOUT_VERSION) { /* already converted */ return;}/*if*/
Assert(version == 0);
for (i = 1; i <= maxoff; ++i) { ItemId itid = PageGetItemId(page, i); // ??? if (ItemIdIsUsed(itid)) ...
HeapTupleHeaderht = PageGetItem(page, itid); Size oldsz = ht->t_hoff; Size newsz;
newsz = HeapTupleHeader_To73Format(ht, compact); if (newsz < oldsz) { int diff = oldsz - newsz;
ItemOffsetoff = ItemIdGetOffset(itid); char *addr; int lng; int j;
/* move tuple header to the right */ addr = (char *)ht; memmove(addr + diff, addr, newsz);
itid->lp_off+= diff; itid->lp_len -= diff;
/* ** Move all tuples that lie to the left of our tuple header. ** (Shamelessly copied from
PageIndexTupleDelete()). */ addr = (char *) page + phdr->pd_upper; lng = (int) (off -
phdr->pd_upper); if (lng > 0) memmove(addr + diff, addr, lng);
memset(addr, 0, diff);
/* ** Adjust upper free space boundary pointer, ** lower is not affected. */
phdr->pd_upper+= diff;
/* Adjust linp entries. */ for (j = 1; j <= maxoff; ++j) { ItemId ii = PageGetItemId(page,
j); if (ii->lp_off < off) ii->lp_off += diff; }/*for*/ }/*if*/ else
Assert(newsz== oldsz);}/*for*/
PageSetPageSizeAndVersion(page, size, PG_PAGE_LAYOUT_VERSION);
}
/*
** Convert a pre 7.3 page to 7.3 format,
** or leave the page alone, if it is already in 7.3 format.
**
** The page is converted in place.
**
** We should have exclusive access to the page, either per
** LockBufferForCleanup() or because we a running in a standalone
** tool.
*/
void
Page_To73Format(Page page)
{int version = PageGetPageLayoutVersion(page);Size size = PageGetPageSize(page);
if (version == PG_PAGE_LAYOUT_VERSION) { /* already converted */ return;}/*if*/
Assert(version == 0);if (PageGetSpecialSize(page) == 0) { /* ** Heap page. ** XXX Sure? ** XXX Is there a
betterway to tell? */ HeapPage_To73Format(page, true);}/*if*/else { /* ** Not a heap page: no format
change,just adjust version */ PageSetPageSizeAndVersion(page, size, PG_PAGE_LAYOUT_VERSION);}/*else*/
}
This should handle all format changes I'm aware of:. bitmap length. overlaying fields. optional oid. page format
version
Am I missing something?
Above code is completely untested, I've not even run it through a
compiler; please consider it as a basis for discussion. If there is
agreement, that we want 7.2 -> 7.3.x pg_upgrade, I'll put more work
into it.
What's missing is mainly a call to Page_To73Format() somewhere. I can
think of. an input-file-to-output-file-converter run by pg_upgrade instead of copying/moving the files. an
in-place-converterrun by pg_upgrade after copying/moving the files. converting each page during normal operation
immediatelyafter it is fetched from disk.
#include <access/htup.h>
typedef struct HeapTupleHeader72Data
{Oid t_oid; /* OID of this tuple -- 4 bytes */CommandId t_cmin; /* insert CID stamp
--4 bytes each */CommandId t_cmax; /* delete CommandId stamp */TransactionId t_xmin; /* insert XID
stamp-- 4 bytes each */TransactionId t_xmax; /* delete XID stamp */ItemPointerData t_ctid; /* current TID
ofthis or newer tuple */int16 t_natts; /* number of attributes */uint16 t_infomask; /*
variousinfos */uint8 t_hoff; /* sizeof() tuple header *//* ^ - 31 bytes - ^ */bits8
t_bits[1];/*bit map of NULLs */
} HeapTupleHeader72Data;
typedef HeapTupleHeader72Data *HeapTupleHeader72;
/*
** Convert a pre-7.3 heap tuple header to 7.3 format.
**
** On entry ht points to a heap tuple header in 7.2 format,
** which will be converted to the new format in place.
** If compact is true, the size of the heap tuple header
** (t_hoff) is reduced, otherwise enough padding bytes are
** inserted to keep the old length.
**
** The return value is the new size.
*/
Size
HeapTupleHeader_To73Format(HeapTupleHeader ht, bool compact)
{HeapTupleHeaderData newdata;Oid oid;HeapTupleHeader72 ht72;int len;
ht72 = (HeapTupleHeader72) ht;oid = ht72->t_oid;MemSet(&newdata, 0, sizeof(HeapTupleHeaderData));
/* copy fixed fields */ItemPointerCopy(&ht72->t_ctid, &newdata.t_ctid);newdata.t_natts =
ht72->t_natts;newdata.t_infomask= ht72->t_infomask;
HeapTupleHeaderSetXmin(&newdata, ht72->t_xmin);if (newdata.t_infomask & HEAP_XMAX_INVALID) {
HeapTupleHeaderSetCmin(&newdata,ht72->t_cmin);}/*if*/else { HeapTupleHeaderSetXmax(&newdata,
ht72->t_xmax);}/*else*/
if (newdata.t_infomask & HEAP_MOVED) { HeapTupleHeaderSetXvac(&newdata, ht72->t_cmin);}/*if*/else {
HeapTupleHeaderSetCmax(&newdata,ht72->t_cmax);}/*else*/
/* move new structure into original position */len = offsetof(HeapTupleHeaderData, t_bits);memcpy(ht, &newdata, len);
/* copy bitmap (if there is one) */if (ht->t_infomask & HEAP_HASNULL) { int bitmaplen = BITMAPLEN(ht->t_natts);
intoff = offsetof(HeapTupleHeader72Data, t_bits); char *p = (char *) ht; int i;
Assert(len < off); for (i = 0; i < bitmaplen; ++i) { p[len + i] = p[off + i]; }/*for*/
len += bitmaplen;}/*if*/
/* pad rest with 0 */Assert(len < ht->t_hoff);memset((char *)ht + len, 0, ht->t_hoff - len);
/* change length, if requested */if (compact) { if (oid != 0) { len += sizeof(Oid); }/*if*/
ht->t_hoff = MAXALIGN(len);}/*if*/
/* copy oid (if there is one) */if (oid != 0) { ht->t_infomask |= HEAP_HASOID; HeapTupleHeaderSetOid(ht,
oid);}/*if*/
return ht->t_hoff;
}
#include <storage/bufpage.h>
#include <access/htup.h>
/*
** Convert a pre 7.3 heap page to 7.3 format,
** or leave the page alone, if it is already in 7.3 format.
**
** The page is converted in place.
**
** We should have exclusive access to the page, either per
** LockBufferForCleanup() or because we a running in a standalone
** tool.
*/
void
HeapPage_To73Format(Page page, bool compact)
{PageHeader phdr = (PageHeader)page;int version = PageGetPageLayoutVersion(page);Size size = PageGetPageSize(page);int
maxoff= PageGetMaxOffsetNumber(page);int i;
if (version == PG_PAGE_LAYOUT_VERSION) { /* already converted */ return;}/*if*/
Assert(version == 0);
for (i = 1; i <= maxoff; ++i) { ItemId itid = PageGetItemId(page, i); // ??? if (ItemIdIsUsed(itid)) ...
HeapTupleHeaderht = PageGetItem(page, itid); Size oldsz = ht->t_hoff; Size newsz;
newsz = HeapTupleHeader_To73Format(ht, compact); if (newsz < oldsz) { int diff = oldsz - newsz;
ItemOffsetoff = ItemIdGetOffset(itid); char *addr; int lng; int j;
/* move tuple header to the right */ addr = (char *)ht; memmove(addr + diff, addr, newsz);
itid->lp_off+= diff; itid->lp_len -= diff;
/* ** Move all tuples that lie to the left of our tuple header. ** (Shamelessly copied from
PageIndexTupleDelete()). */ addr = (char *) page + phdr->pd_upper; lng = (int) (off -
phdr->pd_upper); if (lng > 0) memmove(addr + diff, addr, lng);
memset(addr, 0, diff);
/* ** Adjust upper free space boundary pointer, ** lower is not affected. */
phdr->pd_upper+= diff;
/* Adjust linp entries. */ for (j = 1; j <= maxoff; ++j) { ItemId ii = PageGetItemId(page,
j); if (ii->lp_off < off) ii->lp_off += diff; }/*for*/ }/*if*/ else
Assert(newsz== oldsz);}/*for*/
PageSetPageSizeAndVersion(page, size, PG_PAGE_LAYOUT_VERSION);
}
/*
** Convert a pre 7.3 page to 7.3 format,
** or leave the page alone, if it is already in 7.3 format.
**
** The page is converted in place.
**
** We should have exclusive access to the page, either per
** LockBufferForCleanup() or because we a running in a standalone
** tool.
*/
void
Page_To73Format(Page page)
{int version = PageGetPageLayoutVersion(page);Size size = PageGetPageSize(page);
if (version == PG_PAGE_LAYOUT_VERSION) { /* already converted */ return;}/*if*/
Assert(version == 0);if (PageGetSpecialSize(page) == 0) { /* ** Heap page. ** XXX Sure? ** XXX Is there a
betterway to tell? */ HeapPage_To73Format(page, true);}/*if*/else { /* ** Not a heap page: no format
change,just adjust version */ PageSetPageSizeAndVersion(page, size, PG_PAGE_LAYOUT_VERSION);}/*else*/
}
ServusManfred
pgsql-hackers by date: