| Index: components/precache/core/precache_statistics_table.cc | 
| diff --git a/components/precache/core/precache_statistics_table.cc b/components/precache/core/precache_statistics_table.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..4b8c133b2abd6643550c99f87009a76f3ccde4a6 | 
| --- /dev/null | 
| +++ b/components/precache/core/precache_statistics_table.cc | 
| @@ -0,0 +1,173 @@ | 
| +// Copyright 2013 The Chromium Authors. All rights reserved. | 
| +// Use of this source code is governed by a BSD-style license that can be | 
| +// found in the LICENSE file. | 
| + | 
| +#include "components/precache/core/precache_statistics_table.h" | 
| + | 
| +#include "base/logging.h" | 
| +#include "base/strings/stringprintf.h" | 
| +#include "sql/connection.h" | 
| +#include "sql/statement.h" | 
| + | 
| +using sql::Statement; | 
| + | 
| +namespace { | 
| + | 
| +const char kStatisticsTableName[] = "precache_statistics"; | 
| + | 
| +// Returns the number of 24 hour intervals that have passed between time 0 and | 
| +// |time_on_day|, rounded down. | 
| +int64 GetKey(const base::Time& time_on_day) { | 
| +  return (time_on_day - base::Time()).InDays(); | 
| +} | 
| + | 
| +// Returns the time of the beginning of the 24 hour interval specified by |key|. | 
| +base::Time FromKey(int64 key) { | 
| +  return base::Time() + base::TimeDelta::FromDays(key); | 
| +} | 
| + | 
| +}  // namespace | 
| + | 
| +namespace precache { | 
| + | 
| +PrecacheStatisticsTable::PrecacheStatistics::PrecacheStatistics() | 
| +    : downloaded_precache_motivated_bytes(0), | 
| +      downloaded_non_precache_bytes(0), | 
| +      downloaded_non_precache_bytes_cellular(0), | 
| +      saved_bytes(0), | 
| +      saved_bytes_cellular(0) {} | 
| + | 
| +PrecacheStatisticsTable::PrecacheStatistics::PrecacheStatistics( | 
| +    int64 downloaded_precache_motivated_bytes, | 
| +    int64 downloaded_non_precache_bytes, | 
| +    int64 downloaded_non_precache_bytes_cellular, int64 saved_bytes, | 
| +    int64 saved_bytes_cellular) | 
| +    : downloaded_precache_motivated_bytes(downloaded_precache_motivated_bytes), | 
| +      downloaded_non_precache_bytes(downloaded_non_precache_bytes), | 
| +      downloaded_non_precache_bytes_cellular( | 
| +          downloaded_non_precache_bytes_cellular), | 
| +      saved_bytes(saved_bytes), | 
| +      saved_bytes_cellular(saved_bytes_cellular) {} | 
| + | 
| +bool PrecacheStatisticsTable::PrecacheStatistics::operator==( | 
| +    const PrecacheStatistics& other) const { | 
| +  return downloaded_precache_motivated_bytes == | 
| +             other.downloaded_precache_motivated_bytes && | 
| +         downloaded_non_precache_bytes == other.downloaded_non_precache_bytes && | 
| +         downloaded_non_precache_bytes_cellular == | 
| +             other.downloaded_non_precache_bytes_cellular && | 
| +         saved_bytes == other.saved_bytes && | 
| +         saved_bytes_cellular == other.saved_bytes_cellular; | 
| +} | 
| + | 
| +PrecacheStatisticsTable::PrecacheStatisticsTable() : db_(NULL) {} | 
| + | 
| +PrecacheStatisticsTable::~PrecacheStatisticsTable() {} | 
| + | 
| +void PrecacheStatisticsTable::Init(sql::Connection* db) { | 
| +  DCHECK(!db_);  // Init must only be called once. | 
| +  DCHECK(db);    // The database connection must be non-NULL. | 
| +  db_ = db; | 
| +  CreateTableIfNonExistent(); | 
| +} | 
| + | 
| +void PrecacheStatisticsTable::IncreaseDailyStats( | 
| +    const base::Time& time_on_day, const PrecacheStatistics& delta) { | 
| +  DCHECK(db_); | 
| + | 
| +  // Create a row for that day if there is no existing one. | 
| +  Statement insert_statement(db_->GetCachedStatement( | 
| +      SQL_FROM_HERE, | 
| +      base::StringPrintf("INSERT OR IGNORE INTO %s (date) VALUES(?)", | 
| +                         kStatisticsTableName).c_str())); | 
| + | 
| +  insert_statement.BindInt64(0, GetKey(time_on_day)); | 
| +  insert_statement.Run(); | 
| + | 
| +  // Increase the recorded statistics for that day. | 
| +  Statement update_statement(db_->GetCachedStatement( | 
| +      SQL_FROM_HERE, | 
| +      base::StringPrintf( | 
| +          "UPDATE %s SET " | 
| +              "downloaded_precache_motivated_bytes = " | 
| +                  "downloaded_precache_motivated_bytes + ?, " | 
| +              "downloaded_non_precache_bytes = " | 
| +                  "downloaded_non_precache_bytes + ?, " | 
| +              "downloaded_non_precache_bytes_cellular = " | 
| +                  "downloaded_non_precache_bytes_cellular + ?, " | 
| +              "saved_bytes = saved_bytes + ?, " | 
| +              "saved_bytes_cellular = saved_bytes_cellular + ? " | 
| +          "WHERE date = ?", kStatisticsTableName).c_str())); | 
| + | 
| +  update_statement.BindInt64(0, delta.downloaded_precache_motivated_bytes); | 
| +  update_statement.BindInt64(1, delta.downloaded_non_precache_bytes); | 
| +  update_statement.BindInt64(2, delta.downloaded_non_precache_bytes_cellular); | 
| +  update_statement.BindInt64(3, delta.saved_bytes); | 
| +  update_statement.BindInt64(4, delta.saved_bytes_cellular); | 
| +  update_statement.BindInt64(5, GetKey(time_on_day)); | 
| + | 
| +  update_statement.Run(); | 
| +} | 
| + | 
| +void PrecacheStatisticsTable::GetOldStats(const base::Time& current_time, | 
| +                                          PrecacheStatisticsMap* stats_map) { | 
| +  DCHECK(db_); | 
| +  DCHECK(stats_map);  // |stats_map| must not be NULL. | 
| +  stats_map->clear(); | 
| + | 
| +  Statement statement(db_->GetCachedStatement( | 
| +      SQL_FROM_HERE, base::StringPrintf( | 
| +                         "SELECT date, " | 
| +                         "downloaded_precache_motivated_bytes, " | 
| +                         "downloaded_non_precache_bytes, " | 
| +                         "downloaded_non_precache_bytes_cellular, " | 
| +                         "saved_bytes, " | 
| +                         "saved_bytes_cellular " | 
| +                         "FROM %s WHERE date < ?", | 
| +                         kStatisticsTableName).c_str())); | 
| +  statement.BindInt64(0, GetKey(current_time)); | 
| + | 
| +  while (statement.Step()) { | 
| +    base::Time date = FromKey(statement.ColumnInt64(0)); | 
| +    PrecacheStatistics stats; | 
| + | 
| +    stats.downloaded_precache_motivated_bytes = statement.ColumnInt64(1); | 
| +    stats.downloaded_non_precache_bytes = statement.ColumnInt64(2); | 
| +    stats.downloaded_non_precache_bytes_cellular = statement.ColumnInt64(3); | 
| +    stats.saved_bytes = statement.ColumnInt64(4); | 
| +    stats.saved_bytes_cellular = statement.ColumnInt64(5); | 
| + | 
| +    (*stats_map)[date] = stats; | 
| +  } | 
| +} | 
| + | 
| +void PrecacheStatisticsTable::DeleteOldStats(const base::Time& current_time) { | 
| +  DCHECK(db_); | 
| + | 
| +  Statement statement(db_->GetCachedStatement( | 
| +      SQL_FROM_HERE, base::StringPrintf("DELETE FROM %s WHERE date < ?", | 
| +                                        kStatisticsTableName).c_str())); | 
| + | 
| +  statement.BindInt64(0, GetKey(current_time)); | 
| +  statement.Run(); | 
| +} | 
| + | 
| +void PrecacheStatisticsTable::CreateTableIfNonExistent() { | 
| +  DCHECK(db_); | 
| +  if (db_->DoesTableExist(kStatisticsTableName)) | 
| +    return; | 
| + | 
| +  if (!db_->Execute(base::StringPrintf( | 
| +           "CREATE TABLE %s (date INTEGER, " | 
| +           "downloaded_precache_motivated_bytes INTEGER DEFAULT 0, " | 
| +           "downloaded_non_precache_bytes INTEGER DEFAULT 0, " | 
| +           "downloaded_non_precache_bytes_cellular INTEGER DEFAULT 0, " | 
| +           "saved_bytes INTEGER DEFAULT 0, " | 
| +           "saved_bytes_cellular INTEGER DEFAULT 0, " | 
| +           "PRIMARY KEY(date))", | 
| +           kStatisticsTableName).c_str())) { | 
| +    DLOG(WARNING) << "Could not create precache statistics table in database."; | 
| +  } | 
| +} | 
| + | 
| +}  // namespace precache | 
|  |