blob: dca3a973146e7825382fc93c5990cd788d64821f [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/service_manager/service_instance_registry.h"
#include <algorithm>
#include "services/service_manager/public/cpp/manifest.h"
#include "services/service_manager/service_instance.h"
namespace service_manager {
ServiceInstanceRegistry::Entry::Entry(const base::Token& guid,
ServiceInstance* instance)
: guid(guid), instance(instance) {
DCHECK(!guid.is_zero());
DCHECK(instance);
}
ServiceInstanceRegistry::Entry::Entry(const Entry&) = default;
ServiceInstanceRegistry::Entry::~Entry() = default;
ServiceInstanceRegistry::RegularInstanceKey::RegularInstanceKey(
const std::string& service_name,
const base::Token& instance_group,
const base::Token& instance_id)
: service_name(service_name),
instance_group(instance_group),
instance_id(instance_id) {}
ServiceInstanceRegistry::RegularInstanceKey::RegularInstanceKey(
const RegularInstanceKey&) = default;
ServiceInstanceRegistry::RegularInstanceKey::~RegularInstanceKey() = default;
bool ServiceInstanceRegistry::RegularInstanceKey::operator==(
const RegularInstanceKey& other) const {
return service_name == other.service_name &&
instance_group == other.instance_group &&
instance_id == other.instance_id;
}
bool ServiceInstanceRegistry::RegularInstanceKey::operator<(
const RegularInstanceKey& other) const {
return std::tie(service_name, instance_group, instance_id) <
std::tie(other.service_name, other.instance_group, other.instance_id);
}
ServiceInstanceRegistry::SharedInstanceKey::SharedInstanceKey(
const std::string& service_name,
const base::Token& instance_id)
: service_name(service_name), instance_id(instance_id) {}
ServiceInstanceRegistry::SharedInstanceKey::SharedInstanceKey(
const SharedInstanceKey&) = default;
ServiceInstanceRegistry::SharedInstanceKey::~SharedInstanceKey() = default;
bool ServiceInstanceRegistry::SharedInstanceKey::operator==(
const SharedInstanceKey& other) const {
return service_name == other.service_name && instance_id == other.instance_id;
}
bool ServiceInstanceRegistry::SharedInstanceKey::operator<(
const SharedInstanceKey& other) const {
if (service_name != other.service_name)
return service_name < other.service_name;
return instance_id < other.instance_id;
}
ServiceInstanceRegistry::ServiceInstanceRegistry() = default;
ServiceInstanceRegistry::~ServiceInstanceRegistry() = default;
void ServiceInstanceRegistry::Register(ServiceInstance* instance) {
DCHECK_NE(instance, nullptr);
const Identity& identity = instance->identity();
DCHECK_EQ(FindMatching(identity), nullptr);
switch (instance->manifest().options.instance_sharing_policy) {
case Manifest::InstanceSharingPolicy::kNoSharing: {
const RegularInstanceKey key{identity.name(), identity.instance_group(),
identity.instance_id()};
regular_instances_[key].emplace_back(identity.globally_unique_id(),
instance);
break;
}
case Manifest::InstanceSharingPolicy::kSharedAcrossGroups: {
const SharedInstanceKey key{identity.name(), identity.instance_id()};
shared_instances_[key].emplace_back(identity.globally_unique_id(),
instance);
break;
}
case Manifest::InstanceSharingPolicy::kSingleton:
singleton_instances_[identity.name()].emplace_back(
identity.globally_unique_id(), instance);
break;
default:
NOTREACHED();
}
}
bool ServiceInstanceRegistry::Unregister(ServiceInstance* instance) {
DCHECK(instance);
const Identity& identity = instance->identity();
const RegularInstanceKey regular_key{
identity.name(), identity.instance_group(), identity.instance_id()};
auto regular_iter = regular_instances_.find(regular_key);
if (regular_iter != regular_instances_.end()) {
auto& entries = regular_iter->second;
if (EraseEntry(identity.globally_unique_id(), &entries)) {
if (entries.empty())
regular_instances_.erase(regular_iter);
return true;
}
}
const SharedInstanceKey shared_key{identity.name(), identity.instance_id()};
auto shared_iter = shared_instances_.find(shared_key);
if (shared_iter != shared_instances_.end()) {
auto& entries = shared_iter->second;
if (EraseEntry(identity.globally_unique_id(), &entries)) {
if (entries.empty())
shared_instances_.erase(shared_iter);
return true;
}
}
auto singleton_iter = singleton_instances_.find(identity.name());
if (singleton_iter != singleton_instances_.end()) {
auto& entries = singleton_iter->second;
if (EraseEntry(identity.globally_unique_id(), &entries)) {
if (entries.empty())
singleton_instances_.erase(singleton_iter);
return true;
}
}
return false;
}
ServiceInstance* ServiceInstanceRegistry::FindMatching(
const ServiceFilter& filter) const {
DCHECK(filter.instance_group());
DCHECK(filter.instance_id());
DCHECK(!filter.globally_unique_id() ||
!filter.globally_unique_id()->is_zero());
const RegularInstanceKey regular_key{
filter.service_name(), *filter.instance_group(), *filter.instance_id()};
auto regular_iter = regular_instances_.find(regular_key);
if (regular_iter != regular_instances_.end()) {
return FindMatchInEntries(regular_iter->second,
filter.globally_unique_id());
}
const SharedInstanceKey shared_key{filter.service_name(),
*filter.instance_id()};
auto shared_iter = shared_instances_.find(
SharedInstanceKey(filter.service_name(), *filter.instance_id()));
if (shared_iter != shared_instances_.end()) {
return FindMatchInEntries(shared_iter->second, filter.globally_unique_id());
}
auto singleton_iter = singleton_instances_.find(filter.service_name());
if (singleton_iter != singleton_instances_.end()) {
return FindMatchInEntries(singleton_iter->second,
filter.globally_unique_id());
}
return nullptr;
}
ServiceInstance* ServiceInstanceRegistry::FindMatchInEntries(
const std::vector<Entry>& entries,
const base::Optional<base::Token>& guid) const {
DCHECK(!entries.empty());
if (!guid.has_value())
return entries.front().instance;
for (const auto& entry : entries) {
if (entry.guid == *guid)
return entry.instance;
}
return nullptr;
}
bool ServiceInstanceRegistry::EraseEntry(const base::Token& guid,
std::vector<Entry>* entries) {
auto it =
std::find_if(entries->begin(), entries->end(),
[&guid](const Entry& entry) { return entry.guid == guid; });
if (it == entries->end())
return false;
entries->erase(it);
return true;
}
} // namespace service_manager