package.xml 0000664 0001750 0001750 00000212504 12161007456 012531 0 ustar andrey andrey
mysqlnd_mspecl.php.netA replication and load balancing plugin for mysqlndThe mysqlnd_ms replication and load balancing plugin can be used with PHP MySQL extensions (ext/mysql, ext/mysqli, ext/pdo_mysql) if they are compiled to use mysqlnd. The plugin inspects queries and does read-write splitting. Read-only queries are sent to MySQL replication slave servers while all other queries are redirected to the MySQL replication master server. Very few, if any, application changes are required, depending on the usage scenario.Andrey Hristovandreyandrey@php_netyesUlf Wendeluwuw@php_netyesJohannes Schlüterjohannesjohannes@php.netyes2013-06-211.5.21.5.0stablestablePHP License
Fix hardcoded version number
5.3.6-dev1.4.0mysqlnd_ms1.5.21.5.0GAGA2013-06-21PHP License
Fix hardcoded version number
1.5.11.5.0GAGA2013-06-18PHP License
GA release
1.5.01.5.0alphaalpha2012-08-15PHP License
alpha
1.4.11.4.0betabeta2012-08-01PHP License
Beta release, stable API, for testing
1.4.01.4.0alphaalpha2012-07-16PHP License
Small change to fix the build in case MS is built/used together with QC
1.3.11.3.0alphaalpha2012-04-16PHP License
Small change to fix the build in case MS is built/used together with QC
1.3.01.3.0alphaalpha2012-04-12PHP License
New feature release with QoS and QC integration
1.2.11.2.0betabeta2012-01-24PHP License
beta release
1.2.01.2.0alphaalpha2011-12-14PHP License
Global Transaction ID injection and quality-of-service concept
1.1.21.1.0stablestable2011-11-04PHP License
Fixed the build for 5.4. Declaring the code as stable. Refer to CHANGES for more information
1.1.11.1.0betastable2011-10-11PHP License
The same as 1.1.0 code-wise. A note added to config.m4 for an experimental and currently unsupported option
1.1.01.1.0betastable2011-09-29PHP License
Numerous feature enhancements. Refer to CHANGES for more information
1.0.11.0.0alphastable2011-04-21PHP License
Fixed debug build (credits to Vladimir Getmanshchuk). All 1.0 features implemented.
1.0.01.0.0alphastable2011-04-20PHP License
Initial package release. All 1.0 features implemented.
mysqlnd_ms-1.5.2/examples/config.php 0000664 0001750 0001750 00000000126 12161007456 017032 0 ustar andrey andrey
mysqlnd_ms-1.5.2/examples/failover.php 0000664 0001750 0001750 00000005200 12161007456 017372 0 ustar andrey andrey query($query);
/* After the query has been send, $conn either points to master or slave.
By recording the connection thread id we can reverse-engineer which
queries have been send via which connection. One cannot tell based on
the thread id if a connection is a master or slave connection but
common sense will tell you if you look at the recorded data... */
if (!isset($queries[$conn->thread_id]))
$queries[$conn->thread_id] = array($query);
else
$queries[$conn->thread_id][] = $query;
if (!$ret)
/* KLUDGE - you will do proper error handling, won't you? */
die(sprintf("[%d] %s\n", $conn->errno, $conn->error));
return $ret;
}
require_once("./config.php");
printf("\n");
if (!($conn = new mysqli("myapp", DB_USER, DB_PASSWORD, DB_SCHEMA)) || mysqli_connect_errno()) {
die(sprintf("Please check the *config.json used and config.php, failed to connect: [%d] %s\n",
mysqli_connect_errno(), mysqli_connect_error()));
}
$queries = array();
printf("Creating a test table. Statements should be send to the master...\n");
run_query($conn, "DROP TABLE IF EXISTS test");
run_query($conn, "CREATE TABLE test(id INT)");
run_query($conn, "INSERT INTO test(id) VALUES (1)");
printf("Dumping list of connections. Should be only one, the master connection...\n");
foreach ($queries as $thread_id => $details) {
printf("\t... Connection %d has run\n", $thread_id);
foreach ($details as $query)
printf("\t\t... %s\n", $query);
}
printf("\nRunning a SELECT, it should be send to the slaves...\n");
printf("NOTE: A warning is emitted but script continues without interruption. You can suppress the warning using @. The plugin cannot control it.\n");
$res = run_query($conn, "SELECT '\tWarning but resultset' AS _hint FROM DUAL");
$row = $res->fetch_assoc();
echo $row['_hint'] . "\n";
printf("\nRunning SELECT but plugin has learned that slave1 is unavailable...\n");
$res = run_query($conn, "SELECT '\tNo warning' AS _hint FROM DUAL");
$row = $res->fetch_assoc();
echo $row['_hint'] . "\n";
printf("\nDropping the test table. Statement should be send to the master...\n");
run_query($conn, "DROP TABLE IF EXISTS test");
printf("\nDumping list of connections. Should be two: master and slave...\n");
foreach ($queries as $thread_id => $details) {
printf("\t... Connection %d has run\n", $thread_id);
foreach ($details as $query)
printf("\t\t... %s\n", $query);
}
printf("\n");
?> mysqlnd_ms-1.5.2/examples/multi_master.php 0000664 0001750 0001750 00000003255 12161007456 020300 0 ustar andrey andrey query($query);
/* After the query has been send, $conn either points to master or slave.
By recording the connection thread id we can reverse-engineer which
queries have been send via which connection. One cannot tell based on
the thread id if a connection is a master or slave connection but
common sense will tell you if you look at the recorded data... */
if (!isset($queries[$conn->thread_id]))
$queries[$conn->thread_id] = array($query);
else
$queries[$conn->thread_id][] = $query;
if (!$ret)
/* KLUDGE - you will do proper error handling, won't you? */
die(sprintf("[%d] %s\n", $conn->errno, $conn->error));
return $ret;
}
require_once("./config.php");
printf("\n");
if (!($conn = new mysqli("myapp", DB_USER, DB_PASSWORD, DB_SCHEMA)) || mysqli_connect_errno()) {
die(sprintf("Please check the *config.json used and config.php, failed to connect: [%d] %s\n",
mysqli_connect_errno(), mysqli_connect_error()));
}
$queries = array();
printf("Running some statements in a roundrobin fashion\n");
run_query($conn, "SELECT 'Query 1, round robin: master1'");
run_query($conn, "SELECT 'Query 2, round robin: master2'");
run_query($conn, "SELECT 'Query 3, round robin: master1'");
printf("Dumping list of connections. Should be two. Queries distributed in a roundrobin fashion.\n");
foreach ($queries as $thread_id => $details) {
printf("\t... Connection %d has run\n", $thread_id);
foreach ($details as $query)
printf("\t\t... %s\n", $query);
}
printf("\n");
?> mysqlnd_ms-1.5.2/examples/mysqlnd_ms_multi_master_config.json 0000664 0001750 0001750 00000000610 12161007456 024245 0 ustar andrey andrey {
"myapp": {
"master": {
"master_1": {
"host": "localhost",
"socket": "\/tmp\/mysql57.sock"
},
"master_2": {
"host": "192.168.2.28",
"port": 3306
}
},
"slave": {
},
"filters": {
"roundrobin": {
}
},
"failover": {
"strategy": "loop_before_master",
"remember_failed": true
}
}
} mysqlnd_ms-1.5.2/examples/mysqlnd_ms_single_master_config_failover.json 0000664 0001750 0001750 00000000774 12161007456 026276 0 ustar andrey andrey {
"myapp": {
"master": {
"master_1": {
"host": "localhost",
"socket": "\/tmp\/mysql57.sock"
}
},
"slave": {
"slave_0": {
"host": "unavailable_to_trigger_failover",
"port": 9999
},
"slave_1": {
"host": "192.168.2.28",
"port": 3306
}
},
"filters": {
"random": {
"sticky": "1"
}
},
"failover": {
"strategy": "loop_before_master",
"remember_failed": true
}
}
} mysqlnd_ms-1.5.2/examples/mysqlnd_ms_single_master_config.json 0000664 0001750 0001750 00000000607 12161007456 024402 0 ustar andrey andrey {
"myapp": {
"master": {
"master_1": {
"host": "localhost",
"socket": "\/tmp\/mysql57.sock"
}
},
"slave": {
"slave_0": {
"host": "127.0.0.1",
"port": 3308
},
"slave_1": {
"host": "192.168.2.28",
"port": 3306
}
},
"filters": {
"random": {
"sticky": "1"
}
}
}
} mysqlnd_ms-1.5.2/examples/mysqlnd_ms_single_master_config_sharding.json 0000664 0001750 0001750 00000000763 12161007456 026264 0 ustar andrey andrey {
"myapp": {
"master": {
"master_1": {
"host": "localhost",
"socket": "\/tmp\/mysql57.sock"
}
},
"slave": {
"slave_0": {
"host": "127.0.0.1",
"port": 3308
},
"slave_1": {
"host": "192.168.2.28",
"port": 3306
}
},
"filters": {
"node_groups": {
"Partition_A" : {
"master": ["master_1"],
"slave": ["slave_0"]
}
},
"roundrobin": []
}
}
} mysqlnd_ms-1.5.2/examples/README 0000664 0001750 0001750 00000007260 12161007456 015742 0 ustar andrey andrey The examples try to help you getting started with the mysqlnd plugin.
*Find more in the manual!*
Please, find more examples at:
http://php.net/mysqlnd_ms
The examples given here cover a fraction of the functionality only. Explanations
are kept to a bare minimum.
*Preconditions*
Make sure you have compiled PHP with PECL/mysqlnd_ms support, the extension
is loaded and the PHP MySQL extensions are configured to use the mysqlnd library
when building PHP:
./configure --with-mysql=mysqlnd --with-mysqli=mysqlnd
--with-pdo-mysql=mysqlnd --enable-mysqlnd-ms
If you are unfamiliar with the mysqlnd library, please consult the PHP manual:
http://php.net/mysqlnd_ms
*Setup*
Edit the server settings in the configuration file you plan to use:
mysqlnd_ms_single_master_config.json
mysqlnd_ms_single_master_config_client_failover.json
mysqlnd_ms_multi_master_config.json
mysqlnd_ms_single_master_config_sharding.json
Use the single_master configuration files if running a lazy primary copy
(asynchronous master slave) cluster of MySQL such as MySQL Replication. Use
the multi_master configuration file if running a non-lazy update-anywhere
(synchronous multi master) cluster of MySQL, for example, MySQL Cluster.
Further cluster topologies are supported but beyond the scope of the examples.
Edit the server settings.
It is assumed that you have configured one MySQL user on all servers using
the same password on all servers. Using different users on different servers
is explained in the documentation.
Edit config.php to set username and password. All examples include config.php.
*Running*
The examples and tests make use of the mysqli extension and its API. mysqli
is the most feature-complete of the three PHP MySQL extensions
(mysql, mysqli, PDO_MYSQL). Because PECL/mysqlnd_ms is a plugin for the mysqlnd
library and all of the three PHP MySQL extensions can be configured to use the
mysqlnd library "under the hood" at the C level, the plugin can be used with any
of the three extensions. However, mysqli is the most powerful of the breed
and I'm familiar with it. Thus, I'm always using mysqli in the examples
and in the tests.
Single master with read-write splitting enabled:
php -d mysqlnd_ms.enable=1 \
-d mysqlnd_ms.config_file=mysqlnd_ms_single_master_config.json \
rw_split.php
Single master with failover (see documentation notes!):
php -d mysqlnd_ms.enable=1 \
-d mysqlnd_ms.config_file=mysqlnd_ms_single_master_config_failover.json \
failover.php
Single master with manual partitioning/sharding (see documentation notes!):
php -d mysqlnd_ms.enable=1 \
-d mysqlnd_ms.config_file=mysqlnd_ms_single_master_config_sharding.json \
sharding.php
Multi master with read-write splitting disabled:
php -d mysqlnd_ms.enable=1 \
-d mysqlnd_ms.multi_master=1 \
-d mysqlnd_ms.disable_rw_split=1 \
-d mysqlnd_ms.config_file=mysqlnd_ms_multi_master_config.json \
multi_master.php
*Pitfall*
Unfortunately the plugin cannot emit a proper warning if a config file is not
a valid JSON document! Instead you will get an error message such as:
Warning: mysqli::mysqli(): php_network_getaddresses: getaddrinfo failed: Name or service not known in /home/nixnutz/php-src/pecl/mysqlnd_ms/trunk/examples/multi_master.php on line 34
Warning: mysqli::mysqli(): (HY000/2002): php_network_getaddresses: getaddrinfo failed: Name or service not known in /home/nixnutz/php-src/pecl/mysqlnd_ms/trunk/examples/multi_master.php on line 34
Please check the *config.json used and config.php, failed to connect: [2002] php_network_getaddresses: getaddrinfo failed: Name or service not known
Thus, double check your changes if you make edits to the configuration files!
mysqlnd_ms-1.5.2/examples/rw_split.php 0000664 0001750 0001750 00000004173 12161007456 017436 0 ustar andrey andrey query($query);
/* After the query has been send, $conn either points to master or slave.
By recording the connection thread id we can reverse-engineer which
queries have been send via which connection. One cannot tell based on
the thread id if a connection is a master or slave connection but
common sense will tell you if you look at the recorded data... */
if (!isset($queries[$conn->thread_id]))
$queries[$conn->thread_id] = array($query);
else
$queries[$conn->thread_id][] = $query;
if (!$ret)
/* KLUDGE - you will do proper error handling, won't you? */
die(sprintf("[%d] %s\n", $conn->errno, $conn->error));
return $ret;
}
require_once("./config.php");
printf("\n");
if (!($conn = new mysqli("myapp", DB_USER, DB_PASSWORD, DB_SCHEMA)) || mysqli_connect_errno()) {
die(sprintf("Please check the *config.json used and config.php, failed to connect: [%d] %s\n",
mysqli_connect_errno(), mysqli_connect_error()));
}
$queries = array();
printf("Creating a test table. Statements should be send to the master...\n");
run_query($conn, "DROP TABLE IF EXISTS test");
run_query($conn, "CREATE TABLE test(id INT)");
run_query($conn, "INSERT INTO test(id) VALUES (1)");
printf("Dumping list of connections. Should be only one, the master connection...\n");
foreach ($queries as $thread_id => $details) {
printf("\t... Connection %d has run\n", $thread_id);
foreach ($details as $query)
printf("\t\t... %s\n", $query);
}
printf("Running a SELECT, it should be send to the slaves...\n");
run_query($conn, "SELECT 1 FROM DUAL");
printf("Dropping the test table. Statement should be send to the master...\n");
run_query($conn, "DROP TABLE IF EXISTS test");
printf("Dumping list of connections. Should be two: master and slave...\n");
foreach ($queries as $thread_id => $details) {
printf("\t... Connection %d has run\n", $thread_id);
foreach ($details as $query)
printf("\t\t... %s\n", $query);
}
printf("\n");
?> mysqlnd_ms-1.5.2/examples/sharding.php 0000664 0001750 0001750 00000006213 12161007456 017367 0 ustar andrey andrey query($query);
/* After the query has been send, $conn either points to master or slave.
By recording the connection thread id we can reverse-engineer which
queries have been send via which connection. One cannot tell based on
the thread id if a connection is a master or slave connection but
common sense will tell you if you look at the recorded data... */
if (!isset($queries[$conn->thread_id]))
$queries[$conn->thread_id] = array($query);
else
$queries[$conn->thread_id][] = $query;
if (!$ret)
/* KLUDGE - you will do proper error handling, won't you? */
die(sprintf("[%d] %s\n", $conn->errno, $conn->error));
return $ret;
}
require_once("./config.php");
printf("\n");
if (!($conn = new mysqli("myapp", DB_USER, DB_PASSWORD, DB_SCHEMA)) || mysqli_connect_errno()) {
die(sprintf("Please check the *config.json used and config.php, failed to connect: [%d] %s\n",
mysqli_connect_errno(), mysqli_connect_error()));
}
$queries = array();
printf("Creating a test table. Statements should be send to the master...\n");
run_query($conn, "DROP TABLE IF EXISTS test");
run_query($conn, "CREATE TABLE test(id INT)");
run_query($conn, "INSERT INTO test(id) VALUES (1)");
printf("Dumping list of connections. Should be only one, the master connection...\n");
foreach ($queries as $thread_id => $details) {
printf("\t... Connection %d has run\n", $thread_id);
foreach ($details as $query)
printf("\t\t... %s\n", $query);
}
printf("Running a SELECT, it should be send to the first slave...\n");
run_query($conn, "SELECT 'slave1' FROM DUAL");
printf("Running a SELECT, it should be send to the second slave because of round robin...\n");
run_query($conn, "SELECT 'slave2' FROM DUAL");
printf("Dumping list of connections. Should be three: master and both slaves, one SELECT on each slave\n");
foreach ($queries as $thread_id => $details) {
printf("\t... Connection %d has run\n", $thread_id);
foreach ($details as $query)
printf("\t\t... %s\n", $query);
}
printf("\n");
printf("Running a SELECT, it should be send the slaves configured for partition A only. This is the first slave only...\n");
run_query($conn, "/*Partition_A*/SELECT 'slave1' FROM DUAL");
printf("Running a SELECT, it should be send the slaves configured for partition A only. This is the first slave only...\n");
run_query($conn, "/*Partition_A*/SELECT 'slave1' FROM DUAL");
printf("Dumping list of connections. Should be three: master and both slaves, three queries for slave one, one query for slave two\n");
foreach ($queries as $thread_id => $details) {
printf("\t... Connection %d has run\n", $thread_id);
foreach ($details as $query)
printf("\t\t... %s\n", $query);
}
printf("
If everything has gone right, you should see how the queries prefixed with the SQL hint /*Partition_A*/
have been executed on the only slave that can handle this partition.
This can be used for partitioning, including manual sharding but also to work around hotspots.\n");
printf("\n");
?> mysqlnd_ms-1.5.2/tests/bench/framework/web/rb_create_csv.php 0000664 0001750 0001750 00000015546 12161007456 023557 0 ustar andrey andrey getRunList();
$binaries = (isset($_REQUEST['binaries'])) ? $_REQUEST['binaries'] : NULL;
$binarylist = ($run_id) ? $storage->getBinaryList($run_id) : NULL;
$labels = (isset($_REQUEST['labels'])) ? $_REQUEST['labels'] : NULL;
$labellist = ($binaries) ? $storage->getMeasuredTimeLabels($run_id) : NULL;
if ($run_id && $binaries && $labels) {
$lines = array();
$sep = ';';
$first = true;
foreach ($binaries as $k => $run_id) {
$run_info = $storage->getRunInfoByRunID($run_id);
if ($first) {
$line = '';
foreach ($run_info as $label => $v)
$line .= sprintf("%s%s", $label, $sep);
$line = substr($line, 0, strlen($sep) * -1);
$lines[] = $line;
$first = false;
}
$lines[] = implode($sep, $run_info);
}
$lines[] = '';
$file = sys_get_temp_dir() . '/version.php';
$fp = fopen($file, 'w');
fwrite($fp, '');
fclose($fp);
$line1 = $line2 = $line3 = $line4 = '';
$line_bin_label = $sep;
$mysqlnd_run_id = null;
foreach ($binaries as $k => $run_id) {
foreach ($binarylist as $k => $binaryinfo) {
if ($binaryinfo['run_id'] == $run_id) {
$line1 .= sprintf("%s%s", $binaryinfo['binary_label'], $sep);
$line2 .= sprintf("%s%s", $binaryinfo['binary_file'], $sep);
$cmd = sprintf('%s -f %s', $binaryinfo['binary_file'], $file);
$output = array();
exec($cmd, $output);
$line3 .= sprintf("%s%s", $output[0], $sep);
$line4 .= sprintf("%s%s", $output[1], $sep);
if (stristr($output[1], 'mysqlnd'))
$mysqlnd_run_id = $run_id;
}
}
}
$line_bin_label .= substr($line1, 0, strlen($sep) * -1);
$lines[] = substr($line1, 0, strlen($sep) * -1);
$lines[] = substr($line2, 0, strlen($sep) * -1);
$lines[] = substr($line3, 0, strlen($sep) * -1);
$lines[] = substr($line4, 0, strlen($sep) * -1);
$lines[] = '';
if (!$mysqlnd_run_id) {
reset($binaries);
list($k, $mysqlnd_run_id) = each($binaries);
}
unlink($file);
/* HACK */
$runtimes = array();
foreach ($labels as $k => $label) {
foreach ($binaries as $k => $run_id) {
$runtime = $storage->getRuntimeByRunIDAndLabel($run_id, $label);
$runtimes[$label][$run_id] = $runtime['runtime'];
}
}
$lines[] = $line_bin_label;
foreach ($labels as $k => $label) {
$fac = (0 == $runtimes[$label][$mysqlnd_run_id]) ? 0 : 100 / $runtimes[$label][$mysqlnd_run_id];
$line = sprintf("%s%s", $label, $sep);
foreach ($binaries as $k => $run_id) {
if ($run_id == $mysqlnd_run_id) {
if (0 == $fac)
$line .= sprintf("%s%s", number_format(0, 3, ',', ''), $sep);
else
$line .= sprintf("%s%s", number_format(100, 3, ',', ''), $sep);
} else {
$line .= sprintf("%s%s", number_format($runtimes[$label][$run_id] * $fac, 3, ',', ''), $sep);
}
}
$lines[] = substr($line, 0, strlen($sep) * -1);
}
$lines[] = '';
$lines[] = $line_bin_label;
foreach ($labels as $k => $label) {
$line = sprintf("%s%s", $label, $sep);
foreach ($binaries as $k => $run_id) {
$line .= sprintf("%s%s", str_replace('.', ',', sprintf("%f", $runtimes[$label][$run_id])), $sep);
}
$lines[] = substr($line, 0, strlen($sep) * -1);
}
$lines[] = '';
$csv = implode("\n", $lines);
header("Content-type: application/vnd.ms-excel");
header("Content-Length: " . strlen($csv));
header("Content-disposition: attachment; filename=mysqlnd.csv");
die($csv);
}
} catch (Exception $e) {
printf('
Error
%s
',
nl2br(htmlspecialchars($e->getMessage())));
}
?>
Bench: Extract CVS data for Excel and Co.