\Drupal\strata\Capture Watermark

A cheap, bounded fingerprint of one table.

The reconciler compares two of these to answer "did this table change since we last looked", for tables nothing instrumented. It has to be cheap enough to run over every captured table on every cron, which rules out reading the table, and complete enough that an in-place update does not slip past, which rules out a row count on its own.

Four measurements, each catching what the others miss:

  • row count catches inserts and deletes, and misses an update, and misses an insert paired with a delete.
  • highest key catches an insert paired with the deletion of an OLDER row, where the count returns to where it started but the maximum has moved up.
  • highest changed timestamp catches an update, on the tables that carry such a column.
  • sampled digest catches an update on the tables that do not, over a bounded number of rows.

Two blind spots, stated rather than implied. A row inserted and then deleted again between two readings leaves nothing behind: the count returns to its old value and MAX() drops back with it, since a deleted row's key cannot be recovered from the column. And the digest is a sample, so a change confined to rows outside it is not seen. Both are why drift raises a finding for a human to read rather than driving a silent repair, and why the sample size is a setting.

Summary

Methods
Properties
Constants
__construct
differsFrom
changesFrom
describe
isMeasured
jsonSerialize
fromRow
table
rowCount
maxKey
maxChanged
digest
observed
sampled
No public constants found
No protected methods found
No protected properties found
No protected constants found
No private methods found
No private properties found
No private constants found

Properties

$table

$table : string

Type

string

$rowCount

$rowCount : int

Type

int

$maxKey

$maxKey : ?string

Type

string|null

$maxChanged

$maxChanged : ?int

Type

int|null

$digest

$digest : string

Type

string

$observed

$observed : int

Type

int

$sampled

$sampled : int

Type

int

Methods

__construct()

__construct(string  $table, int  $rowCount = 0, string|null  $maxKey = null, int|null  $maxChanged = null, string  $digest = '', int  $observed = 0, int  $sampled = 0) : mixed

Constructs a watermark.

Parameters

string $table

The table it describes.

int $rowCount

Rows at the time of the reading.

string|null $maxKey

Highest primary key seen, or NULL when the table has no single-column key.

int|null $maxChanged

Highest value of a changed-timestamp column, or NULL when the table has none.

string $digest

Digest over a bounded sample of rows, or an empty string when none was taken.

int $observed

Unix timestamp of the reading.

int $sampled

How many rows the digest covered.

Returns

mixed —

differsFrom()

differsFrom(\Drupal\strata\Capture\Watermark  $earlier) : bool

Whether this reading differs from an earlier one.

Parameters

\Drupal\strata\Capture\Watermark $earlier

The stored reading.

Returns

bool —

TRUE when any measurement moved.

changesFrom()

changesFrom(\Drupal\strata\Capture\Watermark  $earlier) : array<string,string>

Which measurements moved, and how.

Named rather than counted, because "the row count is unchanged but the digest moved" and "four hundred rows appeared" call for different responses and a boolean cannot tell them apart.

Parameters

\Drupal\strata\Capture\Watermark $earlier

The stored reading.

Returns

array

Measurement name keyed to a description of the change.

describe()

describe(\Drupal\strata\Capture\Watermark  $earlier) : string

A one-line description of what moved.

Parameters

\Drupal\strata\Capture\Watermark $earlier

The stored reading.

Returns

string —

Something such as "rows 40 to 41, key 40 to 41".

isMeasured()

isMeasured() : bool

Whether this reading measured anything at all.

A table with no rows, no key, no timestamp column and no sample is indistinguishable from a table the reader could not inspect, so the two are not treated as equal.

Returns

bool —

TRUE when at least one measurement was taken.

jsonSerialize()

jsonSerialize() : array<string,mixed>

{@inheritdoc}

Returns

array

The watermark as a plain array.

fromRow()

fromRow(array  $row) : self

Rebuilds a watermark from a stored row.

Parameters

array $row

A row from strata_watermark.

Returns

self —

The watermark.