Index: lucene/core/src/java/org/apache/lucene/store/CachingRAMDirectory.java =================================================================== --- lucene/core/src/java/org/apache/lucene/store/CachingRAMDirectory.java (revision 0) +++ lucene/core/src/java/org/apache/lucene/store/CachingRAMDirectory.java (working copy) @@ -0,0 +1,191 @@ +package org.apache.lucene.store; + +/** + * 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. + */ + +import java.io.EOFException; +import java.io.IOException; +import java.util.Collection; +import java.util.concurrent.ConcurrentHashMap; + +// TODO +// - off heap alloc? native (unsafe) alloc? +// - we could segment the byte[] so we can handle > 2.1 GB +// files + +// nocommit back move to misc + +/** Wraps another directory but on opening an input fully + * loads the file's contents into a single byte[] and reads + * from that. This cannot handle files over ~2.1 GB! */ +public class CachingRAMDirectory extends Directory implements Cloneable { + private final Directory delegate; + + private final ConcurrentHashMap files = new ConcurrentHashMap(); + + public CachingRAMDirectory(Directory delegate) { + this.delegate = delegate; + this.lockFactory = delegate.getLockFactory(); + } + + // nocommit + public CachingRAMDirectory() { + this(new RAMDirectory()); + } + + @Override + public synchronized Lock makeLock(String name) { + return delegate.makeLock(name); + } + + @Override + public synchronized void clearLock(String name) throws IOException { + delegate.clearLock(name); + } + + @Override + public synchronized void setLockFactory(LockFactory lockFactory) throws IOException { + delegate.setLockFactory(lockFactory); + } + + @Override + public synchronized LockFactory getLockFactory() { + return delegate.getLockFactory(); + } + + @Override + public synchronized String getLockID() { + return delegate.getLockID(); + } + + @Override + public final String[] listAll() throws IOException { + return delegate.listAll(); + } + + @Override + public final boolean fileExists(String name) throws IOException { + return delegate.fileExists(name); + } + + @Override + public final long fileLength(String name) throws IOException { + return delegate.fileLength(name); + } + + @Override + public void deleteFile(String name) throws IOException { + files.remove(name); + delegate.deleteFile(name); + } + + @Override + public synchronized IndexOutput createOutput(String name, IOContext context) throws IOException { + // NOTE: Lucene doesn't normally double-write, but some + // tests do: + if (files.containsKey(name)) { + files.remove(name); + } + return delegate.createOutput(name, context); + } + + @Override + public void sync(Collection names) throws IOException { + delegate.sync(names); + } + + // TODO: createSlicer? + + @Override + public synchronized IndexInput openInput(String name, IOContext context) throws IOException { + if (name.startsWith("segments")) { + // Always open segments files from real directory, + // because Lucene relies on getting IOE if the + // segments file is not fully written yet: + return delegate.openInput(name, context); + } else if (!files.containsKey(name)) { + IndexInput in = delegate.openInput(name, context); + try { + files.put(name, new CachedIndexInput(name, delegate.fileLength(name), in)); + } finally { + in.close(); + } + } + return files.get(name).clone(); + } + + @Override + public void close() throws IOException { + delegate.close(); + files.clear(); + } + + // TODO: can we somehow merge w/ or extend ByteArrayDataInput? + private static final class CachedIndexInput extends IndexInput { + // NOTE: 2.1 GB limit!!! + private final byte[] bytes; + private int pos; + + public CachedIndexInput(String name, long length, IndexInput in) throws IOException { + super("CachedIndexInput(" + name + ")"); + if (length > Integer.MAX_VALUE) { + throw new IllegalStateException("cannot read file " + name + ": size (" + length + ") is over Integer.MAX_VALUE"); + } + bytes = new byte[(int) length]; + in.readBytes(bytes, 0, (int) length); + } + + @Override + public void close() { + // nothing to do here + } + + @Override + public long length() { + return bytes.length; + } + + @Override + public byte readByte() throws IOException { + try { + return bytes[pos++]; + } catch (ArrayIndexOutOfBoundsException aioobe) { + throw new EOFException("read past EOF: " + this); + } + } + + @Override + public void readBytes(byte[] b, int offset, int len) throws IOException { + try { + System.arraycopy(bytes, pos, b, offset, len); + } catch (ArrayIndexOutOfBoundsException aioobe) { + throw new EOFException("read past EOF: " + this); + } + pos += len; + } + + @Override + public long getFilePointer() { + return pos; + } + + @Override + public void seek(long pos) throws IOException { + this.pos = (int) pos; + } + } +} Property changes on: lucene/core/src/java/org/apache/lucene/store/CachingRAMDirectory.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property