blob: 7eca97d94aa19d74e57e935895b7bf3c6c24bc7f [file] [log] [blame]
#include "managed_store.hpp"
#include "dbus_utility.hpp"
#include <boost/asio/io_context.hpp>
#include <boost/system/error_code.hpp>
#include <sdbusplus/asio/property.hpp>
#include <sdbusplus/message/native_types.hpp>
// TODO:: move these to a separate file (future CL when we have more stores):
namespace managedStore
{
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
ManagedObjectStore* managedObjectStore = nullptr;
// TODO:: can ^ be a std::shared_ptr on `static ManagedObjectStore::instance()`
// when we implement graceful shutdowns
void ManagedObjectStore::processDbusResponse(KeyType keyType,
const ValueType& managedValue,
bool isReadThroughRequest)
{
ValueType value(managedValue);
std::string keyTypeStr = keyType.toString();
BMCWEB_LOG_STATEFUL_DEBUG << "Updating store with fresh "
<< " Object: " << keyTypeStr
<< " Value: " << value.toString()
<< " ec: " << value.errorCode.message();
// Initialize numTimesUsed:
value.numTimesUsed = 1;
auto currentObjectIter = managedObjects.find(keyTypeStr);
if (currentObjectIter != managedObjects.end())
{
// preserve the lastUsed:
value.lastUsed = currentObjectIter->second.lastUsed;
// preserve the lastUsedAges:
value.lastUsedAges = currentObjectIter->second.lastUsedAges;
// preserve the numTimesUsed:
value.numTimesUsed = currentObjectIter->second.numTimesUsed;
// an shared / unique pointer) count refreshes:
value.numRefreshesDone = currentObjectIter->second.numRefreshesDone + 1;
// count the scheduled refreshes:
value.numRefreshesScheduled =
currentObjectIter->second.numRefreshesScheduled;
BMCWEB_LOG_STATEFUL_DEBUG << "Updating Current Object:"
<< " Key: " << keyTypeStr
<< " Value: " << value.toString();
}
// Avoid queuing a refresh if a Pq entry exists for the key.
if (!pqEntrySet.contains(keyTypeStr))
{
// Queue refresh operation
pq.push(PriorityQueueEntry(keyType, value.nextRefreshAt));
// Track pq entry
pqEntrySet.insert(keyTypeStr);
}
// upsert the key:
managedObjects.insert_or_assign(keyTypeStr, value);
BMCWEB_LOG_STATEFUL_DEBUG
<< "Updated Object:"
<< " Object: " << keyTypeStr
<< " New: " << managedObjects.find(keyTypeStr)->second.toString();
// Update pending dbus response count on receiving response.
this->managedStoreTracker.decrementPendingDbusResponses(
isReadThroughRequest);
auto cbMapIter = requestCbMap.find(keyTypeStr);
if (cbMapIter != requestCbMap.end())
{
std::queue<ManagedStoreCb>& cbQueue = cbMapIter->second;
while (!cbQueue.empty())
{
auto callback = cbQueue.front();
callback(value);
cbQueue.pop();
}
requestCbMap.erase(cbMapIter->first);
}
// Finally, call scheduler to queue up next refresh operations.
scheduleRefresh();
}
void ManagedObjectStore::refreshObject(const KeyType& key,
bool isReadThroughRequest)
{
auto managedObjectIter = this->managedObjects.find(key.toString());
if (managedObjectIter != this->managedObjects.end())
{
managedObjectIter->second.numRefreshesScheduled += 1;
BMCWEB_LOG_STATEFUL_DEBUG
<< "refreshObject:"
<< " Key: " << managedObjectIter->first
<< " value: " << managedObjectIter->second.toString();
}
switch (key.getManagedType())
{
case ManagedType::kManagedObject:
{
getManagedObjectsFromDbusService(
key.serviceName, key.objectPath,
[this, self = shared_from_this(), keyType = key,
isReadThroughRequest](const ValueType& managedValue) mutable {
processDbusResponse(std::move(keyType), managedValue,
isReadThroughRequest);
});
break;
}
case ManagedType::kManagedPropertyMap:
{
getManagedPropertiesMapFromDbusService(
key.serviceName, key.objectPath, key.interface,
[this, self = shared_from_this(), keyType = key,
isReadThroughRequest](const ValueType& managedValue) mutable {
processDbusResponse(std::move(keyType), managedValue,
isReadThroughRequest);
});
break;
}
case ManagedType::kManagedProperty:
{
getManagedPropertiesFromDbusService(
key.serviceName, key.objectPath, key.interface, key.property,
[this, self = shared_from_this(), keyType = key,
isReadThroughRequest](const ValueType& managedValue) mutable {
processDbusResponse(std::move(keyType), managedValue,
isReadThroughRequest);
});
break;
}
case ManagedType::kManagedSubtree:
{
getManagedSubtreeFromDbusService(
key.objectPath, key.treeDepth, key.interfaceList,
[this, self = shared_from_this(), keyType = key,
isReadThroughRequest](const ValueType& managedValue) mutable {
processDbusResponse(std::move(keyType), managedValue,
isReadThroughRequest);
});
break;
}
case ManagedType::kManagedSubtreePaths:
{
getManagedSubtreePathsFromDbusService(
key.objectPath, key.treeDepth, key.interfaceList,
[this, self = shared_from_this(), keyType = key,
isReadThroughRequest](const ValueType& managedValue) mutable {
processDbusResponse(std::move(keyType), managedValue,
isReadThroughRequest);
});
break;
}
case ManagedType::kManagedAssociatedSubtree:
{
getManagedAssociatedSubtreeFromDbusService(
key.associatedPath, key.objectPath, key.treeDepth,
key.interfaceList,
[this, self = shared_from_this(), keyType = key,
isReadThroughRequest](const ValueType& managedValue) mutable {
processDbusResponse(std::move(keyType), managedValue,
isReadThroughRequest);
});
break;
}
case ManagedType::kManagedAssociatedSubtreePaths:
{
getManagedAssociatedSubtreePathsFromDbusService(
key.associatedPath, key.objectPath, key.treeDepth,
key.interfaceList,
[this, self = shared_from_this(), keyType = key,
isReadThroughRequest](const ValueType& managedValue) mutable {
processDbusResponse(std::move(keyType), managedValue,
isReadThroughRequest);
});
break;
}
}
// Record a pending refresh operation.
this->managedStoreTracker.incrementPendingDbusResponses(
isReadThroughRequest);
}
bool ManagedObjectStore::canScheduleRefresh()
{
// The timer callback will schedule the next refresh if the scheduler is
// active.
if (this->isSchedulerActive)
{
return false;
}
// Cannot schedule refresh if pending dbus responses reach threshold.
if (this->managedStoreTracker.countPendingDbusResponses >=
this->config.pendingDbusResponsesMax)
{
BMCWEB_LOG_STATEFUL_DEBUG << "scheduleRefresh: Pending io "
<< "threshold reached.";
return false;
}
// Scan the priority queue to pop the entries that are no longer used
// or can be refreshed instantly to get to a schedulable entry.
std::chrono::steady_clock::time_point timeNow = clockNow();
bool canSchedule = false;
while (!canSchedule && !this->pq.empty())
{
const PriorityQueueEntry& pqEntry = pq.top();
// Get managedStore key to queue refresh of corresponding object in
// the managedStore.
const KeyType& managedStoreKey = pqEntry.managedStoreKey;
const std::string managedStoreKeyStr = managedStoreKey.toString();
auto managedObjectIter = managedObjects.find(managedStoreKeyStr);
// the object is no longer tracked:
if (managedObjectIter == managedObjects.end())
{
pq.pop();
pqEntrySet.erase(managedStoreKeyStr);
continue;
}
ValueType& keyValue = managedObjectIter->second;
const auto durationSinceUsed = clockSince(keyValue.lastUsed, timeNow);
bool isRecentlyUsed = durationSinceUsed < this->config.tLRUThreshold;
BMCWEB_LOG_STATEFUL_DEBUG
<< "SinceUsed:"
<< " Key: " << managedStoreKeyStr << " durationSinceUsed: "
<< clockSinceMilliseconds(keyValue.lastUsed, timeNow)
<< " isRecentlyUsed: " << isRecentlyUsed;
// LRU Eviction:
if (!isRecentlyUsed)
{
BMCWEB_LOG_STATEFUL_DEBUG << "Since Used: Evict:"
<< " Key: " << managedStoreKeyStr;
managedObjects.erase(managedObjectIter->first);
pq.pop();
pqEntrySet.erase(managedStoreKeyStr);
continue;
}
// If the object corresponding to pqEntry was recently refreshed,
// re-queue the entry to schedule refresh for later point in time.
if (keyValue.nextRefreshAt > pqEntry.nextRefreshAt)
{
BMCWEB_LOG_STATEFUL_DEBUG << "PQ entry recently refreshed: "
<< "Re-queue Key: " << managedStoreKeyStr;
// Remember associated managedStore key before we pop the pq entry.
const KeyType key = managedStoreKey;
pq.pop();
pq.push(PriorityQueueEntry(key, keyValue.nextRefreshAt));
continue;
}
canSchedule = true;
}
return canSchedule;
}
void ManagedObjectStore::scheduleRefresh()
{
if (!this->canScheduleRefresh())
{
return;
}
BMCWEB_LOG_STATEFUL_DEBUG
<< "scheduleRefresh: " << pq.size() << " Pending dbus responses: "
<< this->managedStoreTracker.countPendingDbusResponses;
PriorityQueueEntry pqEntry = pq.top();
pq.pop();
std::chrono::steady_clock::time_point timeNow = clockNow();
// Get service name and object path to schedule refresh of the corresponding
// object in store.
const KeyType& managedStoreKey = pqEntry.managedStoreKey;
std::string managedStoreKeyStr = managedStoreKey.toString();
// Stop tracking the pq entry once it is pop'd from the queue.
pqEntrySet.erase(managedStoreKeyStr);
// Set scheduler status to active before scheduling the refresh op to ensure
// an immediate callback keeps the system in the correct state.
isSchedulerActive = true;
// If the refresh needs to be scheduled later in time, we set the timeout
// based on the time difference between the expected refresh time and
// current time.
// NOTE: the expected refresh time is set based on t_ttl.
const auto timerTimeout =
std::chrono::duration_cast<std::chrono::milliseconds>(
pqEntry.nextRefreshAt - timeNow);
timer.expires_after(timerTimeout);
BMCWEB_LOG_STATEFUL_DEBUG
<< "Scheduling Refresh after " << timerTimeout.count()
<< " milliseconds. "
<< "ServiceName: " << managedStoreKey.serviceName
<< " ObjectPath: " << managedStoreKey.objectPath.str
<< " Interface: " << managedStoreKey.interface << " Property: "
<< managedStoreKey.property;
timer.async_wait([this, self = shared_from_this(),
managedStoreKey](boost::system::error_code ec) {
isSchedulerActive = false;
if (ec == boost::asio::error::operation_aborted)
{
BMCWEB_LOG_STATEFUL_ERROR << "Timer operation aborted" << ec;
return;
}
if (ec)
{
BMCWEB_LOG_STATEFUL_ERROR << "Async_wait failed" << ec;
return;
}
BMCWEB_LOG_STATEFUL_DEBUG
<< "Refreshing managed object. "
<< "ServiceName: " << managedStoreKey.serviceName
<< " ObjectPath: " << managedStoreKey.objectPath.str
<< " Interface: " << managedStoreKey.interface << " Property: "
<< managedStoreKey.property;
refreshObject(managedStoreKey);
scheduleRefresh();
});
}
void ManagedObjectStore::getProperty(
const KeyType& keyType, const ManagedObjectStoreContext& requestContext,
GetManagedPropertyCb&& callback)
{
// When Object Store is disabled, the requests read through.
if (!this->isEnabled())
{
dbus::utility::getProperty(keyType.serviceName, keyType.objectPath,
keyType.interface, keyType.property,
std::move(callback));
return;
}
getManagedObjectsInStore(
keyType, requestContext,
[callback{std::move(callback)}](const ValueType& valueType) {
if (!valueType.managedProperty.has_value())
{
callback(valueType.errorCode, {});
return;
}
callback(valueType.errorCode, valueType.managedProperty.value());
});
}
void ManagedObjectStore::getAllProperties(
const std::string& service, const std::string& objectPath,
const std::string& interface,
const ManagedObjectStoreContext& requestContext,
GetManagedPropertyMapCb&& callback)
{
// When Object Store is disabled, the requests read through.
if (!this->isEnabled())
{
sdbusplus::asio::getAllProperties(*crow::connections::systemBus,
service, objectPath, interface,
std::move(callback));
return;
}
KeyType keyType(ManagedType::kManagedPropertyMap, service, objectPath,
interface);
getManagedObjectsInStore(
keyType, requestContext,
[callback{std::move(callback)}](const ValueType& valueType) {
if (!valueType.managedPropertyMap.has_value())
{
callback(valueType.errorCode, {});
return;
}
callback(valueType.errorCode, valueType.managedPropertyMap.value());
});
}
void ManagedObjectStore::getSubTree(
const std::string& path, int32_t depth,
const std::vector<std::string>& interfaces,
const ManagedObjectStoreContext& requestContext,
GetManagedSubtreeCb&& callback)
{
// When Object Store is disabled, the requests read through.
if (!this->isEnabled())
{
crow::connections::systemBus->async_method_call(
[callback{std::move(callback)}](
const boost::system::error_code& ec,
const dbus::utility::MapperGetSubTreeResponse& subtree) {
callback(ec, subtree);
},
"xyz.openbmc_project.ObjectMapper",
"/xyz/openbmc_project/object_mapper",
"xyz.openbmc_project.ObjectMapper", "GetSubTree", path, depth,
interfaces);
return;
}
KeyType keyType(ManagedType::kManagedSubtree, path, depth, interfaces);
getManagedObjectsInStore(
keyType, requestContext,
[callback{std::move(callback)}](const ValueType& valueType) {
if (!valueType.managedSubtree.has_value())
{
callback(valueType.errorCode, {});
return;
}
callback(valueType.errorCode, valueType.managedSubtree.value());
});
}
void ManagedObjectStore::getSubTree(
const std::string& path, int32_t depth,
std::span<const std::string_view> interfaces,
const ManagedObjectStoreContext& requestContext,
GetManagedSubtreeCb&& callback)
{
std::vector<std::string> interfaces2;
for (auto& s : interfaces)
{
interfaces2.emplace_back(s);
}
this->getSubTree(path, depth, interfaces2, requestContext,
std::move(callback));
}
void ManagedObjectStore::getSubTreePaths(
const std::string& path, int32_t depth,
std::span<const std::string_view> interfaces,
const ManagedObjectStoreContext& requestContext,
GetManagedSubtreePathsCb&& callback)
{
std::vector<std::string> interfaces2;
for (auto& s : interfaces)
{
interfaces2.emplace_back(s);
}
// When Object Store is disabled, the requests read through.
if (!this->isEnabled())
{
crow::connections::systemBus->async_method_call(
[callback{std::move(callback)}](
const boost::system::error_code& ec,
const dbus::utility::MapperGetSubTreePathsResponse&
subtreePaths) { callback(ec, subtreePaths); },
"xyz.openbmc_project.ObjectMapper",
"/xyz/openbmc_project/object_mapper",
"xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", path, depth,
interfaces2);
return;
}
KeyType keyType(ManagedType::kManagedSubtreePaths, path, depth,
interfaces2);
getManagedObjectsInStore(
keyType, requestContext,
[callback{std::move(callback)}](const ValueType& valueType) {
if (!valueType.managedSubtreePaths.has_value())
{
callback(valueType.errorCode, {});
return;
}
callback(valueType.errorCode, valueType.managedSubtreePaths.value());
});
}
void ManagedObjectStore::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)
{
std::vector<std::string> interfaces2;
for (auto& s : interfaces)
{
interfaces2.emplace_back(s);
}
this->getAssociatedSubTree(associatedPath, path, depth, interfaces2,
requestContext, std::move(callback));
}
void ManagedObjectStore::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)
{
std::vector<std::string> interfaces2;
for (auto& s : interfaces)
{
interfaces2.emplace_back(s);
}
// When Object Store is disabled, the requests read through.
if (!this->isEnabled())
{
crow::connections::systemBus->async_method_call(
[callback{std::move(callback)}](
const boost::system::error_code& ec,
const dbus::utility::MapperGetSubTreeResponse& subtree) {
callback(ec, subtree);
},
"xyz.openbmc_project.ObjectMapper",
"/xyz/openbmc_project/object_mapper",
"xyz.openbmc_project.ObjectMapper", "GetAssociatedSubTree",
associatedPath, path, depth, interfaces2);
return;
}
KeyType keyType(ManagedType::kManagedAssociatedSubtree, associatedPath.str,
path.str, depth, interfaces2);
getManagedObjectsInStore(
keyType, requestContext,
[callback{std::move(callback)}](const ValueType& valueType) {
if (!valueType.managedSubtree.has_value())
{
callback(valueType.errorCode, {});
return;
}
callback(valueType.errorCode, valueType.managedSubtree.value());
});
}
void ManagedObjectStore::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)
{
std::vector<std::string> interfaces2;
for (auto& s : interfaces)
{
interfaces2.emplace_back(s);
}
// When Object Store is disabled, the requests read through.
if (!this->isEnabled())
{
crow::connections::systemBus->async_method_call(
[callback{std::move(callback)}](
const boost::system::error_code& ec,
const dbus::utility::MapperGetSubTreePathsResponse&
subtreePaths) { callback(ec, subtreePaths); },
"xyz.openbmc_project.ObjectMapper",
"/xyz/openbmc_project/object_mapper",
"xyz.openbmc_project.ObjectMapper", "GetAssociatedSubTreePaths",
associatedPath, path, depth, interfaces);
return;
}
KeyType keyType(ManagedType::kManagedAssociatedSubtreePaths,
associatedPath.str, path.str, depth, interfaces2);
getManagedObjectsInStore(
keyType, requestContext,
[callback{std::move(callback)}](const ValueType& valueType) {
if (!valueType.managedSubtreePaths.has_value())
{
callback(valueType.errorCode, {});
return;
}
callback(valueType.errorCode, valueType.managedSubtreePaths.value());
});
}
void ManagedObjectStore::getManagedObjects(
const std::string& service, const sdbusplus::message::object_path& path,
GetManagedObjectsCb&& callback)
{
BMCWEB_LOG_STATEFUL_DEBUG << "getManagedObjects:"
<< " service: " << service
<< " path: " << path.str;
// std::shared_ptr<bmcweb::AsyncResp> resp;
ManagedObjectStoreContext context(nullptr);
getManagedObjectsWithContext(service, path, context, std::move(callback));
}
void ManagedObjectStore::getManagedObjectsWithContext(
const std::string& service, const sdbusplus::message::object_path& path,
const ManagedObjectStoreContext& requestContext,
GetManagedObjectsCb&& callback)
{
// total counter of calls:
this->managedStoreTracker.countGetManagedObjects += 1;
BMCWEB_LOG_STATEFUL_DEBUG
<< "getManagedObjectsWithContext:"
<< " service: " << service << " path: " << path.str
<< " requestContext: " << requestContext.toString()
<< " count: " << this->managedStoreTracker.countGetManagedObjects;
// When Object Store is disabled, the requests read through.
if (!this->isEnabled())
{
// TODO:: do we want to count that (if the cache is actually disabled)
// i think we should since we want to use that as validation for the
// store being enabled?
this->managedStoreTracker.countGetManagedObjectsCacheMiss += 1;
dbus::utility::getManagedObjects(service, path, std::move(callback));
return;
}
KeyType keyType(ManagedType::kManagedObject, service, path.str);
getManagedObjectsInStore(
keyType, requestContext,
[callback{std::move(callback)}](const ValueType& valueType) {
if (valueType.managedObject.has_value())
{
callback(valueType.errorCode, valueType.managedObject.value());
return;
}
callback(valueType.errorCode, {});
});
}
void ManagedObjectStore::getManagedObjectsInStore(
const KeyType& keyType, const ManagedObjectStoreContext& requestContext,
ManagedStoreCb&& callback)
{
BMCWEB_LOG_STATEFUL_DEBUG
<< "getManagedObjectsInStore:"
<< " service: " << keyType.serviceName
<< " path: " << keyType.objectPath.str << " interface: "
<< keyType.interface << " property: " << keyType.property
<< " requestContext: " << requestContext.toString();
// Execute callback immidiately if object is cached in store.
std::string keyTypeStr = keyType.toString();
auto managedObjectIter = managedObjects.find(keyTypeStr);
if (managedObjectIter != managedObjects.end())
{
ValueType& mappedValueInStore = managedObjectIter->second;
const std::chrono::steady_clock::time_point timeNow = clockNow();
const auto currentAge =
clockSince(mappedValueInStore.lastRefreshAt, timeNow);
// update lastUsed:
mappedValueInStore.lastUsed = timeNow;
// count number of times used:
mappedValueInStore.numTimesUsed += 1;
// update lastUsedAges:
if (!mappedValueInStore.lastUsedAges)
{
mappedValueInStore.lastUsedAges = std::make_shared<
std::list<std::chrono::steady_clock::duration>>();
}
mappedValueInStore.lastUsedAges->push_back(currentAge);
while (mappedValueInStore.lastUsedAges->size() >=
mappedValueInStore.kLastUsedAgesMaxSize)
{
mappedValueInStore.lastUsedAges->pop_front();
}
BMCWEB_LOG_STATEFUL_DEBUG
<< "ManagedObject found in store. "
<< " service: " << keyType.serviceName
<< " path: " << keyType.objectPath.str << " interface: "
<< keyType.interface << " property: " << keyType.property
<< " CurrentAge: " << clockDurationMilliseconds(currentAge)
<< " Context: " << requestContext.toString()
<< " Value: " << mappedValueInStore.toString();
// check if the current object is stale:
const bool isObjectStale = currentAge >= (this->config.tfixedThreshold +
this->config.tgraceThreshold);
// can we use it as is:
bool isUseCurrentObject = !isObjectStale;
if (requestContext.hintMaxAge > std::chrono::seconds(0))
{
// we have to refresh it because of hintMaxAge
isUseCurrentObject = (currentAge <= requestContext.hintMaxAge);
this->managedStoreTracker.countGetManagedObjectsCacheMissMaxAge +=
1;
BMCWEB_LOG_STATEFUL_DEBUG
<< "apply:"
<< " hintMaxAgeMS: "
<< clockDurationMilliseconds(requestContext.hintMaxAge);
}
// Return if the object is still fresh.
if (isUseCurrentObject)
{
this->managedStoreTracker.countGetManagedObjectsCacheHit += 1;
callback(mappedValueInStore);
return;
}
// Evict the object from store as it has became stale.
if (isObjectStale)
{
BMCWEB_LOG_ALWAYS
<< "Object has become stale! "
<< " service: " << keyType.serviceName
<< " path: " << keyType.objectPath.str << " interface: "
<< keyType.interface << " property: " << keyType.property
<< " CurrentAge: " << clockDurationMilliseconds(currentAge)
<< " Context: " << requestContext.toString()
<< " Value: " << mappedValueInStore.toString();
managedObjects.erase(managedObjectIter->first);
}
}
BMCWEB_LOG_STATEFUL_DEBUG
<< "Fetching fresh object over dbus. "
<< " Key: " << keyType.toString()
<< " requestContext: " << requestContext.toString();
// Handle concurrent requests for the same object by storing callback
// for the request.
auto cbMapIter = requestCbMap.find(keyTypeStr);
if (cbMapIter != requestCbMap.end())
{
// Since a request has already read through, any subsequent request
// will not read through. The callback for these duplicate requests
// will be stored and invoked when the first request gets a response
// from dbus.
cbMapIter->second.push(std::move(callback));
return;
}
requestCbMap[keyTypeStr].push(std::move(callback));
this->managedStoreTracker.countGetManagedObjectsCacheMiss += 1;
// Note: This refresh operation is not rate limited i.e all incoming
// requests with cache-miss will continue to read through without a cap on
// pending i/o since we don't want to block on scheduler or send a failure
// response.
refreshObject(keyType, true);
}
void ManagedObjectStore::clearAllObjects()
{
this->managedObjects.clear();
// looks like it's the only way to do this:
this->pq = ManagedStorePriorityQueue();
}
void ManagedObjectStore::getManagedObjectsFromDbusService(
const std::string& service, const sdbusplus::message::object_path& path,
ManagedStoreCb&& callback)
{
dbus::utility::getManagedObjects(
service, path,
[this, self = shared_from_this(), callback{std::move(callback)}](
const boost::system::error_code& ec,
const dbus::utility::ManagedObjectType& objects) {
std::chrono::steady_clock::time_point timeNow = clockNow();
ValueType value(objects, ec, timeNow,
timeNow + this->config.tfixedThreshold);
callback(value);
});
}
void ManagedObjectStore::getManagedPropertiesFromDbusService(
const std::string& service, const sdbusplus::message::object_path& path,
const std::string& interface, const std::string& property,
ManagedStoreCb&& callback)
{
dbus::utility::getProperty(
service, path, interface, property,
[this, self = shared_from_this(), callback{std::move(callback)}](
const boost::system::error_code& ec,
const dbus::utility::DbusVariantType& propertyValue) {
std::chrono::steady_clock::time_point timeNow = clockNow();
ValueType value(propertyValue, ec, timeNow,
timeNow + this->config.tfixedThreshold);
callback(value);
});
}
void ManagedObjectStore::getManagedPropertiesMapFromDbusService(
const std::string& service, const sdbusplus::message::object_path& path,
const std::string& interface, ManagedStoreCb&& callback)
{
sdbusplus::asio::getAllProperties(
*crow::connections::systemBus, service, path.str, interface,
[this, self = shared_from_this(), callback{std::move(callback)}](
const boost::system::error_code& ec,
const dbus::utility::DBusPropertiesMap& propertyMap) {
std::chrono::steady_clock::time_point timeNow = clockNow();
ValueType value(propertyMap, ec, timeNow,
timeNow + this->config.tfixedThreshold);
callback(value);
});
}
// Calls into dbus service to get subtree.
void ManagedObjectStore::getManagedSubtreeFromDbusService(
const sdbusplus::message::object_path& path, int32_t depth,
const std::vector<std::string>& interfaces, ManagedStoreCb&& callback)
{
crow::connections::systemBus->async_method_call(
[this, self = shared_from_this(), callback{std::move(callback)}](
const boost::system::error_code& ec,
const dbus::utility::MapperGetSubTreeResponse& subtree) {
std::chrono::steady_clock::time_point timeNow = clockNow();
ValueType value(subtree, ec, timeNow,
timeNow + this->config.tfixedThreshold);
callback(value);
},
"xyz.openbmc_project.ObjectMapper",
"/xyz/openbmc_project/object_mapper",
"xyz.openbmc_project.ObjectMapper", "GetSubTree", path.str, depth,
interfaces);
}
// Calls into dbus service to get subtree paths.
void ManagedObjectStore::getManagedSubtreePathsFromDbusService(
const sdbusplus::message::object_path& path, int32_t depth,
const std::vector<std::string>& interfaces, ManagedStoreCb&& callback)
{
crow::connections::systemBus->async_method_call(
[this, self = shared_from_this(), callback{std::move(callback)}](
const boost::system::error_code& ec,
const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) {
std::chrono::steady_clock::time_point timeNow = clockNow();
ValueType value(subtreePaths, ec, timeNow,
timeNow + this->config.tfixedThreshold);
callback(value);
},
"xyz.openbmc_project.ObjectMapper",
"/xyz/openbmc_project/object_mapper",
"xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", path.str, depth,
interfaces);
}
// Calls into dbus service to get subtree.
void ManagedObjectStore::getManagedAssociatedSubtreeFromDbusService(
const sdbusplus::message::object_path& associatedPath,
const sdbusplus::message::object_path& path, int32_t depth,
const std::vector<std::string>& interfaces, ManagedStoreCb&& callback)
{
crow::connections::systemBus->async_method_call(
[this, self = shared_from_this(), callback{std::move(callback)}](
const boost::system::error_code& ec,
const dbus::utility::MapperGetSubTreeResponse& subtree) {
std::chrono::steady_clock::time_point timeNow = clockNow();
ValueType value(subtree, ec, timeNow,
timeNow + this->config.tfixedThreshold);
callback(value);
},
"xyz.openbmc_project.ObjectMapper",
"/xyz/openbmc_project/object_mapper",
"xyz.openbmc_project.ObjectMapper", "GetAssociatedSubTree",
associatedPath, path, depth, interfaces);
}
// Calls into dbus service to get subtree paths.
void ManagedObjectStore::getManagedAssociatedSubtreePathsFromDbusService(
const sdbusplus::message::object_path& associatedPath,
const sdbusplus::message::object_path& path, int32_t depth,
const std::vector<std::string>& interfaces, ManagedStoreCb&& callback)
{
crow::connections::systemBus->async_method_call(
[this, self = shared_from_this(), callback{std::move(callback)}](
const boost::system::error_code& ec,
const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) {
std::chrono::steady_clock::time_point timeNow = clockNow();
ValueType value(subtreePaths, ec, timeNow,
timeNow + this->config.tfixedThreshold);
callback(value);
},
"xyz.openbmc_project.ObjectMapper",
"/xyz/openbmc_project/object_mapper",
"xyz.openbmc_project.ObjectMapper", "GetAssociatedSubTreePaths",
associatedPath, path, depth, interfaces);
}
std::string ManagedObjectStoreConfig::toString() const
{
return this->toJson().dump();
}
nlohmann::json ManagedObjectStoreConfig::toJson() const
{
nlohmann::json obj;
obj["is_enabled"] = this->isEnabled;
obj["pendingDbusResponsesMax"] = this->pendingDbusResponsesMax;
obj["tfixedThresholdMilliseconds"] =
clockDurationMilliseconds(this->tfixedThreshold);
obj["tgraceThresholdMilliseconds"] =
clockDurationMilliseconds(this->tgraceThreshold);
obj["tLRUThresholdMilliseconds"] =
clockDurationMilliseconds(this->tLRUThreshold);
return obj;
}
} // namespace managedStore