summaryrefslogtreecommitdiff
path: root/redfish-core
diff options
context:
space:
mode:
authorNan Zhou <nanzhoumails@gmail.com>2022-03-28 18:45:00 +0300
committerNan Zhou <nanzhoumails@gmail.com>2022-04-11 18:42:31 +0300
commit928fefb9a542b816d7c0418077def2b3874d1b0f (patch)
treefbbf2c8924b3ffbab4159ce54b9a7c3f1b7e71c6 /redfish-core
parenta6b9125ff91500afed34dc923e9bafb90da75ec4 (diff)
downloadbmcweb-928fefb9a542b816d7c0418077def2b3874d1b0f.tar.xz
sensor collection: implement efficient expand handler
This change adds an efficient expand handler for $levels=1 expand at the sensors collection. Instead of Query one sensor at time, it reuses existing codes for Thermal and Power (which has AutoExpand), and queries the whole sensor at one query. It's more efficient than the default expand handler as well since the default handler stills query all the sensors and filter other sensors when querying a single sensor. Performance improves dramatically on a real hardware with 220+ sensors: Before this change, time wget -qO- 'http://localhost/redfish/v1/Chassis/xxx/Sensors?$expand=.($levels=1)' > /tmp/log_slow.json real 0m33.786s user 0m0.000s sys 0m0.000s After this change time wget -qO- 'http://localhost/redfish/v1/Chassis/xxx/Sensors?$expand=.($levels=1)' > /tmp/log_fast.json real 0m0.769s user 0m0.010s sys 0m0.010s TESTED:: 1. QEMU Redfish/IPMI passed 2. Validator passed (though it doesn't support query paramters) 3. Tested on real hardware. { "@odata.id": "/redfish/v1/Chassis/xxx/Sensors", "@odata.type": "#SensorCollection.SensorCollection", "Description": "Collection of Sensors for this Chassis", "Members": [ { "@odata.id": "/redfish/v1/Chassis/xxx/Sensors/abc", "@odata.type": "#Sensor.v1_0_0.Sensor", "Id": "abc", "Name": "abc", "Reading": 3.133, "ReadingRangeMax": 5.8500060148599005, "ReadingRangeMin": 0.0, "ReadingType": "Voltage", "ReadingUnits": "V", "Status": { "Health": "OK", "State": "Enabled" }, "Thresholds": { "LowerCritical": { "Reading": 2.205 }, "UpperCritical": { "Reading": 3.507 } } }, ], "Members@odata.count": 225, "Name": "Sensors" } Signed-off-by: Nan Zhou <nanzhoumails@gmail.com> Change-Id: I745a31d6fe8d0aac08d532ea976bfc1a4a40b19c
Diffstat (limited to 'redfish-core')
-rw-r--r--redfish-core/lib/sensors.hpp124
1 files changed, 94 insertions, 30 deletions
diff --git a/redfish-core/lib/sensors.hpp b/redfish-core/lib/sensors.hpp
index 2e314aca98..ec63945d7c 100644
--- a/redfish-core/lib/sensors.hpp
+++ b/redfish-core/lib/sensors.hpp
@@ -26,6 +26,7 @@
#include <registries/privilege_registry.hpp>
#include <sdbusplus/asio/property.hpp>
#include <utils/json_utils.hpp>
+#include <utils/query_param.hpp>
#include <cmath>
#include <utility>
@@ -177,7 +178,8 @@ class SensorsAsyncResp
const std::vector<const char*>& typesIn,
const std::string_view& subNode) :
asyncResp(asyncResp),
- chassisId(chassisIdIn), types(typesIn), chassisSubNode(subNode)
+ chassisId(chassisIdIn), types(typesIn), chassisSubNode(subNode),
+ efficientExpand(false)
{}
// Store extra data about sensor mapping and return it in callback
@@ -187,11 +189,21 @@ class SensorsAsyncResp
const std::string_view& subNode,
DataCompleteCb&& creationComplete) :
asyncResp(asyncResp),
- chassisId(chassisIdIn), types(typesIn),
- chassisSubNode(subNode), metadata{std::vector<SensorData>()},
+ chassisId(chassisIdIn), types(typesIn), chassisSubNode(subNode),
+ efficientExpand(false), metadata{std::vector<SensorData>()},
dataComplete{std::move(creationComplete)}
{}
+ // sensor collections expand
+ SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& chassisIdIn,
+ const std::vector<const char*>& typesIn,
+ const std::string_view& subNode, bool efficientExpand) :
+ asyncResp(asyncResp),
+ chassisId(chassisIdIn), types(typesIn), chassisSubNode(subNode),
+ efficientExpand(efficientExpand)
+ {}
+
~SensorsAsyncResp()
{
if (asyncResp->res.result() ==
@@ -252,6 +264,7 @@ class SensorsAsyncResp
const std::string chassisId;
const std::vector<const char*> types;
const std::string chassisSubNode;
+ const bool efficientExpand;
private:
std::optional<std::vector<SensorData>> metadata;
@@ -2524,7 +2537,8 @@ inline void getSensorData(
nlohmann::json* sensorJson = nullptr;
- if (sensorSchema == sensors::node::sensors)
+ if (sensorSchema == sensors::node::sensors &&
+ !sensorsAsyncResp->efficientExpand)
{
sensorsAsyncResp->asyncResp->res.jsonValue["@odata.id"] =
"/redfish/v1/Chassis/" + sensorsAsyncResp->chassisId +
@@ -2535,7 +2549,11 @@ inline void getSensorData(
else
{
std::string fieldName;
- if (sensorType == "temperature")
+ if (sensorsAsyncResp->efficientExpand)
+ {
+ fieldName = "Members";
+ }
+ else if (sensorType == "temperature")
{
fieldName = "Temperatures";
}
@@ -2599,6 +2617,16 @@ inline void getSensorData(
sensorsAsyncResp->chassisId));
}
}
+ else if (fieldName == "Members")
+ {
+ tempArray.push_back(
+ {{"@odata.id",
+ "/redfish/v1/Chassis/" +
+ sensorsAsyncResp->chassisId + "/" +
+ sensorsAsyncResp->chassisSubNode + "/" +
+ sensorName}});
+ sensorJson = &(tempArray.back());
+ }
else
{
tempArray.push_back(
@@ -2621,7 +2649,17 @@ inline void getSensorData(
if (sensorsAsyncResp.use_count() == 1)
{
sortJSONResponse(sensorsAsyncResp);
- if (sensorsAsyncResp->chassisSubNode == sensors::node::thermal)
+ if (sensorsAsyncResp->chassisSubNode ==
+ sensors::node::sensors &&
+ sensorsAsyncResp->efficientExpand)
+ {
+ sensorsAsyncResp->asyncResp->res
+ .jsonValue["Members@odata.count"] =
+ sensorsAsyncResp->asyncResp->res.jsonValue["Members"]
+ .size();
+ }
+ else if (sensorsAsyncResp->chassisSubNode ==
+ sensors::node::thermal)
{
populateFanRedundancy(sensorsAsyncResp);
}
@@ -2706,9 +2744,12 @@ inline void
processSensorList(sensorsAsyncResp, sensorNames);
BMCWEB_LOG_DEBUG << "getChassisCb exit";
};
- sensorsAsyncResp->asyncResp->res.jsonValue["Redundancy"] =
- nlohmann::json::array();
-
+ // SensorCollection doesn't contain the Redundancy property
+ if (sensorsAsyncResp->chassisSubNode != sensors::node::sensors)
+ {
+ sensorsAsyncResp->asyncResp->res.jsonValue["Redundancy"] =
+ nlohmann::json::array();
+ }
// Get set of sensors in chassis
getChassis(sensorsAsyncResp, std::move(getChassisCb));
BMCWEB_LOG_DEBUG << "getChassisData exit";
@@ -2923,6 +2964,7 @@ inline void retrieveUriToDbusMap(const std::string& chassis,
namespace sensors
{
+
inline void getChassisCallback(
const std::shared_ptr<SensorsAsyncResp>& asyncResp,
const std::shared_ptr<boost::container::flat_set<std::string>>& sensorNames)
@@ -2958,28 +3000,50 @@ inline void requestRoutesSensorCollection(App& app)
{
BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/")
.privileges(redfish::privileges::getSensorCollection)
- .methods(boost::beast::http::verb::get)(
- [&app](const crow::Request& req,
- const std::shared_ptr<bmcweb::AsyncResp>& aResp,
- const std::string& chassisId) {
- if (!redfish::setUpRedfishRoute(app, req, aResp->res))
- {
- return;
- }
+ .methods(
+ boost::beast::http::verb::get)([&app](
+ const crow::Request& req,
+ const std::shared_ptr<
+ bmcweb::AsyncResp>& aResp,
+ const std::string& chassisId) {
+ query_param::QueryCapabilities capabilities = {
+ .canDelegateExpandLevel = 1,
+ };
+ query_param::Query delegatedQuery;
+ if (!redfish::setUpRedfishRouteWithDelegation(
+ app, req, aResp->res, delegatedQuery, capabilities))
+ {
+ return;
+ }
- BMCWEB_LOG_DEBUG << "SensorCollection doGet enter";
-
- std::shared_ptr<SensorsAsyncResp> asyncResp =
- std::make_shared<SensorsAsyncResp>(
- aResp, chassisId,
- sensors::dbus::paths.at(sensors::node::sensors),
- sensors::node::sensors);
- // Get set of sensors in chassis
- getChassis(
- asyncResp,
- std::bind_front(sensors::getChassisCallback, asyncResp));
- BMCWEB_LOG_DEBUG << "SensorCollection doGet exit";
- });
+ if (delegatedQuery.expandType != query_param::ExpandType::None)
+ {
+ // we perform efficient expand.
+ auto asyncResp = std::make_shared<SensorsAsyncResp>(
+ aResp, chassisId,
+ sensors::dbus::paths.at(sensors::node::sensors),
+ sensors::node::sensors,
+ /*efficientExpand=*/true);
+ getChassisData(asyncResp);
+
+ BMCWEB_LOG_DEBUG
+ << "SensorCollection doGet exit via efficient expand handler";
+ return;
+ };
+
+ // if there's no efficient expand available, we use the default
+ // Query Parameters route
+ auto asyncResp = std::make_shared<SensorsAsyncResp>(
+ aResp, chassisId,
+ sensors::dbus::paths.at(sensors::node::sensors),
+ sensors::node::sensors);
+
+ // We get all sensors as hyperlinkes in the chassis (this
+ // implies we reply on the default query parameters handler)
+ getChassis(asyncResp,
+ std::bind_front(sensors::getChassisCallback, asyncResp));
+ BMCWEB_LOG_DEBUG << "SensorCollection doGet exit";
+ });
}
inline void requestRoutesSensor(App& app)