\Drupal\strata\Delta DeltaCodec

Encodes a value against its previous version.

This is the mechanism that replaced content-defined chunking. A rewritten field - a body, a JSON blob of notifications, a serialized settings array - is almost entirely the value it replaces, but a byte-level splitter cannot see that because the change is interior. Handing the previous version to the compressor as its dictionary can: measured on 5,967-byte notification blobs with one flag flipped and one entry appended, zstd -19 against the previous version reached 63.70x and 94 bytes per object, against 4.49x and 1,330 bytes standalone - 93.0% smaller. At level 3 it is 51.93x, so the win survives the fast setting used on the flush path.

The previous version is already in memory during a capture as the entity's original, and is retrievable from the store by digest during a restore, so neither path pays to fetch it twice.

Two rules bound the dependency this creates. A chain deeper than the policy allows is anchored instead. And an encoding that does not beat the standalone form by DeltaCodec::MIN_GAIN is discarded in favour of the anchor, so a codec without dictionary support produces correct output without a branch at any call site.

Summary

Methods
Properties
Constants
__construct
canDelta
encode
decode
decodeChain
No public properties found
MIN_GAIN
No protected methods found
No protected properties found
No protected constants found
verify
codec
policy
level
No private constants found

Constant

MIN_GAIN

MIN_GAIN = 0.1

How much smaller a delta must be than its anchor to be worth the dependency.

A delta that saves less than this is discarded. A chain link costs restore latency and widens the blast radius of a lost frame, so a small saving does not cover it.

Properties

$level

$level : ?int

Type

int|null

Methods

__construct()

__construct(\Drupal\strata\Codec\CompressionCodecInterface  $codec, \Drupal\strata\Delta\ChainDepthPolicy  $policy, int|null  $level = null) : mixed

Constructs a codec.

Parameters

\Drupal\strata\Codec\CompressionCodecInterface $codec

The compressor. When it reports no dictionary support every frame is an anchor, so CodecRegistry prefers a dictionary-capable codec.

\Drupal\strata\Delta\ChainDepthPolicy $policy

The chain-depth policy.

int|null $level

Compression level, or NULL for the codec's default.

Returns

mixed —

canDelta()

canDelta() : bool

Whether this codec can actually produce deltas on this host.

Returns

bool —

FALSE when the compressor has no dictionary support, in which case every frame anchors.

encode()

encode(string  $current, string|null  $previous = null, string|null  $parentHash = null, int  $parentDepth = 0) : \Drupal\strata\Delta\DeltaFrame

Encodes a value, against its previous version when that is worthwhile.

Parameters

string $current

The value to encode.

string|null $previous

The previous version of the same subject, or NULL when there is none.

string|null $parentHash

Digest of $previous, or NULL to compute it. Pass it when the caller already has it.

int $parentDepth

Chain depth of the frame holding $previous; zero when that frame is an anchor.

Throws

\RuntimeException

When the compressor fails.

Returns

\Drupal\strata\Delta\DeltaFrame —

A delta frame when one is available, cheaper and within the depth policy; otherwise an anchor.

decode()

decode(\Drupal\strata\Delta\DeltaFrame  $frame, string|null  $previous = null) : string

Decodes a frame back to its value.

Parameters

\Drupal\strata\Delta\DeltaFrame $frame

The frame to decode.

string|null $previous

The parent value, required for a delta frame and ignored for an anchor.

Throws

\RuntimeException

When a delta frame is handed no parent, the wrong parent, or the decode is truncated.

Returns

string —

The decoded value.

decodeChain()

decodeChain(list<\Drupal\strata\Delta\DeltaFrame>  $chain) : string

Walks a chain of successive versions to the value the last frame encodes.

The whole chain is decoded in order because a delta is meaningless without the link before it. It must begin with an anchor: a chain starting at a delta cannot be decoded without a parent the caller has not supplied.

An anchor part-way through is NOT an error and must not be treated as one. Two ordinary things produce it - the depth cap forcing a re-anchor, and DeltaCodec::encode() discarding a delta that failed to beat its own anchor by DeltaCodec::MIN_GAIN, which happens whenever a value is small enough that a chain link cannot pay for itself. Such an anchor RESTARTS the chain: every frame before it becomes unnecessary and depth counting begins again.

A depth that does not follow its predecessor within the current run is a corruption symptom and is named in the error.

Parameters

list<\Drupal\strata\Delta\DeltaFrame> $chain

Frames from an anchor to the target, in order.

Throws

\RuntimeException

When the chain is empty, does not start at an anchor, has a depth discontinuity within a run, or any link fails to decode.

Returns

string —

The value the last frame encodes.

verify()

verify(\Drupal\strata\Delta\DeltaFrame  $frame, string  $plain) : string

Catches a decode that came back the wrong length.

A truncated decompression is indistinguishable from correct output until much later, so the recorded plain length is checked before the bytes leave this class.

Parameters

\Drupal\strata\Delta\DeltaFrame $frame

The frame that was decoded.

string $plain

The decoded bytes.

Throws

\RuntimeException

When the decoded length does not match what the frame recorded.

Returns

string —

The same bytes, once they are known to be complete.