blob: 6a65ed7cb4d8d79ed6de52d181c953c3e458c013 [file] [log] [blame]
#pragma once
#include "dbus_utility.hpp"
#include "managed_store_clock.hpp"
#include "managed_store_types.hpp"
#include "nlohmann/json.hpp"
#include <boost/asio/io_context.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/system/error_code.hpp>
#include <sdbusplus/asio/property.hpp>
#include <sdbusplus/message/native_types.hpp>
#include <unordered_set>
namespace managedStore
{
// forward declaration:
class ManagedObjectStoreHttp;
// ManagedObjectStore caches all responses to GetManagedObjects in memory.
// This store aims to provide O(1) access to ManagedObjectType objects to save
// the round trip latency to query data from each DBus connection.
// A background async task using boost::asio::steady_timer ensures freshness of
// managed objects in store.
class ManagedObjectStore :
public std::enable_shared_from_this<ManagedObjectStore>
{
public:
friend class ManagedObjectStoreHttp;
explicit ManagedObjectStore(const ManagedObjectStoreConfig& cfg,
boost::asio::io_context& io) :
config(cfg),
timer(io), managedStoreTracker(cfg.pendingDbusResponsesMax)
{}
virtual ~ManagedObjectStore() = default;
using GetManagedObjectsCb =
std::function<void(const boost::system::error_code&,
const dbus::utility::ManagedObjectType&)>;
using GetManagedPropertyMapCb =
std::function<void(const boost::system::error_code&,
const ::dbus::utility::DBusPropertiesMap&)>;
using GetManagedPropertyCb =
std::function<void(const boost::system::error_code&,
const dbus::utility::DbusVariantType&)>;
using GetManagedSubtreeCb =
std::function<void(const boost::system::error_code&,
const dbus::utility::MapperGetSubTreeResponse&)>;
using GetManagedSubtreePathsCb = std::function<void(
const boost::system::error_code&,
const dbus::utility::MapperGetSubTreePathsResponse&)>;
// Callback used to move managed objects/properties within the store.
// This allows the store to operate on ValueType instead of specific
// dbus::utility::DbusVariantType, dbus::utility::ManagedObjectType.
using ManagedStoreCb = std::function<void(const ValueType&)>;
// Maps ManagedStore key to request callback.
using ManagedStoreCallbackMap =
std::unordered_map<std::string, std::queue<ManagedStoreCb>>;
// Tracks all entries in PQ to prevent redundant refresh requests to queue
// up.
using ManagedStorePqEntrySet = std::unordered_set<std::string>;
// call getManagedObjectsWithContext with a default context
void getManagedObjects(const std::string& service,
const sdbusplus::message::object_path& path,
GetManagedObjectsCb&& callback);
void getAllProperties(const std::string& service,
const std::string& objectPath,
const std::string& interface,
const ManagedObjectStoreContext& requestContext,
GetManagedPropertyMapCb&& callback);
void getSubTree(const std::string& path, int32_t depth,
std::span<const std::string_view> interfaces,
const ManagedObjectStoreContext& requestContext,
GetManagedSubtreeCb&& callback);
void getSubTree(const std::string& path, int32_t depth,
const std::vector<std::string>& interfaces,
const ManagedObjectStoreContext& requestContext,
GetManagedSubtreeCb&& callback);
void getSubTreePaths(const std::string& path, int32_t depth,
std::span<const std::string_view> interfaces,
const ManagedObjectStoreContext& requestContext,
GetManagedSubtreePathsCb&& callback);
void getAssociatedSubTree(
const sdbusplus::message::object_path& associatedPath,
const sdbusplus::message::object_path& path, int32_t depth,
const std::vector<std::string>& interfaces,
const ManagedObjectStoreContext& requestContext,
GetManagedSubtreeCb&& callback);
void getAssociatedSubTree(
const sdbusplus::message::object_path& associatedPath,
const sdbusplus::message::object_path& path, int32_t depth,
std::span<const std::string_view> interfaces,
const ManagedObjectStoreContext& requestContext,
GetManagedSubtreeCb&& callback);
void getAssociatedSubTreePaths(
const sdbusplus::message::object_path& associatedPath,
const sdbusplus::message::object_path& path, int32_t depth,
std::span<const std::string_view> interfaces,
const ManagedObjectStoreContext& requestContext,
GetManagedSubtreePathsCb&& callback);
ManagedStoreTracker getStoreTracker() const
{
return this->managedStoreTracker;
}
// call the 'callback' with cached/fetched object
void getManagedObjectsWithContext(
const std::string& service, const sdbusplus::message::object_path& path,
const ManagedObjectStoreContext& requestContext,
GetManagedObjectsCb&& callback);
// call the 'callback' with cached/fetched property
void getProperty(const KeyType& keyType,
const ManagedObjectStoreContext& requestContext,
GetManagedPropertyCb&& callback);
// check if the store is enabled:
bool isEnabled() const
{
return config.isEnabled;
}
// get the current config
const ManagedObjectStoreConfig& getConfig() const
{
return config;
}
// protected APIs (SPI):
protected:
// clear/flush all managed objects:
void clearAllObjects();
// Calls into dbus service to get managed objects.
// Virtual to allow unit testing and possible derived implementations of
// managedStore.
virtual void getManagedObjectsFromDbusService(
const std::string& service, const sdbusplus::message::object_path& path,
ManagedStoreCb&& callback);
// Calls into dbus service to get managed properties.
virtual void getManagedPropertiesFromDbusService(
const std::string& service, const sdbusplus::message::object_path& path,
const std::string& interface, const std::string& property,
ManagedStoreCb&& callback);
// Calls into dbus service to getAllProperties.
virtual void getManagedPropertiesMapFromDbusService(
const std::string& service, const sdbusplus::message::object_path& path,
const std::string& interface, ManagedStoreCb&& callback);
// Calls into dbus service to get subtree.
virtual void getManagedSubtreeFromDbusService(
const sdbusplus::message::object_path& path, int32_t depth,
const std::vector<std::string>& interfaces, ManagedStoreCb&& callback);
// Calls into dbus service to get subtree paths.
virtual void getManagedSubtreePathsFromDbusService(
const sdbusplus::message::object_path& path, int32_t depth,
const std::vector<std::string>& interfaces, ManagedStoreCb&& callback);
virtual void getManagedAssociatedSubtreeFromDbusService(
const sdbusplus::message::object_path& associatedPath,
const sdbusplus::message::object_path& path, int32_t depth,
const std::vector<std::string>& interfaces, ManagedStoreCb&& callback);
virtual void getManagedAssociatedSubtreePathsFromDbusService(
const sdbusplus::message::object_path& associatedPath,
const sdbusplus::message::object_path& path, int32_t depth,
const std::vector<std::string>& interfaces, ManagedStoreCb&& callback);
private:
// schedule the next refresh event (timer):
void scheduleRefresh();
// Checks all the invariants for scheduling a refresh operation.
// An object can be scheduled for refresh if:
// 1) The object can be fetched from queue i.e queue is not empty
// 2) The object is tracked in managedObjects.
// 3) The object is not overdue for a refresh (refresh the object
// instantly in that case)
// 4) The object was last used within tLRUThreshold time.
bool canScheduleRefresh();
// fetch the given object from DBUS:
// Refresh operation is considered high priority when isReadThroughRequest
// is set to true i.e the refresh is not subject to the pending i/o
// threshold invariant.
void refreshObject(const KeyType& key, bool isReadThroughRequest = false);
// Process dbus response after refreshObject(), invokes given callback if
// valid.
void processDbusResponse(KeyType keyType, const ValueType& managedValue,
bool isReadThroughRequest);
// Get managed entities (properties / objects) from store.
// Triggers refresh if not in store.
void getManagedObjectsInStore(
const KeyType& keyType, const ManagedObjectStoreContext& requestContext,
ManagedStoreCb&& callback);
// priority queue of refreshes:
ManagedStorePriorityQueue pq;
// Tracks callback for incoming requests.
ManagedStoreCallbackMap requestCbMap;
// Tracks all entries in managedStore priority queue.
ManagedStorePqEntrySet pqEntrySet;
// Stores ManagedObjectType objects with D-Bus interface and connection as
// key along with other metadata necessary for scheduling data refresh.
ManagedObjectsMap managedObjects;
// runtime config for the store
ManagedObjectStoreConfig config;
// A single timer object is used to asynchronously wait for a fixed duration
// before refreshing ManagedObject in store with the shortest deadline.
boost::asio::steady_timer timer;
// Flag set to true when scheduler has scheduled a refresh operation.
bool isSchedulerActive = false;
// Tracks state of managed object store.
ManagedStoreTracker managedStoreTracker;
protected: // friend (ManagedObjectStoreHttp class would use there)
// read only list of objects (metrics):
const std::unordered_map<std::string, ValueType>& getManagedObjects() const
{
return managedObjects;
}
// read only priority queue of refreshes:
const ManagedStorePriorityQueue& getPriorityQueue() const
{
return pq;
}
// Disable copy constructors (singelton)
ManagedObjectStore(const ManagedObjectStore&) = delete;
ManagedObjectStore& operator=(const ManagedObjectStore&) = delete;
// Not yet: https://gbmc-private-review.git.corp.google.com/c/gbmcweb/+/3520
// ManagedObjectStore(ManagedObjectStore&&) = delete;
// ManagedObjectStore& operator=(ManagedObjectStore&&) = delete;
// TODO: use this macro / template ^
// https://www.boost.org/doc/libs/1_81_0/libs/serialization/doc/singleton.html
};
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
extern ManagedObjectStore* managedObjectStore;
// TODO: this should be a ManagedObjectStore::instance() ^
// TODO: can this be a std::shared_ptr
// TODO:
// https://www.boost.org/doc/libs/1_81_0/libs/serialization/doc/singleton.html
} // namespace managedStore