blob: 7354ca51b42a13b01b8f773b3f64421e73addcdd [file]
#ifndef THIRD_PARTY_MILOTIC_EXTERNAL_CC_HFT_ADAPTER_DATA_SOURCE_H_
#define THIRD_PARTY_MILOTIC_EXTERNAL_CC_HFT_ADAPTER_DATA_SOURCE_H_
#include <cstddef>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
#include "absl/hash/hash.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/substitute.h"
#include "absl/time/time.h"
#include "g3/macros.h"
#include "fru_identifier.pb.h"
#include "identifier.pb.h"
#include "payload.pb.h"
#include "sensor_identifier.pb.h"
#include "subscription_params.pb.h"
namespace milotic_hft {
class SensorMutationBatch;
// Abstracts the underlying data source for the High Frequency Telemetry.
// This is implemented by tlBMC and gSys.
class DataSource {
public:
virtual ~DataSource() = default;
// Configures the data source for the given `identifier` with the given
// `sampling_interval_ms`.
// `max_buffer_size` is the maximum number of readings that the data source
// should buffer.
// Returns an error if the data source cannot be configured.
virtual absl::Status ConfigureSamplingInterval(const Identifier& identifier,
int sampling_interval_ms) = 0;
// Configures the data source for the given `identifier` with the given
// `max_batch_size`.
// Returns an error if the data source cannot be configured.
virtual absl::Status ConfigureBatchSize(const Identifier& identifier,
int max_batch_size) = 0;
// Resets the data source to the default configuration for the given
// `identifier`.
virtual absl::Status ResetSamplingIntervalToDefault(
const Identifier& identifier) = 0;
// Resets the batch size to the default configuration for the given
// `identifier`.
virtual absl::Status ResetBatchSizeToDefault(
const Identifier& identifier) = 0;
// Collects the data from the data source for the given `identifier` since the
// `start_time`.
// Returns an error if the data source is cannot serve the data.
virtual absl::StatusOr<Payload> Collect(const Identifier& identifier,
absl::Time start_time) const = 0;
virtual absl::StatusOr<std::vector<Identifier>> GetIdentifiersForResourceType(
const SubscriptionPolicy::ResourceType& resource_type) const = 0;
// Returns the name of the data source. This is used for logging and
// debugging.
virtual std::string GetName() const = 0;
// Creates a sensor mutation batch for the given resource type and
// identifiers. Only one resource type per batch.
virtual std::unique_ptr<SensorMutationBatch> CreateSensorMutationBatch(
SubscriptionPolicy::ResourceType resource_type,
std::vector<Identifier> identifiers);
// Creates a SensorMutationBatch for the given `resource_type`.
// GetIdentifiersForResourceType will be called.
virtual absl::StatusOr<std::unique_ptr<SensorMutationBatch>>
CreateSensorMutationBatch(SubscriptionPolicy::ResourceType resource_type) {
ECCLESIA_ASSIGN_OR_RETURN(auto ids,
GetIdentifiersForResourceType(resource_type));
return CreateSensorMutationBatch(resource_type, std::move(ids));
}
};
// Applies multiple sensor mutations to the data source.
// Default behavior shifts changes to Apply(), through the standard DataSource
// interface.
class SensorMutationBatch {
// An optional sampling interval and an optional max batch size
using Mutation = std::pair<std::optional<int>, std::optional<int>>;
public:
virtual ~SensorMutationBatch() = default;
virtual absl::Status SetSamplingInterval(const Identifier& identifier,
int sampling_interval_ms) & {
ECCLESIA_ASSIGN_OR_RETURN(auto& mutation, GetMutation(identifier));
mutation.first = sampling_interval_ms;
return absl::OkStatus();
}
virtual absl::Status SetBatchSize(const Identifier& identifier,
int max_batch_size) & {
ECCLESIA_ASSIGN_OR_RETURN(auto& mutation, GetMutation(identifier));
mutation.second = max_batch_size;
return absl::OkStatus();
}
virtual absl::Status ResetSensor(const Identifier& identifier) & {
ECCLESIA_RETURN_IF_ERROR(CheckIdentifier(identifier));
resets_.push_back(identifier);
return absl::OkStatus();
}
// Applies the mutations to the data source
virtual absl::Status Apply() && {
for (const auto& [identifier, mutation] : mutations_) {
if (mutation.second.has_value()) {
ECCLESIA_RETURN_IF_ERROR(data_source_->ConfigureBatchSize(
identifier, mutation.second.value()));
}
if (mutation.first.has_value()) {
ECCLESIA_RETURN_IF_ERROR(data_source_->ConfigureSamplingInterval(
identifier, mutation.first.value()));
}
}
for (const auto& identifier : resets_) {
ECCLESIA_RETURN_IF_ERROR(
data_source_->ResetSamplingIntervalToDefault(identifier));
ECCLESIA_RETURN_IF_ERROR(
data_source_->ResetBatchSizeToDefault(identifier));
}
return absl::OkStatus();
}
protected:
friend class DataSource;
SensorMutationBatch(DataSource* data_source,
const std::vector<Identifier>& identifiers)
: data_source_(data_source),
identifiers_(identifiers.begin(), identifiers.end()) {}
// Early detection of bad identifiers prevent Apply() failures.
absl::Status CheckIdentifier(const Identifier& identifier) {
if (!identifiers_.contains(identifier)) {
return absl::NotFoundError(
absl::Substitute("Identifier $0 is not found", identifier));
}
return absl::OkStatus();
}
private:
struct IdentifierHash {
size_t operator()(const Identifier& v) const {
return v.identifier_case() == Identifier::kSensorIdentifier
? absl::HashOf(1, v.sensor_identifier().name())
: absl::HashOf(2, v.fru_identifier().barepath());
}
};
struct IdentifierEqual {
bool operator()(const Identifier& lhs, const Identifier& rhs) const {
if (lhs.identifier_case() != rhs.identifier_case()) {
return false;
}
return lhs.identifier_case() == Identifier::kSensorIdentifier
? lhs.sensor_identifier().name() ==
rhs.sensor_identifier().name()
: lhs.fru_identifier().barepath() ==
rhs.fru_identifier().barepath();
}
};
absl::StatusOr<Mutation&> GetMutation(const Identifier& identifier) {
ECCLESIA_RETURN_IF_ERROR(CheckIdentifier(identifier));
return mutations_[identifier];
}
DataSource* data_source_;
// All sampling interval and batch size changes, per sensor identifier
absl::flat_hash_map<Identifier, Mutation, IdentifierHash, IdentifierEqual>
mutations_;
std::vector<Identifier> resets_;
absl::flat_hash_set<Identifier, IdentifierHash, IdentifierEqual> identifiers_;
};
inline std::unique_ptr<SensorMutationBatch>
DataSource::CreateSensorMutationBatch(
SubscriptionPolicy::ResourceType /*resource_type*/,
std::vector<Identifier> identifiers) {
return std::unique_ptr<SensorMutationBatch>(
new SensorMutationBatch(this, std::move(identifiers)));
}
} // namespace milotic_hft
#endif // THIRD_PARTY_MILOTIC_EXTERNAL_CC_HFT_ADAPTER_DATA_SOURCE_H_