1
#include "source/common/init/manager_impl.h"
2

            
3
#include <functional>
4

            
5
#include "source/common/common/assert.h"
6
#include "source/common/init/watcher_impl.h"
7

            
8
namespace Envoy {
9
namespace Init {
10

            
11
ManagerImpl::ManagerImpl(absl::string_view name)
12
55799
    : name_(fmt::format("init manager {}", name)),
13
55804
      watcher_(name_, [this](absl::string_view target_name) { onTargetReady(target_name); }) {}
14

            
15
34957
Manager::State ManagerImpl::state() const { return state_; }
16

            
17
23374
void ManagerImpl::add(const Target& target) {
18
23374
  ++count_;
19
23374
  TargetHandlePtr target_handle(target.createHandle(name_));
20
23374
  ++target_names_count_[target.name()];
21
23374
  switch (state_) {
22
12366
  case State::Uninitialized:
23
    // If the manager isn't initialized yet, save the target handle to be initialized later.
24
12366
    ENVOY_LOG(debug, "added {} to {}", target.name(), name_);
25
12366
    target_handles_.push_back(std::move(target_handle));
26
12366
    return;
27
11008
  case State::Initializing:
28
    // If the manager is already initializing, initialize the new target immediately. Note that
29
    // it's important in this case that count_ was incremented above before calling the target,
30
    // because if the target calls the init manager back immediately, count_ will be decremented
31
    // here (see the definition of watcher_ above).
32
11008
    target_handle->initialize(watcher_);
33
11008
    return;
34
  case State::Initialized:
35
    // If the manager has already completed initialization, consider this a programming error.
36
    ASSERT(false, fmt::format("attempted to add {} to initialized {}", target.name(), name_));
37
23374
  }
38
23374
}
39

            
40
50905
void ManagerImpl::initialize(const Watcher& watcher) {
41
  // If the manager is already initializing or initialized, consider this a programming error.
42
50905
  ASSERT(state_ == State::Uninitialized, fmt::format("attempted to initialize {} twice", name_));
43

            
44
  // Create a handle to notify when initialization is complete.
45
50905
  watcher_handle_ = watcher.createHandle(name_);
46

            
47
50905
  if (count_ == 0) {
48
    // If we have no targets, initialization trivially completes. This can happen, and is fine.
49
38873
    ENVOY_LOG(debug, "{} contains no targets", name_);
50
38873
    ready();
51
39022
  } else {
52
    // If we have some targets, start initialization...
53
12032
    ENVOY_LOG(debug, "{} initializing", name_);
54
12032
    state_ = State::Initializing;
55

            
56
    // Attempt to initialize each target. If a target is unavailable, treat it as though it
57
    // completed immediately.
58
12242
    for (const auto& target_handle : target_handles_) {
59
12242
      if (!target_handle->initialize(watcher_)) {
60
10
        onTargetReady(target_handle->name());
61
10
      }
62
12242
    }
63
12032
  }
64
50905
}
65

            
66
1
void ManagerImpl::updateWatcher(const Watcher& watcher) {
67
1
  ASSERT(state_ != State::Initialized, "attempted to update watcher on initialized manager");
68
1
  watcher_handle_ = watcher.createHandle(name_);
69
1
};
70

            
71
6
void ManagerImpl::dumpUnreadyTargets(envoy::admin::v3::UnreadyTargetsDumps& unready_targets_dumps) {
72
6
  auto& message = *unready_targets_dumps.mutable_unready_targets_dumps()->Add();
73
6
  message.set_name(name_);
74
6
  for (const auto& [target_name, count] : target_names_count_) {
75
6
    UNREFERENCED_PARAMETER(count);
76
6
    message.add_target_names(target_name);
77
6
  }
78
6
}
79

            
80
23071
void ManagerImpl::onTargetReady(absl::string_view target_name) {
81
  // If there are no remaining targets and one mysteriously calls us back, this manager is haunted.
82
23071
  ASSERT(count_ != 0,
83
23071
         fmt::format("{} called back by target after initialization complete", target_name));
84

            
85
  // Decrease target_name count by 1.
86
23071
  ASSERT(target_names_count_.find(target_name) != target_names_count_.end());
87
23071
  if (--target_names_count_[target_name] == 0) {
88
23030
    target_names_count_.erase(target_name);
89
23030
  }
90

            
91
  // If there are no uninitialized targets remaining when called back by a target, that means it was
92
  // the last. Signal `ready` to the handle we saved in `initialize`.
93
23071
  if (--count_ == 0) {
94
11853
    ready();
95
11853
  }
96
23071
}
97

            
98
50726
void ManagerImpl::ready() {
99
50726
  state_ = State::Initialized;
100
50726
  watcher_handle_->ready();
101
50726
}
102

            
103
} // namespace Init
104
} // namespace Envoy