1
|
|
|
<?php |
2
|
|
|
declare(strict_types=1); |
3
|
|
|
error_reporting(E_ALL); |
4
|
|
|
date_default_timezone_set('UTC'); |
5
|
|
|
include __DIR__ . '/../vendor/autoload.php'; |
6
|
|
|
|
7
|
|
|
use Doctrine\DBAL\Connection; |
8
|
|
|
use Doctrine\DBAL\DriverManager; |
9
|
|
|
use MySQLReplication\Config\ConfigBuilder; |
10
|
|
|
use MySQLReplication\Definitions\ConstEventType; |
11
|
|
|
use MySQLReplication\Event\DTO\UpdateRowsDTO; |
12
|
|
|
use MySQLReplication\Event\EventSubscribers; |
13
|
|
|
use MySQLReplication\MySQLReplicationFactory; |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* Simple benchmark to test how fast events are consumed |
17
|
|
|
*/ |
18
|
|
|
class benchmark |
19
|
|
|
{ |
20
|
|
|
private const DB_NAME = 'mysqlreplication_test'; |
21
|
|
|
private const DB_USER = 'root'; |
22
|
|
|
private const DB_PASS = 'root'; |
23
|
|
|
private const DB_HOST = '127.0.0.1'; |
24
|
|
|
private const DB_PORT = 3306; |
25
|
|
|
|
26
|
|
|
private $binLogStream; |
27
|
|
|
|
28
|
|
|
public function __construct() |
29
|
|
|
{ |
30
|
|
|
$conn = $this->getConnection(); |
31
|
|
|
$conn->exec('DROP DATABASE IF EXISTS ' . self::DB_NAME); |
|
|
|
|
32
|
|
|
$conn->exec('CREATE DATABASE ' . self::DB_NAME); |
|
|
|
|
33
|
|
|
$conn->exec('USE ' . self::DB_NAME); |
|
|
|
|
34
|
|
|
$conn->exec('CREATE TABLE test (i INT) ENGINE = MEMORY'); |
|
|
|
|
35
|
|
|
$conn->exec('INSERT INTO test VALUES(1)'); |
|
|
|
|
36
|
|
|
$conn->exec('CREATE TABLE test2 (i INT) ENGINE = MEMORY'); |
|
|
|
|
37
|
|
|
$conn->exec('INSERT INTO test2 VALUES(1)'); |
|
|
|
|
38
|
|
|
$conn->exec('RESET MASTER'); |
|
|
|
|
39
|
|
|
|
40
|
|
|
$this->binLogStream = new MySQLReplicationFactory( |
41
|
|
|
(new ConfigBuilder()) |
42
|
|
|
->withUser(self::DB_USER) |
43
|
|
|
->withPassword(self::DB_PASS) |
44
|
|
|
->withHost(self::DB_HOST) |
45
|
|
|
->withPort(self::DB_PORT) |
46
|
|
|
->withEventsOnly([ConstEventType::UPDATE_ROWS_EVENT_V2]) |
47
|
|
|
->withSlaveId(9999) |
48
|
|
|
->withDatabasesOnly([self::DB_NAME]) |
49
|
|
|
->build() |
50
|
|
|
); |
51
|
|
|
|
52
|
|
|
$this->binLogStream->registerSubscriber( |
53
|
|
|
new class extends EventSubscribers |
54
|
|
|
{ |
55
|
|
|
private $start; |
56
|
|
|
private $counter = 0; |
57
|
|
|
|
58
|
|
|
public function __construct() |
59
|
|
|
{ |
60
|
|
|
$this->start = microtime(true); |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
public function onUpdate(UpdateRowsDTO $event): void |
64
|
|
|
{ |
65
|
|
|
++$this->counter; |
66
|
|
|
if (0 === ($this->counter % 1000)) { |
67
|
|
|
echo ((int)($this->counter / (microtime(true) - $this->start)) . ' event by seconds (' . $this->counter . ' total)') . PHP_EOL; |
68
|
|
|
} |
69
|
|
|
} |
70
|
|
|
} |
71
|
|
|
); |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
private function getConnection(): Connection |
75
|
|
|
{ |
76
|
|
|
return DriverManager::getConnection( |
77
|
|
|
[ |
78
|
|
|
'user' => self::DB_USER, |
79
|
|
|
'password' => self::DB_PASS, |
80
|
|
|
'host' => self::DB_HOST, |
81
|
|
|
'port' => self::DB_PORT, |
82
|
|
|
'driver' => 'pdo_mysql', |
83
|
|
|
'dbname' => self::DB_NAME |
84
|
|
|
] |
85
|
|
|
); |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
public function run(): void |
89
|
|
|
{ |
90
|
|
|
$pid = pcntl_fork(); |
91
|
|
|
if ($pid === -1) { |
92
|
|
|
throw new InvalidArgumentException('Could not fork'); |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
if ($pid) { |
96
|
|
|
$this->consume(); |
97
|
|
|
pcntl_wait($status); |
98
|
|
|
} else { |
99
|
|
|
$this->produce(); |
100
|
|
|
} |
101
|
|
|
} |
102
|
|
|
|
103
|
|
|
private function consume(): void |
104
|
|
|
{ |
105
|
|
|
$this->binLogStream->run(); |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
private function produce(): void |
109
|
|
|
{ |
110
|
|
|
$conn = $this->getConnection(); |
111
|
|
|
|
112
|
|
|
echo 'Start insert data' . PHP_EOL; |
113
|
|
|
while (1) { |
114
|
|
|
$conn->exec('UPDATE test SET i = i + 1;'); |
|
|
|
|
115
|
|
|
$conn->exec('UPDATE test2 SET i = i + 1;'); |
|
|
|
|
116
|
|
|
} |
117
|
|
|
} |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
(new benchmark())->run(); |
121
|
|
|
|
This function has been deprecated. The supplier of the function has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.