dcb45f404e50b2b8ff2323ce844d09f3e50ad7f7
[yangtools.git] / common / util / src / main / java / org / opendaylight / yangtools / util / concurrent / TrackingLinkedBlockingQueue.java
1 /*
2  * Copyright (c) 2014 Brocade Communications 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 package org.opendaylight.yangtools.util.concurrent;
9
10 import com.google.common.annotations.Beta;
11 import java.lang.invoke.MethodHandles;
12 import java.lang.invoke.VarHandle;
13 import java.util.Collection;
14 import java.util.concurrent.LinkedBlockingQueue;
15 import java.util.concurrent.TimeUnit;
16 import org.eclipse.jdt.annotation.NonNull;
17
18 /**
19  * A {@link LinkedBlockingQueue} that tracks the largest queue size for debugging.
20  *
21  * @author Thomas Pantelis
22  *
23  * @param <E> the element t.ype
24  */
25 public class TrackingLinkedBlockingQueue<E> extends LinkedBlockingQueue<E> {
26     @java.io.Serial
27     private static final long serialVersionUID = 1L;
28
29     private static final VarHandle LARGEST_QUEUE_SIZE;
30
31     static {
32         try {
33             LARGEST_QUEUE_SIZE = MethodHandles.lookup()
34                 .findVarHandle(TrackingLinkedBlockingQueue.class, "largestQueueSize", int.class);
35         } catch (NoSuchFieldException | IllegalAccessException e) {
36             throw new ExceptionInInitializerError(e);
37         }
38     }
39
40     /**
41      * Holds largestQueueSize, this field should be only updated using {@link #LARGEST_QUEUE_SIZE}.
42      */
43     private volatile int largestQueueSize;
44
45     /**
46      * See {@link LinkedBlockingQueue#LinkedBlockingQueue()}.
47      */
48     public TrackingLinkedBlockingQueue() {
49     }
50
51     /**
52      * See {@link LinkedBlockingQueue#LinkedBlockingQueue(Collection)}.
53      */
54     @SuppressWarnings("checkstyle:parameterName")
55     public TrackingLinkedBlockingQueue(final @NonNull Collection<? extends E> c) {
56         super(c);
57     }
58
59     /**
60      * See {@link LinkedBlockingQueue#LinkedBlockingQueue(int)}.
61      */
62     public TrackingLinkedBlockingQueue(final int capacity) {
63         super(capacity);
64     }
65
66     /**
67      * Returns the largest queue size.
68      */
69     @Beta
70     // FIXME: 11.0.0: return int
71     public long getLargestQueueSize() {
72         return largestQueueSize;
73     }
74
75     @Override
76     @SuppressWarnings("checkstyle:parameterName")
77     public boolean offer(final E e, final long timeout, final TimeUnit unit) throws InterruptedException {
78         if (super.offer(e, timeout, unit)) {
79             updateLargestQueueSize();
80             return true;
81         }
82
83         return false;
84     }
85
86     @Override
87     @SuppressWarnings("checkstyle:parameterName")
88     public boolean offer(final E e) {
89         if (super.offer(e)) {
90             updateLargestQueueSize();
91             return true;
92         }
93
94         return false;
95     }
96
97     @Override
98     @SuppressWarnings("checkstyle:parameterName")
99     public void put(final E e) throws InterruptedException {
100         super.put(e);
101         updateLargestQueueSize();
102     }
103
104     @Override
105     @SuppressWarnings("checkstyle:parameterName")
106     public boolean add(final E e) {
107         boolean result = super.add(e);
108         updateLargestQueueSize();
109         return result;
110     }
111
112     @Override
113     @SuppressWarnings("checkstyle:parameterName")
114     public boolean addAll(final Collection<? extends E> c) {
115         try {
116             return super.addAll(c);
117         } finally {
118             updateLargestQueueSize();
119         }
120     }
121
122     private void updateLargestQueueSize() {
123         final int size = size();
124
125         int largest = (int) LARGEST_QUEUE_SIZE.getAcquire(this);
126         while (largest < size) {
127             largest = (int) LARGEST_QUEUE_SIZE.compareAndExchangeRelease(this, largest, size);
128         }
129     }
130 }