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  package org.apache.directory.mavibot.btree;
21  
22  
23  import java.io.IOException;
24  import java.lang.reflect.Array;
25  import java.util.Comparator;
26  import java.util.UUID;
27  
28  import org.apache.directory.mavibot.btree.exception.BTreeOperationException;
29  import org.apache.directory.mavibot.btree.exception.EndOfFileExceededException;
30  import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
31  
32  
33  /**
34   * A holder to store the Values
35   *
36   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
37   * @param <V> The value type
38   */
39  /* No qualifier */class InMemoryValueHolder<V> extends AbstractValueHolder<V>
40  {
41      /**
42       * Creates a new instance of a ValueHolder, containing the serialized values.
43       *
44       * @param parentBtree the parent BTree
45       * @param valueSerializer The Value's serializer
46       * @param raw The raw data containing the values
47       * @param nbValues the number of stored values
48       * @param raw the byte[] containing either the serialized array of values or the sub-btree offset
49       */
50      InMemoryValueHolder( BTree<?, V> parentBtree, int nbValues )
51      {
52          valueSerializer = parentBtree.getValueSerializer();
53  
54          if ( nbValues <= 1 )
55          {
56              valueArray = ( V[] ) Array.newInstance( valueSerializer.getType(), nbValues );
57          }
58      }
59  
60  
61      /**
62       * Creates a new instance of a ValueHolder, containing Values. This constructor is called
63       * when we need to create a new ValueHolder with deserialized values.
64       *
65       * @param parentBtree The parent BTree
66       * @param values The Values stored in the ValueHolder
67       */
68      InMemoryValueHolder( BTree<?, V> parentBtree, V... values )
69      {
70          valueSerializer = parentBtree.getValueSerializer();
71  
72          if ( ( values != null ) && ( values.length > 0 ) )
73          {
74              int nbValues = values.length;
75  
76              if ( nbValues == 1 )
77              {
78                  // Store the value
79                  valueArray = ( V[] ) Array.newInstance( valueSerializer.getType(), nbValues );
80                  valueArray[0] = values[0];
81                  nbArrayElems = nbValues;
82              }
83              else
84              {
85                  // Use a sub btree, now that we have reached the threshold
86                  createSubTree();
87  
88                  // Now inject all the values into it
89                  for ( V value : values )
90                  {
91                      try
92                      {
93                          valueBtree.insert( value, value );
94                      }
95                      catch ( IOException e )
96                      {
97                          e.printStackTrace();
98                      }
99                  }
100             }
101         }
102     }
103 
104 
105     /**
106      * {@inheritDoc}
107      */
108     public int size()
109     {
110         if ( valueBtree != null )
111         {
112             return ( int ) valueBtree.getNbElems();
113         }
114         else
115         {
116             return nbArrayElems;
117         }
118     }
119 
120 
121     /**
122      * Create a new Sub-BTree to store the values.
123      */
124     protected void createSubTree()
125     {
126         InMemoryBTreeConfiguration<V, V> configuration = new InMemoryBTreeConfiguration<V, V>();
127         configuration.setAllowDuplicates( false );
128         configuration.setName( UUID.randomUUID().toString() );
129         configuration.setKeySerializer( valueSerializer );
130         configuration.setValueSerializer( valueSerializer );
131 
132         valueBtree = BTreeFactory.createInMemoryBTree( configuration );
133     }
134 
135 
136     /**
137      * Set the subBtree in the ValueHolder
138      */
139     /* No qualifier*/void setSubBtree( BTree<V, V> subBtree )
140     {
141         valueBtree = subBtree;
142         valueArray = null;
143     }
144 
145 
146     /**
147      * {@inheritDoc}
148      */
149     public V remove( V value )
150     {
151         V removedValue = null;
152 
153         if ( valueArray != null )
154         {
155             removedValue = removeFromArray( value );
156         }
157         else
158         {
159             removedValue = removeFromBtree( value );
160         }
161 
162         return removedValue;
163     }
164 
165 
166     /**
167      * Remove the value from a sub btree
168      */
169     private V removeFromBtree( V removedValue )
170     {
171         V returnedValue = null;
172 
173         try
174         {
175             Tuple<V, V> removedTuple = valueBtree.delete( removedValue );
176 
177             if ( removedTuple != null )
178             {
179                 returnedValue = removedTuple.getKey();
180             }
181         }
182         catch ( IOException e )
183         {
184             throw new BTreeOperationException( e );
185         }
186 
187         if ( valueBtree.getNbElems() == 1 )
188         {
189             try
190             {
191                 valueArray = ( V[] ) Array.newInstance( valueSerializer.getType(), 1 );
192                 valueArray[0] = valueBtree.browse().next().getKey();
193                 nbArrayElems = 1;
194                 valueBtree.close();
195                 valueBtree = null;
196             }
197             catch ( EndOfFileExceededException e )
198             {
199                 throw new BTreeOperationException( e );
200             }
201             catch ( IOException e )
202             {
203                 throw new BTreeOperationException( e );
204             }
205             catch ( KeyNotFoundException knfe )
206             {
207                 throw new BTreeOperationException( knfe );
208             }
209         }
210 
211         return returnedValue;
212     }
213 
214 
215     /**
216      * Remove a value from an array
217      */
218     private V removeFromArray( V value )
219     {
220         // First check that the value is not already present in the ValueHolder
221         Comparator<V> comparator = valueSerializer.getComparator();
222 
223         int result = comparator.compare( valueArray[0], value );
224 
225         if ( result != 0 )
226         {
227             // The value does not exists : nothing to do
228             return null;
229         }
230         else
231         {
232             V returnedValue = valueArray[0];
233             nbArrayElems = 0;
234 
235             return returnedValue;
236         }
237     }
238 
239 
240     /**
241      * {@inheritDoc}
242      */
243     public boolean contains( V checkedValue )
244     {
245         if ( valueBtree != null )
246         {
247             try
248             {
249                 return valueBtree.hasKey( checkedValue );
250             }
251             catch ( IOException e )
252             {
253                 // TODO Auto-generated catch block
254                 e.printStackTrace();
255                 return false;
256             }
257             catch ( KeyNotFoundException knfe )
258             {
259                 // TODO Auto-generated catch block
260                 knfe.printStackTrace();
261                 return false;
262             }
263         }
264         else
265         {
266             Comparator<V> comparator = valueSerializer.getComparator();
267 
268             int result = comparator.compare( checkedValue, valueArray[0] );
269 
270             return result == 0;
271         }
272     }
273 
274 
275     /**
276      * @see Object#toString()
277      */
278     public String toString()
279     {
280         StringBuilder sb = new StringBuilder();
281 
282         sb.append( "ValueHolder[" ).append( valueSerializer.getClass().getSimpleName() );
283 
284         if ( valueBtree != null )
285         {
286             sb.append( ", SubBTree" );
287         }
288         else
289         {
290             sb.append( ", {" );
291 
292             if ( size() != 0 )
293             {
294                 sb.append( valueArray[0] );
295             }
296 
297             sb.append( "}" );
298         }
299 
300         sb.append( "]" );
301 
302         return sb.toString();
303     }
304 }