001: /*
002: * (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
003: * [See end of file]
004: */
005:
006: package com.hp.hpl.jena.rdf.model.test;
007:
008: import com.hp.hpl.jena.rdf.model.*;
009:
010: import junit.framework.*;
011:
012: /**
013: * @author Andy Seaborne
014: * @version $Id: TestConcurrency.java,v 1.9 2008/01/02 12:04:43 andy_seaborne Exp $
015: */
016: public class TestConcurrency extends TestSuite {
017:
018: /** Creates new RDQLTestSuite */
019: static public TestSuite suite() {
020: return new TestConcurrency();
021: }
022:
023: // Test suite to exercise the locking
024: static long SLEEP = 100;
025: static int threadCount = 0;
026:
027: // Note : reuse the model across tests.
028: final static Model model1 = ModelFactory.createDefaultModel();
029: final static Model model2 = ModelFactory.createDefaultModel();
030:
031: public TestConcurrency() {
032: super ("Model concurrency control");
033:
034: if (true) {
035: // Same model: inner and outer
036: addTest(new Nesting("Lock nesting 1 - same model", model1,
037: ModelLock.READ, ModelLock.READ, false));
038: addTest(new Nesting("Lock nesting 2 - same model", model1,
039: ModelLock.WRITE, ModelLock.WRITE, false));
040: addTest(new Nesting("Lock nesting 3 - same model", model1,
041: ModelLock.READ, ModelLock.WRITE, true));
042: addTest(new Nesting("Lock nesting 4 - same model", model1,
043: ModelLock.WRITE, ModelLock.READ, false));
044:
045: // Different model: inner and outer
046: addTest(new Nesting("Lock nesting 1 - defifferent models",
047: model1, ModelLock.READ, model2, ModelLock.READ,
048: false));
049: addTest(new Nesting("Lock nesting 2 - defifferent models",
050: model1, ModelLock.WRITE, model2, ModelLock.WRITE,
051: false));
052: addTest(new Nesting("Lock nesting 3 - defifferent models",
053: model1, ModelLock.READ, model2, ModelLock.WRITE,
054: false));
055: addTest(new Nesting("Lock nesting 4 - defifferent models",
056: model1, ModelLock.WRITE, model2, ModelLock.READ,
057: false));
058: }
059: if (true) {
060: // Crude test
061: addTest(new Parallel("Parallel concurrency test"));
062: }
063:
064: }
065:
066: static class Nesting extends TestCase {
067: Model outerModel;
068: Model innerModel;
069: boolean outerLock;
070: boolean innerLock;
071: boolean exceptionExpected;
072:
073: // Same model
074: Nesting(String testName, Model model, boolean lock1,
075: boolean lock2, boolean exExpected) {
076: this (testName, model, lock1, model, lock2, exExpected);
077: }
078:
079: // Potetnially different models
080: Nesting(String testName, Model model1, boolean lock1,
081: Model model2, boolean lock2, boolean exExpected) {
082: super (testName);
083: outerModel = model1;
084: outerLock = lock1;
085: innerModel = model2;
086: innerLock = lock2;
087: exceptionExpected = exExpected;
088: }
089:
090: protected void runTest() throws Throwable {
091: boolean gotException = false;
092: try {
093: outerModel.enterCriticalSection(outerLock);
094:
095: try {
096: try {
097: // Should fail if outerLock is READ and innerLock is WRITE
098: // and its on the same model, inner and outer.
099: innerModel.enterCriticalSection(innerLock);
100:
101: } finally {
102: innerModel.leaveCriticalSection();
103: }
104: } catch (Exception ex) {
105: gotException = true;
106: }
107:
108: } finally {
109: outerModel.leaveCriticalSection();
110: }
111:
112: if (exceptionExpected)
113: assertTrue(
114: "Failed to get expected lock promotion error",
115: gotException);
116: else
117: assertTrue("Got unexpected lock promotion error",
118: !gotException);
119: }
120: }
121:
122: static class Parallel extends TestCase {
123: int threadTotal = 10;
124:
125: Parallel(String testName) {
126: super (testName);
127: }
128:
129: protected void runTest() throws Throwable {
130: Model model = ModelFactory.createDefaultModel();
131: Thread threads[] = new Thread[threadTotal];
132:
133: boolean getReadLock = ModelLock.READ;
134: for (int i = 0; i < threadTotal; i++) {
135: String nextId = "T" + Integer.toString(++threadCount);
136: threads[i] = new Operation(model, getReadLock);
137: threads[i].setName(nextId);
138: threads[i].start();
139:
140: getReadLock = !getReadLock;
141: }
142:
143: boolean problems = false;
144: for (int i = 0; i < threadTotal; i++) {
145: try {
146: threads[i].join(200 * SLEEP);
147: } catch (InterruptedException intEx) {
148: }
149: }
150:
151: // Try again for any we missed.
152: for (int i = 0; i < threadTotal; i++) {
153: if (threads[i].isAlive())
154: try {
155: threads[i].join(200 * SLEEP);
156: } catch (InterruptedException intEx) {
157: }
158: if (threads[i].isAlive()) {
159: System.out.println("Thread " + threads[i].getName()
160: + " failed to finish");
161: problems = true;
162: }
163: }
164:
165: assertTrue("Some thread failed to finish", !problems);
166: }
167:
168: class Operation extends Thread {
169: Model model;
170: boolean readLock;
171:
172: Operation(Model m, boolean withReadLock) {
173: model = m;
174: readLock = withReadLock;
175: }
176:
177: public void run() {
178: for (int i = 0; i < 2; i++) {
179: try {
180: model.enterCriticalSection(readLock);
181: if (readLock)
182: readOperation(false);
183: else
184: writeOperation(false);
185: } finally {
186: model.leaveCriticalSection();
187: }
188: }
189: }
190: }
191:
192: // Operations ----------------------------------------------
193:
194: volatile int writers = 0;
195:
196: // The example model operations
197: void doStuff(String label, boolean doThrow) {
198: String id = Thread.currentThread().getName();
199: // Puase a while to cause other threads to (try to) enter the region.
200: try {
201: Thread.sleep(SLEEP);
202: } catch (InterruptedException intEx) {
203: }
204: if (doThrow)
205: throw new RuntimeException(label);
206: }
207:
208: // Example operations
209:
210: public void readOperation(boolean doThrow) {
211: if (writers > 0)
212: System.err
213: .println("Concurrency error: writers around!");
214: doStuff("read operation", false);
215: if (writers > 0)
216: System.err
217: .println("Concurrency error: writers around!");
218: }
219:
220: public void writeOperation(boolean doThrow) {
221: writers++;
222: doStuff("write operation", false);
223: writers--;
224:
225: }
226: }
227: }
228:
229: /*
230: * (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
231: * All rights reserved.
232: *
233: * Redistribution and use in source and binary forms, with or without
234: * modification, are permitted provided that the following conditions
235: * are met:
236: * 1. Redistributions of source code must retain the above copyright
237: * notice, this list of conditions and the following disclaimer.
238: * 2. Redistributions in binary form must reproduce the above copyright
239: * notice, this list of conditions and the following disclaimer in the
240: * documentation and/or other materials provided with the distribution.
241: * 3. The name of the author may not be used to endorse or promote products
242: * derived from this software without specific prior written permission.
243: *
244: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
245: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
246: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
247: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
248: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
249: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
250: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
251: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
253: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
254: */
|