1 /*
2  * Copyright (c) 2016. Amazon.com, Inc. or its affiliates. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License").
5  * You may not use this file except in compliance with the License.
6  * A copy of the License is located at
7  *
8  * http://aws.amazon.com/apache2.0
9  *
10  * or in the "license" file accompanying this file. This file is distributed
11  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12  * express or implied. See the License for the specific language governing
13  * permissions and limitations under the License.
14  */

15 package com.amazonaws.util;
16
17 /**
18  * Manages capacity of a finite resource.  Capacity can be acquired and
19  * released.
20  */

21 public class CapacityManager {
22
23     private volatile int availableCapacity;
24     private final int maxCapacity;
25
26     private final Object lock = new Object();
27
28     /**
29      * Creates a CapacityManager.
30      *
31      * @param maxCapacity maximum capacity of this resource.
32      *                    available capacity will initially be set to this value.
33      *                    if a negative value is provided the capacity manager will operate in a no-op
34      *                    passthrough mode in which all acquire calls will return true.
35      */

36     public CapacityManager(final int maxCapacity) {
37         this.maxCapacity = maxCapacity;
38         this.availableCapacity = maxCapacity;
39     }
40
41     /**
42      * Attempts to acquire a single capacity unit.
43      * If acquired, capacity will be consumed from the available pool.
44
45      * @return true if capacity can be acquired, false if not
46      */

47     public boolean acquire() {
48         return acquire(1);
49     }
50
51     /**
52      * Attempts to acquire a given amount of capacity.
53      * If acquired, capacity will be consumed from the available pool.
54      *
55      * @param capacity capacity to acquire
56      * @return true if capacity can be acquired, false if not
57      * @throws IllegalArgumentException if given capacity is negative
58      */

59     public boolean acquire(int capacity) {
60         if (capacity < 0) {
61             throw new IllegalArgumentException("capacity to acquire cannot be negative");
62         }
63
64         if (availableCapacity < 0) {
65             return true;
66         }
67
68         synchronized (lock) {
69             if (availableCapacity - capacity >= 0) {
70                 availableCapacity -= capacity;
71                 return true;
72             } else {
73                 return false;
74             }
75         }
76     }
77
78     /**
79      * Releases a single unit of capacity back to the pool, making it available
80      * to consumers.
81      */

82     public void release() {
83         release(1);
84     }
85
86     /**
87      * Releases a given amount of capacity back to the pool, making it available
88      * to consumers.
89      *
90      * @param capacity capacity to release
91      * @throws IllegalArgumentException if given capacity is negative
92      */

93     public void release(int capacity) {
94         if (capacity < 0) {
95             throw new IllegalArgumentException("capacity to release cannot be negative");
96         }
97
98         // in the common 'good' case where we have our full capacity available we can
99         // short circuit going any further and avoid unnecessary locking.
100         if (availableCapacity >= 0 && availableCapacity != maxCapacity) {
101             synchronized (lock) {
102                 availableCapacity = Math.min((availableCapacity + capacity), maxCapacity);
103             }
104         }
105     }
106
107     /**
108      * Returns the currently consumed capacity.
109      *
110      * @return consumed capacity
111      */

112     public int consumedCapacity() {
113         return (availableCapacity < 0) ? 0 : (maxCapacity - availableCapacity);
114     }
115
116     /**
117      * Returns the currently available capacity.
118      *
119      * @return available capacity
120      */

121     public int availableCapacity() {
122         return availableCapacity;
123     }
124 }
125