SOURCE
SOURCE = 'heuristic'
Recorded against any classification a rule produced.
Guesses what a key is for, from what it is called.
Drupal's ephemeral keyspace is named by convention rather than by contract, and the conventions
are strong enough to classify most of it: anything under cache is a cache, anything under
lock is a lock, queue holds work, flood holds a security counter. So a first pass over a
discovered keyspace can place the great majority of it without asking anyone.
Every rule here is a GUESS and is recorded as one. A rule that matches produces a classification
with Heuristics::SOURCE attached, and a human decision always outranks it - see
ClassificationRegistry, which never overwrites a human's answer with a rule's. That distinction is
what makes it safe to add rules: the worst a wrong rule can do is be corrected, not silently
override a decision someone already made.
The rules are ordered and the first match wins, so a specific pattern must sit above the general one it would otherwise be swallowed by.
RULES = [
// expirable stores come first: their names contain the names of the persistent ones, so a
// broader rule below would otherwise swallow them and mark a cache authoritative
'key_value_expire*' => \Drupal\strata\Capture\Classifier\Classification::DERIVABLE,
'keyvalue.expirable*' => \Drupal\strata\Capture\Classifier\Classification::DERIVABLE,
'*expirable*' => \Drupal\strata\Capture\Classifier\Classification::DERIVABLE,
'*_expire*' => \Drupal\strata\Capture\Classifier\Classification::DERIVABLE,
'*.expire' => \Drupal\strata\Capture\Classifier\Classification::DERIVABLE,
'tempstore*' => \Drupal\strata\Capture\Classifier\Classification::DERIVABLE,
// work nobody else has a record of: losing a queue loses the work in it
'queue*' => \Drupal\strata\Capture\Classifier\Classification::AUTHORITATIVE,
'*.queue' => \Drupal\strata\Capture\Classifier\Classification::AUTHORITATIVE,
'reliable_queue*' => \Drupal\strata\Capture\Classifier\Classification::AUTHORITATIVE,
// a security counter; rebuilding it as empty hands an attacker their attempts back
'flood*' => \Drupal\strata\Capture\Classifier\Classification::AUTHORITATIVE,
// someone is logged in with this
'session*' => \Drupal\strata\Capture\Classifier\Classification::AUTHORITATIVE,
'php_session*' => \Drupal\strata\Capture\Classifier\Classification::AUTHORITATIVE,
// a semaphore mid-operation; restoring a stale one deadlocks whatever waits on it
'semaphore*' => \Drupal\strata\Capture\Classifier\Classification::AUTHORITATIVE,
// key-value collections are persistent by name, and are captured in their own realm
'key_value*' => \Drupal\strata\Capture\Classifier\Classification::AUTHORITATIVE,
'keyvalue*' => \Drupal\strata\Capture\Classifier\Classification::AUTHORITATIVE,
// a lock is only meaningful while its holder is running, and its holder is not
'lock*' => \Drupal\strata\Capture\Classifier\Classification::DERIVABLE,
// every cache bin rebuilds itself on demand, by definition
'cache*' => \Drupal\strata\Capture\Classifier\Classification::DERIVABLE,
'*_cache' => \Drupal\strata\Capture\Classifier\Classification::DERIVABLE,
'cachetags*' => \Drupal\strata\Capture\Classifier\Classification::DERIVABLE,
'render*' => \Drupal\strata\Capture\Classifier\Classification::DERIVABLE,
'page*' => \Drupal\strata\Capture\Classifier\Classification::DERIVABLE,
'dynamic_page_cache*' => \Drupal\strata\Capture\Classifier\Classification::DERIVABLE,
'discovery*' => \Drupal\strata\Capture\Classifier\Classification::DERIVABLE,
'bootstrap*' => \Drupal\strata\Capture\Classifier\Classification::DERIVABLE,
'config*' => \Drupal\strata\Capture\Classifier\Classification::DERIVABLE,
'container*' => \Drupal\strata\Capture\Classifier\Classification::DERIVABLE,
'menu*' => \Drupal\strata\Capture\Classifier\Classification::DERIVABLE,
'entity*' => \Drupal\strata\Capture\Classifier\Classification::DERIVABLE,
'data*' => \Drupal\strata\Capture\Classifier\Classification::DERIVABLE,
'default*' => \Drupal\strata\Capture\Classifier\Classification::DERIVABLE,
'jsonapi*' => \Drupal\strata\Capture\Classifier\Classification::DERIVABLE,
'library*' => \Drupal\strata\Capture\Classifier\Classification::DERIVABLE,
'toolbar*' => \Drupal\strata\Capture\Classifier\Classification::DERIVABLE,
] : array<string, <a href="classes/Drupal-strata-Capture-Classifier-Classification.html"><abbr title="\Drupal\strata\Capture\Classifier\Classification">Classification</abbr></a>>
Glob patterns keyed to what they mean, most specific first.
classify(string $key) : \Drupal\strata\Capture\Classifier\Classification
Classifies one key.
| string | $key | The key or namespace, such as "cache_render" or "queue:aggregator_feeds". |
What the rules make of it, or Classification::UNCLASSIFIED when nothing matched.
patternFor(string $key) : string
The pattern that classified a key, for the audit trail.
A registry stores rules by pattern rather than by key, so a thousand cache keys under one bin become one row rather than a thousand. This is how the row is named.
| string | $key | The key or namespace. |
The matching pattern, or the key's own namespace with a wildcard when nothing matched.
namespaceOf(string $key) : string
The leading namespace of a key.
Keys arrive as bin:key, bin.key or bin_key depending on who wrote them, so all three
separators are treated as the boundary. A key with no separator is its own namespace.
| string | $key | The key. |
The namespace, without a trailing separator.
matches(string $pattern, string $key) : bool
Whether a glob pattern matches a key.
fnmatch() is not used: it is unavailable on some Windows builds of PHP and its behaviour
around separators differs by platform, which would make a classification depend on the host.
| string | $pattern | A pattern using |
| string | $key | The key to test. |
TRUE when the pattern matches.