이 프로젝트는 논문에 정의 된 벡터 클록 및 Lamport 타임 스탬프 의 개념을 PHP 구현 : 부분 순서 (paper/vector-clock-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 :: testpaperfigure1a 및 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테스트 사례 : asyncvectorscenariotest :: testpaperfigure3 용지의 전체 시나리오를 볼 수 있습니다.

<?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 :: testpaperfigure7 용지의 전체 시나리오를 볼 수 있습니다.

구식 PHP 설치 또는 Docker를 사용하여 프로젝트를 로컬로 시작할 수 있습니다.
Docker를 사용하는 경우 docker 디렉토리에 Docker-Compose 파일이 있습니다.
cd docker && docker-compose up -dComposer 사용 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=@SymfonyPhpstan 에 의해 분석됩니다
php vendor/bin/phpstan analyse src -c /app/phpstan.neon프로젝트는 phpunit을 사용합니다
테스트 스위트를 시작하라는 명령은 다음과 같습니다
php vendor/phpunit/phpunit/phpunit --configuration phpunit.xml.dist tests참고 : 적용 범위에는 Xdebug가 필요합니다. 이 프로젝트에 제공된 Docker Env를 사용하는 경우 이미 설치 및 구성되었습니다.
Commits 메시지는 이 컨벤션을 준수해야합니다