Skip to content

Keep MemoryFileSystem append writes private until transaction commit - #2185

Merged
martindurant merged 4 commits into
fsspec:masterfrom
glaziermag:fix-memory-transaction-append-20260924
Sep 28, 2026
Merged

martindurant merged 4 commits into
fsspec:masterfrom
glaziermag:fix-memory-transaction-append-20260924

Conversation

@glaziermag

@glaziermag glaziermag commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Appending to an existing MemoryFileSystem file inside fs.transaction changes the stored bytes immediately, so an exception leaves the appended data behind. _open() returns the committed buffer for ab/a+b; this change appends to a copy instead, which is committed or discarded with the transaction.

Minimal reproduction on current master:

import fsspec

fs = fsspec.filesystem("memory", global_store=False, skip_instance_cache=True)
fs.pipe_file("target", b"original")
try:
    with fs.transaction:
        with fs.open("target", "ab") as stream:
            stream.write(b"-uncommitted")
        raise RuntimeError("abort transaction")
except RuntimeError:
    pass

assert fs.cat_file("target") == b"original"

Before the fix, the assertion fails with b'original-uncommitted'. The transaction guarantee says an uncaught exception discards the files and leaves target locations untouched.

Validation: 63 memory-backend tests and 7 local transaction tests pass. The regression covers commit/rollback, both append modes and shared/independent stores; all eight cases fail before the fix.

Prepared with AI assistance.

Comment thread fsspec/implementations/memory.py Outdated
f = self.store[path]
if self._intrans and "a" in mode:
for pending in reversed(self.transaction.files):
if pending.path == path:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You mean, the same file has been opened more than once within the transaction? I'm not sure that something we particularly account for in other places either.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, e.g. two appends to the same file in one transaction. Without the lookup, the second open starts again from the committed bytes, so appending -1 then -2 to orig would commit orig-2 rather than orig-1-2 as on master. 4255a87 extends it to a file first written earlier in the same transaction. You're right that this isn't handled anywhere else, so if you'd rather keep it minimal I can drop the lookup and only copy on append.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

the second open starts again from the committed bytes,

I'm not sure that's wrong. Let's not process this here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

OK, dropped the lookup in 9ad4344, so this is now just the copy on append.

claude and others added 3 commits September 28, 2026 19:50
Look up the latest pending file for the path before checking the store,
so an append also builds on a file first written earlier in the same
transaction ("wb" then "ab", or two appends to a new path). Previously
the later file started empty and replaced the earlier one on commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014mE9zdG8orox5svQ6swNSr
An append inside a transaction only copies the committed bytes; a
second open of the same file starts from the store again, like any
other open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@martindurant
martindurant merged commit 0542806 into fsspec:master Sep 28, 2026
11 checks passed
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.

3 participants