| #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 |