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;
22  
23  
24  import static org.apache.directory.mavibot.btree.BTreeFactory.createLeaf;
25  import static org.apache.directory.mavibot.btree.BTreeFactory.createNode;
26  import static org.apache.directory.mavibot.btree.BTreeFactory.setKey;
27  import static org.apache.directory.mavibot.btree.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.serializer.ElementSerializer;
36  
37  
38  /**
39   * A BTree builder that builds a tree from the bottom.
40   *
41   * @author <a href="mailto:labs@labs.apache.org">Mavibot labs Project</a>
42   */
43  public class BTreeBuilder<K, V>
44  {
45      private String name;
46  
47      private int numKeysInNode;
48  
49      private ElementSerializer<K> keySerializer;
50  
51      private ElementSerializer<V> valueSerializer;
52  
53  
54      public BTreeBuilder( String name, int numKeysInNode, ElementSerializer<K> keySerializer,
55          ElementSerializer<V> valueSerializer )
56      {
57          this.name = name;
58          this.numKeysInNode = numKeysInNode;
59          this.keySerializer = keySerializer;
60          this.valueSerializer = valueSerializer;
61      }
62  
63  
64      public BTree<K, V> build( Iterator<Tuple<K, V>> sortedTupleItr ) throws IOException
65      {
66          BTree<K, V> btree = new BTree<K, V>( name, keySerializer, valueSerializer );
67          btree.init();
68  
69          List<Page<K, V>> lstLeaves = new ArrayList<Page<K, V>>();
70  
71          int totalTupleCount = 0;
72  
73          Leaf<K, V> leaf1 = createLeaf( btree, 0, numKeysInNode );
74          lstLeaves.add( leaf1 );
75  
76          int leafIndex = 0;
77          while ( sortedTupleItr.hasNext() )
78          {
79              Tuple<K, V> tuple = sortedTupleItr.next();
80  
81              setKey( leaf1, leafIndex, tuple.getKey() );
82  
83              MemoryHolder<K, V> eh = new MemoryHolder<K, V>( btree, tuple.getValue() );
84  
85              setValue( leaf1, leafIndex, eh );
86  
87              leafIndex++;
88              totalTupleCount++;
89              if ( ( totalTupleCount % numKeysInNode ) == 0 )
90              {
91                  leafIndex = 0;
92                  leaf1 = createLeaf( btree, 0, numKeysInNode );
93                  lstLeaves.add( leaf1 );
94              }
95          }
96  
97          if ( lstLeaves.isEmpty() )
98          {
99              return btree;
100         }
101 
102         // remove null keys and values from the last leaf and resize
103         Leaf<K, V> lastLeaf = ( Leaf<K, V> ) lstLeaves.get( lstLeaves.size() - 1 );
104         for ( int i = 0; i < lastLeaf.nbElems; i++ )
105         {
106             if ( lastLeaf.keys[i] == null )
107             {
108                 int n = i;
109                 lastLeaf.nbElems = n;
110                 K[] keys = lastLeaf.keys;
111 
112                 Class<?> keyType = btree.getKeyType();
113                 lastLeaf.keys = ( K[] ) Array.newInstance( keyType, n );
114                 System.arraycopy( keys, 0, lastLeaf.keys, 0, n );
115 
116                 ElementHolder<V, K, V>[] values = lastLeaf.values;
117                 lastLeaf.values = ( MemoryHolder<K, V>[] ) Array.newInstance( MemoryHolder.class, n );
118                 System.arraycopy( values, 0, lastLeaf.values, 0, n );
119 
120                 break;
121             }
122         }
123 
124         Page<K, V> rootPage = attachNodes( lstLeaves, btree );
125 
126         btree.rootPage = rootPage;
127 
128         return btree;
129     }
130 
131 
132     private Page<K, V> attachNodes( List<Page<K, V>> children, BTree btree ) throws IOException
133     {
134         if ( children.size() == 1 )
135         {
136             return children.get( 0 );
137         }
138 
139         List<Page<K, V>> lstNodes = new ArrayList<Page<K, V>>();
140 
141         int numChildren = numKeysInNode + 1;
142 
143         Node<K, V> node = createNode( btree, 0, numKeysInNode );
144         lstNodes.add( node );
145         int i = 0;
146         int totalNodes = 0;
147         for ( Page<K, V> p : children )
148         {
149             if ( i != 0 )
150             {
151                 setKey( node, i-1, p.getLeftMostKey() );
152             }
153 
154             node.children[i] = btree.createHolder( p );
155 
156             i++;
157             totalNodes++;
158 
159             if ( ( totalNodes % numChildren ) == 0 )
160             {
161                 i = 0;
162                 node = createNode( btree, 0, numKeysInNode );
163                 lstNodes.add( node );
164             }
165         }
166 
167         // remove null keys and values from the last node and resize
168         AbstractPage<K, V> lastNode = ( AbstractPage<K, V> ) lstNodes.get( lstNodes.size() - 1 );
169         for ( int j = 0; j < lastNode.nbElems; j++ )
170         {
171             if ( lastNode.keys[j] == null )
172             {
173                 int n = j;
174                 lastNode.nbElems = n;
175                 K[] keys = lastNode.keys;
176 
177                 Class<?> keyType = btree.getKeyType();
178                 lastNode.keys = ( K[] ) Array.newInstance( keyType, n );
179                 System.arraycopy( keys, 0, lastNode.keys, 0, n );
180 
181                 break;
182             }
183         }
184 
185         return attachNodes( lstNodes, btree );
186     }
187 }