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