You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2012/06/01 19:27:22 UTC
svn commit: r1345279 - in /commons/proper/io/trunk/src: changes/changes.xml
main/java/org/apache/commons/io/input/Tailer.java
Author: ggregory
Date: Fri Jun 1 17:27:21 2012
New Revision: 1345279
URL: http://svn.apache.org/viewvc?rev=1345279&view=rev
Log:
[IO-332] Improve tailer's reading performance.
Modified:
commons/proper/io/trunk/src/changes/changes.xml
commons/proper/io/trunk/src/main/java/org/apache/commons/io/input/Tailer.java
Modified: commons/proper/io/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/changes/changes.xml?rev=1345279&r1=1345278&r2=1345279&view=diff
==============================================================================
--- commons/proper/io/trunk/src/changes/changes.xml (original)
+++ commons/proper/io/trunk/src/changes/changes.xml Fri Jun 1 17:27:21 2012
@@ -47,6 +47,9 @@ The <action> type attribute can be add,u
<body>
<!-- The release date is the date RC is cut -->
<release version="2.4" date="2012-TDB-TDB" description="">
+ <action issue="IO-332" dev="ggregory" type="fix" due-to="liangly">
+ Improve tailer's reading performance.
+ </action>
<action issue="IO-329" dev="ggregory" type="fix" due-to="tivv">
FileUtils.writeLines uses unbuffered IO.
</action>
Modified: commons/proper/io/trunk/src/main/java/org/apache/commons/io/input/Tailer.java
URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/main/java/org/apache/commons/io/input/Tailer.java?rev=1345279&r1=1345278&r2=1345279&view=diff
==============================================================================
--- commons/proper/io/trunk/src/main/java/org/apache/commons/io/input/Tailer.java (original)
+++ commons/proper/io/trunk/src/main/java/org/apache/commons/io/input/Tailer.java Fri Jun 1 17:27:21 2012
@@ -106,6 +106,15 @@ import org.apache.commons.io.IOUtils;
*/
public class Tailer implements Runnable {
+ private static final String RAF_MODE = "r";
+
+ private static final int DEFAULT_BUFSIZE = 4096;
+
+ /**
+ * Buffer on top of RandomAccessFile.
+ */
+ private byte inbuf[];
+
/**
* The file which will be tailed.
*/
@@ -158,16 +167,30 @@ public class Tailer implements Runnable
* @param end Set to true to tail from the end of the file, false to tail from the beginning of the file.
*/
public Tailer(File file, TailerListener listener, long delay, boolean end) {
+ this(file, listener, delay, end, DEFAULT_BUFSIZE);
+ }
+
+ /**
+ * Creates a Tailer for the given file, with a specified buffer size.
+ * @param file the file to follow.
+ * @param listener the TailerListener to use.
+ * @param delay the delay between checks of the file for new content in milliseconds.
+ * @param end Set to true to tail from the end of the file, false to tail from the beginning of the file.
+ * @param bufSize Buffer size
+ */
+ public Tailer(File file, TailerListener listener, long delay, boolean end, int bufSize) {
this.file = file;
this.delay = delay;
this.end = end;
+
+ this.inbuf = new byte[bufSize];
// Save and prepare the listener
this.listener = listener;
listener.init(this);
}
-
+
/**
* Creates and starts a Tailer for the given file.
*
@@ -175,10 +198,11 @@ public class Tailer implements Runnable
* @param listener the TailerListener to use.
* @param delay the delay between checks of the file for new content in milliseconds.
* @param end Set to true to tail from the end of the file, false to tail from the beginning of the file.
+ * @param buffer size.
* @return The new tailer
*/
- public static Tailer create(File file, TailerListener listener, long delay, boolean end) {
- Tailer tailer = new Tailer(file, listener, delay, end);
+ public static Tailer create(File file, TailerListener listener, long delay, boolean end, int bufSize) {
+ Tailer tailer = new Tailer(file, listener, delay, end, bufSize);
Thread thread = new Thread(tailer);
thread.setDaemon(true);
thread.start();
@@ -186,6 +210,19 @@ public class Tailer implements Runnable
}
/**
+ * Creates and starts a Tailer for the given file with default buffer size.
+ *
+ * @param file the file to follow.
+ * @param listener the TailerListener to use.
+ * @param delay the delay between checks of the file for new content in milliseconds.
+ * @param end Set to true to tail from the end of the file, false to tail from the beginning of the file.
+ * @return The new tailer
+ */
+ public static Tailer create(File file, TailerListener listener, long delay, boolean end) {
+ return create(file, listener, delay, end, DEFAULT_BUFSIZE);
+ }
+
+ /**
* Creates and starts a Tailer for the given file, starting at the beginning of the file
*
* @param file the file to follow.
@@ -238,7 +275,7 @@ public class Tailer implements Runnable
// Open the file
while (run && reader == null) {
try {
- reader = new RandomAccessFile(file, "r");
+ reader = new RandomAccessFile(file, RAF_MODE);
} catch (FileNotFoundException e) {
listener.fileNotFound();
}
@@ -252,11 +289,10 @@ public class Tailer implements Runnable
// The current position in the file
position = end ? file.length() : 0;
last = System.currentTimeMillis();
- reader.seek(position);
+ reader.seek(position);
}
}
-
while (run) {
// Check the file length to see if it was rotated
@@ -271,7 +307,7 @@ public class Tailer implements Runnable
try {
// Ensure that the old file is closed iff we re-open it successfully
RandomAccessFile save = reader;
- reader = new RandomAccessFile(file, "r");
+ reader = new RandomAccessFile(file, RAF_MODE);
position = 0;
// close old file explicitly rather than relying on GC picking up previous RAF
IOUtils.closeQuietly(save);
@@ -293,9 +329,9 @@ public class Tailer implements Runnable
} else if (FileUtils.isFileNewer(file, last)) {
- /* This can happen if the file is truncated or overwritten
- * with the exact same length of information. In cases like
- * this, the file position needs to be reset
+ /*
+ * This can happen if the file is truncated or overwritten with the exact same length of
+ * information. In cases like this, the file position needs to be reset
*/
position = 0;
reader.seek(position); // cannot be null here
@@ -335,31 +371,22 @@ public class Tailer implements Runnable
* @throws java.io.IOException if an I/O error occurs.
*/
private long readLines(RandomAccessFile reader) throws IOException {
+ StringBuilder sb = new StringBuilder();
+
long pos = reader.getFilePointer();
- String line = readLine(reader);
- while (line != null) {
- pos = reader.getFilePointer();
- listener.handle(line);
- line = readLine(reader);
- }
- reader.seek(pos); // Ensure we can re-read if necessary
- return pos;
- }
+ long rePos = pos; // position to re-read
- /**
- * Version of readline() that returns null on EOF rather than a partial line.
- * @param reader the input file
- * @return the line, or null if EOF reached before '\n' is seen.
- * @throws IOException if an error occurs.
- */
- private String readLine(RandomAccessFile reader) throws IOException {
- StringBuffer sb = new StringBuffer();
- int ch;
+ int num;
boolean seenCR = false;
- while((ch=reader.read()) != -1) {
- switch(ch) {
+ while (run && ((num = reader.read(inbuf)) != -1)) {
+ for (int i = 0; i < num; i++) {
+ byte ch = inbuf[i];
+ switch (ch) {
case '\n':
- return sb.toString();
+ listener.handle(sb.toString());
+ sb = new StringBuilder();
+ rePos = pos + i + 1;
+ break;
case '\r':
seenCR = true;
break;
@@ -368,9 +395,15 @@ public class Tailer implements Runnable
sb.append('\r');
seenCR = false;
}
- sb.append((char)ch); // add character, not its ascii value
+ sb.append((char) ch); // add character, not its ascii value
+ }
}
+
+ pos = reader.getFilePointer();
}
- return null;
+
+ reader.seek(rePos); // Ensure we can re-read if necessary
+ return rePos;
}
+
}