blob: 97c43196ad808c15c646e745d98ea84e8d8feee5 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COBALT_ANALYZER_REPORT_MASTER_REPORT_HISTORY_CACHE_H_
#define COBALT_ANALYZER_REPORT_MASTER_REPORT_HISTORY_CACHE_H_
#include <memory>
#include <string>
#include <unordered_map>
#include "analyzer/report_master/report_internal.pb.h"
#include "analyzer/store/report_store.h"
#include "config/analyzer_config.h"
namespace cobalt {
namespace analyzer {
// ReportHistoryCache is used by ReportScheduler to determine the current
// state of report execution for a given report configuration. Let's define
// a |report configuration| to be a triple of the form:
// (ReportConfig, first_day_index, last_day_index). Triples of this form
// act as the indices over which ReportScheduler operates. That is, given
// a triple of this form, ReportScheduler needs to decide whether or not
// a report needs to be executed corresponding to this triple.
// There are two questions that the ReportScheduler needs to ask about a given
// report configuration:
// (i) Is there at least one successfully completed instance of a report for it?
// (ii) Is there currently an ongoing execution of a report for it? We define
// the notion of an ongoing execution to mean that a report was started
// during this instantiation of the ReportMaster. In other words if
// a report was started and then the ReportMaster crashes before the
// report completes and then the ReportMaster is restarted, then the
// ReportStore will contain an indication that the report was started
// but not completed, but the ReportHistoryCache will not consider this to
// be an ongoing execution. The previous report execution will be
// abandoned. Only reports that were started during the current running
// of the ReportMaster count as ongoing reports.
//
// The ReportScheduler queries the ReportHistoryCache for answers to questions
// (i) and (ii) via the methods InProgress() and
// CompletedSuccessfullyOrInProgress(). (The ReportScheduler really wants to
// ask either question (i) or the disjunction of questions (i) and (ii).)
// Furthermore the ReportScheduler notifies the ReportHistoryCache that
// execution of a report instance has begun via the method RecordStart().
//
// The ReportHistoryCache answers questions (i) and (ii) via a combination of
// querying an underlying ReportStore, and keeping an in-memory cache.
// There are two types of queries against the underlying ReportStore that
// are made:
// (a) A scan of all ReportMetadata for a given ReportConfig over a certain
// time window.
// (b) A fetching of the ReportMetadata for a single
// (ReportConfig, first_day_index, last_day_index) triple.
// The type (a) query is only ever performed once per ReportConfig. After
// that all further questions are answered via queries of type (b) and
// the in-memory cache.
//
// Usage:
// Construct an instance of ReportHistoryCache passing in a lower bound for
// the day indices that will ever be used in a query, and a pointer to the
// ReportStore that should be queried. Then Invoke RecordStart() whenever
// a new report execution begins and invoke InProgress() and
// CompletedSuccessfullyOrInProgress() in order to query the current execution
// state of a report configuration.
class ReportHistoryCache {
public:
// Constructor
// |day_index_lower_bound|. All values for first_day_index and last_day_index
// in all invocations of the methods on the constructed instance must be
// breater than or equal to this lower bound or the results are undefined.
//
// |report_store|. The underlying ReportStore that the ReportHistoryCache
// will query.
ReportHistoryCache(uint32_t day_index_lower_bound,
std::shared_ptr<store::ReportStore> report_store);
~ReportHistoryCache();
// Is there currently an in-progress report execution ongoing for the given
// (report_config, first_day_index, last_day_index) triple. This is defined
// to mean that RecordStart() was invoked for this triple with some
// |report_id| and the ReportStore indicates that the report with that
// |report_id| is not yet complete.
bool InProgress(const ReportConfig& report_config, uint32_t first_day_index,
uint32_t last_day_index);
// Is it the case that either there is currently an in-progress report
// execution ongoing for the given
// (report_config, first_day_index, last_day_index) triple or there is
// at least one successfully completed report for this triple?
bool CompletedSuccessfullyOrInProgress(const ReportConfig& report_config,
uint32_t first_day_index,
uint32_t last_day_index);
// This method informs the ReportCache that a new report execution is
// starting.
void RecordStart(const ReportConfig& report_config, uint32_t first_day_index,
uint32_t last_day_index, const ReportId& report_id);
private:
struct ReportHistory;
ReportHistory* GetHistory(const ReportConfig& report_config,
uint32_t first_day_index, uint32_t last_day_index);
bool WasQueryPerformed(const ReportConfig& report_config);
void SetQueryPerformed(const ReportConfig& report_config);
void Refresh(const ReportConfig& report_config, uint32_t first_day_index,
uint32_t last_day_index);
void QueryCompletedReports(const ReportConfig& report_config);
int64_t query_interval_start_time_seconds_;
// The keys of the map represent triples of the form
// (report_config_id, firt_day_index, last_day_index).
std::unordered_map<std::string, std::unique_ptr<ReportHistory> > history_map_;
// We only need to perform a full query for a given report config ID one time
// in the lifetime of this instance. The keys to this map represent
// report config IDs and an entry in the map indicates the query has been
// performed.
std::unordered_map<std::string, bool> query_performed_;
std::shared_ptr<store::ReportStore> report_store_;
};
} // namespace analyzer
} // namespace cobalt
#endif // COBALT_ANALYZER_REPORT_MASTER_REPORT_HISTORY_CACHE_H_