Add cached_markdown_version_for_bulk_clear helper
What does this MR do and why?
Adds Gitlab::MarkdownCache.cached_markdown_version_for_bulk_clear, which
resolves the lowest cached_markdown_version that should still be treated as
current:
def self.cached_markdown_version_for_bulk_clear(local_version: nil)
previous_cached_markdown_version(local_version: local_version) ||
cached_markdown_version_for_write(local_version: local_version)
endAnything strictly below the returned version is stale: its cached HTML will be re-rendered on the next read anyway, so it is safe to clear in bulk. This composes the two existing rollout states:
- Mid-rollout:
previous_cached_markdown_versionis non-nil, so the bound is the previous version. A bulk clear then only touches true stragglers below it, leaving the previous and current populations alone since they are still rolling forward through the read path. - Steady state: there is no rollout,
previous_cached_markdown_versionreturnsnil, and the bound falls back tocached_markdown_version_for_write, the current version, so everything below it is stale.
Why a separate method, and this name
latest_cached_markdown_version is already documented as the staleness check,
but it is the per-read one: during a rollout it rolls stochastically, which is
the load-shedding mechanism for read traffic. A bulk clear needs the opposite
property, a bound that never rolls, so the two cannot share a method. The name
follows the existing cached_markdown_version_for_<purpose> shape used by
cached_markdown_version_for_write, naming the operation rather than claiming
to be the general answer to "is this row stale".
This cannot live on the CacheMarkdownField model concern, because background
operations iterate a dynamic batchable model
(Gitlab::Database::DynamicModelHelpers) that does not include it. Putting the
fallback in Gitlab::MarkdownCache keeps the version-resolution rules in one
place instead of duplicating them per caller.
This MR adds only the helper and its spec. There is no caller on master yet;
Gitlab::BackgroundOperation::MergeRequestsClearStaleCachedHtml will be the
first, once it is rebased on this.
Nothing user-facing changes, so no changelog entry is warranted.