I have an object responsible for persisting JTable
state to disk. It saves/loads visible columns, their size, position etc. A few interesting bits from its class definition are below.
class TableSaver {
Timer timer = new Timer(true);
TableSaver() {
timer.schedule(new TableSaverTimerTask(), 15000, SAVE_STATE_PERIOD);
}
synchronized TableColumns load(PersistentTable table) {
String xml = loadFile(table.getTableKey());
// parse XML, return
}
synchronized void save(String key, TableColumns value) {
try {
// Some preparations
writeFile(app.getTableConfigFileName(key), xml);
} catch (Exception e) {
// ... handle
}
}
private class TableSaverTimerTask extends TimerTask {
@Override
public void run() {
synchronized (TableSaver.this) {
Iterator<PersistentTable> iterator = queue.iterator();
while (iterator.hasNext()) {
PersistentTable table = iterator.next();
if (table.getTableKey() != null) {
save(table.getTableKey(), dumpState(table));
}
iterator.remove();
}
}
}
}
}
TableSaver
, ever.load()
can be called from many threads. Timer clearly is another thread.loadFile()
and writeFile()
do not leave open file streams - they use a robust, well tested and broadly used library which always closes the streams with try ... finally
.Sometimes this fails with an exception like:
java.lang.RuntimeException: java.io.FileNotFoundException: C:\path\to\table-MyTable.xml (The requested operation cannot be performed on a file with a user-mapped section open)
at package.FileUtil.writeFile(FileUtil.java:33)
at package.TableSaver.save(TableSaver.java:175)
at package.TableSaver.access$600(TableSaver.java:34)
at package.TableSaver$TableSaverTimerTask.run(TableSaver.java:246)
at java.util.TimerThread.mainLoop(Unknown Source)
at java.util.TimerThread.run(Unknown Source)
Caused by: java.io.FileNotFoundException: C:\path\to\table-MyTable.xml (The requested operation cannot be performed on a file with a user-mapped section open)
at java.io.FileOutputStream.open(Native Method)
at java.io.FileOutputStream.<init>(Unknown Source)
at java.io.FileOutputStream.<init>(Unknown Source)
at package.FileUtilWorker.writeFile(FileUtilWorker.java:57)
... 6 more
So I have two questions:
TableSaver
.package.TableSaver.access$600(TableSaver.java:34)
? Line 34 is the line with class TableSaver {
. Can this be the reason why the synchronization is not working?Google learns me that this seems to be Windows specific. Here's an extract of Bug 6354433:
This is Windows platform issue with memory-mapped file, i.e.
MappedByteBuffer
. The Java 5.0 doc forFileChannel
state that "the buffer and the mapping that it represents will remain valid until the buffer itself is garbage-collected". The error occurs when we tried to re-open the filestore and the mapped byte buffer has not been GC. Since there is nounmap()
method for mapped byte buffer (see bug 4724038), we're at the mercy of the underlying operating system on when the buffer get free up. CallingSystem.gc()
might free up the buffer but it is not guarantee. The problem doesn't occurs on Solaris; may be due to the way shared memory is implemented on Solaris. So the work-around for Windows is not to use memory-mapped file for the transaction information tables.
What Java/Windows version are you using? Does it have the latest updates?
Here are two other related bugs with some useful insights:
As to your second question, that's just the autogenerated classname of an inner or anonymous class.
Assuming there are no issues with the code I have seen this occur when a virus scanner is running in the background which is cheerfully opening files to scan them behind the scenes. If you have a memory resident virus scanner that checks files in the background try disabling it, or at least disabling it for the directory you reading from/writing to.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With