1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.db.tests.client;
14 import java.util.concurrent.Semaphore;
15 import java.util.concurrent.atomic.AtomicBoolean;
16 import java.util.concurrent.atomic.AtomicInteger;
18 import org.junit.Test;
19 import org.simantics.db.AsyncReadGraph;
20 import org.simantics.db.ReadGraph;
21 import org.simantics.db.Session;
22 import org.simantics.db.WriteGraph;
23 import org.simantics.db.common.TransactionPolicyKeep;
24 import org.simantics.db.common.TransactionPolicyRelease;
25 import org.simantics.db.common.request.ReadRequest;
26 import org.simantics.db.common.request.WriteRequest;
27 import org.simantics.db.exception.DatabaseException;
28 import org.simantics.db.procedure.AsyncProcedure;
29 import org.simantics.db.request.Read;
30 import org.simantics.db.service.LifecycleSupport;
31 import org.simantics.db.service.TransactionPolicySupport;
32 import org.simantics.db.testing.base.ExistingDatabaseTest;
33 import org.simantics.db.testing.common.Tests;
34 import org.simantics.db.testing.impl.Configuration;
36 public class TransactionTest1 extends ExistingDatabaseTest {
38 public void testTransaction1() throws DatabaseException {
43 void empty1() throws DatabaseException {
44 TransactionClient1 client = new TransactionClient1(this);
46 client.setPolicyRelease();
47 client.emptySyncReadLoop();
48 client.setPolicyKeep();
49 client.emptySyncReadLoop();
55 void empty2() throws DatabaseException {
56 TransactionClient1 client = new TransactionClient1(this);
57 TransactionClient2 client2 = new TransactionClient2(this);
59 client2.tryToKeepReadTransaction();
60 client.setPolicyRelease();
61 client.emptySyncReadLoop();
62 client.setPolicyKeep();
63 client.emptySyncReadLoop();
69 public void empty3() throws DatabaseException {
70 TransactionClient1 client = new TransactionClient1(this);
71 TransactionClient2 client2 = new TransactionClient2(this);
73 client2.tryToKeepWriteTransaction();
74 client.setPolicyRelease();
75 client.emptySyncReadLoop();
76 client.setPolicyKeep();
77 client.emptySyncReadLoop();
84 class TranasctionSession {
85 protected static final boolean DEBUG = Configuration.get().debug;
86 protected Session session;
87 TranasctionSession() throws DatabaseException {
88 session = Tests.getTestHandler().getSession();
90 public void close() throws DatabaseException {
92 if (null != session) {
93 LifecycleSupport ls = session.getService(LifecycleSupport.class);
101 class TransctionCommon extends TranasctionSession {
102 protected final ExistingDatabaseTest testCommon;
103 protected final int REQUEST_COUNT = 50;
104 private AtomicInteger counter = new AtomicInteger(0);
105 TransctionCommon(ExistingDatabaseTest testCommon)
106 throws DatabaseException {
107 this.testCommon = testCommon;
109 public void emptySyncReadLoop()
110 throws DatabaseException {
112 long start = System.nanoTime();
113 for(int i = 0; i < REQUEST_COUNT; ++i) {
114 session.syncRequest(new ReadRequest() {
116 public void run(ReadGraph graph) throws DatabaseException {
117 int value = counter.incrementAndGet();
119 System.out.println("DEBUG: Sync read count=" + value);
123 long end = System.nanoTime();
124 double time = (double)(end-start) * (double)(1e-9);
125 if (REQUEST_COUNT != counter.get())
126 throw new DatabaseException("Transaction count does not match. Transaction counter was " + counter);
127 double speed = counter.get() / time;
128 String t = "Transaction speed was " + speed + " empty synchronous read transactions per second.";
130 System.out.println(t);
132 void setPolicyKeep() {
134 System.out.println("Transaction policy is keep.");
135 session.registerService(TransactionPolicySupport.class, new TransactionPolicyKeep());
137 void setPolicyRelease() {
139 System.out.println("Transaction policy is release.");
140 session.registerService(TransactionPolicySupport.class, new TransactionPolicyRelease());
144 class TransactionClient1 extends TransctionCommon {
145 TransactionClient1(ExistingDatabaseTest testCommon)
146 throws DatabaseException {
151 class TransactionClient2 extends TransctionCommon
152 implements TransactionPolicySupport {
153 Thread tryToKeepWrite;
156 AtomicBoolean breakTransaction = new AtomicBoolean(false);
157 Semaphore relinquish = new Semaphore(0);
159 TransactionClient2(ExistingDatabaseTest testCommon)
160 throws DatabaseException {
164 private void init() {
165 synchronized (this) {
168 breakTransaction.set(false);
172 public void tryToKeepReadTransaction()
173 throws DatabaseException {
176 session.registerService(TransactionPolicySupport.class, this);
177 startReadTransaction();
179 public void tryToKeepWriteTransaction()
180 throws DatabaseException {
183 session.registerService(TransactionPolicySupport.class, this);
184 // startWriteTransaction();
185 this.tryToKeepWrite = new Thread(new TryToKeepWrite(), "TryToKeepWrite");
186 this.tryToKeepWrite.start();
189 public boolean holdOnToTransactionAfterRead() {
193 public boolean holdOnToTransactionAfterCancel() {
197 public boolean holdOnToTransactionAfterCommit() {
201 public void onRelinquish() {
202 freeTransactionSync();
206 public void onRelinquishDone() {
207 relinquish.release();
211 public void onRelinquishError() {
212 relinquish.release();
216 } catch (DatabaseException e) {
217 System.out.println("OnRelinquishError: " + e.getMessage() + ".");
224 throws DatabaseException {
226 freeTransactionSync();
227 // This HACK gives time for implementation to remove
228 // the asynchronous call from bookkeeping. At this point
229 // one asynchronous call might still be active.
231 session.syncRequest(new WriteRequest() {
233 public void perform(WriteGraph graph) throws DatabaseException {
236 } catch (DatabaseException e) {
237 System.out.println("Empty sync write failed: " + e.getMessage());
241 void freeTransactionSync() {
242 breakTransaction.set(true);
243 synchronized (this) {
247 TransactionClient2.this.wait();
248 } catch (InterruptedException e) {
249 System.out.println("Wait was interruped: " + e);
254 private void startReadTransaction()
255 throws DatabaseException {
256 session.asyncRequest(new Read<Integer>() {
258 public Integer perform(ReadGraph graph) throws DatabaseException {
259 synchronized (TransactionClient2.this) {
260 TransactionClient2.this.transactionIn();
262 System.out.println("DEBUG: Read request begin ok, count= " + in);
263 while (TransactionClient2.this.transactionKeep()) {
265 TransactionClient2.this.wait();
266 } catch (InterruptedException e) {
268 System.out.println("DEBUG: read request wait interrupted: " + e.getMessage());
274 }, new AsyncProcedure<Integer>() {
276 public void execute(AsyncReadGraph graph, Integer result) {
277 TransactionClient2.this.transactionOut();
279 System.out.println("DEBUG: Read request end ok, count= " + result);
282 public void exception(AsyncReadGraph graph, Throwable throwable) {
283 TransactionClient2.this.transactionOut();
285 System.out.println("DEBUG: read request end failed: " + throwable.getMessage());
288 synchronized (this) {
291 TransactionClient2.this.wait();
292 } catch (InterruptedException e) {
294 System.out.println("DEBUG: read request sleep was interruped: " + e);
299 synchronized boolean transactionKeep() {
300 return !breakTransaction.get();
302 synchronized int transactionIn() {
307 synchronized int transactionOut() {
312 class TryToKeepWrite implements Runnable {
319 session.syncRequest(new WriteRequest() {
321 public void perform(WriteGraph graph) throws DatabaseException {
322 synchronized (TransactionClient2.this) {
323 TransactionClient2.this.transactionIn();
325 System.out.println("DEBUG: Write request begin ok, count= " + in);
326 while (TransactionClient2.this.transactionKeep()) {
328 TransactionClient2.this.wait();
329 } catch (InterruptedException e) {
331 System.out.println("DEBUG: Write request wait interrupted: " + e.getMessage());
337 } catch (DatabaseException e) {
338 System.out.println("Empty sync write failed: " + e.getMessage());
340 TransactionClient2.this.transactionOut();
344 relinquish.acquire();
346 } catch (InterruptedException e) {
348 System.out.println("DEBUG: Relinquish wait interrupted: " + e.getMessage());
351 System.out.println("DEBUG: Write request end, count= " + out);