Earlier quoted context omitted.
> NTFS doesn't do append correctly. Care to elaborate on that? I haven't seen issues with the two mechanisms I know of in NT: 1. CreateFile with FILE_APPEND_DATA 2. WriteFile with the OVERLAPPED offset set to ~0 Both of these get you writes that are as far as I know safe to have multiple processes writing to a common log file. Not sure about flushes to disk but you could probably get away with FlushFileBuffers for th…
NTFS handles append just fine. As another comment speculated, the parent may have meant NFS, which does notoriously have lots of problems with append, and many other POSIX semantics.
Unix’s file durability problem
121–130 of 161 posts
Re: Unix’s file durability problem
#122Earlier 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"…
Your response pretty aptly demonstrates the problem in the original article. If you write to a temp file and then use rename, you need to pick a suitable temporary name (without a race condition) that other programs will ignore, and now you've probably created a garbage file if the program crashes before you get to the rename. You also need to make sure you've preserved the permissions in the original file, and hope…
Re: Unix’s file durability problem
#123I ran across a nice paper a few years ago: Rethink the Sync. https://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…
Re: Unix’s file durability problem
#124Earlier 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…
> How do you guarantee that, after a crash, the end of the file is at the end of some write? By updating the file size after the write. Note that Linux ext4 does not do this. On a power outage, you can get bogus trailing zeros on a file which you were appending, because the file size was updated before the data was written. I asked Ted T'so about this and he said it was working as intended. https://plus.google.com/+K…
Re: Unix’s file durability problem
#125I'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…
> - "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"…
[1] https://www.usenix.org/system/files/conference/osdi14/osdi14...
Re: Unix’s file durability problem
#126I ran across a nice paper a few years ago: Rethink the Sync. https://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…
Warning! This comment is _not_ saying that your operating system provides these guarantees. In fact, it almost certainly does not. This is a novel suggestion (and implementation?) presented in this particular paper.
Re: Unix’s file durability problem
#127Disks can buffer, disks can have firmware bugs, disks can fail both catastrophically and subtly. Even the fanciest battery-backed RAID controllers have firmware bugs and dead batteries. Those are just ways your storage hardware can fail you even if the kernel and libraries are bug free and you follow the right mystic incantations to sync data. While there's no excuse for bad documentation or poor APIs, you can never…
Yeah, from a SRE perspective, the last N writes are always purely probabilistic. The real quest is to have enough redundancy that that curve is fairly close to 1, and enough failure warning that your system will fix itself before it droops. That means Battery Backup, SMART detection, ECC memory, etc.
So yes, agreed++. You need to have a level of redundancy appropriate to the criticality of the data.
Re: Unix’s file durability problem
#128Earlier quoted context omitted.
> You have 100 concurrent web serving processes all writing to an access.log That makes no sense. Have each process write to its own log. This is making your life hard for no reason. > If you have a use-case for strictly serializing writes to disk like this that's fine, but it's not the common case with log files This isn't about access.log, it's about transaction logs for database systems. Like the commit log for Po…
> That makes no sense. Have each process write to its own log. This is > making your life hard for no reason. This is literally how pretty much every daemon process works on Unix systems. You don't log in and tail /var/log/apache/access.log.{1..N} where N is the number of threads/processes. You just tail /var/log/apache/access.log which all of them write to by virtue of PIPE_BUF semantics. Having to tail N logs where…
I can see how this would be convenient. That's fine and I have nothing against it. It's just not a problem I consider interesting, because there is no inherent need for all 100 writers to write to the same file. You could just as easily have each write to a separate file and have a separate process that merges them together if you want a single file for convenience.
> I really don't see how any of this is relevant to the original point of having "log" files.
Maybe you're not aware: every major database keeps a commit log, and writes it to a file called a log file (sometimes "write-ahead log file"). That is what I think of when I hear about "log" files in the context of file durability, because this is the case where file consistency and durability actually affect the consistency of the system. Here are some examples:
https://www.sqlite.org/tempfiles.html#walfile
http://www.postgresql.org/docs/9.1/static/wal-intro.html
https://leveldb.googlecode.com/svn/trunk/doc/impl.html
This is a much more interesting problem (to me) because it is harder and relevant to the consistency of any database system.
> Now you're talking about DB transaction logs and blockchains, which really don't need to have their nuances implemented in terms of POSIX file semantics. They can just have a single process that manages those expectations.
You do realize that SQLite can't just corrupt your database because you ran two SQLites concurrently, right?
SQLite has chosen to support concurrent SQLite processes all writing to the same database. Maybe you think they shouldn't do that, but they find it useful. And even in your world where they shouldn't do that, it's still not ok to just corrupt the database because the user didn't follow the rules.
> Everyone's expectations don't have to be implemented on the filesystem level
One of the kernel's key responsibilities is to arbitrate concurrent access to shared resources. It provides primitives that makes it possible to build higher-level abstractions. What I am describing is a primitive that allows for lock-free appends to consistent transaction logs. It could be useful for a lot of things, and makes at least as much sense as plenty of other things that are already in syscall interfaces.
Re: Unix’s file durability problem
#129I ran across a nice paper a few years ago: Rethink the Sync. https://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…
I misread this comment and it could be dangerous if someone who doesn't know misreads it the same way. So I want to put a big warning here. Warning! This comment is _not_ saying that your operating system provides these guarantees. In fact, it almost certainly does not. This is a novel suggestion (and implementation?) presented in this particular paper.
Re: Unix’s file durability problem
#130I'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…
> - "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"…
It doesn't mean atomic with respect to a system crash.
The easiest way to get asynchronous fsync(2) is to do the fsync(2) in a different thread.