Work-around for a race condition with parallel session initialization
authorAlexander Ebert <ebert@woltlab.com>
Sun, 8 Feb 2015 15:59:44 +0000 (16:59 +0100)
committerAlexander Ebert <ebert@woltlab.com>
Sun, 8 Feb 2015 15:59:44 +0000 (16:59 +0100)
wcfsetup/install/files/lib/system/session/SessionHandler.class.php

index 0337999cc1764c4bf665e1730e40263d8950788d..b5e156d35ce2ed9ca0d5531703c6a7ef692768c4 100644 (file)
@@ -514,7 +514,33 @@ class SessionHandler extends SingletonFactory {
                        );
                        
                        if ($spiderID !== null) $sessionData['spiderID'] = $spiderID;
-                       $this->session = call_user_func(array($this->sessionEditorClassName, 'create'), $sessionData);
+                       
+                       try {
+                               $this->session = call_user_func(array($this->sessionEditorClassName, 'create'), $sessionData);
+                       }
+                       catch (DatabaseException $e) {
+                               // MySQL error 23000 = unique key
+                               // do not check against the message itself, some weird systems localize them
+                               if ($e->getCode() == 23000 && $this->supportsVirtualSessions) {
+                                       // find existing session
+                                       $session = call_user_func(array($this->sessionClassName, 'getSessionByUserID'), $this->user->userID);
+                                       
+                                       if ($session === null) {
+                                               // MySQL reported a unique key error, but no corresponding session exists, rethrow exception
+                                               throw $e;
+                                       }
+                                       else {
+                                               // inherit existing session
+                                               $this->session = $session;
+                                               $this->loadVirtualSession(true);
+                                       }
+                               }
+                               else {
+                                       // unrelated to user id
+                                       throw $e;
+                               }
+                       }
+                       
                        $this->firstVisit = true;
                        $this->loadVirtualSession(true);
                }