hi,

> YAMAMOTO Takashi <y...@mwd.biglobe.ne.jp> wrote:
>  
>> it seems that PredicateLockTupleRowVersionLink sometimes create
>> a loop of targets (it founds an existing 'newtarget' whose
>> nextVersionOfRow chain points to the 'oldtarget') and it later
>> causes CheckTargetForConflictsIn loop forever.
>  
> Is this a hypothetical risk based on looking at the code, or have
> you seen this actually happen?  Either way, could you provide more
> details?  (A reproducible test case would be ideal.)

i have seen this actually happen.  i've confirmed the creation of the loop
with the attached patch.  it's easily reproducable with my application.
i can provide the full source code of my application if you want.
(but it isn't easy to run unless you are familiar with the recent
version of NetBSD)
i haven't found a smaller reproducible test case yet.

YAMAMOTO Takashi

>  
> This being the newest part of the code, I'll grant that it is the
> most likely to have an unidentified bug; but given that the pointers
> are from one predicate lock target structure identified by a tuple
> ID to one identified by the tuple ID of the next version of the row,
> it isn't obvious to me how a cycle could develop.
>  
> -Kevin
diff --git a/src/backend/storage/lmgr/predicate.c 
b/src/backend/storage/lmgr/predicate.c
index 722d0f8..3e1a3e2 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -2350,7 +2350,25 @@ PredicateLockTupleRowVersionLink(const Relation relation,
                        newtarget->nextVersionOfRow = NULL;
                }
                else
+               {
                        Assert(newtarget->priorVersionOfRow == NULL);
+#if 0
+                       Assert(newtarget->nextVersionOfRow == NULL);
+#endif
+                       if (newtarget->nextVersionOfRow != NULL) {
+                               PREDICATELOCKTARGET *t;
+
+                               elog(WARNING, "new %p has next %p\n",
+                                       newtarget, newtarget->nextVersionOfRow);
+                               for (t = newtarget->nextVersionOfRow; t != NULL;
+                                       t = t->nextVersionOfRow) {
+                                       if (oldtarget != t) {
+                                               elog(WARNING, "creating a loop 
new=%p old=%p\n",
+                                                       newtarget, oldtarget);
+                                       }
+                               }
+                       }
+               }
 
                newtarget->priorVersionOfRow = oldtarget;
                oldtarget->nextVersionOfRow = newtarget;
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to