001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.fusesource.hawtdb.api;
018    
019    import org.fusesource.hawtbuf.codec.Codec;
020    import org.fusesource.hawtdb.internal.index.BTreeIndex;
021    import org.fusesource.hawtbuf.codec.ObjectCodec;
022    
023    import java.util.Comparator;
024    
025    /**
026     * This object is used to create variable magnitude b+tree indexes. 
027     * 
028     * A b+tree can be used for set or map-based indexing. Leaf
029     * nodes are linked together for faster iteration of the values.
030     * 
031     * <br>
032     * The variable magnitude attribute means that the b+tree attempts 
033     * to store as many values and pointers on one page as is possible.
034     * 
035     * <br>
036     * It will act as a simple-prefix b+tree if a prefixer is configured.
037     * 
038     * <br>
039     * In a simple-prefix b+tree, instead of promoting actual keys to branch pages, when
040     * leaves are split, a shortest-possible separator is generated at the pivot.
041     * That separator is what is promoted to the parent branch (and continuing up
042     * the list). As a result, actual keys and pointers can only be found at the
043     * leaf level. This also affords the index the ability to ignore costly merging
044     * and redistribution of pages when deletions occur. Deletions only affect leaf
045     * pages in this implementation, and so it is entirely possible for a leaf page
046     * to be completely empty after all of its keys have been removed.
047     * 
048     * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
049     */
050    public class BTreeIndexFactory<Key, Value> implements IndexFactory<Key, Value> {
051    
052        private Codec<Key> keyCodec = new ObjectCodec<Key>();
053        private Codec<Value> valueCodec = new ObjectCodec<Value>();
054        private boolean deferredEncoding=true;
055        private Prefixer<Key> prefixer;
056        private Comparator comparator = null;
057    
058        /**
059         * Creates a new BTree index on the Paged object.
060         */
061        public SortedIndex<Key, Value> create(Paged paged) {
062            BTreeIndex<Key, Value> index = createInstance(paged, paged.alloc());
063            index.create();
064            return index;
065        }
066        
067        @Override
068        public String toString() {
069            return "{ deferredEncoding: "+deferredEncoding+" }";
070        }
071        
072        /**
073         * Loads an existing BTree index from the paged object.
074         */
075        public SortedIndex<Key, Value> open(Paged paged, int indexNumber) {
076            return createInstance(paged, indexNumber);
077        }
078    
079        /**
080         * Loads an existing BTree index from the paged object.
081         */
082        public SortedIndex<Key, Value> open(Paged paged) {
083            return createInstance(paged, 0);
084        }
085    
086        private BTreeIndex<Key, Value> createInstance(Paged paged, int page) {
087            return new BTreeIndex<Key, Value>(paged, page, this);
088        }
089    
090        /**
091         * Defaults to an {@link org.fusesource.hawtbuf.codec.ObjectCodec} if not explicitly set.
092         * 
093         * @return the marshaller used for keys.
094         */
095        public Codec<Key> getKeyCodec() {
096            return keyCodec;
097        }
098    
099        /**
100         * Allows you to configure custom marshalling logic to encode the index keys.
101         * 
102         * @param codec the marshaller used for keys.
103         */
104        public void setKeyCodec(Codec<Key> codec) {
105            this.keyCodec = codec;
106        }
107    
108        /**
109         * Defaults to an {@link org.fusesource.hawtbuf.codec.ObjectCodec} if not explicitly set.
110         *  
111         * @return the marshaller used for values.
112         */
113        public Codec<Value> getValueCodec() {
114            return valueCodec;
115        }
116    
117        /**
118         * Allows you to configure custom marshalling logic to encode the index values.
119         * 
120         * @param codec the marshaller used for values
121         */
122        public void setValueCodec(Codec<Value> codec) {
123            this.valueCodec = codec;
124        }
125    
126        /**
127         * 
128         * @return true if deferred encoding enabled
129         */
130        public boolean isDeferredEncoding() {
131            return deferredEncoding;
132        }
133    
134        /**
135         * <p>
136         * When deferred encoding is enabled, the index avoids encoding keys and values
137         * for as long as possible so take advantage of collapsing multiple updates of the 
138         * same key/value into a single update operation and single encoding operation.
139         * </p><p>
140         * Using this feature requires the keys and values to be immutable objects since 
141         * unexpected errors would occur if they are changed after they have been handed
142         * to to the index for storage. 
143         * </p>
144         * @param enable should deferred encoding be enabled.
145         */
146        public void setDeferredEncoding(boolean enable) {
147            this.deferredEncoding = enable;
148        }
149    
150        public Prefixer<Key> getPrefixer() {
151            return prefixer;
152        }
153    
154        public void setPrefixer(Prefixer<Key> prefixer) {
155            this.prefixer = prefixer;
156        }
157    
158        /**
159         * Gets the custom configured Comparator used to sort the keys
160         * in the index.  Defaults to null.
161         * 
162         * @return
163         */
164        public Comparator getComparator() {
165            return comparator;
166        }
167    
168        /**
169         * Configures a custom Comparator used to sort the keys
170         * in the index.  If not set, the keys must implement the
171         * {@link Comparable} interface.
172         *
173         * @param comparator
174         */
175        public void setComparator(Comparator comparator) {
176            this.comparator = comparator;
177        }
178    }