Home | History | Annotate | Download | only in child
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/child/web_database_observer_impl.h"
      6 
      7 #include "base/metrics/histogram.h"
      8 #include "base/strings/string16.h"
      9 #include "content/common/database_messages.h"
     10 #include "third_party/WebKit/public/platform/WebCString.h"
     11 #include "third_party/WebKit/public/platform/WebString.h"
     12 #include "third_party/sqlite/sqlite3.h"
     13 
     14 using blink::WebString;
     15 
     16 namespace content {
     17 
     18 namespace {
     19 
     20 const int kResultHistogramSize = 50;
     21 const int kCallsiteHistogramSize = 10;
     22 
     23 int DetermineHistogramResult(int websql_error, int sqlite_error) {
     24   // If we have a sqlite error, log it after trimming the extended bits.
     25   // There are 26 possible values, but we leave room for some new ones.
     26   if (sqlite_error)
     27     return std::min(sqlite_error & 0xff, 30);
     28 
     29   // Otherwise, websql_error may be an SQLExceptionCode, SQLErrorCode
     30   // or a DOMExceptionCode, or -1 for success.
     31   if (websql_error == -1)
     32     return 0;  // no error
     33 
     34   // SQLExceptionCode starts at 1000
     35   if (websql_error >= 1000)
     36     websql_error -= 1000;
     37 
     38   return std::min(websql_error + 30, kResultHistogramSize - 1);
     39 }
     40 
     41 #define UMA_HISTOGRAM_WEBSQL_RESULT(name, is_sync_database, \
     42                                     callsite, websql_error, sqlite_error) \
     43   do { \
     44     DCHECK(callsite < kCallsiteHistogramSize); \
     45     int result = DetermineHistogramResult(websql_error, sqlite_error); \
     46     if (is_sync_database) { \
     47       UMA_HISTOGRAM_ENUMERATION("websql.Sync." name, \
     48                                 result, kResultHistogramSize); \
     49       if (result) { \
     50         UMA_HISTOGRAM_ENUMERATION("websql.Sync." name ".ErrorSite", \
     51                                   callsite, kCallsiteHistogramSize); \
     52       } \
     53     } else { \
     54       UMA_HISTOGRAM_ENUMERATION("websql.Async." name, \
     55                                 result, kResultHistogramSize); \
     56       if (result) { \
     57         UMA_HISTOGRAM_ENUMERATION("websql.Async." name ".ErrorSite", \
     58                                   callsite, kCallsiteHistogramSize); \
     59       } \
     60     } \
     61   } while (0)
     62 
     63 }  // namespace
     64 
     65 WebDatabaseObserverImpl::WebDatabaseObserverImpl(IPC::SyncMessageFilter* sender)
     66     : sender_(sender),
     67       open_connections_(new storage::DatabaseConnectionsWrapper) {
     68   DCHECK(sender);
     69 }
     70 
     71 WebDatabaseObserverImpl::~WebDatabaseObserverImpl() {
     72 }
     73 
     74 void WebDatabaseObserverImpl::databaseOpened(
     75     const WebString& origin_identifier,
     76     const WebString& database_name,
     77     const WebString& database_display_name,
     78     unsigned long estimated_size) {
     79   open_connections_->AddOpenConnection(origin_identifier.utf8(),
     80                                        database_name);
     81   sender_->Send(new DatabaseHostMsg_Opened(
     82       origin_identifier.utf8(), database_name,
     83       database_display_name, estimated_size));
     84 }
     85 
     86 void WebDatabaseObserverImpl::databaseModified(
     87     const WebString& origin_identifier,
     88     const WebString& database_name) {
     89   sender_->Send(new DatabaseHostMsg_Modified(
     90       origin_identifier.utf8(), database_name));
     91 }
     92 
     93 void WebDatabaseObserverImpl::databaseClosed(
     94     const WebString& origin_identifier,
     95     const WebString& database_name) {
     96   sender_->Send(new DatabaseHostMsg_Closed(
     97       origin_identifier.utf8(), database_name));
     98   open_connections_->RemoveOpenConnection(origin_identifier.utf8(),
     99                                           database_name);
    100 }
    101 
    102 void WebDatabaseObserverImpl::reportOpenDatabaseResult(
    103     const WebString& origin_identifier,
    104     const WebString& database_name,
    105     bool is_sync_database,
    106     int callsite, int websql_error, int sqlite_error) {
    107   UMA_HISTOGRAM_WEBSQL_RESULT("OpenResult", is_sync_database, callsite,
    108                               websql_error, sqlite_error);
    109   HandleSqliteError(origin_identifier, database_name, sqlite_error);
    110 }
    111 
    112 void WebDatabaseObserverImpl::reportChangeVersionResult(
    113     const WebString& origin_identifier,
    114     const WebString& database_name,
    115     bool is_sync_database,
    116     int callsite, int websql_error, int sqlite_error) {
    117   UMA_HISTOGRAM_WEBSQL_RESULT("ChangeVersionResult", is_sync_database, callsite,
    118                               websql_error, sqlite_error);
    119   HandleSqliteError(origin_identifier, database_name, sqlite_error);
    120 }
    121 
    122 void WebDatabaseObserverImpl::reportStartTransactionResult(
    123     const WebString& origin_identifier,
    124     const WebString& database_name,
    125     bool is_sync_database,
    126     int callsite, int websql_error, int sqlite_error) {
    127   UMA_HISTOGRAM_WEBSQL_RESULT("BeginResult", is_sync_database, callsite,
    128                               websql_error, sqlite_error);
    129   HandleSqliteError(origin_identifier, database_name, sqlite_error);
    130 }
    131 
    132 void WebDatabaseObserverImpl::reportCommitTransactionResult(
    133     const WebString& origin_identifier,
    134     const WebString& database_name,
    135     bool is_sync_database,
    136     int callsite, int websql_error, int sqlite_error) {
    137   UMA_HISTOGRAM_WEBSQL_RESULT("CommitResult", is_sync_database, callsite,
    138                               websql_error, sqlite_error);
    139   HandleSqliteError(origin_identifier, database_name, sqlite_error);
    140 }
    141 
    142 void WebDatabaseObserverImpl::reportExecuteStatementResult(
    143     const WebString& origin_identifier,
    144     const WebString& database_name,
    145     bool is_sync_database,
    146     int callsite, int websql_error, int sqlite_error) {
    147   UMA_HISTOGRAM_WEBSQL_RESULT("StatementResult", is_sync_database, callsite,
    148                               websql_error, sqlite_error);
    149   HandleSqliteError(origin_identifier, database_name, sqlite_error);
    150 }
    151 
    152 void WebDatabaseObserverImpl::reportVacuumDatabaseResult(
    153     const WebString& origin_identifier,
    154     const WebString& database_name,
    155     bool is_sync_database,
    156     int sqlite_error) {
    157   int result = DetermineHistogramResult(-1, sqlite_error);
    158   if (is_sync_database) {
    159     UMA_HISTOGRAM_ENUMERATION("websql.Sync.VacuumResult",
    160                               result, kResultHistogramSize);
    161   } else {
    162     UMA_HISTOGRAM_ENUMERATION("websql.Async.VacuumResult",
    163                               result, kResultHistogramSize);
    164   }
    165   HandleSqliteError(origin_identifier, database_name, sqlite_error);
    166 }
    167 
    168 void WebDatabaseObserverImpl::WaitForAllDatabasesToClose() {
    169   open_connections_->WaitForAllDatabasesToClose();
    170 }
    171 
    172 void WebDatabaseObserverImpl::HandleSqliteError(
    173     const WebString& origin_identifier,
    174     const WebString& database_name,
    175     int error) {
    176   // We filter out errors which the backend doesn't act on to avoid
    177   // a unnecessary ipc traffic, this method can get called at a fairly
    178   // high frequency (per-sqlstatement).
    179   if (error == SQLITE_CORRUPT || error == SQLITE_NOTADB) {
    180     sender_->Send(new DatabaseHostMsg_HandleSqliteError(
    181         origin_identifier.utf8(),
    182         database_name,
    183         error));
    184   }
    185 }
    186 
    187 }  // namespace content
    188