[Development] QFile: writing via a temporary file

João Abecasis joao.abecasis at nokia.com
Fri Jan 6 11:41:05 CET 2012


David Faure wrote:
> A very common issue with writing over an existing file, is that in
> case of problem in the middle of the writing operation (disk full,
> application crash, power failure...) the existing file will be lost.
> If it contained your thesis, you might be a bit angry at the Qt
> application that did that.
> 
> The typical solution is to write into a temporary file in the same
> directory, and then atomically renaming the temp file to overwrite the
> existing file.  This then works like a transaction, with the choice to
> end the writing operation with a commit (= rename the temp file) or
> rollback (=erase the temp file), in case of errors while writing.

I agree that this is a common problem and that it would be nice to have
a pre-packaged solution to support it. So, in general I'm in favor of
adding such a feature to Qt.

However...

[ reordering solutions for the sake of argument ]

> Solution 2: how about making this functionality part of QFile itself?
> No need to "port to another class" anymore, just enable the safety
> feature by calling file.setUseTemporaryFile(true).  This is what I've
> started doing in the attached patch, but I'd like to gather feedback
> before polishing it up.  One issue is that after doing
> file.setUseTemporaryFile(true) and file.open(), all the operations on
> the file object are no longer operating on the given fileName, but on
> the "internal" temporary file. That's what we want for writing, but
> maybe it could confuse people that remove() or rename() leaves the
> existing file untouched? I think it would simply have to be
> documented: when enabling the feature, all that happens between open()
> and close(), happens on the temp file.

I don't support putting this in QFile as has been suggested as, from my
experience with it, this will open a can of worms in maintenance and
subtle issues cropping up in user code such as the ones being discussed:
what's fileName()?  Does it exists() before commit? What do remove() and
rename(newName) do?

So, let me re-frame the question. What in the current QFile API needs to
be exposed in such a class?

I think we would be well served by an API that exposes a QIODevice
interface plus additional interface for commit/rollback.

> The other question is, would one have to call commit/rollback
> explicitely, or should QFile::close() (and the dtor) do the
> committing?

I think commit should require explicit action, for instance, by
explicitly calling close(). I don't like having the destructor
automatically commit (even if it calls close) though. An exception being
thrown in the middle of a save operation could potentially unwind the
stack, call the destructor and commit a transaction half-way through.

What happens to writes happening after a commit, though?

> And how should one rollback? Explicit file.rollback(), or
> in the existing file.remove()?  Oswald suggested doing that in
> close()/remove() directly, and getting rid of commit()/rollback().
> Opinions?

I wouldn't like remove() to be doing anything different from what it
does now: delete the file pointed to by fileName. 

I'm ok with having implicit rollback done by the destructor. I also
don't see a problem with having more explicit rollback functionality.
That means, that one would be able to rollback and start over a
transaction.

> Solution 1: using a separate class for handling the QTemporaryFile and
> the rename call. KDE's KSaveFile and QtCreator's SaveFile do that. The
> code of such a class is quite easy. The downside is that from an API
> point of view, it's a bit weird. You have to use this "save file"
> wrapper class, which is hard to picture in one's mind, and to name
> properly for what it does.  API-wise, such a class has methods like
> commit() and rollback(), to decide what happens when we're done. If
> you forget to call either one, the destructor will decide for you.
> Funny, in KDE it commits, in QtCreator it rolls back...

And still those are working examples from the real-world where exactly
such solutions were preferred over extending QFile.

Cheers,

João





More information about the Development mailing list