HELP: java1.4.2 on windows, FileChannel.Close

A

Andrew Rollings

Hi...
I'm having a few problems with the close method of the FileChannel class in
Sun java 1.4.2 (latest as of this date) on Windows.
The code I've written seems to perform as expected on both MacOsX and linux,
so I'm wondering if anyone has come across similar circumstances, and has
found a workaround.

Or alternatively, just tell me what I'm doing that's dumb.

I have a class that maintains a TreeMap of FileChannels. At a certain point
in the class execution, I iterate through the map, and close out all of the
channels, and then attempt to delete the underlying file.
The code to this this is as follows:


-- begin excerpt
Iterator iter = m_FileChannelMap.keySet().iterator();
java.util.Vector keysToRemove = new java.util.Vector();
while ( iter.hasNext() )
{
Long lKey = ( Long ) iter.next();
if (lKey.longValue() < 0)
{
// get the channel and close it
FileChannel fc = (FileChannel)m_FileChannelMap.get(lKey);
fc.truncate(0);
fc.force(true);
fc.close();

// okay - file channel should be closed... we can delete the
// file it represents...
String strFilename = m_strFileroot +
this.getSegmentName(lKey.longValue());
if (!strFilename.endsWith(".T")) throw new IOException("Invalid
segment");
java.io.File fSegment = new File(strFilename);
if (false == fSegment.delete())
{
throw new IOException("Cannot close .T segment:" +
strFilename );
}
}
}
-- end excerpt

The problem is, that the IOException is *always* thrown. It seems that
FileChannel.close() does not immediately close the channel. I'm wondering if
this is anything to do with the fact that I'm maintaining a reference to the
FileChannel object in the TreeMap, but I don't see why that should be the
case. Anyway, this code works perfectly on Mac and Linux, but appears to
barf out on Windows.

Can anyone tell me what's wrong with the code? Failing that can anyone
suggest an alternate method that will work?
(And as an aside, is it safe to remove an item from the map while I'm
iterating through it? I don't currently do that, but I may want to at some
point.)

Thanks for reading.

Andrew
 
J

John C. Bollinger

Andrew said:
Hi...
I'm having a few problems with the close method of the FileChannel class in
Sun java 1.4.2 (latest as of this date) on Windows.
The code I've written seems to perform as expected on both MacOsX and linux,
so I'm wondering if anyone has come across similar circumstances, and has
found a workaround.

Or alternatively, just tell me what I'm doing that's dumb.

I have a class that maintains a TreeMap of FileChannels. At a certain point

That's dumb unless it's important that the channels remain always in
order by whatever key you use, including if you need to use the methods
specific to the SortedSet interface. In any other circumstance a
HashMap is a better choice. That isn't relevant to your problem, however.
in the class execution, I iterate through the map, and close out all of the
channels, and then attempt to delete the underlying file.
The code to this this is as follows:


-- begin excerpt
Iterator iter = m_FileChannelMap.keySet().iterator();

I'd iterate over the entry set, myself, since you are going to retrive
the value for each key anyway. That's not causing your problem either
though.
java.util.Vector keysToRemove = new java.util.Vector();

You don't appear to use this Vector.
while ( iter.hasNext() )
{
Long lKey = ( Long ) iter.next();
if (lKey.longValue() < 0)
{

That's a bit odd. You identify the entries to close by their keys? I
thought you were closing them all. Did you somehow arrange that the
keys you were interested in would all be negative, or did you rekey the
channels? (The latter would be quite inefficient, and more so for a
TreeMap than for a HashMap.)
// get the channel and close it
FileChannel fc = (FileChannel)m_FileChannelMap.get(lKey);
fc.truncate(0);
fc.force(true);
fc.close();

// okay - file channel should be closed... we can delete the
// file it represents...
String strFilename = m_strFileroot +
this.getSegmentName(lKey.longValue());
if (!strFilename.endsWith(".T")) throw new IOException("Invalid
segment");
java.io.File fSegment = new File(strFilename);
if (false == fSegment.delete())
{
throw new IOException("Cannot close .T segment:" +
strFilename );
}
}
}
-- end excerpt

The problem is, that the IOException is *always* thrown. It seems that
FileChannel.close() does not immediately close the channel.

From the API docs of FileChannel's superclass,
AbstractInterruptibleChannel: "This class encapsulates the low-level
machinery required to implement the asynchronous closing and
interruption of channels." It would appear, then, that asynchronous
closing is a design feature of the class.
I'm wondering if
this is anything to do with the fact that I'm maintaining a reference to the
FileChannel object in the TreeMap, but I don't see why that should be the
case.

No, there is no reason why holding a reference in any particular place
would affect the behavior of an object in any way. Affect the behavior
of the GC, yes, but not of the object.
Anyway, this code works perfectly on Mac and Linux, but appears to
barf out on Windows.

I'd say that the code is just plain buggy, even if so far the problem
has only manifested on Windows. Since you are already truncating the
files to zero length, perhaps it would be sufficient to flag them for
deletion on JVM exit instead of deleting them immediately (via
File.deleteOnExit()). If you must affirmatively delete them then you
must be prepared to handle the possibility that they are sill open when
you attempt to do so. One way of handling that would be to catch the
exception and try again after a delay.
Can anyone tell me what's wrong with the code? Failing that can anyone
suggest an alternate method that will work?

See above.
(And as an aside, is it safe to remove an item from the map while I'm
iterating through it? I don't currently do that, but I may want to at some
point.)

Only if you do so via the iterator itself; otherwise (for TreeMap) you
will get ConcurrentModificationException from you iterator after the
removal. For Generic Maps behavior of the iterator subsequent to
modification of the underlying Map is undefined. (See API docs for
Map.keySet(), Map.entrySet(), and Map.values().)


John Bollinger
(e-mail address removed)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top