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