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 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(
     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 WebString& origin_identifier,
     77     const WebString& database_name,
     78     const WebString& database_display_name,
     79     unsigned long estimated_size) {
     80   open_connections_->AddOpenConnection(origin_identifier.utf8(),
     81                                        database_name);
     82   sender_->Send(new DatabaseHostMsg_Opened(
     83       origin_identifier.utf8(), database_name,
     84       database_display_name, estimated_size));
     85 }
     86 
     87 void WebDatabaseObserverImpl::databaseModified(
     88     const WebString& origin_identifier,
     89     const WebString& database_name) {
     90   sender_->Send(new DatabaseHostMsg_Modified(
     91       origin_identifier.utf8(), database_name));
     92 }
     93 
     94 void WebDatabaseObserverImpl::databaseClosed(
     95     const WebString& origin_identifier,
     96     const WebString& database_name) {
     97   sender_->Send(new DatabaseHostMsg_Closed(
     98       origin_identifier.utf8(), database_name));
     99   open_connections_->RemoveOpenConnection(origin_identifier.utf8(),
    100                                           database_name);
    101 }
    102 
    103 void WebDatabaseObserverImpl::reportOpenDatabaseResult(
    104     const WebString& origin_identifier,
    105     const WebString& database_name,
    106     bool is_sync_database,
    107     int callsite, int websql_error, int sqlite_error) {
    108   HISTOGRAM_WEBSQL_RESULT("OpenResult", is_sync_database,
    109                           callsite, websql_error, sqlite_error);
    110   HandleSqliteError(origin_identifier, database_name, sqlite_error);
    111 }
    112 
    113 void WebDatabaseObserverImpl::reportChangeVersionResult(
    114     const WebString& origin_identifier,
    115     const WebString& database_name,
    116     bool is_sync_database,
    117     int callsite, int websql_error, int sqlite_error) {
    118   HISTOGRAM_WEBSQL_RESULT("ChangeVersionResult", is_sync_database,
    119                           callsite, websql_error, sqlite_error);
    120   HandleSqliteError(origin_identifier, database_name, sqlite_error);
    121 }
    122 
    123 void WebDatabaseObserverImpl::reportStartTransactionResult(
    124     const WebString& origin_identifier,
    125     const WebString& database_name,
    126     bool is_sync_database,
    127     int callsite, int websql_error, int sqlite_error) {
    128   HISTOGRAM_WEBSQL_RESULT("BeginResult", is_sync_database,
    129                           callsite, websql_error, sqlite_error);
    130   HandleSqliteError(origin_identifier, database_name, sqlite_error);
    131 }
    132 
    133 void WebDatabaseObserverImpl::reportCommitTransactionResult(
    134     const WebString& origin_identifier,
    135     const WebString& database_name,
    136     bool is_sync_database,
    137     int callsite, int websql_error, int sqlite_error) {
    138   HISTOGRAM_WEBSQL_RESULT("CommitResult", is_sync_database,
    139                           callsite, websql_error, sqlite_error);
    140   HandleSqliteError(origin_identifier, database_name, sqlite_error);
    141 }
    142 
    143 void WebDatabaseObserverImpl::reportExecuteStatementResult(
    144     const WebString& origin_identifier,
    145     const WebString& database_name,
    146     bool is_sync_database,
    147     int callsite, int websql_error, int sqlite_error) {
    148   HISTOGRAM_WEBSQL_RESULT("StatementResult", is_sync_database,
    149                           callsite, websql_error, sqlite_error);
    150   HandleSqliteError(origin_identifier, database_name, sqlite_error);
    151 }
    152 
    153 void WebDatabaseObserverImpl::reportVacuumDatabaseResult(
    154     const WebString& origin_identifier,
    155     const WebString& database_name,
    156     bool is_sync_database,
    157     int sqlite_error) {
    158   int result = DetermineHistogramResult(-1, sqlite_error);
    159   if (is_sync_database) {
    160     UMA_HISTOGRAM_ENUMERATION("websql.Sync.VacuumResult",
    161                               result, kResultHistogramSize);
    162   } else {
    163     UMA_HISTOGRAM_ENUMERATION("websql.Async.VacuumResult",
    164                               result, kResultHistogramSize);
    165   }
    166   HandleSqliteError(origin_identifier, database_name, sqlite_error);
    167 }
    168 
    169 void WebDatabaseObserverImpl::WaitForAllDatabasesToClose() {
    170   open_connections_->WaitForAllDatabasesToClose();
    171 }
    172 
    173 void WebDatabaseObserverImpl::HandleSqliteError(
    174     const WebString& origin_identifier,
    175     const WebString& database_name,
    176     int error) {
    177   // We filter out errors which the backend doesn't act on to avoid
    178   // a unnecessary ipc traffic, this method can get called at a fairly
    179   // high frequency (per-sqlstatement).
    180   if (error == SQLITE_CORRUPT || error == SQLITE_NOTADB) {
    181     sender_->Send(new DatabaseHostMsg_HandleSqliteError(
    182         origin_identifier.utf8(),
    183         database_name,
    184         error));
    185   }
    186 }
    187 
    188 }  // namespace content
    189