/* * 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.ignite.internal.processors.query.h2.opt; import java.io.IOException; import org.apache.ignite.internal.util.offheap.unsafe.GridUnsafeMemory; import org.apache.lucene.store.DataInput; import org.apache.lucene.store.IndexOutput; /** * A memory-resident {@link IndexOutput} implementation. */ public class GridLuceneOutputStream extends IndexOutput { /** Off-heap page size. */ static final int BUFFER_SIZE = 32 * 1024; /** */ private GridLuceneFile file; /** */ private long currBuf; /** */ private int currBufIdx; /** */ private int bufPosition; /** */ private long bufStart; /** */ private int bufLength; /** */ private final GridUnsafeMemory mem; /** * Constructor. * * @param f File. */ public GridLuceneOutputStream(GridLuceneFile f) { file = f; mem = f.getDirectory().memory(); // make sure that we switch to the // first needed buffer lazily currBufIdx = -1; currBuf = 0; } /** * Resets this to an empty file. */ public void reset() { currBuf = 0; currBufIdx = -1; bufPosition = 0; bufStart = 0; bufLength = 0; file.setLength(0); } /** {@inheritDoc} */ @Override public void close() throws IOException { flush(); } /** {@inheritDoc} */ @Override public void seek(long pos) throws IOException { // set the file length in case we seek back // and flush() has not been called yet setFileLength(); if (pos < bufStart || pos >= bufStart + bufLength) { currBufIdx = (int)(pos / BUFFER_SIZE); switchCurrentBuffer(); } bufPosition = (int)(pos % BUFFER_SIZE); } /** {@inheritDoc} */ @Override public long length() { return file.getLength(); } /** {@inheritDoc} */ @Override public void writeByte(byte b) throws IOException { if (bufPosition == bufLength) { currBufIdx++; switchCurrentBuffer(); } mem.writeByte(currBuf + bufPosition++, b); } /** {@inheritDoc} */ @Override public void writeBytes(byte[] b, int offset, int len) throws IOException { assert b != null; while (len > 0) { if (bufPosition == bufLength) { currBufIdx++; switchCurrentBuffer(); } int remainInBuf = BUFFER_SIZE - bufPosition; int bytesToCp = len < remainInBuf ? len : remainInBuf; mem.writeBytes(currBuf + bufPosition, b, offset, bytesToCp); offset += bytesToCp; len -= bytesToCp; bufPosition += bytesToCp; } } /** * Switch buffer to next. */ private void switchCurrentBuffer() { currBuf = currBufIdx == file.numBuffers() ? file.addBuffer() : file.getBuffer(currBufIdx); bufPosition = 0; bufStart = (long)BUFFER_SIZE * (long)currBufIdx; bufLength = BUFFER_SIZE; } /** * Sets file length. */ private void setFileLength() { long pointer = bufStart + bufPosition; if (pointer > file.getLength()) file.setLength(pointer); } /** {@inheritDoc} */ @Override public void flush() throws IOException { setFileLength(); } /** {@inheritDoc} */ @Override public long getFilePointer() { return currBufIdx < 0 ? 0 : bufStart + bufPosition; } /** * Returns byte usage of all buffers. * * @return Bytes used. */ public long sizeInBytes() { return (long)file.numBuffers() * (long)BUFFER_SIZE; } /** {@inheritDoc} */ @Override public void copyBytes(DataInput input, long numBytes) throws IOException { assert numBytes >= 0 : "numBytes=" + numBytes; GridLuceneInputStream gridInput = input instanceof GridLuceneInputStream ? (GridLuceneInputStream)input : null; while (numBytes > 0) { if (bufPosition == bufLength) { currBufIdx++; switchCurrentBuffer(); } int toCp = BUFFER_SIZE - bufPosition; if (numBytes < toCp) toCp = (int)numBytes; if (gridInput != null) gridInput.readBytes(currBuf + bufPosition, toCp); else { byte[] buff = new byte[toCp]; input.readBytes(buff, 0, toCp, false); mem.writeBytes(currBuf + bufPosition, buff); } numBytes -= toCp; bufPosition += toCp; } } /** * For direct usage by {@link GridLuceneInputStream}. * * @param ptr Pointer. * @param len Length. * @throws IOException If failed. */ void writeBytes(long ptr, int len) throws IOException { while (len > 0) { if (bufPosition == bufLength) { currBufIdx++; switchCurrentBuffer(); } int remainInBuf = BUFFER_SIZE - bufPosition; int bytesToCp = len < remainInBuf ? len : remainInBuf; mem.copyMemory(ptr, currBuf + bufPosition, bytesToCp); ptr += bytesToCp; len -= bytesToCp; bufPosition += bytesToCp; } } }