/** * 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.blur.store.blockcache_v2; import java.io.IOException; import org.apache.blur.store.buffer.BufferStore; import org.apache.blur.store.buffer.Store; import org.apache.lucene.store.Directory; import org.apache.lucene.store.IOContext; import org.apache.lucene.store.IndexOutput; public class CacheIndexOutput extends IndexOutput { private final IndexOutput _indexOutput; private final Cache _cache; private final String _fileName; private final CacheDirectory _directory; private final long _fileId; private final int _fileBufferSize; private final int _cacheBlockSize; private final Store _store; private long _position; private byte[] _buffer; private int _bufferPosition; public CacheIndexOutput(CacheDirectory directory, String fileName, Cache cache, Directory dir, IOContext context) throws IOException { _cache = cache; _directory = directory; _fileName = fileName; _fileBufferSize = _cache.getFileBufferSize(_directory, _fileName); _cacheBlockSize = _cache.getCacheBlockSize(_directory, _fileName); _fileId = _cache.getFileId(_directory, _fileName); _indexOutput = dir.createOutput(fileName, context); _store = BufferStore.instance(_cacheBlockSize); _buffer = _store.takeBuffer(_cacheBlockSize); } @Override public void setLength(long length) throws IOException { } @Override public void writeByte(byte b) throws IOException { tryToFlush(); _buffer[_bufferPosition] = b; _bufferPosition++; _position++; } @Override public void writeBytes(byte[] b, int offset, int len) throws IOException { while (len > 0) { tryToFlush(); int remaining = remaining(); int length = Math.min(len, remaining); System.arraycopy(b, offset, _buffer, _bufferPosition, length); _bufferPosition += length; _position += length; len -= length; offset += length; } } private int remaining() { return _cacheBlockSize - _bufferPosition; } private void tryToFlush() throws IOException { if (remaining() == 0) { flushInternal(); } } private void flushInternal() throws IOException { final int length = _cacheBlockSize - remaining(); if (length == 0) { return; } CacheValue cacheValue = _cache.newInstance(_directory, _fileName); cacheValue.write(0, _buffer, 0, length); long blockId = (_position - length) / _cacheBlockSize; cacheValue = cacheValue.trim(length); _cache.put(_directory, _fileName, new CacheKey(_fileId, blockId), cacheValue); _bufferPosition = 0; writeBufferToOutputStream(length); } private void writeBufferToOutputStream(int len) throws IOException { int offset = 0; while (len > 0) { int length = Math.min(_fileBufferSize, len); _indexOutput.writeBytes(_buffer, offset, length); len -= length; offset += length; } } @Override public void seek(long pos) throws IOException { throw new IOException("Seek is not supported."); } @Override public void close() throws IOException { flushInternal(); _indexOutput.flush(); _indexOutput.close(); _store.putBuffer(_buffer); _cache.fileClosedForWriting(_directory, _fileName, _fileId); } @Override public void flush() throws IOException { } @Override public long getFilePointer() { return _position; } @Override public long length() throws IOException { return getFilePointer(); } }