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 (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers