relation_free_space-v5.1.patch
text/x-patch
Filename: relation_free_space-v5.1.patch
Type: text/x-patch
Part: 1
Message:
Re: Measuring relation free space
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
Series: patch v5
| File | + | − |
|---|---|---|
| contrib/pageinspect/btreefuncs.c | 0 | 0 |
| contrib/pageinspect/btreefuncs.h | 0 | 0 |
| contrib/pageinspect/idxfuncs.c | 0 | 0 |
| contrib/pageinspect/idxfuncs.h | 0 | 0 |
| contrib/pageinspect/Makefile | 0 | 0 |
| contrib/pageinspect/rawpage.c | 0 | 0 |
diff --git a/contrib/pageinspect/Makefile b/contrib/pageinspect/Makefile
new file mode 100644
index 63fab95..f63b92f
*** a/contrib/pageinspect/Makefile
--- b/contrib/pageinspect/Makefile
***************
*** 1,7 ****
# contrib/pageinspect/Makefile
MODULE_big = pageinspect
! OBJS = rawpage.o heapfuncs.o btreefuncs.o fsmfuncs.o
EXTENSION = pageinspect
DATA = pageinspect--1.0.sql pageinspect--1.1.sql \
--- 1,7 ----
# contrib/pageinspect/Makefile
MODULE_big = pageinspect
! OBJS = rawpage.o heapfuncs.o btreefuncs.o idxfuncs.o fsmfuncs.o
EXTENSION = pageinspect
DATA = pageinspect--1.0.sql pageinspect--1.1.sql \
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
new file mode 100644
index 9c0b0fb..b399b85
*** a/contrib/pageinspect/btreefuncs.c
--- b/contrib/pageinspect/btreefuncs.c
***************
*** 34,41 ****
#include "utils/builtins.h"
#include "utils/rel.h"
- #include "btreefuncs.h"
-
extern Datum bt_metap(PG_FUNCTION_ARGS);
extern Datum bt_page_items(PG_FUNCTION_ARGS);
extern Datum bt_page_stats(PG_FUNCTION_ARGS);
--- 34,39 ----
*************** GetBTPageStatistics(BlockNumber blkno, B
*** 156,216 ****
stat->avg_item_size = 0;
}
- /*------------------------------------------------
- * GetBTRelationFreeSpace
- *
- * Get the free space for a btree index.
- * This is a helper function for relation_free_space()
- *------------------------------------------------
- */
- float4
- GetBTRelationFreeSpace(Relation rel)
- {
- BTPageStat stat;
-
- Buffer buffer;
- BlockNumber blkno;
- BlockNumber totalBlcksInRelation = RelationGetNumberOfBlocks(rel);
- BlockNumber totalBlcksCounted = 0;
- Size free_space = 0;
- double free_percent = 0;
-
- BufferAccessStrategy bstrategy = GetAccessStrategy(BAS_BULKREAD);
-
- /* Skip page 0 because it is a metapage */
- for (blkno = 1; blkno < totalBlcksInRelation; blkno++)
- {
- buffer = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy);
- /*
- * get the statistics of the indexes and use that info
- * to determine free space on the page
- */
- GetBTPageStatistics(blkno, buffer, &stat);
- /*
- * Consider pages DELETED and HALF_DEAD as empty,
- * besides those only consider LEAF pages
- */
- if (stat.type == 'd' || stat.type == 'e')
- {
- free_space += stat.page_size;
- totalBlcksCounted++;
- }
- else if (stat.type == 'l')
- {
- free_space += stat.free_size;
- totalBlcksCounted++;
- }
-
- ReleaseBuffer(buffer);
- }
-
- if (totalBlcksCounted > 0)
- free_percent = ((float4) free_space) / (totalBlcksCounted * BLCKSZ);
-
- return free_percent;
- }
-
-
/* -----------------------------------------------
* bt_page()
*
--- 154,159 ----
diff --git a/contrib/pageinspect/btreefuncs.h b/contrib/pageinspect/btreefuncs.h
new file mode .
index 549f878..e69de29
*** a/contrib/pageinspect/btreefuncs.h
--- b/contrib/pageinspect/btreefuncs.h
***************
*** 1,5 ****
- /*
- * contrib/pageinspect/btreefuncs.h
- */
-
- float4 GetBTRelationFreeSpace(Relation);
--- 0 ----
diff --git a/contrib/pageinspect/idxfuncs.c b/contrib/pageinspect/idxfuncs.c
new file mode 100644
index ...6533429
*** a/contrib/pageinspect/idxfuncs.c
--- b/contrib/pageinspect/idxfuncs.c
***************
*** 0 ****
--- 1,313 ----
+ /*
+ * contrib/pageinspect/idxfuncs.c
+ *
+ *
+ * idxfuncs.c
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose, without fee, and without a
+ * written agreement is hereby granted, provided that the above
+ * copyright notice and this paragraph and the following two
+ * paragraphs appear in all copies.
+ *
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT,
+ * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
+ * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
+ * DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS
+ * IS" BASIS, AND THE AUTHOR HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE,
+ * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+ #include "postgres.h"
+
+ #include "access/gin_private.h"
+ #include "access/gist_private.h"
+ #include "access/hash.h"
+ #include "access/nbtree.h"
+ #include "access/spgist_private.h"
+ #include "funcapi.h"
+ #include "utils/rel.h"
+
+ #include "idxfuncs.h"
+
+ /*------------------------------------------------
+ * GetIndexRelationFreeSpace
+ *
+ * Look the type of the index and call the appropiate
+ * function to get the free space
+ *------------------------------------------------
+ */
+ float4
+ GetIndexRelationFreeSpace(Relation rel)
+ {
+ switch (rel->rd_rel->relam)
+ {
+ case BTREE_AM_OID:
+ return GetBTRelationFreeSpace(rel);
+ case HASH_AM_OID:
+ return GetHashRelationFreeSpace(rel);
+ case GIST_AM_OID:
+ return GetGistRelationFreeSpace(rel);
+ case GIN_AM_OID:
+ return GetGinRelationFreeSpace(rel);
+ case SPGIST_AM_OID:
+ return GetSpGistRelationFreeSpace(rel);
+ default:
+ elog(ERROR, "Unknown index type %d", rel->rd_rel->relam);
+ }
+
+ return 0;
+ }
+
+ /*------------------------------------------------
+ * GetBTRelationFreeSpace
+ *
+ * Get the free space for a btree index.
+ * This is a helper function for relation_free_space()
+ *------------------------------------------------
+ */
+ float4
+ GetBTRelationFreeSpace(Relation rel)
+ {
+ BlockNumber blkno;
+ BlockNumber totalBlcksInRelation = RelationGetNumberOfBlocks(rel);
+ BlockNumber totalBlcksCounted = 0;
+ Size free_space = 0;
+ double free_percent = 0;
+
+ BufferAccessStrategy bstrategy = GetAccessStrategy(BAS_BULKREAD);
+
+ /* Start just after the metapage */
+ for (blkno = BTREE_METAPAGE + 1; blkno < totalBlcksInRelation; blkno++)
+ {
+ Buffer buffer = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy);
+ Page page = BufferGetPage(buffer);
+ BTPageOpaque opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+
+ /*
+ * Consider pages DELETED and HALF_DEAD as empty,
+ * besides those only consider LEAF pages
+ */
+ if (P_ISDELETED(opaque) || P_ISHALFDEAD(opaque))
+ {
+ free_space += PageGetPageSize(page);
+ totalBlcksCounted++;
+ }
+ else if (P_ISLEAF(opaque))
+ {
+ free_space += PageGetFreeSpace(page);
+ totalBlcksCounted++;
+ }
+
+ ReleaseBuffer(buffer);
+ }
+
+ if (totalBlcksCounted > 0)
+ free_percent = ((float4) free_space) / (totalBlcksCounted * BLCKSZ);
+
+ return free_percent;
+ }
+
+
+ /*------------------------------------------------
+ * GetHashRelationFreeSpace
+ *
+ * Get the free space for a Hash index.
+ * This is a helper function for relation_free_space()
+ *------------------------------------------------
+ */
+ float4
+ GetHashRelationFreeSpace(Relation rel)
+ {
+ BlockNumber blkno;
+ BlockNumber totalBlcksInRelation = RelationGetNumberOfBlocks(rel);
+ BlockNumber totalBlcksCounted = 0;
+ Size free_space = 0;
+ double free_percent = 0;
+
+ BufferAccessStrategy bstrategy = GetAccessStrategy(BAS_BULKREAD);
+
+ /* Start just after the metapage */
+ for (blkno = HASH_METAPAGE + 1; blkno < totalBlcksInRelation; blkno++)
+ {
+ Buffer buffer = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy);
+ Page page = BufferGetPage(buffer);
+ HashPageOpaque opaque = (HashPageOpaque) PageGetSpecialPointer(page);
+
+ /*
+ * Consider pages LH_UNUSED_PAGE as empty,
+ * besides that consider the free space in LH_OVERFLOW_PAGE and LH_BUCKET_PAGE pages
+ */
+ if (opaque->hasho_flag == LH_UNUSED_PAGE)
+ {
+ free_space += PageGetPageSize(page);
+ totalBlcksCounted++;
+ }
+ else if (opaque->hasho_flag == LH_OVERFLOW_PAGE || opaque->hasho_flag == LH_BUCKET_PAGE)
+ {
+ free_space += PageGetFreeSpace(page);
+ totalBlcksCounted++;
+ }
+
+ ReleaseBuffer(buffer);
+ }
+
+ if (totalBlcksCounted > 0)
+ free_percent = ((float4) free_space) / (totalBlcksCounted * BLCKSZ);
+
+ return free_percent;
+ }
+
+ /*------------------------------------------------
+ * GetGistRelationFreeSpace
+ *
+ * Get the free space for a Gist index.
+ * This is a helper function for relation_free_space()
+ *------------------------------------------------
+ */
+ float4
+ GetGistRelationFreeSpace(Relation rel)
+ {
+ BlockNumber blkno;
+ BlockNumber totalBlcksInRelation = RelationGetNumberOfBlocks(rel);
+ BlockNumber totalBlcksCounted = 0;
+ Size free_space = 0;
+ double free_percent = 0;
+
+ BufferAccessStrategy bstrategy = GetAccessStrategy(BAS_BULKREAD);
+
+ /* Start from the root */
+ for (blkno = GIST_ROOT_BLKNO; blkno < totalBlcksInRelation; blkno++)
+ {
+ Buffer buffer = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy);
+ Page page = BufferGetPage(buffer);
+
+ /*
+ * Consider pages LH_UNUSED_PAGE as empty,
+ * besides that consider the free space in LH_OVERFLOW_PAGE and LH_BUCKET_PAGE pages
+ */
+ if (GistPageIsDeleted(page))
+ {
+ free_space += PageGetPageSize(page);
+ totalBlcksCounted++;
+ }
+ else if (GistPageIsLeaf(page))
+ {
+ free_space += PageGetFreeSpace(page);
+ totalBlcksCounted++;
+ }
+
+ ReleaseBuffer(buffer);
+ }
+
+ if (totalBlcksCounted > 0)
+ free_percent = ((float4) free_space) / (totalBlcksCounted * BLCKSZ);
+
+ return free_percent;
+ }
+
+ /*------------------------------------------------
+ * GetGinRelationFreeSpace
+ *
+ * Get the free space for a Gin index.
+ * This is a helper function for relation_free_space()
+ *------------------------------------------------
+ */
+ float4
+ GetGinRelationFreeSpace(Relation rel)
+ {
+ BlockNumber blkno;
+ BlockNumber totalBlcksInRelation = RelationGetNumberOfBlocks(rel);
+ BlockNumber totalBlcksCounted = 0;
+ Size free_space = 0;
+ double free_percent = 0;
+
+ BufferAccessStrategy bstrategy = GetAccessStrategy(BAS_BULKREAD);
+
+ /* Start just after the first root */
+ for (blkno = GIN_METAPAGE_BLKNO + 1; blkno < totalBlcksInRelation; blkno++)
+ {
+ Buffer buffer = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy);
+ Page page = BufferGetPage(buffer);
+
+ /*
+ * Consider pages GIN_DELETED as empty,
+ * besides that consider the free space in GIN_DATA and GIN_LEAF pages
+ */
+ if (GinPageIsDeleted(page))
+ {
+ free_space += PageGetPageSize(page);
+ totalBlcksCounted++;
+ }
+ else if (GinPageIsLeaf(page))
+ {
+ free_space += PageGetFreeSpace(page);
+ totalBlcksCounted++;
+ }
+ else if (GinPageIsData(page))
+ {
+ free_space += GinDataPageGetFreeSpace(page);
+ totalBlcksCounted++;
+ }
+
+ ReleaseBuffer(buffer);
+ }
+
+ if (totalBlcksCounted > 0)
+ free_percent = ((float4) free_space) / (totalBlcksCounted * BLCKSZ);
+
+ return free_percent;
+ }
+
+ /*------------------------------------------------
+ * GetSPGistRelationFreeSpace
+ *
+ * Get the free space for a SPGist index.
+ * This is a helper function for relation_free_space()
+ *------------------------------------------------
+ */
+ float4
+ GetSpGistRelationFreeSpace(Relation rel)
+ {
+ BlockNumber blkno;
+ BlockNumber totalBlcksInRelation = RelationGetNumberOfBlocks(rel);
+ BlockNumber totalBlcksCounted = 0;
+ Size free_space = 0;
+ double free_percent = 0;
+
+ BufferAccessStrategy bstrategy = GetAccessStrategy(BAS_BULKREAD);
+
+ /* Start just after the first root */
+ for (blkno = SPGIST_METAPAGE_BLKNO + 1; blkno < totalBlcksInRelation; blkno++)
+ {
+ Buffer buffer = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy);
+ Page page = BufferGetPage(buffer);
+
+ /*
+ * Consider pages GIN_DELETED as empty,
+ * besides that consider the free space in GIN_DATA and GIN_LEAF pages
+ */
+ if (SpGistPageIsDeleted(page))
+ {
+ free_space += PageGetPageSize(page);
+ totalBlcksCounted++;
+ }
+ else if (SpGistPageIsLeaf(page))
+ {
+ free_space += SpGistPageGetFreeSpace(page, 1);
+ totalBlcksCounted++;
+ }
+
+ ReleaseBuffer(buffer);
+ }
+
+ if (totalBlcksCounted > 0)
+ free_percent = ((float4) free_space) / (totalBlcksCounted * BLCKSZ);
+
+ return free_percent;
+ }
diff --git a/contrib/pageinspect/idxfuncs.h b/contrib/pageinspect/idxfuncs.h
new file mode 100644
index ...788d920
*** a/contrib/pageinspect/idxfuncs.h
--- b/contrib/pageinspect/idxfuncs.h
***************
*** 0 ****
--- 1,10 ----
+ /*
+ * contrib/pageinspect/idxfuncs.h
+ */
+
+ float4 GetIndexRelationFreeSpace(Relation);
+ float4 GetBTRelationFreeSpace(Relation);
+ float4 GetHashRelationFreeSpace(Relation);
+ float4 GetGistRelationFreeSpace(Relation);
+ float4 GetGinRelationFreeSpace(Relation);
+ float4 GetSpGistRelationFreeSpace(Relation);
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
new file mode 100644
index 9a54744..99fccab
*** a/contrib/pageinspect/rawpage.c
--- b/contrib/pageinspect/rawpage.c
***************
*** 23,30 ****
#include "utils/builtins.h"
#include "utils/rel.h"
- #include "btreefuncs.h"
#include "heapfuncs.h"
PG_MODULE_MAGIC;
--- 23,30 ----
#include "utils/builtins.h"
#include "utils/rel.h"
#include "heapfuncs.h"
+ #include "idxfuncs.h"
PG_MODULE_MAGIC;
*************** relation_free_space(PG_FUNCTION_ARGS)
*** 276,282 ****
free_space = GetHeapRelationFreeSpace(rel);
break;
case RELKIND_INDEX:
! free_space = GetBTRelationFreeSpace(rel);
break;
}
relation_close(rel, AccessShareLock);
--- 276,282 ----
free_space = GetHeapRelationFreeSpace(rel);
break;
case RELKIND_INDEX:
! free_space = GetIndexRelationFreeSpace(rel);
break;
}
relation_close(rel, AccessShareLock);