Attached is a patch that addresses the todo item "Improve relation
size functions such as pg_relation_size() to avoid producing an error
when called against a no longer visible relation."
http://archives.postgresql.org/pgsql-general/2010-10/msg00332.php
Instead of returning an error, they now return NULL if the OID is
found in pg_class when using SnapshotAny. I only applied it to 4
functions: select pg_relation_size, pg_total_relation_size,
pg_table_size and pg_indexes_size. These are the ones that were using
relation_open(). I changed them to using try_relation_open(). For
three of them I had to move the try_relation_open() call up one level
in the call stack and change the parameter types for some support
functions from Oid to Relation. They now also call a new function
relation_recently_dead() which is what checks for relation in
SnapshotAny. All regression tests passed.
Is SnapshotAny the snapshot I should be using? It seems to get the
correct results. I can drop a table and I get NULL. Then after a
vacuumdb it returns an error.
diff --git a/src/backend/utils/adt/dbsize.c b/src/backend/utils/adt/dbsize.c
new file mode 100644
index 2ee5966..0623935
*** a/src/backend/utils/adt/dbsize.c
--- b/src/backend/utils/adt/dbsize.c
***************
*** 24,32 ****
--- 24,34 ----
#include "storage/fd.h"
#include "utils/acl.h"
#include "utils/builtins.h"
+ #include "utils/fmgroids.h"
#include "utils/rel.h"
#include "utils/relmapper.h"
#include "utils/syscache.h"
+ #include "utils/tqual.h"
/* Return physical size of directory contents, or 0 if dir doesn't exist */
*************** calculate_relation_size(RelFileNode *rfn
*** 281,286 ****
--- 283,321 ----
return totalsize;
}
+ /*
+ * relation_recently_dead
+ *
+ * Check to see if a relation exists in SnapshotAny
+ */
+ static bool
+ relation_recently_dead(Oid relOid)
+ {
+ Relation classRel;
+ ScanKeyData key[1];
+ HeapScanDesc scan;
+ bool status;
+
+ classRel = heap_open(RelationRelationId, AccessShareLock);
+
+ ScanKeyInit(&key[0],
+ Anum_pg_class_relfilenode,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(relOid));
+
+ scan = heap_beginscan(classRel, SnapshotAny, 1, key);
+
+ if (heap_getnext(scan, ForwardScanDirection) != NULL)
+ status = true;
+ else
+ status = false;
+
+ heap_endscan(scan);
+ heap_close(classRel, AccessShareLock);
+
+ return status;
+ }
+
Datum
pg_relation_size(PG_FUNCTION_ARGS)
{
*************** pg_relation_size(PG_FUNCTION_ARGS)
*** 289,295 ****
Relation rel;
int64 size;
! rel = relation_open(relOid, AccessShareLock);
size = calculate_relation_size(&(rel->rd_node), rel->rd_backend,
forkname_to_number(text_to_cstring(forkName)));
--- 324,338 ----
Relation rel;
int64 size;
! rel = try_relation_open(relOid, AccessShareLock);
!
! if (rel == NULL)
! {
! if ((relOid != 0) && relation_recently_dead(relOid))
! PG_RETURN_NULL();
! else
! elog(ERROR, "could not open relation with OID %u", relOid);
! }
size = calculate_relation_size(&(rel->rd_node), rel->rd_backend,
forkname_to_number(text_to_cstring(forkName)));
*************** calculate_toast_table_size(Oid toastreli
*** 339,352 ****
* those won't have attached toast tables, but they can have multiple forks.
*/
static int64
! calculate_table_size(Oid relOid)
{
int64 size = 0;
- Relation rel;
ForkNumber forkNum;
- rel = relation_open(relOid, AccessShareLock);
-
/*
* heap size, including FSM and VM
*/
--- 382,392 ----
* those won't have attached toast tables, but they can have multiple forks.
*/
static int64
! calculate_table_size(Relation rel)
{
int64 size = 0;
ForkNumber forkNum;
/*
* heap size, including FSM and VM
*/
*************** calculate_table_size(Oid relOid)
*** 360,367 ****
if (OidIsValid(rel->rd_rel->reltoastrelid))
size += calculate_toast_table_size(rel->rd_rel->reltoastrelid);
- relation_close(rel, AccessShareLock);
-
return size;
}
--- 400,405 ----
*************** calculate_table_size(Oid relOid)
*** 371,382 ****
* Can be applied safely to an index, but you'll just get zero.
*/
static int64
! calculate_indexes_size(Oid relOid)
{
int64 size = 0;
- Relation rel;
-
- rel = relation_open(relOid, AccessShareLock);
/*
* Aggregate all indexes on the given relation
--- 409,417 ----
* Can be applied safely to an index, but you'll just get zero.
*/
static int64
! calculate_indexes_size(Relation rel)
{
int64 size = 0;
/*
* Aggregate all indexes on the given relation
*************** calculate_indexes_size(Oid relOid)
*** 405,412 ****
list_free(index_oids);
}
- relation_close(rel, AccessShareLock);
-
return size;
}
--- 440,445 ----
*************** Datum
*** 414,429 ****
pg_table_size(PG_FUNCTION_ARGS)
{
Oid relOid = PG_GETARG_OID(0);
! PG_RETURN_INT64(calculate_table_size(relOid));
}
Datum
pg_indexes_size(PG_FUNCTION_ARGS)
{
Oid relOid = PG_GETARG_OID(0);
! PG_RETURN_INT64(calculate_indexes_size(relOid));
}
/*
--- 447,494 ----
pg_table_size(PG_FUNCTION_ARGS)
{
Oid relOid = PG_GETARG_OID(0);
+ Relation rel;
+ int64 size;
! rel = try_relation_open(relOid, AccessShareLock);
!
! if (rel == NULL)
! {
! if ((relOid != 0) && relation_recently_dead(relOid))
! PG_RETURN_NULL();
! else
! elog(ERROR, "could not open relation with OID %u", relOid);
! }
!
! size = calculate_table_size(rel);
!
! relation_close(rel, AccessShareLock);
!
! PG_RETURN_INT64(size);
}
Datum
pg_indexes_size(PG_FUNCTION_ARGS)
{
Oid relOid = PG_GETARG_OID(0);
+ Relation rel;
+ int64 size;
! rel = try_relation_open(relOid, AccessShareLock);
!
! if (rel == NULL)
! {
! if ((relOid != 0) && relation_recently_dead(relOid))
! PG_RETURN_NULL();
! else
! elog(ERROR, "could not open relation with OID %u", relOid);
! }
!
! size = calculate_indexes_size(rel);
!
! relation_close(rel, AccessShareLock);
!
! PG_RETURN_INT64(size);
}
/*
*************** pg_indexes_size(PG_FUNCTION_ARGS)
*** 431,437 ****
* including heap data, index data, toast data, FSM, VM.
*/
static int64
! calculate_total_relation_size(Oid Relid)
{
int64 size;
--- 496,502 ----
* including heap data, index data, toast data, FSM, VM.
*/
static int64
! calculate_total_relation_size(Relation Rel)
{
int64 size;
*************** calculate_total_relation_size(Oid Relid)
*** 439,450 ****
* Aggregate the table size, this includes size of the heap, toast and
* toast index with free space and visibility map
*/
! size = calculate_table_size(Relid);
/*
* Add size of all attached indexes as well
*/
! size += calculate_indexes_size(Relid);
return size;
}
--- 504,515 ----
* Aggregate the table size, this includes size of the heap, toast and
* toast index with free space and visibility map
*/
! size = calculate_table_size(Rel);
/*
* Add size of all attached indexes as well
*/
! size += calculate_indexes_size(Rel);
return size;
}
*************** calculate_total_relation_size(Oid Relid)
*** 452,460 ****
Datum
pg_total_relation_size(PG_FUNCTION_ARGS)
{
! Oid relid = PG_GETARG_OID(0);
! PG_RETURN_INT64(calculate_total_relation_size(relid));
}
/*
--- 517,541 ----
Datum
pg_total_relation_size(PG_FUNCTION_ARGS)
{
! Oid relOid = PG_GETARG_OID(0);
! Relation rel;
! int64 size;
! rel = try_relation_open(relOid, AccessShareLock);
!
! if (rel == NULL)
! {
! if ((relOid != 0) && relation_recently_dead(relOid))
! PG_RETURN_NULL();
! else
! elog(ERROR, "could not open relation with OID %u", relOid);
! }
!
! size = calculate_total_relation_size(rel);
!
! relation_close(rel, AccessShareLock);
!
! PG_RETURN_INT64(size);
}
/*
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers