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