From a1c3d54fb6b9fd974fa4d0166bfd1fde30c8d8c2 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 2 Nov 2013 16:45:42 -0400 Subject: Retry after buffer locking failure during SPGiST index creation. The original coding thought this case was impossible, but it can happen if the bgwriter or checkpointer processes decide to write out an index page while creation is still proceeding, leading to a bogus "unexpected spgdoinsert() failure" error. Problem reported by Jonathan S. Katz. Teodor Sigaev --- src/backend/access/spgist/spginsert.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'src/backend/access/spgist/spginsert.c') diff --git a/src/backend/access/spgist/spginsert.c b/src/backend/access/spgist/spginsert.c index b20ddcc79a3..c496f387ff0 100644 --- a/src/backend/access/spgist/spginsert.c +++ b/src/backend/access/spgist/spginsert.c @@ -43,10 +43,17 @@ spgistBuildCallback(Relation index, HeapTuple htup, Datum *values, /* Work in temp context, and reset it after each tuple */ oldCtx = MemoryContextSwitchTo(buildstate->tmpCtx); - /* No concurrent insertions can be happening, so failure is unexpected */ - if (!spgdoinsert(index, &buildstate->spgstate, &htup->t_self, - *values, *isnull)) - elog(ERROR, "unexpected spgdoinsert() failure"); + /* + * Even though no concurrent insertions can be happening, we still might + * get a buffer-locking failure due to bgwriter or checkpointer taking a + * lock on some buffer. So we need to be willing to retry. We can flush + * any temp data when retrying. + */ + while (!spgdoinsert(index, &buildstate->spgstate, &htup->t_self, + *values, *isnull)) + { + MemoryContextReset(buildstate->tmpCtx); + } MemoryContextSwitchTo(oldCtx); MemoryContextReset(buildstate->tmpCtx); -- cgit v1.2.3