From c4fb4c198b0c8f5e72817d75f918e4403ae601e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Tue, 31 May 2016 23:29:17 +0200 Subject: [PATCH] Fix race condition leading to multiple leaves --- file/lib/data/room/Room.class.php | 18 ++++++++++++++++-- file/lib/data/room/RoomAction.class.php | 2 ++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/file/lib/data/room/Room.class.php b/file/lib/data/room/Room.class.php index ecf9af0..eafc3c0 100644 --- a/file/lib/data/room/Room.class.php +++ b/file/lib/data/room/Room.class.php @@ -240,9 +240,23 @@ public static function getDeadUsers() { $time = TIME_NOW; } + $sql = "SELECT userID + FROM wcf".WCF_N."_user + WHERE chatRoomID IS NOT NULL + AND chatLastActivity < ? + FOR UPDATE"; + $statement = WCF::getDB()->prepareStatement($sql); + $statement->execute([ $time - 30 ]); + $userIDs = []; + while ($userID = $statement->fetchColumn()) $userIDs[] = $userID; + $userList = new \wcf\data\user\UserList(); - $userList->getConditionBuilder()->add('user_table.chatRoomID IS NOT NULL', array()); - $userList->getConditionBuilder()->add('user_table.chatLastActivity < ?', array($time - 30)); + if (!empty($userIDs)) { + $userList->getConditionBuilder()->add('user_table.userID IN (?)', array($userIDs)); + } + else { + $userList->getConditionBuilder()->add('1 = 0', []); + } $userList->readObjects(); diff --git a/file/lib/data/room/RoomAction.class.php b/file/lib/data/room/RoomAction.class.php index 8181d0b..bc97d14 100644 --- a/file/lib/data/room/RoomAction.class.php +++ b/file/lib/data/room/RoomAction.class.php @@ -329,6 +329,7 @@ public function leave() { * Forces dead users to leave the chat. */ public function removeDeadUsers() { + WCF::getDB()->beginTransaction(); $deadUsers = Room::getDeadUsers(); foreach ($deadUsers as $deadUser) { @@ -337,6 +338,7 @@ public function removeDeadUsers() { )); $roomAction->executeAction(); } + WCF::getDB()->commitTransaction(); } /**