]> granicus.if.org Git - postgresql/commitdiff
Fix pgstattuple to acquire a read lock on the target table. This
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 19 Dec 2001 20:28:41 +0000 (20:28 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 19 Dec 2001 20:28:41 +0000 (20:28 +0000)
prevents embarassments such as having the table dropped or truncated
partway through the scan.  Also, fix free space calculation to include
pages that currently contain no tuples.

contrib/pgstattuple/README.pgstattuple
contrib/pgstattuple/pgstattuple.c

index c54f97e82f5ba731dcb077113195672a4f9659d6..6a191e9cced316a92f532536d74b67f21cd34a81 100644 (file)
@@ -15,7 +15,7 @@ NOTICE:  physical length: 0.08MB live tuples: 20 (0.00MB, 1.17%) dead tuples: 32
        18.75
 (1 row)
 
-   Above example shows tellers tables includes 18.75% dead tuples.
+   Above example shows tellers table includes 18.75% dead tuples.
 
    physical length     physical size of the table in MB
    live tuples         information on the live tuples
@@ -40,7 +40,7 @@ NOTICE:  physical length: 0.08MB live tuples: 20 (0.00MB, 1.17%) dead tuples: 32
 
 4. Notes
 
-   pgstattuple does not lock the target table at all. So concurrent
+   pgstattuple acquires only a read lock on the table. So concurrent
    update may affect the result.
 
    pgstattuple judges a tuple is "dead" if HeapTupleSatisfiesNow()
index 45e92298100b96dbdcf2cb434a4e9515ec9baa69..b5afab80de1ec4c62968b371f73ed2b8de833dcd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Header: /cvsroot/pgsql/contrib/pgstattuple/pgstattuple.c,v 1.2 2001/10/25 05:49:20 momjian Exp $
+ * $Header: /cvsroot/pgsql/contrib/pgstattuple/pgstattuple.c,v 1.3 2001/12/19 20:28:41 tgl Exp $
  *
  * Copyright (c) 2001  Tatsuo Ishii
  *
@@ -23,6 +23,7 @@
  */
 
 #include "postgres.h"
+
 #include "fmgr.h"
 #include "access/heapam.h"
 #include "access/transam.h"
@@ -48,20 +49,21 @@ pgstattuple(PG_FUNCTION_ARGS)
        HeapScanDesc scan;
        HeapTuple       tuple;
        BlockNumber nblocks;
-       BlockNumber block = InvalidBlockNumber;
+       BlockNumber block = 0;          /* next block to count free space in */
+       BlockNumber tupblock;
+       Buffer          buffer;
        double          table_len;
        uint64          tuple_len = 0;
        uint64          dead_tuple_len = 0;
-       uint32          tuple_count = 0;
-       uint32          dead_tuple_count = 0;
+       uint64          tuple_count = 0;
+       uint64          dead_tuple_count = 0;
        double          tuple_percent;
        double          dead_tuple_percent;
 
-       Buffer          buffer = InvalidBuffer;
        uint64          free_space = 0; /* free/reusable space in bytes */
        double          free_percent;   /* free/reusable space in % */
 
-       rel = heap_openr(NameStr(*p), NoLock);
+       rel = heap_openr(NameStr(*p), AccessShareLock);
        nblocks = RelationGetNumberOfBlocks(rel);
        scan = heap_beginscan(rel, false, SnapshotAny, 0, NULL);
 
@@ -78,17 +80,33 @@ pgstattuple(PG_FUNCTION_ARGS)
                        dead_tuple_count++;
                }
 
-               if (!BlockNumberIsValid(block) ||
-                       block != BlockIdGetBlockNumber(&tuple->t_self.ip_blkid))
+               /*
+                * To avoid physically reading the table twice, try to do the
+                * free-space scan in parallel with the heap scan.  However,
+                * heap_getnext may find no tuples on a given page, so we cannot
+                * simply examine the pages returned by the heap scan.
+                */
+               tupblock = BlockIdGetBlockNumber(&tuple->t_self.ip_blkid);
+
+               while (block <= tupblock)
                {
-                       block = BlockIdGetBlockNumber(&tuple->t_self.ip_blkid);
                        buffer = ReadBuffer(rel, block);
                        free_space += PageGetFreeSpace((Page) BufferGetPage(buffer));
                        ReleaseBuffer(buffer);
+                       block++;
                }
        }
        heap_endscan(scan);
-       heap_close(rel, NoLock);
+
+       while (block < nblocks)
+       {
+               buffer = ReadBuffer(rel, block);
+               free_space += PageGetFreeSpace((Page) BufferGetPage(buffer));
+               ReleaseBuffer(buffer);
+               block++;
+       }
+
+       heap_close(rel, AccessShareLock);
 
        table_len = (double) nblocks *BLCKSZ;
 
@@ -105,20 +123,20 @@ pgstattuple(PG_FUNCTION_ARGS)
                free_percent = (double) free_space *100.0 / table_len;
        }
 
-       elog(NOTICE, "physical length: %.2fMB live tuples: %u (%.2fMB, %.2f%%) dead tuples: %u (%.2fMB, %.2f%%) free/reusable space: %.2fMB (%.2f%%) overhead: %.2f%%",
+       elog(NOTICE, "physical length: %.2fMB live tuples: %.0f (%.2fMB, %.2f%%) dead tuples: %.0f (%.2fMB, %.2f%%) free/reusable space: %.2fMB (%.2f%%) overhead: %.2f%%",
 
-                table_len / 1024 / 1024,               /* phsical length in MB */
+                table_len / (1024 * 1024),             /* physical length in MB */
 
-                tuple_count,                   /* number of live tuples */
-                (double) tuple_len / 1024 / 1024,              /* live tuples in MB */
+                (double) tuple_count,  /* number of live tuples */
+                (double) tuple_len / (1024 * 1024),            /* live tuples in MB */
                 tuple_percent,                 /* live tuples in % */
 
-                dead_tuple_count,              /* number of dead tuples */
-                (double) dead_tuple_len / 1024 / 1024, /* dead tuples in MB */
+                (double) dead_tuple_count,     /* number of dead tuples */
+                (double) dead_tuple_len / (1024 * 1024), /* dead tuples in MB */
                 dead_tuple_percent,    /* dead tuples in % */
 
-                (double) free_space / 1024 / 1024,             /* free/available space in
-                                                                                                * MB */
+                (double) free_space / (1024 * 1024), /* free/available space in
+                                                                                          * MB */
 
                 free_percent,                  /* free/available space in % */