| /* |
| * 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; |
| |
| /** |
| * Cache the blocks as they are written. The cache file name is the name of |
| * the file until the file is closed, at which point the cache is updated |
| * to include the last modified date (which is unknown until that point). |
| * @lucene.experimental |
| */ |
| public class CachedIndexOutput extends ReusedBufferedIndexOutput { |
| private final BlockDirectory directory; |
| private final IndexOutput dest; |
| private final int blockSize; |
| private final String name; |
| private final String location; |
| private final Cache cache; |
| |
| public CachedIndexOutput(BlockDirectory directory, IndexOutput dest, |
| int blockSize, String name, Cache cache, int bufferSize) { |
| super("dest=" + dest + " name=" + name, name, bufferSize); |
| this.directory = directory; |
| this.dest = dest; |
| this.blockSize = blockSize; |
| this.name = name; |
| this.location = directory.getFileCacheLocation(name); |
| this.cache = cache; |
| } |
| |
| @Override |
| public void closeInternal() throws IOException { |
| dest.close(); |
| cache.renameCacheFile(location, directory.getFileCacheName(name)); |
| } |
| |
| private int writeBlock(long position, byte[] b, int offset, int length) |
| throws IOException { |
| // read whole block into cache and then provide needed data |
| long blockId = BlockDirectory.getBlock(position); |
| int blockOffset = (int) BlockDirectory.getPosition(position); |
| int lengthToWriteInBlock = Math.min(length, blockSize - blockOffset); |
| |
| // write the file and copy into the cache |
| dest.writeBytes(b, offset, lengthToWriteInBlock); |
| cache.update(location, blockId, blockOffset, b, offset, |
| lengthToWriteInBlock); |
| |
| return lengthToWriteInBlock; |
| } |
| |
| @Override |
| public void writeInternal(byte[] b, int offset, int length) |
| throws IOException { |
| long position = getBufferStart(); |
| while (length > 0) { |
| int len = writeBlock(position, b, offset, length); |
| position += len; |
| length -= len; |
| offset += len; |
| } |
| } |
| |
| @Override |
| public long getChecksum() throws IOException { |
| flushBufferToCache(); |
| return dest.getChecksum(); |
| } |
| } |