Skip to content

Commit ae90128

Browse files
committed
Fix NOTIFY to cope with I/O problems, such as out-of-disk-space.
The LISTEN/NOTIFY subsystem got confused if SimpleLruZeroPage failed, which would typically happen as a result of a write() failure while attempting to dump a dirty pg_notify page out of memory. Subsequently, all attempts to send more NOTIFY messages would fail with messages like "Could not read from file "pg_notify/nnnn" at offset nnnnn: Success". Only restarting the server would clear this condition. Per reports from Kevin Grittner and Christoph Berg. Back-patch to 9.0, where the problem was introduced during the LISTEN/NOTIFY rewrite.
1 parent 9e26326 commit ae90128

File tree

1 file changed

+22
-5
lines changed

1 file changed

+22
-5
lines changed

src/backend/commands/async.c

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1285,15 +1285,29 @@ static ListCell *
12851285
asyncQueueAddEntries(ListCell *nextNotify)
12861286
{
12871287
AsyncQueueEntry qe;
1288+
QueuePosition queue_head;
12881289
int pageno;
12891290
int offset;
12901291
int slotno;
12911292

12921293
/* We hold both AsyncQueueLock and AsyncCtlLock during this operation */
12931294
LWLockAcquire(AsyncCtlLock, LW_EXCLUSIVE);
12941295

1296+
/*
1297+
* We work with a local copy of QUEUE_HEAD, which we write back to shared
1298+
* memory upon exiting. The reason for this is that if we have to advance
1299+
* to a new page, SimpleLruZeroPage might fail (out of disk space, for
1300+
* instance), and we must not advance QUEUE_HEAD if it does. (Otherwise,
1301+
* subsequent insertions would try to put entries into a page that slru.c
1302+
* thinks doesn't exist yet.) So, use a local position variable. Note
1303+
* that if we do fail, any already-inserted queue entries are forgotten;
1304+
* this is okay, since they'd be useless anyway after our transaction
1305+
* rolls back.
1306+
*/
1307+
queue_head = QUEUE_HEAD;
1308+
12951309
/* Fetch the current page */
1296-
pageno = QUEUE_POS_PAGE(QUEUE_HEAD);
1310+
pageno = QUEUE_POS_PAGE(queue_head);
12971311
slotno = SimpleLruReadPage(AsyncCtl, pageno, true, InvalidTransactionId);
12981312
/* Note we mark the page dirty before writing in it */
12991313
AsyncCtl->shared->page_dirty[slotno] = true;
@@ -1305,7 +1319,7 @@ asyncQueueAddEntries(ListCell *nextNotify)
13051319
/* Construct a valid queue entry in local variable qe */
13061320
asyncQueueNotificationToEntry(n, &qe);
13071321

1308-
offset = QUEUE_POS_OFFSET(QUEUE_HEAD);
1322+
offset = QUEUE_POS_OFFSET(queue_head);
13091323

13101324
/* Check whether the entry really fits on the current page */
13111325
if (offset + qe.length <= QUEUE_PAGESIZE)
@@ -1331,8 +1345,8 @@ asyncQueueAddEntries(ListCell *nextNotify)
13311345
&qe,
13321346
qe.length);
13331347

1334-
/* Advance QUEUE_HEAD appropriately, and note if page is full */
1335-
if (asyncQueueAdvance(&(QUEUE_HEAD), qe.length))
1348+
/* Advance queue_head appropriately, and detect if page is full */
1349+
if (asyncQueueAdvance(&(queue_head), qe.length))
13361350
{
13371351
/*
13381352
* Page is full, so we're done here, but first fill the next page
@@ -1342,12 +1356,15 @@ asyncQueueAddEntries(ListCell *nextNotify)
13421356
* asyncQueueIsFull() ensured that there is room to create this
13431357
* page without overrunning the queue.
13441358
*/
1345-
slotno = SimpleLruZeroPage(AsyncCtl, QUEUE_POS_PAGE(QUEUE_HEAD));
1359+
slotno = SimpleLruZeroPage(AsyncCtl, QUEUE_POS_PAGE(queue_head));
13461360
/* And exit the loop */
13471361
break;
13481362
}
13491363
}
13501364

1365+
/* Success, so update the global QUEUE_HEAD */
1366+
QUEUE_HEAD = queue_head;
1367+
13511368
LWLockRelease(AsyncCtlLock);
13521369

13531370
return nextNotify;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy