All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bigdata.htree.data.DefaultDirectoryPageCoder Maven / Gradle / Ivy

/*

Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016.  All rights reserved.

Contact:
     SYSTAP, LLC DBA Blazegraph
     2501 Calvert ST NW #106
     Washington, DC 20008
     [email protected]

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
/*
 * Created on Aug 28, 2009
 */

package com.bigdata.htree.data;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

import com.bigdata.btree.data.AbstractReadOnlyNodeData;
import com.bigdata.btree.data.IAbstractNodeDataCoder;
import com.bigdata.io.AbstractFixedByteArrayBuffer;
import com.bigdata.io.DataOutputBuffer;
import com.bigdata.util.Bytes;

/**
 * Default implementation for immutable {@link IDirectoryData} records.
 * 
 * @author Bryan Thompson
 * @version $Id: DefaultNodeCoder.java 4585 2011-06-01 13:42:56Z thompsonbry $
 * 
 * TODO Support RWStore 4 byte native addrs.
 * 
 * TODO Explicit test suite based on the B+Tree test suites.
 */
public class DefaultDirectoryPageCoder implements IAbstractNodeDataCoder,
        Externalizable {

	/**
	 * The initial version of the serialized representation of the
	 * {@link DefaultDirectoryPageCoder} class (versus the serialized
	 * representation of the node or leaf).
	 */
    private final static transient byte VERSION0 = 0x00;
    
    public void readExternal(final ObjectInput in) throws IOException,
            ClassNotFoundException {

        final byte version = in.readByte();
        switch(version) {
        case VERSION0:
            break;
        default:
            throw new IOException();
        }
        
    }

    public void writeExternal(final ObjectOutput out) throws IOException {

        out.write(VERSION0);
        
    }

    /** No. */
    final public boolean isLeafDataCoder() {
        
        return false;
        
    }

    /** Yes. */
    public boolean isNodeDataCoder() {

        return true;
        
    }

//    public String toString() {
//
//        return super.toString() + "{keysCoder=" + keysCoder + "}";
//
//    }
    
    /**
     * De-serialization ctor.
     */
    public DefaultDirectoryPageCoder() {
        
    }
    
    public IDirectoryData decode(final AbstractFixedByteArrayBuffer data) {

        return new ReadOnlyDirectoryData(data);
        
    }

    public IDirectoryData encodeLive(final IDirectoryData node, final DataOutputBuffer buf) {

        if (node == null)
            throw new IllegalArgumentException();

        if (buf == null)
            throw new IllegalArgumentException();

        final short version = ReadOnlyDirectoryData.currentVersion;
        
        // The byte offset of the start of the coded data in the buffer.
        final int O_origin = buf.pos();
        
        buf.putByte(ReadOnlyDirectoryData.NODE);

        buf.putShort(version);

		final boolean hasVersionTimestamps = node.hasVersionTimestamps();
		short flags = 0;
		if (hasVersionTimestamps) {
			flags |= AbstractReadOnlyNodeData.FLAG_VERSION_TIMESTAMPS;
			throw new UnsupportedOperationException();
		}
		if(node.isOverflowDirectory()) {
		    flags |= AbstractReadOnlyNodeData.FLAG_OVERFLOW_DIRECTORY;
		}
        buf.putShort(flags);
        
        if (node.isOverflowDirectory()) {
            final byte[] ok = node.getOverflowKey();
        	buf.putShort((short) ok.length);
        	buf.put(ok);
        }
        
		final int nchildren = node.getChildCount();
		if (nchildren > Short.MAX_VALUE)
			throw new UnsupportedOperationException();
		buf.putShort((short) nchildren);

        // childAddr[] : TODO code childAddr[] (if RWSTORE bit is set, covert to 4 byte native addr).
        for (int i = 0; i < nchildren; i++) {
            buf.putLong(node.getChildAddr(i));
        }
        
        // Slice onto the coded data record.
        final AbstractFixedByteArrayBuffer slice = buf.slice(//
                O_origin, buf.pos() - O_origin);

        // Read-only coded IDataRecord. 
        return new ReadOnlyDirectoryData(slice);
        
    }

    public AbstractFixedByteArrayBuffer encode(final IDirectoryData node,
            final DataOutputBuffer buf) {

        return encodeLive(node, buf).data();

    }

    /**
     * A read-only view of the data for a B+Tree node.
     * 

* Note: The leading byte of the record format codes for a leaf, a double-linked * leaf or a node in a manner which is compatible with {@link ReadOnlyNodeData}. * * @author Bryan Thompson * @version $Id: DefaultNodeCoder.java 4585 2011-06-01 13:42:56Z thompsonbry $ */ static private class ReadOnlyDirectoryData extends AbstractReadOnlyNodeData implements IDirectoryData { /** The backing buffer */ private final AbstractFixedByteArrayBuffer b; /** The record serialization version. */ private final short version; // fields which are cached by the ctor. private final short flags; private final int nchildren; private final byte[] overflowKey; /** * Offset of the encoded childAddr[] in the buffer. */ private final int O_childAddr; final public AbstractFixedByteArrayBuffer data() { return b; } //static int s_newKeys = 0; /** * Constructor used when the caller is encoding the {@link IDirectoryData}. * * @param buf * The buffer containing the data for the node. * @param keys The coded keys. */ public ReadOnlyDirectoryData(final AbstractFixedByteArrayBuffer buf) { if (buf == null) throw new IllegalArgumentException(); int pos = O_TYPE; final byte type = buf.getByte(pos); pos += SIZEOF_TYPE; switch (type) { case NODE: break; case LEAF: throw new AssertionError(); case LINKED_LEAF: throw new AssertionError(); default: throw new AssertionError("type=" + type); } version = buf.getShort(pos); pos += SIZEOF_VERSION; switch (version) { case VERSION0: case VERSION1: break; default: throw new AssertionError("version=" + version); } // flags flags = buf.getShort(pos); pos += SIZEOF_FLAGS; if (isOverflowDirectory()) { final int oksze = buf.getShort(pos); pos += Bytes.SIZEOF_SHORT; overflowKey = new byte[oksze]; //s_newKeys++; buf.get(pos, overflowKey); pos += oksze; } else { overflowKey = null; } nchildren = buf.getShort(pos); pos += Bytes.SIZEOF_SHORT; O_childAddr = pos; // save reference to buffer this.b = buf; } final public boolean hasVersionTimestamps() { return ((flags & FLAG_VERSION_TIMESTAMPS) != 0); } final public long getMinimumVersionTimestamp() { if(!hasVersionTimestamps()) throw new UnsupportedOperationException(); // Note: version timestamps not yet supported by HTree. throw new UnsupportedOperationException(); } final public long getMaximumVersionTimestamp() { if(!hasVersionTimestamps()) throw new UnsupportedOperationException(); // Note: version timestamps not yet supported by HTree. throw new UnsupportedOperationException(); } final public boolean isOverflowDirectory() { return (flags & AbstractReadOnlyNodeData.FLAG_OVERFLOW_DIRECTORY) != 0; } /** * Always returns false. */ final public boolean isLeaf() { return false; } /** * Yes. */ final public boolean isReadOnly() { return true; } /** * Yes. */ final public boolean isCoded() { return true; } final public int getChildCount() { return nchildren; } /** * Bounds check. * * @throws IndexOutOfBoundsException * if index is LT ZERO (0) * @throws IndexOutOfBoundsException * if index is GT nkeys+1 */ protected boolean assertChildIndex(final int index) { if (index < 0 || index > nchildren) throw new IndexOutOfBoundsException("index=" + index + ", nchildren=" + nchildren); return true; } final public long getChildAddr(final int index) { assert assertChildIndex(index); return b.getLong(O_childAddr + index * SIZEOF_ADDR); } public String toString() { final StringBuilder sb = new StringBuilder(); sb.append(getClass().getName() + "{"); DefaultDirectoryPageCoder.toString(this, sb); sb.append("}"); return sb.toString(); } public byte[] getOverflowKey() { return overflowKey; } } /** * Utility method formats the {@link IDirectoryData}. * * @param node * A node data record. * @param sb * The representation will be written onto this object. * * @return The sb parameter. */ static public StringBuilder toString(final IDirectoryData node, final StringBuilder sb) { final int nchildren = node.getChildCount(); sb.append(", nchildren=" + nchildren); { sb.append(",\nchildAddr=["); for (int i = 0; i < nchildren; i++) { if (i > 0) sb.append(", "); sb.append(node.getChildAddr(i)); } sb.append("]"); } if(node.hasVersionTimestamps()) { sb.append(",\nversionTimestamps={min=" + node.getMinimumVersionTimestamp() + ",max=" + node.getMaximumVersionTimestamp() + "}"); } return sb; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy