EMMA Coverage Report (generated Sun Mar 01 22:06:14 CET 2015)
[all classes][org.h2.util]

COVERAGE SUMMARY FOR SOURCE FILE [AbbaDetector.java]

nameclass, %method, %block, %line, %
AbbaDetector.java100% (2/2)25%  (2/8)8%   (16/201)8%   (4/51)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class AbbaDetector100% (1/1)17%  (1/6)7%   (13/194)6%   (3/49)
AbbaDetector (): void 0%   (0/1)0%   (0/3)0%   (0/1)
begin (Object): Object 0%   (0/1)0%   (0/45)0%   (0/16)
getObjectName (Object): String 0%   (0/1)0%   (0/14)0%   (0/1)
getTest (Object): Object 0%   (0/1)0%   (0/2)0%   (0/1)
markHigher (Object, Deque): void 0%   (0/1)0%   (0/117)0%   (0/27)
<static initializer> 100% (1/1)100% (13/13)100% (3/3)
     
class AbbaDetector$1100% (1/1)50%  (1/2)43%  (3/7)50%  (1/2)
initialValue (): Deque 0%   (0/1)0%   (0/4)0%   (0/1)
AbbaDetector$1 (): void 100% (1/1)100% (3/3)100% (1/1)

1/*
2 * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
3 * and the EPL 1.0 (http://h2database.com/html/license.html).
4 * Initial Developer: H2 Group
5 */
6package org.h2.util;
7 
8import java.util.ArrayDeque;
9import java.util.Deque;
10import java.util.HashSet;
11import java.util.Map;
12import java.util.Set;
13import java.util.WeakHashMap;
14 
15/**
16 * Utility to detect AB-BA deadlocks.
17 */
18public class AbbaDetector {
19 
20    private static final boolean TRACE = false;
21 
22    private static final ThreadLocal<Deque<Object>> STACK =
23            new ThreadLocal<Deque<Object>>() {
24                @Override protected Deque<Object> initialValue() {
25                    return new ArrayDeque<Object>();
26            }
27        };
28 
29    /**
30     * Map of (object A) -> (
31     *      map of (object locked before object A) ->
32     *      (stack trace where locked) )
33     */
34    private static final Map<Object, Map<Object, Exception>> LOCK_ORDERING =
35            new WeakHashMap<Object, Map<Object, Exception>>();
36 
37    private static final Set<String> KNOWN_DEADLOCKS = new HashSet<String>();
38 
39    /**
40     * This method is called just before or just after an object is
41     * synchronized.
42     *
43     * @param o the object, or null for the current class
44     * @return the object that was passed
45     */
46    public static Object begin(Object o) {
47        if (o == null) {
48            o = new SecurityManager() {
49                Class<?> clazz = getClassContext()[2];
50            }.clazz;
51        }
52        Deque<Object> stack = STACK.get();
53        if (!stack.isEmpty()) {
54            // Ignore locks which are locked multiple times in succession -
55            // Java locks are recursive
56            if (stack.contains(o)) {
57                // already synchronized on this
58                return o;
59            }
60            while (!stack.isEmpty()) {
61                Object last = stack.peek();
62                if (Thread.holdsLock(last)) {
63                    break;
64                }
65                stack.pop();
66            }
67        }
68        if (TRACE) {
69            String thread = "[thread " + Thread.currentThread().getId() + "]";
70            String indent = new String(new char[stack.size() * 2]).replace((char) 0, ' ');
71            System.out.println(thread + " " + indent +
72                    "sync " + getObjectName(o));
73        }
74        if (stack.size() > 0) {
75            markHigher(o, stack);
76        }
77        stack.push(o);
78        return o;
79    }
80 
81    private static Object getTest(Object o) {
82        // return o.getClass();
83        return o;
84    }
85 
86    private static String getObjectName(Object o) {
87        return o.getClass().getSimpleName() + "@" + System.identityHashCode(o);
88    }
89 
90    private static synchronized void markHigher(Object o, Deque<Object> older) {
91        Object test = getTest(o);
92        Map<Object, Exception> map = LOCK_ORDERING.get(test);
93        if (map == null) {
94            map = new WeakHashMap<Object, Exception>();
95            LOCK_ORDERING.put(test, map);
96        }
97        Exception oldException = null;
98        for (Object old : older) {
99            Object oldTest = getTest(old);
100            if (oldTest == test) {
101                continue;
102            }
103            Map<Object, Exception> oldMap = LOCK_ORDERING.get(oldTest);
104            if (oldMap != null) {
105                Exception e = oldMap.get(test);
106                if (e != null) {
107                    String deadlockType = test.getClass() + " " + oldTest.getClass();
108                    if (!KNOWN_DEADLOCKS.contains(deadlockType)) {
109                        String message = getObjectName(test) +
110                                " synchronized after \n " + getObjectName(oldTest) +
111                                ", but in the past before";
112                        RuntimeException ex = new RuntimeException(message);
113                        ex.initCause(e);
114                        ex.printStackTrace(System.out);
115                        // throw ex;
116                        KNOWN_DEADLOCKS.add(deadlockType);
117                    }
118                }
119            }
120            if (!map.containsKey(oldTest)) {
121                if (oldException == null) {
122                    oldException = new Exception("Before");
123                }
124                map.put(oldTest, oldException);
125            }
126        }
127    }
128 
129}

[all classes][org.h2.util]
EMMA 2.0.5312 (C) Vladimir Roubtsov