/* * Copyright 2004-2009 the original author or authors. * * Licensed 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.lucene.store.jdbc.index; import java.io.IOException; import org.apache.lucene.store.IndexOutput; import org.apache.lucene.store.jdbc.JdbcDirectory; import org.apache.lucene.store.jdbc.JdbcFileEntrySettings; /** * An <code>IndexOutput</code> implementation that initially writes the data to a memory buffer. Once it exceeds * the configured threshold ({@link #INDEX_OUTPUT_THRESHOLD_SETTING}, will start working with a temporary file, * releasing the previous buffer. * * @author kimchy */ public class RAMAndFileJdbcIndexOutput extends IndexOutput implements JdbcIndexConfigurable { /** * The threshold setting name. See {@link JdbcFileEntrySettings#setLongSetting(String, long)}. * Should be set in bytes. */ public static final String INDEX_OUTPUT_THRESHOLD_SETTING = "indexOutput.threshold"; /** * The default value for the threshold (in bytes). Currently 16K. */ public static final long DEFAULT_THRESHOLD = 16 * 1024; private long threshold; private RAMJdbcIndexOutput ramIndexOutput; private FileJdbcIndexOutput fileIndexOutput; private JdbcDirectory jdbcDirectory; private String name; private JdbcFileEntrySettings settings; private long position; public void configure(String name, JdbcDirectory jdbcDirectory, JdbcFileEntrySettings settings) throws IOException { this.jdbcDirectory = jdbcDirectory; this.name = name; this.settings = settings; this.threshold = settings.getSettingAsLong(INDEX_OUTPUT_THRESHOLD_SETTING, DEFAULT_THRESHOLD); ramIndexOutput = createRamJdbcIndexOutput(); ramIndexOutput.configure(name, jdbcDirectory, settings); } public void writeByte(byte b) throws IOException { switchIfNeeded(1).writeByte(b); } public void writeBytes(byte[] b, int offset, int length) throws IOException { switchIfNeeded(length).writeBytes(b, offset, length); } public void flush() throws IOException { actualOutput().flush(); } public void close() throws IOException { actualOutput().close(); } public long getFilePointer() { return actualOutput().getFilePointer(); } public void seek(long pos) throws IOException { position = pos; actualOutput().seek(pos); } public long length() throws IOException { return actualOutput().length(); } private IndexOutput actualOutput() { if (fileIndexOutput != null) { return fileIndexOutput; } return ramIndexOutput; } private IndexOutput switchIfNeeded(int length) throws IOException { if (fileIndexOutput != null) { return fileIndexOutput; } position += length; if (position < threshold) { return ramIndexOutput; } fileIndexOutput = createFileJdbcIndexOutput(); fileIndexOutput.configure(name, jdbcDirectory, settings); ramIndexOutput.flushToIndexOutput(fileIndexOutput); // let it be garbage collected ramIndexOutput = null; return fileIndexOutput; } protected FileJdbcIndexOutput createFileJdbcIndexOutput() { return new FileJdbcIndexOutput(); } protected RAMJdbcIndexOutput createRamJdbcIndexOutput() { return new RAMJdbcIndexOutput(); } }