]> granicus.if.org Git - postgresql/commitdiff
tableam: Don't assume that every AM uses md.c style storage.
authorAndres Freund <andres@anarazel.de>
Sat, 18 May 2019 01:06:18 +0000 (18:06 -0700)
committerAndres Freund <andres@anarazel.de>
Sat, 18 May 2019 01:56:47 +0000 (18:56 -0700)
Previously various parts of the code routed size requests through
RelationGetNumberOfBlocks[InFork]. That works if md.c is used by the
AM, but not otherwise.

Add a tableam callback to return the size of the table. As not every
AM will use postgres' BLCKSZ, have it return bytes, and have
RelationGetNumberOfBlocksInFork() round the byte size up into blocks.

To allow code outside of the AM to determine the actual relation size
map InvalidForkNumber the total size of a relation, as not every AM
might just need the postgres defined forks.

A few users of RelationGetNumberOfBlocks() ought to be converted away
from that. One case, the use of it to determine whether a tid is
valid, will be fixed in a follow up commit. Others will have to wait
for v13.

Author: Andres Freund
Discussion: https://postgr.es/m/20190423225201.3bbv6tbqzkb5w7cw@alap3.anarazel.de

src/backend/access/heap/heapam_handler.c
src/backend/access/table/tableamapi.c
src/backend/storage/buffer/bufmgr.c
src/include/access/tableam.h

index 00505ec3f4d8d7447a5ca6620814512a64b5fe75..9aa468295ae9246e2e0c43fb45314a67ff9b0833 100644 (file)
@@ -1975,6 +1975,31 @@ heapam_scan_get_blocks_done(HeapScanDesc hscan)
 }
 
 
+/* ------------------------------------------------------------------------
+ * Miscellaneous callbacks for the heap AM
+ * ------------------------------------------------------------------------
+ */
+
+static uint64
+heapam_relation_size(Relation rel, ForkNumber forkNumber)
+{
+       uint64          nblocks = 0;
+
+       /* Open it at the smgr level if not already done */
+       RelationOpenSmgr(rel);
+
+       /* InvalidForkNumber indicates returning the size for all forks */
+       if (forkNumber == InvalidForkNumber)
+       {
+               for (int i = 0; i < MAX_FORKNUM; i++)
+                       nblocks += smgrnblocks(rel->rd_smgr, i);
+       }
+       else
+               nblocks = smgrnblocks(rel->rd_smgr, forkNumber);
+
+       return nblocks * BLCKSZ;
+}
+
 
 /* ------------------------------------------------------------------------
  * Planner related callbacks for the heap AM
@@ -2556,6 +2581,8 @@ static const TableAmRoutine heapam_methods = {
        .index_build_range_scan = heapam_index_build_range_scan,
        .index_validate_scan = heapam_index_validate_scan,
 
+       .relation_size = heapam_relation_size,
+
        .relation_estimate_size = heapam_estimate_rel_size,
 
        .scan_bitmap_next_block = heapam_scan_bitmap_next_block,
index 0053dc95cab673ac47b08e367948edc573b0098b..32877e7674f52d5d04a0dd4fe2d80b617791145c 100644 (file)
@@ -86,6 +86,9 @@ GetTableAmRoutine(Oid amhandler)
        Assert(routine->scan_analyze_next_tuple != NULL);
        Assert(routine->index_build_range_scan != NULL);
        Assert(routine->index_validate_scan != NULL);
+
+       Assert(routine->relation_size != NULL);
+
        Assert(routine->relation_estimate_size != NULL);
 
        /* optional, but one callback implies presence of hte other */
index 887023fc8a5a20ad93f1eadbcee0cee6d410677f..33d7941a405c879339d330198eb128d32741e577 100644 (file)
@@ -33,6 +33,7 @@
 #include <sys/file.h>
 #include <unistd.h>
 
+#include "access/tableam.h"
 #include "access/xlog.h"
 #include "catalog/catalog.h"
 #include "catalog/storage.h"
@@ -2789,14 +2790,50 @@ FlushBuffer(BufferDesc *buf, SMgrRelation reln)
 /*
  * RelationGetNumberOfBlocksInFork
  *             Determines the current number of pages in the specified relation fork.
+ *
+ * Note that the accuracy of the result will depend on the details of the
+ * relation's storage. For builtin AMs it'll be accurate, but for external AMs
+ * it might not be.
  */
 BlockNumber
 RelationGetNumberOfBlocksInFork(Relation relation, ForkNumber forkNum)
 {
-       /* Open it at the smgr level if not already done */
-       RelationOpenSmgr(relation);
+       switch (relation->rd_rel->relkind)
+       {
+               case RELKIND_SEQUENCE:
+               case RELKIND_INDEX:
+               case RELKIND_PARTITIONED_INDEX:
+                       /* Open it at the smgr level if not already done */
+                       RelationOpenSmgr(relation);
+
+                       return smgrnblocks(relation->rd_smgr, forkNum);
+
+               case RELKIND_RELATION:
+               case RELKIND_TOASTVALUE:
+               case RELKIND_MATVIEW:
+                       {
+                               /*
+                                * Not every table AM uses BLCKSZ wide fixed size
+                                * blocks. Therefore tableam returns the size in bytes - but
+                                * for the purpose of this routine, we want the number of
+                                * blocks. Therefore divide, rounding up.
+                                */
+                               uint64 szbytes;
+
+                               szbytes = table_relation_size(relation, forkNum);
+
+                               return (szbytes + (BLCKSZ - 1)) / BLCKSZ;
+                       }
+               case RELKIND_VIEW:
+               case RELKIND_COMPOSITE_TYPE:
+               case RELKIND_FOREIGN_TABLE:
+               case RELKIND_PARTITIONED_TABLE:
+               default:
+                       Assert(false);
+                       break;
+       }
 
-       return smgrnblocks(relation->rd_smgr, forkNum);
+       return 0;                                       /* keep compiler quiet */
 }
 
 /*
index ebfa0d51855cd381de75f4a18598ab563c753dc2..c5d64602036a31eb121f8ad9de61492c98a4c1fb 100644 (file)
@@ -540,6 +540,22 @@ typedef struct TableAmRoutine
                                                                                struct ValidateIndexState *state);
 
 
+       /* ------------------------------------------------------------------------
+        * Miscellaneous functions.
+        * ------------------------------------------------------------------------
+        */
+
+       /*
+        * See table_relation_size().
+        *
+        * Note that currently a few callers use the MAIN_FORKNUM size to vet the
+        * validity of tids (e.g. nodeTidscans.c), and others use it to figure out
+        * the range of potentially interesting blocks (brin, analyze). The
+        * abstraction around this will need to be improved in the near future.
+        */
+       uint64          (*relation_size) (Relation rel, ForkNumber forkNumber);
+
+
        /* ------------------------------------------------------------------------
         * Planner related functions.
         * ------------------------------------------------------------------------
@@ -550,6 +566,10 @@ typedef struct TableAmRoutine
         *
         * While block oriented, it shouldn't be too hard for an AM that doesn't
         * doesn't internally use blocks to convert into a usable representation.
+        *
+        * This differs from the relation_size callback by returning size
+        * estimates (both relation size and tuple count) for planning purposes,
+        * rather than returning a currently correct estimate.
         */
        void            (*relation_estimate_size) (Relation rel, int32 *attr_widths,
                                                                                   BlockNumber *pages, double *tuples,
@@ -1503,6 +1523,26 @@ table_index_validate_scan(Relation heap_rel,
 }
 
 
+/* ----------------------------------------------------------------------------
+ * Miscellaneous functionality
+ * ----------------------------------------------------------------------------
+ */
+
+/*
+ * Return the current size of `rel` in bytes. If `forkNumber` is
+ * InvalidForkNumber, return the relation's overall size, otherwise the size
+ * for the indicated fork.
+ *
+ * Note that the overall size might not be the equivalent of the sum of sizes
+ * for the individual forks for some AMs, e.g. because the AMs storage does
+ * not neatly map onto the builtin types of forks.
+ */
+static inline uint64
+table_relation_size(Relation rel, ForkNumber forkNumber)
+{
+       return rel->rd_tableam->relation_size(rel, forkNumber);
+}
+
 /* ----------------------------------------------------------------------------
  * Planner related functionality
  * ----------------------------------------------------------------------------