64 lines
3.5 KiB
SQL
64 lines
3.5 KiB
SQL
|
|
-- Negative rows in `storage.content_derived_blobs`.
|
||
|
|
--
|
||
|
|
-- Some derivations can only be known to be useless by doing the whole
|
||
|
|
-- expensive job. `ImageTranscodeService` learns that WebP is not smaller
|
||
|
|
-- than the original by decoding and re-encoding the whole image; a
|
||
|
|
-- thumbnail renderer learns a source is undecodable, or over the
|
||
|
|
-- 50-megapixel ceiling, only by attempting it. Recomputing that verdict
|
||
|
|
-- on every request is the same cost as computing it the first time.
|
||
|
|
--
|
||
|
|
-- Today those verdicts live in RAM (moka's zero-weight empty-Bytes
|
||
|
|
-- convention) and, for transcodes, as zero-byte `.skip` files on local
|
||
|
|
-- disk. Both vanish: moka evicts, and the local disk is exactly what
|
||
|
|
-- this plan is deleting. So the verdict is stored here, next to the
|
||
|
|
-- positive derivations, as a row whose derived Blob is NULL.
|
||
|
|
--
|
||
|
|
-- ## Why NULL rather than a sentinel hash
|
||
|
|
--
|
||
|
|
-- A reserved hash was considered and rejected. It would stop
|
||
|
|
-- `blob_hash` naming a real Blob, and every consumer — the refcount
|
||
|
|
-- recompute in `manifests_consistency`, `dedup_gc`'s reap predicate,
|
||
|
|
-- `satellites_consistency`'s dangling check — would need to learn the
|
||
|
|
-- exception or silently mis-handle it. NULL is already the SQL way to
|
||
|
|
-- say "no Blob", and those consumers all join on `blob_hash`, so a NULL
|
||
|
|
-- drops out of the join instead of matching something fictional.
|
||
|
|
--
|
||
|
|
-- ## The CHECK matters
|
||
|
|
--
|
||
|
|
-- A row with a `blob_hash` but no `content_type` is unserveable; a row
|
||
|
|
-- with a `content_type` but no `blob_hash` claims a type for bytes that
|
||
|
|
-- do not exist. Both are bugs that would surface far from their cause,
|
||
|
|
-- so the pair moves together or not at all.
|
||
|
|
--
|
||
|
|
-- ## What must NOT become a negative row
|
||
|
|
--
|
||
|
|
-- Only failures that are DETERMINISTIC IN THE CONTENT. A transcode that
|
||
|
|
-- was not smaller, or a source that cannot be decoded, will fail the
|
||
|
|
-- same way forever — those are worth remembering. A generation timeout,
|
||
|
|
-- a closed semaphore, an I/O error reading the source Blob are
|
||
|
|
-- properties of the moment, not the content; persisting one marks a
|
||
|
|
-- perfectly good image as underivable permanently, and nothing ever
|
||
|
|
-- retries it. The asymmetry sets the default: a wrongly-cached
|
||
|
|
-- transient is silent and forever, a missing negative merely costs
|
||
|
|
-- repeated work. When in doubt, do not write the row.
|
||
|
|
|
||
|
|
ALTER TABLE storage.content_derived_blobs
|
||
|
|
ALTER COLUMN blob_hash DROP NOT NULL,
|
||
|
|
ALTER COLUMN content_type DROP NOT NULL;
|
||
|
|
|
||
|
|
ALTER TABLE storage.content_derived_blobs
|
||
|
|
DROP CONSTRAINT IF EXISTS content_derived_blobs_positive_or_negative;
|
||
|
|
|
||
|
|
ALTER TABLE storage.content_derived_blobs
|
||
|
|
ADD CONSTRAINT content_derived_blobs_positive_or_negative
|
||
|
|
CHECK (
|
||
|
|
(blob_hash IS NOT NULL AND content_type IS NOT NULL)
|
||
|
|
OR (blob_hash IS NULL AND content_type IS NULL)
|
||
|
|
);
|
||
|
|
|
||
|
|
COMMENT ON COLUMN storage.content_derived_blobs.blob_hash IS
|
||
|
|
'The derived Blob, or NULL for a NEGATIVE row: the derivation was attempted and is known not to be worth storing (transcode came out larger, source undecodable, source over the decode ceiling). Reference HOLDER when present — bumps chunk_manifests.ref_count via DedupService::add_reference. Only content-deterministic failures may be recorded as negatives; transient ones (timeout, semaphore, I/O) must not, or a momentary failure becomes permanent.';
|
||
|
|
|
||
|
|
COMMENT ON COLUMN storage.content_derived_blobs.content_type IS
|
||
|
|
'MIME type of the derived Blob. NULL exactly when blob_hash is NULL — the CHECK keeps the pair together, since a type without bytes describes nothing and bytes without a type cannot be served.';
|