8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $PostgreSQL: pgsql/src/backend/storage/page/bufpage.c,v 1.62 2004/12/31 22:01:10 pgsql Exp $
11
+ * $PostgreSQL: pgsql/src/backend/storage/page/bufpage.c,v 1.63 2005/03/22 06:17:03 tgl Exp $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
@@ -274,13 +274,14 @@ PageRestoreTempPage(Page tempPage, Page oldPage)
274
274
}
275
275
276
276
/*
277
- * sorting support for PageRepairFragmentation
277
+ * sorting support for PageRepairFragmentation and PageIndexMultiDelete
278
278
*/
279
279
typedef struct itemIdSortData
280
280
{
281
281
int offsetindex ; /* linp array index */
282
282
int itemoff ; /* page offset of item data */
283
283
Size alignedlen ; /* MAXALIGN(item data len) */
284
+ ItemIdData olditemid ; /* used only in PageIndexMultiDelete */
284
285
} itemIdSortData ;
285
286
typedef itemIdSortData * itemIdSort ;
286
287
@@ -297,7 +298,8 @@ itemoffcompare(const void *itemidp1, const void *itemidp2)
297
298
*
298
299
* Frees fragmented space on a page.
299
300
* It doesn't remove unused line pointers! Please don't change this.
300
- * This routine is usable for heap pages only.
301
+ *
302
+ * This routine is usable for heap pages only, but see PageIndexMultiDelete.
301
303
*
302
304
* Returns number of unused line pointers on page. If "unused" is not NULL
303
305
* then the unused[] array is filled with indexes of unused line pointers.
@@ -543,3 +545,135 @@ PageIndexTupleDelete(Page page, OffsetNumber offnum)
543
545
}
544
546
}
545
547
}
548
+
549
+
550
+ /*
551
+ * PageIndexMultiDelete
552
+ *
553
+ * This routine handles the case of deleting multiple tuples from an
554
+ * index page at once. It is considerably faster than a loop around
555
+ * PageIndexTupleDelete ... however, the caller *must* supply the array
556
+ * of item numbers to be deleted in item number order!
557
+ */
558
+ void
559
+ PageIndexMultiDelete (Page page , OffsetNumber * itemnos , int nitems )
560
+ {
561
+ PageHeader phdr = (PageHeader ) page ;
562
+ Offset pd_lower = phdr -> pd_lower ;
563
+ Offset pd_upper = phdr -> pd_upper ;
564
+ Offset pd_special = phdr -> pd_special ;
565
+ itemIdSort itemidbase ,
566
+ itemidptr ;
567
+ ItemId lp ;
568
+ int nline ,
569
+ nused ;
570
+ int i ;
571
+ Size totallen ;
572
+ Offset upper ;
573
+ Size size ;
574
+ unsigned offset ;
575
+ int nextitm ;
576
+ OffsetNumber offnum ;
577
+
578
+ /*
579
+ * If there aren't very many items to delete, then retail
580
+ * PageIndexTupleDelete is the best way. Delete the items in reverse
581
+ * order so we don't have to think about adjusting item numbers for
582
+ * previous deletions.
583
+ *
584
+ * TODO: tune the magic number here
585
+ */
586
+ if (nitems <= 2 )
587
+ {
588
+ while (-- nitems >= 0 )
589
+ PageIndexTupleDelete (page , itemnos [nitems ]);
590
+ return ;
591
+ }
592
+
593
+ /*
594
+ * As with PageRepairFragmentation, paranoia seems justified.
595
+ */
596
+ if (pd_lower < SizeOfPageHeaderData ||
597
+ pd_lower > pd_upper ||
598
+ pd_upper > pd_special ||
599
+ pd_special > BLCKSZ ||
600
+ pd_special != MAXALIGN (pd_special ))
601
+ ereport (ERROR ,
602
+ (errcode (ERRCODE_DATA_CORRUPTED ),
603
+ errmsg ("corrupted page pointers: lower = %u, upper = %u, special = %u" ,
604
+ pd_lower , pd_upper , pd_special )));
605
+
606
+ /*
607
+ * Scan the item pointer array and build a list of just the ones we
608
+ * are going to keep. Notice we do not modify the page yet, since
609
+ * we are still validity-checking.
610
+ */
611
+ nline = PageGetMaxOffsetNumber (page );
612
+ itemidbase = (itemIdSort ) palloc (sizeof (itemIdSortData ) * nline );
613
+ itemidptr = itemidbase ;
614
+ totallen = 0 ;
615
+ nused = 0 ;
616
+ nextitm = 0 ;
617
+ for (offnum = 1 ; offnum <= nline ; offnum ++ )
618
+ {
619
+ lp = PageGetItemId (page , offnum );
620
+ size = ItemIdGetLength (lp );
621
+ offset = ItemIdGetOffset (lp );
622
+ if (offset < pd_upper ||
623
+ (offset + size ) > pd_special ||
624
+ offset != MAXALIGN (offset ))
625
+ ereport (ERROR ,
626
+ (errcode (ERRCODE_DATA_CORRUPTED ),
627
+ errmsg ("corrupted item pointer: offset = %u, size = %u" ,
628
+ offset , (unsigned int ) size )));
629
+
630
+ if (nextitm < nitems && offnum == itemnos [nextitm ])
631
+ {
632
+ /* skip item to be deleted */
633
+ nextitm ++ ;
634
+ }
635
+ else
636
+ {
637
+ itemidptr -> offsetindex = nused ; /* where it will go */
638
+ itemidptr -> itemoff = offset ;
639
+ itemidptr -> olditemid = * lp ;
640
+ itemidptr -> alignedlen = MAXALIGN (size );
641
+ totallen += itemidptr -> alignedlen ;
642
+ itemidptr ++ ;
643
+ nused ++ ;
644
+ }
645
+ }
646
+
647
+ /* this will catch invalid or out-of-order itemnos[] */
648
+ if (nextitm != nitems )
649
+ elog (ERROR , "incorrect index offsets supplied" );
650
+
651
+ if (totallen > (Size ) (pd_special - pd_lower ))
652
+ ereport (ERROR ,
653
+ (errcode (ERRCODE_DATA_CORRUPTED ),
654
+ errmsg ("corrupted item lengths: total %u, available space %u" ,
655
+ (unsigned int ) totallen , pd_special - pd_lower )));
656
+
657
+ /* sort itemIdSortData array into decreasing itemoff order */
658
+ qsort ((char * ) itemidbase , nused , sizeof (itemIdSortData ),
659
+ itemoffcompare );
660
+
661
+ /* compactify page and install new itemids */
662
+ upper = pd_special ;
663
+
664
+ for (i = 0 , itemidptr = itemidbase ; i < nused ; i ++ , itemidptr ++ )
665
+ {
666
+ lp = PageGetItemId (page , itemidptr -> offsetindex + 1 );
667
+ upper -= itemidptr -> alignedlen ;
668
+ memmove ((char * ) page + upper ,
669
+ (char * ) page + itemidptr -> itemoff ,
670
+ itemidptr -> alignedlen );
671
+ * lp = itemidptr -> olditemid ;
672
+ lp -> lp_off = upper ;
673
+ }
674
+
675
+ phdr -> pd_lower = SizeOfPageHeaderData + nused * sizeof (ItemIdData );
676
+ phdr -> pd_upper = upper ;
677
+
678
+ pfree (itemidbase );
679
+ }
0 commit comments