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