Skip to content

[Web][COS] Persist URL→hash mapping across page loads#19569

Open
tomayac wants to merge 1 commit into
apache:mainfrom
tomayac:cos-refinement
Open

[Web][COS] Persist URL→hash mapping across page loads#19569
tomayac wants to merge 1 commit into
apache:mainfrom
tomayac:cos-refinement

Conversation

@tomayac
Copy link
Copy Markdown

@tomayac tomayac commented May 15, 2026

The CrossOriginStorage class was storing the URL→hash map only in the module-level GLOBAL_HASH_CACHE. After a page reload that cache is empty, and getFileHash() can only recover hashes for HuggingFace LFS files (URLs containing /resolve/). This left several resource categories uncacheable across sessions:

Screenshot 2026-05-15 at 17 43 15
  • JSON files not stored in LFS (mlc-chat-config.json, tokenizer.json, tensor-cache.json) — getFileHash returns null for their /resolve/ URLs because the raw pointer is the actual file content, not an LFS pointer.
  • .wasm files from GitHub raw URLs — no /resolve/ pattern at all.
  • Any file whose hash was computed from blob content via getBlobHash.

Additionally, even for genuine LFS model shards, each page load was re-fetching every shard's LFS pointer file over the network just to re-derive the SHA-256 hash.

Fix: persist the URL→hash mapping to a dedicated Cache API store (tvmjs-cos-hash-meta). Two write sites:

  1. put() — after a file is stored in COS, persist its blob-derived hash. This covers all non-LFS files and non-HuggingFace URLs.

  2. resolveHashDescriptor() — after getFileHash() resolves a hash from the LFS pointer, persist it immediately. This eliminates repeated pointer-file network requests for model shards on subsequent visits.

Both write sites use a best-effort try/catch so storage quota errors are silently ignored. loadPersistedHashEntry() similarly swallows errors. The typeof caches === "undefined" guard keeps the code safe in Node.js test environments.

The CrossOriginStorage class was storing the URL→hash map only in the
module-level GLOBAL_HASH_CACHE. After a page reload that cache is empty,
and getFileHash() can only recover hashes for HuggingFace LFS files
(URLs containing /resolve/). This left several resource categories
uncacheable across sessions:

- JSON files not stored in LFS (mlc-chat-config.json, tokenizer.json,
  tensor-cache.json) — getFileHash returns null for their /resolve/ URLs
  because the raw pointer is the actual file content, not an LFS pointer.
- .wasm files from GitHub raw URLs — no /resolve/ pattern at all.
- Any file whose hash was computed from blob content via getBlobHash.

Additionally, even for genuine LFS model shards, each page load was
re-fetching every shard's LFS pointer file over the network just to
re-derive the SHA-256 hash.

Fix: persist the URL→hash mapping to a dedicated Cache API store
(tvmjs-cos-hash-meta). Two write sites:

1. put() — after a file is stored in COS, persist its blob-derived hash.
   This covers all non-LFS files and non-HuggingFace URLs.

2. resolveHashDescriptor() — after getFileHash() resolves a hash from
   the LFS pointer, persist it immediately. This eliminates repeated
   pointer-file network requests for model shards on subsequent visits.

Both write sites use a best-effort try/catch so storage quota errors are
silently ignored. loadPersistedHashEntry() similarly swallows errors.
The typeof caches === "undefined" guard keeps the code safe in Node.js
test environments.
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements persistent caching for hash descriptors in CrossOriginStorage using the browser's Cache API. It introduces persistHashEntry and loadPersistedHashEntry methods to store and retrieve hashes, reducing redundant network requests for non-LFS files and specific URLs on subsequent visits. I have no feedback to provide as there were no review comments.

@tomayac
Copy link
Copy Markdown
Author

tomayac commented May 15, 2026

Most likely @CharlieFRuan, @guan404ming, and @akaashrp would be good reviewers for this refinement.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant