OK, problem solved, not a Scala issue.
Using memory mapped files is problematic. The mapping is not removed
until the MappedByteBuffer is finalized at garbage collection, so the
file is locked against modification.
There is nothing in the API to force the unmapping, but you can use
reflection to get at the internal 'clean' method.
Things would have been so much easier if MappedByteBuffer had a close()
method the allowed explicit unmapping.
Cheers, Eric
/**
* DirectByteBuffers are garbage collected by using a phantom
reference and a
* reference queue. Every once a while, the JVM checks the reference
queue and
* cleans the DirectByteBuffers. However, as this doesn't happen
* immediately after discarding all references to a DirectByteBuffer, it's
* easy to OutOfMemoryError yourself using DirectByteBuffers.
*
* Also, if a file is still mapped, then it is locked and cannot be
destroyed
* or possibly written to if it was mapped read.
*
* This function explicitly calls the Cleaner method of a
DirectByteBuffer.
*
* @param toBeDestroyed
* The DirectByteBuffer that will be "cleaned". Utilizes
reflection.
*
*/
public static void destroyDirectByteBuffer(ByteBuffer toBeDestroyed)
throws IllegalArgumentException, IllegalAccessException,
InvocationTargetException, SecurityException, NoSuchMethodException {
if (toBeDestroyed == null) return;
if (!toBeDestroyed.isDirect()) {
System.err.println("toBeDestroyed isn't direct!");
return;
}
Method cleanerMethod = toBeDestroyed.getClass().getMethod("cleaner");
cleanerMethod.setAccessible(true);
Object cleaner = cleanerMethod.invoke(toBeDestroyed);
Method cleanMethod = cleaner.getClass().getMethod("clean");
cleanMethod.setAccessible(true);
cleanMethod.invoke(cleaner);