]> granicus.if.org Git - postgresql/commitdiff
Fix pg_buffercache to release buffer partition locks in reverse order,
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 16 Jul 2007 21:20:36 +0000 (21:20 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 16 Jul 2007 21:20:36 +0000 (21:20 +0000)
and add a note about why.  This is not tremendously important right now,
probably, but it will get more urgent if NUM_BUFFER_PARTITIONS is increased
as much as proposed.

contrib/pg_buffercache/pg_buffercache_pages.c

index 991c3db8e251daba873a451ec594361b48f3e943..e7c5b06a563bfcc62ae236203dfab2a0133abb0e 100644 (file)
@@ -3,7 +3,7 @@
  * pg_buffercache_pages.c
  *       display some contents of the buffer cache
  *
- *       $PostgreSQL: pgsql/contrib/pg_buffercache/pg_buffercache_pages.c,v 1.12 2007/04/07 16:09:14 momjian Exp $
+ *       $PostgreSQL: pgsql/contrib/pg_buffercache/pg_buffercache_pages.c,v 1.13 2007/07/16 21:20:36 tgl Exp $
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
@@ -110,7 +110,8 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
                /*
                 * To get a consistent picture of the buffer state, we must lock all
                 * partitions of the buffer map.  Needless to say, this is horrible
-                * for concurrency...
+                * for concurrency.  Must grab locks in increasing order to avoid
+                * possible deadlocks.
                 */
                for (i = 0; i < NUM_BUFFER_PARTITIONS; i++)
                        LWLockAcquire(FirstBufMappingLock + i, LW_SHARED);
@@ -145,8 +146,14 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
                        UnlockBufHdr(bufHdr);
                }
 
-               /* Release Buffer map. */
-               for (i = 0; i < NUM_BUFFER_PARTITIONS; i++)
+               /*
+                * And release locks.  We do this in reverse order for two reasons:
+                * (1) Anyone else who needs more than one of the locks will be trying
+                * to lock them in increasing order; we don't want to release the other
+                * process until it can get all the locks it needs.
+                * (2) This avoids O(N^2) behavior inside LWLockRelease.
+                */
+               for (i = NUM_BUFFER_PARTITIONS; --i >= 0;)
                        LWLockRelease(FirstBufMappingLock + i);
        }