Merge changes Ia7cd7eda,If961a029,I9f6a57a2,Id8551489
[controller.git] / opendaylight / config / config-manager / src / main / java / org / opendaylight / controller / config / manager / impl / DeadlockMonitor.java
1 package org.opendaylight.controller.config.manager.impl;
2
3 import java.util.Deque;
4 import java.util.LinkedList;
5 import java.util.concurrent.TimeUnit;
6 import javax.annotation.Nullable;
7 import javax.annotation.concurrent.GuardedBy;
8 import org.opendaylight.controller.config.api.ModuleIdentifier;
9 import org.slf4j.Logger;
10 import org.slf4j.LoggerFactory;
11
12 public class DeadlockMonitor implements AutoCloseable {
13     private static final Logger LOG = LoggerFactory.getLogger(DeadlockMonitor.class);
14
15     private static final long WARN_AFTER_MILLIS = 5000;
16
17     private final TransactionIdentifier transactionIdentifier;
18     private final DeadlockMonitorRunnable thread;
19     @GuardedBy("this")
20     private final Deque<ModuleIdentifierWithNanos> moduleIdentifierWithNanosStack = new LinkedList<>();
21     @GuardedBy("this")
22     private ModuleIdentifierWithNanos top = ModuleIdentifierWithNanos.EMPTY;
23
24     public DeadlockMonitor(TransactionIdentifier transactionIdentifier) {
25         this.transactionIdentifier = transactionIdentifier;
26         thread = new DeadlockMonitorRunnable();
27         thread.start();
28     }
29
30     public synchronized void setCurrentlyInstantiatedModule(ModuleIdentifier currentlyInstantiatedModule) {
31
32         boolean popping = currentlyInstantiatedModule == null;
33         if (popping) {
34             moduleIdentifierWithNanosStack.pop();
35             if (moduleIdentifierWithNanosStack.isEmpty()) {
36                 top = ModuleIdentifierWithNanos.EMPTY;
37             } else {
38                 top = moduleIdentifierWithNanosStack.peekLast();
39             }
40         } else {
41             ModuleIdentifierWithNanos current = new ModuleIdentifierWithNanos(currentlyInstantiatedModule);
42             moduleIdentifierWithNanosStack.push(current);
43             top = current;
44         }
45         LOG.trace("setCurrentlyInstantiatedModule {}, top {}", currentlyInstantiatedModule, top);
46     }
47
48     public boolean isAlive() {
49         return thread.isAlive();
50     }
51
52     @Override
53     public void close() {
54         thread.interrupt();
55     }
56
57     @Override
58     public String toString() {
59         return "DeadlockMonitor{" + transactionIdentifier + '}';
60     }
61
62     private class DeadlockMonitorRunnable extends Thread {
63
64         private DeadlockMonitorRunnable() {
65             super(DeadlockMonitor.this.toString());
66         }
67
68         @Override
69         public void run() {
70             ModuleIdentifierWithNanos old = new ModuleIdentifierWithNanos(); // null moduleId
71             while (this.isInterrupted() == false) {
72                 ModuleIdentifierWithNanos copy = new ModuleIdentifierWithNanos(DeadlockMonitor.this.top);
73                 if (old.moduleIdentifier == null || old.equals(copy) == false) {
74                     // started
75                     old = copy;
76                 } else {
77                     // is the getInstance() running longer than WARN_AFTER_MILLIS ?
78                     long runningTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - copy.nanoTime);
79                     if (runningTime > WARN_AFTER_MILLIS) {
80                         LOG.warn("{} did not finish after {} ms", copy.moduleIdentifier, runningTime);
81                     }
82                 }
83                 try {
84                     sleep(1000);
85                 } catch (InterruptedException e) {
86                     interrupt();
87                 }
88             }
89             LOG.trace("Exiting {}", this);
90         }
91
92         @Override
93         public String toString() {
94             return "DeadLockMonitorRunnable{" + transactionIdentifier + "}";
95         }
96     }
97
98
99
100
101     private static class ModuleIdentifierWithNanos {
102         private static ModuleIdentifierWithNanos EMPTY = new ModuleIdentifierWithNanos();
103         @Nullable
104         private final ModuleIdentifier moduleIdentifier;
105
106         private final long nanoTime;
107
108         private ModuleIdentifierWithNanos() {
109             this((ModuleIdentifier)null);
110         }
111
112         private ModuleIdentifierWithNanos(ModuleIdentifier moduleIdentifier) {
113             this.moduleIdentifier = moduleIdentifier;
114             nanoTime = System.nanoTime();
115         }
116
117         private ModuleIdentifierWithNanos(ModuleIdentifierWithNanos copy) {
118             moduleIdentifier = copy.moduleIdentifier;
119             nanoTime = copy.nanoTime;
120         }
121
122         @Override
123         public boolean equals(Object o) {
124             if (this == o) {
125                 return true;
126             }
127             if (o == null || getClass() != o.getClass()) {
128                 return false;
129             }
130
131             ModuleIdentifierWithNanos that = (ModuleIdentifierWithNanos) o;
132
133             if (nanoTime != that.nanoTime) {
134                 return false;
135             }
136             if (moduleIdentifier != null ? !moduleIdentifier.equals(that.moduleIdentifier) : that.moduleIdentifier != null) {
137                 return false;
138             }
139
140             return true;
141         }
142
143         @Override
144         public int hashCode() {
145             int result = moduleIdentifier != null ? moduleIdentifier.hashCode() : 0;
146             result = 31 * result + (int) (nanoTime ^ (nanoTime >>> 32));
147             return result;
148         }
149
150         @Override
151         public String toString() {
152             return "ModuleIdentifierWithNanos{" +
153                     moduleIdentifier +
154                     '}';
155         }
156     }
157 }