1cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// found in the LICENSE file.
4cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#ifndef COMPONENTS_METRICS_PERSISTED_LOGS_H_
6cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#define COMPONENTS_METRICS_PERSISTED_LOGS_H_
7cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <string>
9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <vector>
10cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/basictypes.h"
12cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/logging.h"
13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/values.h"
14cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)class PrefService;
16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
17cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)namespace metrics {
18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Maintains a list of unsent logs that are written and restored from disk.
20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)class PersistedLogs {
21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) public:
22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Used to produce a histogram that keeps track of the status of recalling
23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // persisted per logs.
24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  enum LogReadStatus {
25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    RECALL_SUCCESS,         // We were able to correctly recall a persisted log.
26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    LIST_EMPTY,             // Attempting to recall from an empty list.
27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    LIST_SIZE_MISSING,      // Failed to recover list size using GetAsInteger().
28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    LIST_SIZE_TOO_SMALL,    // Too few elements in the list (less than 3).
29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    LIST_SIZE_CORRUPTION,   // List size is not as expected.
30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    LOG_STRING_CORRUPTION,  // Failed to recover log string using GetAsString().
31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    CHECKSUM_CORRUPTION,    // Failed to verify checksum.
32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    CHECKSUM_STRING_CORRUPTION,  // Failed to recover checksum string using
33cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                 // GetAsString().
34cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DECODE_FAIL,            // Failed to decode log.
35cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DEPRECATED_XML_PROTO_MISMATCH,  // The XML and protobuf logs have
36cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                    // inconsistent data.
37cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    END_RECALL_STATUS       // Number of bins to use to create the histogram.
38cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  };
39cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
40f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Constructs a PersistedLogs that stores data in |local_state| under the
4103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // preference |pref_name|.
42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Calling code is responsible for ensuring that the lifetime of |local_state|
43f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // is longer than the lifetime of PersistedLogs.
44f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  //
45f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // When saving logs to disk, stores either the first |min_log_count| logs, or
46f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // at least |min_log_bytes| bytes of logs, whichever is greater.
47f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  //
48f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // If the optional |max_log_size| parameter is non-zero, all logs larger than
495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // that limit will be skipped when writing to disk.
50cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  PersistedLogs(PrefService* local_state,
51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                const char* pref_name,
52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                size_t min_log_count,
53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                size_t min_log_bytes,
54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                size_t max_log_size);
55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ~PersistedLogs();
56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
57cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Write list to storage.
585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  void SerializeLogs() const;
59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Reads the list from the preference.
61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  LogReadStatus DeserializeLogs();
62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
63f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Adds a log to the list.
64f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  void StoreLog(const std::string& log_data);
65cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Stages the most recent log.  The staged_log will remain the same even if
67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // additional logs are added.
68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void StageLog();
69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Remove the staged log.
71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void DiscardStagedLog();
72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // True if a log has been staged.
7403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  bool has_staged_log() const { return staged_log_index_ != -1; }
75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Returns the element in the front of the list.
77cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const std::string& staged_log() const {
78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DCHECK(has_staged_log());
795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return list_[staged_log_index_].compressed_log_data;
80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
81cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
82cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Returns the element in the front of the list.
83cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const std::string& staged_log_hash() const {
84cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DCHECK(has_staged_log());
855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return list_[staged_log_index_].hash;
86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // The number of elements currently stored.
89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  size_t size() const { return list_.size(); }
90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // True if there are no stored logs.
92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  bool empty() const { return list_.empty(); }
93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) private:
95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Writes the list to the ListValue.
965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  void WriteLogsToPrefList(base::ListValue* list) const;
97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Reads the list from the ListValue.
99cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  LogReadStatus ReadLogsFromPrefList(const base::ListValue& list);
100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // A weak pointer to the PrefService object to read and write the preference
102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // from.  Calling code should ensure this object continues to exist for the
103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // lifetime of the PersistedLogs object.
104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  PrefService* local_state_;
105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
106f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // The name of the preference to serialize logs to/from.
107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const char* pref_name_;
108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // We will keep at least this |min_log_count_| logs or |min_log_bytes_| bytes
110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // of logs, whichever is greater, when writing to disk.  These apply after
111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // skipping logs greater than |max_log_size_|.
112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const size_t min_log_count_;
113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const size_t min_log_bytes_;
114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Logs greater than this size will not be written to disk.
116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const size_t max_log_size_;
117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  struct LogHashPair {
119f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // Initializes the members based on uncompressed |log_data|.
120f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    void Init(const std::string& log_data);
121f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
122f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // Compressed log data - a serialized protobuf that's been gzipped.
123f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::string compressed_log_data;
124f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
125f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // The SHA1 hash of log, stored to catch errors from memory corruption.
126f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::string hash;
127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  };
128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // A list of all of the stored logs, stored with SHA1 hashes to check for
129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // corruption while they are stored in memory.
130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::vector<LogHashPair> list_;
131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // The index and type of the log staged for upload. If nothing has been
1335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // staged, the index will be -1.
1345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int staged_log_index_;
135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
136cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(PersistedLogs);
137cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
139cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}  // namespace metrics
140cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#endif  // COMPONENTS_METRICS_PERSISTED_LOGS_H_
142