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 java.io.IOException;
25  import java.lang.reflect.Array;
26  import java.util.ArrayList;
27  import java.util.Iterator;
28  import java.util.List;
29  
30  import org.apache.directory.mavibot.btree.serializer.ElementSerializer;
31  
32  
33  /**
34   * A BTree builder that builds a tree from the bottom.
35   *
36   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
37   */
38  public class InMemoryBTreeBuilder<K, V>
39  {
40      private String name;
41  
42      private int numKeysInNode;
43  
44      private ElementSerializer<K> keySerializer;
45  
46      private ElementSerializer<V> valueSerializer;
47  
48  
49      public InMemoryBTreeBuilder( String name, int numKeysInNode, ElementSerializer<K> keySerializer,
50          ElementSerializer<V> valueSerializer )
51      {
52          this.name = name;
53          this.numKeysInNode = numKeysInNode;
54          this.keySerializer = keySerializer;
55          this.valueSerializer = valueSerializer;
56      }
57  
58  
59      @SuppressWarnings("unchecked")
60      public BTree<K, V> build( Iterator<Tuple<K, V>> sortedTupleItr ) throws IOException
61      {
62          BTree<K, V> btree = BTreeFactory.createInMemoryBTree( name, keySerializer, valueSerializer );
63  
64          List<Page<K, V>> lstLeaves = new ArrayList<Page<K, V>>();
65  
66          int totalTupleCount = 0;
67  
68          InMemoryLeaf<K, V> leaf1 = ( InMemoryLeaf<K, V> ) BTreeFactory.createLeaf( btree, 0, numKeysInNode );
69          lstLeaves.add( leaf1 );
70  
71          int leafIndex = 0;
72  
73          while ( sortedTupleItr.hasNext() )
74          {
75              Tuple<K, V> tuple = sortedTupleItr.next();
76  
77              BTreeFactory.setKey( btree, leaf1, leafIndex, tuple.getKey() );
78  
79              InMemoryValueHolder<V> eh = new InMemoryValueHolder<V>( btree, tuple.getValue() );
80  
81              BTreeFactory.setValue( btree, leaf1, leafIndex, eh );
82  
83              leafIndex++;
84              totalTupleCount++;
85  
86              if ( ( totalTupleCount % numKeysInNode ) == 0 )
87              {
88                  leafIndex = 0;
89                  leaf1 = ( InMemoryLeaf<K, V> ) BTreeFactory.createLeaf( btree, 0, numKeysInNode );
90                  lstLeaves.add( leaf1 );
91              }
92          }
93  
94          if ( lstLeaves.isEmpty() )
95          {
96              return btree;
97          }
98  
99          // remove null keys and values from the last leaf and resize
100         InMemoryLeaf<K, V> lastLeaf = ( InMemoryLeaf<K, V> ) lstLeaves.get( lstLeaves.size() - 1 );
101 
102         for ( int i = 0; i < lastLeaf.getNbElems(); i++ )
103         {
104             if ( lastLeaf.getKeys()[i] == null )
105             {
106                 int n = i;
107                 lastLeaf.setNbElems( n );
108                 KeyHolder<K>[] keys = lastLeaf.getKeys();
109 
110                 lastLeaf.setKeys( ( KeyHolder[] ) Array.newInstance( KeyHolder.class, n ) );
111                 System.arraycopy( keys, 0, lastLeaf.getKeys(), 0, n );
112 
113                 ValueHolder<V>[] values = lastLeaf.values;
114                 lastLeaf.values = ( InMemoryValueHolder<V>[] ) Array.newInstance( InMemoryValueHolder.class, n );
115                 System.arraycopy( values, 0, lastLeaf.values, 0, n );
116 
117                 break;
118             }
119         }
120 
121         Page<K, V> rootPage = attachNodes( lstLeaves, btree );
122 
123         System.out.println( "built rootpage : " + rootPage );
124 
125         ( ( AbstractBTree<K, V> ) btree ).setRootPage( rootPage );
126 
127         return btree;
128     }
129 
130 
131     @SuppressWarnings("unchecked")
132     private Page<K, V> attachNodes( List<Page<K, V>> children, BTree<K, V> 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         InMemoryNode<K, V> node = ( InMemoryNode<K, V> ) BTreeFactory.createNode( btree, 0, numKeysInNode );
144         lstNodes.add( node );
145         int i = 0;
146         int totalNodes = 0;
147 
148         for ( Page<K, V> p : children )
149         {
150             if ( i != 0 )
151             {
152                 BTreeFactory.setKey( btree, node, i - 1, p.getLeftMostKey() );
153             }
154 
155             node.setPageHolder( i, new PageHolder<K, V>( btree, p ) );
156 
157             i++;
158             totalNodes++;
159 
160             if ( ( totalNodes % numChildren ) == 0 )
161             {
162                 i = 0;
163                 node = ( InMemoryNode<K, V> ) BTreeFactory.createNode( btree, 0, numKeysInNode );
164                 lstNodes.add( node );
165             }
166         }
167 
168         // remove null keys and values from the last node and resize
169         AbstractPage<K, V> lastNode = ( AbstractPage<K, V> ) lstNodes.get( lstNodes.size() - 1 );
170 
171         for ( int j = 0; j < lastNode.getNbElems(); j++ )
172         {
173             if ( lastNode.getKey( j ) == null )
174             {
175                 int n = j;
176                 lastNode.setNbElems( n );
177                 KeyHolder<K>[] keys = lastNode.getKeys();
178 
179                 lastNode.setKeys( ( KeyHolder[] ) Array.newInstance( KeyHolder.class, n ) );
180                 System.arraycopy( keys, 0, lastNode.getKeys(), 0, n );
181 
182                 break;
183             }
184         }
185 
186         return attachNodes( lstNodes, btree );
187     }
188 }