1
#pragma once
2

            
3
#include <memory>
4
#include <string>
5

            
6
#include "envoy/admin/v3/config_dump.pb.h"
7
#include "envoy/init/manager.h"
8
#include "envoy/init/target.h"
9
#include "envoy/rds/config_traits.h"
10
#include "envoy/rds/route_config_provider.h"
11
#include "envoy/server/admin.h"
12

            
13
#include "source/common/common/matchers.h"
14
#include "source/common/protobuf/utility.h"
15
#include "source/common/runtime/runtime_features.h"
16

            
17
#include "absl/container/node_hash_map.h"
18
#include "absl/container/node_hash_set.h"
19

            
20
namespace Envoy {
21
namespace Rds {
22

            
23
class RouteConfigProviderManager {
24
public:
25
  RouteConfigProviderManager(OptRef<Server::Admin> admin, const std::string& config_tracker_key,
26
                             ProtoTraits& proto_traits);
27

            
28
  void eraseStaticProvider(RouteConfigProvider* provider);
29
  void eraseDynamicProvider(uint64_t manager_identifier);
30

            
31
11136
  ProtoTraits& protoTraits() { return proto_traits_; }
32

            
33
  std::unique_ptr<envoy::admin::v3::RoutesConfigDump>
34
  dumpRouteConfigs(const Matchers::StringMatcher& name_matcher) const;
35

            
36
  RouteConfigProviderPtr
37
  addStaticProvider(std::function<RouteConfigProviderPtr()> create_static_provider);
38

            
39
  template <class RdsConfig>
40
  RouteConfigProviderSharedPtr addDynamicProvider(
41
      const RdsConfig& rds, const std::string& route_config_name, Init::Manager& init_manager,
42
      std::function<absl::StatusOr<std::pair<RouteConfigProviderSharedPtr, const Init::Target*>>(
43
          uint64_t manager_identifier)>
44
486
          create_dynamic_provider) {
45

            
46
    // Normalize the config_source part of the passed config. Some parts of the config_source
47
    // do not affect selection of the RDS provider. They will be cleared (zeroed) and restored
48
    // after calculating hash.
49
    // Since rds is passed as const, the constness must be casted away before modifying rds.
50
486
    auto* orig_initial_timeout =
51
486
        const_cast<RdsConfig&>(rds).mutable_config_source()->release_initial_fetch_timeout();
52
486
    const uint64_t manager_identifier = MessageUtil::hash(rds);
53
486
    const_cast<RdsConfig&>(rds).mutable_config_source()->set_allocated_initial_fetch_timeout(
54
486
        orig_initial_timeout);
55

            
56
486
    auto existing_provider =
57
486
        reuseDynamicProvider(manager_identifier, init_manager, route_config_name);
58

            
59
486
    if (existing_provider) {
60
106
      return existing_provider;
61
106
    }
62
380
    using PtrPair = std::pair<RouteConfigProviderSharedPtr, const Init::Target*>;
63
380
    auto new_provider = THROW_OR_RETURN_VALUE(create_dynamic_provider(manager_identifier), PtrPair);
64
380
    init_manager.add(*new_provider.second);
65
380
    dynamic_route_config_providers_.insert({manager_identifier, new_provider});
66
380
    return new_provider.first;
67
486
  }
68

            
69
private:
70
  // TODO(jsedgwick) These two members are prime candidates for the owned-entry list/map
71
  // as in ConfigTracker. I.e. the ProviderImpls would have an EntryOwner for these lists
72
  // Then the lifetime management stuff is centralized and opaque.
73
  absl::node_hash_map<uint64_t, std::pair<std::weak_ptr<RouteConfigProvider>, const Init::Target*>>
74
      dynamic_route_config_providers_;
75
  absl::node_hash_set<RouteConfigProvider*> static_route_config_providers_;
76
  Server::ConfigTracker::EntryOwnerPtr config_tracker_entry_;
77
  ProtoTraits& proto_traits_;
78

            
79
  RouteConfigProviderSharedPtr reuseDynamicProvider(uint64_t manager_identifier,
80
                                                    Init::Manager& init_manager,
81
                                                    const std::string& route_config_name);
82
};
83

            
84
} // namespace Rds
85
} // namespace Envoy