1
#include "source/common/http/session_idle_list.h"
2

            
3
#include <algorithm>
4
#include <cstddef>
5

            
6
#include "envoy/common/time.h"
7

            
8
#include "source/common/common/assert.h"
9
#include "source/common/common/logger.h"
10
#include "source/common/http/session_idle_list_interface.h"
11

            
12
#include "absl/time/time.h"
13

            
14
namespace Envoy {
15
namespace Http {
16

            
17
27
void SessionIdleList::AddSession(IdleSessionInterface& session) {
18
27
  idle_sessions_.AddSessionToList(dispatcher_.approximateMonotonicTime(), session);
19
27
}
20

            
21
15
void SessionIdleList::RemoveSession(IdleSessionInterface& session) {
22
15
  idle_sessions_.RemoveSessionFromList(session);
23
15
}
24

            
25
11
void SessionIdleList::MaybeTerminateIdleSessions(bool is_saturated) {
26
11
  const size_t max_sessions_to_terminate =
27
11
      std::min(MaxSessionsToTerminateInOneRound(is_saturated), idle_sessions_.size());
28
11
  size_t num_terminated;
29
21
  for (num_terminated = 0; num_terminated < max_sessions_to_terminate; ++num_terminated) {
30
12
    IdleSessionInterface& next_session = idle_sessions_.next_session_to_terminate();
31
12
    absl::Duration time_since_enqueue = absl::FromChrono(
32
12
        dispatcher_.approximateMonotonicTime() - idle_sessions_.GetEnqueueTime(next_session));
33
    // If the resource pressure is scaling but not saturated, we should respect
34
    // the min_time_before_termination_allowed_ and only terminate connections
35
    // that have been idle longer than the threshold.
36
12
    if (!is_saturated && time_since_enqueue < min_time_before_termination_allowed_) {
37
2
      break;
38
2
    }
39
10
    next_session.TerminateIdleSession();
40
    // The class implementing IdleSessionInterface may or may not remove itself
41
    // from the idle list. We remove it here to be sure.
42
10
    idle_sessions_.RemoveSessionFromList(next_session);
43
10
  }
44
11
  ENVOY_LOG(debug, "Terminated {} idle sessions.", num_terminated);
45
11
};
46

            
47
11
size_t SessionIdleList::MaxSessionsToTerminateInOneRound(bool is_saturated) const {
48
11
  return is_saturated ? max_sessions_to_terminate_in_one_round_when_saturated_
49
11
                      : max_sessions_to_terminate_in_one_round_;
50
11
};
51

            
52
1
absl::Duration SessionIdleList::MinTimeBeforeTerminationAllowed() const {
53
1
  return min_time_before_termination_allowed_;
54
1
};
55

            
56
void SessionIdleList::IdleSessions::AddSessionToList(MonotonicTime enqueue_time,
57
27
                                                     IdleSessionInterface& session) {
58
27
  if (map_.find(&session) != map_.end()) {
59
1
    IS_ENVOY_BUG("Session is already on the idle list.");
60
1
    return;
61
1
  }
62

            
63
26
  auto [iter, added] = set_.emplace(SessionInfo(session, enqueue_time));
64
26
  if (added) {
65
26
    map_.emplace(&session, *iter);
66
26
  } else {
67
    ENVOY_BUG(added, "Attempt to add session which is already in the idle set.");
68
  }
69
26
}
70

            
71
25
void SessionIdleList::IdleSessions::RemoveSessionFromList(IdleSessionInterface& session) {
72
25
  auto it = map_.find(&session);
73
25
  if (it != map_.end()) {
74
20
    set_.erase(it->second);
75
20
    map_.erase(it);
76
20
  }
77
25
}
78

            
79
13
MonotonicTime SessionIdleList::IdleSessions::GetEnqueueTime(IdleSessionInterface& session) const {
80
13
  auto it = map_.find(&session);
81
13
  if (it != map_.end()) {
82
12
    return it->second.enqueue_time;
83
12
  }
84
1
  IS_ENVOY_BUG("Attempt to get enqueue time for session which is not in the idle set.");
85
1
  return MonotonicTime{};
86
13
}
87

            
88
} // namespace Http
89
} // namespace Envoy