What's the proper way to 'checkpoint' an open file so as to ensure
that the file's control structures are consistant on disk? I would
have thought that calling fflush() after every file write would be sufficient, but a recent trap proved that calling fflush() after file writes was no protection against CHKDSK truncating the file well before the last write. I suppose I could close and reopen the file after
every update, but I was hoping to find a more elegant solution. Any ideas?
What's the proper way to 'checkpoint' an open file so as to ensure thatthe
file's control structures are consistant on disk? I would have thought that calling fflush() after every file write would be sufficient, but a recent trap proved that calling fflush() after file writes was no protection against CHKDSK truncating the file well before the last write. I suppose I could close and reopen the file after every update, but I was hoping to find a more elegant solution. Any ideas?
What's the proper way to 'checkpoint' an open file so as to
ensure that the file's control structures are consistant on
disk? I would have thought that calling fflush() after every
file write would be sufficient,
but a recent trap proved that
calling fflush() after file writes was no protection against
CHKDSK truncating the file well before the last write. I
suppose I could close and reopen the file after every update,
but I was hoping to find a more elegant solution. Any ideas?
What's the proper way to 'checkpoint' an open file so as to ensure
that the file's control structures are consistant on disk? I would
have thought that calling fflush() after every file write would be sufficient, but a recent trap proved that calling fflush() after file writes was no protection against CHKDSK truncating the file well
before the last write. I suppose I could close and reopen the file
after every update, but I was hoping to find a more elegant solution.
Don't use the C runtime! Use DosOpen(....OPEN_FLAGS_WRITE_THROUGH....) and other Dos... APIs instead.
So, what you'd need to do is get an OS/2 handle to the file, and use DosResetBuffer() directly. If you can't get a handle, you can also
use that API to flush all open files for the current process.
How low do you want to go?
Firstly, you should not be doing buffered I/O if your updates must be committed immediately, so you should not use fopen() and fwrite() withouta
setbuf() call to suppress buffer allocation. Better yet, you should consider using open() and write() instead, and use the UNIX-like unbuffered I/O routines.
Moreover, if your data resources are critically important then you should be handling any traps that occur in your program and cleaning up the critical data resources in an orderly manner. This is far and away themost
professional approach to the situation. About the only things you can't handle are kernel level traps and power outages.
In your situation, I would have used the second facility before considering any intermediate commits.
I'm building an open-source databasing offline Usenet news system, basically along the lines of standard Fidonet message tossers and
readers, except designed from the ground up for Usenet news. As I
intend the system to be portable, I'd like to keep the number of platform-specific API calls to an absolute minimum.
Firstly, you should not be doing buffered I/O if your updates must be
committed immediately, so you should not use fopen() and fwrite()
without a setbuf() call to suppress buffer allocation. Better yet,
you should consider using open() and write() instead, and use the
UNIX-like unbuffered I/O routines.
I'm concerned that disabling buffering entirely is going to hurt performance very badly as my application does lots of short (4 to 256 byte) IO calls. Relying on the disk cache to handle this kind of
load seems a bit wasteful.
Moreover, if your data resources are critically important then you
should be handling any traps that occur in your program and cleaning
up the critical data resources in an orderly manner. This is far and
away the most professional approach to the situation. About the only
things you can't handle are kernel level traps and power outages.
The problem I ran into was that the kernel trapped (for reasons
unrelated to this project) a few hours after I wrote an article into
the article database. Since database was still in open (I leave the article reader running 24x7), the file system structures were
inconsistant enough that CHKDSK truncated the database well before
its proper end point. As you say, catching exceptions wouldn't help
much here.
My database format and engine implementations are robust enough to
cope with applications dying unexpectedly without finishing write operations; they're not robust enough to handle boot-up CHKDSK
removing 80Kb of data from the end of a 100Kb file.
In your situation, I would have used the second facility before
considering any intermediate commits.
It's not intermediate commits I need: what I need is some way to flush
out write operations made to files which might be open for days or
weeks at a time.
It's not intermediate commits I need: what I need is some way to
flush out write operations made to files which might be open for
days or weeks at a time
The only reliable way I know of is _NOT_ to keep the files open but to open and close them as needed. It is the _only_ way I know which is guaranteed to update the directory information (Inode under *NIX) so
that a chkdsk won't cause you that sort of grief. In a similar
situation I ended up opening and closing the file during normal
operation to ensure the on-disk information and structures were
updated. Originally I opened the file on start-up and kept it open.
Moreover, if your data resources are critically important then
you should be handling any traps that occur in your program and
cleaning up the critical data resources in an orderly manner.
This is far and away the most professional approach to the
situation. About the only things you can't handle are kernel
level traps and power outages.
The problem I ran into was that the kernel trapped (for reasons
unrelated to this project) a few hours after I wrote an article
into the article database. Since database was still in open (I
leave the article reader running 24x7), the file system structures
were inconsistant enough that CHKDSK truncated the database well
before its proper end point. As you say, catching exceptions
wouldn't help much here
My database format and engine implementations are robust enough to
cope with applications dying unexpectedly without finishing write operations; they're not robust enough to handle boot-up CHKDSK
removing 80Kb of data from the end of a 100Kb file
In your situation, I would have used the second facility before
considering any intermediate commits.
It's not intermediate commits I need: what I need is some way to
flush out write operations made to files which might be open for
days or weeks at a time
Replying to a message of George White to Coridon Henshaw:
It's not intermediate commits I need: what I need is some way to
flush out write operations made to files which might be open for
days or weeks at a time
The only reliable way I know of is _NOT_ to keep the files open
but to open and close them as needed. It is the _only_ way I know
which is guaranteed to update the directory information (Inode
under *NIX) so that a chkdsk won't cause you that sort of grief.
In a similar situation I ended up opening and closing the file
during normal operation to ensure the on-disk information and
structures were updated. Originally I opened the file on start-up
and kept it open.
This is true when one is keeping things simple, such as using
sequential file structures
A genuine database [and that is what Coridon claims he is coding]
does not restrict itself to simple file structures. The usual
approach is to allocate and pre-format a suitably large area of
disk, known as a tablespace in DB2, and then maintain
database-specific structural data within that. The pre-format
operation finishes by closing the physical file, thus ensuring the underlying file system has recorded the number and size of all
disk extents allocated to the file. The DBMS is then free to
"suballocate" the disk space as and how it sees fit. It also takes
on the responsibility to ensure the consistency of the database's
content
We will see how Coridon implements such a database system.
Since 4-to-256 bytes does not constitute a typical Usenet article, those would not be your logical syncpoints. You should be physically writing the data to disk at your syncpoints and only at your syncpoints.
My database format and engine implementations are robust enough to
cope with applications dying unexpectedly without finishing write
operations; they're not robust enough to handle boot-up CHKDSK
removing 80Kb of data from the end of a 100Kb file.
So you do have a syncpoint architecture, then?
This seems to me to be the type of activity you really want to perform.One
of your problems is that your input stream is not persistent, as it would be a socket connected to a NNTP server [if I read your design correctly, and assume you are coding from the ground up]. This means that you need to be able to restart a failed instance of the application, resuming from its most recent succesful syncpoint. The usual method to deal with this is to use a log or journal file that keeps track of "in flight" transactions;the
journal is where your I/O remains unbuffered. If your NNTP server allows you to re-fetch articles -- and most do -- you can keep your journal inRAM
or on a RAMDISK; this prevents performance hits for doing short I/O's.
Sysop: | digital man |
---|---|
Location: | Riverside County, California |
Users: | 1,043 |
Nodes: | 16 (0 / 16) |
Uptime: | 89:35:22 |
Calls: | 500,953 |
Calls today: | 2 |
Files: | 109,377 |
D/L today: |
1,133 files (199M bytes) |
Messages: | 304,684 |