[Fix #3831] Apply per-DB instance attach locking (#3862)

This commit is contained in:
Teddy Reed 2017-10-21 11:19:57 -07:00 committed by GitHub
parent 4375495cb4
commit 979cd4e5d1
5 changed files with 21 additions and 7 deletions

View File

@ -790,6 +790,8 @@ static int shell_exec(
} }
while (zSql[0] && (SQLITE_OK == rc)) { while (zSql[0] && (SQLITE_OK == rc)) {
auto lock(dbc->attachLock());
/* A lock for attaching virtual tables, but also the SQL object states. */ /* A lock for attaching virtual tables, but also the SQL object states. */
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover); rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
if (SQLITE_OK != rc) { if (SQLITE_OK != rc) {

View File

@ -203,7 +203,7 @@ void SQLiteSQLPlugin::detach(const std::string& name) {
if (!dbc->isPrimary()) { if (!dbc->isPrimary()) {
return; return;
} }
detachTableInternal(name, dbc->db()); detachTableInternal(name, dbc);
} }
SQLiteDBInstance::SQLiteDBInstance(sqlite3*& db, Mutex& mtx) SQLiteDBInstance::SQLiteDBInstance(sqlite3*& db, Mutex& mtx)
@ -251,6 +251,10 @@ bool SQLiteDBInstance::useCache() const {
return use_cache_; return use_cache_;
} }
WriteLock SQLiteDBInstance::attachLock() const {
return WriteLock(attach_mutex_);
}
void SQLiteDBInstance::addAffectedTable(VirtualTableContent* table) { void SQLiteDBInstance::addAffectedTable(VirtualTableContent* table) {
// An xFilter/scan was requested for this virtual table. // An xFilter/scan was requested for this virtual table.
affected_tables_.insert(std::make_pair(table->name, table)); affected_tables_.insert(std::make_pair(table->name, table));

View File

@ -77,6 +77,9 @@ class SQLiteDBInstance : private boost::noncopyable {
/// Check if the query requested use of the warm query cache. /// Check if the query requested use of the warm query cache.
bool useCache() const; bool useCache() const;
/// Lock the database for attaching virtual tables.
WriteLock attachLock() const;
private: private:
/// Handle the primary/forwarding requests for table attribute accesses. /// Handle the primary/forwarding requests for table attribute accesses.
TableAttributes getAttributes() const; TableAttributes getAttributes() const;
@ -102,6 +105,9 @@ class SQLiteDBInstance : private boost::noncopyable {
/// An attempted unique lock on the manager's primary database access mutex. /// An attempted unique lock on the manager's primary database access mutex.
WriteLock lock_; WriteLock lock_;
/// Attaching can occur async from the registry APIs.
mutable Mutex attach_mutex_;
/// Vector of tables that need their constraints cleared after execution. /// Vector of tables that need their constraints cleared after execution.
std::map<std::string, VirtualTableContent*> affected_tables_; std::map<std::string, VirtualTableContent*> affected_tables_;

View File

@ -624,7 +624,7 @@ Status attachTableInternal(const std::string& name,
// Note, if the clientData API is used then this will save a registry call // Note, if the clientData API is used then this will save a registry call
// within xCreate. // within xCreate.
RecursiveLock lock(kAttachMutex); auto lock(instance->attachLock());
int rc = sqlite3_create_module( int rc = sqlite3_create_module(
instance->db(), name.c_str(), &module, (void*)&(*instance)); instance->db(), name.c_str(), &module, (void*)&(*instance));
if (rc == SQLITE_OK || rc == SQLITE_MISUSE) { if (rc == SQLITE_OK || rc == SQLITE_MISUSE) {
@ -637,10 +637,11 @@ Status attachTableInternal(const std::string& name,
return Status(rc, getStringForSQLiteReturnCode(rc)); return Status(rc, getStringForSQLiteReturnCode(rc));
} }
Status detachTableInternal(const std::string& name, sqlite3* db) { Status detachTableInternal(const std::string& name,
RecursiveLock lock(kAttachMutex); const SQLiteDBInstanceRef& instance) {
auto lock(instance->attachLock());
auto format = "DROP TABLE IF EXISTS temp." + name; auto format = "DROP TABLE IF EXISTS temp." + name;
int rc = sqlite3_exec(db, format.c_str(), nullptr, nullptr, 0); int rc = sqlite3_exec(instance->db(), format.c_str(), nullptr, nullptr, 0);
if (rc != SQLITE_OK) { if (rc != SQLITE_OK) {
LOG(ERROR) << "Error detaching table: " << name << " (" << rc << ")"; LOG(ERROR) << "Error detaching table: " << name << " (" << rc << ")";
} }
@ -655,7 +656,7 @@ Status attachFunctionInternal(
// Hold the manager connection instance again in callbacks. // Hold the manager connection instance again in callbacks.
auto dbc = SQLiteDBManager::get(); auto dbc = SQLiteDBManager::get();
// Add some shell-specific functions to the instance. // Add some shell-specific functions to the instance.
RecursiveLock lock(kAttachMutex); auto lock(dbc->attachLock());
int rc = sqlite3_create_function( int rc = sqlite3_create_function(
dbc->db(), dbc->db(),
name.c_str(), name.c_str(),

View File

@ -84,7 +84,8 @@ Status attachTableInternal(const std::string& name,
const SQLiteDBInstanceRef& instance); const SQLiteDBInstanceRef& instance);
/// Detach (drop) a table. /// Detach (drop) a table.
Status detachTableInternal(const std::string& name, sqlite3* db); Status detachTableInternal(const std::string& name,
const SQLiteDBInstanceRef& instance);
Status attachFunctionInternal( Status attachFunctionInternal(
const std::string& name, const std::string& name,