Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@
use FreeDSx\Ldap\Server\Backend\Storage\Adapter\Support\ArrayEntryStorageTrait;
use FreeDSx\Ldap\Server\Backend\Storage\EntryStream;
use FreeDSx\Ldap\Server\Backend\Storage\EntryStorageInterface;
use FreeDSx\Ldap\Server\Backend\Storage\Journal\Capture\ChangeJournalingInterface;
use FreeDSx\Ldap\Server\Backend\Storage\Journal\Change\PendingChange;
use FreeDSx\Ldap\Server\Backend\Storage\Journal\ChangeJournalInterface;
use FreeDSx\Ldap\Server\Backend\Storage\Journal\ChangeJournalingInterface;
use FreeDSx\Ldap\Server\Backend\Storage\Journal\InMemoryChangeJournal;
use FreeDSx\Ldap\Server\Backend\Storage\Journal\PendingChange;
use FreeDSx\Ldap\Server\Backend\Storage\StorageListOptions;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
* file that was distributed with this source code.
*/

namespace FreeDSx\Ldap\Server\Backend\Storage\Journal;
namespace FreeDSx\Ldap\Server\Backend\Storage\Journal\Capture;

use FreeDSx\Ldap\Server\Backend\Storage\Journal\Change\PendingChange;

/**
* Append a change within the active write boundary.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@
* file that was distributed with this source code.
*/

namespace FreeDSx\Ldap\Server\Backend\Storage\Journal;
namespace FreeDSx\Ldap\Server\Backend\Storage\Journal\Capture;

use FreeDSx\Ldap\Entry\Dn;
use FreeDSx\Ldap\Entry\Entry;
use FreeDSx\Ldap\Schema\Definition\AttributeTypeOid;
use FreeDSx\Ldap\Server\Backend\Storage\EntryStorageInterface;
use FreeDSx\Ldap\Server\Backend\Storage\Journal\Change\ChangeType;
use FreeDSx\Ldap\Server\Backend\Storage\Journal\Change\PendingChange;
use FreeDSx\Ldap\Server\Backend\Write\WriteContext;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@
* file that was distributed with this source code.
*/

namespace FreeDSx\Ldap\Server\Backend\Storage\Journal;
namespace FreeDSx\Ldap\Server\Backend\Storage\Journal\Change;

use DateTimeImmutable;
use FreeDSx\Ldap\Server\Backend\Storage\Journal\ReplicaId;

/**
* A PendingChange stamped by the journal.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
* file that was distributed with this source code.
*/

namespace FreeDSx\Ldap\Server\Backend\Storage\Journal;
namespace FreeDSx\Ldap\Server\Backend\Storage\Journal\Change;

/**
* The kind of write a change-journal record captures.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
* file that was distributed with this source code.
*/

namespace FreeDSx\Ldap\Server\Backend\Storage\Journal;
namespace FreeDSx\Ldap\Server\Backend\Storage\Journal\Change;

use FreeDSx\Ldap\Entry\Dn;
use FreeDSx\Ldap\Entry\Entry;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@

namespace FreeDSx\Ldap\Server\Backend\Storage\Journal;

use FreeDSx\Ldap\Server\Backend\Storage\Journal\Change\ChangeRecord;
use FreeDSx\Ldap\Server\Backend\Storage\Journal\Change\PendingChange;

/**
* Append-only log of committed writes.
*
Expand Down Expand Up @@ -40,4 +43,11 @@ public function read(int $afterSeq = 0): iterable;
* @api
*/
public function latestSeq(): int;

/**
* Drop records that fall outside the policy; returns how many were removed. seq keeps climbing.
*
* @api
*/
public function prune(RetentionPolicy $policy): int;
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

namespace FreeDSx\Ldap\Server\Backend\Storage\Journal;

use FreeDSx\Ldap\Server\Backend\Storage\Journal\Change\ChangeRecord;
use FreeDSx\Ldap\Server\Backend\Storage\Journal\Change\PendingChange;
use FreeDSx\Ldap\Server\Clock\ClockInterface;
use FreeDSx\Ldap\Server\Clock\SystemClock;

Expand Down Expand Up @@ -61,4 +63,29 @@ public function latestSeq(): int
{
return $this->seq;
}

public function prune(RetentionPolicy $policy): int
{
$before = count($this->records);
$records = $this->records;

if ($policy->maxRecords !== null && count($records) > $policy->maxRecords) {
$records = array_slice(
$records,
count($records) - $policy->maxRecords,
);
}

if ($policy->maxAgeSeconds !== null) {
$oldest = $this->clock->now()->getTimestamp() - $policy->maxAgeSeconds;
$records = array_filter(
$records,
static fn(ChangeRecord $record): bool => $record->createdAt->getTimestamp() >= $oldest,
);
}

$this->records = array_values($records);

return $before - count($this->records);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

declare(strict_types=1);

/**
* This file is part of the FreeDSx LDAP package.
*
* (c) Chad Sikorra <Chad.Sikorra@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace FreeDSx\Ldap\Server\Backend\Storage\Journal\Read;

use FreeDSx\Ldap\Entry\Dn;

/**
* A base DN plus extent that decides whether a change falls within a consumer's view.
*
* @author Chad Sikorra <Chad.Sikorra@gmail.com>
*/
final readonly class ChangeScope
{
private function __construct(
private Dn $baseDn,
private ScopeType $type,
) {}

public static function baseObject(Dn $baseDn): self
{
return new self(
$baseDn,
ScopeType::BaseObject,
);
}

public static function oneLevel(Dn $baseDn): self
{
return new self(
$baseDn,
ScopeType::OneLevel,
);
}

public static function wholeSubtree(Dn $baseDn): self
{
return new self(
$baseDn,
ScopeType::WholeSubtree,
);
}

public function contains(Dn $dn): bool
{
return match ($this->type) {
ScopeType::BaseObject => $dn->normalize()->toString() === $this->baseDn->normalize()->toString(),
ScopeType::OneLevel => $dn->isChildOf($this->baseDn),
ScopeType::WholeSubtree => $dn->isDescendantOf($this->baseDn),
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

declare(strict_types=1);

/**
* This file is part of the FreeDSx LDAP package.
*
* (c) Chad Sikorra <Chad.Sikorra@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace FreeDSx\Ldap\Server\Backend\Storage\Journal\Read;

use FreeDSx\Ldap\Server\Backend\Storage\Journal\Change\ChangeRecord;
use FreeDSx\Ldap\Server\Backend\Storage\Journal\ChangeJournalInterface;

/**
* Read-only view over the journal: the seam the audit sink and RFC 4533 provider consume.
*
* @author Chad Sikorra <Chad.Sikorra@gmail.com>
*/
final readonly class ChangeStream
{
public function __construct(
private ChangeJournalInterface $journal,
) {}

/**
* Records with seq greater than $afterSeq, optionally narrowed to a scope, in ascending seq order.
*
* @api
*
* @return iterable<ChangeRecord>
*/
public function since(
int $afterSeq = 0,
?ChangeScope $scope = null,
): iterable {
foreach ($this->journal->read($afterSeq) as $record) {
if ($scope === null || $scope->contains($record->change->dn)) {
yield $record;
}
}
}

/**
* The highest seq currently in the journal; the high-water mark a consumer cookie advances to.
*
* @api
*/
public function latestSeq(): int
{
return $this->journal->latestSeq();
}
}
26 changes: 26 additions & 0 deletions src/FreeDSx/Ldap/Server/Backend/Storage/Journal/Read/ScopeType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

declare(strict_types=1);

/**
* This file is part of the FreeDSx LDAP package.
*
* (c) Chad Sikorra <Chad.Sikorra@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace FreeDSx\Ldap\Server\Backend\Storage\Journal\Read;

/**
* The DIT extent a change stream covers.
*
* @author Chad Sikorra <Chad.Sikorra@gmail.com>
*/
enum ScopeType
{
case BaseObject;
case OneLevel;
case WholeSubtree;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

/**
* This file is part of the FreeDSx LDAP package.
*
* (c) Chad Sikorra <Chad.Sikorra@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace FreeDSx\Ldap\Server\Backend\Storage\Journal;

use FreeDSx\Ldap\Exception\InvalidArgumentException;

/**
* Bounds journal growth: a record is purge-eligible once it fails either limit (whichever is tighter).
*
* @author Chad Sikorra <Chad.Sikorra@gmail.com>
*/
final readonly class RetentionPolicy
{
/**
* @param ?int $maxRecords hard ceiling on retained records, or null for no count limit
* @param ?int $maxAgeSeconds age horizon in seconds, or null for no time limit
*/
public function __construct(
public ?int $maxRecords = null,
public ?int $maxAgeSeconds = null,
) {
if ($maxRecords !== null && $maxRecords < 1) {
throw new InvalidArgumentException('maxRecords must be at least 1 when set.');
}

if ($maxAgeSeconds !== null && $maxAgeSeconds < 1) {
throw new InvalidArgumentException('maxAgeSeconds must be at least 1 when set.');
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
use FreeDSx\Ldap\Operation\Request\SearchRequest;
use FreeDSx\Ldap\Operation\ResultCode;
use FreeDSx\Ldap\Server\Backend\Storage\Adapter\Operation\WriteEntryOperationHandler;
use FreeDSx\Ldap\Server\Backend\Storage\Journal\ChangeRecorder;
use FreeDSx\Ldap\Server\Backend\Storage\Journal\Capture\ChangeRecorder;
use FreeDSx\Ldap\Server\Backend\Write\Command\AddCommand;
use FreeDSx\Ldap\Server\Backend\Write\Command\DeleteCommand;
use FreeDSx\Ldap\Server\Backend\Write\Command\MoveCommand;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@
use FreeDSx\Ldap\Server\Backend\Storage\Adapter\InMemoryStorage;
use FreeDSx\Ldap\Server\Backend\Storage\EntryStorageInterface;
use FreeDSx\Ldap\Server\Backend\Storage\EntryStream;
use FreeDSx\Ldap\Server\Backend\Storage\Journal\ChangeRecord;
use FreeDSx\Ldap\Server\Backend\Storage\Journal\ChangeRecorder;
use FreeDSx\Ldap\Server\Backend\Storage\Journal\ChangeType;
use FreeDSx\Ldap\Server\Backend\Storage\Journal\Capture\ChangeRecorder;
use FreeDSx\Ldap\Server\Backend\Storage\Journal\Change\ChangeRecord;
use FreeDSx\Ldap\Server\Backend\Storage\Journal\Change\ChangeType;
use FreeDSx\Ldap\Server\Backend\Storage\Journal\Change\PendingChange;
use FreeDSx\Ldap\Server\Backend\Storage\Journal\InMemoryChangeJournal;
use FreeDSx\Ldap\Server\Backend\Storage\Journal\PendingChange;
use FreeDSx\Ldap\Server\Backend\Storage\Exception\InvalidAttributeException;
use FreeDSx\Ldap\Server\Backend\Storage\Exception\StorageIoException;
use FreeDSx\Ldap\Server\Backend\Storage\Exception\TimeLimitExceededException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
* file that was distributed with this source code.
*/

namespace Tests\Unit\FreeDSx\Ldap\Server\Backend\Storage\Journal;
namespace Tests\Unit\FreeDSx\Ldap\Server\Backend\Storage\Journal\Capture;

use FreeDSx\Ldap\Control\ControlBag;
use FreeDSx\Ldap\Entry\Attribute;
Expand All @@ -20,9 +20,9 @@
use FreeDSx\Ldap\Schema\Definition\AttributeTypeOid;
use FreeDSx\Ldap\Server\Backend\Storage\Adapter\InMemoryStorage;
use FreeDSx\Ldap\Server\Backend\Storage\EntryStorageInterface;
use FreeDSx\Ldap\Server\Backend\Storage\Journal\ChangeRecord;
use FreeDSx\Ldap\Server\Backend\Storage\Journal\ChangeRecorder;
use FreeDSx\Ldap\Server\Backend\Storage\Journal\ChangeType;
use FreeDSx\Ldap\Server\Backend\Storage\Journal\Capture\ChangeRecorder;
use FreeDSx\Ldap\Server\Backend\Storage\Journal\Change\ChangeRecord;
use FreeDSx\Ldap\Server\Backend\Storage\Journal\Change\ChangeType;
use FreeDSx\Ldap\Server\Backend\Storage\Journal\InMemoryChangeJournal;
use FreeDSx\Ldap\Server\Backend\Write\WriteContext;
use FreeDSx\Ldap\Server\Token\BindToken;
Expand Down
Loading
Loading