diff --git a/baseline.xml b/baseline.xml
index 1516fe05e..6ad294974 100644
--- a/baseline.xml
+++ b/baseline.xml
@@ -82,30 +82,31 @@
$name
-
+
$bus
$repository
$store
-
+
+ $adapter
$bus
$repository
$snapshotStore
$store
-
+
$bus
- $profile
$repository
+ $snapshotStore
$store
-
+
$bus
$profile
diff --git a/src/Snapshot/Adapter/InMemorySnapshotAdapter.php b/src/Snapshot/Adapter/InMemorySnapshotAdapter.php
index 74fa75bc3..70ab200da 100644
--- a/src/Snapshot/Adapter/InMemorySnapshotAdapter.php
+++ b/src/Snapshot/Adapter/InMemorySnapshotAdapter.php
@@ -26,4 +26,9 @@ public function load(string $key): array
return $this->snapshots[$key];
}
+
+ public function clear(): void
+ {
+ $this->snapshots = [];
+ }
}
diff --git a/tests/Benchmark/BasicImplementation/Aggregate/Profile.php b/tests/Benchmark/BasicImplementation/Aggregate/Profile.php
index 875ed9b70..9d02bcc8c 100644
--- a/tests/Benchmark/BasicImplementation/Aggregate/Profile.php
+++ b/tests/Benchmark/BasicImplementation/Aggregate/Profile.php
@@ -10,6 +10,7 @@
use Patchlevel\EventSourcing\Attribute\Snapshot;
use Patchlevel\EventSourcing\Tests\Benchmark\BasicImplementation\Events\NameChanged;
use Patchlevel\EventSourcing\Tests\Benchmark\BasicImplementation\Events\ProfileCreated;
+use Patchlevel\EventSourcing\Tests\Benchmark\BasicImplementation\Events\Reborn;
use Patchlevel\EventSourcing\Tests\Benchmark\BasicImplementation\Normalizer\ProfileIdNormalizer;
use Patchlevel\EventSourcing\Tests\Benchmark\BasicImplementation\ProfileId;
@@ -39,6 +40,14 @@ public function changeName(string $name): void
$this->recordThat(new NameChanged($name));
}
+ public function reborn(): void
+ {
+ $this->recordThat(new Reborn(
+ $this->id,
+ $this->name,
+ ));
+ }
+
#[Apply]
protected function applyProfileCreated(ProfileCreated $event): void
{
@@ -52,6 +61,13 @@ protected function applyNameChanged(NameChanged $event): void
$this->name = $event->name;
}
+ #[Apply]
+ protected function applyReborn(Reborn $event): void
+ {
+ $this->id = $event->profileId;
+ $this->name = $event->name;
+ }
+
public function name(): string
{
return $this->name;
diff --git a/tests/Benchmark/BasicImplementation/Events/Reborn.php b/tests/Benchmark/BasicImplementation/Events/Reborn.php
new file mode 100644
index 000000000..e4d7e9ef2
--- /dev/null
+++ b/tests/Benchmark/BasicImplementation/Events/Reborn.php
@@ -0,0 +1,22 @@
+id;
}
+
+ public static function generate(): self
+ {
+ return new self(uniqid('', true));
+ }
}
diff --git a/tests/Benchmark/LoadEventsBench.php b/tests/Benchmark/SimpleSetupBench.php
similarity index 82%
rename from tests/Benchmark/LoadEventsBench.php
rename to tests/Benchmark/SimpleSetupBench.php
index fb98e5bd7..a2c2078ae 100644
--- a/tests/Benchmark/LoadEventsBench.php
+++ b/tests/Benchmark/SimpleSetupBench.php
@@ -23,7 +23,7 @@
use function unlink;
#[Bench\BeforeMethods('setUp')]
-final class LoadEventsBench
+final class SimpleSetupBench
{
private const DB_PATH = __DIR__ . '/BasicImplementation/data/db.sqlite3';
@@ -74,4 +74,23 @@ public function benchLoad10000Events(): void
{
$this->repository->load('1');
}
+
+ #[Bench\Revs(20)]
+ public function benchSave1Event(): void
+ {
+ $profile = Profile::create(ProfileId::generate(), 'Peter');
+ $this->repository->save($profile);
+ }
+
+ #[Bench\Revs(20)]
+ public function benchSave10000Events(): void
+ {
+ $profile = Profile::create(ProfileId::generate(), 'Peter');
+
+ for ($i = 1; $i < 10_000; $i++) {
+ $profile->changeName('Peter');
+ }
+
+ $this->repository->save($profile);
+ }
}
diff --git a/tests/Benchmark/LoadEventsWithSnapshotsBench.php b/tests/Benchmark/SnapshotsBench.php
similarity index 89%
rename from tests/Benchmark/LoadEventsWithSnapshotsBench.php
rename to tests/Benchmark/SnapshotsBench.php
index 2f87ff3ba..0a14eee32 100644
--- a/tests/Benchmark/LoadEventsWithSnapshotsBench.php
+++ b/tests/Benchmark/SnapshotsBench.php
@@ -26,7 +26,7 @@
use function unlink;
#[Bench\BeforeMethods('setUp')]
-final class LoadEventsWithSnapshotsBench
+final class SnapshotsBench
{
private const DB_PATH = __DIR__ . '/BasicImplementation/data/db.sqlite3';
@@ -35,6 +35,8 @@ final class LoadEventsWithSnapshotsBench
private SnapshotStore $snapshotStore;
private Repository $repository;
+ private InMemorySnapshotAdapter $adapter;
+
public function setUp(): void
{
if (file_exists(self::DB_PATH)) {
@@ -55,7 +57,9 @@ public function setUp(): void
'eventstore',
);
- $this->snapshotStore = new DefaultSnapshotStore(['default' => new InMemorySnapshotAdapter()]);
+ $this->adapter = new InMemorySnapshotAdapter();
+
+ $this->snapshotStore = new DefaultSnapshotStore(['default' => $this->adapter]);
$this->repository = new DefaultRepository($this->store, $this->bus, Profile::metadata(), $this->snapshotStore);
@@ -76,6 +80,13 @@ public function setUp(): void
$this->snapshotStore->save($profile);
}
+ #[Bench\Revs(20)]
+ public function benchLoad10000EventsMissingSnapshot(): void
+ {
+ $this->adapter->clear();
+ $this->repository->load('1');
+ }
+
#[Bench\Revs(20)]
public function benchLoad10000Events(): void
{
diff --git a/tests/Benchmark/WriteEventsBench.php b/tests/Benchmark/SplitStreamBench.php
similarity index 60%
rename from tests/Benchmark/WriteEventsBench.php
rename to tests/Benchmark/SplitStreamBench.php
index 0a2cff4ba..cc90efd82 100644
--- a/tests/Benchmark/WriteEventsBench.php
+++ b/tests/Benchmark/SplitStreamBench.php
@@ -6,36 +6,35 @@
use Doctrine\DBAL\Driver\PDO\SQLite\Driver;
use Doctrine\DBAL\DriverManager;
+use Patchlevel\EventSourcing\EventBus\Decorator\SplitStreamDecorator;
use Patchlevel\EventSourcing\EventBus\DefaultEventBus;
use Patchlevel\EventSourcing\EventBus\EventBus;
use Patchlevel\EventSourcing\Metadata\AggregateRoot\AttributeAggregateRootRegistryFactory;
-use Patchlevel\EventSourcing\Projection\Projection\Store\InMemoryStore;
-use Patchlevel\EventSourcing\Projection\Projectionist\DefaultProjectionist;
-use Patchlevel\EventSourcing\Projection\Projector\InMemoryProjectorRepository;
+use Patchlevel\EventSourcing\Metadata\Event\AttributeEventMetadataFactory;
use Patchlevel\EventSourcing\Repository\DefaultRepository;
use Patchlevel\EventSourcing\Repository\Repository;
use Patchlevel\EventSourcing\Schema\DoctrineSchemaDirector;
use Patchlevel\EventSourcing\Serializer\DefaultEventSerializer;
+use Patchlevel\EventSourcing\Snapshot\SnapshotStore;
use Patchlevel\EventSourcing\Store\DoctrineDbalStore;
use Patchlevel\EventSourcing\Store\Store;
use Patchlevel\EventSourcing\Tests\Benchmark\BasicImplementation\Aggregate\Profile;
-use Patchlevel\EventSourcing\Tests\Benchmark\BasicImplementation\Processor\SendEmailProcessor;
use Patchlevel\EventSourcing\Tests\Benchmark\BasicImplementation\ProfileId;
-use Patchlevel\EventSourcing\Tests\Benchmark\BasicImplementation\Projection\ProfileProjector;
use PhpBench\Attributes as Bench;
use function file_exists;
+use function sprintf;
use function unlink;
#[Bench\BeforeMethods('setUp')]
-final class WriteEventsBench
+final class SplitStreamBench
{
private const DB_PATH = __DIR__ . '/BasicImplementation/data/db.sqlite3';
private Store $store;
private EventBus $bus;
+ private SnapshotStore $snapshotStore;
private Repository $repository;
- private Profile $profile;
public function setUp(): void
{
@@ -48,6 +47,8 @@ public function setUp(): void
'path' => self::DB_PATH,
]);
+ $this->bus = new DefaultEventBus();
+
$this->store = new DoctrineDbalStore(
$connection,
DefaultEventSerializer::createFromPaths([__DIR__ . '/BasicImplementation/Events']),
@@ -55,48 +56,63 @@ public function setUp(): void
'eventstore',
);
- $profileProjection = new ProfileProjector($connection);
- $projectionRepository = new InMemoryProjectorRepository(
- [$profileProjection],
- );
-
- $projectionist = new DefaultProjectionist(
+ $this->repository = new DefaultRepository(
$this->store,
- new InMemoryStore(),
- $projectionRepository,
+ $this->bus,
+ Profile::metadata(),
+ null,
+ new SplitStreamDecorator(
+ new AttributeEventMetadataFactory(),
+ ),
);
- $this->bus = new DefaultEventBus();
- $this->bus->addListener(new SendEmailProcessor());
-
- $this->repository = new DefaultRepository($this->store, $this->bus, Profile::metadata());
-
$schemaDirector = new DoctrineSchemaDirector(
$connection,
$this->store,
);
$schemaDirector->create();
- $projectionist->boot();
+ }
+
+ public function provideData(): void
+ {
+ $profile = Profile::create(ProfileId::fromString('1'), 'Peter');
+
+ for ($i = 0; $i < 10_000; $i++) {
+ $profile->changeName(sprintf('Peter %d', $i));
- $this->profile = Profile::create(ProfileId::fromString('1'), 'Peter');
- $this->repository->save($this->profile);
+ if ($i % 100 !== 0) {
+ continue;
+ }
+
+ $profile->reborn();
+ }
+
+ $this->repository->save($profile);
}
#[Bench\Revs(20)]
- public function benchSave1Event(): void
+ #[Bench\BeforeMethods('provideData')]
+ public function benchLoad10000Events(): void
{
- $this->profile->changeName('Peter');
- $this->repository->save($this->profile);
+ $this->repository->load('1');
}
#[Bench\Revs(20)]
- public function benchSave10000Events(): void
+ public function benchWrite10000Events(): void
{
+ $profile = Profile::create(ProfileId::generate(), 'Peter');
+
for ($i = 0; $i < 10_000; $i++) {
- $this->profile->changeName('Peter');
+ $profile->changeName(sprintf('Peter %d', $i));
+
+ if ($i % 100 !== 0) {
+ continue;
+ }
+
+ $profile->reborn();
}
- $this->repository->save($this->profile);
+ $this->repository->save($profile);
}
}
diff --git a/tests/Benchmark/WriteEventsWithSyncProjectionistBench.php b/tests/Benchmark/SyncProjectionistBench.php
similarity index 98%
rename from tests/Benchmark/WriteEventsWithSyncProjectionistBench.php
rename to tests/Benchmark/SyncProjectionistBench.php
index ab691e939..028eec29c 100644
--- a/tests/Benchmark/WriteEventsWithSyncProjectionistBench.php
+++ b/tests/Benchmark/SyncProjectionistBench.php
@@ -33,7 +33,7 @@
use function unlink;
#[Bench\BeforeMethods('setUp')]
-final class WriteEventsWithSyncProjectionistBench
+final class SyncProjectionistBench
{
private const DB_PATH = __DIR__ . '/BasicImplementation/data/db.sqlite3';