mangoweb / pg-deadlock-playground
v0.1.1
2017-02-27 16:34 UTC
Requires
- php: ~7.1
- ext-pgsql: *
- nette/tester: ~1.7
- nette/utils: ~2.4
This package is auto-updated.
Last update: 2024-08-29 04:31:16 UTC
README
一个简单的工具,用于与多个并发 PostgreSQL 事务进行交互,并测试它们在什么情况下可能导致死锁。验证器类可以自动测试给定场景的所有可能的顺序。
安装
composer require mangoweb/pg-deadlock-playground
文档
创建场景
场景是一个步骤的有序序列。每个步骤都定义为一个连接 ID 和查询的元组。
$scenario = new Mangoweb\PgDeadlockPlayground\Scenario(); $scenario->addStep(0, 'SELECT 123'); // first execute SELECT 123 on connection #0 $scenario->addStep(1, 'SELECT 456'); // then execute SELECT 456 on connection #1 $scenario->addStep(1, 'SELECT 789'); // then execute SELECT 789 on connection #1 $scenario->addStep(2, 'SELECT \'abc\''); // then execute SELECT 'abc' on connection #2 $scenario->addStep(0, 'SELECT NOW()'); // then execute SELECT NOW on connection #0
在任何时刻,您都可以使用 $scenario->dump()
调用转储场景。在这种情况下,它将打印
SELECT 123
SELECT 456
SELECT 789
SELECT 'abc'
SELECT NOW()
或者,您也可以使用 Scenario::fromArray
创建相同的场景
$scenario = Mangoweb\PgDeadlockPlayground\Scenario::fromArray([ ['SELECT 123', NULL, NULL ], [NULL, 'SELECT 456', NULL ], [NULL, 'SELECT 789', NULL ], [NULL, NULL, 'SELECT \'abc\''], ['SELECT NOW()', NULL, NULL ], ]);
生成所有场景步骤顺序
要获取给定场景的所有可能的步骤顺序,请调用 $scenario->getAllOrderings()
。例如,以下代码
$scenario = Mangoweb\PgDeadlockPlayground\Scenario::fromArray([ ['SELECT 123', NULL ], [NULL, 'SELECT 456'], [NULL, 'SELECT 789'], ]); foreach ($scenario->getAllOrderings() as $scenarioVariant) { $scenarioVariant->dump(); }
将输出
SELECT 123
SELECT 456
SELECT 789
-----------------------
SELECT 456
SELECT 123
SELECT 789
-----------------------
SELECT 456
SELECT 789
SELECT 123
执行场景
要执行场景,您需要一个 ScenarioExecutor
实例。
$executor = Mangoweb\PgDeadlockPlayground\ScenarioExecutor::create([ 'dbname' => 'deadlock_playground', 'user' => 'postgres', 'password' => '', ]);
调用 $executor->execute($scenario)
将始终返回一个 ScenarioExecutionResult
实例。您可以通过调用 $result->dump()
来检查结果。
$result = $executor->execute($scenario); $result->dump();
理解结果
$result->dump()
的输出类似于 $scenario->dump()
,但每个步骤都带有重要的标签。
例子
用法
$config = [ 'host' => '127.0.0.1', 'dbname' => 'deadlock_playground', 'user' => 'postgres', 'password' => '', ]; $initQueries = [ 'DROP TABLE IF EXISTS users', 'CREATE TABLE users (id INTEGER NOT NULL, name TEXT NOT NULL)', 'INSERT INTO users VALUES (1, \'Logan\')' ]; $executor = Mangoweb\PgDeadlockPlayground\ScenarioExecutor::create($config, $initQueries); $verifier = new Mangoweb\PgDeadlockPlayground\ScenarioExpectationVerifier($executor); $verifier->setVerbose(); $verifier->expectAlwaysOk( Scenario::fromArray([ ['START TRANSACTION ISOLATION LEVEL REPEATABLE READ', NULL], ['LOCK users IN SHARE MODE', NULL], ['SELECT * FROM users WHERE id = 1 FOR UPDATE', NULL], ['COMMIT', NULL], [NULL, 'START TRANSACTION ISOLATION LEVEL REPEATABLE READ'], [NULL, 'UPDATE users SET name = \'John\' WHERE id = 1'], [NULL, 'COMMIT'], ]) );
输出
...
SUCCESS: completed without error
in C:\Projects\deadlock-playground\examples\readme.php:25
[OK] START TRANSACTION ISOLATION LEVEL REPEATABLE READ
[OK] LOCK users IN SHARE MODE
[OK] SELECT * FROM users WHERE id = 1 FOR UPDATE
[OK] START TRANSACTION ISOLATION LEVEL REPEATABLE READ
[OK] COMMIT
[OK] UPDATE users SET name = 'John' WHERE id = 1
[OK] COMMIT
----------------------------------------------------------------------------------------------------------------------------------
SUCCESS: completed without error
in C:\Projects\deadlock-playground\examples\readme.php:25
[OK] START TRANSACTION ISOLATION LEVEL REPEATABLE READ
[OK] LOCK users IN SHARE MODE
[OK] SELECT * FROM users WHERE id = 1 FOR UPDATE
[OK] START TRANSACTION ISOLATION LEVEL REPEATABLE READ
[WAITING...] UPDATE users SET name = 'John' WHERE id = 1
[OK] COMMIT
[...SUCCESS]
[OK] COMMIT
...