Fix for LUCENE-435: Optimize BufferedIndexOutput.writeBytes(). Contributed by Lukas Zapletal.

git-svn-id: https://svn.apache.org/repos/asf/lucene/java/trunk@379532 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Doug Cutting 2006-02-21 17:00:40 +00:00
parent 2b686b68aa
commit 7c09d17565
4 changed files with 87 additions and 29 deletions

View File

@ -2,6 +2,15 @@ Lucene Change Log
$Id$ $Id$
1.9 RC2
Optimizations
1. Optimized BufferedIndexOutput.writeBytes() to use
System.arraycopy() in more cases, rather than copying byte-by-byte.
(Lukas Zapletal via Cutting)
1.9 RC1 1.9 RC1
Note that this realease is mostly but not 100% source compatible with the Note that this realease is mostly but not 100% source compatible with the

View File

@ -41,8 +41,41 @@ public abstract class BufferedIndexOutput extends IndexOutput {
* @see IndexInput#readBytes(byte[],int,int) * @see IndexInput#readBytes(byte[],int,int)
*/ */
public void writeBytes(byte[] b, int length) throws IOException { public void writeBytes(byte[] b, int length) throws IOException {
for (int i = 0; i < length; i++) int bytesLeft = BUFFER_SIZE - bufferPosition;
writeByte(b[i]); // 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 {
// is data larger then buffer?
if (length > BUFFER_SIZE) {
// we flush the buffer
if (bufferPosition > 0)
flush();
// and write data at once
flushBuffer(b, length);
} 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. */ /** Forces any buffered output to be written. */

View File

@ -66,27 +66,27 @@ public class RAMOutputStream extends BufferedIndexOutput {
} }
public void flushBuffer(byte[] src, int len) { public void flushBuffer(byte[] src, int len) {
int bufferNumber = pointer/BUFFER_SIZE; byte[] buffer;
int bufferOffset = pointer%BUFFER_SIZE; int bufferPos = 0;
int bytesInBuffer = BUFFER_SIZE - bufferOffset; while (bufferPos != len) {
int bytesToCopy = bytesInBuffer >= len ? len : bytesInBuffer; int bufferNumber = pointer/BUFFER_SIZE;
int bufferOffset = pointer%BUFFER_SIZE;
int bytesInBuffer = BUFFER_SIZE - bufferOffset;
int remainInSrcBuffer = len - bufferPos;
int bytesToCopy = bytesInBuffer >= remainInSrcBuffer ? remainInSrcBuffer : bytesInBuffer;
if (bufferNumber == file.buffers.size()) if (bufferNumber == file.buffers.size()) {
file.buffers.addElement(new byte[BUFFER_SIZE]); buffer = new byte[BUFFER_SIZE];
file.buffers.addElement(buffer);
} else {
buffer = (byte[]) file.buffers.elementAt(bufferNumber);
}
byte[] buffer = (byte[])file.buffers.elementAt(bufferNumber); System.arraycopy(src, bufferPos, buffer, bufferOffset, bytesToCopy);
System.arraycopy(src, 0, buffer, bufferOffset, bytesToCopy); bufferPos += bytesToCopy;
pointer += bytesToCopy;
if (bytesToCopy < len) { // not all in one buffer
int srcOffset = bytesToCopy;
bytesToCopy = len - bytesToCopy; // remaining bytes
bufferNumber++;
if (bufferNumber == file.buffers.size())
file.buffers.addElement(new byte[BUFFER_SIZE]);
buffer = (byte[])file.buffers.elementAt(bufferNumber);
System.arraycopy(src, srcOffset, buffer, 0, bytesToCopy);
} }
pointer += len;
if (pointer > file.length) if (pointer > file.length)
file.length = pointer; file.length = pointer;

View File

@ -28,14 +28,13 @@ import java.util.Random;
class StoreTest { class StoreTest {
public static void main(String[] args) { public static void main(String[] args) {
try { try {
test(1000, true); test(1000, true, true);
} catch (Exception e) { } catch (Exception e) {
System.out.println(" caught a " + e.getClass() + e.printStackTrace();
"\n with message: " + e.getMessage());
} }
} }
public static void test(int count, boolean ram) public static void test(int count, boolean ram, boolean buffered)
throws Exception { throws Exception {
Random gen = new Random(1251971); Random gen = new Random(1251971);
int i; int i;
@ -51,6 +50,8 @@ class StoreTest {
final int LENGTH_MASK = 0xFFF; final int LENGTH_MASK = 0xFFF;
final byte[] buffer = new byte[LENGTH_MASK];
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
String name = i + ".dat"; String name = i + ".dat";
int length = gen.nextInt() & LENGTH_MASK; int length = gen.nextInt() & LENGTH_MASK;
@ -59,8 +60,14 @@ class StoreTest {
IndexOutput file = store.createOutput(name); IndexOutput file = store.createOutput(name);
for (int j = 0; j < length; j++) if (buffered) {
file.writeByte(b); 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(); file.close();
} }
@ -89,9 +96,18 @@ class StoreTest {
if (file.length() != length) if (file.length() != length)
throw new Exception("length incorrect"); throw new Exception("length incorrect");
for (int j = 0; j < length; j++) byte[] content = new byte[length];
if (file.readByte() != b) if (buffered) {
throw new Exception("contents incorrect"); 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(); file.close();
} }