Opened 12 years ago

Last modified 5 days ago

#21602 assigned Cleanup/optimization

FileSystemStorage._save() Should Save to a Temporary Filename and Rename to Attempt to be Atomic

Reported by: Kevin Stone Owned by: Jyry Suvilehto
Component: File uploads/storage Version: dev
Severity: Normal Keywords:
Cc: bcail, Jyry Suvilehto Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: yes
Easy pickings: no UI/UX: no

Description

When using FileSystemStorage based backend with say, staticfiles, creates a race condition where it's writing the intended destination file which can lead to race conditions where your web server can serve incomplete assets while they're being written.

Another case happens with post-processing since CachedStaticFilesStorage actually deletes the hash-named file before saving over it.

These issue should be circumventing by directing the writing to a temporary file name and then atomically renaming it to the intended destination. Even better, FileSystemStorage._save() has to site in a While-loop because of race conditions in get_available_name(). Instead, it could defer calling get_available_name until it's prepared to rename the file to its destination.

I'm working on implementing these changes in my own sub-class of FileSystemStorage (and CachedStaticFilesStorage to avoid the delete() call) and would be apply to submit them as a patch if there's interest.

Change History (9)

comment:1 by Alex Gaynor, 12 years ago

Triage Stage: UnreviewedAccepted

Agreed that atomic rename should be used.

comment:2 by Tim Graham, 12 years ago

Type: UncategorizedCleanup/optimization

comment:3 by Tim Graham, 10 years ago

This is also suggested in #27334 (closed as duplicate).

comment:4 by bcail, 2 years ago

Cc: bcail added

This should be easier to implement once the OS_OPEN_FLAGS are removed (they're currently deprecated).

comment:5 by Jyry Suvilehto, 6 days ago

Cc: Jyry Suvilehto added
Owner: changed from nobody to Jyry Suvilehto
Status: newassigned

comment:6 by Jyry Suvilehto, 6 days ago

Has patch: set

comment:7 by Jyry Suvilehto, 6 days ago

I added a patch / here.

Reviewer comments are especially welcome on whether or not this needs new tests? in theory this change could result in ghost files in a local temp directory if there are unhandled exceptions.

Version 0, edited 6 days ago by Jyry Suvilehto (next)

comment:8 by Jyry Suvilehto, 6 days ago

Now the system uses atomic os.rename() where possible. This lead to another issue: if two uploads to the same file name os.rename() calls are made almost simultaneously with the same target file name, only the latter file will exist at the end. The current implementation does not behave like this. Will it be surprising to the users if in rare cases two uploads can result in only one file?

We could avoid this by copying the files ourselves and locking, but that just moves a hacky locking operation from the upload to the copy. Copy will be a faster operation since it's on the same machine, but still a bit clunky IMO.

comment:9 by JaeHyuckSa, 5 days ago

Patch needs improvement: set
Note: See TracTickets for help on using tickets.
Back to Top