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/WebKit/public/web/WebDatabase.h"
     13 #include "third_party/sqlite/sqlite3.h"
     14 
     15 using WebKit::WebDatabase;
     16 
     17 namespace content {
     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 HISTOGRAM_WEBSQL_RESULT(name, database, callsite, \
     42                                 websql_error, sqlite_error) \
     43   do { \
     44     DCHECK(callsite < kCallsiteHistogramSize); \
     45     int result = DetermineHistogramResult(websql_error, sqlite_error); \
     46     if (database.isSyncDatabase()) { \
     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(
     66     IPC::SyncMessageFilter* sender)
     67     : sender_(sender),
     68       open_connections_(new webkit_database::DatabaseConnectionsWrapper) {
     69   DCHECK(sender);
     70 }
     71 
     72 WebDatabaseObserverImpl::~WebDatabaseObserverImpl() {
     73 }
     74 
     75 void WebDatabaseObserverImpl::databaseOpened(
     76     const WebDatabase& database) {
     77   std::string origin_identifier =
     78       database.securityOrigin().databaseIdentifier().utf8();
     79   string16 database_name = database.name();
     80   open_connections_->AddOpenConnection(origin_identifier, database_name);
     81   sender_->Send(new DatabaseHostMsg_Opened(
     82       origin_identifier, database_name,
     83       database.displayName(), database.estimatedSize()));
     84 }
     85 
     86 void WebDatabaseObserverImpl::databaseModified(
     87     const WebDatabase& database) {
     88   sender_->Send(new DatabaseHostMsg_Modified(
     89       database.securityOrigin().databaseIdentifier().utf8(), database.name()));
     90 }
     91 
     92 void WebDatabaseObserverImpl::databaseClosed(
     93     const WebDatabase& database) {
     94   std::string origin_identifier =
     95       database.securityOrigin().databaseIdentifier().utf8();
     96   string16 database_name = database.name();
     97   sender_->Send(new DatabaseHostMsg_Closed(
     98       origin_identifier, database_name));
     99   open_connections_->RemoveOpenConnection(origin_identifier, database_name);
    100 }
    101 
    102 void WebDatabaseObserverImpl::reportOpenDatabaseResult(
    103     const WebDatabase& database, int callsite, int websql_error,
    104     int sqlite_error) {
    105   HISTOGRAM_WEBSQL_RESULT("OpenResult", database, callsite,
    106                           websql_error, sqlite_error);
    107   HandleSqliteError(database, sqlite_error);
    108 }
    109 
    110 void WebDatabaseObserverImpl::reportChangeVersionResult(
    111     const WebDatabase& database, int callsite, int websql_error,
    112     int sqlite_error) {
    113   HISTOGRAM_WEBSQL_RESULT("ChangeVersionResult", database, callsite,
    114                           websql_error, sqlite_error);
    115   HandleSqliteError(database, sqlite_error);
    116 }
    117 
    118 void WebDatabaseObserverImpl::reportStartTransactionResult(
    119     const WebDatabase& database, int callsite, int websql_error,
    120     int sqlite_error) {
    121   HISTOGRAM_WEBSQL_RESULT("BeginResult", database, callsite,
    122                           websql_error, sqlite_error);
    123   HandleSqliteError(database, sqlite_error);
    124 }
    125 
    126 void WebDatabaseObserverImpl::reportCommitTransactionResult(
    127     const WebDatabase& database, int callsite, int websql_error,
    128     int sqlite_error) {
    129   HISTOGRAM_WEBSQL_RESULT("CommitResult", database, callsite,
    130                           websql_error, sqlite_error);
    131   HandleSqliteError(database, sqlite_error);
    132 }
    133 
    134 void WebDatabaseObserverImpl::reportExecuteStatementResult(
    135     const WebDatabase& database, int callsite, int websql_error,
    136     int sqlite_error) {
    137   HISTOGRAM_WEBSQL_RESULT("StatementResult", database, callsite,
    138                           websql_error, sqlite_error);
    139   HandleSqliteError(database, sqlite_error);
    140 }
    141 
    142 void WebDatabaseObserverImpl::reportVacuumDatabaseResult(
    143     const WebDatabase& database, int sqlite_error) {
    144   int result = DetermineHistogramResult(-1, sqlite_error);
    145   if (database.isSyncDatabase()) {
    146     UMA_HISTOGRAM_ENUMERATION("websql.Sync.VacuumResult",
    147                               result, kResultHistogramSize);
    148   } else {
    149     UMA_HISTOGRAM_ENUMERATION("websql.Async.VacuumResult",
    150                               result, kResultHistogramSize);
    151   }
    152   HandleSqliteError(database, sqlite_error);
    153 }
    154 
    155 void WebDatabaseObserverImpl::WaitForAllDatabasesToClose() {
    156   open_connections_->WaitForAllDatabasesToClose();
    157 }
    158 
    159 void WebDatabaseObserverImpl::HandleSqliteError(
    160     const WebDatabase& database, int error) {
    161   // We filter out errors which the backend doesn't act on to avoid
    162   // a unnecessary ipc traffic, this method can get called at a fairly
    163   // high frequency (per-sqlstatement).
    164   if (error == SQLITE_CORRUPT || error == SQLITE_NOTADB) {
    165     sender_->Send(new DatabaseHostMsg_HandleSqliteError(
    166         database.securityOrigin().databaseIdentifier().utf8(),
    167         database.name(),
    168         error));
    169   }
    170 }
    171 
    172 }  // namespace content
    173