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