You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by mi...@apache.org on 2006/10/10 07:40:38 UTC

svn commit: r454623 - in /db/derby/code/trunk/java: engine/org/apache/derby/iapi/store/access/ testing/org/apache/derbyTesting/functionTests/master/ testing/org/apache/derbyTesting/functionTests/suites/ testing/org/apache/derbyTesting/functionTests/tes...

Author: mikem
Date: Mon Oct  9 22:40:37 2006
New Revision: 454623

URL: http://svn.apache.org/viewvc?view=rev&rev=454623
Log:
DERBY-1939

Bug was already fixed in trunk, merging added tests and new sanity
check from 10.1 codeline to trunk.


Added:
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/st_derby1939.out   (props changed)
      - copied unchanged from r454410, db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/st_derby1939.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/storetests/st_derby1939.java   (props changed)
      - copied unchanged from r454410, db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/storetests/st_derby1939.java
Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/store/access/DiskHashtable.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/suites/storetests.runall

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/store/access/DiskHashtable.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/store/access/DiskHashtable.java?view=diff&rev=454623&r1=454622&r2=454623
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/store/access/DiskHashtable.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/store/access/DiskHashtable.java Mon Oct  9 22:40:37 2006
@@ -18,7 +18,6 @@
    limitations under the License.
 
  */
-
 package org.apache.derby.iapi.store.access;
 
 import java.util.Enumeration;
@@ -29,17 +28,18 @@
 import org.apache.derby.iapi.services.io.FormatableBitSet;
 import org.apache.derby.iapi.types.DataValueDescriptor;
 import org.apache.derby.iapi.types.SQLInteger;
-import org.apache.derby.impl.store.access.heap.HeapRowLocation;
 import org.apache.derby.iapi.types.RowLocation;
 import org.apache.derby.iapi.services.context.ContextService;
 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
+import org.apache.derby.iapi.services.sanity.SanityManager;
 
 /**
- * This class is used by BackingStoreHashtable when the BackingStoreHashtable must spill to disk.
- * It implements the methods of a hash table: put, get, remove, elements, however it is not implemented
- * as a hash table. In order to minimize the amount of unique code it is implemented using a Btree and a heap
- * conglomerate. The Btree indexes the hash code of the row key. The actual key may be too long for
- * our Btree implementation.
+ * This class is used by BackingStoreHashtable when the BackingStoreHashtable 
+ * must spill to disk.  It implements the methods of a hash table: put, get, 
+ * remove, elements, however it is not implemented as a hash table. In order to
+ * minimize the amount of unique code it is implemented using a Btree and a 
+ * heap conglomerate. The Btree indexes the hash code of the row key. The 
+ * actual key may be too long for our Btree implementation.
  *
  * Created: Fri Jan 28 13:58:03 2005
  *
@@ -49,77 +49,126 @@
 
 public class DiskHashtable 
 {
-    private final long rowConglomerateId;
-    private ConglomerateController rowConglomerate;
-    private final long btreeConglomerateId;
-    private ConglomerateController btreeConglomerate;
-    private final DataValueDescriptor[] btreeRow;
-    private final int[] key_column_numbers;
-    private final boolean remove_duplicates;
-    private final TransactionController tc;
-    private final DataValueDescriptor[] row;
-    private final DataValueDescriptor[] scanKey = { new SQLInteger()};
-    private int size;
-    private boolean keepStatistics;
+    private final long                    rowConglomerateId;
+    private       ConglomerateController  rowConglomerate;
+    private final long                    btreeConglomerateId;
+    private       ConglomerateController  btreeConglomerate;
+    private final DataValueDescriptor[]   btreeRow;
+    private final int[]                   key_column_numbers;
+    private final boolean                 remove_duplicates;
+    private final TransactionController   tc;
+    private final DataValueDescriptor[]   row;
+    private final DataValueDescriptor[]   scanKey = { new SQLInteger()};
+    private int                           size;
+    private boolean                       keepStatistics;
 
     /**
      * Creates a new <code>DiskHashtable</code> instance.
      *
      * @param tc
-     * @param template An array of DataValueDescriptors that serves as a template for the rows.
-     * @param key_column_numbers The indexes of the key columns (0 based)
-     * @param remove_duplicates If true then rows with duplicate keys are removed
-     * @param keepAfterCommit If true then the hash table is kept after a commit
+     * @param template              An array of DataValueDescriptors that 
+     *                              serves as a template for the rows.
+     * @param key_column_numbers    The indexes of the key columns (0 based)
+     * @param remove_duplicates     If true then rows with duplicate keys are 
+     *                              removed.
+     * @param keepAfterCommit       If true then the hash table is kept after 
+     *                              a commit
      */
-    public DiskHashtable( TransactionController tc,
-                          DataValueDescriptor[] template,
-                          int[] key_column_numbers,
-                          boolean remove_duplicates,
-                          boolean keepAfterCommit)
+    public DiskHashtable( 
+    TransactionController   tc,
+    DataValueDescriptor[]   template,
+    int[]                   key_column_numbers,
+    boolean                 remove_duplicates,
+    boolean                 keepAfterCommit)
         throws StandardException
     {
-        this.tc = tc;
-        this.key_column_numbers = key_column_numbers;
-        this.remove_duplicates = remove_duplicates;
-        LanguageConnectionContext lcc = (LanguageConnectionContext)
-				ContextService.getContextOrNull(LanguageConnectionContext.CONTEXT_ID);
+        this.tc                         = tc;
+        this.key_column_numbers         = key_column_numbers;
+        this.remove_duplicates          = remove_duplicates;
+        LanguageConnectionContext lcc   = (LanguageConnectionContext)
+            ContextService.getContextOrNull(
+                LanguageConnectionContext.CONTEXT_ID);
+
         keepStatistics = (lcc != null) && lcc.getRunTimeStatisticsMode();
-        row = new DataValueDescriptor[ template.length];
+
+        // Create template row used for creating the conglomerate and 
+        // fetching rows.
+        row = new DataValueDescriptor[template.length];
         for( int i = 0; i < row.length; i++)
+        {
             row[i] = template[i].getNewNull();
-        int tempFlags = keepAfterCommit ? (TransactionController.IS_TEMPORARY | TransactionController.IS_KEPT)
-          : TransactionController.IS_TEMPORARY;
+
+            if (SanityManager.DEBUG)
+            {
+                // must have an object template for all cols in hash overflow.
+                SanityManager.ASSERT(
+                    row[i] != null, 
+                    "Template for the hash table must have non-null object");
+            }
+        }
+
+        int tempFlags = 
+            keepAfterCommit ? 
+            (TransactionController.IS_TEMPORARY | 
+             TransactionController.IS_KEPT) : 
+            TransactionController.IS_TEMPORARY;
         
-        rowConglomerateId = tc.createConglomerate( "heap",
-                                                   template,
-                                                   (ColumnOrdering[]) null,
-                                                   (Properties) null,
-                                                   tempFlags);
-        rowConglomerate = tc.openConglomerate( rowConglomerateId,
-                                               keepAfterCommit,
-                                               TransactionController.OPENMODE_FORUPDATE,
-                                               TransactionController.MODE_TABLE,
-                                               TransactionController.ISOLATION_NOLOCK /* Single thread only */ );
+        // create the "base" table of the hash overflow.
+        rowConglomerateId = 
+            tc.createConglomerate( 
+                "heap",
+                template,
+                (ColumnOrdering[]) null,
+                (Properties) null,
+                tempFlags);
+
+        // open the "base" table of the hash overflow.
+        rowConglomerate = 
+            tc.openConglomerate( 
+                rowConglomerateId,
+                keepAfterCommit,
+                TransactionController.OPENMODE_FORUPDATE,
+                TransactionController.MODE_TABLE,
+                TransactionController.ISOLATION_NOLOCK/* Single thread only */);
+
+        // create the index on the "hash" base table.  The key of the index
+        // is the hash code of the row key.  The second column is the 
+        // RowLocation of the row in the "base" table of the hash overflow.
+        btreeRow = 
+            new DataValueDescriptor[] 
+                { new SQLInteger(), rowConglomerate.newRowLocationTemplate()};
 
-        btreeRow = new DataValueDescriptor[] { new SQLInteger(), rowConglomerate.newRowLocationTemplate()};
         Properties btreeProps = new Properties();
-        btreeProps.put( "baseConglomerateId", String.valueOf( rowConglomerateId));
-        btreeProps.put( "rowLocationColumn", "1");
-        btreeProps.put( "allowDuplicates", "false"); // Because the row location is part of the key
-        btreeProps.put( "nKeyFields", "2"); // Include the row location column
-        btreeProps.put( "nUniqueColumns", "2"); // Include the row location column
-        btreeProps.put( "maintainParentLinks", "false");
-        btreeConglomerateId = tc.createConglomerate( "BTREE",
-                                                     btreeRow,
-                                                     (ColumnOrdering[]) null,
-                                                     btreeProps,
-                                                     tempFlags);
-
-        btreeConglomerate = tc.openConglomerate( btreeConglomerateId,
-                                                 keepAfterCommit,
-                                                 TransactionController.OPENMODE_FORUPDATE,
-                                                 TransactionController.MODE_TABLE,
-                                                 TransactionController.ISOLATION_NOLOCK /* Single thread only */ );
+
+        btreeProps.put("baseConglomerateId", 
+                String.valueOf(rowConglomerateId));
+        btreeProps.put("rowLocationColumn",  
+                "1");
+        btreeProps.put("allowDuplicates",    
+                "false"); // Because the row location is part of the key
+        btreeProps.put("nKeyFields",         
+                "2"); // Include the row location column
+        btreeProps.put("nUniqueColumns",     
+                "2"); // Include the row location column
+        btreeProps.put("maintainParentLinks", 
+                "false");
+        btreeConglomerateId = 
+            tc.createConglomerate( 
+                "BTREE",
+                btreeRow,
+                (ColumnOrdering[]) null,
+                btreeProps,
+                tempFlags);
+
+        // open the "index" of the hash overflow.
+        btreeConglomerate = 
+            tc.openConglomerate( 
+                btreeConglomerateId,
+                keepAfterCommit,
+                TransactionController.OPENMODE_FORUPDATE,
+                TransactionController.MODE_TABLE,
+                TransactionController.ISOLATION_NOLOCK /*Single thread only*/ );
+
     } // end of constructor
 
     public void close() throws StandardException
@@ -135,49 +184,60 @@
      *
      * @param row The row to be inserted.
      *
-     * @return true if the row was added,
-     *         false if it was not added (because it was a duplicate and we are eliminating duplicates).
+     * @return true  if the row was added,
+     *         false if it was not added (because it was a duplicate and we 
+     *               are eliminating duplicates).
      *
      * @exception StandardException standard error policy
      */
-    public boolean put( Object key, Object[] row)
+    public boolean put(Object key, Object[] row)
         throws StandardException
     {
         boolean isDuplicate = false;
-        if( remove_duplicates || keepStatistics)
+        if (remove_duplicates || keepStatistics)
         {
             // Go to the work of finding out whether it is a duplicate
-            isDuplicate = (getRemove( key, false, true) != null);
-            if( remove_duplicates && isDuplicate)
+            isDuplicate = (getRemove(key, false, true) != null);
+            if (remove_duplicates && isDuplicate)
                 return false;
         }
-        rowConglomerate.insertAndFetchLocation( (DataValueDescriptor[]) row, (RowLocation) btreeRow[1]);
+
+        // insert the row into the "base" conglomerate.
+        rowConglomerate.insertAndFetchLocation( 
+            (DataValueDescriptor[]) row, (RowLocation) btreeRow[1]);
+
+        // create index row from hashcode and rowlocation just inserted, and
+        // insert index row into index.
         btreeRow[0].setValue( key.hashCode());
         btreeConglomerate.insert( btreeRow);
-        if( keepStatistics && !isDuplicate)
+
+        if (keepStatistics && !isDuplicate)
             size++;
+
         return true;
+
     } // end of put
 
     /**
      * Get a row from the overflow structure.
      *
-     * @param key If the rows only have one key column then the key value. If there is more than one
-     *            key column then a KeyHasher
+     * @param key If the rows only have one key column then the key value. 
+     *            If there is more than one key column then a KeyHasher
      *
      * @return null if there is no corresponding row,
-     *         the row (DataValueDescriptor[]) if there is exactly one row with the key
+     *         the row (DataValueDescriptor[]) if there is exactly one row 
+     *         with the key, or
      *         a Vector of all the rows with the key if there is more than one.
      *
      * @exception StandardException
      */
-    public Object get( Object key)
+    public Object get(Object key)
         throws StandardException
     {
-        return getRemove( key, false, false);
+        return getRemove(key, false, false);
     }
 
-    private Object getRemove( Object key, boolean remove, boolean existenceOnly)
+    private Object getRemove(Object key, boolean remove, boolean existenceOnly)
         throws StandardException
     {
         int hashCode = key.hashCode();
@@ -185,37 +245,49 @@
         Object retValue = null;
 
         scanKey[0].setValue( hashCode);
-        ScanController scan = tc.openScan( btreeConglomerateId,
-                                           false, // do not hold
-                                           remove ? TransactionController.OPENMODE_FORUPDATE : 0,
-                                           TransactionController.MODE_TABLE,
-                                           TransactionController.ISOLATION_READ_UNCOMMITTED,
-                                           null, // Scan all the columns
-                                           scanKey,
-                                           ScanController.GE,
-                                           (Qualifier[][]) null,
-                                           scanKey,
-                                           ScanController.GT);
+        ScanController scan = 
+            tc.openScan( 
+                btreeConglomerateId,
+                false, // do not hold
+                remove ? TransactionController.OPENMODE_FORUPDATE : 0,
+                TransactionController.MODE_TABLE,
+                TransactionController.ISOLATION_READ_UNCOMMITTED,
+                null, // Scan all the columns
+                scanKey,
+                ScanController.GE,
+                (Qualifier[][]) null,
+                scanKey,
+                ScanController.GT);
         try
         {
-            while( scan.fetchNext( btreeRow))
+            while (scan.fetchNext(btreeRow))
             {
-                if( rowConglomerate.fetch( (RowLocation) btreeRow[1], row, (FormatableBitSet) null /* all columns */)
+                if (rowConglomerate.fetch(
+                        (RowLocation) btreeRow[1], 
+                        row, 
+                        (FormatableBitSet) null /* all columns */)
                     && rowMatches( row, key))
                 {
                     if( existenceOnly)
                         return this;
 
                     rowCount++;
-                    if( rowCount == 1) 
+                    if( rowCount == 1)
                     {
-                        retValue = BackingStoreHashtable.shallowCloneRow( row);                        
-                    } 
+                        // if there is only one matching row just return row. 
+                        retValue = BackingStoreHashtable.shallowCloneRow( row);
+                    }
                     else 
                     {
+                        // if there is more than one row, return a vector of
+                        // the rows.
+                        //
                         Vector v;
                         if( rowCount == 2)
                         {
+                            // convert the "single" row retrieved from the
+                            // first trip in the loop, to a vector with the
+                            // first two rows.
                             v = new Vector( 2);
                             v.add( retValue);
                             retValue = v;
@@ -246,8 +318,9 @@
     } // end of getRemove
 
 
-    private boolean rowMatches( DataValueDescriptor[] row,
-                                Object key)
+    private boolean rowMatches( 
+    DataValueDescriptor[] row,
+    Object                key)
     {
         if( key_column_numbers.length == 1)
             return row[ key_column_numbers[0]].equals( key);

Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/st_derby1939.out
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/suites/storetests.runall
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/suites/storetests.runall?view=diff&rev=454623&r1=454622&r2=454623
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/suites/storetests.runall (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/suites/storetests.runall Mon Oct  9 22:40:37 2006
@@ -1,4 +1,5 @@
 storetests/st_schema.sql
+storetests/st_derby1939.java
 storetests/st_derby1189.sql
 storetests/st_reclaim_longcol.java
 storetests/st_derby715.java

Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/storetests/st_derby1939.java
------------------------------------------------------------------------------
    svn:eol-style = native