Package org.fusesource.hawtdb.internal.index

Source Code of org.fusesource.hawtdb.internal.index.BTreeIndex$PageOverflowIOException

/**
* 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.fusesource.hawtdb.internal.index;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.fusesource.hawtbuf.codec.Codec;
import org.fusesource.hawtdb.api.*;
import org.fusesource.hawtdb.internal.index.BTreeNode.Data;
import org.fusesource.hawtdb.internal.page.Extent;
import org.fusesource.hawtbuf.Buffer;
import org.fusesource.hawtbuf.DataByteArrayInputStream;
import org.fusesource.hawtbuf.DataByteArrayOutputStream;


/**
* A variable magnitude b+tree indexes with support for optional
* simple-prefix optimization.
*
* @author <a href="http://hiramchirino.com">Hiram Chirino</a>
*/
public class BTreeIndex<Key, Value> implements SortedIndex<Key, Value> {

    private final BTreeNode.DataPagedAccessor<Key, Value> DATA_ENCODER_DECODER = new BTreeNode.DataPagedAccessor<Key, Value>(this);

    private final Paged paged;
    private final int page;
    private final Codec<Key> keyCodec;
    private final Codec<Value> valueCodec;
    private final Prefixer<Key> prefixer;
    private final boolean deferredEncoding;
    private final Comparator comparator;

    public BTreeIndex(Paged paged, int page, BTreeIndexFactory<Key, Value> factory) {
        this.paged = paged;
        this.page = page;
        this.keyCodec = factory.getKeyCodec();
        this.valueCodec = factory.getValueCodec();

        // Deferred encoding can only done if the keys and value sizes can be computed.
        this.deferredEncoding = factory.isDeferredEncoding() &&
                ( keyCodec.isEstimatedSizeSupported() || keyCodec.getFixedSize()>=0 ) &&
                ( valueCodec.isEstimatedSizeSupported() || valueCodec.getFixedSize()>=0 );

        this.prefixer = factory.getPrefixer();
        this.comparator = factory.getComparator();
    }
   
    @Override
    public String toString() {
        return "{ page: "+page+", deferredEncoding: "+deferredEncoding+" }";
    }
   
    public void create() {
        // Store the root page..
        BTreeNode<Key, Value> root = new BTreeNode<Key, Value>(null, page);
        storeNode(root);
    }

    public boolean containsKey(Key key) {
        return root().contains(this, key);
    }

    public Value get(Key key) {
        return root().get(this, key);
    }

    public Value put(Key key, Value value) {
        return root().put(this, key, value);
    }

    public Value putIfAbsent(Key key, Value value) {
        return root().putIfAbsent(this, key, value);
    }

    public Value remove(Key key) {
        return root().remove(this, key);
    }
   
    public int size() {
        return root().size(this);
    }

    public boolean isEmpty() {
        return root().isEmpty(this);
    }

    public void clear() {
        root().clear(this);
    }

    public int getMinLeafDepth() {
        return root().getMinLeafDepth(this, 0);
    }

    public int getMaxLeafDepth() {
        return root().getMaxLeafDepth(this, 0);
    }

    public void printStructure(PrintWriter out) {
        root().printStructure(this, out, "", "");
    }

    public void printStructure(OutputStream out) {
        PrintWriter pw = new PrintWriter(out, false);
        root().printStructure(this, pw, "", "");
        pw.flush();
    }

    public Iterator<Map.Entry<Key, Value>> iterator() {
        return root().iterator(this);
    }

    public Iterator<Map.Entry<Key, Value>> iterator(Predicate<Key> predicate) {
        return root().iterator(this, predicate);
    }

    public Iterator<Map.Entry<Key, Value>> iterator(final Key initialKey) {
        return root().iterator(this, initialKey);
    }

    public void visit(IndexVisitor<Key, Value> visitor) {
        root().visit(this, visitor);
    }

    public Map.Entry<Key, Value> getFirst() {
        return root().getFirst(this);
    }

    public Map.Entry<Key, Value> getLast() {
        return root().getLast(this);
    }

    // /////////////////////////////////////////////////////////////////
    // Internal implementation methods
    // /////////////////////////////////////////////////////////////////
    private BTreeNode<Key, Value> root() {
        return loadNode(null, page);
    }

    // /////////////////////////////////////////////////////////////////
    // Internal methods made accessible to BTreeNode
    // /////////////////////////////////////////////////////////////////
    BTreeNode<Key, Value> createNode(BTreeNode<Key, Value> parent, Data<Key, Value> data) {
        return new BTreeNode<Key, Value>(parent, paged.allocator().alloc(1), data);
    }
   
    BTreeNode<Key, Value> createNode(BTreeNode<Key, Value> parent) {
        return new BTreeNode<Key, Value>(parent, paged.allocator().alloc(1));
    }
   
    @SuppressWarnings("serial")
    static class PageOverflowIOException extends IndexException {
    }
   
    /**
     *
     * @param node
     * @return false if page overflow occurred
     */
    boolean storeNode(BTreeNode<Key, Value> node) {
        if (deferredEncoding) {
            int size = BTreeNode.estimatedSize(this, node.data);
            size += 9; // The extent header.
           
            if( !node.allowPageOverflow() && size>paged.getPageSize()) {
                return false;
            }

            paged.put(DATA_ENCODER_DECODER, node.getPage(), node.data);
            node.storedInExtent=true;
        } else {
           
            if( node.storedInExtent ) {
                DATA_ENCODER_DECODER.pagesLinked(paged, node.page);
            }
           
            if (node.isLeaf()) {
                List<Integer> pages = DATA_ENCODER_DECODER.store(paged, node.page, node.data);
                if( !node.allowPageOverflow() && pages.size()>1 ) {
                    DATA_ENCODER_DECODER.pagesLinked(paged, node.page);
                    node.storedInExtent=false;
                    return false;
                }
                node.storedInExtent=true;
            } else {
                DataByteArrayOutputStream os = new DataByteArrayOutputStream(paged.getPageSize()) {
                    protected void resize(int newcount) {
                        throw new PageOverflowIOException();
                    };
                };
                try {
                    BTreeNode.write(os, this, node.data);
                    paged.write(node.page, os.toBuffer());
                    node.storedInExtent=false;
                } catch (IOException e) {
                    throw new IndexException("Could not write btree node");
                } catch (PageOverflowIOException e) {
                    return false;
                }
            }
        }
        return true;
    }
   


    BTreeNode<Key, Value> loadNode(BTreeNode<Key, Value> parent, int page) {
        BTreeNode<Key, Value> node = new BTreeNode<Key, Value>(parent, page);
        if( deferredEncoding ) {
            node.data = paged.get(DATA_ENCODER_DECODER, page);
            node.storedInExtent=true;
        } else {
            Buffer buffer = new Buffer(paged.getPageSize());
            paged.read(page, buffer);
            if ( buffer.startsWith(Extent.DEFAULT_MAGIC) ) {
                // Page data was stored in an extent..
                node.data = DATA_ENCODER_DECODER.load(paged, page);
                node.storedInExtent=true;
            } else {
                // It was just in a plain page..
                DataByteArrayInputStream is = new DataByteArrayInputStream(buffer);
                try {
                    node.data = BTreeNode.read(is, this);
                    node.storedInExtent=false;
                } catch (IOException e) {
                    throw new IndexException("Could not read btree node");
                }
            }
        }
        return node;
    }
   
    void free( BTreeNode<Key, Value> node ) {
        if( deferredEncoding ) {
            paged.clear(DATA_ENCODER_DECODER, node.page);
        } else {
            if ( node.storedInExtent ) {
                DATA_ENCODER_DECODER.pagesLinked(paged, node.page);
            }
        }
        paged.free(node.page);
    }

    // /////////////////////////////////////////////////////////////////
    // Property Accessors
    // /////////////////////////////////////////////////////////////////

    public Paged getPaged() {
        return paged;
    }

    public int getIndexLocation() {
        return page;
    }

    public Codec<Key> getKeyMarshaller() {
        return keyCodec;
    }

    public Codec<Value> getValueMarshaller() {
        return valueCodec;
    }

    public Prefixer<Key> getPrefixer() {
        return prefixer;
    }

    public Comparator getComparator() {
        return comparator;
    }

    public void destroy() {
        clear();
        paged.free(page);
    }


}
TOP

Related Classes of org.fusesource.hawtdb.internal.index.BTreeIndex$PageOverflowIOException

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.