File: ModuleLoadingTest.java

package info (click to toggle)
derby 10.14.2.0-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 79,056 kB
  • sloc: java: 691,961; sql: 42,686; xml: 20,512; sh: 3,373; sed: 96; makefile: 60
file content (138 lines) | stat: -rw-r--r-- 5,230 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
 * Derby - Class org.apache.derbyTesting.functionTests.tests.engine.ModuleLoadingTest
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.engine;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.ArrayList;
import junit.framework.Test;
import org.apache.derbyTesting.junit.BaseJDBCTestCase;
import org.apache.derbyTesting.junit.BaseTestSuite;
import org.apache.derbyTesting.junit.JDBC;
import org.apache.derbyTesting.junit.TestConfiguration;

/**
 * This class contains tests for correct loading (booting) of modules
 * and factories.
 */
public class ModuleLoadingTest extends BaseJDBCTestCase {
    public ModuleLoadingTest(String name) {
        super(name);
    }

    public static Test suite() {
        BaseTestSuite ts = new BaseTestSuite();

        // Run concurrentLoadingOfSortFactory in a separate database so that
        // the sort factory isn't already loaded.
        ts.addTest(TestConfiguration.singleUseDatabaseDecorator(
                new ModuleLoadingTest("concurrentLoadingOfSortFactory")));

        return ts;
    }

    /**
     * Test case for DERBY-2074. When multiple threads tried to load
     * ExternalSortFactory concurrently, we sometimes got a
     * NullPointerException.
     */
    public void concurrentLoadingOfSortFactory() throws Throwable {
        // number of concurrent threads
        final int numThreads = 10;

        // Helper object to make it easier to refer to ModuleLoadingTest.this
        // from within the nested Runnable class. Used for synchronization
        // between the threads.
        final Object me = this;

        // Flag that tells the threads whether they're allowed to start.
        final boolean[] go = new boolean[1];
        // Active threads count.
        final int[] activeThreads = new int[1];
        // List of exceptions/throwables thrown by the forked threads.
        final ArrayList<Throwable> exceptions = new ArrayList<Throwable>();

        Thread[] threads = new Thread[numThreads];

        // Start the threads.
        for (int i = 0; i < numThreads; i++) {
            final Connection c = openDefaultConnection();
            // Prepare a statement that ends up calling
            // DistinctScalarAggregateResultSet.loadSorter().
            final PreparedStatement ps = c.prepareStatement(
                    "select count(distinct tablename) from sys.systables");
            threads[i] = new Thread(new Runnable() {
                public void run() {
                    try {
                        _run();
                    } catch (Throwable t) {
                        synchronized (me) {
                            exceptions.add(t);
                        }
                    }
                }
                private void _run() throws Exception {
                    synchronized (me) {
                        // Notify the main thread that we're ready to execute.
                        activeThreads[0]++;
                        me.notifyAll();

                        // Wait for the main thread to notify us that we
                        // should go ahead.
                        while (!go[0]) {
                            me.wait();
                        }
                    }
                    // executeQuery() below used to get occational NPEs before
                    // DERBY-2074.
                    JDBC.assertDrainResults(ps.executeQuery());
                    ps.close();
                    c.close();
                }
            });
            threads[i].start();
        }

        // We want all threads to execute the statement at the same time,
        // so wait for all threads to be ready before giving them the GO
        // signal.
        synchronized (me) {
            while (activeThreads[0] < numThreads && exceptions.isEmpty()) {
                me.wait();
            }

            // All threads are active, or at least one of the threads have
            // failed, so tell the threads to stop waiting.
            go[0] = true;
            me.notifyAll();
        }

        // The threads have been started, now wait for them to finish.
        for (int i = 0; i < numThreads; i++) {
            threads[i].join();
        }

        // At least one of the threads failed. Re-throw the first error
        // reported.
        if (!exceptions.isEmpty()) {
            throw exceptions.get(0);
        }
    }
}