Atomic mission-fill for kiosk registration (fixes overfill race)
- dev/migrations/001-innodb.sql: convert pqs_queue + pqs_mission to InnoDB. - includes/queue.php: pqs_enqueue_player() seats a player in the next open mission (creating one if needed), serialized with GET_LOCK and wrapped in a transaction; capacity judged by real COUNT(*), numplayers rewritten from it so the counter self-heals and can't drift. - callsign.php: normal registration path now calls pqs_enqueue_player instead of the non-atomic read-check-insert. Verified on the local stack: 140 concurrent registrations -> 24 missions, zero overfill, zero counter drift. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+5
-32
@@ -194,38 +194,11 @@ if (isset($_GET['submit'])) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$sql = "SELECT MissionID, numplayers FROM pqs_mission WHERE Completed = 0 AND locked = 0 AND numplayers < MissionSize ORDER BY MissionID ASC";
|
||||
$getid = mysqli_query($link, $sql) or die('Query failed: ' . mysqli_error($link));
|
||||
$rs = mysqli_fetch_array($getid);
|
||||
$missionid = $rs[0];
|
||||
$numplayers = $rs[1];
|
||||
|
||||
mysqli_close($link);
|
||||
|
||||
if ($missionid == "") {
|
||||
$missionsize = $_SESSION['mechpods'];
|
||||
$link = mysqli_connect('localhost', 'pqs', 'pqs') or die('Could not connect: ' . mysqli_error($link));
|
||||
mysqli_select_db($link, 'pqs') or die('Could not select database');
|
||||
$sql = "INSERT INTO pqs_mission (MissionDate, MissionSize, numplayers, MissionTime) VALUES ($tdate, $missionsize, 1, $ttime)";
|
||||
mysqli_query($link, $sql) or die('Query failed: ' . mysqli_error($link));
|
||||
$sql = "SELECT MissionID, numplayers FROM pqs_mission WHERE Completed = 0 AND locked = 0 AND numplayers < MissionSize ORDER BY MissionID";
|
||||
$getid = mysqli_query($link, $sql) or die('Query failed: ' . mysqli_error($link));
|
||||
$rs1 = mysqli_fetch_array($getid);
|
||||
$missionid = $rs1[0];
|
||||
$query = "INSERT INTO pqs_queue (callsign, mech, missionid) VALUES ('$callsign','$mechname',$missionid)";
|
||||
$result = mysqli_query($link, $query) or die('Query failed: ' . mysqli_error($link));
|
||||
mysqli_query($link, $sql) or die('Query failed: ' . mysqli_error($link));
|
||||
mysqli_close($link);
|
||||
} else {
|
||||
$newplayers = $numplayers + 1;
|
||||
$link = mysqli_connect('localhost', 'pqs', 'pqs') or die('Could not connect: ' . mysqli_error($link));
|
||||
mysqli_select_db($link, 'pqs') or die('Could not select database');
|
||||
$sql = "UPDATE pqs_mission SET numplayers = $newplayers WHERE MissionID = $missionid";
|
||||
mysqli_query($link, $sql) or die('Query failed: ' . mysqli_error($link));
|
||||
$query = "INSERT INTO pqs_queue (callsign, mech, missionid) VALUES ('$callsign','$mechname',$missionid)";
|
||||
$result = mysqli_query($link, $query) or die('Query failed: ' . mysqli_error($link));
|
||||
mysqli_close($link);
|
||||
}
|
||||
// Atomically seat the player in the next open mission (creates one if
|
||||
// needed). Serialized + transactional to prevent the overfill race that
|
||||
// concurrent kiosk/staff registrations used to cause. See includes/queue.php.
|
||||
require_once("includes/queue.php");
|
||||
$missionid = pqs_enqueue_player($callsign, $mechname);
|
||||
|
||||
$minToDeparture = $timePerGame*($missionid-$lastCommitedMissionID);
|
||||
$d=strtotime("+$minToDeparture Minutes",$lastCommitTime);
|
||||
|
||||
Reference in New Issue
Block a user