\Drupal\strata\Segment Collapser

Reduces a window of journal ops to the net effect on each subject.

One request can touch a node a dozen times: a create, an update per widget, another update from a hook. All twelve ops describe one subject, and a restore only needs the value the subject held at the end of the window. Folding a window before it is flushed keeps a journal proportional to the number of subjects that changed rather than to the number of writes.

The fold runs per JournalOp::key(), over ops in sequence order, and applies one rule per pair:

  • create then update stays a create, carrying the later value.
  • create then delete drops both ops; the subject never existed outside the window.
  • create then create is a recreate, carrying the later value.
  • update then update is one update, over the union of both field lists.
  • update then delete is a delete.
  • update then create is an update; the subject was already there when the window opened.
  • delete then create is an update, for the same reason.
  • delete then update is an update.
  • delete then delete is one delete.

A survivor keeps the sequence, the microtime and the parentHash of the earliest op in the run it replaces, and the payloadHash, payloadLength, label, actor and requestId of the latest. The sequence keeps ordering against other subjects stable. The parentHash names the state before the window, which is the last version the store received; an intermediate digest names a value that was never written.

Two kinds of op never fold, and are emitted verbatim in sequence order:

  • a rename, a truncate or a ddl, each of which changes the shape or the identity of the subject instead of its contents. One of these also closes the run before it, so no survivor can carry a value across it.
  • anything in the schema or the file realm, where ddl order is load-bearing and one uri can be written and rewritten with different contents.

Summary

Methods
Properties
Constants
collapse
isFoldable
statistics
No public properties found
FOLDABLE_VERBS
VERBATIM_REALMS
No protected methods found
No protected properties found
No protected constants found
fold
survivingVerb
union
inSequenceOrder
No private properties found
No private constants found

Constant

FOLDABLE_VERBS

FOLDABLE_VERBS = [\Drupal\strata\Journal\Verb::CREATE, \Drupal\strata\Journal\Verb::UPDATE, \Drupal\strata\Journal\Verb::DELETE]

Verbs that describe a change to the contents of a subject, and so can fold.

VERBATIM_REALMS

VERBATIM_REALMS = [\Drupal\strata\Journal\Realm::SCHEMA, \Drupal\strata\Journal\Realm::FILE]

Realms where every op is kept, because order and contents both carry meaning.

Methods

collapse()

collapse(list<\Drupal\strata\Journal\JournalOp>  $ops) : list<\Drupal\strata\Journal\JournalOp>

Folds a window down to the net effect on each subject.

Parameters

list<\Drupal\strata\Journal\JournalOp> $ops

The window, in any order; the sequence decides which op is earlier.

Returns

list<\Drupal\strata\Journal\JournalOp> —

The surviving ops by sequence ascending, never more of them than went in. An op that took part in no fold is the same instance that went in.

isFoldable()

isFoldable(\Drupal\strata\Journal\JournalOp  $op) : bool

Whether an op takes part in a fold at all.

Parameters

\Drupal\strata\Journal\JournalOp $op

The op.

Returns

bool —

TRUE when the verb is one of FOLDABLE_VERBS and the realm is not one of VERBATIM_REALMS.

statistics()

statistics(list<\Drupal\strata\Journal\JournalOp>  $before, list<\Drupal\strata\Journal\JournalOp>  $after) : array{input: int, output: int, dropped: int, ratio: float}

What the fold bought, for the flush log and the operator-facing window view.

Parameters

list<\Drupal\strata\Journal\JournalOp> $before

The window as captured.

list<\Drupal\strata\Journal\JournalOp> $after

The window as collapse() returned it.

Returns

array{input: int, output: int, dropped: int, ratio: float} —

Counts either side of the fold, how many ops disappeared, and input over output as a factor. The ratio is 1.0 when nothing survived, so a caller can print it without a guard.

fold()

fold(\Drupal\strata\Journal\JournalOp  $earlier, \Drupal\strata\Journal\JournalOp  $later) : \Drupal\strata\Journal\JournalOp|null

Merges the op a run has produced so far with the next op on the same subject.

Parameters

\Drupal\strata\Journal\JournalOp $earlier

The survivor of the run so far, which is the first op of the run when there is only one.

\Drupal\strata\Journal\JournalOp $later

The next op on the same key.

Returns

\Drupal\strata\Journal\JournalOp|null —

The single op that replaces both, or NULL when the pair cancels out and neither survives.

survivingVerb()

survivingVerb(\Drupal\strata\Journal\Verb  $earlier, \Drupal\strata\Journal\Verb  $later) : \Drupal\strata\Journal\Verb|null

The verb the net effect of a pair is described by.

Every pair of foldable verbs has an arm here. The default is unreachable, because collapse() only folds ops isFoldable() accepted, and returning the later verb is the answer that loses the least if a verb is ever added to FOLDABLE_VERBS without an arm.

Parameters

\Drupal\strata\Journal\Verb $earlier

Verb of the survivor of the run so far.

\Drupal\strata\Journal\Verb $later

Verb of the next op on the same key.

Returns

\Drupal\strata\Journal\Verb|null —

The surviving verb, or NULL when the pair cancels out.

union()

union(list  $left, list  $right) : list<string>

Both field lists, first-seen order, no duplicates.

Parameters

list $left

Field names from the earlier op.

list $right

Field names from the later op.

Returns

list

The union.

inSequenceOrder()

inSequenceOrder(list<\Drupal\strata\Journal\JournalOp>  $ops) : list<\Drupal\strata\Journal\JournalOp>

Orders ops the way the journal appended them.

Sorted on sequence, then microtime, and PHP sorts stably, so two ops the journal numbered identically keep the order they arrived in rather than swapping between runs.

Parameters

list<\Drupal\strata\Journal\JournalOp> $ops

The ops, in any order.

Returns

list<\Drupal\strata\Journal\JournalOp> —

The same ops, by sequence ascending.