CREATE btree INDEX takes dead tuples into account when old transactions
authorHiroshi Inoue <inoue@tpf.co.jp>
Thu, 10 Aug 2000 02:33:20 +0000 (02:33 +0000)
committerHiroshi Inoue <inoue@tpf.co.jp>
Thu, 10 Aug 2000 02:33:20 +0000 (02:33 +0000)
are running.

src/backend/access/nbtree/nbtree.c
src/backend/access/nbtree/nbtsort.c
src/include/access/nbtree.h

index 072d4000705dd0e8ec87fc662f4571133d368929..7fec982fa2d9e59388ca0f9121255c75ff9fcc8e 100644 (file)
@@ -12,7 +12,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.62 2000/07/21 06:42:32 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.63 2000/08/10 02:33:20 inoue Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -25,6 +25,7 @@
 #include "catalog/index.h"
 #include "executor/executor.h"
 #include "miscadmin.h"
+#include "storage/sinval.h"
 
 
 bool       BuildingBtree = false;      /* see comment in btbuild() */
@@ -70,6 +71,16 @@ btbuild(PG_FUNCTION_ARGS)
    BTSpool    *spool = NULL;
    BTItem      btitem;
    bool        usefast;
+   Snapshot    snapshot;
+   TransactionId   XmaxRecent;
+   /*
+    * spool2 is needed only when the index is an unique index.
+    * Dead tuples are put into spool2 instead of spool in
+    * order to avoid uniqueness check.
+    */
+   BTSpool     *spool2 = NULL;
+   bool        tupleIsAlive;
+   int     dead_count;
 
    /* note that this is a new btree */
    BuildingBtree = true;
@@ -135,13 +146,41 @@ btbuild(PG_FUNCTION_ARGS)
    nhtups = nitups = 0;
 
    if (usefast)
+   {
        spool = _bt_spoolinit(index, indexInfo->ii_Unique);
+       /*
+        * Different from spool,the uniqueness isn't checked
+        * for spool2.
+        */
+       if (indexInfo->ii_Unique)
+           spool2 = _bt_spoolinit(index, false);
+   }
 
    /* start a heap scan */
-   hscan = heap_beginscan(heap, 0, SnapshotNow, 0, (ScanKey) NULL);
+   dead_count = 0;
+   snapshot = (IsBootstrapProcessingMode() ? SnapshotNow : SnapshotAny);
+   hscan = heap_beginscan(heap, 0, snapshot, 0, (ScanKey) NULL);
+   XmaxRecent = 0;
+   if (snapshot == SnapshotAny)
+       GetXmaxRecent(&XmaxRecent);
 
    while (HeapTupleIsValid(htup = heap_getnext(hscan, 0)))
    {
+       if (snapshot == SnapshotAny)
+       {
+           tupleIsAlive = HeapTupleSatisfiesNow(htup->t_data);
+           if (!tupleIsAlive)
+           {
+               if ((htup->t_data->t_infomask & HEAP_XMIN_INVALID) != 0)
+                   continue;
+               if (htup->t_data->t_infomask & HEAP_XMAX_COMMITTED &&
+                   htup->t_data->t_xmax < XmaxRecent)
+                   continue;
+           }
+       }
+       else
+           tupleIsAlive = true;
+       
        MemoryContextReset(econtext->ecxt_per_tuple_memory);
 
        nhtups++;
@@ -222,7 +261,15 @@ btbuild(PG_FUNCTION_ARGS)
         * into the btree.
         */
        if (usefast)
-           _bt_spool(btitem, spool);
+       {
+           if (tupleIsAlive || !spool2)
+               _bt_spool(btitem, spool);
+           else /* dead tuples are put into spool2 */
+           {
+               dead_count++;
+               _bt_spool(btitem, spool2);
+           }
+       }
        else
            res = _bt_doinsert(index, btitem, indexInfo->ii_Unique, heap);
 
@@ -234,6 +281,11 @@ btbuild(PG_FUNCTION_ARGS)
 
    /* okay, all heap tuples are indexed */
    heap_endscan(hscan);
+   if (spool2 && !dead_count) /* spool2 was found to be unnecessary */
+   {
+       _bt_spooldestroy(spool2);
+       spool2 = NULL;
+   }
 
 #ifndef OMIT_PARTIAL_INDEX
    if (pred != NULL || oldPred != NULL)
@@ -250,8 +302,10 @@ btbuild(PG_FUNCTION_ARGS)
     */
    if (usefast)
    {
-       _bt_leafbuild(spool);
+       _bt_leafbuild(spool, spool2);
        _bt_spooldestroy(spool);
+       if (spool2)
+           _bt_spooldestroy(spool2);
    }
 
 #ifdef BTREE_BUILD_STATS
index 40408e2b3b28e881792e06f723b905d541e3556f..b52522fa8de8f8ab939add48d5f630f5ac654df5 100644 (file)
@@ -35,7 +35,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsort.c,v 1.56 2000/07/21 22:14:09 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsort.c,v 1.57 2000/08/10 02:33:20 inoue Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -95,7 +95,7 @@ static void _bt_sortaddtup(Page page, Size itemsize,
                           BTItem btitem, OffsetNumber itup_off);
 static void _bt_buildadd(Relation index, BTPageState *state, BTItem bti);
 static void _bt_uppershutdown(Relation index, BTPageState *state);
-static void _bt_load(Relation index, BTSpool *btspool);
+static void _bt_load(Relation index, BTSpool *btspool, BTSpool *btspool2);
 
 
 /*
@@ -153,7 +153,7 @@ _bt_spool(BTItem btitem, BTSpool *btspool)
  * create an entire btree.
  */
 void
-_bt_leafbuild(BTSpool *btspool)
+_bt_leafbuild(BTSpool *btspool, BTSpool *btspool2)
 {
 #ifdef BTREE_BUILD_STATS
    if (Show_btree_build_stats)
@@ -165,7 +165,9 @@ _bt_leafbuild(BTSpool *btspool)
 #endif /* BTREE_BUILD_STATS */
    tuplesort_performsort(btspool->sortstate);
 
-   _bt_load(btspool->index, btspool);
+   if (btspool2)
+       tuplesort_performsort(btspool2->sortstate);
+   _bt_load(btspool->index, btspool, btspool2);
 }
 
 
@@ -523,28 +525,106 @@ _bt_uppershutdown(Relation index, BTPageState *state)
  * btree leaves.
  */
 static void
-_bt_load(Relation index, BTSpool *btspool)
+_bt_load(Relation index, BTSpool *btspool, BTSpool *btspool2)
 {
    BTPageState *state = NULL;
-
-   for (;;)
+   bool        merge = (btspool2 != NULL);
+   BTItem      bti, bti2 = NULL;
+   bool        should_free, should_free2, load1;
+   TupleDesc   tupdes = RelationGetDescr(index);
+   int     i, keysz = RelationGetNumberOfAttributes(index);
+   ScanKey     indexScanKey = NULL;
+
+   if (merge)
    {
-       BTItem      bti;
-       bool        should_free;
-
-       bti = (BTItem) tuplesort_getindextuple(btspool->sortstate, true,
-                                              &should_free);
-       if (bti == (BTItem) NULL)
-           break;
-
-       /* When we see first tuple, create first index page */
-       if (state == NULL)
-           state = _bt_pagestate(index, BTP_LEAF, 0);
-
-       _bt_buildadd(index, state, bti);
+       /*
+        * Another BTSpool for dead tuples exists.
+        * Now we have to merge btspool and btspool2.
+        */
+       ScanKey entry;
+       Datum   attrDatum1, attrDatum2;
+       bool    isFirstNull, isSecondNull;
+       int32   compare;
+
+       /* the preparation of merge */
+       bti = (BTItem) tuplesort_getindextuple(btspool->sortstate, true, &should_free);
+       bti2 = (BTItem) tuplesort_getindextuple(btspool2->sortstate, true, &should_free2);
+       indexScanKey = _bt_mkscankey_nodata(index);
+       for (;;)
+       {
+           load1 = true; /* load BTSpool next ? */
+           if (NULL == bti2)
+           {
+               if (NULL == bti)
+                   break;
+           }
+           else if (NULL != bti)
+           {
+
+               for (i = 1; i <= keysz; i++)
+               {
+                   entry = indexScanKey + i - 1;
+                   attrDatum1 = index_getattr((IndexTuple)bti, i, tupdes, &isFirstNull);
+                   attrDatum2 = index_getattr((IndexTuple)bti2, i, tupdes, &isSecondNull);
+                   if (isFirstNull)
+                   {
+                       if (!isSecondNull)
+                       {
+                           load1 = false;
+                           break;
+                       }
+                   }
+                   else if (isSecondNull)
+                       break;
+                   else
+                   {
+                       compare = DatumGetInt32(FunctionCall2(&entry->sk_func, attrDatum1, attrDatum2));
+                       if (compare > 0)
+                       {
+                           load1 = false;
+                           break;
+                       }
+                       else if (compare < 0)
+                           break;
+                   }   
+               }
+           }
+           else
+               load1 = false;
+
+           /* When we see first tuple, create first index page */
+           if (state == NULL)
+               state = _bt_pagestate(index, BTP_LEAF, 0);
+
+           if (load1)
+           {
+               _bt_buildadd(index, state, bti);
+               if (should_free)
+                   pfree((void *) bti);
+               bti = (BTItem) tuplesort_getindextuple(btspool->sortstate, true, &should_free);
+           }
+           else
+           {
+               _bt_buildadd(index, state, bti2);
+               if (should_free2)
+                   pfree((void *) bti2);
+               bti2 = (BTItem) tuplesort_getindextuple(btspool2->sortstate, true, &should_free2);
+           }
+       }
+       _bt_freeskey(indexScanKey);
+   }
+   else    /* merge is unnecessary */
+   {
+       while (bti = (BTItem) tuplesort_getindextuple(btspool->sortstate, true, &should_free), bti != (BTItem) NULL)
+       {
+           /* When we see first tuple, create first index page */
+           if (state == NULL)
+               state = _bt_pagestate(index, BTP_LEAF, 0);
 
-       if (should_free)
-           pfree((void *) bti);
+           _bt_buildadd(index, state, bti);
+           if (should_free)
+               pfree((void *) bti);
+       }
    }
 
    /* Close down final pages, if we had any data at all */
index d84cfa5ded94b8496856d8a1f253f2df741ed4ae..da080603fc0236d647c78f04a5eb54c3a1ec4531 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: nbtree.h,v 1.40 2000/07/25 04:47:57 tgl Exp $
+ * $Id: nbtree.h,v 1.41 2000/08/10 02:33:19 inoue Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -289,6 +289,6 @@ typedef struct BTSpool BTSpool; /* opaque type known only within nbtsort.c */
 extern BTSpool *_bt_spoolinit(Relation index, bool isunique);
 extern void _bt_spooldestroy(BTSpool *btspool);
 extern void _bt_spool(BTItem btitem, BTSpool *btspool);
-extern void _bt_leafbuild(BTSpool *btspool);
+extern void _bt_leafbuild(BTSpool *btspool, BTSpool *spool2);
 
 #endif  /* NBTREE_H */