\Drupal\strata\Cas PackIndex

The per-frame directory a pack carries at its own end.

A pack is a flat concatenation of encoded frames with no framing between them, so the only thing that can find a frame inside one is a map of offsets. Keeping that map exclusively in the local database would make every packed frame unreadable the moment the database went away - which is precisely the situation strata:reindex exists to recover from, and precisely the situation a module uninstall creates. So the map is written into the object as well, after the frames.

The directory sits at the END rather than the front because a frame is read by absolute offset from byte zero; a header would have to be a fixed width or every offset would depend on the size of the thing describing them. A trailer of a known shape is found by reading the last PackIndex::TAIL_BYTES bytes, which is one ranged GET on any endpoint that supports ranges.

Each entry carries what a frame record needs and nothing more. At 16 KiB frames in a 1 MiB pack that is about 64 entries and roughly 0.8% of the object.

Summary

Methods
Properties
Constants
encode
decode
trailerLength
No public properties found
MAGIC
LENGTH_DIGITS
TAIL_BYTES
No protected methods found
No protected properties found
No protected constants found
parse
No private properties found
No private constants found

Constant

MAGIC

MAGIC = 'STRATA-PAK-1'

Magic bytes and format version closing every pack.

LENGTH_DIGITS

LENGTH_DIGITS = 10

Width of the decimal length that follows the magic.

TAIL_BYTES

TAIL_BYTES = 22

Fixed size of the tail: the magic plus the directory length.

Methods

encode()

encode(list>  $entries) : string

Serializes a directory into the bytes that close a pack.

Parameters

list> $entries

One entry per frame, each carrying hash, offset, length, raw, codec, cipher and optionally dictionary, parent and depth.

Throws

\InvalidArgumentException

When an entry names no valid content address.

Returns

string —

The trailer, ready to append to the concatenated frames.

decode()

decode(string  $key, string  $object) : list<array<string,mixed>>

Reads the directory out of a whole pack object.

Parameters

string $key

The object key, for error messages.

string $object

The pack bytes, including the trailer.

Throws

\RuntimeException

When the object is too short, carries no directory, or the directory does not parse.

Returns

list> —

One entry per frame, in the order they appear in the pack, with the same keys PackIndex::encode() accepts.

trailerLength()

trailerLength(string  $key, string  $tail) : int

Reads the directory length out of a pack's fixed-size tail.

Split out so a reader with range support can fetch PackIndex::TAIL_BYTES, learn how long the directory is, and fetch only that - two small reads instead of a whole 1 MiB object.

Parameters

string $key

The object key, for error messages.

string $tail

The last PackIndex::TAIL_BYTES bytes of the object.

Throws

\RuntimeException

When the tail is the wrong size, or does not carry the magic this release writes.

Returns

int —

Length of the directory in bytes.

parse()

parse(string  $key, string  $body) : list<array<string,mixed>>

Expands a serialized directory back into entries.

Parameters

string $key

The object key, for error messages.

string $body

The serialized directory.

Throws

\RuntimeException

When the directory does not parse, or names a version this release cannot read.

Returns

list> —

The entries.