vector clock
1.0.0
该项目是论文中定义的向量时钟和Lamport时间戳的概念的PHP实现:通过消息通信系统中的时间戳保留部分排序(Paper/Vector/vector-clock-lock-paper.pdf)。
该库提供:
这些实现仔细遵循研究论文,所有类别都经过全面测试(100%覆盖范围)。
本文中存在的每个示例都被转录为Phpunit测试。
composer require dynamophp/vector-clock <?php
$ lt1 = new LamportTimestamp ( 76 );
$ lt2 = new LamportTimestamp ( 59 );
assertEquals ( 76 , lt1-> getValue ());
assertEquals ( 59 , lt2-> getValue ());
assertTrue ( $ lt1 -> happenAfter ( $ lt2 )); // lt2 -> lt1
assertTrue ( $ lt2 -> happenBefore ( $ lt1 ));
$ lt1 -> applyLocalEvent ();
$ lt2 -> applyLocalEvent ();
assertEquals ( 77 , lt1-> getValue ());
assertEquals ( 60 , lt2-> getValue ());
assertTrue ( $ lt1 -> happenAfter ( $ lt2 )); // lt2 -> lt1
assertTrue ( $ lt2 -> happenBefore ( $ lt1 ));
$ lt1ToSend = clone $ lt1 -> applySendEvent ();
$ lt2 -> applyLocalEvent ();
assertEquals ( 78 , lt1-> getValue ());
assertEquals ( 78 , $ lt1ToSend -> getValue ());
assertEquals ( 61 , lt2-> getValue ());
assertTrue ( $ lt1 -> isIdenticalTo ( $ lt1ToSend )); // lt1 == lt1ToSend
assertFalse ( $ lt2 -> isIdenticalTo ( $ lt1ToSend )); // lt2 != lt1ToSend
$ lt2 -> applyReceiveEvent ( $ lt1ToSend );
assertEquals ( 78 , lt1-> getValue ());
assertEquals ( 79 , lt2-> getValue ());
assertTrue ( $ lt1 -> happenBefore ( $ lt2 )); // lt1 -> lt2
assertTrue ( $ lt2 -> happenAfter ( $ lt1 ));在测试案例中: Lamporttimestampscenariotest :: Test PaperpaperFigure1a和LamportTimestampScenariotest :: Testpaperfigure1b您可以看到论文的完整情况:

<?php
// We create three clocks, one for each node in our system
$ clockNode1 = new AsyncVectorClock ( ' NODE-1 ' );
$ clockNode2 = new AsyncVectorClock ( ' NODE-2 ' );
$ clockNode3 = new AsyncVectorClock ( ' NODE-3 ' );
// Then, for each clock, we add the others nodes in the current vector
$ clockNode1 -> addNode ( ' NODE-2 ' );
$ clockNode1 -> addNode ( ' NODE-3 ' );
$ clockNode2 -> addNode ( ' NODE-1 ' );
$ clockNode2 -> addNode ( ' NODE-3 ' );
$ clockNode3 -> addNode ( ' NODE-1 ' );
$ clockNode3 -> addNode ( ' NODE-2 ' );
// All clocks must look like [0, 0, 0]
// After the initialization part, we can play with our clocks
$ a = ( clone $ clockProcess1 )-> applySendEvent (); // [1, 0, 0]
$ l = ( clone $ clockProcess2 )-> applyLocalEvent (); // [0, 1, 0]
$ v = ( clone $ clockProcess3 )-> applyLocalEvent (); // [0, 0, 1]
$ b = ( clone $ a )-> applyLocalEvent (); // [2, 0, 0]
$ m = ( clone $ l )-> applyReceiveEvent ( $ a ); // [2, 2, 0]
$ w = ( clone $ v )-> applyLocalEvent (); // [0, 0, 3]
// And one more important thing, we can compare clocks
assertTrue ( $ l -> canBeComparedWith ( $ v ));
assertTrue ( $ a -> isIdenticalTo ( $ a )); // a == a
assertTrue ( $ l -> isConcurrentWith ( $ v )); // l <-> v
assertTrue ( $ m -> happenAfter ( $ a )); // a -> m
assertTrue ( $ a -> happenBefore ( $ m )); // a -> m
assertTrue ( $ l -> happenBefore ( $ m )); // l -> m在测试案例中:异步vectorcenariotest :: Test Paperpaperfigure3您可以看到本文的完整情况:

<?php
// We create three clocks, one for each node in our system
$ clockNode1 = new SyncVectorClock ( ' NODE-1 ' );
$ clockNode2 = new SyncVectorClock ( ' NODE-2 ' );
$ clockNode3 = new SyncVectorClock ( ' NODE-3 ' );
// Then, for each clock, we add the others nodes in the current vector
$ clockNode1 -> addNode ( ' NODE-2 ' );
$ clockNode1 -> addNode ( ' NODE-3 ' );
$ clockNode2 -> addNode ( ' NODE-1 ' );
$ clockNode2 -> addNode ( ' NODE-3 ' );
$ clockNode3 -> addNode ( ' NODE-1 ' );
$ clockNode3 -> addNode ( ' NODE-2 ' );
// All clocks must look like [0, 0, 0] and are idle (i.e. not in communication with another node)
// After the initialization part, we can play with our clocks
assertTrue ( $ clockNode1 -> isIdle ());
assertTrue ( $ clockNode2 -> isIdle ());
assertTrue ( $ clockNode3 -> isIdle ());
$ a = ( clone $ clockNode1 )-> applyLocalEvent (); // [1, 0, 0]
$ t = ( clone $ clockNode3 )-> applyLocalEvent (); // [0, 0, 1]
// Then we want to make a synchrone communication between node1 and node2
$ b = clone $ a ; // [1, 0, 0]
$ l = clone $ clockNode2 ; // [0, 0, 0]
$ b -> applySendEvent ( $ l -> getNode ());
assertTrue ( $ b -> isCommunicating ());
assertEquals ( ' NODE-2 ' , $ b -> getCommunicatingNode ());
// $b sends its clock and is in a communicating state
// This means that, if you try to modify the clock you will get a ClockIsNotIdleException
// The only way for $b to become idle again is to receive a clock from NODE-2 (the current node is communicating with)
// As soon as $b receive a clock from NODE-2, it will merge it and go back to idle state and can be modified again
$ l -> applyReceiveEvent ( $ b ); // [2, 1, 0]
$ b -> applyReceiveEvent ( $ l ); // [2, 1, 0]
assertTrue ( $ b -> isIdle ());
// And one more important thing, we can compare clocks
assertTrue ( $ a -> canBeComparedWith ( $ t ));
assertTrue ( $ a -> isIdenticalTo ( $ a )); // a == a
assertTrue ( $ l -> isIdenticalTo ( $ b )); // l == b
assertTrue ( $ a -> isConcurrentWith ( $ t )); // a <-> t
assertTrue ( $ l -> happenAfter ( $ a )); // a -> l
assertTrue ( $ a -> happenBefore ( $ b )); // a -> b
assertTrue ( $ a -> happenBefore ( $ l )); // a -> l在测试案例中: SyncvectorsCenariotest :: Test Paperpaperfigure7您可以看到本文的完整情况:

您可以使用旧的PHP安装或Docker在本地启动该项目。
如果您使用Docker,则在docker目录中为您提供一个Docker-Compose文件。
cd docker && docker-compose up -d在您中使用作曲家dev env:
composer install您的代码必须通过phpcsfixer传递:
修复src/
php vendor/bin/php-cs-fixer fix src --rules=@Symfony修复tests/
php vendor/bin/php-cs-fixer fix tests --rules=@Symfony并通过phpstan进行分析
php vendor/bin/phpstan analyse src -c /app/phpstan.neon该项目使用phpunit
这是启动测试套件的命令
php vendor/phpunit/phpunit/phpunit --configuration phpunit.xml.dist tests注意:您需要Xdebug进行覆盖范围。如果您使用此项目中提供的Docker Env,则已经安装和配置。
您的提交消息必须遵循此公约