mirror of
https://github.com/Shadowss/TravianZ.git
synced 2026-09-04 09:27:17 +00:00
Merge pull request #148 from hdmaniak2/fix-market-race-condition2
This commit is contained in:
@@ -5599,6 +5599,24 @@ References: User ID/Message ID, Mode
|
|||||||
return self::$merchantsUseCountCache[$vid];
|
return self::$merchantsUseCountCache[$vid];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***************************
|
||||||
|
Function to acquire/release MySQL advisory lock for merchant operations
|
||||||
|
Prevents race conditions when sending merchants concurrently
|
||||||
|
***************************/
|
||||||
|
function getMerchantLock($vid, $timeout = 10)
|
||||||
|
{
|
||||||
|
$lockName = TB_PREFIX . 'merchant_' . (int)$vid;
|
||||||
|
$result = mysqli_query($this->dblink, "SELECT GET_LOCK('$lockName', $timeout) AS lock_acquired");
|
||||||
|
$row = mysqli_fetch_assoc($result);
|
||||||
|
return $row['lock_acquired'] == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function releaseMerchantLock($vid)
|
||||||
|
{
|
||||||
|
$lockName = TB_PREFIX . 'merchant_' . (int)$vid;
|
||||||
|
mysqli_query($this->dblink, "SELECT RELEASE_LOCK('$lockName')");
|
||||||
|
}
|
||||||
|
|
||||||
function getMovement($type, $village, $mode, $use_cache = true) {
|
function getMovement($type, $village, $mode, $use_cache = true) {
|
||||||
$array_passed = is_array($village);
|
$array_passed = is_array($village);
|
||||||
|
|
||||||
|
|||||||
+29
-2
@@ -114,6 +114,10 @@ class Market
|
|||||||
$resource = [$wtrans, $ctrans, $itrans, $crtrans];
|
$resource = [$wtrans, $ctrans, $itrans, $crtrans];
|
||||||
$reqMerc = ceil((array_sum($resource) - 0.1) / $this->maxcarry);
|
$reqMerc = ceil((array_sum($resource) - 0.1) / $this->maxcarry);
|
||||||
|
|
||||||
|
// Acquire merchant lock to prevent race condition
|
||||||
|
$database->getMerchantLock($village->wid);
|
||||||
|
$this->used = $database->totalMerchantUsed($village->wid, false);
|
||||||
|
|
||||||
if($this->merchantAvail() > 0 && $reqMerc <= $this->merchantAvail())
|
if($this->merchantAvail() > 0 && $reqMerc <= $this->merchantAvail())
|
||||||
{
|
{
|
||||||
$id = $post['getwref'];
|
$id = $post['getwref'];
|
||||||
@@ -129,10 +133,15 @@ class Market
|
|||||||
$logging->addMarketLog($village->wid, 1, [$resource[0], $resource[1], $resource[2], $resource[3], $id]);
|
$logging->addMarketLog($village->wid, 1, [$resource[0], $resource[1], $resource[2], $resource[3], $id]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$database->releaseMerchantLock($village->wid);
|
||||||
header("Location: build.php?id=".$post['id']);
|
header("Location: build.php?id=".$post['id']);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
else $form->addError("error", TOO_FEW_MERCHANTS);
|
else
|
||||||
|
{
|
||||||
|
$database->releaseMerchantLock($village->wid);
|
||||||
|
$form->addError("error", TOO_FEW_MERCHANTS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else $form->addError("error", TOO_FEW_RESOURCES);
|
else $form->addError("error", TOO_FEW_RESOURCES);
|
||||||
}
|
}
|
||||||
@@ -197,6 +206,10 @@ class Market
|
|||||||
|
|
||||||
if(($wood+$clay+$iron+$crop) > $this->maxcarry*$reqMerc) $reqMerc += 1;
|
if(($wood+$clay+$iron+$crop) > $this->maxcarry*$reqMerc) $reqMerc += 1;
|
||||||
}
|
}
|
||||||
|
// Acquire merchant lock to prevent race condition
|
||||||
|
$database->getMerchantLock($village->wid);
|
||||||
|
$this->used = $database->totalMerchantUsed($village->wid, false);
|
||||||
|
|
||||||
if($this->merchantAvail() > 0 && $reqMerc <= $this->merchantAvail())
|
if($this->merchantAvail() > 0 && $reqMerc <= $this->merchantAvail())
|
||||||
{
|
{
|
||||||
if($database->modifyResource($village->wid,$wood,$clay,$iron,$crop,0))
|
if($database->modifyResource($village->wid,$wood,$clay,$iron,$crop,0))
|
||||||
@@ -207,12 +220,14 @@ class Market
|
|||||||
$database->addMarket($village->wid,$post['rid1'],$post['m1'],$post['rid2'],$post['m2'],$time,$alliance,$reqMerc,0);
|
$database->addMarket($village->wid,$post['rid1'],$post['m1'],$post['rid2'],$post['m2'],$time,$alliance,$reqMerc,0);
|
||||||
}
|
}
|
||||||
// Enough merchants
|
// Enough merchants
|
||||||
|
$database->releaseMerchantLock($village->wid);
|
||||||
header("Location: build.php?id=".$post['id']."&t=2");
|
header("Location: build.php?id=".$post['id']."&t=2");
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Not enough merchants
|
// Not enough merchants
|
||||||
|
$database->releaseMerchantLock($village->wid);
|
||||||
header("Location: build.php?id=".$post['id']."&t=2&e3");
|
header("Location: build.php?id=".$post['id']."&t=2&e3");
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
@@ -254,12 +269,23 @@ class Market
|
|||||||
{
|
{
|
||||||
header("Location: build.php?id=".$get['id']."&t=1&e2");
|
header("Location: build.php?id=".$get['id']."&t=1&e2");
|
||||||
exit;
|
exit;
|
||||||
} // We don't have enough merchants
|
} // We don't have enough merchants (initial check before lock)
|
||||||
elseif($reqMerc > $this->merchantAvail()){
|
elseif($reqMerc > $this->merchantAvail()){
|
||||||
header("Location: build.php?id=".$get['id']."&t=1&e3");
|
header("Location: build.php?id=".$get['id']."&t=1&e3");
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Acquire merchant lock to prevent race condition
|
||||||
|
$database->getMerchantLock($village->wid);
|
||||||
|
$this->used = $database->totalMerchantUsed($village->wid, false);
|
||||||
|
|
||||||
|
if($reqMerc > $this->merchantAvail())
|
||||||
|
{
|
||||||
|
$database->releaseMerchantLock($village->wid);
|
||||||
|
header("Location: build.php?id=".$get['id']."&t=1&e3");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
$myresource = $hisresource = [ 1=> 0, 0, 0, 0];
|
$myresource = $hisresource = [ 1=> 0, 0, 0, 0];
|
||||||
$myresource[$infoarray['wtype']] = $infoarray['wamt'];
|
$myresource[$infoarray['wtype']] = $infoarray['wamt'];
|
||||||
$mysendid = $database->sendResource($myresource[1],$myresource[2],$myresource[3],$myresource[4],$reqMerc,0);
|
$mysendid = $database->sendResource($myresource[1],$myresource[2],$myresource[3],$myresource[4],$reqMerc,0);
|
||||||
@@ -284,6 +310,7 @@ class Market
|
|||||||
$database->setMarketAcc($get['g']);
|
$database->setMarketAcc($get['g']);
|
||||||
$database->removeAcceptedOffer($get['g']);
|
$database->removeAcceptedOffer($get['g']);
|
||||||
$logging->addMarketLog($village->wid, 2, [$infoarray['vref'], $get['g']]);
|
$logging->addMarketLog($village->wid, 2, [$infoarray['vref'], $get['g']]);
|
||||||
|
$database->releaseMerchantLock($village->wid);
|
||||||
header("Location: build.php?id=" . $get['id']);
|
header("Location: build.php?id=" . $get['id']);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user