> I don't in general disagree with this sort of optimization, but I think 
> a good fix is a bit more complicated than what you posted.

Hi Doug, I had some time to redo my fixes...

> This forces a flush() each time a byte array of any size is written. 
> That could be much slower when lots of small byte arrays are written, 
> since flush() invokes a system call.  What would be best is, if there is 

Yes, I made a better version in an exact way you have described above.
The patch replaces writeBytes method with the whole new implementation:

  public void writeBytes(byte[] b, int length) throws IOException {
    int bytesLeft = BUFFER_SIZE - bufferPosition;
    // is there enough space in the buffer?
    if (bytesLeft >= length) {
      // we add the data to the end of the buffer
      System.arraycopy(b, 0, buffer, bufferPosition, length);
      bufferPosition += length;
      // if the buffer is full, flush it
      if (BUFFER_SIZE - bufferPosition == 0)
        flush();
    } else {
      // we fill/flush the buffer (until the input is written)
      int pos = 0; // position in the input data
      int pieceLength;
      while (pos < length) {
        pieceLength = (length - pos < bytesLeft) ? 
                length - pos : bytesLeft; 
        System.arraycopy(b, pos, buffer, 
                bufferPosition, pieceLength); 
        pos += pieceLength;
        bufferPosition += pieceLength;
        // if the buffer is full, flush it
        bytesLeft = BUFFER_SIZE - bufferPosition;
        if (bytesLeft == 0) {
          flush();
          bytesLeft = BUFFER_SIZE;
        }
      }
    }
  }

This is much smarter and it is not slow for lots of one-byte writes. I
agree with the assession of my "fix" of readBytes:

> Again, this could be much slower when lots of small arrays are written, 
> since each call forces seek and read system calls.  However this could 
> be optimized for the case where the desired data resides entirely in the 
> current buffer to use System.arraycopy.

So I tried to optimize the reads from buffer, but the method was so
complicated I dropped this thought. Readbytes is fast enough.

I have modified the StoreTest, now you can test the *byte or *bytes
methods (3rd parameter). Because of creating and testing the buffers,
there is not speed improvement here but when you write from some
prepared buffer (e.g. from a file), the speed increases.

-- 
S pozdravem / Best regards
Lukas Zapletal
sefredaktor / editor-in-chief
LinuxEXPRES - opravdovy linuxovy magazin
www.LinuxEXPRES.cz
tel.:+420 777 003 843
Index: src/test/org/apache/lucene/StoreTest.java
===================================================================
--- src/test/org/apache/lucene/StoreTest.java	(revision 290385)
+++ src/test/org/apache/lucene/StoreTest.java	(working copy)
@@ -28,14 +28,13 @@
 class StoreTest {
   public static void main(String[] args) {
     try {
-      test(1000, true);
+      test(1000, true, true);
     } catch (Exception e) {
-      System.out.println(" caught a " + e.getClass() +
-			 "\n with message: " + e.getMessage());
+		e.printStackTrace();
     }
   }
 
-  public static void test(int count, boolean ram)
+  public static void test(int count, boolean ram, boolean buffered)
        throws Exception {
     Random gen = new Random(1251971);
     int i;
@@ -51,6 +50,8 @@
 
     final int LENGTH_MASK = 0xFFF;
 
+	final byte[] buffer = new byte[LENGTH_MASK];
+
     for (i = 0; i < count; i++) {
       String name = i + ".dat";
       int length = gen.nextInt() & LENGTH_MASK;
@@ -59,8 +60,14 @@
 
       IndexOutput file = store.createOutput(name);
 
-      for (int j = 0; j < length; j++)
-	file.writeByte(b);
+      if (buffered) {
+        for (int j = 0; j < length; j++)
+          buffer[j] = b;
+        file.writeBytes(buffer, length);
+      } else {
+        for (int j = 0; j < length; j++)
+          file.writeByte(b);
+      }
       
       file.close();
     }
@@ -89,9 +96,18 @@
       if (file.length() != length)
 	throw new Exception("length incorrect");
 
-      for (int j = 0; j < length; j++)
-	if (file.readByte() != b)
-	  throw new Exception("contents incorrect");
+      byte[] content = new byte[length];
+      if (buffered) {
+        file.readBytes(content, 0, length);
+        // check the buffer
+        for (int j = 0; j < length; j++)
+          if (content[j] != b)
+            throw new Exception("contents incorrect");
+      } else {
+        for (int j = 0; j < length; j++)
+          if (file.readByte() != b)
+            throw new Exception("contents incorrect");
+      }
 
       file.close();
     }
Index: src/java/org/apache/lucene/store/BufferedIndexOutput.java
===================================================================
--- src/java/org/apache/lucene/store/BufferedIndexOutput.java	(revision 290385)
+++ src/java/org/apache/lucene/store/BufferedIndexOutput.java	(working copy)
@@ -41,8 +41,32 @@
    * @see IndexInput#readBytes(byte[],int,int)
    */
   public void writeBytes(byte[] b, int length) throws IOException {
-    for (int i = 0; i < length; i++)
-      writeByte(b[i]);
+    int bytesLeft = BUFFER_SIZE - bufferPosition;
+    // is there enough space in the buffer?
+    if (bytesLeft >= length) {
+      // we add the data to the end of the buffer
+      System.arraycopy(b, 0, buffer, bufferPosition, length);
+      bufferPosition += length;
+      // if the buffer is full, flush it
+      if (BUFFER_SIZE - bufferPosition == 0)
+        flush();
+    } else {
+      // we fill/flush the buffer (until the input is written)
+      int pos = 0; // position in the input data
+      int pieceLength;
+      while (pos < length) {
+        pieceLength = (length - pos < bytesLeft) ? length - pos : bytesLeft;
+        System.arraycopy(b, pos, buffer, bufferPosition, pieceLength);
+        pos += pieceLength;
+        bufferPosition += pieceLength;
+        // if the buffer is full, flush it
+        bytesLeft = BUFFER_SIZE - bufferPosition;
+        if (bytesLeft == 0) {
+          flush();
+          bytesLeft = BUFFER_SIZE;
+        }
+      }
+    }
   }
 
   /** Forces any buffered output to be written. */

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to