sensor-cache: Add cache for sdr and threshold

Add cache for sdr and threshold so that it does not have to make DBus
calls every time.

Tested: Verify the ipmi sensor list/sdr list works fine.

Signed-off-by: Lei YU <yulei.sh@bytedance.com>
Change-Id: I8047144b1f66b95414905d1a065c9bf54410f0f5
diff --git a/sensorhandler.cpp b/sensorhandler.cpp
index 350eced..143982d 100644
--- a/sensorhandler.cpp
+++ b/sensorhandler.cpp
@@ -79,6 +79,13 @@
     uint8_t sennum;
 } __attribute__((packed));
 
+using SDRCacheMap = std::unordered_map<uint8_t, get_sdr::SensorDataFullRecord>;
+SDRCacheMap sdrCacheMap __attribute__((init_priority(101)));
+
+using SensorThresholdMap =
+    std::unordered_map<uint8_t, get_sdr::GetSensorThresholdsResponse>;
+SensorThresholdMap sensorThresholdMap __attribute__((init_priority(101)));
+
 int get_bus_for_path(const char* path, char** busname)
 {
     return mapper_get_service(bus, path, busname);
@@ -598,8 +605,13 @@
         return ipmi::responseSuccess();
     }
 
-    get_sdr::GetSensorThresholdsResponse resp{};
-    resp = getSensorThresholds(ctx, sensorNum);
+    auto it = sensorThresholdMap.find(sensorNum);
+    if (it == sensorThresholdMap.end())
+    {
+        sensorThresholdMap[sensorNum] = getSensorThresholds(ctx, sensorNum);
+    }
+
+    const auto& resp = sensorThresholdMap[sensorNum];
 
     return ipmi::responseSuccess(resp.validMask, resp.lowerNonCritical,
                                  resp.lowerCritical, resp.lowerNonRecoverable,
@@ -764,6 +776,8 @@
             std::get<propertyName>(property), ipmi::Value(valueToSet));
     }
 
+    // Invalidate the cache
+    sensorThresholdMap.erase(sensorNum);
     return ipmi::responseSuccess();
 }
 
@@ -1076,7 +1090,6 @@
     ipmi_ret_t ret = IPMI_CC_OK;
     get_sdr::GetSdrReq* req = (get_sdr::GetSdrReq*)request;
     get_sdr::GetSdrResp* resp = (get_sdr::GetSdrResp*)response;
-    get_sdr::SensorDataFullRecord record = {0};
 
     // Note: we use an iterator so we can provide the next ID at the end of
     // the call.
@@ -1112,30 +1125,37 @@
 
     uint8_t sensor_id = sensor->first;
 
-    /* Header */
-    get_sdr::header::set_record_id(sensor_id, &(record.header));
-    record.header.sdr_version = 0x51; // Based on IPMI Spec v2.0 rev 1.1
-    record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
-    record.header.record_length = sizeof(record.key) + sizeof(record.body);
-
-    /* Key */
-    get_sdr::key::set_owner_id_bmc(&(record.key));
-    record.key.sensor_number = sensor_id;
-
-    /* Body */
-    record.body.entity_id = sensor->second.entityType;
-    record.body.sensor_type = sensor->second.sensorType;
-    record.body.event_reading_type = sensor->second.sensorReadingType;
-    record.body.entity_instance = sensor->second.instance;
-    if (ipmi::sensor::Mutability::Write ==
-        (sensor->second.mutability & ipmi::sensor::Mutability::Write))
+    auto it = sdrCacheMap.find(sensor_id);
+    if (it == sdrCacheMap.end())
     {
-        get_sdr::body::init_settable_state(true, &(record.body));
+        /* Header */
+        get_sdr::SensorDataFullRecord record = {0};
+        get_sdr::header::set_record_id(sensor_id, &(record.header));
+        record.header.sdr_version = 0x51; // Based on IPMI Spec v2.0 rev 1.1
+        record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
+        record.header.record_length = sizeof(record.key) + sizeof(record.body);
+
+        /* Key */
+        get_sdr::key::set_owner_id_bmc(&(record.key));
+        record.key.sensor_number = sensor_id;
+
+        /* Body */
+        record.body.entity_id = sensor->second.entityType;
+        record.body.sensor_type = sensor->second.sensorType;
+        record.body.event_reading_type = sensor->second.sensorReadingType;
+        record.body.entity_instance = sensor->second.instance;
+        if (ipmi::sensor::Mutability::Write ==
+            (sensor->second.mutability & ipmi::sensor::Mutability::Write))
+        {
+            get_sdr::body::init_settable_state(true, &(record.body));
+        }
+
+        // Set the type-specific details given the DBus interface
+        populate_record_from_dbus(&(record.body), &(sensor->second), data_len);
+        sdrCacheMap[sensor_id] = std::move(record);
     }
 
-    // Set the type-specific details given the DBus interface
-    ret =
-        populate_record_from_dbus(&(record.body), &(sensor->second), data_len);
+    const auto& record = sdrCacheMap[sensor_id];
 
     if (++sensor == ipmi::sensor::sensors.end())
     {
@@ -1163,7 +1183,8 @@
                          sizeof(record) - req->offset);
 
     std::memcpy(resp->record_data,
-                reinterpret_cast<uint8_t*>(&record) + req->offset, *data_len);
+                reinterpret_cast<const uint8_t*>(&record) + req->offset,
+                *data_len);
 
     // data_len should include the LSB and MSB:
     *data_len +=