Artifact a9c2805cd2479253dd01b86130dfef92f44d642da9b314c5a21d1922322fe238:
- File
internal/blob/doc.go
— part of check-in
[0fc4d176c3]
at
2026-10-28 22:52:43
on branch feat/chunked-blobs
— Record chunked length in blob.content and verify parts on read
Review of the chunked-blob change found a missing last part read back short with no error, and a chunked write outside a transaction could leave a torn row that looked held.
A chunked row now keeps its stored length in blob.content as an INTEGER. Reads check the parts run unbroken from seq 0, are full-sized but for the last, and add up to that length; anything else is ErrPartsCorrupt, and a NULL content is no longer mistaken for a chunked one. StoredLenSQL reads the length off the row and needs no schema probe.
Chunked writes, and the phantom fill around them, run in a savepoint of the caller's transaction or a transaction of their own, so a failed part leaves nothing behind. A value needing more than 4096 parts is an error, not a panic, since stored values can come from peers. The cone and sparse local payload reads use ReadStoredExact, which loads a value only at the length already budgeted for.
MaxValueBytes is documented as process-wide, and unversioned content as not chunked. (user: [email protected], size: 1535) [annotate] [blame] [check-ins using]
// Package blob handles content-addressed blob storage in Fossil // repository databases. // // Fossil's blob format is a 4-byte big-endian uncompressed-size prefix // followed by zlib-compressed data. [Compress] and [Decompress] handle // this encoding transparently. // // [Store] compresses content, computes its SHA1 hash, and inserts it // into the blob table. [Load] retrieves and decompresses a blob by RID. // [StoreDeltaRaw] stores content that arrived over the wire already // delta-encoded, without expanding it. [EncodeForStorage] is the shared // decision point for whether a receive path can skip [Compress] entirely // and write already-encoded wire bytes straight to blob.content. // // A row's stored bytes are read and written only through [ReadStored], // [ReadStoredExact], [WriteStored], [InsertStored], [StoredHead] and // [DropStored] (and the scan expressions [StoredLenSQL] and // [StoredPrefixSQL]), because a value over db.DriverConfig.MaxValueBytes // lives in blobpart rows, with only its length in blob.content. // // This package does not decide what gets delta-encoded. Deltifying an // artifact that is already stored means rewriting an existing row, not // inserting a new one, and the decision needs to expand content, which // this package cannot do without importing internal/content. Both live // in content.Deltify, which is the only place the policy is stated. // [StoreDelta] inserts a new row as a delta and has no callers outside // tests; it is not the commit path's primitive. package blob