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
DetermineHistogramResult(int websql_error,int sqlite_error)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
WebDatabaseObserverImpl(IPC::SyncMessageFilter * sender)65 WebDatabaseObserverImpl::WebDatabaseObserverImpl(
66 IPC::SyncMessageFilter* sender)
67 : sender_(sender),
68 open_connections_(new webkit_database::DatabaseConnectionsWrapper) {
69 DCHECK(sender);
70 }
71
~WebDatabaseObserverImpl()72 WebDatabaseObserverImpl::~WebDatabaseObserverImpl() {
73 }
74
databaseOpened(const WebString & origin_identifier,const WebString & database_name,const WebString & database_display_name,unsigned long estimated_size)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
databaseModified(const WebString & origin_identifier,const WebString & database_name)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
databaseClosed(const WebString & origin_identifier,const WebString & database_name)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
reportOpenDatabaseResult(const WebString & origin_identifier,const WebString & database_name,bool is_sync_database,int callsite,int websql_error,int sqlite_error)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
reportChangeVersionResult(const WebString & origin_identifier,const WebString & database_name,bool is_sync_database,int callsite,int websql_error,int sqlite_error)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
reportStartTransactionResult(const WebString & origin_identifier,const WebString & database_name,bool is_sync_database,int callsite,int websql_error,int sqlite_error)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
reportCommitTransactionResult(const WebString & origin_identifier,const WebString & database_name,bool is_sync_database,int callsite,int websql_error,int sqlite_error)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
reportExecuteStatementResult(const WebString & origin_identifier,const WebString & database_name,bool is_sync_database,int callsite,int websql_error,int sqlite_error)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
reportVacuumDatabaseResult(const WebString & origin_identifier,const WebString & database_name,bool is_sync_database,int sqlite_error)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
WaitForAllDatabasesToClose()169 void WebDatabaseObserverImpl::WaitForAllDatabasesToClose() {
170 open_connections_->WaitForAllDatabasesToClose();
171 }
172
HandleSqliteError(const WebString & origin_identifier,const WebString & database_name,int error)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