EMMA Coverage Report (generated Wed Jun 28 22:15:27 PDT 2006)
[all classes][org.apache.derby.iapi.store.access]

COVERAGE SUMMARY FOR SOURCE FILE [DiskHashtable.java]

nameclass, %method, %block, %line, %
DiskHashtable.java100% (2/2)83%  (10/12)78%  (427/549)73%  (79.1/108)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class DiskHashtable100% (1/1)78%  (7/9)82%  (357/438)82%  (64.1/78)
DiskHashtable (TransactionController, DataValueDescriptor [], int [], boolean... 100% (1/1)99%  (156/158)100% (24/24)
close (): void 100% (1/1)100% (17/17)100% (5/5)
elements (): Enumeration 100% (1/1)100% (5/5)100% (1/1)
get (Object): Object 100% (1/1)100% (6/6)100% (1/1)
getRemove (Object, boolean, boolean): Object 100% (1/1)78%  (110/141)83%  (22.4/27)
put (Object, Object []): boolean 100% (1/1)80%  (49/61)80%  (8.8/11)
remove (Object): Object 0%   (0/1)0%   (0/6)0%   (0/1)
rowMatches (DataValueDescriptor [], Object): boolean 100% (1/1)34%  (14/41)29%  (2/7)
size (): int 0%   (0/1)0%   (0/3)0%   (0/1)
     
class DiskHashtable$ElementEnum100% (1/1)100% (3/3)63%  (70/111)50%  (15/30)
DiskHashtable$ElementEnum (DiskHashtable): void 100% (1/1)64%  (37/58)43%  (6/14)
hasMoreElements (): boolean 100% (1/1)100% (3/3)100% (1/1)
nextElement (): Object 100% (1/1)60%  (30/50)53%  (8/15)

1/*
2 
3   Derby - Class org.apache.derby.iapi.store.access.DiskHashtable
4 
5   Copyright 2005 The Apache Software Foundation or its licensors, as applicable.
6 
7   Licensed under the Apache License, Version 2.0 (the "License");
8   you may not use this file except in compliance with the License.
9   You may obtain a copy of the License at
10 
11      http://www.apache.org/licenses/LICENSE-2.0
12 
13   Unless required by applicable law or agreed to in writing, software
14   distributed under the License is distributed on an "AS IS" BASIS,
15   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   See the License for the specific language governing permissions and
17   limitations under the License.
18 
19 */
20 
21package org.apache.derby.iapi.store.access;
22 
23import java.util.Enumeration;
24import java.util.NoSuchElementException;
25import java.util.Properties;
26import java.util.Vector;
27import org.apache.derby.iapi.error.StandardException;
28import org.apache.derby.iapi.services.io.FormatableBitSet;
29import org.apache.derby.iapi.types.DataValueDescriptor;
30import org.apache.derby.iapi.types.SQLInteger;
31import org.apache.derby.impl.store.access.heap.HeapRowLocation;
32import org.apache.derby.iapi.types.RowLocation;
33import org.apache.derby.iapi.services.context.ContextService;
34import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
35 
36/**
37 * This class is used by BackingStoreHashtable when the BackingStoreHashtable must spill to disk.
38 * It implements the methods of a hash table: put, get, remove, elements, however it is not implemented
39 * as a hash table. In order to minimize the amount of unique code it is implemented using a Btree and a heap
40 * conglomerate. The Btree indexes the hash code of the row key. The actual key may be too long for
41 * our Btree implementation.
42 *
43 * Created: Fri Jan 28 13:58:03 2005
44 *
45 * @author <a href="mailto:klebanof@us.ibm.com">Jack Klebanoff</a>
46 * @version 1.0
47 */
48 
49public class DiskHashtable 
50{
51    private final long rowConglomerateId;
52    private ConglomerateController rowConglomerate;
53    private final long btreeConglomerateId;
54    private ConglomerateController btreeConglomerate;
55    private final DataValueDescriptor[] btreeRow;
56    private final int[] key_column_numbers;
57    private final boolean remove_duplicates;
58    private final TransactionController tc;
59    private final DataValueDescriptor[] row;
60    private final DataValueDescriptor[] scanKey = { new SQLInteger()};
61    private int size;
62    private boolean keepStatistics;
63 
64    /**
65     * Creates a new <code>DiskHashtable</code> instance.
66     *
67     * @param tc
68     * @param template An array of DataValueDescriptors that serves as a template for the rows.
69     * @param key_column_numbers The indexes of the key columns (0 based)
70     * @param remove_duplicates If true then rows with duplicate keys are removed
71     * @param keepAfterCommit If true then the hash table is kept after a commit
72     */
73    public DiskHashtable( TransactionController tc,
74                          DataValueDescriptor[] template,
75                          int[] key_column_numbers,
76                          boolean remove_duplicates,
77                          boolean keepAfterCommit)
78        throws StandardException
79    {
80        this.tc = tc;
81        this.key_column_numbers = key_column_numbers;
82        this.remove_duplicates = remove_duplicates;
83        LanguageConnectionContext lcc = (LanguageConnectionContext)
84                                ContextService.getContextOrNull(LanguageConnectionContext.CONTEXT_ID);
85        keepStatistics = (lcc != null) && lcc.getRunTimeStatisticsMode();
86        row = new DataValueDescriptor[ template.length];
87        for( int i = 0; i < row.length; i++)
88            row[i] = template[i].getNewNull();
89        int tempFlags = keepAfterCommit ? (TransactionController.IS_TEMPORARY | TransactionController.IS_KEPT)
90          : TransactionController.IS_TEMPORARY;
91        
92        rowConglomerateId = tc.createConglomerate( "heap",
93                                                   template,
94                                                   (ColumnOrdering[]) null,
95                                                   (Properties) null,
96                                                   tempFlags);
97        rowConglomerate = tc.openConglomerate( rowConglomerateId,
98                                               keepAfterCommit,
99                                               TransactionController.OPENMODE_FORUPDATE,
100                                               TransactionController.MODE_TABLE,
101                                               TransactionController.ISOLATION_NOLOCK /* Single thread only */ );
102 
103        btreeRow = new DataValueDescriptor[] { new SQLInteger(), rowConglomerate.newRowLocationTemplate()};
104        Properties btreeProps = new Properties();
105        btreeProps.put( "baseConglomerateId", String.valueOf( rowConglomerateId));
106        btreeProps.put( "rowLocationColumn", "1");
107        btreeProps.put( "allowDuplicates", "false"); // Because the row location is part of the key
108        btreeProps.put( "nKeyFields", "2"); // Include the row location column
109        btreeProps.put( "nUniqueColumns", "2"); // Include the row location column
110        btreeProps.put( "maintainParentLinks", "false");
111        btreeConglomerateId = tc.createConglomerate( "BTREE",
112                                                     btreeRow,
113                                                     (ColumnOrdering[]) null,
114                                                     btreeProps,
115                                                     tempFlags);
116 
117        btreeConglomerate = tc.openConglomerate( btreeConglomerateId,
118                                                 keepAfterCommit,
119                                                 TransactionController.OPENMODE_FORUPDATE,
120                                                 TransactionController.MODE_TABLE,
121                                                 TransactionController.ISOLATION_NOLOCK /* Single thread only */ );
122    } // end of constructor
123 
124    public void close() throws StandardException
125    {
126        btreeConglomerate.close();
127        rowConglomerate.close();
128        tc.dropConglomerate( btreeConglomerateId);
129        tc.dropConglomerate( rowConglomerateId);
130    } // end of close
131    
132    /**
133     * Put a new row in the overflow structure.
134     *
135     * @param row The row to be inserted.
136     *
137     * @return true if the row was added,
138     *         false if it was not added (because it was a duplicate and we are eliminating duplicates).
139     *
140     * @exception StandardException standard error policy
141     */
142    public boolean put( Object key, Object[] row)
143        throws StandardException
144    {
145        boolean isDuplicate = false;
146        if( remove_duplicates || keepStatistics)
147        {
148            // Go to the work of finding out whether it is a duplicate
149            isDuplicate = (getRemove( key, false, true) != null);
150            if( remove_duplicates && isDuplicate)
151                return false;
152        }
153        rowConglomerate.insertAndFetchLocation( (DataValueDescriptor[]) row, (RowLocation) btreeRow[1]);
154        btreeRow[0].setValue( key.hashCode());
155        btreeConglomerate.insert( btreeRow);
156        if( keepStatistics && !isDuplicate)
157            size++;
158        return true;
159    } // end of put
160 
161    /**
162     * Get a row from the overflow structure.
163     *
164     * @param key If the rows only have one key column then the key value. If there is more than one
165     *            key column then a KeyHasher
166     *
167     * @return null if there is no corresponding row,
168     *         the row (DataValueDescriptor[]) if there is exactly one row with the key
169     *         a Vector of all the rows with the key if there is more than one.
170     *
171     * @exception StandardException
172     */
173    public Object get( Object key)
174        throws StandardException
175    {
176        return getRemove( key, false, false);
177    }
178 
179    private Object getRemove( Object key, boolean remove, boolean existenceOnly)
180        throws StandardException
181    {
182        int hashCode = key.hashCode();
183        int rowCount = 0;
184        Object retValue = null;
185 
186        scanKey[0].setValue( hashCode);
187        ScanController scan = tc.openScan( btreeConglomerateId,
188                                           false, // do not hold
189                                           remove ? TransactionController.OPENMODE_FORUPDATE : 0,
190                                           TransactionController.MODE_TABLE,
191                                           TransactionController.ISOLATION_READ_UNCOMMITTED,
192                                           null, // Scan all the columns
193                                           scanKey,
194                                           ScanController.GE,
195                                           (Qualifier[][]) null,
196                                           scanKey,
197                                           ScanController.GT);
198        try
199        {
200            while( scan.fetchNext( btreeRow))
201            {
202                if( rowConglomerate.fetch( (RowLocation) btreeRow[1], row, (FormatableBitSet) null /* all columns */)
203                    && rowMatches( row, key))
204                {
205                    if( existenceOnly)
206                        return this;
207 
208                    rowCount++;
209                    if( rowCount == 1)
210                        retValue = BackingStoreHashtable.cloneRow( row);
211                    else 
212                    {
213                        Vector v;
214                        if( rowCount == 2)
215                        {
216                            v = new Vector( 2);
217                            v.add( retValue);
218                            retValue = v;
219                        }
220                        else
221                            v = (Vector) retValue;
222                        v.add( BackingStoreHashtable.cloneRow( row));
223                    }
224                    if( remove)
225                    {
226                        rowConglomerate.delete( (RowLocation) btreeRow[1]);
227                        scan.delete();
228                        size--;
229                    }
230                    if( remove_duplicates)
231                        // This must be the only row with the key
232                        return retValue;
233                }
234            }
235        }
236        finally
237        {
238            scan.close();
239        }
240        return retValue;
241    } // end of getRemove
242 
243 
244    private boolean rowMatches( DataValueDescriptor[] row,
245                                Object key)
246    {
247        if( key_column_numbers.length == 1)
248            return row[ key_column_numbers[0]].equals( key);
249 
250        KeyHasher kh = (KeyHasher) key;
251        for( int i = 0; i < key_column_numbers.length; i++)
252        {
253            if( ! row[ key_column_numbers[i]].equals( kh.getObject(i)))
254                return false;
255        }
256        return true;
257    } // end of rowMatches
258 
259    /**
260     * remove all rows with a given key from the hash table.
261     *
262     * @param key          The key of the rows to remove.
263     *
264     * @return The removed row(s).
265     *
266         * @exception  StandardException  Standard exception policy.
267     **/
268    public Object remove( Object key)
269                throws StandardException
270    {
271        return getRemove( key, true, false);
272    } // end of remove
273 
274    /**
275     * @return The number of rows in the hash table
276     */
277    public int size()
278    {
279        return size;
280    }
281    
282    /**
283     * Return an Enumeration that can be used to scan entire table.
284     * <p>
285     * RESOLVE - is it worth it to support this routine?
286     *
287         * @return The Enumeration.
288     *
289         * @exception  StandardException  Standard exception policy.
290     **/
291    public Enumeration elements()
292        throws StandardException
293    {
294        return new ElementEnum();
295    }
296 
297    private class ElementEnum implements Enumeration
298    {
299        private ScanController scan;
300        private boolean hasMore;
301 
302        ElementEnum()
303        {
304            try
305            {
306                scan = tc.openScan( rowConglomerateId,
307                                    false, // do not hold
308                                    0, // read only
309                                    TransactionController.MODE_TABLE,
310                                    TransactionController.ISOLATION_NOLOCK,
311                                    (FormatableBitSet) null, // all columns
312                                    (DataValueDescriptor[]) null, // no start key
313                                    0, // no start key operator
314                                    (Qualifier[][]) null,
315                                    (DataValueDescriptor[]) null, // no stop key
316                                    0 /* no stop key operator */);
317                hasMore = scan.next();
318                if( ! hasMore)
319                {
320                    scan.close();
321                    scan = null;
322                }
323            }
324            catch( StandardException se)
325            {
326                hasMore = false;
327                if( scan != null)
328                {
329                    try
330                    {
331                        scan.close();
332                    }
333                    catch( StandardException se1){};
334                    scan = null;
335                }
336            }
337        } // end of constructor
338 
339        public boolean hasMoreElements()
340        {
341            return hasMore;
342        }
343 
344        public Object nextElement()
345        {
346            if( ! hasMore)
347                throw new NoSuchElementException();
348            try
349            {
350                scan.fetch( row);
351                Object retValue =  BackingStoreHashtable.cloneRow( row);
352                hasMore = scan.next();
353                if( ! hasMore)
354                {
355                    scan.close();
356                    scan = null;
357                }
358 
359                return retValue;
360            }
361            catch( StandardException se)
362            {
363                if( scan != null)
364                {
365                    try
366                    {
367                        scan.close();
368                    }
369                    catch( StandardException se1){};
370                    scan = null;
371                }
372                throw new NoSuchElementException();
373            }
374        } // end of nextElement
375    } // end of class ElementEnum
376}

[all classes][org.apache.derby.iapi.store.access]
EMMA 2.0.5312 (C) Vladimir Roubtsov