wordpress-mobile / wordpress-mobile/GutenbergKit

Asset bundle commit is a non-atomic remove-then-copy

Open
#665 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

[Type] Bug iOS
Dominant language
JavaScript
Stars
29
Forks
6
Avg merge
1d 9h
Merged PRs (30d)
41

Description

EditorAssetBundle.copy(to:) commits a downloaded asset bundle by deleting the destination and copying into it. Two editors on the same site can run that concurrently, so one can delete the directory the other is currently serving assets from.

Detail

ios/Sources/GutenbergKit/Sources/Model/EditorAssetBundle.swift:217-223 is directoryExistsremoveItemcreateDirectorycopyItem, against storageRoot/<manifest-checksum> (EditorAssetLibrary.swift:245).

Nothing serializes two writers. Each EditorViewController builds its own EditorService (EditorViewController.swift:223), which builds its own EditorAssetLibrary — actor isolation is per-instance, so two editors for the same site are two independent actors writing the same path.

How it bites

Cold asset cache (first open of a site, or after deleteAllData), slow connection. The user opens the editor, backs out, and immediately reopens.

Editor B downloads and commits, then starts serving assets from storageRoot/<checksum>. Editor A — still finishing its own download — reaches copy(to:), sees the directory exists, removes it, and re-copies. For the duration of that window every plugin/theme asset request misses the bundle.

The blast radius is smaller than it first looks, and worth stating so nobody over-fixes it:

  • The path is checksum-keyed, so identical checksum means identical content. This is a window of absence, not corruption.
  • EditorAssetBundleProvider.swift:78-85 already falls back to fetchFromRemote for any asset missing from the bundle, so the visible editor degrades to network refetches rather than erroring. Offline, those assets just don't load.
  • prepareAssetBundle() short-circuits on readAssetBundles().first (EditorService.swift:234-243), so a warm cache never reaches copy(to:) at all.

Suggested fix

Commit via an atomic rename — write to a sibling temp directory and replaceItemAt — or skip the copy entirely when hasBundle(forManifestChecksum:) is already true.

Found while reviewing #651. Pre-existing; the removal of the mid-load cancellation widens the window slightly, but the old cancellation was worse here (see #667).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with ios/Sources/GutenbergKit/Sources/Model/EditorAssetBundle.swift:217-223 and trace the storage path from EditorAssetLibrary.swift:245. Review EditorViewController.swift:223 and EditorService.swift:234-243 to understand independent writers and the warm-cache shortcut. Update the commit flow so concurrent bundle commits do not expose a missing directory, then verify the provider fallback in EditorAssetBundleProvider.swift:78-85 still behaves as expected.

Written by the indexing model from the issue text.

Assessment

Tech stack
swift
Domain
mobile
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
65/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.