On Mon, Dec 19, 2011 at 1:27 PM, Phil Sorber <p...@omniti.com> wrote: > On Sat, Dec 17, 2011 at 3:52 PM, Phil Sorber <p...@omniti.com> wrote: >> 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. > > Something I'd like to point out myself is that I need to be using > ObjectIdAttributeNumber instead of Anum_pg_class_relfilenode. Probably > just luck that I got the intended results before. This will also > change the logic in a few other places. > > Still not clear on the semantics of Snapshot{Any|Self|Now|Dirty}.
I've attached the updated version of my patch with the changes mentioned in the previous email.
diff --git a/src/backend/utils/adt/dbsize.c b/src/backend/utils/adt/dbsize.c new file mode 100644 index 2ee5966..bc2c862 *** a/src/backend/utils/adt/dbsize.c --- b/src/backend/utils/adt/dbsize.c *************** *** 15,20 **** --- 15,21 ---- #include <sys/stat.h> #include "access/heapam.h" + #include "access/sysattr.h" #include "catalog/catalog.h" #include "catalog/namespace.h" #include "catalog/pg_tablespace.h" *************** *** 24,32 **** --- 25,35 ---- #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 **** --- 284,322 ---- 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], + ObjectIdAttributeNumber, + 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))); --- 325,339 ---- Relation rel; int64 size; ! rel = try_relation_open(relOid, AccessShareLock); ! ! if (rel == NULL) ! { ! if (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 */ --- 383,393 ---- * 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; } --- 401,406 ---- *************** 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 --- 410,418 ---- * 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; } --- 441,446 ---- *************** 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)); } /* --- 448,495 ---- 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 (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 (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; --- 497,503 ---- * 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; } --- 505,516 ---- * 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)); } /* --- 518,542 ---- 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 (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