Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(597)

Side by Side Diff: sql/connection.cc

Issue 1393393007: [sql] Track uploads of diagnostic data to prevent duplication. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Other changes from pkotwicz Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sql/connection.h ('k') | sql/connection_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "sql/connection.h" 5 #include "sql/connection.h"
6 6
7 #include <string.h> 7 #include <string.h>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/files/file_path.h" 10 #include "base/files/file_path.h"
11 #include "base/files/file_util.h" 11 #include "base/files/file_util.h"
12 #include "base/json/json_file_value_serializer.h"
12 #include "base/lazy_instance.h" 13 #include "base/lazy_instance.h"
13 #include "base/logging.h" 14 #include "base/logging.h"
14 #include "base/message_loop/message_loop.h" 15 #include "base/message_loop/message_loop.h"
15 #include "base/metrics/histogram.h" 16 #include "base/metrics/histogram.h"
16 #include "base/metrics/sparse_histogram.h" 17 #include "base/metrics/sparse_histogram.h"
17 #include "base/strings/string_split.h" 18 #include "base/strings/string_split.h"
18 #include "base/strings/string_util.h" 19 #include "base/strings/string_util.h"
19 #include "base/strings/stringprintf.h" 20 #include "base/strings/stringprintf.h"
20 #include "base/strings/utf_string_conversions.h" 21 #include "base/strings/utf_string_conversions.h"
21 #include "base/synchronization/lock.h" 22 #include "base/synchronization/lock.h"
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after
250 cache_size); 251 cache_size);
251 dump->AddScalar("schema_size", 252 dump->AddScalar("schema_size",
252 base::trace_event::MemoryAllocatorDump::kUnitsBytes, 253 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
253 schema_size); 254 schema_size);
254 dump->AddScalar("statement_size", 255 dump->AddScalar("statement_size",
255 base::trace_event::MemoryAllocatorDump::kUnitsBytes, 256 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
256 statement_size); 257 statement_size);
257 return true; 258 return true;
258 } 259 }
259 260
261 // Data is persisted in a file shared between databases in the same directory.
262 // Any error reading or writing the file is considered failure.
pkotwicz 2015/10/15 23:31:06 This seems to be covered by the comment in the .h
263 //
264 // Top level is a dictionary storing a version number, and an array of histogram
265 // tags for databases which have been dumped.
pkotwicz 2015/10/15 23:31:06 It is unclear what "Top level" refers to. How abou
266 bool Connection::RegisterIntentToUpload() const {
267 static const char* kVersionKey = "version";
268 static const char* kDiagnosticDumpsKey = "DiagnosticDumps";
269 static int kVersion = 1;
270
271 AssertIOAllowed();
272
273 if (histogram_tag_.empty())
274 return false;
275
276 if (!is_open())
277 return false;
278
279 if (in_memory_)
280 return false;
281
282 const base::FilePath db_path = DbPath();
283 if (db_path.empty())
284 return false;
285
286 // Put the collection of diagnostic data next to the databases. In most
287 // cases, this is the profile directory, but safe-browsing stores a Cookies
288 // file in the directory above the profile directory.
289 base::FilePath breadcrumb_path(
290 db_path.DirName().Append(FILE_PATH_LITERAL("sqlite-diag")));
Scott Hess - ex-Googler 2015/10/15 21:24:44 Hmm. I am considering using this file to also tra
pkotwicz 2015/10/15 23:31:06 Fair enough
291
292 // Lock against multiple updates to the diagnostics file. This code should
293 // seldom be called in the first place, and when called it should seldom be
294 // called for multiple databases, and when called for multiple databases there
295 // is _probably_ something systemic wrong with the user's system. So the lock
296 // should never be contended, but when it is the database experience is
297 // already bad.
298 base::AutoLock lock(g_sqlite_init_lock.Get());
299
300 scoped_ptr<base::Value> root;
301 if (!base::PathExists(breadcrumb_path)) {
302 scoped_ptr<base::DictionaryValue> root_dict(new base::DictionaryValue());
303 root_dict->SetInteger(kVersionKey, kVersion);
304
305 scoped_ptr<base::ListValue> dumps(new base::ListValue);
306 dumps->AppendString(histogram_tag_);
307 root_dict->Set(kDiagnosticDumpsKey, dumps.Pass());
308
309 root = root_dict.Pass();
310 } else {
311 // Failure to read a valid dictionary implies that something is going wrong
312 // on the system.
313 JSONFileValueDeserializer deserializer(breadcrumb_path);
314 scoped_ptr<base::Value> read_root(
315 deserializer.Deserialize(nullptr, nullptr));
316 if (!read_root.get())
317 return false;
318 scoped_ptr<base::DictionaryValue> root_dict =
319 base::DictionaryValue::From(read_root.Pass());
320 if (!root_dict)
321 return false;
322
323 // Don't upload if the version is missing or newer.
324 int version = 0;
325 if (!root_dict->GetInteger(kVersionKey, &version) || version > kVersion)
326 return false;
327
328 base::ListValue* dumps = nullptr;
329 if (!root_dict->GetList(kDiagnosticDumpsKey, &dumps))
330 return false;
331
332 const size_t size = dumps->GetSize();
333 for (size_t i = 0; i < size; ++i) {
334 std::string s;
335
336 // Don't upload if the value isn't a string, or indicates a prior upload.
337 if (!dumps->GetString(i, &s) || s == histogram_tag_)
338 return false;
339 }
340
341 // Record intention to proceed with upload.
342 dumps->AppendString(histogram_tag_);
343 root = root_dict.Pass();
344 }
345
346 const base::FilePath breadcrumb_new =
347 breadcrumb_path.AddExtension(FILE_PATH_LITERAL("new"));
348 base::DeleteFile(breadcrumb_new, false);
349
350 // No upload if the breadcrumb file cannot be updated.
351 // TODO(shess): Consider ImportantFileWriter::WriteFileAtomically() to land
352 // the data on disk. For now, losing the data is not a big problem, so the
353 // sync overhead would probably not be worth it.
354 JSONFileValueSerializer serializer(breadcrumb_new);
355 if (!serializer.Serialize(*root))
356 return false;
357 if (!base::PathExists(breadcrumb_new))
358 return false;
359 if (!base::ReplaceFile(breadcrumb_new, breadcrumb_path, nullptr)) {
360 base::DeleteFile(breadcrumb_new, false);
361 return false;
362 }
363
364 return true;
365 }
366
260 // static 367 // static
261 void Connection::SetErrorIgnorer(Connection::ErrorIgnorerCallback* cb) { 368 void Connection::SetErrorIgnorer(Connection::ErrorIgnorerCallback* cb) {
262 CHECK(current_ignorer_cb_ == NULL); 369 CHECK(current_ignorer_cb_ == NULL);
263 current_ignorer_cb_ = cb; 370 current_ignorer_cb_ = cb;
264 } 371 }
265 372
266 // static 373 // static
267 void Connection::ResetErrorIgnorer() { 374 void Connection::ResetErrorIgnorer() {
268 CHECK(current_ignorer_cb_); 375 CHECK(current_ignorer_cb_);
269 current_ignorer_cb_ = NULL; 376 current_ignorer_cb_ = NULL;
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after
575 // If no changes have been made, skip flushing. This allows the first page of 682 // If no changes have been made, skip flushing. This allows the first page of
576 // the database to remain in cache across multiple reads. 683 // the database to remain in cache across multiple reads.
577 const int total_changes = sqlite3_total_changes(db_); 684 const int total_changes = sqlite3_total_changes(db_);
578 if (total_changes == total_changes_at_last_release_) 685 if (total_changes == total_changes_at_last_release_)
579 return; 686 return;
580 687
581 total_changes_at_last_release_ = total_changes; 688 total_changes_at_last_release_ = total_changes;
582 sqlite3_db_release_memory(db_); 689 sqlite3_db_release_memory(db_);
583 } 690 }
584 691
692 base::FilePath Connection::DbPath() const {
693 if (!is_open())
694 return base::FilePath();
695
696 const char* path = sqlite3_db_filename(db_, "main");
697 const base::StringPiece db_path(path);
698 #if defined(OS_WIN)
699 return base::FilePath(base::UTF8ToWide(db_path));
700 #elif defined(OS_POSIX)
701 return base::FilePath(db_path);
702 #else
703 NOTREACHED();
704 return base::FilePath();
705 #endif
706 }
707
585 void Connection::TrimMemory(bool aggressively) { 708 void Connection::TrimMemory(bool aggressively) {
586 if (!db_) 709 if (!db_)
587 return; 710 return;
588 711
589 // TODO(shess): investigate using sqlite3_db_release_memory() when possible. 712 // TODO(shess): investigate using sqlite3_db_release_memory() when possible.
590 int original_cache_size; 713 int original_cache_size;
591 { 714 {
592 Statement sql_get_original(GetUniqueStatement("PRAGMA cache_size")); 715 Statement sql_get_original(GetUniqueStatement("PRAGMA cache_size"));
593 if (!sql_get_original.Step()) { 716 if (!sql_get_original.Step()) {
594 DLOG(WARNING) << "Could not get cache size " << GetErrorMessage(); 717 DLOG(WARNING) << "Could not get cache size " << GetErrorMessage();
(...skipping 932 matching lines...) Expand 10 before | Expand all | Expand 10 after
1527 ignore_result(Execute(kNoWritableSchema)); 1650 ignore_result(Execute(kNoWritableSchema));
1528 1651
1529 return ret; 1652 return ret;
1530 } 1653 }
1531 1654
1532 base::TimeTicks TimeSource::Now() { 1655 base::TimeTicks TimeSource::Now() {
1533 return base::TimeTicks::Now(); 1656 return base::TimeTicks::Now();
1534 } 1657 }
1535 1658
1536 } // namespace sql 1659 } // namespace sql
OLDNEW
« no previous file with comments | « sql/connection.h ('k') | sql/connection_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698