So I have a an application which is running on top of gridgain and does so quite successfully for about 12-24 hours of stress testing before it starts to act funny. After this period of time the application will suddenly start replying to all queries with the exception java.nio.channels.ClosedByInterruptException (full stack trace is at http://pastie.org/664717
The method that is failing from is (edited to use #stephenc feedback)
public static com.vlc.edge.FileChannel createChannel(final File file) {
FileChannel channel = null;
try {
channel = new FileInputStream(file).getChannel();
channel.position(0);
final com.vlc.edge.FileChannel fileChannel = new FileChannelImpl(channel);
channel = null;
return fileChannel;
} catch (FileNotFoundException e) {
throw new VlcRuntimeException("Failed to open file: " + file, e);
} catch (IOException e) {
throw new VlcRuntimeException(e);
} finally {
if (channel != null) {
try {
channel.close();
} catch (IOException e){
// noop
LOGGER.error("There was a problem closing the file: " + file);
}
}
}
}
and the calling function correctly closes the object
private void fillContactBuffer(final File signFile) {
contactBuffer = ByteBuffer.allocate((int) signFile.length());
final FileChannel channel = FileUtils.createChannel(signFile);
try {
channel.read(contactBuffer);
} finally {
channel.close();
}
contactBuffer.rewind();
}
The application basically serves as a distributed file parser so it does a lot of these types of operations (will typically open about 10 such channels per query per node). It seems that after a certain period it stops being able to open files and I'm at a loss to explain why this could be happening and would greatly appreciate any one who can tell me what could be causing this and how I could go about tracking it down and fixing it. If it is possibly related to file handle exhaustion, I'd love to hear any tips for finding out for sure... i.e. querying the JVM while it's running or using linux command line tools to find out more information about what handles are currently open.
update: I've been using command line tools to interrogate the output of lsof and haven't been able to see any evidence that file handles are being held open... each node in the grid has a very stable profile of openned files which I can see changing as the above code is executed... but it always returns to a stable number of open files.
Related to this question: Freeing java file handles
There are a couple of scenarios where file handles might not be being closed:
There might be some other code that opens files.
There might be some other bit of code that calls createChannel(...) and doesn't call fillContactBuffer(...)
If channel.position(0) throws an exception, the channel won't be closed. The fix is to rearrange the code so that the following statements are inside the try block.
channel.position(0);
return new FileChannelImpl(channel);
EDIT: Looking at the stack trace, it seems that the two methods are in different code-bases. I'd point the finger of blame at the createChannel method. It is potentially leaky, even if it is not the source of your problems. It needs an in internal finally clause to make sure that the channel is closed in the event of an exception.
Something like this should do the trick. Note that you need to make sure that the finally block does not closes the channel on success!
public static com.vlc.edge.FileChannel createChannel(final File file) {
final FileChannel channel = null;
try {
channel = new FileInputStream(file).getChannel();
channel.position(0);
FileChannel res = new FileChannelImpl(channel);
channel = null;
return res;
} catch (FileNotFoundException e) {
throw new VlcRuntimeException("Failed to open file: " + file, e);
} catch (IOException e) {
throw new VlcRuntimeException(e);
} finally {
if (channel != null) {
try {
channel.close();
} catch (...) {
...
}
}
}
}
FOLLOWUP much later
Given that file handle leakage has been eliminated as a possible cause, my next theory would be that the server side is actually interrupting its own threads using Thread.interrupt(). Some low-level I/O calls respond to an interrupt by throwing an exception, and the root exception being thrown here looks like one such exception.
This doesn't explain why this is happening, but at a wild guess I'd say that it was the server-side framework trying to resolve an overload or deadlock problem.
Related
I was trying to get some networking going in my app, but i encountered some issues. It seems that I cant write to the OutputStream object. Though my server recieves the connection, it does not recieve any data. I've tried using Writer, DataOutputStream among others. none seemed to work.
My app uses asynctasks that call this object with a Socket object and a message. (The socket object has already been used to set Streams after initialisation using the setStreams method.)
can someone please try and find the problem? I will be very thankful.
public class NetworkingUtils {
private OutputStream out = null;
private InputStream in = null;
//set streams
public void setStreams(Socket sock){
if (sock.isConnected()) {
try {
this.out = (OutputStream) sock.getOutputStream();
this.in = (InputStream) sock.getInputStream();
} catch (Throwable e) {
Log.d("SOCKET", "FAILED TO SET STREAMS");
e.printStackTrace();
}
}
}
//send \n terminated messages to pre defined socket
public void sendMessage(Socket sock, String message) throws Throwable {
if (sock.isConnected()) {
try {
this.out.write(message.getBytes());
Log.d("SOCKET","WRITING COMPLETE. " + message);
} catch (Throwable e) {
throw e;
}
}
}
public String recvMessage(Socket sock) throws Throwable {
//receives \n terminated message from pre defined socket
String answer = null;
if (sock.isConnected()){
try{
answer = this.convertStreamToString(this.in);
Log.d("SOCKET","READING COMPLETE");
}
catch (Throwable e){
Log.d("socket",e.getLocalizedMessage());
throw e;
}
}
else{
Log.d("socket","is not connected!!!");
}
if (answer.length() == 0){
//empty string answer from server
throw new IOException();
}
else {
return answer;
}
}
private String convertStreamToString(java.io.InputStream is) {
java.util.Scanner s = null;
try{
s = new java.util.Scanner(is).useDelimiter("\r\n");}
catch (Throwable e){
e.printStackTrace();
}
return s.hasNext() ? s.next() : "";
}
}
I can only see one client-side that might cause this ... and I'm doubtful about it. (That is to say: try this, just in case it makes a differences, but I don't think it will.)
this.out.write(message.getBytes());
Log.d("SOCKET","WRITING COMPLETE. " + message);
The potential problem is that if out is a "buffered" stream, then a write may only result in the bytes being written to the buffer. It may be necessary to call this.out.flush() to "push" to the server.
But I am doubtful it will help, because (to my knowledge) a socket output stream isn't buffered in Java. I think it is more likely that the real problem is on the server side.
If you are stumped with figuring out which side the problem is occuring, I suggest you try using a network monitoring / packet sniffing tool (on the server side) to check if the data is reaching the server host.
While I have your attention, your exception code is really, really bad.
Don't declare methods as throws Throwable (or throws Exception). That basically says "this method may throw ANY exception, and I'm not telling you which one". When you do that, the caller code has to cope with any exception, which is basically impossible to do intelligently.
What you should do is to declare the method as throwing the checked exceptions that the code can throw. For example, in your case, IOException is probably sufficient.
It is not a good idea to catch an exception, log it, and then rethrow it. Why? Because further up the stack there are probably other methods that will see the exception. They can't know if the exception has already been logged or not. So should they log it (possibly resulting in duplicate logs events for the same problem) or not (possibly resulting in the exception going unlogged.)
Don't throw exceptions without a message:
throw new IOException();
It is lazy. You should always include a simple message that can (at least) be grep'd or googled for.
In addition, your testing of Socket.isConnected() all over the place is unnecessary. According to the javadoc:
Returns: true if the socket was successfuly connected to a server
Note: Closing a socket doesn't clear its connection state, which means
this method will return true for a closed socket (see isClosed()) if
it was successfuly connected prior to being closed.
So repeatedly testing isConnected is nugatory. If it returns true once, it will will always return true from then on.
Even the initial isConnected test in setStreams is doubtful. I'd just call getInputStream without testing, and rely on the Socket API throwing an IOException if the socket is in the wrong state.
You're effectively reading lines with that obscure Scanner usage, but you're not writing lines. So the scanner will block until a line terminator or EOS arrives.
You need to append a line terminator when sending.
Here is most of the relevant code, running on a cRIO with the FRC Java image:
try {
SocketConnection http = (SocketConnection) Connector.open("socket://" + BEAGELIP);
InputStream data = http.openInputStream();
database = "";
int p = data.read();
while (p >= 0) {
database += (char) p;
p = data.read();
}
data.close();
http.close();
} catch (Exception e) {
System.out.println(e);
}
This method is being repeatedly called.
After repeated failures to connect (e.g., the server is not plugged in), the IOException switches from java.io.IOException: ConnectException: connect refused to java.io.IOException: errno: 24 on fd:-1 during socket create
We think the reason this might be happening is because on failure, Connector.open returns null, which we cannot close(), freezing up a filedescriptor.
What is the correct way to prevent all of the file descriptors from being used up in this procedure?
If anyone can give a suggestion on how this should be done, that would be wonderful.
Your closes must be in a finally {} block. Otherwise they don't happen if there was an exception, and there will be an exception sooner or later,
I want to have a class which instances from different threads will write or read from the same file. Below is pretty much the write operation but I get a java.nio.file.FileSystemException. I am using 2 instances as a trivial multi-thread access but I can't make it work
try {
fileChannel = AsynchronousFileChannel.open(Paths.get("Filename.txt"),
StandardOpenOption.READ,
StandardOpenOption.WRITE);
} catch (IOException e) {
e.printStackTrace();
}
Future<Integer> writeFuture =
fileChannel.write(ByteBuffer.wrap(obj.toString().getBytes()), position);
try {
fileChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
EDIT:
The stacktrace:
java.nio.file.FileSystemException: C:\Documents and Settings\Administrator\workspace\TileMap\FileMap.txt: The process cannot access the file because it is being used by another process.
at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:86)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:90)
at sun.nio.fs.WindowsChannelFactory.newAsynchronousFileChannel(WindowsChannelFactory.java:199)
at sun.nio.fs.WindowsFileSystemProvider.newAsynchronousFileChannel(WindowsFileSystemProvider.java:138)
at java.nio.channels.AsynchronousFileChannel.open(AsynchronousFileChannel.java:248)
at java.nio.channels.AsynchronousFileChannel.open(AsynchronousFileChannel.java:300)
at slick.FileMap.updateFiguredMap(FileMap.java:84)
at agents.PlayerMap.seeFiguredMap(PlayerMap.java:196)
at agents.TickerExplorerRandomMapFile.seeFiguredMap(TickerExplorerRandomMapFile.java:206)
at agents.TickerExplorerRandomMapFile$1.onTick(TickerExplorerRandomMapFile.java:236)
at jade.core.behaviours.TickerBehaviour.action(TickerBehaviour.java:72)
at jade.core.behaviours.Behaviour.actionWrapper(Behaviour.java:344)
at jade.core.Agent$ActiveLifeCycle.execute(Agent.java:1532)
at jade.core.Agent.run(Agent.java:1471)
at java.lang.Thread.run(Thread.java:722)
When your thread are finished updating the file, then it should close the stream. If a thread has an active file handle or it has not release the handle after finishing the update, then other thread will not be able to get the file handle. Most probably, that is the reason why you are getting the exception saying
"The process cannot access the file because it is being used by
another process."
I am creating a file on a network drive and then adding data to it. Time to time writing to that file fails. Is there a good way of checking if the file is accessible before every time i save data to it or maybe is tehre a way checking afther to see if the data was saved?
EDIT:
Right now i am using try-catch block with PrintStream in my code:
try
{
logfile = new File(new File(isic_log), "log_" + production);
//nasty workaround - we'll have a file the moment we assign an output stream to it
if (!logfile.exists())
{
prodrow = production;
}
out = new FileOutputStream(logfile.getPath(), logfile.exists());
p = new PrintStream(out);
if (prodrow != "")
{
p.println (prodrow);
}
p.println (chip_code + ":" + isic_number);
p.close();
}
catch (Exception e)
{
logger.info("Got exception while writing to isic production log: " + e.getMessage());
}
So might be the PrintStream the problem? (PrintWriter and PrintStream never throw IOExceptions)
I would use plain BufferedWriter and add the newlines myself as required.
Normal FileOutputStream operations should throw an IOException if there is an error.
AFAIK, The only exception is PrintWriter which does not throw an exception. Instead you need to call checkError() but it gives you no indication of what the error was or when it occurred.
I suggest you not use PrintWriter in this situation.
The only reasonable way to address this is to try to write to the file, and handle any resulting exception in an appropriate manner. It's pretty much impossible to know beforehand whether an I/O operation is going to succeed, due to the unreliable nature of networks.
I have the following code in a java Web Service:
public boolean makeFile(String fileName, String audio)
{
if (makeUserFolder())
{
File file = new File(getUserFolderPath() + fileName + amr);
FileOutputStream fileOutputStream = null;
try
{
file.createNewFile();
fileOutputStream = new FileOutputStream(file);
fileOutputStream.write(Base64.decode(audio));
return true;
}
catch(FileNotFoundException ex)
{
return false;
}
catch(IOException ex)
{
return false;
}
finally{
try {
fileOutputStream.close();
convertFile(fileName);
} catch (IOException ex) {
Logger.getLogger(FileUtils.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
else
return false;
}
public boolean convertFile(String fileName)
{
Process ffmpeg;
String filePath = this.userFolderPath + fileName;
try {
ProcessBuilder pb = new ProcessBuilder("ffmpeg","-i",filePath + amr,filePath + mp3);
pb.redirectErrorStream();
ffmpeg = pb.start();
} catch (IOException ex) {
return false;
}
return true;
}
It used to work and now it simply won't execute the ffmpeg conversion for some reason. I thought it was a problem with my file but after running the command from terminal no errors are thrown or anything, thought it was maybe permissions issue but all the permissions have been granted in the folder I'm saving the files. I noticed that the input BufferedReader ins being set to null after running the process, any idea what's happening?
First of all, a small nitpick with your code...when you create the FileOutputStream you create it using a string rather than a File, when you have already created the File before, so you might as well recycle that rather than force the FileOutputStream to instantiate the File itself.
Another small nitpick is the fact that when you are writing out the audio file, you should enclose that in a try block and close the output stream in a finally block. If you are allowed to add a new library to your project, you might use Guava which has a method Files.write(byte[],File), which will take care of all the dirty resource management for you.
The only thing that I can see that looks like a definite bug is the fact that you are ignoring the error stream of ffmpeg. If you are blocking waiting for input on the stdout of ffmpeg, then it will not work.
The easiest way to take care of this bug is to use ProcessBuilder instead of Runtime.
ProcessBuilder pb = new ProcessBuilder("ffmpeg","-i",filePath+amr,filePath+mp3);
pb.redirectErrorStream(); // This will make both stdout and stderr be redirected to process.getInputStream();
ffmpeg = pb.start();
If you start it this way, then your current code will be able to read both input streams fully. It is possible that the stderr was hiding some error that you were not able to see due to not reading it.
If that was not your problem, I would recommend using absolute paths with ffmpeg...in other words:
String lastdot = file.getName().lastIndexOf('.');
File mp3file = new File(file.getParentFile(),file.getName().substring(0,lastdot)+".mp3");
ProcessBuilder pb = new ProcessBuilder("ffmpeg","-i",file.getAbsolutePath(),mp3file.getAbsolutePath());
// ...
If that doesn't work, I would change ffmpeg to be an absolute path as well (in order to rule out path issues).
Edit: Further suggestions.
I would personally refactor the writing code into its own method, so that you can use it elsewhere necessary. In other other words:
public static boolean write(byte[] content, File to) {
FileOutputStream fos = new FileOutputStream(to);
try {
fos.write(content);
} catch (IOException io) {
// logging code here
return false;
} finally {
closeQuietly(fos);
}
return true;
}
public static void closeQuietly(Closeable toClose) {
if ( toClose == null ) { return; }
try {
toClose.close();
} catch (IOException e) {
// logging code here
}
}
The reason that I made the closeQuietly(Closeable) method is due to the fact that if you do not close it in that way, there is a possibility that an exception will be thrown by the close() method, and that exception will obscure the exception that was thrown originally. If you put these in a utility class (although looking at your code, I assume that the class that it is currently in is named FileUtils), then you will be able to use them throughout your application whenever you need to deal with file output.
This will allow you to rewrite the block as:
File file = new File(getUserFolderPath() + fileName + amr);
file.createNewFile()
write(Base64.decode(audio),file);
convertFile(fileName);
I don't know whether or not you should do this, however if you want to be sure that the ffmpeg process has completed, then you should say ffmpeg.waitFor(); to be sure that it has completed. If you do that, then you should examine ffmpeg.exitValue(); to make sure that it completed successfully.
Another thing that you might want to do is once it has completed, write what it output to a log file so you have a record of what happened, just in case something happens.