%PDF- %PDF-
| Direktori : /home/bitrix/www/bitrix/modules/cluster/classes/mysql/ |
| Current File : /home/bitrix/www/bitrix/modules/cluster/classes/mysql/slave.php |
<?php
IncludeModuleLangFile(__FILE__);
class CClusterSlave
{
public static function SetOnLine($node_id, $master_id)
{
global $DB;
$arNode = CClusterDBNode::GetByID($node_id);
if(!is_array($arNode))
return;
if($arNode["ROLE_ID"] == "SLAVE")
{
if($master_id == 1)
{
$masterDB = $DB;
}
else
{
ob_start();
$masterDB = CDatabase::GetDBNodeConnection($master_id, true);
$error = ob_get_contents();
ob_end_clean();
}
$rs = $masterDB->Query("show master status", false, '', array('fixed_connection'=>true));
if($arMasterStatus = $rs->Fetch())
{
ob_start();
$nodeDB = CDatabase::GetDBNodeConnection($arNode["ID"], true);
$error = ob_get_contents();
ob_end_clean();
if(is_object($nodeDB))
{
$rs = $nodeDB->Query("
CHANGE MASTER TO
MASTER_HOST = '".$DB->ForSQL($arNode["MASTER_HOST"])."'
,MASTER_USER = '".$DB->ForSQL($masterDB->DBLogin)."'
,MASTER_PASSWORD = '".$DB->ForSQL($masterDB->DBPassword)."'
,MASTER_PORT = ".$DB->ForSQL($arNode["MASTER_PORT"])."
,MASTER_LOG_FILE = '".$arMasterStatus["File"]."'
,MASTER_LOG_POS = ".$arMasterStatus["Position"]."
", false, '', array('fixed_connection'=>true));
if($rs)
$rs = $nodeDB->Query("START SLAVE");
if($rs)
{
$obNode = new CClusterDBNode;
$obNode->Update($node_id, array("MASTER_ID" => $master_id));
CClusterDBNode::SetOnline($node_id);
CClusterSlave::AdjustServerID($arNode, $nodeDB);
}
}
}
}
elseif($arNode["ROLE_ID"] == "MASTER" && preg_match("/^(.+):(\\d+)$/", $arNode["DB_HOST"], $match))
{
$rs = $DB->Query("show master status", false, '', array('fixed_connection'=>true));
if($arMasterStatus = $rs->Fetch())
{
ob_start();
$nodeDB = CDatabase::GetDBNodeConnection($arNode["ID"], true);
$error = ob_get_contents();
ob_end_clean();
if(is_object($nodeDB))
{
$rs = $nodeDB->Query("STOP SLAVE", true, '', array('fixed_connection'=>true));
if($rs)
$rs = $nodeDB->Query("
CHANGE MASTER TO
MASTER_HOST = '".$DB->ForSQL($arNode["MASTER_HOST"])."'
,MASTER_USER = '".$DB->ForSQL($DB->DBLogin)."'
,MASTER_PASSWORD = '".$DB->ForSQL($DB->DBPassword)."'
,MASTER_PORT = ".$DB->ForSQL($arNode["MASTER_PORT"])."
,MASTER_LOG_FILE = '".$arMasterStatus["File"]."'
,MASTER_LOG_POS = ".$arMasterStatus["Position"]."
", false, '', array('fixed_connection'=>true));
if($rs)
$rs = $nodeDB->Query("START SLAVE");
if($rs)
{
$rs = $nodeDB->Query("show master status", false, '', array('fixed_connection'=>true));
if($arMasterStatus = $rs->Fetch())
{
$rs = $DB->Query("STOP SLAVE", true, '', array('fixed_connection'=>true));
if($rs)
$rs = $DB->Query("
CHANGE MASTER TO
MASTER_HOST = '".$DB->ForSQL($match[1])."'
,MASTER_USER = '".$DB->ForSQL($arNode["DB_LOGIN"])."'
,MASTER_PASSWORD = '".$DB->ForSQL($arNode["DB_PASSWORD"])."'
,MASTER_PORT = ".$DB->ForSQL($match[2])."
,MASTER_LOG_FILE = '".$arMasterStatus["File"]."'
,MASTER_LOG_POS = ".$arMasterStatus["Position"]."
", false, '', array('fixed_connection'=>true));
if($rs)
$rs = $DB->Query("START SLAVE");
if($rs)
{
$obNode = new CClusterDBNode;
$obNode->Update($node_id, array("MASTER_ID" => $master_id));
$obNode->Update($master_id, array("MASTER_ID" => $node_id));
CClusterDBNode::SetOnline($node_id);
CClusterSlave::AdjustServerID($arNode, $nodeDB);
}
}
}
}
}
}
}
public static function Pause($node_id)
{
global $DB;
$arNode = CClusterDBNode::GetByID($node_id);
if(!is_array($arNode))
return;
if($node_id == 1)
{
$nodeDB = $DB;
}
else
{
ob_start();
$nodeDB = CDatabase::GetDBNodeConnection($arNode["ID"], true);
$error = ob_get_contents();
ob_end_clean();
}
if(!is_object($nodeDB))
return;
$rs = $nodeDB->Query("STOP SLAVE SQL_THREAD", false, '', array('fixed_connection'=>true));
if($rs)
{
$ob = new CClusterDBNode;
$ob->Update($arNode["ID"], array("STATUS"=>"PAUSED"));
}
}
public static function Resume($node_id)
{
global $DB;
$arNode = CClusterDBNode::GetByID($node_id);
if(!is_array($arNode))
return;
if($node_id == 1)
{
$nodeDB = $DB;
}
else
{
ob_start();
$nodeDB = CDatabase::GetDBNodeConnection($arNode["ID"], true, false);
$error = ob_get_contents();
ob_end_clean();
}
if(!is_object($nodeDB))
return;
$rs = $nodeDB->Query("START SLAVE", false, '', array('fixed_connection'=>true));
if($rs)
{
$ob = new CClusterDBNode;
$ob->Update($arNode["ID"], array("STATUS"=>"ONLINE"));
}
}
public static function Stop($node_id)
{
global $DB;
$arNode = CClusterDBNode::GetByID($node_id);
if(!is_array($arNode))
return false;
if($node_id == 1)
{
$nodeDB = $DB;
}
else
{
ob_start();
$nodeDB = CDatabase::GetDBNodeConnection($arNode["ID"], true, false);
$error = ob_get_contents();
ob_end_clean();
}
if(!is_object($nodeDB))
return false;
$rs = $nodeDB->Query("STOP SLAVE", false, '', array('fixed_connection'=>true));
if($rs)
{
$ob = new CClusterDBNode;
if($node_id == 1)
$res = $ob->Update($arNode["ID"], array("MASTER_ID" => false, "STATUS"=> "ONLINE"));
else
$res = $ob->Update($arNode["ID"], array("STATUS"=>"READY"));
return $res;
}
else
{
return false;
}
}
public static function SkipSQLError($node_id)
{
global $DB;
$arNode = CClusterDBNode::GetByID($node_id);
if(is_array($arNode))
{
if($node_id == 1)
{
$nodeDB = $DB;
}
else
{
ob_start();
$nodeDB = CDatabase::GetDBNodeConnection($arNode["ID"], true, false);
$error = ob_get_contents();
ob_end_clean();
}
if(is_object($nodeDB))
{
//TODO check if started just make active
$rs = $nodeDB->Query("STOP SLAVE", false, '', array('fixed_connection'=>true));
if($rs)
$rs = $nodeDB->Query("SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1", false, '', array('fixed_connection'=>true));
if($rs)
$rs = $nodeDB->Query("START SLAVE", false, '', array('fixed_connection'=>true));
}
}
}
public static function GetStatus($node_id, $bSlaveStatus = true, $bGlobalStatus = true, $bVariables = true)
{
global $DB;
$arNode = CClusterDBNode::GetByID($node_id);
if(!is_array($arNode))
return false;
if($node_id == 1)
{
$nodeDB = $DB;
}
else
{
ob_start();
$nodeDB = CDatabase::GetDBNodeConnection($node_id, true, false);
$error = ob_get_contents();
ob_end_clean();
}
if(!is_object($nodeDB))
return false;
$arStatus = array(
'server_id' => null,
);
if($bVariables)
{
$rs = $nodeDB->Query("show variables like 'server_id'", false, "", array("fixed_connection" => true));
if($ar = $rs->Fetch())
$arStatus['server_id'] = $ar["Value"];
}
$rsSlaves = CClusterDBNode::GetList(array(), array("=MASTER_ID" => $node_id));
if($rsSlaves->Fetch())
{
$arStatus = array_merge($arStatus, array(
'File' => null,
'Position' => null,
));
if($bSlaveStatus)
{
$rs = $nodeDB->Query("SHOW MASTER STATUS", true, "", array("fixed_connection" => true));
if(!$rs)
return GetMessage("CLU_NO_PRIVILEGES", array("#sql#" => "GRANT REPLICATION CLIENT on *.* to '".$nodeDB->DBLogin."'@'%';"));
$ar = $rs->Fetch();
if(is_array($ar))
{
foreach($ar as $key=>$value)
{
if($key == 'Last_Error')
$key = 'Last_SQL_Error';
if(array_key_exists($key, $arStatus))
$arStatus[$key] = $value;
}
}
}
}
if(strlen($arNode["MASTER_ID"]))
{
$arStatus = array_merge($arStatus, array(
'Slave_IO_State' => null,
'Slave_IO_Running' => null,
'Read_Master_Log_Pos' => null,
'Slave_SQL_Running' => null,
'Exec_Master_Log_Pos' => null,
'Seconds_Behind_Master' => null,
'Last_IO_Error' => null,
'Last_SQL_Error' => null,
// 'Replicate_Ignore_Table' => null,
'Com_select' => null,
));
if($bSlaveStatus)
{
$rs = $nodeDB->Query("SHOW SLAVE STATUS", true, "", array("fixed_connection" => true));
if(!$rs)
return GetMessage("CLU_NO_PRIVILEGES", array("#sql#" => "GRANT REPLICATION CLIENT on *.* to '".$nodeDB->DBLogin."'@'%';"));
$ar = $rs->Fetch();
if(is_array($ar))
{
foreach($ar as $key=>$value)
{
if($key == 'Last_Error')
$key = 'Last_SQL_Error';
if(array_key_exists($key, $arStatus))
$arStatus[$key] = $value;
}
}
}
}
if($bGlobalStatus)
{
$rs = $nodeDB->Query("show global status where Variable_name in ('Com_select', 'Com_do')", true, "", array("fixed_connection" => true));
if(is_object($rs))
{
while($ar = $rs->Fetch())
{
if($ar['Variable_name'] == 'Com_do')
$arStatus['Com_select'] -= $ar['Value']*2;
else
$arStatus['Com_select'] += $ar['Value'];
}
}
else
{
$rs = $nodeDB->Query("show status like 'Com_select'", false, "", array("fixed_connection" => true));
$ar = $rs->Fetch();
if($ar)
$arStatus['Com_select'] += $ar['Value'];
$rs = $nodeDB->Query("show status like 'Com_do'", false, "", array("fixed_connection" => true));
$ar = $rs->Fetch();
if($ar)
$arStatus['Com_select'] -= $ar['Value']*2;
}
}
return $arStatus;
}
public static function GetList()
{
global $DB, $CACHE_MANAGER;
static $arSlaves = false;
if($arSlaves === false)
{
$cache_id = "db_slaves_v2";
if(
CACHED_b_cluster_dbnode !== false
&& $CACHE_MANAGER->Read(CACHED_b_cluster_dbnode, $cache_id, "b_cluster_dbnode")
)
{
$arSlaves = $CACHE_MANAGER->Get($cache_id);
}
else
{
$arSlaves = array();
$rs = $DB->Query("
SELECT ID, WEIGHT, ROLE_ID, GROUP_ID
FROM b_cluster_dbnode
WHERE STATUS = 'ONLINE' AND (SELECTABLE is null or SELECTABLE = 'Y')
ORDER BY ID
", false, '', array('fixed_connection'=>true));
while($ar = $rs->Fetch())
$arSlaves[intval($ar['ID'])] = $ar;
if(CACHED_b_cluster_dbnode !== false)
$CACHE_MANAGER->Set($cache_id, $arSlaves);
}
}
return $arSlaves;
}
/**
* @param array $arNode
* @param CDatabase $nodeDB
*/
public static function AdjustServerID($arNode, $nodeDB)
{
$rs = $nodeDB->Query("show variables like 'server_id'", false, '', array("fixed_connection"=>true));
if($ar = $rs->Fetch())
{
if($ar["Value"] != $arNode["SERVER_ID"])
{
$ob = new CClusterDBNode;
$ob->Update($arNode["ID"], array("SERVER_ID"=>$ar["Value"]));
}
}
}
public static function GetRandomNode()
{
$arSlaves = static::GetList();
if(empty($arSlaves))
return false;
$max_slave_delay = COption::GetOptionInt("cluster", "max_slave_delay", 10);
if(isset($_SESSION["BX_REDIRECT_TIME"]))
{
$redirect_delay = time() - $_SESSION["BX_REDIRECT_TIME"] + 1;
if(
$redirect_delay > 0
&& $redirect_delay < $max_slave_delay
)
$max_slave_delay = $redirect_delay;
}
$total_weight = 0;
foreach($arSlaves as $i=>$slave)
{
$bOtherGroup = defined("BX_CLUSTER_GROUP") && ($slave["GROUP_ID"] != BX_CLUSTER_GROUP);
if (
defined("BX_CLUSTER_SLAVE_USE_ANY_GROUP")
&& BX_CLUSTER_SLAVE_USE_ANY_GROUP === true
&& $slave["ROLE_ID"] == "SLAVE"
)
{
$bOtherGroup = false;
}
if($bOtherGroup)
{
unset($arSlaves[$i]);
}
elseif($slave["ROLE_ID"] == "SLAVE")
{
$arSlaveStatus = static::GetStatus($slave["ID"], true, false, false);
if(
$arSlaveStatus['Seconds_Behind_Master'] > $max_slave_delay
|| $arSlaveStatus['Last_SQL_Error'] != ''
|| $arSlaveStatus['Last_IO_Error'] != ''
|| $arSlaveStatus['Slave_SQL_Running'] === 'No'
)
{
unset($arSlaves[$i]);
}
else
{
$total_weight += $slave["WEIGHT"];
$arSlaves[$i]["PIE_WEIGHT"] = $total_weight;
}
}
else
{
$total_weight += $slave["WEIGHT"];
$arSlaves[$i]["PIE_WEIGHT"] = $total_weight;
}
}
$found = false;
$rand = ($total_weight > 0? mt_rand(0, $total_weight - 1): 0);
foreach($arSlaves as $slave)
{
if($rand < $slave["PIE_WEIGHT"])
{
$found = $slave;
break;
}
}
if(!$found || $found["ROLE_ID"] != "SLAVE")
{
return false; //use main connection
}
return $found;
}
}