The short story:
Configuration.flushFileBuffers(false) is no more. If you still want to configure the behaviour that used to be available in db4o 6.1, you can do so by setting up IoAdapters as follows:
RandomAccessFileAdapter randomAccessFileAdapter = new RandomAccessFileAdapter();
NonFlushingIoAdapter nonFlushingIoAdapter =
new NonFlushingIoAdapter(randomAccessFileAdapter);
CachedIoAdapter cachedIoAdapter = new CachedIoAdapter(nonFlushingIoAdapter);
Configuration configuration = Db4o.newConfiguration();
configuration.io(cachedIoAdapter);
Db4o.openFile(configuration, PATH);
The long story:
We do a lot of things for consistent transactions (for the C in ACID). A commit of a db4o transaction consists of 4 write phases:
- Writing a commit log to the database file
- Switching the database file to commit mode
- Committing all slots
- Switching the database file to normal mode
Because a cache at any level may turn around the write order of individual slots and because a failure may end up in a partial write, it is essential that all data is flushed to the device after each one of these 4 phases.
This flush call takes a lot of time. It is the slowest part of the commit. On a system where you are sure enough (100% ? ) that the commit process always is successful, a tuning switch that skips flushing sounds like a smart way to improve performance.
That's what we thought and why we added the #flushFileBuffers(false) configuration switch in the first place.
Starting with db4o 6.4 we have added a new CachedIoAdapter to the IO layer as the default. This IoAdapter uses the #sync() calls as a signal to flush it's pages to the database file. What we did not think about well enough when we added this functionality: If users use the #flushFileBuffers(false) tuning switch, they also skip the flush of the CachedIoAdapter.
This issue does not surface as long as the database file is always shut down correctly, so it took us a long time to realize how serious it can be. Since we have switched db4o 6.4 to "stable", there have been a couple of support discussions like this one:
User: "We have switched to db4o 6.4. We are sometimes getting new exceptions like IncompatibleFileException."
db4objects: "Uhoh. Are you maybe using #flushFileBuffers(false) in productive use? Please don't do that. Don't tell us that you are."
User: "Yes we are."
After investing some time and thought we have figured that the CachedIoAdapter makes it much much more likely that corruption can happen if a database file is not shut down correctly (with the #flushFileBuffers(false) configuration call). Because this is so serious (it leads to corrupted database files), we have decided to turn off this configuration switch completely.
A similar functionality as in 6.1 is still available, if you really know what you are doing and if you know that you are taking the risc of corrupted database files if your system is halted because someone hits the power-off switch by accident in the middle of a commit. With the layer of IoAdapters, as outlined at the beginning of this posting, the risk of corruption is fairly small, just as it used to be in 6.1. Corruption will only happen if the OS cache or disc cache changes around the order of writes.
The changes are effective and the new IoAdapter is available from iteration 48 and revision 10977 onwards, e.g. from db4o versions:
6.4.48.10977
7.2.48.10977
7.4.48.10977
For previous stable 6.4 versions we strongly recommend not to use the #flushFileBuffers(false) setting in production use.
Many thanks to our users for reporting their problems!