Alleviate OOM failures in COMMIT callback

Previously those failures caused us to crash, postgres abort()s when it
notices a failure in the COMMIT callback.
pull/2176/head
Brian Cloutier 2018-05-09 13:23:08 -07:00 committed by Brian Cloutier
parent f163932a1b
commit 9667ee5ac9
1 changed files with 32 additions and 0 deletions

View File

@ -49,6 +49,9 @@ dlist_head InProgressTransactions = DLIST_STATIC_INIT(InProgressTransactions);
/* stack of active sub-transactions */ /* stack of active sub-transactions */
static List *activeSubXacts = NIL; static List *activeSubXacts = NIL;
/* some pre-allocated memory so we don't need to call malloc() during callbacks */
MemoryContext CommitContext = NULL;
/* /*
* Should this coordinated transaction use 2PC? Set by * Should this coordinated transaction use 2PC? Set by
* CoordinatedTransactionUse2PC(), e.g. if DDL was issued and * CoordinatedTransactionUse2PC(), e.g. if DDL was issued and
@ -136,6 +139,13 @@ InitializeTransactionManagement(void)
RegisterSubXactCallback(CoordinatedSubTransactionCallback, NULL); RegisterSubXactCallback(CoordinatedSubTransactionCallback, NULL);
AdjustMaxPreparedTransactions(); AdjustMaxPreparedTransactions();
/* set aside 8kb of memory for use in CoordinatedTransactionCallback */
CommitContext = AllocSetContextCreate(TopMemoryContext,
"CommitContext",
8 * 1024,
8 * 1024,
8 * 1024);
} }
@ -154,6 +164,24 @@ CoordinatedTransactionCallback(XactEvent event, void *arg)
{ {
case XACT_EVENT_COMMIT: case XACT_EVENT_COMMIT:
{ {
/*
* ERRORs thrown during XACT_EVENT_COMMIT will cause postgres to abort, at
* this point enough work has been done that it's not possible to rollback.
*
* One possible source of errors is memory allocation failures. To minimize
* the chance of those happening we've pre-allocated some memory in the
* CommitContext, it has 8kb of memory that we're allowed to use.
*
* We only do this in the COMMIT callback because:
* - Errors thrown in other callbacks (such as PRE_COMMIT) won't cause
* crashes, they will simply cause the ABORT handler to be called.
* - The exception is ABORT, errors thrown there could also cause crashes, but
* postgres already creates a TransactionAbortContext which performs this
* trick, so there's no need for us to do it again.
*/
MemoryContext previousContext = CurrentMemoryContext;
MemoryContextSwitchTo(CommitContext);
/* /*
* Call other parts of citus that need to integrate into * Call other parts of citus that need to integrate into
* transaction management. Do so before doing other work, so the * transaction management. Do so before doing other work, so the
@ -180,6 +208,10 @@ CoordinatedTransactionCallback(XactEvent event, void *arg)
CoordinatedTransactionUses2PC = false; CoordinatedTransactionUses2PC = false;
UnSetDistributedTransactionId(); UnSetDistributedTransactionId();
/* empty the CommitContext to ensure we're not leaking memory */
MemoryContextSwitchTo(previousContext);
MemoryContextReset(CommitContext);
break; break;
} }