blob: d862539e9f4031f202fe8a7103f5e397228a7a33 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.solr.store.blockcache;
import java.io.IOException;
import org.apache.lucene.store.IndexOutput;
/**
* @lucene.experimental
*/
public abstract class ReusedBufferedIndexOutput extends IndexOutput {
public static final int BUFFER_SIZE = 1024;
private int bufferSize = BUFFER_SIZE;
protected byte[] buffer;
/** position in the file of buffer */
private long bufferStart = 0;
/** end of valid bytes */
private int bufferLength = 0;
/** next byte to write */
private int bufferPosition = 0;
/** total length of the file */
private long fileLength = 0;
private final Store store;
public ReusedBufferedIndexOutput(String resourceDescription, String name) {
this(resourceDescription, name, BUFFER_SIZE);
}
public ReusedBufferedIndexOutput(String resourceDescription, String name, int bufferSize) {
super(resourceDescription, name);
checkBufferSize(bufferSize);
this.bufferSize = bufferSize;
store = BufferStore.instance(bufferSize);
buffer = store.takeBuffer(this.bufferSize);
}
protected long getBufferStart() {
return bufferStart;
}
private void checkBufferSize(int bufferSize) {
if (bufferSize <= 0) throw new IllegalArgumentException(
"bufferSize must be greater than 0 (got " + bufferSize + ")");
}
/** Write the buffered bytes to cache */
protected void flushBufferToCache() throws IOException {
writeInternal(buffer, 0, bufferLength);
bufferStart += bufferLength;
bufferLength = 0;
bufferPosition = 0;
}
protected abstract void closeInternal() throws IOException;
@Override
public void close() throws IOException {
flushBufferToCache();
closeInternal();
store.putBuffer(buffer);
buffer = null;
}
@Override
public long getFilePointer() {
return bufferStart + bufferPosition;
}
@Override
public void writeByte(byte b) throws IOException {
if (bufferPosition >= bufferSize) {
flushBufferToCache();
}
if (getFilePointer() >= fileLength) {
fileLength++;
}
buffer[bufferPosition++] = b;
if (bufferPosition > bufferLength) {
bufferLength = bufferPosition;
}
}
/**
* Expert: implements buffer flushing to cache. Writes bytes to the current
* position in the output.
*
* @param b
* the array of bytes to write
* @param offset
* the offset in the array of bytes to write
* @param length
* the number of bytes to write
*/
protected abstract void writeInternal(byte[] b, int offset, int length)
throws IOException;
@Override
public void writeBytes(byte[] b, int offset, int length) throws IOException {
if (getFilePointer() + length > fileLength) {
fileLength = getFilePointer() + length;
}
if (length <= bufferSize - bufferPosition) {
// the buffer contains enough space to satisfy this request
if (length > 0) { // to allow b to be null if len is 0...
System.arraycopy(b, offset, buffer, bufferPosition, length);
}
bufferPosition += length;
if (bufferPosition > bufferLength) {
bufferLength = bufferPosition;
}
} else {
// the buffer does not have enough space. First buffer all we've got.
int available = bufferSize - bufferPosition;
if (available > 0) {
System.arraycopy(b, offset, buffer, bufferPosition, available);
offset += available;
length -= available;
bufferPosition = bufferSize;
bufferLength = bufferSize;
}
flushBufferToCache();
// and now, write the remaining 'length' bytes:
if (length < bufferSize) {
// If the amount left to write is small enough do it in the usual
// buffered way:
System.arraycopy(b, offset, buffer, 0, length);
bufferPosition = length;
bufferLength = length;
} else {
// The amount left to write is larger than the buffer
// there's no performance reason not to write it all
// at once.
writeInternal(b, offset, length);
bufferStart += length;
bufferPosition = 0;
bufferLength = 0;
}
}
}
}