[tracing] Add separate dump provider for sql connection
The sql connection memory dump is not thread safe since the connections can get deleted while a dump is happening. To make this thread safe, this CL introduces a dump provider class owned by the connection. This class holds a lock when dumping and deleting the database. Also, to workaround thread safe dump provider registration, it uses the UnregisterAndDeleteDumpProviderAsync api added in crrev.com/1430073002. BUG=466141 Review URL: https://codereview.chromium.org/1434993002 Cr-Commit-Position: refs/heads/master@{#369161}
This commit is contained in:
@ -8,6 +8,8 @@ component("sql") {
|
||||
sources = [
|
||||
"connection.cc",
|
||||
"connection.h",
|
||||
"connection_memory_dump_provider.cc",
|
||||
"connection_memory_dump_provider.h",
|
||||
"error_delegate_util.cc",
|
||||
"error_delegate_util.h",
|
||||
"init_status.h",
|
||||
|
@ -27,7 +27,7 @@
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/synchronization/lock.h"
|
||||
#include "base/trace_event/memory_dump_manager.h"
|
||||
#include "base/trace_event/process_memory_dump.h"
|
||||
#include "sql/connection_memory_dump_provider.h"
|
||||
#include "sql/meta_table.h"
|
||||
#include "sql/statement.h"
|
||||
#include "third_party/sqlite/sqlite3.h"
|
||||
@ -254,44 +254,6 @@ bool Connection::ShouldIgnoreSqliteCompileError(int error) {
|
||||
basic_error == SQLITE_CORRUPT;
|
||||
}
|
||||
|
||||
bool Connection::OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
|
||||
base::trace_event::ProcessMemoryDump* pmd) {
|
||||
if (args.level_of_detail ==
|
||||
base::trace_event::MemoryDumpLevelOfDetail::LIGHT ||
|
||||
!db_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// The high water mark is not tracked for the following usages.
|
||||
int cache_size, dummy_int;
|
||||
sqlite3_db_status(db_, SQLITE_DBSTATUS_CACHE_USED, &cache_size, &dummy_int,
|
||||
0 /* resetFlag */);
|
||||
int schema_size;
|
||||
sqlite3_db_status(db_, SQLITE_DBSTATUS_SCHEMA_USED, &schema_size, &dummy_int,
|
||||
0 /* resetFlag */);
|
||||
int statement_size;
|
||||
sqlite3_db_status(db_, SQLITE_DBSTATUS_STMT_USED, &statement_size, &dummy_int,
|
||||
0 /* resetFlag */);
|
||||
|
||||
std::string name = base::StringPrintf(
|
||||
"sqlite/%s_connection/%p",
|
||||
histogram_tag_.empty() ? "Unknown" : histogram_tag_.c_str(), this);
|
||||
base::trace_event::MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(name);
|
||||
dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
|
||||
base::trace_event::MemoryAllocatorDump::kUnitsBytes,
|
||||
cache_size + schema_size + statement_size);
|
||||
dump->AddScalar("cache_size",
|
||||
base::trace_event::MemoryAllocatorDump::kUnitsBytes,
|
||||
cache_size);
|
||||
dump->AddScalar("schema_size",
|
||||
base::trace_event::MemoryAllocatorDump::kUnitsBytes,
|
||||
schema_size);
|
||||
dump->AddScalar("statement_size",
|
||||
base::trace_event::MemoryAllocatorDump::kUnitsBytes,
|
||||
statement_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Connection::ReportDiagnosticInfo(int extended_error, Statement* stmt) {
|
||||
AssertIOAllowed();
|
||||
|
||||
@ -386,13 +348,9 @@ Connection::Connection()
|
||||
update_time_histogram_(NULL),
|
||||
query_time_histogram_(NULL),
|
||||
clock_(new TimeSource()) {
|
||||
base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
|
||||
this, "sql::Connection", nullptr);
|
||||
}
|
||||
|
||||
Connection::~Connection() {
|
||||
base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
|
||||
this);
|
||||
Close();
|
||||
}
|
||||
|
||||
@ -511,6 +469,17 @@ void Connection::CloseInternal(bool forced) {
|
||||
// of the function. http://crbug.com/136655.
|
||||
AssertIOAllowed();
|
||||
|
||||
// Reseting acquires a lock to ensure no dump is happening on the database
|
||||
// at the same time. Unregister takes ownership of provider and it is safe
|
||||
// since the db is reset. memory_dump_provider_ could be null if db_ was
|
||||
// poisoned.
|
||||
if (memory_dump_provider_) {
|
||||
memory_dump_provider_->ResetDatabase();
|
||||
base::trace_event::MemoryDumpManager::GetInstance()
|
||||
->UnregisterAndDeleteDumpProviderSoon(
|
||||
std::move(memory_dump_provider_));
|
||||
}
|
||||
|
||||
int rc = sqlite3_close(db_);
|
||||
if (rc != SQLITE_OK) {
|
||||
UMA_HISTOGRAM_SPARSE_SLOWLY("Sqlite.CloseFailure", rc);
|
||||
@ -1848,6 +1817,12 @@ bool Connection::OpenInternal(const std::string& file_name,
|
||||
mmap_enabled_ = true;
|
||||
}
|
||||
|
||||
DCHECK(!memory_dump_provider_);
|
||||
memory_dump_provider_.reset(
|
||||
new ConnectionMemoryDumpProvider(db_, histogram_tag_));
|
||||
base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
|
||||
memory_dump_provider_.get(), "sql::Connection", nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "base/threading/thread_restrictions.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/trace_event/memory_dump_provider.h"
|
||||
#include "sql/sql_export.h"
|
||||
|
||||
struct sqlite3;
|
||||
@ -33,6 +32,7 @@ class HistogramBase;
|
||||
|
||||
namespace sql {
|
||||
|
||||
class ConnectionMemoryDumpProvider;
|
||||
class Recovery;
|
||||
class Statement;
|
||||
|
||||
@ -105,7 +105,7 @@ class SQL_EXPORT TimeSource {
|
||||
DISALLOW_COPY_AND_ASSIGN(TimeSource);
|
||||
};
|
||||
|
||||
class SQL_EXPORT Connection : public base::trace_event::MemoryDumpProvider {
|
||||
class SQL_EXPORT Connection {
|
||||
private:
|
||||
class StatementRef; // Forward declaration, see real one below.
|
||||
|
||||
@ -113,7 +113,7 @@ class SQL_EXPORT Connection : public base::trace_event::MemoryDumpProvider {
|
||||
// The database is opened by calling Open[InMemory](). Any uncommitted
|
||||
// transactions will be rolled back when this object is deleted.
|
||||
Connection();
|
||||
~Connection() override;
|
||||
~Connection();
|
||||
|
||||
// Pre-init configuration ----------------------------------------------------
|
||||
|
||||
@ -484,11 +484,6 @@ class SQL_EXPORT Connection : public base::trace_event::MemoryDumpProvider {
|
||||
// with the syntax of a SQL statement, or problems with the database schema.
|
||||
static bool ShouldIgnoreSqliteCompileError(int error);
|
||||
|
||||
// base::trace_event::MemoryDumpProvider implementation.
|
||||
bool OnMemoryDump(
|
||||
const base::trace_event::MemoryDumpArgs& args,
|
||||
base::trace_event::ProcessMemoryDump* process_memory_dump) override;
|
||||
|
||||
// Collect various diagnostic information and post a crash dump to aid
|
||||
// debugging. Dump rate per database is limited to prevent overwhelming the
|
||||
// crash server.
|
||||
@ -511,6 +506,7 @@ class SQL_EXPORT Connection : public base::trace_event::MemoryDumpProvider {
|
||||
|
||||
FRIEND_TEST_ALL_PREFIXES(SQLConnectionTest, CollectDiagnosticInfo);
|
||||
FRIEND_TEST_ALL_PREFIXES(SQLConnectionTest, GetAppropriateMmapSize);
|
||||
FRIEND_TEST_ALL_PREFIXES(SQLConnectionTest, OnMemoryDump);
|
||||
FRIEND_TEST_ALL_PREFIXES(SQLConnectionTest, RegisterIntentToUpload);
|
||||
|
||||
// Internal initialize function used by both Init and InitInMemory. The file
|
||||
@ -795,6 +791,9 @@ class SQL_EXPORT Connection : public base::trace_event::MemoryDumpProvider {
|
||||
// changes.
|
||||
scoped_ptr<TimeSource> clock_;
|
||||
|
||||
// Stores the dump provider object when db is open.
|
||||
scoped_ptr<ConnectionMemoryDumpProvider> memory_dump_provider_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Connection);
|
||||
};
|
||||
|
||||
|
74
sql/connection_memory_dump_provider.cc
Normal file
74
sql/connection_memory_dump_provider.cc
Normal file
@ -0,0 +1,74 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "sql/connection_memory_dump_provider.h"
|
||||
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/trace_event/process_memory_dump.h"
|
||||
#include "third_party/sqlite/sqlite3.h"
|
||||
|
||||
namespace sql {
|
||||
|
||||
ConnectionMemoryDumpProvider::ConnectionMemoryDumpProvider(
|
||||
sqlite3* db,
|
||||
const std::string& name)
|
||||
: db_(db), connection_name_(name) {}
|
||||
|
||||
ConnectionMemoryDumpProvider::~ConnectionMemoryDumpProvider() {}
|
||||
|
||||
void ConnectionMemoryDumpProvider::ResetDatabase() {
|
||||
base::AutoLock lock(lock_);
|
||||
db_ = nullptr;
|
||||
}
|
||||
|
||||
bool ConnectionMemoryDumpProvider::OnMemoryDump(
|
||||
const base::trace_event::MemoryDumpArgs& args,
|
||||
base::trace_event::ProcessMemoryDump* pmd) {
|
||||
if (args.level_of_detail == base::trace_event::MemoryDumpLevelOfDetail::LIGHT)
|
||||
return true;
|
||||
|
||||
int cache_size = 0;
|
||||
int schema_size = 0;
|
||||
int statement_size = 0;
|
||||
{
|
||||
// Lock is acquired here so that db_ is not reset in ResetDatabase when
|
||||
// collecting stats.
|
||||
base::AutoLock lock(lock_);
|
||||
if (!db_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The high water mark is not tracked for the following usages.
|
||||
int dummy_int;
|
||||
int status = sqlite3_db_status(db_, SQLITE_DBSTATUS_CACHE_USED, &cache_size,
|
||||
&dummy_int, 0 /* resetFlag */);
|
||||
DCHECK_EQ(SQLITE_OK, status);
|
||||
status = sqlite3_db_status(db_, SQLITE_DBSTATUS_SCHEMA_USED, &schema_size,
|
||||
&dummy_int, 0 /* resetFlag */);
|
||||
DCHECK_EQ(SQLITE_OK, status);
|
||||
status = sqlite3_db_status(db_, SQLITE_DBSTATUS_STMT_USED, &statement_size,
|
||||
&dummy_int, 0 /* resetFlag */);
|
||||
DCHECK_EQ(SQLITE_OK, status);
|
||||
}
|
||||
|
||||
std::string name = base::StringPrintf(
|
||||
"sqlite/%s_connection/%p",
|
||||
connection_name_.empty() ? "Unknown" : connection_name_.c_str(), this);
|
||||
base::trace_event::MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(name);
|
||||
dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
|
||||
base::trace_event::MemoryAllocatorDump::kUnitsBytes,
|
||||
cache_size + schema_size + statement_size);
|
||||
dump->AddScalar("cache_size",
|
||||
base::trace_event::MemoryAllocatorDump::kUnitsBytes,
|
||||
cache_size);
|
||||
dump->AddScalar("schema_size",
|
||||
base::trace_event::MemoryAllocatorDump::kUnitsBytes,
|
||||
schema_size);
|
||||
dump->AddScalar("statement_size",
|
||||
base::trace_event::MemoryAllocatorDump::kUnitsBytes,
|
||||
statement_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace sql
|
41
sql/connection_memory_dump_provider.h
Normal file
41
sql/connection_memory_dump_provider.h
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SQL_CONNECTION_MEMORY_DUMP_PROVIDER_H
|
||||
#define SQL_CONNECTION_MEMORY_DUMP_PROVIDER_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "base/synchronization/lock.h"
|
||||
#include "base/trace_event/memory_dump_provider.h"
|
||||
|
||||
struct sqlite3;
|
||||
|
||||
namespace sql {
|
||||
|
||||
class ConnectionMemoryDumpProvider
|
||||
: public base::trace_event::MemoryDumpProvider {
|
||||
public:
|
||||
ConnectionMemoryDumpProvider(sqlite3* db, const std::string& name);
|
||||
~ConnectionMemoryDumpProvider() override;
|
||||
|
||||
void ResetDatabase();
|
||||
|
||||
// base::trace_event::MemoryDumpProvider implementation.
|
||||
bool OnMemoryDump(
|
||||
const base::trace_event::MemoryDumpArgs& args,
|
||||
base::trace_event::ProcessMemoryDump* process_memory_dump) override;
|
||||
|
||||
private:
|
||||
sqlite3* db_; // not owned.
|
||||
base::Lock lock_;
|
||||
std::string connection_name_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ConnectionMemoryDumpProvider);
|
||||
};
|
||||
|
||||
} // namespace sql
|
||||
|
||||
#endif // SQL_CONNECTION_MEMORY_DUMP_PROVIDER_H
|
@ -15,6 +15,7 @@
|
||||
#include "base/test/histogram_tester.h"
|
||||
#include "base/trace_event/process_memory_dump.h"
|
||||
#include "sql/connection.h"
|
||||
#include "sql/connection_memory_dump_provider.h"
|
||||
#include "sql/correct_sql_test_base.h"
|
||||
#include "sql/meta_table.h"
|
||||
#include "sql/statement.h"
|
||||
@ -1308,7 +1309,7 @@ TEST_F(SQLConnectionTest, OnMemoryDump) {
|
||||
base::trace_event::ProcessMemoryDump pmd(nullptr);
|
||||
base::trace_event::MemoryDumpArgs args = {
|
||||
base::trace_event::MemoryDumpLevelOfDetail::DETAILED};
|
||||
ASSERT_TRUE(db().OnMemoryDump(args, &pmd));
|
||||
ASSERT_TRUE(db().memory_dump_provider_->OnMemoryDump(args, &pmd));
|
||||
EXPECT_GE(pmd.allocator_dumps().size(), 1u);
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,8 @@
|
||||
'sources': [
|
||||
'connection.cc',
|
||||
'connection.h',
|
||||
'connection_memory_dump_provider.cc',
|
||||
'connection_memory_dump_provider.h',
|
||||
'error_delegate_util.cc',
|
||||
'error_delegate_util.h',
|
||||
'init_status.h',
|
||||
|
@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SQL_PROCESS_MEMORY_DUMP_PROVIDER_H
|
||||
#define SQL_PROCESS_MEMORY_DUMP_PROVIDER_H
|
||||
#ifndef SQL_SQL_MEMORY_DUMP_PROVIDER_H
|
||||
#define SQL_SQL_MEMORY_DUMP_PROVIDER_H
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "base/memory/singleton.h"
|
||||
@ -34,4 +34,4 @@ class SQL_EXPORT SqlMemoryDumpProvider
|
||||
|
||||
} // namespace sql
|
||||
|
||||
#endif // SQL_PROCESS_MEMORY_DUMP_PROVIDER_H
|
||||
#endif // SQL_SQL_MEMORY_DUMP_PROVIDER_H
|
||||
|
Reference in New Issue
Block a user