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/03/13 23:20:12 UTC

svn commit: r385674 [3/3] - in /db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests: store/ storetests/

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/storetests/st_derby715.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/storetests/st_derby715.java?rev=385674&r1=385673&r2=385674&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/storetests/st_derby715.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/storetests/st_derby715.java Mon Mar 13 14:20:10 2006
@@ -1,282 +1,282 @@
-/*
-
-   Derby - Class org.apache.derbyTesting.functionTests.harness.procedure
-
-   Copyright 2005 The Apache Software Foundation or its licensors, as applicable.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-
- */
-
-package org.apache.derbyTesting.functionTests.tests.storetests;
-
-
-import org.apache.derby.iapi.services.sanity.SanityManager;
-
-import org.apache.derbyTesting.functionTests.tests.store.BaseTest;
-
-import java.sql.CallableStatement;
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-
-import org.apache.derby.tools.ij;
-
-
-/**
-
-The purpose of this test is to reproduce JIRA DERBY-715:
-
-Sometimes a deadlock would be incorrectly reported as a deadlock.  The
-bug seemed to always reproduce at least once if the following test
-was run (at least one of the iterations in the loop would get an
-incorrect timeout vs. a deadlock).
-
-**/
-
-public class st_derby715 extends BaseTest
-{
-    static boolean verbose = false;
-
-    public st_derby715()
-    {
-    }
-
-
-    /**
-     * Create the base table that the 2 threads will use.
-     **/
-    private static void setup()
-        throws Exception
-    {
-        Connection conn = ij.startJBMS();
-        Statement  stmt = conn.createStatement();
-
-        // drop table, ignore table does not exist error.
-
-        try
-        {
-            stmt.executeUpdate("drop table a");
-        }
-        catch (Exception e)
-        {
-            // ignore drop table errors.
-        }
-
-        try
-        {
-            stmt.executeUpdate("drop table b");
-        }
-        catch (Exception e)
-        {
-            // ignore drop table errors.
-        }
-
-        stmt.executeUpdate("create table a (a integer)");
-        stmt.executeUpdate("create table b (b integer)");
-        stmt.close();
-        conn.commit();
-        conn.close();
-    }
-
-    public static class t1 implements Runnable
-    {
-        String[] argv;
-
-        public t1(String[] argv)
-        {
-            argv = argv;
-        }
-        public void run()
-        {
-            try
-            {
-                ij.getPropertyArg(argv); 
-                Connection conn = ij.startJBMS();
-                conn.setAutoCommit(false);
-                conn.setTransactionIsolation(
-                        Connection.TRANSACTION_SERIALIZABLE);
-
-                Statement stmt = conn.createStatement();
-                if (verbose)
-                    System.out.println("Thread 1 before selecting from b");
-
-                // get row locks on all rows in b
-                ResultSet rs = stmt.executeQuery("select * from b");
-
-                if (verbose)
-                    System.out.println("Thread 1 before selecting next from b");
-
-                while (rs.next())
-                {
-                    if (verbose)
-                        System.out.println("Thread t1 got " + rs.getString(1));
-                }
-                if (verbose)
-                    System.out.println("Thread 1 after all next.");
-
-                // give thread 2 a chance to catch up.
-                Thread.sleep(500);
-
-                if (verbose)
-                    System.out.println("Thread 1 before inserting into a...");
-
-                // now wait on lock inserting row into table a - either 
-                // thread 1 or thread 2 should get a deadlock, NOT a timeout.
-                stmt.executeUpdate("insert into a values(1)");
-
-                if (verbose)
-                    System.out.println("Thread 1 after inserting into a...");
-
-                conn.rollback();
-            }
-            catch (SQLException sqle)
-            {
-                if (sqle.getSQLState().equals("40001"))
-                {
-                    // only expected exception is a deadlock, we should
-                    // get at least one deadlock, so print it to output.
-                    // Don't know which thread will get the deadlock, so
-                    // don't label it.
-                    System.out.println("Got a Deadlock.");
-                }
-                else
-                {
-                    org.apache.derby.tools.JDBCDisplayUtil.ShowSQLException(
-                        System.out, sqle);
-                    sqle.printStackTrace(System.out);
-                }
-                if (verbose)
-                    System.out.println("Thread 1 got exception:\n");
-            }
-            catch (Exception ex)
-            {
-                System.out.println("got unexpected exception: " + ex);
-            }
-        }
-    }
-
-    public static class t2 implements Runnable
-    {
-        String[] argv;
-        public t2 (String[] argv)
-        {
-            argv = argv;
-        }
-        public void run()
-        {
-            try
-            {
-                ij.getPropertyArg(argv); 
-                Connection conn = ij.startJBMS();
-                conn.setAutoCommit(false);
-                conn.setTransactionIsolation(
-                        Connection.TRANSACTION_SERIALIZABLE);
-
-                Statement stmt = conn.createStatement();
-
-                if (verbose)
-                    System.out.println("Thread 2 before selecting from a");
-
-                ResultSet rs = stmt.executeQuery("select * from a");
-
-                if (verbose)
-                    System.out.println("Thread 2 before selecting next from a");
-
-                while (rs.next())
-                {
-                    if (verbose)
-                        System.out.println("Thread t2 got " + rs.getString(1));
-                }
-
-                if (verbose)
-                    System.out.println("Thread 2 after all next.");
-
-
-                Thread.sleep(500);
-                
-                if (verbose)
-                    System.out.println("Thread 2 before inserting into b");
-
-                stmt.executeUpdate("insert into b values(2)");
-
-                if (verbose)
-                    System.out.println("Thread 2 after inserting into b");
-
-                conn.rollback();
-            }
-            catch (SQLException sqle)
-            {
-                if (verbose)
-                    System.out.println("Thread 1 got exception:\n");
-
-                if (sqle.getSQLState().equals("40001"))
-                {
-                    // only expected exception is a deadlock, we should
-                    // get at least one deadlock, so print it to output.
-                    // Don't know which thread will get the deadlock, so
-                    // don't label it.
-                    System.out.println("Got a Deadlock.");
-                }
-                else
-                {
-                    org.apache.derby.tools.JDBCDisplayUtil.ShowSQLException(
-                        System.out, sqle);
-                    sqle.printStackTrace(System.out);
-                }
-            }
-            catch (Exception ex)
-            {
-                System.out.println("got unexpected exception: " + ex);
-            }
-        }
-    }
-    
-
-    public void testList(Connection conn)
-        throws SQLException
-    {
-    }
-
-    public static void main(String[] argv) 
-        throws Throwable
-    {
-        ij.getPropertyArg(argv); 
-
-        st_derby715 setup_ddl = new st_derby715();
-        setup_ddl.setup();
-        setup_ddl = null;
-
-        {
-            for (int i = 0; i < 5; i++)
-            {
-                Thread test1 = new Thread(new t1(argv));
-                Thread test2 = new Thread(new t2(argv));
-                test1.start();
-                test2.start();
-                test1.join();
-                test2.join();
-            }
-        }
-        /*
-        catch (SQLException sqle)
-        {
-			org.apache.derby.tools.JDBCDisplayUtil.ShowSQLException(
-                System.out, sqle);
-			sqle.printStackTrace(System.out);
-		}
-        */
-    }
-}
+/*
+
+   Derby - Class org.apache.derbyTesting.functionTests.harness.procedure
+
+   Copyright 2005 The Apache Software Foundation or its licensors, as applicable.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+
+package org.apache.derbyTesting.functionTests.tests.storetests;
+
+
+import org.apache.derby.iapi.services.sanity.SanityManager;
+
+import org.apache.derbyTesting.functionTests.tests.store.BaseTest;
+
+import java.sql.CallableStatement;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import org.apache.derby.tools.ij;
+
+
+/**
+
+The purpose of this test is to reproduce JIRA DERBY-715:
+
+Sometimes a deadlock would be incorrectly reported as a deadlock.  The
+bug seemed to always reproduce at least once if the following test
+was run (at least one of the iterations in the loop would get an
+incorrect timeout vs. a deadlock).
+
+**/
+
+public class st_derby715 extends BaseTest
+{
+    static boolean verbose = false;
+
+    public st_derby715()
+    {
+    }
+
+
+    /**
+     * Create the base table that the 2 threads will use.
+     **/
+    private static void setup()
+        throws Exception
+    {
+        Connection conn = ij.startJBMS();
+        Statement  stmt = conn.createStatement();
+
+        // drop table, ignore table does not exist error.
+
+        try
+        {
+            stmt.executeUpdate("drop table a");
+        }
+        catch (Exception e)
+        {
+            // ignore drop table errors.
+        }
+
+        try
+        {
+            stmt.executeUpdate("drop table b");
+        }
+        catch (Exception e)
+        {
+            // ignore drop table errors.
+        }
+
+        stmt.executeUpdate("create table a (a integer)");
+        stmt.executeUpdate("create table b (b integer)");
+        stmt.close();
+        conn.commit();
+        conn.close();
+    }
+
+    public static class t1 implements Runnable
+    {
+        String[] argv;
+
+        public t1(String[] argv)
+        {
+            argv = argv;
+        }
+        public void run()
+        {
+            try
+            {
+                ij.getPropertyArg(argv); 
+                Connection conn = ij.startJBMS();
+                conn.setAutoCommit(false);
+                conn.setTransactionIsolation(
+                        Connection.TRANSACTION_SERIALIZABLE);
+
+                Statement stmt = conn.createStatement();
+                if (verbose)
+                    System.out.println("Thread 1 before selecting from b");
+
+                // get row locks on all rows in b
+                ResultSet rs = stmt.executeQuery("select * from b");
+
+                if (verbose)
+                    System.out.println("Thread 1 before selecting next from b");
+
+                while (rs.next())
+                {
+                    if (verbose)
+                        System.out.println("Thread t1 got " + rs.getString(1));
+                }
+                if (verbose)
+                    System.out.println("Thread 1 after all next.");
+
+                // give thread 2 a chance to catch up.
+                Thread.sleep(500);
+
+                if (verbose)
+                    System.out.println("Thread 1 before inserting into a...");
+
+                // now wait on lock inserting row into table a - either 
+                // thread 1 or thread 2 should get a deadlock, NOT a timeout.
+                stmt.executeUpdate("insert into a values(1)");
+
+                if (verbose)
+                    System.out.println("Thread 1 after inserting into a...");
+
+                conn.rollback();
+            }
+            catch (SQLException sqle)
+            {
+                if (sqle.getSQLState().equals("40001"))
+                {
+                    // only expected exception is a deadlock, we should
+                    // get at least one deadlock, so print it to output.
+                    // Don't know which thread will get the deadlock, so
+                    // don't label it.
+                    System.out.println("Got a Deadlock.");
+                }
+                else
+                {
+                    org.apache.derby.tools.JDBCDisplayUtil.ShowSQLException(
+                        System.out, sqle);
+                    sqle.printStackTrace(System.out);
+                }
+                if (verbose)
+                    System.out.println("Thread 1 got exception:\n");
+            }
+            catch (Exception ex)
+            {
+                System.out.println("got unexpected exception: " + ex);
+            }
+        }
+    }
+
+    public static class t2 implements Runnable
+    {
+        String[] argv;
+        public t2 (String[] argv)
+        {
+            argv = argv;
+        }
+        public void run()
+        {
+            try
+            {
+                ij.getPropertyArg(argv); 
+                Connection conn = ij.startJBMS();
+                conn.setAutoCommit(false);
+                conn.setTransactionIsolation(
+                        Connection.TRANSACTION_SERIALIZABLE);
+
+                Statement stmt = conn.createStatement();
+
+                if (verbose)
+                    System.out.println("Thread 2 before selecting from a");
+
+                ResultSet rs = stmt.executeQuery("select * from a");
+
+                if (verbose)
+                    System.out.println("Thread 2 before selecting next from a");
+
+                while (rs.next())
+                {
+                    if (verbose)
+                        System.out.println("Thread t2 got " + rs.getString(1));
+                }
+
+                if (verbose)
+                    System.out.println("Thread 2 after all next.");
+
+
+                Thread.sleep(500);
+                
+                if (verbose)
+                    System.out.println("Thread 2 before inserting into b");
+
+                stmt.executeUpdate("insert into b values(2)");
+
+                if (verbose)
+                    System.out.println("Thread 2 after inserting into b");
+
+                conn.rollback();
+            }
+            catch (SQLException sqle)
+            {
+                if (verbose)
+                    System.out.println("Thread 1 got exception:\n");
+
+                if (sqle.getSQLState().equals("40001"))
+                {
+                    // only expected exception is a deadlock, we should
+                    // get at least one deadlock, so print it to output.
+                    // Don't know which thread will get the deadlock, so
+                    // don't label it.
+                    System.out.println("Got a Deadlock.");
+                }
+                else
+                {
+                    org.apache.derby.tools.JDBCDisplayUtil.ShowSQLException(
+                        System.out, sqle);
+                    sqle.printStackTrace(System.out);
+                }
+            }
+            catch (Exception ex)
+            {
+                System.out.println("got unexpected exception: " + ex);
+            }
+        }
+    }
+    
+
+    public void testList(Connection conn)
+        throws SQLException
+    {
+    }
+
+    public static void main(String[] argv) 
+        throws Throwable
+    {
+        ij.getPropertyArg(argv); 
+
+        st_derby715 setup_ddl = new st_derby715();
+        setup_ddl.setup();
+        setup_ddl = null;
+
+        {
+            for (int i = 0; i < 5; i++)
+            {
+                Thread test1 = new Thread(new t1(argv));
+                Thread test2 = new Thread(new t2(argv));
+                test1.start();
+                test2.start();
+                test1.join();
+                test2.join();
+            }
+        }
+        /*
+        catch (SQLException sqle)
+        {
+			org.apache.derby.tools.JDBCDisplayUtil.ShowSQLException(
+                System.out, sqle);
+			sqle.printStackTrace(System.out);
+		}
+        */
+    }
+}

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

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/storetests/st_reclaim_longcol.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/storetests/st_reclaim_longcol.java?rev=385674&r1=385673&r2=385674&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/storetests/st_reclaim_longcol.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/storetests/st_reclaim_longcol.java Mon Mar 13 14:20:10 2006
@@ -1,419 +1,419 @@
-/*
-
-   Derby - Class org.apache.derbyTesting.functionTests.harness.procedure
-
-   Copyright 2005 The Apache Software Foundation or its licensors, as applicable.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-
- */
-
-package org.apache.derbyTesting.functionTests.tests.storetests;
-
-
-import org.apache.derby.iapi.services.sanity.SanityManager;
-
-import org.apache.derbyTesting.functionTests.tests.store.BaseTest;
-
-import java.sql.CallableStatement;
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-
-import java.util.Arrays;
-
-import org.apache.derby.tools.ij;
-
-
-/**
-
-The purpose of this test space reclamation of long rows and long columns.
-This addresses DERBY-670.
-
-The main issue is that previous to fixes for DERBY-670, space reclamation
-was only automatically queued when the last row on a page was deleted.  In
-the case of long columns, the actual row on the main page can be quite small
-as the long data is streamed onto other pages.  So the table can grow 
-unexpectedly quite large before the default space reclamation kicks in.  The
-change queues space reclamation in the case of long columns (blob/clob),
-imediately post commit of the single delete.
-
-The testing strategy is to loop doing insert, delete, commit of a blob for
-a number of iterations and check that the actual size of the table is 
-reasonable.  A sleep will be added to allow time for post commit to catch up
-as the test may be run in a number of environments with varying performance
-of background activities.
-
-**/
-
-public class st_reclaim_longcol extends BaseTest
-{
-    static boolean verbose = false;
-
-    public st_reclaim_longcol()
-    {
-    }
-
-
-    /**
-     * Create the base table.
-     **/
-    private static void setup()
-        throws Exception
-    {
-    }
-
-    /**
-     * Test reclaim of a single deleted blob on a page with non-deleted rows.
-     * <p>
-     * loops through inserting alternating long and short column rows resulting
-     * in pages with 1 short and one long.  Deletes the long column row and
-     * tests that space from the long column row is reclaimed even though
-     * there are non-deleted rows on the page.
-     **/
-    private static final int SHORT_BLOB_SIZE = 10;
-    public void test1(Connection conn, int blob_size, int num_rows)
-        throws SQLException
-    {
-        byte[]  long_byteVal    = new byte[blob_size];
-        byte[]  short_byteVal   = new byte[10];
-
-        beginTest(
-            conn, 
-            "test1:insert/delete of " + num_rows + 
-                " rows with blob(" + blob_size + ")"); 
-
-        Arrays.fill(long_byteVal,  (byte)'L');
-        Arrays.fill(short_byteVal, (byte)'S');
-
-        createTable(
-            conn, 
-            "longcol", 
-            "create table longcol (id int primary key not null, val blob(" + 
-            blob_size + "))");
-
-        conn.commit();
-
-        PreparedStatement ins_stmt = 
-            conn.prepareStatement("insert into longcol values (?, ?)");
-        PreparedStatement del_stmt = 
-            conn.prepareStatement("delete from longcol where id = ?");
-
-        // worst case is a mixture of rows with long columns and those without.
-        // Insert of row with a long column always first goes onto a new 
-        // page by itself, but subsequent non-long column rows can be inserted
-        // on that page.  Then when the long column row is deleted - before the
-        // change - it and all it's chain won't get reclaimed until all rows
-        // on the page get deleted.
-
-        // now do insert/delete/commit for subsequent rows.  Before fix the
-        // space used in the table will grow until the deleted rows do not
-        // fit on the first page.  And even then before the fix the rows
-        // on the first page are never reclaimed as the 1st one is never
-        // deleted.
-        for (int iter = 1; iter < num_rows; iter++)
-        {
-            // insert the long blob
-            ins_stmt.setInt(  1, iter);
-            ins_stmt.setBytes(2, long_byteVal);
-            ins_stmt.executeUpdate();
-
-            // insert the short blob
-            ins_stmt.setInt(  1, -(iter));
-            ins_stmt.setBytes(2, short_byteVal);
-            ins_stmt.executeUpdate();
-
-            // delete the long blob
-            del_stmt.setInt(1, iter);
-            del_stmt.executeUpdate();
-
-            // commit the xact, post commit should kick in to reclaim the
-            // blob space sometime after the commit.
-            conn.commit();
-
-            // sleep, just in case on this machine background
-            // post commit is slow.
-            try
-            {
-                Thread.sleep(20);
-            }
-            catch (Exception ex)
-            {
-                // just ignore interupts of sleep.
-            }
-        }
-
-        int[] sp_info = getSpaceInfo(conn, "APP", "LONGCOL", true);
-
-        int total_pages = 
-            sp_info[SPACE_INFO_NUM_ALLOC] + sp_info[SPACE_INFO_NUM_FREE];
-
-        int total_expected_page_max = 12 + num_rows;
-
-        if (total_pages > total_expected_page_max)
-        {
-            // for the above test case we expect the following space:
-            //     page 0
-            //     page 1 
-            //     free space from 1 blob - 9 pages per blob
-            //     allocated page per long/short blob insert.  Each long
-            //         inserts onto a new page to try and fit it entirely
-            //         on a page.  Then the short blob goes to last inserted
-            //         page.  This process repeats.  The previous pages are
-            //         marked "half-filled" and can be used in future for
-            //         short rows that don't fit on the last page inserted.
-            
-
-
-            System.out.println(
-                "Test failed, expected less than " + 
-                total_expected_page_max + " pages - count is:\n" +
-                "free pages     : "   + sp_info[SPACE_INFO_NUM_FREE] +
-                "\nallocated pages: " + sp_info[SPACE_INFO_NUM_ALLOC]);
-        }
-
-        if (verbose)
-        {
-            System.out.println(
-                "Space information after " + num_rows + 
-                "insert/delete pairs of rows in longcol table containing " + 
-                blob_size + "blobs:");
-
-            System.out.println("isindex = "   + sp_info[SPACE_INFO_IS_INDEX]);
-            System.out.println("num_alloc = " + sp_info[SPACE_INFO_NUM_ALLOC]);
-            System.out.println("num_free = "  + sp_info[SPACE_INFO_NUM_FREE]);
-            System.out.println("page_size = " + sp_info[SPACE_INFO_PAGE_SIZE]);
-            System.out.println(
-                "estimspacesaving = " + sp_info[SPACE_INFO_ESTIMSPACESAVING]);
-        }
-
-        endTest(
-            conn, 
-            "test1:insert/delete of " + num_rows + 
-                " rows with blob(" + blob_size + ")"); 
-    }
-
-    /**
-     * Test reclaim of sequence of deleted blobs.
-     * <p>
-     * Simulates a "queue" of work of input "work_size".  Inserts "work_size"
-     * elements, and then subsequently in each transaction inserts a new 
-     * work item and deletes the oldest work item.  Checks that the used
-     * space reaches a steady state, rather than constantly growing.
-     *
-     **/
-    public void test2(
-    Connection  conn, 
-    int         blob_size, 
-    int         work_size, 
-    int         total_work)
-        throws SQLException
-    {
-        byte[]  long_byteVal    = new byte[blob_size];
-        byte[]  short_byteVal   = new byte[10];
-
-        beginTest(
-            conn, 
-            "test2:queue of " + work_size + 
-                " rows with blob(" + blob_size + "), total_work = " + 
-                total_work); 
-
-        Arrays.fill(long_byteVal,  (byte)'L');
-        Arrays.fill(short_byteVal, (byte)'S');
-
-        createTable(
-            conn, 
-            "longcol", 
-            "create table longcol (id int primary key not null, val blob(" + 
-            blob_size + "))");
-
-        conn.commit();
-
-        PreparedStatement ins_stmt = 
-            conn.prepareStatement("insert into longcol values (?, ?)");
-        PreparedStatement del_stmt = 
-            conn.prepareStatement("delete from longcol where id = ?");
-
-        // insert the "work_size" number of elements into the table
-        for (int iter = 0; iter < work_size; iter++)
-        {
-            // insert the long blob
-            ins_stmt.setInt(  1, iter);
-            ins_stmt.setBytes(2, long_byteVal);
-            ins_stmt.executeUpdate();
-
-            // commit the xact, post commit should kick in to reclaim the
-            // blob space sometime after the commit.
-        }
-        conn.commit();
-
-
-        // for each subsequent work item, queue it to the end and delete
-        // the oldes existing work item.
-        for (int iter = work_size; iter < total_work; iter++)
-        {
-            // insert the long blob
-            ins_stmt.setInt(  1, iter);
-            ins_stmt.setBytes(2, long_byteVal);
-            ins_stmt.executeUpdate();
-
-
-            // delete the long blob
-            del_stmt.setInt(1, iter - work_size - 1);
-            del_stmt.executeUpdate();
-
-            // commit the xact, post commit should kick in to reclaim the
-            // blob space sometime after the commit.
-            conn.commit();
-
-            try
-            {
-                Thread.sleep(20);
-            }
-            catch (Exception ex)
-            {
-                // just ignore interupts of sleep.
-            }
-        }
-
-
-        int[] sp_info = getSpaceInfo(conn, "APP", "LONGCOL", true);
-
-        int total_pages = 
-            sp_info[SPACE_INFO_NUM_ALLOC] + sp_info[SPACE_INFO_NUM_FREE];
-
-        // Expect at least allocated pages * 10 for each item in work_size, 
-        // plus some overhead for 1st page and such.
-        // Free page count depends on how quick post commit can free before
-        // subsequent insert, and very likely is machine/jvm/os dependent. In
-        // my testing adding a sleep of 100 ms. to the above insert/delete
-        // loop changed free from 60 to 30.  Minimum is 10 for the one row 
-        // that is deleted in the same xact as the first inserted row in the 
-        // insert/delete loop.  The 30 below is expected allocate of 10
-        // per work size, and then a guess at how fast post commit can keep
-        // up with free pages.  Run the test with total_work reasonably 
-        // bigger than worksize, something like work_size=5 and total_work >100
-        int total_expected_page_max = 30 * work_size; 
-
-        if (total_pages > total_expected_page_max)
-        {
-            System.out.println(
-                "Test failed, expected less than " + 
-                total_expected_page_max + " pages - count is:\n" +
-                "free pages     : "   + sp_info[SPACE_INFO_NUM_FREE] +
-                "\nallocated pages: " + sp_info[SPACE_INFO_NUM_ALLOC]);
-        }
-
-        if (verbose)
-        {
-            System.out.println("Space information:");
-
-            System.out.println("isindex = "   + sp_info[SPACE_INFO_IS_INDEX]);
-            System.out.println("num_alloc = " + sp_info[SPACE_INFO_NUM_ALLOC]);
-            System.out.println("num_free = "  + sp_info[SPACE_INFO_NUM_FREE]);
-            System.out.println("page_size = " + sp_info[SPACE_INFO_PAGE_SIZE]);
-            System.out.println(
-                "estimspacesaving = " + sp_info[SPACE_INFO_ESTIMSPACESAVING]);
-        }
-
-        // Run another iteration of the work loop, by now memory should 
-        // have gotten to constant.
-        for (int iter = work_size + total_work; iter < (total_work * 2); iter++)
-        {
-            // insert the long blob
-            ins_stmt.setInt(  1, iter);
-            ins_stmt.setBytes(2, long_byteVal);
-            ins_stmt.executeUpdate();
-
-
-            // delete the long blob
-            del_stmt.setInt(1, iter - work_size - 1);
-            del_stmt.executeUpdate();
-
-            // commit the xact, post commit should kick in to reclaim the
-            // blob space sometime after the commit.
-            conn.commit();
-
-            try
-            {
-                Thread.sleep(100);
-            }
-            catch (Exception ex)
-            {
-                // just ignore interupts of sleep.
-            }
-        }
-
-
-        int[] second_sp_info = getSpaceInfo(conn, "APP", "LONGCOL", true);
-
-        int second_total_pages = 
-            sp_info[SPACE_INFO_NUM_ALLOC] + sp_info[SPACE_INFO_NUM_FREE];
-
-        if (total_pages != second_total_pages)
-        {
-            System.out.println(
-                "Test failed, expected constant memory after second run." +
-                "initial total = " + total_pages +
-                "second total = " + second_total_pages);
-        }
-
-        if (verbose)
-        {
-            System.out.println("Space information:");
-
-            System.out.println("isindex = "   + sp_info[SPACE_INFO_IS_INDEX]);
-            System.out.println("num_alloc = " + sp_info[SPACE_INFO_NUM_ALLOC]);
-            System.out.println("num_free = "  + sp_info[SPACE_INFO_NUM_FREE]);
-            System.out.println("page_size = " + sp_info[SPACE_INFO_PAGE_SIZE]);
-            System.out.println(
-                "estimspacesaving = " + sp_info[SPACE_INFO_ESTIMSPACESAVING]);
-        }
-
-        endTest(
-            conn, 
-            "test2:queue of " + work_size + 
-                " rows with blob(" + blob_size + "), total_work = " + 
-                total_work); 
-    }
-
-
-    public void testList(Connection conn)
-        throws SQLException
-    {
-        test1(conn, 250000, 20);
-        test2(conn, 250000, 5, 500);
-    }
-
-    public static void main(String[] argv) 
-        throws Throwable
-    {
-        st_reclaim_longcol test = new st_reclaim_longcol();
-
-        ij.getPropertyArg(argv); 
-        Connection conn = ij.startJBMS();
-
-        try
-        {
-            test.testList(conn);
-        }
-        catch (SQLException sqle)
-        {
-			org.apache.derby.tools.JDBCDisplayUtil.ShowSQLException(
-                System.out, sqle);
-			sqle.printStackTrace(System.out);
-		}
-    }
-}
+/*
+
+   Derby - Class org.apache.derbyTesting.functionTests.harness.procedure
+
+   Copyright 2005 The Apache Software Foundation or its licensors, as applicable.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+
+package org.apache.derbyTesting.functionTests.tests.storetests;
+
+
+import org.apache.derby.iapi.services.sanity.SanityManager;
+
+import org.apache.derbyTesting.functionTests.tests.store.BaseTest;
+
+import java.sql.CallableStatement;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import java.util.Arrays;
+
+import org.apache.derby.tools.ij;
+
+
+/**
+
+The purpose of this test space reclamation of long rows and long columns.
+This addresses DERBY-670.
+
+The main issue is that previous to fixes for DERBY-670, space reclamation
+was only automatically queued when the last row on a page was deleted.  In
+the case of long columns, the actual row on the main page can be quite small
+as the long data is streamed onto other pages.  So the table can grow 
+unexpectedly quite large before the default space reclamation kicks in.  The
+change queues space reclamation in the case of long columns (blob/clob),
+imediately post commit of the single delete.
+
+The testing strategy is to loop doing insert, delete, commit of a blob for
+a number of iterations and check that the actual size of the table is 
+reasonable.  A sleep will be added to allow time for post commit to catch up
+as the test may be run in a number of environments with varying performance
+of background activities.
+
+**/
+
+public class st_reclaim_longcol extends BaseTest
+{
+    static boolean verbose = false;
+
+    public st_reclaim_longcol()
+    {
+    }
+
+
+    /**
+     * Create the base table.
+     **/
+    private static void setup()
+        throws Exception
+    {
+    }
+
+    /**
+     * Test reclaim of a single deleted blob on a page with non-deleted rows.
+     * <p>
+     * loops through inserting alternating long and short column rows resulting
+     * in pages with 1 short and one long.  Deletes the long column row and
+     * tests that space from the long column row is reclaimed even though
+     * there are non-deleted rows on the page.
+     **/
+    private static final int SHORT_BLOB_SIZE = 10;
+    public void test1(Connection conn, int blob_size, int num_rows)
+        throws SQLException
+    {
+        byte[]  long_byteVal    = new byte[blob_size];
+        byte[]  short_byteVal   = new byte[10];
+
+        beginTest(
+            conn, 
+            "test1:insert/delete of " + num_rows + 
+                " rows with blob(" + blob_size + ")"); 
+
+        Arrays.fill(long_byteVal,  (byte)'L');
+        Arrays.fill(short_byteVal, (byte)'S');
+
+        createTable(
+            conn, 
+            "longcol", 
+            "create table longcol (id int primary key not null, val blob(" + 
+            blob_size + "))");
+
+        conn.commit();
+
+        PreparedStatement ins_stmt = 
+            conn.prepareStatement("insert into longcol values (?, ?)");
+        PreparedStatement del_stmt = 
+            conn.prepareStatement("delete from longcol where id = ?");
+
+        // worst case is a mixture of rows with long columns and those without.
+        // Insert of row with a long column always first goes onto a new 
+        // page by itself, but subsequent non-long column rows can be inserted
+        // on that page.  Then when the long column row is deleted - before the
+        // change - it and all it's chain won't get reclaimed until all rows
+        // on the page get deleted.
+
+        // now do insert/delete/commit for subsequent rows.  Before fix the
+        // space used in the table will grow until the deleted rows do not
+        // fit on the first page.  And even then before the fix the rows
+        // on the first page are never reclaimed as the 1st one is never
+        // deleted.
+        for (int iter = 1; iter < num_rows; iter++)
+        {
+            // insert the long blob
+            ins_stmt.setInt(  1, iter);
+            ins_stmt.setBytes(2, long_byteVal);
+            ins_stmt.executeUpdate();
+
+            // insert the short blob
+            ins_stmt.setInt(  1, -(iter));
+            ins_stmt.setBytes(2, short_byteVal);
+            ins_stmt.executeUpdate();
+
+            // delete the long blob
+            del_stmt.setInt(1, iter);
+            del_stmt.executeUpdate();
+
+            // commit the xact, post commit should kick in to reclaim the
+            // blob space sometime after the commit.
+            conn.commit();
+
+            // sleep, just in case on this machine background
+            // post commit is slow.
+            try
+            {
+                Thread.sleep(20);
+            }
+            catch (Exception ex)
+            {
+                // just ignore interupts of sleep.
+            }
+        }
+
+        int[] sp_info = getSpaceInfo(conn, "APP", "LONGCOL", true);
+
+        int total_pages = 
+            sp_info[SPACE_INFO_NUM_ALLOC] + sp_info[SPACE_INFO_NUM_FREE];
+
+        int total_expected_page_max = 12 + num_rows;
+
+        if (total_pages > total_expected_page_max)
+        {
+            // for the above test case we expect the following space:
+            //     page 0
+            //     page 1 
+            //     free space from 1 blob - 9 pages per blob
+            //     allocated page per long/short blob insert.  Each long
+            //         inserts onto a new page to try and fit it entirely
+            //         on a page.  Then the short blob goes to last inserted
+            //         page.  This process repeats.  The previous pages are
+            //         marked "half-filled" and can be used in future for
+            //         short rows that don't fit on the last page inserted.
+            
+
+
+            System.out.println(
+                "Test failed, expected less than " + 
+                total_expected_page_max + " pages - count is:\n" +
+                "free pages     : "   + sp_info[SPACE_INFO_NUM_FREE] +
+                "\nallocated pages: " + sp_info[SPACE_INFO_NUM_ALLOC]);
+        }
+
+        if (verbose)
+        {
+            System.out.println(
+                "Space information after " + num_rows + 
+                "insert/delete pairs of rows in longcol table containing " + 
+                blob_size + "blobs:");
+
+            System.out.println("isindex = "   + sp_info[SPACE_INFO_IS_INDEX]);
+            System.out.println("num_alloc = " + sp_info[SPACE_INFO_NUM_ALLOC]);
+            System.out.println("num_free = "  + sp_info[SPACE_INFO_NUM_FREE]);
+            System.out.println("page_size = " + sp_info[SPACE_INFO_PAGE_SIZE]);
+            System.out.println(
+                "estimspacesaving = " + sp_info[SPACE_INFO_ESTIMSPACESAVING]);
+        }
+
+        endTest(
+            conn, 
+            "test1:insert/delete of " + num_rows + 
+                " rows with blob(" + blob_size + ")"); 
+    }
+
+    /**
+     * Test reclaim of sequence of deleted blobs.
+     * <p>
+     * Simulates a "queue" of work of input "work_size".  Inserts "work_size"
+     * elements, and then subsequently in each transaction inserts a new 
+     * work item and deletes the oldest work item.  Checks that the used
+     * space reaches a steady state, rather than constantly growing.
+     *
+     **/
+    public void test2(
+    Connection  conn, 
+    int         blob_size, 
+    int         work_size, 
+    int         total_work)
+        throws SQLException
+    {
+        byte[]  long_byteVal    = new byte[blob_size];
+        byte[]  short_byteVal   = new byte[10];
+
+        beginTest(
+            conn, 
+            "test2:queue of " + work_size + 
+                " rows with blob(" + blob_size + "), total_work = " + 
+                total_work); 
+
+        Arrays.fill(long_byteVal,  (byte)'L');
+        Arrays.fill(short_byteVal, (byte)'S');
+
+        createTable(
+            conn, 
+            "longcol", 
+            "create table longcol (id int primary key not null, val blob(" + 
+            blob_size + "))");
+
+        conn.commit();
+
+        PreparedStatement ins_stmt = 
+            conn.prepareStatement("insert into longcol values (?, ?)");
+        PreparedStatement del_stmt = 
+            conn.prepareStatement("delete from longcol where id = ?");
+
+        // insert the "work_size" number of elements into the table
+        for (int iter = 0; iter < work_size; iter++)
+        {
+            // insert the long blob
+            ins_stmt.setInt(  1, iter);
+            ins_stmt.setBytes(2, long_byteVal);
+            ins_stmt.executeUpdate();
+
+            // commit the xact, post commit should kick in to reclaim the
+            // blob space sometime after the commit.
+        }
+        conn.commit();
+
+
+        // for each subsequent work item, queue it to the end and delete
+        // the oldes existing work item.
+        for (int iter = work_size; iter < total_work; iter++)
+        {
+            // insert the long blob
+            ins_stmt.setInt(  1, iter);
+            ins_stmt.setBytes(2, long_byteVal);
+            ins_stmt.executeUpdate();
+
+
+            // delete the long blob
+            del_stmt.setInt(1, iter - work_size - 1);
+            del_stmt.executeUpdate();
+
+            // commit the xact, post commit should kick in to reclaim the
+            // blob space sometime after the commit.
+            conn.commit();
+
+            try
+            {
+                Thread.sleep(20);
+            }
+            catch (Exception ex)
+            {
+                // just ignore interupts of sleep.
+            }
+        }
+
+
+        int[] sp_info = getSpaceInfo(conn, "APP", "LONGCOL", true);
+
+        int total_pages = 
+            sp_info[SPACE_INFO_NUM_ALLOC] + sp_info[SPACE_INFO_NUM_FREE];
+
+        // Expect at least allocated pages * 10 for each item in work_size, 
+        // plus some overhead for 1st page and such.
+        // Free page count depends on how quick post commit can free before
+        // subsequent insert, and very likely is machine/jvm/os dependent. In
+        // my testing adding a sleep of 100 ms. to the above insert/delete
+        // loop changed free from 60 to 30.  Minimum is 10 for the one row 
+        // that is deleted in the same xact as the first inserted row in the 
+        // insert/delete loop.  The 30 below is expected allocate of 10
+        // per work size, and then a guess at how fast post commit can keep
+        // up with free pages.  Run the test with total_work reasonably 
+        // bigger than worksize, something like work_size=5 and total_work >100
+        int total_expected_page_max = 30 * work_size; 
+
+        if (total_pages > total_expected_page_max)
+        {
+            System.out.println(
+                "Test failed, expected less than " + 
+                total_expected_page_max + " pages - count is:\n" +
+                "free pages     : "   + sp_info[SPACE_INFO_NUM_FREE] +
+                "\nallocated pages: " + sp_info[SPACE_INFO_NUM_ALLOC]);
+        }
+
+        if (verbose)
+        {
+            System.out.println("Space information:");
+
+            System.out.println("isindex = "   + sp_info[SPACE_INFO_IS_INDEX]);
+            System.out.println("num_alloc = " + sp_info[SPACE_INFO_NUM_ALLOC]);
+            System.out.println("num_free = "  + sp_info[SPACE_INFO_NUM_FREE]);
+            System.out.println("page_size = " + sp_info[SPACE_INFO_PAGE_SIZE]);
+            System.out.println(
+                "estimspacesaving = " + sp_info[SPACE_INFO_ESTIMSPACESAVING]);
+        }
+
+        // Run another iteration of the work loop, by now memory should 
+        // have gotten to constant.
+        for (int iter = work_size + total_work; iter < (total_work * 2); iter++)
+        {
+            // insert the long blob
+            ins_stmt.setInt(  1, iter);
+            ins_stmt.setBytes(2, long_byteVal);
+            ins_stmt.executeUpdate();
+
+
+            // delete the long blob
+            del_stmt.setInt(1, iter - work_size - 1);
+            del_stmt.executeUpdate();
+
+            // commit the xact, post commit should kick in to reclaim the
+            // blob space sometime after the commit.
+            conn.commit();
+
+            try
+            {
+                Thread.sleep(100);
+            }
+            catch (Exception ex)
+            {
+                // just ignore interupts of sleep.
+            }
+        }
+
+
+        int[] second_sp_info = getSpaceInfo(conn, "APP", "LONGCOL", true);
+
+        int second_total_pages = 
+            sp_info[SPACE_INFO_NUM_ALLOC] + sp_info[SPACE_INFO_NUM_FREE];
+
+        if (total_pages != second_total_pages)
+        {
+            System.out.println(
+                "Test failed, expected constant memory after second run." +
+                "initial total = " + total_pages +
+                "second total = " + second_total_pages);
+        }
+
+        if (verbose)
+        {
+            System.out.println("Space information:");
+
+            System.out.println("isindex = "   + sp_info[SPACE_INFO_IS_INDEX]);
+            System.out.println("num_alloc = " + sp_info[SPACE_INFO_NUM_ALLOC]);
+            System.out.println("num_free = "  + sp_info[SPACE_INFO_NUM_FREE]);
+            System.out.println("page_size = " + sp_info[SPACE_INFO_PAGE_SIZE]);
+            System.out.println(
+                "estimspacesaving = " + sp_info[SPACE_INFO_ESTIMSPACESAVING]);
+        }
+
+        endTest(
+            conn, 
+            "test2:queue of " + work_size + 
+                " rows with blob(" + blob_size + "), total_work = " + 
+                total_work); 
+    }
+
+
+    public void testList(Connection conn)
+        throws SQLException
+    {
+        test1(conn, 250000, 20);
+        test2(conn, 250000, 5, 500);
+    }
+
+    public static void main(String[] argv) 
+        throws Throwable
+    {
+        st_reclaim_longcol test = new st_reclaim_longcol();
+
+        ij.getPropertyArg(argv); 
+        Connection conn = ij.startJBMS();
+
+        try
+        {
+            test.testList(conn);
+        }
+        catch (SQLException sqle)
+        {
+			org.apache.derby.tools.JDBCDisplayUtil.ShowSQLException(
+                System.out, sqle);
+			sqle.printStackTrace(System.out);
+		}
+    }
+}

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