1
#include "source/extensions/resource_monitors/downstream_connections/downstream_connections_monitor.h"
2

            
3
#include "envoy/extensions/resource_monitors/downstream_connections/v3/downstream_connections.pb.h"
4

            
5
#include "source/common/common/assert.h"
6

            
7
namespace Envoy {
8
namespace Extensions {
9
namespace ResourceMonitors {
10
namespace DownstreamConnections {
11

            
12
ActiveDownstreamConnectionsResourceMonitor::ActiveDownstreamConnectionsResourceMonitor(
13
    const envoy::extensions::resource_monitors::downstream_connections::v3::
14
        DownstreamConnectionsConfig& config)
15
10
    : max_(config.max_active_downstream_connections()), current_(0) {};
16

            
17
21
bool ActiveDownstreamConnectionsResourceMonitor::tryAllocateResource(int64_t increment) {
18
  // No synchronization is imposed on other reads or writes.
19
21
  auto current = current_.load(std::memory_order_relaxed);
20
22
  while (current + increment <= max_) {
21
    // Testing hook.
22
17
    synchronizer_.syncPoint("try_allocate_pre_cas");
23
    // `current_` value is atomically compared to `current`.
24
    // In case values are bitwise equal, `current` value is replaced with `current + increment`.
25
    // The write will be visible to other threads accessing `current_`.
26
    // If `current` is not equal to value stored in `current_`, `current` will be reloaded with the
27
    // latest value of `current_` and no synchronization will be imposed on other reads or writes.
28
    // After value reload next loop iteration will be attempted until suggested increment breaches
29
    // `max_` or cas operation is successful.
30
17
    if (current_.compare_exchange_weak(current, current + increment, std::memory_order_release,
31
17
                                       std::memory_order_relaxed)) {
32
16
      return true;
33
16
    }
34
17
  }
35
5
  return false;
36
21
}
37

            
38
23
bool ActiveDownstreamConnectionsResourceMonitor::tryDeallocateResource(int64_t decrement) {
39
  // No synchronization is imposed on other reads or writes.
40
23
  auto current = current_.load(std::memory_order_relaxed);
41
24
  while (current - decrement >= 0) {
42
    // Testing hook.
43
16
    synchronizer_.syncPoint("try_deallocate_pre_cas");
44
    // `current_` value is atomically compared to `current`.
45
    // In case values are bitwise equal, `current` value is replaced with `current - decrement`.
46
    // The write will be visible to other threads accessing `current_`.
47
    // If `current` is not equal to value stored in `current_`, `current` will be reloaded with the
48
    // latest value of `current_` and no synchronization will be imposed on other reads or writes.
49
    // After value reload next loop iteration will be attempted until suggested decrement goes below
50
    // 0 or cas operation is successful.
51
16
    if (current_.compare_exchange_weak(current, current - decrement, std::memory_order_release,
52
16
                                       std::memory_order_relaxed)) {
53
15
      return true;
54
15
    }
55
16
  }
56
8
  return false;
57
23
}
58

            
59
8
int64_t ActiveDownstreamConnectionsResourceMonitor::currentResourceUsage() const {
60
8
  return current_.load();
61
8
}
62
2
int64_t ActiveDownstreamConnectionsResourceMonitor::maxResourceUsage() const { return max_; };
63

            
64
} // namespace DownstreamConnections
65
} // namespace ResourceMonitors
66
} // namespace Extensions
67
} // namespace Envoy