Skip to content

Commit

Permalink
Rename save to commit, add rollback
Browse files Browse the repository at this point in the history
  • Loading branch information
kelunik committed Aug 18, 2023
1 parent 22d49a8 commit 5220b9d
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 38 deletions.
85 changes: 49 additions & 36 deletions src/Session.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ final class Session

private LocalMutex $localMutex;

private int $openCount = 0;
private int $lockCount = 0;

private ?Lock $lock = null;

Expand Down Expand Up @@ -120,7 +120,7 @@ public function read(): self
}

/**
* Locks the session and opens it for writing.
* Locks the session for writing.
*
* This will implicitly reload the session data from the storage.
*/
Expand All @@ -142,7 +142,7 @@ public function lock(): self
$this->data = $this->storage->read($id);
}

++$this->openCount;
++$this->lockCount;

$this->status = self::STATUS_READ | self::STATUS_LOCKED;

Expand All @@ -151,51 +151,56 @@ public function lock(): self
}

/**
* Saves the given data in the session.
* Saves the given data in the session and unlocks it.
*
* The session must be locked with either open() before calling this method.
* The session must be locked with lock() before calling this method.
*/
public function save(): void
public function commit(): void
{
synchronized($this->localMutex, function (): void {
$this->assertLocked();
$this->unsynchronizedSave();
$this->write();
});
}

/**
* Destroys and unlocks the session data.
* Reloads the data from the storage discarding modifications and unlocks the session.
*
* @throws \Error If the session has not been opened for writing.
* The session must be locked with lock() before calling this method.
*/
public function destroy(): void
public function rollback(): void
{
synchronized($this->localMutex, function (): void {
$this->assertLocked();

$this->data = [];

$this->unsynchronizedSave();
$this->read();
$this->unlockInternally();
});
}

/**
* Unlocks the session.
*
* The session must be locked with lock() before calling this method.
*/
public function unlock(): void
{
synchronized($this->localMutex, function (): void {
if (!$this->isLocked()) {
return;
}

if ($this->openCount === 1) {
$this->lock?->release();
$this->lock = null;
$this->status &= ~self::STATUS_LOCKED;
}
$this->assertLocked();
$this->unlockInternally();
});
}

--$this->openCount;
/**
* Destroys and unlocks the session data.
*
* @throws \Error If the session has not been locked for writing.
*/
public function destroy(): void
{
synchronized($this->localMutex, function (): void {
$this->assertLocked();
$this->data = [];
$this->write();
});
}

Expand All @@ -213,23 +218,17 @@ public function unlockAll(): void
$this->lock = null;
$this->status &= ~self::STATUS_LOCKED;

$this->openCount = 0;
$this->lockCount = 0;
});
}

/**
* @throws \Error If the session has not been read.
*/
public function has(string $key): bool
{
$this->ensureRead();

return \array_key_exists($key, $this->data);
}

/**
* @throws \Error If the session has not been read.
*/
public function get(string $key): ?string
{
$this->ensureRead();
Expand All @@ -238,7 +237,7 @@ public function get(string $key): ?string
}

/**
* @throws \Error If the session has not been opened for writing.
* @throws \Error If the session has not been locked for writing.
*/
public function set(string $key, mixed $data): void
{
Expand All @@ -248,7 +247,7 @@ public function set(string $key, mixed $data): void
}

/**
* @throws \Error If the session has not been opened for writing.
* @throws \Error If the session has not been locked for writing.
*/
public function unset(string $key): void
{
Expand All @@ -267,15 +266,15 @@ public function getData(): array
return $this->data;
}

private function unsynchronizedSave(): void
private function write(): void
{
if ($this->id === null) {
throw new \Error('Invalid session');
}

$this->storage->write($this->id, $this->data);

if ($this->openCount === 1) {
if ($this->lockCount === 1) {
$this->lock?->release();
$this->lock = null;
$this->status &= ~self::STATUS_LOCKED;
Expand All @@ -285,7 +284,7 @@ private function unsynchronizedSave(): void
}
}

--$this->openCount;
--$this->lockCount;
}

private function ensureRead(): void
Expand All @@ -303,4 +302,18 @@ private function assertLocked(): void
throw new \Error('The session has not been locked');
}
}

/**
* @return void
*/
function unlockInternally(): void
{
if ($this->lockCount === 1) {
$this->lock?->release();
$this->lock = null;
$this->status &= ~self::STATUS_LOCKED;
}

--$this->lockCount;
}
}