\Drupal\strata\File ShiftDetector

Tells a file whose content shifted from one that was edited in place.

Fixed blocks cannot follow an insertion. Insert two megabytes at the front of a file and every block after the insertion moves, so the file looks entirely rewritten even though almost all of its content is unchanged. Measured on a 256 MiB file: a 2 MiB in-place edit moves 0.81% of the blocks and a 2 MiB insertion moves 60.79%, at every block size from 64 KiB to 4 MiB.

That gap is what makes the two cases separable. Above the threshold the file is shifting rather than being edited, and fixed blocks are the wrong tool for it - so the finding is raised and an administrator is offered the two things that would work: whole-object storage, or the content-defined chunker at its measured 4.29 MB/s.

Nothing is changed automatically. A shift is not a fault and the right answer depends on the file type: an appended log wants the chunker, a re-encoded video wants whole-object storage, and a database dump might want neither. Choosing costs storage or CPU, and that is an operator's call.

Summary

Methods
Properties
Constants
__construct
threshold
hasShifted
observe
options
fromSettings
No public properties found
DEFAULT_THRESHOLD
MIN_BLOCKS
No protected methods found
No protected properties found
No protected constants found
No private methods found
threshold
minimumBlocks
No private constants found

Constant

DEFAULT_THRESHOLD

DEFAULT_THRESHOLD = 0.3

Share of moved blocks above which the content is taken to have shifted.

30%, chosen to sit in the wide gap between the measured in-place case at 0.81% and the measured insertion case at 60.79%. A file type whose real distribution straddles this is exactly what calibration is for.

MIN_BLOCKS

MIN_BLOCKS = 16

Fewest blocks a file must have before a ratio means anything.

On a four-block file one changed block is 25% and says nothing about shifting.

Properties

$threshold

$threshold : float

Type

float

$minimumBlocks

$minimumBlocks : int

Type

int

Methods

__construct()

__construct(float  $threshold = \self::DEFAULT_THRESHOLD, int  $minimumBlocks = \self::MIN_BLOCKS) : mixed

Constructs a detector.

Parameters

float $threshold

Share of moved blocks that counts as a shift.

int $minimumBlocks

Fewest blocks before the ratio is judged at all.

Throws

\InvalidArgumentException

When the threshold is not a fraction above zero.

Returns

mixed —

threshold()

threshold() : float

The configured threshold.

Returns

float —

A fraction.

hasShifted()

hasShifted(\Drupal\strata\File\FileMapDiff  $diff) : bool

Whether a change looks like a shift rather than an edit.

Parameters

\Drupal\strata\File\FileMapDiff $diff

The change.

Returns

bool —

TRUE when the moved-block share is past the threshold on a file large enough to judge.

observe()

observe(\Drupal\strata\File\FileMapDiff  $diff) : array<string,mixed>

The observation a tripwire reads.

Parameters

\Drupal\strata\File\FileMapDiff $diff

The change.

Returns

array

The observation.

options()

options(\Drupal\strata\File\FileMapDiff  $diff) : list<string>

What an operator could do about a shifting file.

Parameters

\Drupal\strata\File\FileMapDiff $diff

The change.

Returns

list

The options, each naming what it costs, empty when nothing shifted.

fromSettings()

fromSettings(float|null  $threshold) : \Drupal\strata\File\ShiftDetector

A detector from the module's settings.

Parameters

float|null $threshold

The configured threshold, or NULL for the default.

Returns

\Drupal\strata\File\ShiftDetector —

The detector.