Update of /cvsroot/cweb/bigdata/src/java/com/bigdata/objndx In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv5433/src/java/com/bigdata/objndx Modified Files: IndexSegmentMerger.java BTreeMetadata.java BTree.java IFusedView.java Added Files: ReadOnlyFusedView.java Removed Files: FusedView.java Log Message: Continued minor refactoring in line with model updates. Index: BTree.java =================================================================== RCS file: /cvsroot/cweb/bigdata/src/java/com/bigdata/objndx/BTree.java,v retrieving revision 1.36 retrieving revision 1.37 diff -C2 -d -r1.36 -r1.37 *** BTree.java 6 Mar 2007 20:38:05 -0000 1.36 --- BTree.java 11 Mar 2007 11:41:45 -0000 1.37 *************** *** 47,50 **** --- 47,52 ---- package com.bigdata.objndx; + import java.lang.reflect.Constructor; + import com.bigdata.cache.HardReferenceQueue; import com.bigdata.journal.ICommitter; *************** *** 645,648 **** --- 647,695 ---- /** + * Re-load the {@link BTree} or derived class from the store. The + * {@link BTree} or derived class MUST provide a public constructor with the + * following signature: <code> + * + * <i>className</i>(IRawStore store, BTreeMetadata metadata) + * + * </code> + * + * @param store + * The store. + * @param addr + * The address of the {@link BTreeMetadata} record for that + * class. + * + * @return The {@link BTree} or derived class loaded from that + * {@link BTreeMetadata} record. + * + * @see BTree#newMetadata(), which MUST be overloaded if you subclass + * {@link BTreeMetadata} in order to store extended metadata. + */ + public static BTree load(IRawStore store, long addr) { + + BTreeMetadata metadata = BTreeMetadata.read(store, addr); + + try { + + Class cl = Class.forName(metadata.className); + + Constructor ctor = cl.getConstructor(new Class[] { + IRawStore.class, BTreeMetadata.class }); + + BTree btree = (BTree) ctor.newInstance(new Object[] { store, + metadata }); + + return btree; + + } catch(Exception ex) { + + throw new RuntimeException(ex); + + } + + } + + /** * Factory for mutable nodes and leaves used by the {@link NodeSerializer}. */ Index: BTreeMetadata.java =================================================================== RCS file: /cvsroot/cweb/bigdata/src/java/com/bigdata/objndx/BTreeMetadata.java,v retrieving revision 1.12 retrieving revision 1.13 diff -C2 -d -r1.12 -r1.13 *** BTreeMetadata.java 8 Mar 2007 18:14:05 -0000 1.12 --- BTreeMetadata.java 11 Mar 2007 11:41:44 -0000 1.13 *************** *** 3,7 **** import java.io.Externalizable; import java.io.Serializable; - import java.lang.reflect.Constructor; import java.nio.ByteBuffer; --- 3,6 ---- *************** *** 140,148 **** * @return the metadata record. * ! * @see #load(IRawStore, long), which will load the btree not just the ! * {@link BTreeMetadata}. ! * ! * @todo review remaining uses of this method vs ! * {@link #load(IRawStore, long)}. */ public static BTreeMetadata read(IRawStore store, long addr) { --- 139,144 ---- * @return the metadata record. * ! * @see #load(IRawStore, long), which will load the {@link BTree} or derived ! * subclass not just the {@link BTreeMetadata}. */ public static BTreeMetadata read(IRawStore store, long addr) { *************** *** 153,267 **** /** - * Re-load the {@link BTree} or derived class from the store. The - * {@link BTree} or derived class MUST provide a public constructor with the - * following signature: <code> - * - * <i>className</i>(IRawStore store, BTreeMetadata metadata) - * - * </code> - * - * @param store - * The store. - * @param addr - * The address of the {@link BTreeMetadata} record for that - * class. - * - * @return The {@link BTree} or derived class loaded from that - * {@link BTreeMetadata} record. - * - * @see BTree#newMetadata(), which MUST be overloaded if you subclass - * {@link BTreeMetadata}. - */ - public static BTree load(IRawStore store, long addr) { - - BTreeMetadata metadata = read(store, addr); - - try { - - Class cl = Class.forName(metadata.className); - - Constructor ctor = cl.getConstructor(new Class[] { - IRawStore.class, BTreeMetadata.class }); - - BTree btree = (BTree) ctor.newInstance(new Object[] { store, - metadata }); - - return btree; - - } catch(Exception ex) { - - throw new RuntimeException(ex); - - } - - } - - // /** - // * Write out the metadata record for the btree on the store and return the - // * {@link Addr address}. - // * - // * @return The address of the metadata record. - // */ - // protected long write(IRawStore store) { - // - // ByteBuffer buf = ByteBuffer.allocate(SIZEOF_METADATA); - // - // buf.putLong(addrRoot); - // buf.putInt(branchingFactor); - // buf.putInt(height); - // buf.putInt(nnodes); - // buf.putInt(nleaves); - // buf.putInt(nentries); - // buf.putInt(keyType.intValue()); - // - // buf.flip(); // prepare for writing. - // - // } - - // /** - // * Read the persistent metadata record for the btree. - // * - // * @param addrMetadta - // * The address from which the metadata record will be read. - // * - // * @return The persistent identifier of the root of the btree. - // */ - // public BTreeMetadata(IRawStore store,long addrMetadata) { - // - // assert store != null; - // - // assert addrMetadata != 0L; - // - // this.addrMetadata = addrMetadata; - // - // ByteBuffer buf = store.read(addrMetadata,null); - // assert buf.position() == 0; - // assert buf.limit() == Addr.getByteCount(addrMetadata); - // - // addrRoot = buf.getLong(); - // - // branchingFactor = buf.getInt(); - // - // height = buf.getInt(); - // - // nnodes = buf.getInt(); - // - // nleaves = buf.getInt(); - // - // nentries = buf.getInt(); - // - // keyType = ArrayType.parseInt( buf.getInt() ); - // - // assert branchingFactor >= BTree.MIN_BRANCHING_FACTOR; - // assert height >= 0; - // assert nnodes >= 0; - // assert nleaves >= 0; - // assert nentries >= 0; - // - // BTree.log.info(toString()); - // - // } - - /** * A human readable representation of the metadata record. */ --- 149,152 ---- *************** *** 277,280 **** --- 162,170 ---- sb.append(", nentries=" + nentries); sb.append(", addrMetadata=" + Addr.toString(addrMetadata)); + sb.append(", valueSerializer=" + valueSer.getClass().getName()); + sb.append(", recordCompressor=" + + (recordCompressor == null ? null : recordCompressor + .getClass().getName())); + sb.append(", useChecksum=" + useChecksum); return sb.toString(); --- FusedView.java DELETED --- --- NEW FILE: ReadOnlyFusedView.java --- /** The Notice below must appear in each file of the Source Code of any copy you distribute of the Licensed Product. Contributors to any Modifications may add their own copyright notices to identify their own contributions. License: The contents of this file are subject to the CognitiveWeb Open Source License Version 1.1 (the License). You may not copy or use this file, in either source code or executable form, except in compliance with the License. You may obtain a copy of the License from http://www.CognitiveWeb.org/legal/license/ Software distributed under the License is distributed on an AS IS basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Copyrights: Portions created by or assigned to CognitiveWeb are Copyright (c) 2003-2003 CognitiveWeb. All Rights Reserved. Contact information for CognitiveWeb is available at http://www.CognitiveWeb.org Portions Copyright (c) 2002-2003 Bryan Thompson. Acknowledgements: Special thanks to the developers of the Jabber Open Source License 1.0 (JOSL), from which this License was derived. This License contains terms that differ from JOSL. Special thanks to the CognitiveWeb Open Source Contributors for their suggestions and support of the Cognitive Web. Modifications: */ /* * Created on Feb 1, 2007 */ package com.bigdata.objndx; import java.util.Arrays; import java.util.NoSuchElementException; /** * <p> * A fused view providing read-only operations on multiple B+-Trees mapping * variable length unsigned byte[] keys to arbitrary values. * </p> * * @author <a href="mailto:tho...@us...">Bryan Thompson</a> * @version $Id$ * * @todo support N sources for a {@link ReadOnlyFusedView} by chaining together multiple * {@link ReadOnlyFusedView} instances if not in a more efficient manner. */ public class ReadOnlyFusedView implements IIndex, IFusedView { /** * Holds the various btrees that are the sources for the view. */ public final AbstractBTree[] srcs; public AbstractBTree[] getSources() { return srcs; } public ReadOnlyFusedView(AbstractBTree src1, AbstractBTree src2) { this(new AbstractBTree[] { src1, src2 }); } /** * * @param srcs * The ordered sources for the fused view. The order of the * elements in this array determines which value will be selected * for a given key by lookup() and which value is retained by * rangeQuery(). */ public ReadOnlyFusedView(final AbstractBTree[] srcs) { if (srcs == null) throw new IllegalArgumentException("sources is null"); if (srcs.length < 2) { throw new IllegalArgumentException( "at least two sources are required"); } if(srcs.length>2) { // @todo generalize to N>2 sources. throw new UnsupportedOperationException( "Only two sources are supported."); } for( int i=0; i<srcs.length; i++) { if (srcs[i] == null) throw new IllegalArgumentException("a source is null"); for(int j=0; j<i; j++) { if (srcs[i] == srcs[j]) throw new IllegalArgumentException( "source used more than once"); } } this.srcs = srcs.clone(); } /** * Write operations are not supported on the view. */ public void insert(BatchInsert op) { throw new UnsupportedOperationException(); } /** * Write operations are not supported on the view. */ public void remove(BatchRemove op) { throw new UnsupportedOperationException(); } public Object insert(Object key, Object value) { throw new UnsupportedOperationException(); } public Object remove(Object key) { throw new UnsupportedOperationException(); } /** * Return the first value for the key in an ordered search of the trees in * the view. */ public Object lookup(Object key) { for( int i=0; i<srcs.length; i++) { Object ret = srcs[i].lookup(key); if (ret != null) return ret; } return null; } /** * Returns true if any tree in the view has an entry for the key. */ public boolean contains(byte[] key) { for( int i=0; i<srcs.length; i++) { if (srcs[i].contains(key)) return true; } return false; } /** * @todo implement and write test of chained lookup operations. the * challenge here is that we only want the first value for a * given key. this seems to require that we mark tuples to * be ignored on subsequent indices, which in turn needs to * get into the batch api. the contains() method already has * been modified to finesse this. */ public void lookup(BatchLookup op) { throw new UnsupportedOperationException(); } public void contains( BatchContains op ) { for( int i=0; i<srcs.length; i++) { AbstractBTree src = srcs[i]; // reset the first tuple index for each pass. op.tupleIndex = 0; src.contains(op); } } /** * Returns the sum of the range count on each index in the view. This is the * maximum #of entries that could lie within that key range. However, the * actual number could be less if there are entries for the same key in more * than one source index. * * @todo this could be done using concurrent threads. */ public int rangeCount(byte[] fromKey, byte[] toKey) { int count = 0; for(int i=0; i<srcs.length; i++) { count += srcs[i].rangeCount(fromKey, toKey); } return count; } /** * Returns an iterator that visits the distinct entries. When an entry * appears in more than one index, the entry is choosen based on the order * in which the indices were declared to the constructor. */ public IEntryIterator rangeIterator(byte[] fromKey, byte[] toKey) { return new FusedEntryIterator(srcs, fromKey, toKey); } /** * Helper class merges entries from the sources in the view. * * @author <a href="mailto:tho...@us...">Bryan Thompson</a> * @version $Id$ */ protected static class FusedEntryIterator implements IEntryIterator { private final AbstractBTree[] srcs; // private final byte[] fromKey; // private final byte[] toKey; private final IEntryIterator[] itrs; // private final boolean[] available; private final boolean[] exhausted; /** * The current key from each source and null if we need to get the next * key from that source. */ private final byte[][] keys; /** * Index of the iterator that returned the last value and -1 if no * iterator has returned a value yet. */ private int current = -1; public FusedEntryIterator(AbstractBTree[] srcs,byte[] fromKey, byte[] toKey) { assert srcs != null; assert srcs.length > 0; this.srcs = srcs; // this.fromKey = fromKey; // // this.toKey = toKey; itrs = new IEntryIterator[srcs.length]; for( int i=0; i<itrs.length; i++) { itrs[i] = srcs[i].rangeIterator(fromKey, toKey); } // available = new boolean[srcs.length]; // // Arrays.fill(available,true); keys = new byte[itrs.length][]; exhausted = new boolean[srcs.length]; Arrays.fill(exhausted,false); } public byte[] getKey() { if(current == -1) throw new IllegalStateException(); return itrs[current].getKey(); } public Object getValue() { if(current == -1) throw new IllegalStateException(); return itrs[current].getValue(); } public boolean hasNext() { // @todo this could use advanceKeyStreams() instead. for( int i=0; i<itrs.length; i++ ) { if (!exhausted[i] && keys[i]!= null || itrs[i].hasNext()) { return true; } } return false; } /** * Make sure that we have the current key for each key stream. If we * already have a key for that stream then we use it. * * @return The #of key streams with an available key in {@link #keys}. * When zero(0), all key streams are exhausted. */ private int advanceKeyStreams() { // #of key streams with a key for us to examine. int navailable = 0; for(int i=0; i<itrs.length; i++) { if (exhausted[i]) continue; if (keys[i] == null) { if (itrs[i].hasNext()) { itrs[i].next(); keys[i] = itrs[i].getKey(); navailable++; } else { exhausted[i] = true; } } else { navailable++; } } return navailable; } /** * We are presented with an ordered set of key streams. Each key stream * delivers its keys in order. For a given key, we always choose the * first stream having that key. Once a key is found, all subsequent key * streams are then advanced until their next key is greater than the * current key (this can only cause the same key to be skipped). * <p> * * Each invocation of this method advances one key in the union of the * key streams. We test the current key for each stream on each pass and * choose the key that orders first across all key streams. * <p> * * In the simple case with two streams we examine the current * {@link #keys key} on each stream, fetching the next key iff there is * no key available on that stream and otherwise using the current key * from that stream. If the keys are the same, then we choose the first * stream and also clear the current {@link #keys key} for the other * stream so that we will skip the current entry on that key stream. If * the keys differ, then we choose the stream with the lessor key and * clear the {@link #keys key} for that stream to indicate that it has * been consumed. In any case we set the index of the choosen stream on * {@link #current} so that the other methods on this api will use the * corresponding key and value from that stream and return the current * value for the choosen stream. * * @todo generalize to N>2 key streams. */ public Object next() { assert srcs.length == 2; int navailable = advanceKeyStreams(); if(navailable == 0) { throw new NoSuchElementException(); } /* * Generalization to N streams might sort {key,order,itr} tuples. * The choice of the stream with the lessor key is then the first * entry in sorted tuples if the comparator pays attention to the * stream [order] in addition to the keys. * * if a stream is exhausted then we no longer consider it as a key * source. */ final int cmp = (keys[0] == null ? 1 : keys[1] == null ? -1 : BytesUtil.compareBytes(keys[0], keys[1])); if( cmp == 0 ) { // Choose the first stream in a tie. current = 0; // The current key on each stream tied in 1st place is consumed. keys[0] = keys[1] = null; } else { // Choose the stream with the lessor key. current = cmp < 0 ? 0 : 1; keys[current] = null; // this key was consumed. } // Return the current object on the choosen stream. Object value = itrs[current].getValue(); return value; } public void remove() { throw new UnsupportedOperationException(); } } } Index: IFusedView.java =================================================================== RCS file: /cvsroot/cweb/bigdata/src/java/com/bigdata/objndx/IFusedView.java,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** IFusedView.java 6 Mar 2007 20:38:05 -0000 1.1 --- IFusedView.java 11 Mar 2007 11:42:34 -0000 1.2 *************** *** 56,60 **** * @version $Id$ */ ! public interface IFusedView { } --- 56,65 ---- * @version $Id$ */ ! public interface IFusedView extends IIndex { + /** + * Return the ordered array of sources from which the fused view is reading. + */ + public AbstractBTree[] getSources(); + } Index: IndexSegmentMerger.java =================================================================== RCS file: /cvsroot/cweb/bigdata/src/java/com/bigdata/objndx/IndexSegmentMerger.java,v retrieving revision 1.10 retrieving revision 1.11 diff -C2 -d -r1.10 -r1.11 *** IndexSegmentMerger.java 6 Mar 2007 20:38:05 -0000 1.10 --- IndexSegmentMerger.java 11 Mar 2007 11:41:44 -0000 1.11 *************** *** 85,89 **** * well. * ! * @see {@link FusedView}, which provides a dynamic view of two or more btrees. * However, this class is more efficient when we are going to do a bulk * merge operation since it performs the merge and computes the #of output --- 85,89 ---- * well. * ! * @see {@link ReadOnlyFusedView}, which provides a dynamic view of two or more btrees. * However, this class is more efficient when we are going to do a bulk * merge operation since it performs the merge and computes the #of output |