blob: ad6cce14380e600a4528fcf9326d52795fe37e54 [file] [log] [blame]
// Copyright 2018 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_ENCODER_OBSERVATION_STORE_H_
#define COBALT_ENCODER_OBSERVATION_STORE_H_
#include <deque>
#include <memory>
#include <string>
#include <vector>
#include "./envelope.pb.h"
#include "./observation.pb.h"
#include "./observation_batch.pb.h"
namespace cobalt {
namespace encoder {
// ObservationStoreWriterInterface is an abstract interface to a store
// of Observations, to be used by code that writes to this store. This is
// isolated into an abstract interface that can be mocked out in tests.
class ObservationStoreWriterInterface {
public:
virtual ~ObservationStoreWriterInterface() = default;
enum StoreStatus {
// AddEncryptedObservation() succeeded.
kOk = 0,
// The Observation was not added to the store because it is too big.
kObservationTooBig,
// The observation was not added to the store because it is full. The
// Observation itself is not too big to be added otherwise.
kStoreFull,
// The Observation was not added to the store because of an unspecified
// writing error. It may be a file system error, or some other reason.
kWriteFailed,
};
virtual StoreStatus AddEncryptedObservation(
std::unique_ptr<EncryptedMessage> message,
std::unique_ptr<ObservationMetadata> metadata) = 0;
// Returns the number of Observations that have been added to the
// ObservationStore.
virtual size_t num_observations_added() = 0;
// Resets the count of Observations that have been added to the
// ObservationStore.
virtual void ResetObservationCounter() = 0;
};
// ObservationStore is an abstract interface to an underlying store of encrypted
// observations and their metadata. These are organized within the store into
// Envelopes. Individual (encrypted observation, metadata) pairs are added
// one-at-a-time via the method AddEncryptedObservation(). These pairs are
// pooled together and will eventually be combined into an Envelope. These
// Envelopes are then collected into a list, and will be returned one-at-a-time
// from calls to TakeNextEnvelopeHolder(). If there are no envelopes available
// to return, TakeNextEnvelopeHolder() will return nullptr.
//
// The EnvelopeHolders that are returned from this method should be treated as
// "owned" by the caller. When the EnvelopeHolder is destroyed, its underlying
// data is also deleted. If the underlying data should not be deleted (e.g. if
// the upload failed), the EnvelopeHolder should be placed back into the
// ObservationStore using the ReturnEnvelopeHolder() method.
class ObservationStore : public ObservationStoreWriterInterface {
public:
// EnvelopeHolder holds a reference to a single Envelope and its underlying
// data storage. An instance of EnvelopeHolder is considered to own its
// Envelope. When EnvelopeHolder is deleted, the underlying data storage for
// the owned Envelope will be deleted. The ObservationStore considers the
// envelopes owned by EnvelopeHolders to no longer be in the store.
class EnvelopeHolder {
public:
EnvelopeHolder() {}
// When this EnvelopeHolder is deleted, the underlying data will be deleted.
virtual ~EnvelopeHolder() {}
// MergeWith takes posession of the Envelope owned by |other| and merges
// that EnvelopeHolder's underlying data with that of its own. After the
// call completes, |other| no longer owns any Envelope and it is deleted
// without deleting any underlying data.
virtual void MergeWith(std::unique_ptr<EnvelopeHolder> other) = 0;
// Returns a const reference to the Envelope owned by this EnvelopeHolder.
// This is not necessarily a cheap operation and may involve reading from
// disk.
virtual const Envelope& GetEnvelope() = 0;
// Returns an estimated size on the wire of the resulting Envelope owned by
// thes EnvelopeHolder.
virtual size_t Size() = 0;
private:
EnvelopeHolder(const EnvelopeHolder&) = delete;
EnvelopeHolder& operator=(const EnvelopeHolder&) = delete;
};
// max_bytes_per_observation. AddEncryptedObservation() will return
// kObservationTooBig if the given encrypted Observation's serialized size is
// bigger than this.
//
// max_bytes_per_envelope. When pooling together observations into an
// Envelope, the ObservationStore will try not to form envelopes larger than
// this size. This should be used to avoid sending messages over gRPC or HTTP
// that are too large.
//
// max_bytes_total. This is the maximum size of the Observations in the store.
// If the size of the accumulated Observation data reaches this value then
// ObservationStore will not accept any more Observations:
// AddEncryptedObservation() will return kStoreFull, until enough observations
// are removed from the store.
//
// REQUIRED:
// 0 <= max_bytes_per_observation <= max_bytes_per_envelope <= max_bytes_total
// 0 <= max_bytes_per_envelope
explicit ObservationStore(size_t max_bytes_per_observation,
size_t max_bytes_per_envelope,
size_t max_bytes_total);
virtual ~ObservationStore() {}
// Returns a human-readable name for the StoreStatus.
static std::string StatusDebugString(StoreStatus status);
// Adds the given (encrypted observation, metadata) pair into the store. If
// this causes the pool of observations to exceed max_bytes_per_envelope, then
// the ObservationStore will construct an EnvelopeHolder to be returned from
// TakeNextEnvelopeHolder().
virtual StoreStatus AddEncryptedObservation(
std::unique_ptr<EncryptedMessage> message,
std::unique_ptr<ObservationMetadata> metadata) = 0;
// Returns the next EnvelopeHolder from the list of EnvelopeHolders in the
// store. If there are no more EnvelopeHolders available, this will return
// nullptr. A given EnvelopeHolder will only be returned from this function
// *once* unless it is subsequently returned using ReturnEnvelopeHolder.
virtual std::unique_ptr<EnvelopeHolder> TakeNextEnvelopeHolder() = 0;
// ReturnEnvelopeHolder takes an EnvelopeHolder and adds it back to the store
// so that it may be returned by a later call to TakeNextEnvelopeHolder(). Use
// this when an envelope failed to upload, so the underlying data should not
// be deleted.
virtual void ReturnEnvelopeHolder(
std::unique_ptr<EnvelopeHolder> envelope) = 0;
// Returns true when the size of the data in the ObservationStore exceeds 60%
// of max_bytes_total.
bool IsAlmostFull() const;
// Returns an approximation of the size of all the data in the store.
virtual size_t Size() const = 0;
// Returns wether or not the store is entirely empty.
virtual bool Empty() const = 0;
protected:
const size_t max_bytes_per_observation_;
const size_t max_bytes_per_envelope_;
const size_t max_bytes_total_;
const size_t almost_full_threshold_;
};
} // namespace encoder
} // namespace cobalt
#endif // COBALT_ENCODER_OBSERVATION_STORE_H_