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