Earlier quoted context omitted.
Er, yes, that's the point.
So the reliability and storage semantics bottom out at the filesystem after all. It's not as simple as 'I'll use SQLite: problem solved'. Not for the authors of SQLite, for sure.
Unix’s file durability problem
91–100 of 161 posts
Re: Unix’s file durability problem
#92I think the man page http://linux.die.net/man/2/fsync answers the questions the article asks about fsync(). fsync() = YES metadata, YES data, NO dir entry fdatasync() = NO metadata, YES data, NO dir entry fsync() of dir = NO metadata, NO data, YES dir entry
For Linux, but it's not portable across all Unixes. fsync is allowed to do nothing (1) and does not need to work on directories (2). On Mac OSX, fsync will not flush the disk cache, which can lead to data loss (3). (1) http://pubs.opengroup.org/onlinepubs/9699919799/functions/fs... (2) http://austingroupbugs.net/view.php?id=672 (3) https://developer.apple.com/library/mac/documentation/Darwin...
Re: Unix’s file durability problem
#93Earlier quoted context omitted.
For Linux, but it's not portable across all Unixes. fsync is allowed to do nothing (1) and does not need to work on directories (2). On Mac OSX, fsync will not flush the disk cache, which can lead to data loss (3). (1) http://pubs.opengroup.org/onlinepubs/9699919799/functions/fs... (2) http://austingroupbugs.net/view.php?id=672 (3) https://developer.apple.com/library/mac/documentation/Darwin...
fsync(2) on OS X and other Darwins also does not sync metadata. You need to use fcntl(2) with F_FULLFSYNC for that.
https://opensource.apple.com/source/xnu/xnu-2422.1.72/bsd/hf...
Alternatively, you could just use the ZFS driver for Mac OS X. It will do fsync properly.
Re: Unix’s file durability problem
#94I've suggested an approach to this before. There should be several types of files. - "Unit" files commit when closed properly (this does not include a program exit without close), and then replace the old version of the file. The file system should guarantee that, after a crash, you have either the old version or the new complete version. This should be the default when a file is opened via "creat()" - "Temp" files a…
I think the semantic you want for log files is: write atomically at offset X, but only if the size of the file is currently X.
If the write fails due to a file size mismatch, you are racing with someone else. You can either read the other writer's data before you try writing again or just fail immediately if races shouldn't happen.
Re: Unix’s file durability problem
#95Earlier quoted context omitted.
Rename isn't quite an atomic replacement. If you crash before the rename, the new file hangs around. (Hence unwanted .part files.) O_APPEND isn't airtight on all systems. On some older UNIX systems, multiple writers created with "open()" (not "dup()") do not share a file position. NTFS doesn't do append correctly. How do you guarantee that, after a crash, the end of the file is at the end of some write? By updating t…
sync_file_range(2) allows you to specify ranges to sync, instead of the whole file, but it's not that useful anyway. In most DBs, you have separate data and log. The log is always only appended to, and the nature of disks is such that grouping concurrent transactions together into a single commit is a big win regardless of how syncing works. So syncing all outstanding I/O to the log file is generally what you want to…
See http://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;... and http://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;...
Re: Unix’s file durability problem
#96Earlier quoted context omitted.
Microsoft actually tried something similar with WinFS [0] in the 00's, but the project failed. [0] - https://en.wikipedia.org/wiki/WinFS
Oddly, Apple's Core Data framework achieves pretty much all the goals WinFS set out to achieve—but does so sitting (for no good reason, really) on top of a regular filesystem. It'd actually be pretty easy to flip things around: give Core Data a raw block device persistence backend, and then write a filesystem driver on top of it. One of my recently-planned hobby projects was to write a FUSE filesystem for OSX that wo…
You don't like files? Files are great.
Running Core Data over SQLite instead of a "real database" gets you backups for free, the iOS file-based security model, lets you delete an app's data when it goes away, network mounted home directories… really, the filesystem abstraction is pretty good still.
Re: Unix’s file durability problem
#97Earlier quoted context omitted.
> - "Unit" files commit when closed properly (this does not include a program exit without close), and then replace the old version of the file. The file system should guarantee that, after a crash, you have either the old version or the new complete version. Incidentally, this is the way it currently is. From rename(2) : If "newpath already exists, it will be atomically replaced". Just don't forget that "replacing"…
Don't know why you're downvoted. Everything you said is correct. Additionally, in Linux, you can get asynchronous fdatasync(2) with sync_file_range(2). aio(7) is weird. It really only works with direct I/O (which is necessary much less often than people think it is), and IIRC aio_fsync(2) isn't implemented on Linux, but that doesn't matter so much because generally direct I/O implies synchronous I/O (but not always).…
Re: Unix’s file durability problem
#98A good solution is to use SQLite. It addresses the issues (pretty much by doing all the fsync etc mentioned including on directories) and has a very comprehensive test suite. It is also used very widely on desktops, mobile devices, applications etc. https://www.sqlite.org/whentouse.html A notable quote: SQLite does not compete with client/server databases. SQLite competes with fopen().
The concept was proven before w/ RMS in OpenVMS: https://en.wikipedia.org/wiki/Files-11 It could work. Just best to have hybrids with different types of files, including those bypassing RDBMS function, so one can select proper reliability vs performance tradeoffs. SQLite might have cross-platform, FS-type API's too that I don't know about. Not sure if it's already there or be an extra development.
Re: Unix’s file durability problem
#99I've suggested an approach to this before. There should be several types of files. - "Unit" files commit when closed properly (this does not include a program exit without close), and then replace the old version of the file. The file system should guarantee that, after a crash, you have either the old version or the new complete version. This should be the default when a file is opened via "creat()" - "Temp" files a…
> "Log" files can only be appended. Writers cannot seek. I think the semantic you want for log files is: write atomically at offset X, but only if the size of the file is currently X. If the write fails due to a file size mismatch, you are racing with someone else. You can either read the other writer's data before you try writing again or just fail immediately if races shouldn't happen.
You're just proposing moving the semantics of what could be better done in kernel-space by resizing PIPE_BUF to userspace.
The way this works now is that you open a logfile with O_APPEND, any write(2) you make to the file will be atomic up to PIPE_BUF, so it doesn't matter that you have a "race" with someone else if everyone's write is Now of course if your write is bigger than PIPE_BUF you might have interleaving writes, but at the point where you're making >4K writes you're usually better off having some custom log system anyway and not rely on the kernel serializing things for you.
If you want to emulate this proposed mechanism of yours now without any syscall changes you can simply flock() the file for the duration of your write. The solution you're proposing already exists, but locking sucks more than O_APPEND + <PIPE_BUF sized writes.
Re: Unix’s file durability problem
#100https://www.usenix.org/legacy/event/osdi06/tech/nightingale/...
The basic idea is that the file system provides two guarantees, one boring, and one interesting. I'll illustrate using code instead of words. The boring guarantee is:
FILE* f = fopen("autosave.bak", "w");
fwrite(f, buffer, length); // save current document
fclose(f);
The system will try to make the write durable within 5 seconds of executing the second line. The interesting guarantee is this: FILE* f = fopen("autosave.bak", "w");
fwrite(f, buffer, length); // save current document
puts("Saving complete!")
fclose(f);
The system guarantees that the user will not see the message until the data is safely on disk! The way they do this is to implement a fancy dependency tracking mechanism that makes sure that the computer never generates output until the writes that the output depends on have completed.They do a bunch of benchmarks that show that their system is almost as fast as mounting ext3 _asynchronously_. (In fact, not much worse than a RAM disk even.) Of course, they also show that in the case of power loss, their system behaves well, whereas ext3 does not, unless you turn up all the paranoia knobs to 11, and then the performance is WAY worse than their system.
I'm oversimplifying quite a bit, since this comment is already pretty long. Read the paper for details. Or ask questions here, but I'll probably forget to check the comments, because HN doesn't remind me :(