You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by th...@apache.org on 2011/11/08 11:15:51 UTC
svn commit: r1199173 - in /jackrabbit/sandbox/microkernel/src:
main/java/org/apache/jackrabbit/mk/util/SynchronizedVerifier.java
test/java/org/apache/jackrabbit/mk/util/SynchronizedVerifierTest.java
Author: thomasm
Date: Tue Nov 8 10:15:51 2011
New Revision: 1199173
URL: http://svn.apache.org/viewvc?rev=1199173&view=rev
Log:
Utility to help test concurrency problems.
Added:
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/SynchronizedVerifier.java
jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/util/SynchronizedVerifierTest.java
Added: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/SynchronizedVerifier.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/SynchronizedVerifier.java?rev=1199173&view=auto
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/SynchronizedVerifier.java (added)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/SynchronizedVerifier.java Tue Nov 8 10:15:51 2011
@@ -0,0 +1,90 @@
+/*
+ * 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.jackrabbit.mk.util;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * A utility class that allows to verify access to a resource is synchronized.
+ */
+public class SynchronizedVerifier {
+
+ private static volatile boolean enabled;
+ private static final Map<Class<?>, AtomicBoolean> DETECT =
+ Collections.synchronizedMap(new HashMap<Class<?>, AtomicBoolean>());
+ private static final Map<Object, Boolean> CURRENT =
+ Collections.synchronizedMap(new IdentityHashMap<Object, Boolean>());
+
+ /**
+ * Enable or disable detection for a given class.
+ *
+ * @param clazz the class
+ * @param value the new value (true means detection is enabled)
+ */
+ public static void setDetect(Class<?> clazz, boolean value) {
+ if (value) {
+ DETECT.put(clazz, new AtomicBoolean());
+ } else {
+ AtomicBoolean b = DETECT.remove(clazz);
+ if (b == null) {
+ throw new AssertionError("Detection was not enabled");
+ } else if (!b.get()) {
+ throw new AssertionError("No object of this class was tested");
+ }
+ }
+ enabled = DETECT.size() > 0;
+ }
+
+ /**
+ * Verify the object is not accessed concurrently.
+ *
+ * @param o the object
+ * @param write if the object is modified
+ */
+ public static void check(Object o, boolean write) {
+ if (enabled) {
+ detectConcurrentAccess(o, write);
+ }
+ }
+
+ private static void detectConcurrentAccess(Object o, boolean write) {
+ AtomicBoolean value = DETECT.get(o.getClass());
+ if (value != null) {
+ value.set(true);
+ Boolean old = CURRENT.put(o, write);
+ if (old != null) {
+ if (write || old) {
+ throw new AssertionError("Concurrent write access");
+ }
+ }
+ try {
+ Thread.sleep(1);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ old = CURRENT.remove(o);
+ if (old == null && write) {
+ throw new AssertionError("Concurrent write access");
+ }
+ }
+ }
+
+}
Added: jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/util/SynchronizedVerifierTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/util/SynchronizedVerifierTest.java?rev=1199173&view=auto
==============================================================================
--- jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/util/SynchronizedVerifierTest.java (added)
+++ jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/util/SynchronizedVerifierTest.java Tue Nov 8 10:15:51 2011
@@ -0,0 +1,81 @@
+/*
+ * 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.jackrabbit.mk.util;
+
+import java.util.concurrent.atomic.AtomicInteger;
+import junit.framework.TestCase;
+import org.apache.jackrabbit.mk.util.Concurrent.Task;
+
+/**
+ * Tests the SynchronizedVerifier
+ */
+public class SynchronizedVerifierTest extends TestCase {
+
+ public void testReadRead() throws Exception {
+ final AtomicInteger x = new AtomicInteger();
+ SynchronizedVerifier.setDetect(AtomicInteger.class, true);
+ Concurrent.run(new Task() {
+ public void call() throws Exception {
+ SynchronizedVerifier.check(x, false);
+ x.get();
+ }
+ });
+ SynchronizedVerifier.setDetect(AtomicInteger.class, false);
+ }
+
+ public void testReadWrite() throws Exception {
+ final AtomicInteger x = new AtomicInteger();
+ SynchronizedVerifier.setDetect(AtomicInteger.class, true);
+ try {
+ Concurrent.run(new Task() {
+ public void call() throws Exception {
+ if (Thread.currentThread().getName().endsWith("1")) {
+ SynchronizedVerifier.check(x, true);
+ x.set(1);
+ } else {
+ SynchronizedVerifier.check(x, false);
+ x.get();
+ }
+ }
+ });
+ fail();
+ } catch (AssertionError e) {
+ // expected
+ } finally {
+ SynchronizedVerifier.setDetect(AtomicInteger.class, false);
+ }
+ }
+
+ public void testWriteWrite() throws Exception {
+ final AtomicInteger x = new AtomicInteger();
+ SynchronizedVerifier.setDetect(AtomicInteger.class, true);
+ try {
+ Concurrent.run(new Task() {
+ public void call() throws Exception {
+ SynchronizedVerifier.check(x, true);
+ x.set(1);
+ }
+ });
+ fail();
+ } catch (AssertionError e) {
+ // expected
+ } finally {
+ SynchronizedVerifier.setDetect(AtomicInteger.class, false);
+ }
+ }
+
+}