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

Reply via email to