1 // Copyright (c) 2012 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.
5 #include "content/common/web_database_observer_impl.h"
7 #include "base/metrics/histogram.h"
8 #include "base/string16.h"
9 #include "content/common/database_messages.h"
10 #include "third_party/sqlite/sqlite3.h"
11 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDatabase.h"
12 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h"
14 using WebKit::WebDatabase
;
19 const int kResultHistogramSize
= 50;
20 const int kCallsiteHistogramSize
= 10;
22 int DetermineHistogramResult(int websql_error
, int sqlite_error
) {
23 // If we have a sqlite error, log it after trimming the extended bits.
24 // There are 26 possible values, but we leave room for some new ones.
26 return std::min(sqlite_error
& 0xff, 30);
28 // Otherwise, websql_error may be an SQLExceptionCode, SQLErrorCode
29 // or a DOMExceptionCode, or -1 for success.
30 if (websql_error
== -1)
33 // SQLExceptionCode starts at 1000
34 if (websql_error
>= 1000)
37 return std::min(websql_error
+ 30, kResultHistogramSize
- 1);
40 #define HISTOGRAM_WEBSQL_RESULT(name, database, callsite, \
41 websql_error, sqlite_error) \
43 DCHECK(callsite < kCallsiteHistogramSize); \
44 int result = DetermineHistogramResult(websql_error, sqlite_error); \
45 if (database.isSyncDatabase()) { \
46 UMA_HISTOGRAM_ENUMERATION("websql.Sync." name, \
47 result, kResultHistogramSize); \
49 UMA_HISTOGRAM_ENUMERATION("websql.Sync." name ".ErrorSite", \
50 callsite, kCallsiteHistogramSize); \
53 UMA_HISTOGRAM_ENUMERATION("websql.Async." name, \
54 result, kResultHistogramSize); \
56 UMA_HISTOGRAM_ENUMERATION("websql.Async." name ".ErrorSite", \
57 callsite, kCallsiteHistogramSize); \
64 WebDatabaseObserverImpl::WebDatabaseObserverImpl(
65 IPC::SyncMessageFilter
* sender
)
67 open_connections_(new webkit_database::DatabaseConnectionsWrapper
) {
71 WebDatabaseObserverImpl::~WebDatabaseObserverImpl() {
74 void WebDatabaseObserverImpl::databaseOpened(
75 const WebDatabase
& database
) {
76 string16 origin_identifier
= database
.securityOrigin().databaseIdentifier();
77 string16 database_name
= database
.name();
78 open_connections_
->AddOpenConnection(origin_identifier
, database_name
);
79 sender_
->Send(new DatabaseHostMsg_Opened(
80 origin_identifier
, database_name
,
81 database
.displayName(), database
.estimatedSize()));
84 void WebDatabaseObserverImpl::databaseModified(
85 const WebDatabase
& database
) {
86 sender_
->Send(new DatabaseHostMsg_Modified(
87 database
.securityOrigin().databaseIdentifier(), database
.name()));
90 void WebDatabaseObserverImpl::databaseClosed(
91 const WebDatabase
& database
) {
92 string16 origin_identifier
= database
.securityOrigin().databaseIdentifier();
93 string16 database_name
= database
.name();
94 sender_
->Send(new DatabaseHostMsg_Closed(
95 origin_identifier
, database_name
));
96 open_connections_
->RemoveOpenConnection(origin_identifier
, database_name
);
99 void WebDatabaseObserverImpl::reportOpenDatabaseResult(
100 const WebDatabase
& database
, int callsite
, int websql_error
,
102 HISTOGRAM_WEBSQL_RESULT("OpenResult", database
, callsite
,
103 websql_error
, sqlite_error
);
104 HandleSqliteError(database
, sqlite_error
);
107 void WebDatabaseObserverImpl::reportChangeVersionResult(
108 const WebDatabase
& database
, int callsite
, int websql_error
,
110 HISTOGRAM_WEBSQL_RESULT("ChangeVersionResult", database
, callsite
,
111 websql_error
, sqlite_error
);
112 HandleSqliteError(database
, sqlite_error
);
115 void WebDatabaseObserverImpl::reportStartTransactionResult(
116 const WebDatabase
& database
, int callsite
, int websql_error
,
118 HISTOGRAM_WEBSQL_RESULT("BeginResult", database
, callsite
,
119 websql_error
, sqlite_error
);
120 HandleSqliteError(database
, sqlite_error
);
123 void WebDatabaseObserverImpl::reportCommitTransactionResult(
124 const WebDatabase
& database
, int callsite
, int websql_error
,
126 HISTOGRAM_WEBSQL_RESULT("CommitResult", database
, callsite
,
127 websql_error
, sqlite_error
);
128 HandleSqliteError(database
, sqlite_error
);
131 void WebDatabaseObserverImpl::reportExecuteStatementResult(
132 const WebDatabase
& database
, int callsite
, int websql_error
,
134 HISTOGRAM_WEBSQL_RESULT("StatementResult", database
, callsite
,
135 websql_error
, sqlite_error
);
136 HandleSqliteError(database
, sqlite_error
);
139 void WebDatabaseObserverImpl::reportVacuumDatabaseResult(
140 const WebDatabase
& database
, int sqlite_error
) {
141 int result
= DetermineHistogramResult(-1, sqlite_error
);
142 if (database
.isSyncDatabase()) {
143 UMA_HISTOGRAM_ENUMERATION("websql.Sync.VacuumResult",
144 result
, kResultHistogramSize
);
146 UMA_HISTOGRAM_ENUMERATION("websql.Async.VacuumResult",
147 result
, kResultHistogramSize
);
149 HandleSqliteError(database
, sqlite_error
);
152 void WebDatabaseObserverImpl::WaitForAllDatabasesToClose() {
153 open_connections_
->WaitForAllDatabasesToClose();
156 void WebDatabaseObserverImpl::HandleSqliteError(
157 const WebDatabase
& database
, int error
) {
158 // We filter out errors which the backend doesn't act on to avoid
159 // a unnecessary ipc traffic, this method can get called at a fairly
160 // high frequency (per-sqlstatement).
161 if (error
== SQLITE_CORRUPT
|| error
== SQLITE_NOTADB
) {
162 sender_
->Send(new DatabaseHostMsg_HandleSqliteError(
163 database
.securityOrigin().databaseIdentifier(),
169 } // namespace content