PEL: Keep size statistics of PEL repo

Keep a running total of several size statistics of the PEL repository.

The statistics are:
* Total size of all PELs
* Total size of BMC created PELs
* Total size of BMC created informational PELs
* Total size of BMC created non-informational PELs
* Total size of non-BMC created PELs
* Total size of non-BMC created informational PELs
* Total size of non-BMC created non-informational PELs

Here, size refers to the disk size the PEL uses, which is different than
the file size.  The disk size is retrieved from the stat() function and
is the number of 512B blocks used.

The term 'informational' above doesn't strictly refer to the
informational severity value (0x0), but also includes other cases, such
as hidden recovered PELs.

Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: I07a3ccd7cfe802a344a2db47daba5fb05d56489f
diff --git a/extensions/openpower-pels/repository.cpp b/extensions/openpower-pels/repository.cpp
index 4e40678..8458fcc 100644
--- a/extensions/openpower-pels/repository.cpp
+++ b/extensions/openpower-pels/repository.cpp
@@ -118,6 +118,8 @@
                 _pelAttributes.emplace(
                     LogID(pelID(pel.id()), obmcID(pel.obmcLogID())),
                     attributes);
+
+                updateRepoStats(attributes, true);
             }
             else
             {
@@ -167,6 +169,8 @@
     _pelAttributes.emplace(LogID(pelID(pel->id()), obmcID(pel->obmcLogID())),
                            attributes);
 
+    updateRepoStats(attributes, true);
+
     processAddCallbacks(*pel);
 }
 
@@ -206,6 +210,8 @@
     auto pel = findPEL(id);
     if (pel != _pelAttributes.end())
     {
+        updateRepoStats(pel->second, false);
+
         log<level::DEBUG>("Removing PEL from repository",
                           entry("PEL_ID=0x%X", pel->first.pelID.id),
                           entry("OBMC_LOG_ID=%d", pel->first.obmcID.id));
@@ -425,5 +431,73 @@
     }
 }
 
+bool Repository::isServiceableSev(const PELAttributes& pel)
+{
+    auto sevType = static_cast<SeverityType>(pel.severity & 0xF0);
+    auto sevPVEntry =
+        pel_values::findByValue(pel.severity, pel_values::severityValues);
+    std::string sevName = std::get<pel_values::registryNamePos>(*sevPVEntry);
+
+    bool check1 = (sevType == SeverityType::predictive) ||
+                  (sevType == SeverityType::unrecoverable) ||
+                  (sevType == SeverityType::critical);
+
+    bool check2 = ((sevType == SeverityType::recovered) ||
+                   (sevName == "symptom_recovered")) &&
+                  !pel.actionFlags.test(hiddenFlagBit);
+
+    bool check3 = (sevName == "symptom_predictive") ||
+                  (sevName == "symptom_unrecoverable") ||
+                  (sevName == "symptom_critical");
+
+    return check1 || check2 || check3;
+}
+
+void Repository::updateRepoStats(const PELAttributes& pel, bool pelAdded)
+{
+    auto isServiceable = Repository::isServiceableSev(pel);
+    auto bmcPEL = CreatorID::openBMC == static_cast<CreatorID>(pel.creator);
+
+    auto adjustSize = [pelAdded, &pel](auto& runningSize) {
+        if (pelAdded)
+        {
+            runningSize += pel.sizeOnDisk;
+        }
+        else
+        {
+            runningSize = std::max(static_cast<int64_t>(runningSize) -
+                                       static_cast<int64_t>(pel.sizeOnDisk),
+                                   static_cast<int64_t>(0));
+        }
+    };
+
+    adjustSize(_sizes.total);
+
+    if (bmcPEL)
+    {
+        adjustSize(_sizes.bmc);
+        if (isServiceable)
+        {
+            adjustSize(_sizes.bmcServiceable);
+        }
+        else
+        {
+            adjustSize(_sizes.bmcInfo);
+        }
+    }
+    else
+    {
+        adjustSize(_sizes.nonBMC);
+        if (isServiceable)
+        {
+            adjustSize(_sizes.nonBMCServiceable);
+        }
+        else
+        {
+            adjustSize(_sizes.nonBMCInfo);
+        }
+    }
+}
+
 } // namespace pels
 } // namespace openpower