Redefine the lp_flags field of item pointers as having four states, rather
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 12 Sep 2007 22:10:26 +0000 (22:10 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 12 Sep 2007 22:10:26 +0000 (22:10 +0000)
than two independent bits (one of which was never used in heap pages anyway,
or at least hadn't been in a very long time).  This gives us flexibility to
add the HOT notions of redirected and dead item pointers without requiring
anything so klugy as magic values of lp_off and lp_len.  The state values
are chosen so that for the states currently in use (pre-HOT) there is no
change in the physical representation.

31 files changed:
contrib/pageinspect/btreefuncs.c
contrib/pageinspect/heapfuncs.c
contrib/pgstattuple/pgstattuple.c
src/backend/access/gin/ginentrypage.c
src/backend/access/gin/ginvacuum.c
src/backend/access/gin/ginxlog.c
src/backend/access/gist/gist.c
src/backend/access/gist/gistget.c
src/backend/access/gist/gistutil.c
src/backend/access/gist/gistvacuum.c
src/backend/access/hash/hash.c
src/backend/access/hash/hashinsert.c
src/backend/access/hash/hashovfl.c
src/backend/access/hash/hashpage.c
src/backend/access/heap/heapam.c
src/backend/access/heap/hio.c
src/backend/access/heap/rewriteheap.c
src/backend/access/nbtree/README
src/backend/access/nbtree/nbtinsert.c
src/backend/access/nbtree/nbtpage.c
src/backend/access/nbtree/nbtsort.c
src/backend/access/nbtree/nbtutils.c
src/backend/access/nbtree/nbtxlog.c
src/backend/commands/sequence.c
src/backend/commands/trigger.c
src/backend/commands/vacuum.c
src/backend/commands/vacuumlazy.c
src/backend/executor/nodeBitmapHeapscan.c
src/backend/storage/page/bufpage.c
src/include/storage/bufpage.h
src/include/storage/itemid.h

index e8063d42c62b43868881a263c70f6e70575ce35d..6251fd5b5f918149036f6e8ab05b6c52771e8520 100644 (file)
@@ -140,7 +140,7 @@ GetBTPageStatistics(BlockNumber blkno, Buffer buffer, BTPageStat * stat)
 
                item_size += IndexTupleSize(itup);
 
-               if (!ItemIdDeleted(id))
+               if (!ItemIdIsDead(id))
                        stat->live_items++;
                else
                        stat->dead_items++;
index 600a5242ff7f0721ab93b0c8b507651acafb555c..bf5b53bb6b1b7edd788492e4055125cc83d01f5c 100644 (file)
@@ -156,15 +156,15 @@ heap_page_items(PG_FUNCTION_ARGS)
                 * could be corrupt in many other ways, but at least we won't 
                 * crash.
                 */
-               if ((lp_len >= sizeof(HeapTupleHeader)) &&
-                       (lp_offset == MAXALIGN(lp_offset)) &&
-                       (lp_offset + lp_len <= raw_page_size) &&
-                       ItemIdIsUsed(id))
+               if (ItemIdHasStorage(id) &&
+                       lp_len >= sizeof(HeapTupleHeader) &&
+                       lp_offset == MAXALIGN(lp_offset) &&
+                       lp_offset + lp_len <= raw_page_size)
                {
                        HeapTupleHeader tuphdr;
                        int                             bits_len;
 
-                       /* Extract infromation from the tuple header */
+                       /* Extract information from the tuple header */
 
                        tuphdr = (HeapTupleHeader) PageGetItem(page, id);
                
index 9bb88c0a85631d0ad1e2ad4db901dae9f01621c3..126d0bcdac63e1deb40ca487f187366e80404333 100644 (file)
@@ -477,7 +477,7 @@ pgstat_index_page(pgstattuple_type * stat, Page page,
        {
                ItemId          itemid = PageGetItemId(page, i);
 
-               if (ItemIdDeleted(itemid))
+               if (ItemIdIsDead(itemid))
                {
                        stat->dead_tuple_count++;
                        stat->dead_tuple_len += ItemIdGetLength(itemid);
index d22d26b4ca92d1ec31a568b852e58c2e979ab79d..eff0ae610af74ec909ebc7583097fc5f9f49b43d 100644 (file)
@@ -359,7 +359,7 @@ entryPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prd
        *prdata = rdata;
        data.updateBlkno = entryPreparePage(btree, page, off);
 
-       placed = PageAddItem(page, (Item) btree->entry, IndexTupleSize(btree->entry), off, LP_USED);
+       placed = PageAddItem(page, (Item) btree->entry, IndexTupleSize(btree->entry), off, false);
        if (placed != off)
                elog(ERROR, "failed to add item to index page in \"%s\"",
                         RelationGetRelationName(btree->index));
@@ -488,7 +488,7 @@ entrySplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogR
                        lsize += MAXALIGN(IndexTupleSize(itup)) + sizeof(ItemIdData);
                }
 
-               if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, LP_USED) == InvalidOffsetNumber)
+               if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false) == InvalidOffsetNumber)
                        elog(ERROR, "failed to add item to index page in \"%s\"",
                                 RelationGetRelationName(btree->index));
                ptr += MAXALIGN(IndexTupleSize(itup));
@@ -563,11 +563,11 @@ entryFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf)
        page = BufferGetPage(root);
 
        itup = ginPageGetLinkItup(lbuf);
-       if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, LP_USED) == InvalidOffsetNumber)
+       if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false) == InvalidOffsetNumber)
                elog(ERROR, "failed to add item to index root page");
 
        itup = ginPageGetLinkItup(rbuf);
-       if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, LP_USED) == InvalidOffsetNumber)
+       if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false) == InvalidOffsetNumber)
                elog(ERROR, "failed to add item to index root page");
 }
 
index 02313e659fc02420cf56b90a8ea74550eebc4216..0ae4f17a23008abf2f4911d4fb04f84a4ef87d2a 100644 (file)
@@ -544,7 +544,7 @@ ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint3
                                itup = GinFormTuple(&gvs->ginstate, value, GinGetPosting(itup), newN);
                                PageIndexTupleDelete(tmppage, i);
 
-                               if (PageAddItem(tmppage, (Item) itup, IndexTupleSize(itup), i, LP_USED) != i)
+                               if (PageAddItem(tmppage, (Item) itup, IndexTupleSize(itup), i, false) != i)
                                        elog(ERROR, "failed to add item to index page in \"%s\"",
                                                 RelationGetRelationName(gvs->index));
 
index 811f6d9609a7deff14a7f19f5999b5f0dc51d93a..74d30e4edfce50ce492a2265ca6b6de5a2167e5f 100644 (file)
@@ -199,7 +199,7 @@ ginRedoInsert(XLogRecPtr lsn, XLogRecord *record)
 
                itup = (IndexTuple) (XLogRecGetData(record) + sizeof(ginxlogInsert));
 
-               if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), data->offset, LP_USED) == InvalidOffsetNumber)
+               if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), data->offset, false) == InvalidOffsetNumber)
                        elog(ERROR, "failed to add item to index page in %u/%u/%u",
                                 data->node.spcNode, data->node.dbNode, data->node.relNode);
 
@@ -281,7 +281,7 @@ ginRedoSplit(XLogRecPtr lsn, XLogRecord *record)
 
                for (i = 0; i < data->separator; i++)
                {
-                       if (PageAddItem(lpage, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, LP_USED) == InvalidOffsetNumber)
+                       if (PageAddItem(lpage, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false) == InvalidOffsetNumber)
                                elog(ERROR, "failed to add item to index page in %u/%u/%u",
                                  data->node.spcNode, data->node.dbNode, data->node.relNode);
                        itup = (IndexTuple) (((char *) itup) + MAXALIGN(IndexTupleSize(itup)));
@@ -289,7 +289,7 @@ ginRedoSplit(XLogRecPtr lsn, XLogRecord *record)
 
                for (i = data->separator; i < data->nitem; i++)
                {
-                       if (PageAddItem(rpage, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, LP_USED) == InvalidOffsetNumber)
+                       if (PageAddItem(rpage, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false) == InvalidOffsetNumber)
                                elog(ERROR, "failed to add item to index page in %u/%u/%u",
                                  data->node.spcNode, data->node.dbNode, data->node.relNode);
                        itup = (IndexTuple) (((char *) itup) + MAXALIGN(IndexTupleSize(itup)));
@@ -375,7 +375,7 @@ ginRedoVacuumPage(XLogRecPtr lsn, XLogRecord *record)
 
                for (i = 0; i < data->nitem; i++)
                {
-                       if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, LP_USED) == InvalidOffsetNumber)
+                       if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false) == InvalidOffsetNumber)
                                elog(ERROR, "failed to add item to index page in %u/%u/%u",
                                  data->node.spcNode, data->node.dbNode, data->node.relNode);
                        itup = (IndexTuple) (((char *) itup) + MAXALIGN(IndexTupleSize(itup)));
index 8c1015ae1bd8f06c424f104e6ed4fa093e3d417f..68af1d57da3112df7f177fa48c8b4de9bbd04f5b 100644 (file)
@@ -366,7 +366,7 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
                        data = (char *) (ptr->list);
                        for (i = 0; i < ptr->block.num; i++)
                        {
-                               if (PageAddItem(ptr->page, (Item) data, IndexTupleSize((IndexTuple) data), i + FirstOffsetNumber, LP_USED) == InvalidOffsetNumber)
+                               if (PageAddItem(ptr->page, (Item) data, IndexTupleSize((IndexTuple) data), i + FirstOffsetNumber, false) == InvalidOffsetNumber)
                                        elog(ERROR, "failed to add item to index page in \"%s\"", RelationGetRelationName(state->r));
                                data += IndexTupleSize((IndexTuple) data);
                        }
index f513c8dd16d992831048a0a52cef6777e7125bf0..ccd1425da81641fd3bfe2e273b86185e2fd14bd7 100644 (file)
@@ -46,7 +46,7 @@ killtuple(Relation r, GISTScanOpaque so, ItemPointer iptr)
                {
                        /* page unchanged, so all is simple */
                        offset = ItemPointerGetOffsetNumber(iptr);
-                       PageGetItemId(p, offset)->lp_flags |= LP_DELETE;
+                       ItemIdMarkDead(PageGetItemId(p, offset));
                        SetBufferCommitInfoNeedsSave(buffer);
                        LockBuffer(buffer, GIST_UNLOCK);
                        break;
@@ -61,7 +61,7 @@ killtuple(Relation r, GISTScanOpaque so, ItemPointer iptr)
                        if (ItemPointerEquals(&(ituple->t_tid), iptr))
                        {
                                /* found */
-                               PageGetItemId(p, offset)->lp_flags |= LP_DELETE;
+                               ItemIdMarkDead(PageGetItemId(p, offset));
                                SetBufferCommitInfoNeedsSave(buffer);
                                LockBuffer(buffer, GIST_UNLOCK);
                                if (buffer != so->curbuf)
@@ -289,7 +289,7 @@ gistnext(IndexScanDesc scan, ScanDirection dir, ItemPointer tids,
                                ItemPointerSet(&(so->curpos),
                                                           BufferGetBlockNumber(so->curbuf), n);
 
-                               if (!(ignore_killed_tuples && ItemIdDeleted(PageGetItemId(p, n))))
+                               if (!(ignore_killed_tuples && ItemIdIsDead(PageGetItemId(p, n))))
                                {
                                        it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
                                        tids[ntids] = scan->xs_ctup.t_self = it->t_tid;
index e658d059280de5060d075e1afa527cb1f3027031..1ddf0e97db4596b89243477937b7c9a6c616aa1f 100644 (file)
@@ -42,7 +42,7 @@ gistfillbuffer(Relation r, Page page, IndexTuple *itup,
        for (i = 0; i < len; i++)
        {
                l = PageAddItem(page, (Item) itup[i], IndexTupleSize(itup[i]),
-                                               off, LP_USED);
+                                               off, false);
                if (l == InvalidOffsetNumber)
                        elog(ERROR, "failed to add item to index page in \"%s\"",
                                 RelationGetRelationName(r));
index eaa28a08b5565f6018e8ca49fe86171cdc47699e..7bba2dbd63511ffeb0a55c5ac8f9572ad2d7f73f 100644 (file)
@@ -201,7 +201,7 @@ vacuumSplitPage(GistVacuum *gv, Page tempPage, Buffer buffer, IndexTuple *addon,
                data = (char *) (ptr->list);
                for (i = 0; i < ptr->block.num; i++)
                {
-                       if (PageAddItem(ptr->page, (Item) data, IndexTupleSize((IndexTuple) data), i + FirstOffsetNumber, LP_USED) == InvalidOffsetNumber)
+                       if (PageAddItem(ptr->page, (Item) data, IndexTupleSize((IndexTuple) data), i + FirstOffsetNumber, false) == InvalidOffsetNumber)
                                elog(ERROR, "failed to add item to index page in \"%s\"", RelationGetRelationName(gv->index));
                        data += IndexTupleSize((IndexTuple) data);
                }
index 3fe309720140a76e3ec9f82464fead11b1413e3a..dc5715a799509b2d2970fe9553e0ba750b1efd6a 100644 (file)
@@ -193,11 +193,11 @@ hashgettuple(PG_FUNCTION_ARGS)
                if (scan->kill_prior_tuple)
                {
                        /*
-                        * Yes, so mark it by setting the LP_DELETE bit in the item flags.
+                        * Yes, so mark it by setting the LP_DEAD state in the item flags.
                         */
                        offnum = ItemPointerGetOffsetNumber(&(so->hashso_curpos));
                        page = BufferGetPage(so->hashso_curbuf);
-                       PageGetItemId(page, offnum)->lp_flags |= LP_DELETE;
+                       ItemIdMarkDead(PageGetItemId(page, offnum));
 
                        /*
                         * Since this can be redone later if needed, it's treated the same
@@ -224,7 +224,7 @@ hashgettuple(PG_FUNCTION_ARGS)
                {
                        offnum = ItemPointerGetOffsetNumber(&(so->hashso_curpos));
                        page = BufferGetPage(so->hashso_curbuf);
-                       if (!ItemIdDeleted(PageGetItemId(page, offnum)))
+                       if (!ItemIdIsDead(PageGetItemId(page, offnum)))
                                break;
                        res = _hash_next(scan, dir);
                }
@@ -286,7 +286,7 @@ hashgetmulti(PG_FUNCTION_ARGS)
 
                                offnum = ItemPointerGetOffsetNumber(&(so->hashso_curpos));
                                page = BufferGetPage(so->hashso_curbuf);
-                               if (!ItemIdDeleted(PageGetItemId(page, offnum)))
+                               if (!ItemIdIsDead(PageGetItemId(page, offnum)))
                                        break;
                                res = _hash_next(scan, ForwardScanDirection);
                        }
index 10d91c2844a629d88f2f0eab2a6ace2514fde782..7d4d55f1615edad940b5e50b48d5d27a882df51f 100644 (file)
@@ -200,7 +200,7 @@ _hash_pgaddtup(Relation rel,
        page = BufferGetPage(buf);
 
        itup_off = OffsetNumberNext(PageGetMaxOffsetNumber(page));
-       if (PageAddItem(page, (Item) itup, itemsize, itup_off, LP_USED)
+       if (PageAddItem(page, (Item) itup, itemsize, itup_off, false)
                == InvalidOffsetNumber)
                elog(ERROR, "failed to add index item to \"%s\"",
                         RelationGetRelationName(rel));
index 70e705e1103a3013ab1023cb0c130ef67c638d5d..b9ad162b25b30825190d3f2b76460b9ee2e9f48b 100644 (file)
@@ -684,7 +684,7 @@ _hash_squeezebucket(Relation rel,
                         * we have found room so insert on the "write" page.
                         */
                        woffnum = OffsetNumberNext(PageGetMaxOffsetNumber(wpage));
-                       if (PageAddItem(wpage, (Item) itup, itemsz, woffnum, LP_USED)
+                       if (PageAddItem(wpage, (Item) itup, itemsz, woffnum, false)
                                == InvalidOffsetNumber)
                                elog(ERROR, "failed to add index item to \"%s\"",
                                         RelationGetRelationName(rel));
index 70d46f5d3e35e261f4b17e6ee1c1e9afffe07522..b694e8800c3cc156e8770db69cd79470b1141994 100644 (file)
@@ -830,7 +830,7 @@ _hash_splitbucket(Relation rel,
                        }
 
                        noffnum = OffsetNumberNext(PageGetMaxOffsetNumber(npage));
-                       if (PageAddItem(npage, (Item) itup, itemsz, noffnum, LP_USED)
+                       if (PageAddItem(npage, (Item) itup, itemsz, noffnum, false)
                                == InvalidOffsetNumber)
                                elog(ERROR, "failed to add index item to \"%s\"",
                                         RelationGetRelationName(rel));
index d77e64cd8b34af5568ad4e701a3bb6b7bbcccc76..9f1a7d63848d0c86399b2477bf1ea4faf87b1ce9 100644 (file)
@@ -198,7 +198,7 @@ heapgetpage(HeapScanDesc scan, BlockNumber page)
                 lineoff <= lines;
                 lineoff++, lpp++)
        {
-               if (ItemIdIsUsed(lpp))
+               if (ItemIdIsNormal(lpp))
                {
                        HeapTupleData loctup;
                        bool            valid;
@@ -384,7 +384,7 @@ heapgettup(HeapScanDesc scan,
        {
                while (linesleft > 0)
                {
-                       if (ItemIdIsUsed(lpp))
+                       if (ItemIdIsNormal(lpp))
                        {
                                bool            valid;
 
@@ -653,7 +653,7 @@ heapgettup_pagemode(HeapScanDesc scan,
                {
                        lineoff = scan->rs_vistuples[lineindex];
                        lpp = PageGetItemId(dp, lineoff);
-                       Assert(ItemIdIsUsed(lpp));
+                       Assert(ItemIdIsNormal(lpp));
 
                        tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp);
                        tuple->t_len = ItemIdGetLength(lpp);
@@ -1334,7 +1334,7 @@ heap_release_fetch(Relation relation,
        /*
         * Must check for deleted tuple.
         */
-       if (!ItemIdIsUsed(lp))
+       if (!ItemIdIsNormal(lp))
        {
                LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
                if (keep_buf)
@@ -1463,7 +1463,7 @@ heap_get_latest_tid(Relation relation,
                        break;
                }
                lp = PageGetItemId(dp, offnum);
-               if (!ItemIdIsUsed(lp))
+               if (!ItemIdIsNormal(lp))
                {
                        UnlockReleaseBuffer(buffer);
                        break;
@@ -1775,6 +1775,7 @@ heap_delete(Relation relation, ItemPointer tid,
 
        dp = (PageHeader) BufferGetPage(buffer);
        lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid));
+       Assert(ItemIdIsNormal(lp));
 
        tp.t_data = (HeapTupleHeader) PageGetItem(dp, lp);
        tp.t_len = ItemIdGetLength(lp);
@@ -2079,6 +2080,7 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
 
        dp = (PageHeader) BufferGetPage(buffer);
        lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(otid));
+       Assert(ItemIdIsNormal(lp));
 
        oldtup.t_data = (HeapTupleHeader) PageGetItem(dp, lp);
        oldtup.t_len = ItemIdGetLength(lp);
@@ -2565,7 +2567,7 @@ heap_lock_tuple(Relation relation, HeapTuple tuple, Buffer *buffer,
 
        dp = (PageHeader) BufferGetPage(*buffer);
        lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid));
-       Assert(ItemIdIsUsed(lp));
+       Assert(ItemIdIsNormal(lp));
 
        tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
        tuple->t_len = ItemIdGetLength(lp);
@@ -2958,7 +2960,7 @@ heap_inplace_update(Relation relation, HeapTuple tuple)
        if (PageGetMaxOffsetNumber(page) >= offnum)
                lp = PageGetItemId(page, offnum);
 
-       if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsUsed(lp))
+       if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsNormal(lp))
                elog(ERROR, "heap_inplace_update: invalid lp");
 
        htup = (HeapTupleHeader) PageGetItem(page, lp);
@@ -3523,7 +3525,7 @@ heap_xlog_clean(XLogRecPtr lsn, XLogRecord *record)
                {
                        /* unused[] entries are zero-based */
                        lp = PageGetItemId(page, *unused + 1);
-                       lp->lp_flags &= ~LP_USED;
+                       ItemIdSetUnused(lp);
                        unused++;
                }
        }
@@ -3643,7 +3645,7 @@ heap_xlog_delete(XLogRecPtr lsn, XLogRecord *record)
        if (PageGetMaxOffsetNumber(page) >= offnum)
                lp = PageGetItemId(page, offnum);
 
-       if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsUsed(lp))
+       if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsNormal(lp))
                elog(PANIC, "heap_delete_redo: invalid lp");
 
        htup = (HeapTupleHeader) PageGetItem(page, lp);
@@ -3734,8 +3736,7 @@ heap_xlog_insert(XLogRecPtr lsn, XLogRecord *record)
        HeapTupleHeaderSetCmin(htup, FirstCommandId);
        htup->t_ctid = xlrec->target.tid;
 
-       offnum = PageAddItem(page, (Item) htup, newlen, offnum,
-                                                LP_USED | OverwritePageMode);
+       offnum = PageAddItem(page, (Item) htup, newlen, offnum, true);
        if (offnum == InvalidOffsetNumber)
                elog(PANIC, "heap_insert_redo: failed to add tuple");
        PageSetLSN(page, lsn);
@@ -3796,7 +3797,7 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool move)
        if (PageGetMaxOffsetNumber(page) >= offnum)
                lp = PageGetItemId(page, offnum);
 
-       if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsUsed(lp))
+       if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsNormal(lp))
                elog(PANIC, "heap_update_redo: invalid lp");
 
        htup = (HeapTupleHeader) PageGetItem(page, lp);
@@ -3913,8 +3914,7 @@ newsame:;
        /* Make sure there is no forward chain link in t_ctid */
        htup->t_ctid = xlrec->newtid;
 
-       offnum = PageAddItem(page, (Item) htup, newlen, offnum,
-                                                LP_USED | OverwritePageMode);
+       offnum = PageAddItem(page, (Item) htup, newlen, offnum, true);
        if (offnum == InvalidOffsetNumber)
                elog(PANIC, "heap_update_redo: failed to add tuple");
        PageSetLSN(page, lsn);
@@ -3955,7 +3955,7 @@ heap_xlog_lock(XLogRecPtr lsn, XLogRecord *record)
        if (PageGetMaxOffsetNumber(page) >= offnum)
                lp = PageGetItemId(page, offnum);
 
-       if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsUsed(lp))
+       if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsNormal(lp))
                elog(PANIC, "heap_lock_redo: invalid lp");
 
        htup = (HeapTupleHeader) PageGetItem(page, lp);
@@ -4014,7 +4014,7 @@ heap_xlog_inplace(XLogRecPtr lsn, XLogRecord *record)
        if (PageGetMaxOffsetNumber(page) >= offnum)
                lp = PageGetItemId(page, offnum);
 
-       if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsUsed(lp))
+       if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsNormal(lp))
                elog(PANIC, "heap_inplace_redo: invalid lp");
 
        htup = (HeapTupleHeader) PageGetItem(page, lp);
index c8eedefbdc6a540ac94490114c44be64292b8b74..fa8a2afbba49834b552fba75d6e434cea28234ff 100644 (file)
@@ -41,7 +41,7 @@ RelationPutHeapTuple(Relation relation,
        pageHeader = BufferGetPage(buffer);
 
        offnum = PageAddItem(pageHeader, (Item) tuple->t_data,
-                                                tuple->t_len, InvalidOffsetNumber, LP_USED);
+                                                tuple->t_len, InvalidOffsetNumber, false);
 
        if (offnum == InvalidOffsetNumber)
                elog(PANIC, "failed to add tuple to page");
index 314f01ed75e63ba42090231a5994a980ab1374f8..e4578ea3aa29c9ee873ceb522c08b6a1b6231d2e 100644 (file)
@@ -628,7 +628,7 @@ raw_heap_insert(RewriteState state, HeapTuple tup)
 
        /* And now we can insert the tuple into the page */
        newoff = PageAddItem(page, (Item) heaptup->t_data, len,
-                                                InvalidOffsetNumber, LP_USED);
+                                                InvalidOffsetNumber, false);
        if (newoff == InvalidOffsetNumber)
                elog(ERROR, "failed to add tuple");
 
index 412abed2e6ffdc31ca27009f917c49613b06bb69..f9bd756394075a402b13e9d977c961e8bcf9a97f 100644 (file)
@@ -327,17 +327,17 @@ If a process visits a heap tuple and finds that it's dead and removable
 (ie, dead to all open transactions, not only that process), then we can
 return to the index and mark the corresponding index entry "known dead",
 allowing subsequent index scans to skip visiting the heap tuple.  The
-"known dead" marking uses the LP_DELETE bit in ItemIds.  This is currently
-only done in plain indexscans, not bitmap scans, because only plain scans
-visit the heap and index "in sync" and so there's not a convenient way
-to do it for bitmap scans.
+"known dead" marking works by setting the index item's lp_flags state
+to LP_DEAD.  This is currently only done in plain indexscans, not bitmap
+scans, because only plain scans visit the heap and index "in sync" and so
+there's not a convenient way to do it for bitmap scans.
 
-Once an index tuple has been marked LP_DELETE it can actually be removed
+Once an index tuple has been marked LP_DEAD it can actually be removed
 from the index immediately; since index scans only stop "between" pages,
 no scan can lose its place from such a deletion.  We separate the steps
-because we allow LP_DELETE to be set with only a share lock (it's exactly
+because we allow LP_DEAD to be set with only a share lock (it's exactly
 like a hint bit for a heap tuple), but physically removing tuples requires
-exclusive lock.  In the current code we try to remove LP_DELETE tuples when
+exclusive lock.  In the current code we try to remove LP_DEAD tuples when
 we are otherwise faced with having to split a page to do an insertion (and
 hence have exclusive lock on it already).
 
@@ -349,7 +349,7 @@ same situation is created by REINDEX, since it doesn't enter dead
 tuples into the index.)
 
 It's sufficient to have an exclusive lock on the index page, not a
-super-exclusive lock, to do deletion of LP_DELETE items.  It might seem
+super-exclusive lock, to do deletion of LP_DEAD items.  It might seem
 that this breaks the interlock between VACUUM and indexscans, but that is
 not so: as long as an indexscanning process has a pin on the page where
 the index item used to be, VACUUM cannot complete its btbulkdelete scan
index a8ebe688a2140abe2a53953f4fffe4caa6775c62..8f8f7b63b4926841558931bd72da388b71903b3d 100644 (file)
@@ -221,7 +221,7 @@ _bt_check_unique(Relation rel, IndexTuple itup, Relation heapRel,
                         * we can. We only apply _bt_isequal() when we get to a non-killed
                         * item or the end of the page.
                         */
-                       if (!ItemIdDeleted(curitemid))
+                       if (!ItemIdIsDead(curitemid))
                        {
                                /*
                                 * _bt_compare returns 0 for (1,NULL) and (1,NULL) - this's
@@ -301,7 +301,7 @@ _bt_check_unique(Relation rel, IndexTuple itup, Relation heapRel,
                                        if (HeapTupleSatisfiesVacuum(htup.t_data, RecentGlobalXmin,
                                                                                                 hbuffer) == HEAPTUPLE_DEAD)
                                        {
-                                               curitemid->lp_flags |= LP_DELETE;
+                                               ItemIdMarkDead(curitemid);
                                                opaque->btpo_flags |= BTP_HAS_GARBAGE;
                                                /* be sure to mark the proper buffer dirty... */
                                                if (nbuf != InvalidBuffer)
@@ -368,7 +368,7 @@ _bt_check_unique(Relation rel, IndexTuple itup, Relation heapRel,
  *             any existing equal keys because of the way _bt_binsrch() works.
  *
  *             If there's not enough room in the space, we try to make room by
- *             removing any LP_DELETEd tuples.
+ *             removing any LP_DEAD tuples.
  *
  *             On entry, *buf and *offsetptr point to the first legal position
  *             where the new tuple could be inserted. The caller should hold an
@@ -449,7 +449,7 @@ _bt_findinsertloc(Relation rel,
 
                /*
                 * before considering moving right, see if we can obtain enough
-                * space by erasing LP_DELETE items
+                * space by erasing LP_DEAD items
                 */
                if (P_ISLEAF(lpageop) && P_HAS_GARBAGE(lpageop))
                {
@@ -840,7 +840,7 @@ _bt_split(Relation rel, Buffer buf, OffsetNumber firstright,
                itemsz = ItemIdGetLength(itemid);
                item = (IndexTuple) PageGetItem(origpage, itemid);
                if (PageAddItem(rightpage, (Item) item, itemsz, rightoff,
-                                               LP_USED) == InvalidOffsetNumber)
+                                               false) == InvalidOffsetNumber)
                        elog(PANIC, "failed to add hikey to the right sibling");
                rightoff = OffsetNumberNext(rightoff);
        }
@@ -865,7 +865,7 @@ _bt_split(Relation rel, Buffer buf, OffsetNumber firstright,
                item = (IndexTuple) PageGetItem(origpage, itemid);
        }
        if (PageAddItem(leftpage, (Item) item, itemsz, leftoff,
-                                       LP_USED) == InvalidOffsetNumber)
+                                       false) == InvalidOffsetNumber)
                elog(PANIC, "failed to add hikey to the left sibling");
        leftoff = OffsetNumberNext(leftoff);
 
@@ -1699,7 +1699,8 @@ _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf)
         * Note: we *must* insert the two items in item-number order, for the
         * benefit of _bt_restore_page().
         */
-       if (PageAddItem(rootpage, (Item) new_item, itemsz, P_HIKEY, LP_USED) == InvalidOffsetNumber)
+       if (PageAddItem(rootpage, (Item) new_item, itemsz, P_HIKEY,
+                                       false) == InvalidOffsetNumber)
                elog(PANIC, "failed to add leftkey to new root page");
        pfree(new_item);
 
@@ -1716,7 +1717,8 @@ _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf)
        /*
         * insert the right page pointer into the new root page.
         */
-       if (PageAddItem(rootpage, (Item) new_item, itemsz, P_FIRSTKEY, LP_USED) == InvalidOffsetNumber)
+       if (PageAddItem(rootpage, (Item) new_item, itemsz, P_FIRSTKEY,
+                                       false) == InvalidOffsetNumber)
                elog(PANIC, "failed to add rightkey to new root page");
        pfree(new_item);
 
@@ -1803,7 +1805,7 @@ _bt_pgaddtup(Relation rel,
        }
 
        if (PageAddItem(page, (Item) itup, itemsize, itup_off,
-                                       LP_USED) == InvalidOffsetNumber)
+                                       false) == InvalidOffsetNumber)
                elog(PANIC, "failed to add item to the %s for \"%s\"",
                         where, RelationGetRelationName(rel));
 }
@@ -1858,7 +1860,7 @@ _bt_isequal(TupleDesc itupdesc, Page page, OffsetNumber offnum,
 /*
  * _bt_vacuum_one_page - vacuum just one index page.
  *
- * Try to remove LP_DELETE items from the given page.  The passed buffer
+ * Try to remove LP_DEAD items from the given page.  The passed buffer
  * must be exclusive-locked, but unlike a real VACUUM, we don't need a
  * super-exclusive "cleanup" lock (see nbtree/README).
  */
@@ -1875,7 +1877,7 @@ _bt_vacuum_one_page(Relation rel, Buffer buffer)
 
        /*
         * Scan over all items to see which ones need to be deleted
-        * according to LP_DELETE flags.
+        * according to LP_DEAD flags.
         */
        minoff = P_FIRSTDATAKEY(opaque);
        maxoff = PageGetMaxOffsetNumber(page);
@@ -1885,7 +1887,7 @@ _bt_vacuum_one_page(Relation rel, Buffer buffer)
        {
                ItemId          itemId = PageGetItemId(page, offnum);
 
-               if (ItemIdDeleted(itemId))
+               if (ItemIdIsDead(itemId))
                        deletable[ndeletable++] = offnum;
        }
 
@@ -1893,7 +1895,7 @@ _bt_vacuum_one_page(Relation rel, Buffer buffer)
                _bt_delitems(rel, buffer, deletable, ndeletable);
 
        /*
-        * Note: if we didn't find any LP_DELETE items, then the page's
+        * Note: if we didn't find any LP_DEAD items, then the page's
         * BTP_HAS_GARBAGE hint bit is falsely set.  We do not bother expending a
         * separate write to clear it, however.  We will clear it when we split
         * the page.
index 0821a13ff08dfc4c768dfbaeeab0a153f8ed48d1..2c7a834adc97d2f44197736a62d74969b50cac81 100644 (file)
@@ -669,7 +669,7 @@ _bt_delitems(Relation rel, Buffer buf,
        opaque->btpo_cycleid = 0;
 
        /*
-        * Mark the page as not containing any LP_DELETE items.  This is not
+        * Mark the page as not containing any LP_DEAD items.  This is not
         * certainly true (there might be some that have recently been marked, but
         * weren't included in our target-item list), but it will almost always be
         * true and it doesn't seem worth an additional page scan to check it.
index 87e6da59ef3ee5ede63a639807cf7425de704091..bacf52d48ba8accd6787397160c162e9328576eb 100644 (file)
@@ -400,7 +400,7 @@ _bt_sortaddtup(Page page,
        }
 
        if (PageAddItem(page, (Item) itup, itemsize, itup_off,
-                                       LP_USED) == InvalidOffsetNumber)
+                                       false) == InvalidOffsetNumber)
                elog(ERROR, "failed to add item to the index page");
 }
 
@@ -521,7 +521,7 @@ _bt_buildadd(BTWriteState *wstate, BTPageState *state, IndexTuple itup)
                 */
                hii = PageGetItemId(opage, P_HIKEY);
                *hii = *ii;
-               ii->lp_flags &= ~LP_USED;
+               ItemIdSetUnused(ii);    /* redundant */
                ((PageHeader) opage)->pd_lower -= sizeof(ItemIdData);
 
                /*
index d6c1ee501c3299cdd91ea001c242f9ded4778c7c..a0e115d533aa13ce0a4c3fba1ebb21ed6f6bd13d 100644 (file)
@@ -789,7 +789,7 @@ _bt_checkkeys(IndexScanDesc scan,
         * However, if this is the last tuple on the page, we should check the
         * index keys to prevent uselessly advancing to the next page.
         */
-       if (scan->ignore_killed_tuples && ItemIdDeleted(iid))
+       if (scan->ignore_killed_tuples && ItemIdIsDead(iid))
        {
                /* return immediately if there are more tuples on the page */
                if (ScanDirectionIsForward(dir))
@@ -1088,7 +1088,7 @@ _bt_check_rowcompare(ScanKey skey, IndexTuple tuple, TupleDesc tupdesc,
 }
 
 /*
- * _bt_killitems - set LP_DELETE bit for items an indexscan caller has
+ * _bt_killitems - set LP_DEAD state for items an indexscan caller has
  * told us were killed
  *
  * scan->so contains information about the current page and killed tuples
@@ -1096,7 +1096,7 @@ _bt_check_rowcompare(ScanKey skey, IndexTuple tuple, TupleDesc tupdesc,
  *
  * The caller must have pin on so->currPos.buf, but may or may not have
  * read-lock, as indicated by haveLock.  Note that we assume read-lock
- * is sufficient for setting LP_DELETE hint bits.
+ * is sufficient for setting LP_DEAD status (which is only a hint).
  *
  * We match items by heap TID before assuming they are the right ones to
  * delete.     We cope with cases where items have moved right due to insertions.
@@ -1149,7 +1149,7 @@ _bt_killitems(IndexScanDesc scan, bool haveLock)
                        if (ItemPointerEquals(&ituple->t_tid, &kitem->heapTid))
                        {
                                /* found the item */
-                               iid->lp_flags |= LP_DELETE;
+                               ItemIdMarkDead(iid);
                                killedsomething = true;
                                break;                  /* out of inner search loop */
                        }
@@ -1162,7 +1162,7 @@ _bt_killitems(IndexScanDesc scan, bool haveLock)
         * commit-hint-bit status update for heap tuples: we mark the buffer dirty
         * but don't make a WAL log entry.
         *
-        * Whenever we mark anything LP_DELETEd, we also set the page's
+        * Whenever we mark anything LP_DEAD, we also set the page's
         * BTP_HAS_GARBAGE flag, which is likewise just a hint.
         */
        if (killedsomething)
index 0c09ee8d44d2c901f6e542f6a2356343c1d6d101..ab0c37caa66405f12ecc8ac35d21f7ea113d06c8 100644 (file)
@@ -142,7 +142,7 @@ _bt_restore_page(Page page, char *from, int len)
                itemsz = IndexTupleDSize(itupdata);
                itemsz = MAXALIGN(itemsz);
                if (PageAddItem(page, (Item) from, itemsz,
-                                               FirstOffsetNumber, LP_USED) == InvalidOffsetNumber)
+                                               FirstOffsetNumber, false) == InvalidOffsetNumber)
                        elog(PANIC, "_bt_restore_page: cannot add item to page");
                from += itemsz;
        }
@@ -238,7 +238,7 @@ btree_xlog_insert(bool isleaf, bool ismeta,
                        {
                                if (PageAddItem(page, (Item) datapos, datalen,
                                                        ItemPointerGetOffsetNumber(&(xlrec->target.tid)),
-                                                               LP_USED) == InvalidOffsetNumber)
+                                                               false) == InvalidOffsetNumber)
                                        elog(PANIC, "btree_insert_redo: failed to add item");
 
                                PageSetLSN(page, lsn);
@@ -389,7 +389,7 @@ btree_xlog_split(bool onleft, bool isroot,
                                if (onleft)
                                {
                                        if (PageAddItem(lpage, newitem, newitemsz, newitemoff,
-                                                                       LP_USED) == InvalidOffsetNumber)
+                                                                       false) == InvalidOffsetNumber)
                                                elog(PANIC, "failed to add new item to left page after split");
                                }
 
@@ -398,7 +398,7 @@ btree_xlog_split(bool onleft, bool isroot,
                                hiItem = PageGetItem(rpage, hiItemId);
 
                                if (PageAddItem(lpage, hiItem, ItemIdGetLength(hiItemId),
-                                                               P_HIKEY, LP_USED) == InvalidOffsetNumber)
+                                                               P_HIKEY, false) == InvalidOffsetNumber)
                                        elog(PANIC, "failed to add high key to left page after split");
 
                                /* Fix opaque fields */
@@ -483,7 +483,7 @@ btree_xlog_delete(XLogRecPtr lsn, XLogRecord *record)
        }
 
        /*
-        * Mark the page as not containing any LP_DELETE items --- see comments in
+        * Mark the page as not containing any LP_DEAD items --- see comments in
         * _bt_delitems().
         */
        opaque = (BTPageOpaque) PageGetSpecialPointer(page);
index 662b12135a87406f00b51221c449cbcc61e305e1..bdee553bcae0524182e03a50335d37f850844b51 100644 (file)
@@ -936,7 +936,7 @@ read_info(SeqTable elm, Relation rel, Buffer *buf)
                         RelationGetRelationName(rel), sm->magic);
 
        lp = PageGetItemId(page, FirstOffsetNumber);
-       Assert(ItemIdIsUsed(lp));
+       Assert(ItemIdIsNormal(lp));
        tuple.t_data = (HeapTupleHeader) PageGetItem((Page) page, lp);
 
        seq = (Form_pg_sequence) GETSTRUCT(&tuple);
@@ -1281,7 +1281,7 @@ seq_redo(XLogRecPtr lsn, XLogRecord *record)
        itemsz = record->xl_len - sizeof(xl_seq_rec);
        itemsz = MAXALIGN(itemsz);
        if (PageAddItem(page, (Item) item, itemsz,
-                                       FirstOffsetNumber, LP_USED) == InvalidOffsetNumber)
+                                       FirstOffsetNumber, false) == InvalidOffsetNumber)
                elog(PANIC, "seq_redo: failed to add item to page");
 
        PageSetLSN(page, lsn);
index 1551ee2eb4b8568c8014e954f213000e7258b00a..9e517dfaa0deefcbd00e54e2725166bfd6686823 100644 (file)
@@ -1826,7 +1826,7 @@ ltrmark:;
                dp = (PageHeader) BufferGetPage(buffer);
                lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid));
 
-               Assert(ItemIdIsUsed(lp));
+               Assert(ItemIdIsNormal(lp));
 
                tuple.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
                tuple.t_len = ItemIdGetLength(lp);
index ac60c110b8bb7e50efa15f11274e9762e08dbee2..81083ea604db0a00bdd3a61992703f8e808ba28d 100644 (file)
@@ -1522,7 +1522,7 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
 
                                /* mark it unused on the temp page */
                                lpp = PageGetItemId(tempPage, offnum);
-                               lpp->lp_flags &= ~LP_USED;
+                               ItemIdSetUnused(lpp);
 
                                vacpage->offsets[vacpage->offsets_free++] = offnum;
                                tups_vacuumed += 1;
@@ -1558,7 +1558,7 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
                {
                        /* Just use current available space */
                        vacpage->free = PageGetFreeSpaceWithFillFactor(onerel, page);
-                       /* Need to reap the page if it has ~LP_USED line pointers */
+                       /* Need to reap the page if it has LP_UNUSED line pointers */
                        do_reap = (vacpage->offsets_free > 0);
                }
 
@@ -2582,7 +2582,7 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
                                if (HeapTupleHeaderGetXvac(htup) != myXID)
                                        elog(ERROR, "invalid XVAC in tuple header");
 
-                               itemid->lp_flags &= ~LP_USED;
+                               ItemIdSetUnused(itemid);
                                num_tuples++;
                        }
                        Assert(vacpage->offsets_free == num_tuples);
@@ -2714,7 +2714,7 @@ move_chain_tuple(Relation rel,
        newtup.t_data->t_infomask |= HEAP_MOVED_IN;
        HeapTupleHeaderSetXvac(newtup.t_data, myXID);
        newoff = PageAddItem(dst_page, (Item) newtup.t_data, tuple_len,
-                                                InvalidOffsetNumber, LP_USED);
+                                                InvalidOffsetNumber, false);
        if (newoff == InvalidOffsetNumber)
                elog(PANIC, "failed to add item with len = %lu to page %u while moving tuple chain",
                         (unsigned long) tuple_len, dst_vacpage->blkno);
@@ -2819,7 +2819,7 @@ move_plain_tuple(Relation rel,
 
        /* add tuple to the page */
        newoff = PageAddItem(dst_page, (Item) newtup.t_data, tuple_len,
-                                                InvalidOffsetNumber, LP_USED);
+                                                InvalidOffsetNumber, false);
        if (newoff == InvalidOffsetNumber)
                elog(PANIC, "failed to add item with len = %lu to page %u (free space %lu, nusd %u, noff %u)",
                         (unsigned long) tuple_len,
@@ -3033,7 +3033,7 @@ vacuum_page(Relation onerel, Buffer buffer, VacPage vacpage)
        for (i = 0; i < vacpage->offsets_free; i++)
        {
                itemid = PageGetItemId(page, vacpage->offsets[i]);
-               itemid->lp_flags &= ~LP_USED;
+               ItemIdSetUnused(itemid);
        }
 
        uncnt = PageRepairFragmentation(page, unused);
index 22d7fea211d16bb4e5433e0bd30b277770440042..2911856a3dafe51a3634eb78da77d1c43fafbbaf 100644 (file)
@@ -642,7 +642,7 @@ lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer,
                        break;                          /* past end of tuples for this block */
                toff = ItemPointerGetOffsetNumber(&vacrelstats->dead_tuples[tupindex]);
                itemid = PageGetItemId(page, toff);
-               itemid->lp_flags &= ~LP_USED;
+               ItemIdSetUnused(itemid);
        }
 
        uncnt = PageRepairFragmentation(page, unused);
index 6c42fd3b3204b44c56c35c40d13cc9e2e348eac8..c830e82f147dc2583e4b54d50e6b525fc8f1e1d9 100644 (file)
@@ -183,7 +183,7 @@ BitmapHeapNext(BitmapHeapScanState *node)
                targoffset = scan->rs_vistuples[scan->rs_cindex];
                dp = (Page) BufferGetPage(scan->rs_cbuf);
                lp = PageGetItemId(dp, targoffset);
-               Assert(ItemIdIsUsed(lp));
+               Assert(ItemIdIsNormal(lp));
 
                scan->rs_ctup.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
                scan->rs_ctup.t_len = ItemIdGetLength(lp);
@@ -317,7 +317,7 @@ bitgetpage(HeapScanDesc scan, TBMIterateResult *tbmres)
                /*
                 * Must check for deleted tuple.
                 */
-               if (!ItemIdIsUsed(lp))
+               if (!ItemIdIsNormal(lp))
                        continue;
 
                /*
index b63a19182957054863e512e999bc790ac1188b24..b90ee8fd93bf979e4ca1b4f9b82783af292a6880 100644 (file)
@@ -99,7 +99,10 @@ PageHeaderIsValid(PageHeader page)
  *     Add an item to a page.  Return value is offset at which it was
  *     inserted, or InvalidOffsetNumber if there's not room to insert.
  *
- *     If offsetNumber is valid and <= current max offset in the page,
+ *     If overwrite is true, we just store the item at the specified
+ *     offsetNumber (which must be either a currently-unused item pointer,
+ *     or one past the last existing item).  Otherwise,
+ *     if offsetNumber is valid and <= current max offset in the page,
  *     insert item into the array at that position by shuffling ItemId's
  *     down to make room.
  *     If offsetNumber is not valid, then assign one by finding the first
@@ -112,7 +115,7 @@ PageAddItem(Page page,
                        Item item,
                        Size size,
                        OffsetNumber offsetNumber,
-                       ItemIdFlags flags)
+                       bool overwrite)
 {
        PageHeader      phdr = (PageHeader) page;
        Size            alignedSize;
@@ -121,9 +124,6 @@ PageAddItem(Page page,
        ItemId          itemId;
        OffsetNumber limit;
        bool            needshuffle = false;
-       bool            overwritemode = (flags & OverwritePageMode) != 0;
-
-       flags &= ~OverwritePageMode;
 
        /*
         * Be wary about corrupted page pointers
@@ -146,12 +146,12 @@ PageAddItem(Page page,
        if (OffsetNumberIsValid(offsetNumber))
        {
                /* yes, check it */
-               if (overwritemode)
+               if (overwrite)
                {
                        if (offsetNumber < limit)
                        {
                                itemId = PageGetItemId(phdr, offsetNumber);
-                               if (ItemIdIsUsed(itemId) || ItemIdGetLength(itemId) != 0)
+                               if (ItemIdIsUsed(itemId) || ItemIdHasStorage(itemId))
                                {
                                        elog(WARNING, "will not overwrite a used ItemId");
                                        return InvalidOffsetNumber;
@@ -170,11 +170,15 @@ PageAddItem(Page page,
                /* if no free slot, we'll put it at limit (1st open slot) */
                if (PageHasFreeLinePointers(phdr))
                {
-                       /* look for "recyclable" (unused & deallocated) ItemId */
+                       /*
+                        * Look for "recyclable" (unused) ItemId.  We check for no
+                        * storage as well, just to be paranoid --- unused items
+                        * should never have storage.
+                        */
                        for (offsetNumber = 1; offsetNumber < limit; offsetNumber++)
                        {
                                itemId = PageGetItemId(phdr, offsetNumber);
-                               if (!ItemIdIsUsed(itemId) && ItemIdGetLength(itemId) == 0)
+                               if (!ItemIdIsUsed(itemId) && !ItemIdHasStorage(itemId))
                                        break;
                        }
                        if (offsetNumber >= limit)
@@ -224,9 +228,7 @@ PageAddItem(Page page,
                                (limit - offsetNumber) * sizeof(ItemIdData));
 
        /* set the item pointer */
-       itemId->lp_off = upper;
-       itemId->lp_len = size;
-       itemId->lp_flags = flags;
+       ItemIdSetNormal(itemId, upper, size);
 
        /* copy the item's data onto the page */
        memcpy((char *) page + upper, item, size);
@@ -326,6 +328,7 @@ PageRepairFragmentation(Page page, OffsetNumber *unused)
                                itemidptr;
        ItemId          lp;
        int                     nline,
+                               nstorage,
                                nused;
        int                     i;
        Size            totallen;
@@ -349,38 +352,41 @@ PageRepairFragmentation(Page page, OffsetNumber *unused)
                                                pd_lower, pd_upper, pd_special)));
 
        nline = PageGetMaxOffsetNumber(page);
-       nused = 0;
+       nused = nstorage = 0;
        for (i = 0; i < nline; i++)
        {
                lp = PageGetItemId(page, i + 1);
-               if (ItemIdDeleted(lp))  /* marked for deletion */
-                       lp->lp_flags &= ~(LP_USED | LP_DELETE);
                if (ItemIdIsUsed(lp))
+               {
                        nused++;
-               else if (unused)
-                       unused[i - nused] = (OffsetNumber) i;
+                       if (ItemIdHasStorage(lp))
+                               nstorage++;
+               }
+               else
+               {
+                       /* Unused entries should have lp_len = 0, but make sure */
+                       ItemIdSetUnused(lp);
+                       /* Report to caller if asked for */
+                       if (unused)
+                               unused[i - nused] = (OffsetNumber) i;
+               }
        }
 
-       if (nused == 0)
+       if (nstorage == 0)
        {
                /* Page is completely empty, so just reset it quickly */
-               for (i = 0; i < nline; i++)
-               {
-                       lp = PageGetItemId(page, i + 1);
-                       lp->lp_len = 0;         /* indicate unused & deallocated */
-               }
                ((PageHeader) page)->pd_upper = pd_special;
        }
        else
-       {                                                       /* nused != 0 */
+       {                                                       /* nstorage != 0 */
                /* Need to compact the page the hard way */
-               itemidbase = (itemIdSort) palloc(sizeof(itemIdSortData) * nused);
+               itemidbase = (itemIdSort) palloc(sizeof(itemIdSortData) * nstorage);
                itemidptr = itemidbase;
                totallen = 0;
                for (i = 0; i < nline; i++)
                {
                        lp = PageGetItemId(page, i + 1);
-                       if (ItemIdIsUsed(lp))
+                       if (ItemIdHasStorage(lp))
                        {
                                itemidptr->offsetindex = i;
                                itemidptr->itemoff = ItemIdGetOffset(lp);
@@ -394,10 +400,6 @@ PageRepairFragmentation(Page page, OffsetNumber *unused)
                                totallen += itemidptr->alignedlen;
                                itemidptr++;
                        }
-                       else
-                       {
-                               lp->lp_len = 0; /* indicate unused & deallocated */
-                       }
                }
 
                if (totallen > (Size) (pd_special - pd_lower))
@@ -407,13 +409,13 @@ PageRepairFragmentation(Page page, OffsetNumber *unused)
                                          (unsigned int) totallen, pd_special - pd_lower)));
 
                /* sort itemIdSortData array into decreasing itemoff order */
-               qsort((char *) itemidbase, nused, sizeof(itemIdSortData),
+               qsort((char *) itemidbase, nstorage, sizeof(itemIdSortData),
                          itemoffcompare);
 
                /* compactify page */
                upper = pd_special;
 
-               for (i = 0, itemidptr = itemidbase; i < nused; i++, itemidptr++)
+               for (i = 0, itemidptr = itemidbase; i < nstorage; i++, itemidptr++)
                {
                        lp = PageGetItemId(page, itemidptr->offsetindex + 1);
                        upper -= itemidptr->alignedlen;
@@ -520,6 +522,7 @@ PageIndexTupleDelete(Page page, OffsetNumber offnum)
        offidx = offnum - 1;
 
        tup = PageGetItemId(page, offnum);
+       Assert(ItemIdHasStorage(tup));
        size = ItemIdGetLength(tup);
        offset = ItemIdGetOffset(tup);
 
@@ -577,6 +580,7 @@ PageIndexTupleDelete(Page page, OffsetNumber offnum)
                {
                        ItemId          ii = PageGetItemId(phdr, i);
 
+                       Assert(ItemIdHasStorage(ii));
                        if (ItemIdGetOffset(ii) <= offset)
                                ii->lp_off += size;
                }
@@ -654,6 +658,7 @@ PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)
        for (offnum = 1; offnum <= nline; offnum++)
        {
                lp = PageGetItemId(page, offnum);
+               Assert(ItemIdHasStorage(lp));
                size = ItemIdGetLength(lp);
                offset = ItemIdGetOffset(lp);
                if (offset < pd_upper ||
index deb62477147c2478edd5e9f2f4e293d2525a3d32..786714806b37f0ba34d1610bab501a65bfc122da 100644 (file)
@@ -137,7 +137,7 @@ typedef PageHeaderData *PageHeader;
  * pd_flags contains the following flag bits.  Undefined bits are initialized
  * to zero and may be used in the future.
  *
- * PD_HAS_FREE_LINES is set if there are any not-LP_USED line pointers before
+ * PD_HAS_FREE_LINES is set if there are any LP_UNUSED line pointers before
  * pd_lower.  This should be considered a hint rather than the truth, since
  * changes to it are not WAL-logged.
  */
@@ -274,7 +274,7 @@ typedef PageHeaderData *PageHeader;
 #define PageGetItem(page, itemId) \
 ( \
        AssertMacro(PageIsValid(page)), \
-       AssertMacro(ItemIdIsUsed(itemId)), \
+       AssertMacro(ItemIdHasStorage(itemId)), \
        (Item)(((char *)(page)) + ItemIdGetOffset(itemId)) \
 )
 
@@ -346,7 +346,7 @@ typedef PageHeaderData *PageHeader;
 extern void PageInit(Page page, Size pageSize, Size specialSize);
 extern bool PageHeaderIsValid(PageHeader page);
 extern OffsetNumber PageAddItem(Page page, Item item, Size size,
-                       OffsetNumber offsetNumber, ItemIdFlags flags);
+                       OffsetNumber offsetNumber, bool overwrite);
 extern Page PageGetTempPage(Page page, Size specialSize);
 extern void PageRestoreTempPage(Page tempPage, Page oldPage);
 extern int     PageRepairFragmentation(Page page, OffsetNumber *unused);
index 5dbae48071936ba2cbd42693afa1aa0dcdcddb55..d18bb0d7bc9227f56f959fb6b993a72c945bd82b 100644 (file)
 
 /*
  * An item pointer (also called line pointer) on a buffer page
+ *
+ * In some cases an item pointer is "in use" but does not have any associated
+ * storage on the page.  By convention, lp_len == 0 in every item pointer
+ * that does not have storage, independently of its lp_flags state.
  */
 typedef struct ItemIdData
-{                                                              /* line pointers */
-       unsigned        lp_off:15,              /* offset to start of tuple */
-                               lp_flags:2,             /* flags for tuple */
-                               lp_len:15;              /* length of tuple */
+{
+       unsigned        lp_off:15,              /* offset to tuple (from start of page) */
+                               lp_flags:2,             /* state of item pointer, see below */
+                               lp_len:15;              /* byte length of tuple */
 } ItemIdData;
 
 typedef ItemIdData *ItemId;
 
 /*
- * lp_flags contains these flags:
- */
-#define LP_USED                        0x01    /* this line pointer is being used */
-
-#define LP_DELETE              0x02    /* item is to be deleted */
-
-#define ItemIdDeleted(itemId) \
-       (((itemId)->lp_flags & LP_DELETE) != 0)
-
-/*
- * This bit may be passed to PageAddItem together with
- * LP_USED & LP_DELETE bits to specify overwrite mode
+ * lp_flags has these possible states.  An UNUSED line pointer is available
+ * for immediate re-use, the other states are not.
  */
-#define OverwritePageMode      0x10
+#define LP_UNUSED              0               /* unused (should always have lp_len=0) */
+#define LP_NORMAL              1               /* used (should always have lp_len>0) */
+#define LP_REDIRECT            2               /* HOT redirect (should have lp_len=0) */
+#define LP_DEAD                        3               /* dead, may or may not have storage */
 
 /*
- * Item offsets, lengths, and flags are represented by these types when
+ * Item offsets and lengths are represented by these types when
  * they're not actually stored in an ItemIdData.
  */
 typedef uint16 ItemOffset;
 typedef uint16 ItemLength;
 
-typedef bits16 ItemIdFlags;
-
 
 /* ----------------
  *             support macros
@@ -75,23 +70,114 @@ typedef bits16 ItemIdFlags;
 #define ItemIdGetFlags(itemId) \
    ((itemId)->lp_flags)
 
+/*
+ *             ItemIdGetRedirect
+ * In a REDIRECT pointer, lp_off holds the link to the next item pointer
+ */
+#define ItemIdGetRedirect(itemId) \
+   ((itemId)->lp_off)
+
 /*
  * ItemIdIsValid
- *             True iff disk item identifier is valid.
+ *             True iff item identifier is valid.
+ *             This is a pretty weak test, probably useful only in Asserts.
  */
 #define ItemIdIsValid(itemId)  PointerIsValid(itemId)
 
 /*
  * ItemIdIsUsed
- *             True iff disk item identifier is in use.
- *
- * Note:
- *             Assumes disk item identifier is valid.
+ *             True iff item identifier is in use.
  */
 #define ItemIdIsUsed(itemId) \
+       ((itemId)->lp_flags != LP_UNUSED)
+
+/*
+ * ItemIdIsNormal
+ *             True iff item identifier is in state NORMAL.
+ */
+#define ItemIdIsNormal(itemId) \
+       ((itemId)->lp_flags == LP_NORMAL)
+
+/*
+ * ItemIdIsRedirected
+ *             True iff item identifier is in state REDIRECT.
+ */
+#define ItemIdIsRedirected(itemId) \
+       ((itemId)->lp_flags == LP_REDIRECT)
+
+/*
+ * ItemIdIsDead
+ *             True iff item identifier is in state DEAD.
+ */
+#define ItemIdIsDead(itemId) \
+       ((itemId)->lp_flags == LP_DEAD)
+
+/*
+ * ItemIdHasStorage
+ *             True iff item identifier has associated storage.
+ */
+#define ItemIdHasStorage(itemId) \
+       ((itemId)->lp_len != 0)
+
+/*
+ * ItemIdSetUnused
+ *             Set the item identifier to be UNUSED, with no storage.
+ *             Beware of multiple evaluations of itemId!
+ */
+#define ItemIdSetUnused(itemId) \
+( \
+       (itemId)->lp_flags = LP_UNUSED, \
+       (itemId)->lp_off = 0, \
+       (itemId)->lp_len = 0 \
+)
+
+/*
+ * ItemIdSetNormal
+ *             Set the item identifier to be NORMAL, with the specified storage.
+ *             Beware of multiple evaluations of itemId!
+ */
+#define ItemIdSetNormal(itemId, off, len) \
+( \
+       (itemId)->lp_flags = LP_NORMAL, \
+       (itemId)->lp_off = (off), \
+       (itemId)->lp_len = (len) \
+)
+
+/*
+ * ItemIdSetRedirect
+ *             Set the item identifier to be REDIRECT, with the specified link.
+ *             Beware of multiple evaluations of itemId!
+ */
+#define ItemIdSetRedirect(itemId, link) \
+( \
+       (itemId)->lp_flags = LP_REDIRECT, \
+       (itemId)->lp_off = (link), \
+       (itemId)->lp_len = 0 \
+)
+
+/*
+ * ItemIdSetDead
+ *             Set the item identifier to be DEAD, with no storage.
+ *             Beware of multiple evaluations of itemId!
+ */
+#define ItemIdSetDead(itemId) \
+( \
+       (itemId)->lp_flags = LP_DEAD, \
+       (itemId)->lp_off = 0, \
+       (itemId)->lp_len = 0 \
+)
+
+/*
+ * ItemIdMarkDead
+ *             Set the item identifier to be DEAD, keeping its existing storage.
+ *
+ * Note: in indexes, this is used as if it were a hint-bit mechanism;
+ * we trust that multiple processors can do this in parallel and get
+ * the same result.
+ */
+#define ItemIdMarkDead(itemId) \
 ( \
-       AssertMacro(ItemIdIsValid(itemId)), \
-       (bool) (((itemId)->lp_flags & LP_USED) != 0) \
+       (itemId)->lp_flags = LP_DEAD \
 )
 
 #endif   /* ITEMID_H */