Skip to content

modelartifacts: cache key over-discriminates on allow_patterns, forcing a full re-fetch when patterns are narrowed #11047

Description

@localai-bot

Summary

CacheKey hashes allow_patterns / ignore_patterns into the artifact identity, so any change to a gallery entry's pattern set produces a new cache key and a complete re-download — even when the new pattern set is a strict subset of what is already materialized on disk.

Narrowing patterns to fetch less data therefore costs a full re-fetch of everything, and orphans the previous tree.

Where

pkg/modelartifacts/path.go:62

identity := struct {
    Type           string   `json:"type"`
    Endpoint       string   `json:"endpoint"`
    Repo           string   `json:"repo"`
    Revision       string   `json:"revision"`
    AllowPatterns  []string `json:"allow_patterns,omitempty"`
    IgnorePatterns []string `json:"ignore_patterns,omitempty"`
}{...}
sum := sha256.Sum256(encoded)

Observed

On a distributed cluster, longcat-video-avatar-1.5 was installed under an older config with no allow_patterns, materializing the full repo:

70G  /models/.artifacts/huggingface/cc9cef3a6d15443f7c56a6c3e0e57b8fd58b5121154f871c7c69e2addb78424f

Reinstalling from the current gallery entry — which adds allow_patterns that exclude base_model_int8/**, i.e. asks for less — produced a new key and began re-downloading from HuggingFace:

resuming an abandoned artifact download partial=".../23c6c8baa875bcd06ea4446450e0aacc7b917e0d3aef3b187c447f8181fe9d51..."
Downloading url="https://huggingface.co/meituan-longcat/LongCat-Video-Avatar-1.5/resolve/.../base_model/config.json"
Downloading url=".../base_model/diffusion_pytorch_model-00001-of-00006.safetensors"

Every file requested by the new pattern set was already present under the old key. The old 70 GB tree is now orphaned — nothing references it.

Why the current behaviour is sound but too coarse

Hashing the patterns is correct in the sense that matters: it can never serve an incomplete tree. If the key ignored patterns, a config requesting base_model_int8/** would find a tree materialized without it, believe it complete, and fail at load with missing files. That safety property must be preserved.

The problem is that it treats pattern sets as equal-or-different, when the real relationship is a partial order:

  • requested ⊆ materialized → the existing tree already satisfies the request; no fetch needed
  • requested ⊄ materialized → fetch is needed, but only for the delta

Only the second case justifies downloading, and even then not from scratch.

The machinery already exists

Completed artifact directories carry a manifest next to the snapshot:

/models/.artifacts/huggingface/<key>/
  manifest.json     (18757 bytes for this repo)
  snapshot/

So the file inventory needed for a subset check is already persisted. A lookup could key on type + endpoint + repo + revision and consult the manifest to decide reuse vs delta-fetch, keeping the safety property without the redundant download.

Wrinkle worth designing around

A superset tree contains files the consumer should not see (base_model_int8/ in this case — the entry's comment notes only one of the two base variants is ever read, and fetching both roughly doubles the download). So reuse needs either a filtered view at stage time or a consumer that tolerates extra files. Staging already walks an explicit file list, so filtering there is likely the cheaper half.

Impact

  • Refining a gallery entry's patterns — the main way to reduce download size — is punished with a full re-fetch, so entries are expensive to improve.
  • Orphaned trees accumulate silently; nothing prunes the superseded key.
  • On a distributed cluster this lands on the controller's shared model volume, where the re-fetch is tens of GB over the internet and blocks the model becoming usable.

Not proposing a specific implementation

Filing this as the observation plus the constraint (never serve an incomplete tree). The subset-check-with-manifest direction above is the obvious shape, but the filtered-view question deserves a design decision rather than being settled in the issue.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions