summaryrefslogtreecommitdiff
path: root/src/backend/access/spgist
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2013-11-02 16:45:42 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2013-11-02 16:45:57 -0400
commita1c3d54fb6b9fd974fa4d0166bfd1fde30c8d8c2 (patch)
treebb44e0bb5f9ad361ae0717fee67d0351cbde6b71 /src/backend/access/spgist
parent2f2507e38374b7e2d5badc210a8d1fa6fecab60a (diff)
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
Diffstat (limited to 'src/backend/access/spgist')
-rw-r--r--src/backend/access/spgist/spgdoinsert.c9
-rw-r--r--src/backend/access/spgist/spginsert.c15
2 files changed, 17 insertions, 7 deletions
diff --git a/src/backend/access/spgist/spgdoinsert.c b/src/backend/access/spgist/spgdoinsert.c
index 1df9fbc5b32..35676d69c63 100644
--- a/src/backend/access/spgist/spgdoinsert.c
+++ b/src/backend/access/spgist/spgdoinsert.c
@@ -1952,9 +1952,12 @@ spgdoinsert(Relation index, SpGistState *state,
* Attempt to acquire lock on child page. We must beware of
* deadlock against another insertion process descending from that
* page to our parent page (see README). If we fail to get lock,
- * abandon the insertion and tell our caller to start over. XXX
- * this could be improved; perhaps it'd be worth sleeping a bit
- * before giving up?
+ * abandon the insertion and tell our caller to start over.
+ *
+ * XXX this could be improved, because failing to get lock on a
+ * buffer is not proof of a deadlock situation; the lock might be
+ * held by a reader, or even just background writer/checkpointer
+ * process. Perhaps it'd be worth retrying after sleeping a bit?
*/
if (!ConditionalLockBuffer(current.buffer))
{
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);