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);
}
}
}
|