11
11
*
12
12
*
13
13
* IDENTIFICATION
14
- * $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.122 2004/05/06 16:10:57 tgl Exp $
14
+ * $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.123 2004/05/08 00:34:49 tgl Exp $
15
15
*
16
16
*-------------------------------------------------------------------------
17
17
*/
37
37
#include "utils/relcache.h"
38
38
39
39
40
- /*
41
- * We need one of these structs for each index in the relation to be
42
- * clustered. It's basically the data needed by index_create() so
43
- * we can rebuild the indexes on the new heap.
44
- */
45
- typedef struct
46
- {
47
- Oid indexOID ;
48
- char * indexName ;
49
- IndexInfo * indexInfo ;
50
- Oid accessMethodOID ;
51
- Oid * classOID ;
52
- } IndexAttrs ;
53
-
54
40
/*
55
41
* This struct is used to pass around the information on tables to be
56
42
* clustered. We need this so we can make a list of them when invoked without
@@ -64,6 +50,7 @@ typedef struct
64
50
65
51
66
52
static void cluster_rel (RelToCluster * rv , bool recheck );
53
+ static void rebuild_relation (Relation OldHeap , Oid indexOid );
67
54
static void copy_heap_data (Oid OIDNewHeap , Oid OIDOldHeap , Oid OIDOldIndex );
68
55
static List * get_tables_to_cluster (MemoryContext cluster_context );
69
56
@@ -411,30 +398,99 @@ check_index_is_clusterable(Relation OldHeap, Oid indexOid)
411
398
}
412
399
413
400
/*
414
- * rebuild_relation: rebuild an existing relation
401
+ * mark_index_clustered: mark the specified index as the one clustered on
415
402
*
416
- * This is shared code between CLUSTER and TRUNCATE. In the TRUNCATE
417
- * case, the new relation is built and left empty. In the CLUSTER case,
418
- * it is filled with data read from the old relation in the order specified
419
- * by the index.
403
+ * With indexOid == InvalidOid, will mark all indexes of rel not-clustered.
404
+ */
405
+ void
406
+ mark_index_clustered (Relation rel , Oid indexOid )
407
+ {
408
+ HeapTuple indexTuple ;
409
+ Form_pg_index indexForm ;
410
+ Relation pg_index ;
411
+ List * index ;
412
+
413
+ /*
414
+ * If the index is already marked clustered, no need to do anything.
415
+ */
416
+ if (OidIsValid (indexOid ))
417
+ {
418
+ indexTuple = SearchSysCache (INDEXRELID ,
419
+ ObjectIdGetDatum (indexOid ),
420
+ 0 , 0 , 0 );
421
+ if (!HeapTupleIsValid (indexTuple ))
422
+ elog (ERROR , "cache lookup failed for index %u" , indexOid );
423
+ indexForm = (Form_pg_index ) GETSTRUCT (indexTuple );
424
+
425
+ if (indexForm -> indisclustered )
426
+ {
427
+ ReleaseSysCache (indexTuple );
428
+ return ;
429
+ }
430
+
431
+ ReleaseSysCache (indexTuple );
432
+ }
433
+
434
+ /*
435
+ * Check each index of the relation and set/clear the bit as needed.
436
+ */
437
+ pg_index = heap_openr (IndexRelationName , RowExclusiveLock );
438
+
439
+ foreach (index , RelationGetIndexList (rel ))
440
+ {
441
+ Oid thisIndexOid = lfirsto (index );
442
+
443
+ indexTuple = SearchSysCacheCopy (INDEXRELID ,
444
+ ObjectIdGetDatum (thisIndexOid ),
445
+ 0 , 0 , 0 );
446
+ if (!HeapTupleIsValid (indexTuple ))
447
+ elog (ERROR , "cache lookup failed for index %u" , thisIndexOid );
448
+ indexForm = (Form_pg_index ) GETSTRUCT (indexTuple );
449
+
450
+ /*
451
+ * Unset the bit if set. We know it's wrong because we checked
452
+ * this earlier.
453
+ */
454
+ if (indexForm -> indisclustered )
455
+ {
456
+ indexForm -> indisclustered = false;
457
+ simple_heap_update (pg_index , & indexTuple -> t_self , indexTuple );
458
+ CatalogUpdateIndexes (pg_index , indexTuple );
459
+ /* Ensure we see the update in the index's relcache entry */
460
+ CacheInvalidateRelcacheByRelid (thisIndexOid );
461
+ }
462
+ else if (thisIndexOid == indexOid )
463
+ {
464
+ indexForm -> indisclustered = true;
465
+ simple_heap_update (pg_index , & indexTuple -> t_self , indexTuple );
466
+ CatalogUpdateIndexes (pg_index , indexTuple );
467
+ /* Ensure we see the update in the index's relcache entry */
468
+ CacheInvalidateRelcacheByRelid (thisIndexOid );
469
+ }
470
+ heap_freetuple (indexTuple );
471
+ }
472
+
473
+ heap_close (pg_index , RowExclusiveLock );
474
+ }
475
+
476
+ /*
477
+ * rebuild_relation: rebuild an existing relation in index order
420
478
*
421
479
* OldHeap: table to rebuild --- must be opened and exclusive-locked!
422
- * indexOid: index to cluster by, or InvalidOid in TRUNCATE case
480
+ * indexOid: index to cluster by
423
481
*
424
482
* NB: this routine closes OldHeap at the right time; caller should not.
425
483
*/
426
- void
484
+ static void
427
485
rebuild_relation (Relation OldHeap , Oid indexOid )
428
486
{
429
487
Oid tableOid = RelationGetRelid (OldHeap );
430
- Oid oldClusterIndex ;
431
- List * indexes ;
432
488
Oid OIDNewHeap ;
433
489
char NewHeapName [NAMEDATALEN ];
434
490
ObjectAddress object ;
435
491
436
- /* Save the information about all indexes on the relation. */
437
- indexes = get_indexattr_list (OldHeap , & oldClusterIndex );
492
+ /* Mark the correct index as clustered */
493
+ mark_index_clustered (OldHeap , indexOid );
438
494
439
495
/* Close relcache entry, but keep lock until transaction commit */
440
496
heap_close (OldHeap , NoLock );
@@ -459,8 +515,7 @@ rebuild_relation(Relation OldHeap, Oid indexOid)
459
515
/*
460
516
* Copy the heap data into the new table in the desired order.
461
517
*/
462
- if (OidIsValid (indexOid ))
463
- copy_heap_data (OIDNewHeap , tableOid , indexOid );
518
+ copy_heap_data (OIDNewHeap , tableOid , indexOid );
464
519
465
520
/* To make the new heap's data visible (probably not needed?). */
466
521
CommandCounterIncrement ();
@@ -484,11 +539,11 @@ rebuild_relation(Relation OldHeap, Oid indexOid)
484
539
/* performDeletion does CommandCounterIncrement at end */
485
540
486
541
/*
487
- * Recreate each index on the relation. We do not need
488
- * CommandCounterIncrement() because rebuild_indexes does it.
542
+ * Rebuild each index on the relation (but not the toast table,
543
+ * which is all-new at this point). We do not need
544
+ * CommandCounterIncrement() because reindex_relation does it.
489
545
*/
490
- rebuild_indexes (tableOid , indexes ,
491
- (OidIsValid (indexOid ) ? indexOid : oldClusterIndex ));
546
+ reindex_relation (tableOid , false);
492
547
}
493
548
494
549
/*
@@ -589,138 +644,6 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex)
589
644
heap_close (NewHeap , NoLock );
590
645
}
591
646
592
- /*
593
- * Get the necessary info about the indexes of the relation and
594
- * return a list of IndexAttrs structures. Also, *OldClusterIndex
595
- * is set to the OID of the existing clustered index, or InvalidOid
596
- * if there is none.
597
- */
598
- List *
599
- get_indexattr_list (Relation OldHeap , Oid * OldClusterIndex )
600
- {
601
- List * indexes = NIL ;
602
- List * indlist ;
603
-
604
- * OldClusterIndex = InvalidOid ;
605
-
606
- /* Ask the relcache to produce a list of the indexes of the old rel */
607
- foreach (indlist , RelationGetIndexList (OldHeap ))
608
- {
609
- Oid indexOID = lfirsto (indlist );
610
- Relation oldIndex ;
611
- IndexAttrs * attrs ;
612
-
613
- oldIndex = index_open (indexOID );
614
-
615
- attrs = (IndexAttrs * ) palloc (sizeof (IndexAttrs ));
616
- attrs -> indexOID = indexOID ;
617
- attrs -> indexName = pstrdup (NameStr (oldIndex -> rd_rel -> relname ));
618
- attrs -> accessMethodOID = oldIndex -> rd_rel -> relam ;
619
- attrs -> indexInfo = BuildIndexInfo (oldIndex );
620
- attrs -> classOID = (Oid * )
621
- palloc (sizeof (Oid ) * attrs -> indexInfo -> ii_NumIndexAttrs );
622
- memcpy (attrs -> classOID , oldIndex -> rd_index -> indclass ,
623
- sizeof (Oid ) * attrs -> indexInfo -> ii_NumIndexAttrs );
624
- if (oldIndex -> rd_index -> indisclustered )
625
- * OldClusterIndex = indexOID ;
626
-
627
- index_close (oldIndex );
628
-
629
- indexes = lappend (indexes , attrs );
630
- }
631
-
632
- return indexes ;
633
- }
634
-
635
- /*
636
- * Create new indexes and swap the filenodes with old indexes. Then drop
637
- * the new index (carrying the old index filenode along).
638
- *
639
- * OIDClusterIndex is the OID of the index to be marked as clustered, or
640
- * InvalidOid if none should be marked clustered.
641
- */
642
- void
643
- rebuild_indexes (Oid OIDOldHeap , List * indexes , Oid OIDClusterIndex )
644
- {
645
- List * elem ;
646
-
647
- foreach (elem , indexes )
648
- {
649
- IndexAttrs * attrs = (IndexAttrs * ) lfirst (elem );
650
- Oid oldIndexOID = attrs -> indexOID ;
651
- Oid newIndexOID ;
652
- char newIndexName [NAMEDATALEN ];
653
- bool isclustered ;
654
- ObjectAddress object ;
655
- Form_pg_index index ;
656
- HeapTuple tuple ;
657
- Relation pg_index ;
658
-
659
- /* Create the new index under a temporary name */
660
- snprintf (newIndexName , sizeof (newIndexName ),
661
- "pg_temp_%u" , oldIndexOID );
662
-
663
- /*
664
- * The new index will have primary and constraint status set to
665
- * false, but since we will only use its filenode it doesn't
666
- * matter: after the filenode swap the index will keep the
667
- * constraint status of the old index.
668
- */
669
- newIndexOID = index_create (OIDOldHeap ,
670
- newIndexName ,
671
- attrs -> indexInfo ,
672
- attrs -> accessMethodOID ,
673
- attrs -> classOID ,
674
- false,
675
- false,
676
- allowSystemTableMods ,
677
- false);
678
- CommandCounterIncrement ();
679
-
680
- /* Swap the filenodes. */
681
- swap_relfilenodes (oldIndexOID , newIndexOID );
682
-
683
- CommandCounterIncrement ();
684
-
685
- /*
686
- * Make sure that indisclustered is correct: it should be set only
687
- * for the index specified by the caller.
688
- */
689
- isclustered = (oldIndexOID == OIDClusterIndex );
690
-
691
- pg_index = heap_openr (IndexRelationName , RowExclusiveLock );
692
- tuple = SearchSysCacheCopy (INDEXRELID ,
693
- ObjectIdGetDatum (oldIndexOID ),
694
- 0 , 0 , 0 );
695
- if (!HeapTupleIsValid (tuple ))
696
- elog (ERROR , "cache lookup failed for index %u" , oldIndexOID );
697
- index = (Form_pg_index ) GETSTRUCT (tuple );
698
- if (index -> indisclustered != isclustered )
699
- {
700
- index -> indisclustered = isclustered ;
701
- simple_heap_update (pg_index , & tuple -> t_self , tuple );
702
- CatalogUpdateIndexes (pg_index , tuple );
703
- /* Ensure we see the update in the index's relcache entry */
704
- CacheInvalidateRelcacheByRelid (oldIndexOID );
705
- }
706
- heap_freetuple (tuple );
707
- heap_close (pg_index , RowExclusiveLock );
708
-
709
- /* Destroy new index with old filenode */
710
- object .classId = RelOid_pg_class ;
711
- object .objectId = newIndexOID ;
712
- object .objectSubId = 0 ;
713
-
714
- /*
715
- * The relation is local to our transaction and we know nothing
716
- * depends on it, so DROP_RESTRICT should be OK.
717
- */
718
- performDeletion (& object , DROP_RESTRICT );
719
-
720
- /* performDeletion does CommandCounterIncrement() at its end */
721
- }
722
- }
723
-
724
647
/*
725
648
* Swap the relfilenodes for two given relations.
726
649
*
0 commit comments