View Javadoc

1   /*
2    *   Licensed to the Apache Software Foundation (ASF) under one
3    *   or more contributor license agreements.  See the NOTICE file
4    *   distributed with this work for additional information
5    *   regarding copyright ownership.  The ASF licenses this file
6    *   to you under the Apache License, Version 2.0 (the
7    *   "License"); you may not use this file except in compliance
8    *   with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *   Unless required by applicable law or agreed to in writing,
13   *   software distributed under the License is distributed on an
14   *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *   KIND, either express or implied.  See the License for the
16   *   specific language governing permissions and limitations
17   *   under the License.
18   *
19   */
20  
21  package org.apache.directory.mavibot.btree.managed;
22  
23  
24  import static org.apache.directory.mavibot.btree.managed.BTreeFactory.createLeaf;
25  import static org.apache.directory.mavibot.btree.managed.BTreeFactory.createNode;
26  import static org.apache.directory.mavibot.btree.managed.BTreeFactory.setKey;
27  import static org.apache.directory.mavibot.btree.managed.BTreeFactory.setValue;
28  
29  import java.io.IOException;
30  import java.lang.reflect.Array;
31  import java.util.ArrayList;
32  import java.util.Iterator;
33  import java.util.List;
34  
35  import org.apache.directory.mavibot.btree.Tuple;
36  import org.apache.directory.mavibot.btree.serializer.ElementSerializer;
37  
38  
39  /**
40   * A BTree builder that builds a tree from the bottom.
41   *
42   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
43   */
44  public class BTreeBuilder<K, V>
45  {
46      private String name;
47  
48      private int numKeysInNode;
49  
50      private ElementSerializer<K> keySerializer;
51  
52      private ElementSerializer<V> valueSerializer;
53  
54  
55      public BTreeBuilder( String name, int numKeysInNode, ElementSerializer<K> keySerializer,
56          ElementSerializer<V> valueSerializer )
57      {
58          this.name = name;
59          this.numKeysInNode = numKeysInNode;
60          this.keySerializer = keySerializer;
61          this.valueSerializer = valueSerializer;
62      }
63  
64  
65      @SuppressWarnings("unchecked")
66      public BTree<K, V> build( Iterator<Tuple<K, V>> sortedTupleItr ) throws IOException
67      {
68          BTree<K, V> btree = new BTree<K, V>( name, keySerializer, valueSerializer );
69          btree.init();
70  
71          List<Page<K, V>> lstLeaves = new ArrayList<Page<K, V>>();
72  
73          int totalTupleCount = 0;
74  
75          Leaf<K, V> leaf1 = createLeaf( btree, 0, numKeysInNode );
76          lstLeaves.add( leaf1 );
77  
78          int leafIndex = 0;
79  
80          while ( sortedTupleItr.hasNext() )
81          {
82              Tuple<K, V> tuple = sortedTupleItr.next();
83  
84              setKey( leaf1, leafIndex, tuple.getKey() );
85  
86              ValueHolder<V> eh = new ValueHolder<V>( btree.getRecordManager(), btree.getValueSerializer(),
87                  tuple.getValue() );
88  
89              setValue( leaf1, leafIndex, eh );
90  
91              leafIndex++;
92              totalTupleCount++;
93              if ( ( totalTupleCount % numKeysInNode ) == 0 )
94              {
95                  leafIndex = 0;
96                  leaf1 = createLeaf( btree, 0, numKeysInNode );
97                  lstLeaves.add( leaf1 );
98              }
99          }
100 
101         if ( lstLeaves.isEmpty() )
102         {
103             return btree;
104         }
105 
106         // remove null keys and values from the last leaf and resize
107         Leaf<K, V> lastLeaf = ( Leaf<K, V> ) lstLeaves.get( lstLeaves.size() - 1 );
108         for ( int i = 0; i < lastLeaf.nbElems; i++ )
109         {
110             if ( lastLeaf.keys[i] == null )
111             {
112                 int n = i;
113                 lastLeaf.nbElems = n;
114                 KeyHolder<K>[] keys = lastLeaf.keys;
115 
116                 lastLeaf.keys = ( KeyHolder[] ) Array.newInstance( KeyHolder.class, n );
117                 System.arraycopy( keys, 0, lastLeaf.keys, 0, n );
118 
119                 ValueHolder<V>[] values = lastLeaf.values;
120                 lastLeaf.values = ( ValueHolder<V>[] ) Array.newInstance( ValueHolder.class, n );
121                 System.arraycopy( values, 0, lastLeaf.values, 0, n );
122 
123                 break;
124             }
125         }
126 
127         Page<K, V> rootPage = attachNodes( lstLeaves, btree );
128 
129         btree.rootPage = rootPage;
130 
131         return btree;
132     }
133 
134 
135     @SuppressWarnings("unchecked")
136     private Page<K, V> attachNodes( List<Page<K, V>> children, BTree<K, V> btree ) throws IOException
137     {
138         if ( children.size() == 1 )
139         {
140             return children.get( 0 );
141         }
142 
143         List<Page<K, V>> lstNodes = new ArrayList<Page<K, V>>();
144 
145         int numChildren = numKeysInNode + 1;
146 
147         Node<K, V> node = createNode( btree, 0, numKeysInNode );
148         lstNodes.add( node );
149         int i = 0;
150         int totalNodes = 0;
151 
152         for ( Page<K, V> p : children )
153         {
154             if ( i != 0 )
155             {
156                 setKey( node, i - 1, p.getLeftMostKey() );
157             }
158 
159             node.children[i] = btree.createPageHolder( p );
160 
161             i++;
162             totalNodes++;
163 
164             if ( ( totalNodes % numChildren ) == 0 )
165             {
166                 i = 0;
167                 node = createNode( btree, 0, numKeysInNode );
168                 lstNodes.add( node );
169             }
170         }
171 
172         // remove null keys and values from the last node and resize
173         AbstractPage<K, V> lastNode = ( AbstractPage<K, V> ) lstNodes.get( lstNodes.size() - 1 );
174 
175         for ( int j = 0; j < lastNode.nbElems; j++ )
176         {
177             if ( lastNode.keys[j] == null )
178             {
179                 int n = j;
180                 lastNode.nbElems = n;
181                 KeyHolder<K>[] keys = lastNode.keys;
182 
183                 lastNode.keys = ( KeyHolder[] ) Array.newInstance( KeyHolder.class, n );
184                 System.arraycopy( keys, 0, lastNode.keys, 0, n );
185 
186                 break;
187             }
188         }
189 
190         return attachNodes( lstNodes, btree );
191     }
192 }