dvander@667: /** dvander@667: * vim: set ts=4 : ds@1330: * ============================================================================= dvander@1231: * SourceMod ds@1947: * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. ds@1330: * ============================================================================= dvander@667: * ds@1330: * This program is free software; you can redistribute it and/or modify it under ds@1330: * the terms of the GNU General Public License, version 3.0, as published by the ds@1330: * Free Software Foundation. dvander@1231: * ds@1330: * This program is distributed in the hope that it will be useful, but WITHOUT ds@1330: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ds@1330: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ds@1330: * details. dvander@1231: * ds@1330: * You should have received a copy of the GNU General Public License along with ds@1330: * this program. If not, see . dvander@1231: * ds@1330: * As a special exception, AlliedModders LLC gives you permission to link the ds@1330: * code of this program (as well as its derivative works) to "Half-Life 2," the ds@1330: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software ds@1330: * by the Valve Corporation. You must obey the GNU General Public License in ds@1330: * all respects for all other code used. Additionally, AlliedModders LLC grants ds@1330: * this exception to all derivative works. AlliedModders LLC defines further ds@1330: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), ds@1330: * or . dvander@667: * dvander@667: * Version: $Id$ dvander@667: */ dvander@667: dvander@666: #include "Database.h" dvander@666: #include "HandleSys.h" dvander@862: #include "ShareSys.h" dvander@666: #include "sourcemod.h" dvander@868: #include "sm_stringutil.h" dvander@868: #include "Logger.h" dvander@868: #include "ExtensionSys.h" dvander@868: #include dvander@2726: #include dvander@868: dvander@868: #define DBPARSE_LEVEL_NONE 0 dvander@868: #define DBPARSE_LEVEL_MAIN 1 dvander@868: #define DBPARSE_LEVEL_DATABASE 2 dvander@666: dvander@666: DBManager g_DBMan; dvander@1096: static bool s_OneTimeThreaderErrorMsg = false; dvander@666: dvander@868: DBManager::DBManager() dvander@868: : m_StrTab(512), m_ParseLevel(0), m_ParseState(0), m_pDefault(NULL) dvander@868: { dvander@868: } dvander@868: dvander@666: void DBManager::OnSourceModAllInitialized() dvander@666: { dvander@666: HandleAccess sec; dvander@666: dvander@666: g_HandleSys.InitAccessDefaults(NULL, &sec); dvander@666: sec.access[HandleAccess_Delete] |= HANDLE_RESTRICT_IDENTITY; dvander@666: sec.access[HandleAccess_Clone] |= HANDLE_RESTRICT_IDENTITY; dvander@666: dvander@666: m_DriverType = g_HandleSys.CreateType("IDriver", this, 0, NULL, &sec, g_pCoreIdent, NULL); dvander@666: m_DatabaseType = g_HandleSys.CreateType("IDatabase", this, 0, NULL, NULL, g_pCoreIdent, NULL); dvander@862: dvander@862: g_ShareSys.AddInterface(NULL, this); dvander@868: dvander@868: g_SourceMod.BuildPath(Path_SM, m_Filename, sizeof(m_Filename), "configs/databases.cfg"); dvander@1096: dvander@1096: m_pConfigLock = g_pThreader->MakeMutex(); dvander@1096: m_pThinkLock = g_pThreader->MakeMutex(); dvander@1096: m_pQueueLock = g_pThreader->MakeMutex(); dvander@1096: dvander@1096: g_PluginSys.AddPluginsListener(this); dvander@868: } dvander@868: dvander@868: void DBManager::OnSourceModLevelChange(const char *mapName) dvander@868: { dvander@1656: SMCError err; dvander@1656: SMCStates states = {0, 0}; dvander@1096: dvander@1096: /* We lock and don't give up the lock until we're done. dvander@1096: * This way the thread's search won't be searching through a dvander@1096: * potentially empty/corrupt list, which would be very bad. dvander@1096: */ dvander@1096: m_pConfigLock->Lock(); dvander@1656: if ((err = textparsers->ParseFile_SMC(m_Filename, this, &states)) != SMCError_Okay) dvander@868: { dvander@868: g_Logger.LogError("[SM] Detected parse error(s) in file \"%s\"", m_Filename); dvander@1656: if (err != SMCError_Custom) dvander@868: { dvander@1406: const char *txt = textparsers->GetSMCErrorString(err); dvander@1656: g_Logger.LogError("[SM] Line %d: %s", states.line, txt); dvander@868: } dvander@868: } dvander@1096: m_pConfigLock->Unlock(); dvander@858: } dvander@858: dvander@858: void DBManager::OnSourceModShutdown() dvander@858: { dvander@1096: KillWorkerThread(); dvander@1201: g_PluginSys.RemovePluginsListener(this); dvander@1096: m_pConfigLock->DestroyThis(); dvander@1096: m_pThinkLock->DestroyThis(); dvander@1096: m_pQueueLock->DestroyThis(); dvander@858: g_HandleSys.RemoveType(m_DatabaseType, g_pCoreIdent); dvander@858: g_HandleSys.RemoveType(m_DriverType, g_pCoreIdent); dvander@858: } dvander@858: dvander@858: unsigned int DBManager::GetInterfaceVersion() dvander@858: { dvander@858: return SMINTERFACE_DBI_VERSION; dvander@858: } dvander@858: dvander@858: const char *DBManager::GetInterfaceName() dvander@858: { dvander@858: return SMINTERFACE_DBI_NAME; dvander@666: } dvander@666: dvander@666: void DBManager::OnHandleDestroy(HandleType_t type, void *object) dvander@666: { dvander@666: if (type == m_DriverType) dvander@666: { dvander@666: /* Ignore */ dvander@666: return; dvander@666: } dvander@666: dvander@858: if (g_HandleSys.TypeCheck(type, m_DatabaseType)) dvander@666: { dvander@666: IDatabase *pdb = (IDatabase *)object; dvander@666: pdb->Close(); dvander@666: } dvander@666: } dvander@666: dvander@868: void DBManager::ReadSMC_ParseStart() dvander@666: { dvander@868: m_confs.clear(); dvander@868: m_ParseLevel = 0; dvander@868: m_ParseState = DBPARSE_LEVEL_NONE; dvander@868: m_StrTab.Reset(); dvander@868: m_DefDriver.clear(); dvander@868: } dvander@666: dvander@868: ConfDbInfo s_CurInfo; dvander@1656: SMCResult DBManager::ReadSMC_NewSection(const SMCStates *states, const char *name) dvander@868: { dvander@868: if (m_ParseLevel) dvander@868: { dvander@868: m_ParseLevel++; dvander@1656: return SMCResult_Continue; dvander@868: } dvander@868: dvander@868: if (m_ParseState == DBPARSE_LEVEL_NONE) dvander@666: { dvander@868: if (strcmp(name, "Databases") == 0) dvander@666: { dvander@868: m_ParseState = DBPARSE_LEVEL_MAIN; dvander@868: } else { dvander@868: m_ParseLevel++; dvander@868: } dvander@868: } else if (m_ParseState == DBPARSE_LEVEL_MAIN) { dvander@868: s_CurInfo = ConfDbInfo(); dvander@869: s_CurInfo.name = m_StrTab.AddString(name); dvander@868: m_ParseState = DBPARSE_LEVEL_DATABASE; dvander@868: } else if (m_ParseState == DBPARSE_LEVEL_DATABASE) { dvander@868: m_ParseLevel++; dvander@868: } dvander@868: dvander@1656: return SMCResult_Continue; dvander@868: } dvander@868: dvander@1656: SMCResult DBManager::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value) dvander@868: { dvander@868: if (m_ParseLevel) dvander@868: { dvander@1656: return SMCResult_Continue; dvander@868: } dvander@868: dvander@868: if (m_ParseState == DBPARSE_LEVEL_MAIN) dvander@868: { dvander@868: if (strcmp(key, "driver_default") == 0) dvander@868: { dvander@868: m_DefDriver.assign(value); dvander@868: } dvander@868: } else if (m_ParseState == DBPARSE_LEVEL_DATABASE) { dvander@868: if (strcmp(key, "driver") == 0) dvander@868: { dvander@868: if (strcmp(value, "default") != 0) dvander@868: { dvander@868: s_CurInfo.driver = m_StrTab.AddString(value); dvander@868: } dvander@868: } else if (strcmp(key, "database") == 0) { dvander@868: s_CurInfo.database = m_StrTab.AddString(value); dvander@868: } else if (strcmp(key, "host") == 0) { dvander@868: s_CurInfo.host = m_StrTab.AddString(value); dvander@868: } else if (strcmp(key, "user") == 0) { dvander@868: s_CurInfo.user = m_StrTab.AddString(value); dvander@868: } else if (strcmp(key, "pass") == 0) { dvander@868: s_CurInfo.pass = m_StrTab.AddString(value); dvander@868: } else if (strcmp(key, "timeout") == 0) { dvander@868: s_CurInfo.info.maxTimeout = atoi(value); dvander@868: } else if (strcmp(key, "port") == 0) { dvander@868: s_CurInfo.info.port = atoi(value); dvander@666: } dvander@666: } dvander@666: dvander@1656: return SMCResult_Continue; dvander@868: } dvander@868: dvander@868: #define ASSIGN_VAR(var) \ dvander@868: if (s_CurInfo.var == -1) { \ dvander@868: s_CurInfo.info.var = ""; \ dvander@868: } else { \ dvander@868: s_CurInfo.info.var = m_StrTab.GetString(s_CurInfo.var); \ dvander@868: } dvander@868: dvander@1656: SMCResult DBManager::ReadSMC_LeavingSection(const SMCStates *states) dvander@868: { dvander@868: if (m_ParseLevel) dvander@868: { dvander@868: m_ParseLevel--; dvander@1656: return SMCResult_Continue; dvander@868: } dvander@868: dvander@868: if (m_ParseState == DBPARSE_LEVEL_DATABASE) dvander@868: { dvander@868: /* Set all of the info members to either a blank string dvander@868: * or the string pointer from the string table. dvander@868: */ dvander@868: ASSIGN_VAR(driver); dvander@868: ASSIGN_VAR(database); dvander@868: ASSIGN_VAR(host); dvander@868: ASSIGN_VAR(user); dvander@868: ASSIGN_VAR(pass); dvander@868: dvander@868: /* Save it.. */ dvander@868: m_confs.push_back(s_CurInfo); dvander@868: dvander@868: /* Go up one level */ dvander@868: m_ParseState = DBPARSE_LEVEL_MAIN; dvander@868: } else if (m_ParseState == DBPARSE_LEVEL_MAIN) { dvander@868: m_ParseState = DBPARSE_LEVEL_NONE; dvander@1656: return SMCResult_Halt; dvander@868: } dvander@868: dvander@1656: return SMCResult_Continue; dvander@868: } dvander@868: #undef ASSIGN_VAR dvander@868: dvander@868: void DBManager::ReadSMC_ParseEnd(bool halted, bool failed) dvander@868: { dvander@868: } dvander@868: dvander@868: bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent, char *error, size_t maxlength) dvander@868: { dvander@868: ConfDbInfo *pInfo = GetDatabaseConf(name); dvander@868: dvander@868: if (!pInfo) dvander@868: { dvander@868: if (pdr) dvander@868: { dvander@868: *pdr = NULL; dvander@868: } dvander@868: *pdb = NULL; dvander@868: UTIL_Format(error, maxlength, "Configuration \"%s\" not found", name); dvander@868: return false; dvander@868: } dvander@868: dvander@869: const char *dname = pInfo->info.driver; dvander@868: if (!pInfo->realDriver) dvander@868: { dvander@868: /* Try to assign a real driver pointer */ dvander@868: if (pInfo->info.driver[0] == '\0') dvander@868: { dvander@868: if (!m_pDefault && m_DefDriver.size() > 0) dvander@868: { dvander@868: m_pDefault = FindOrLoadDriver(m_DefDriver.c_str()); dvander@868: } dvander@869: dname = m_DefDriver.size() ? m_DefDriver.c_str() : "default"; dvander@868: pInfo->realDriver = m_pDefault; dvander@868: } else { dvander@868: pInfo->realDriver = FindOrLoadDriver(pInfo->info.driver); dvander@868: } dvander@868: } dvander@868: dvander@868: if (pInfo->realDriver) dvander@868: { dvander@868: if (pdr) dvander@868: { dvander@868: *pdr = pInfo->realDriver; dvander@868: } dvander@868: *pdb = pInfo->realDriver->Connect(&pInfo->info, persistent, error, maxlength); dvander@868: return (*pdb != NULL); dvander@868: } dvander@868: dvander@868: if (pdr) dvander@868: { dvander@868: *pdr = NULL; dvander@868: } dvander@666: *pdb = NULL; dvander@666: dvander@869: UTIL_Format(error, maxlength, "Driver \"%s\" not found", dname); dvander@868: dvander@666: return false; dvander@666: } dvander@858: dvander@858: void DBManager::AddDriver(IDBDriver *pDriver) dvander@858: { dvander@1096: /* Let's kill the worker. Join the thread and let the queries flush. dvander@1096: * This is kind of stupid but we just want to unload safely. dvander@1096: * Rather than recreate the worker, we'll wait until someone throws dvander@1096: * another query through. dvander@1096: */ dvander@1096: KillWorkerThread(); dvander@1096: dvander@858: m_drivers.push_back(pDriver); dvander@858: } dvander@858: dvander@858: void DBManager::RemoveDriver(IDBDriver *pDriver) dvander@858: { dvander@1096: /* Again, we're forced to kill the worker. How rude! dvander@1096: * Doing this flushes the queue, and thus we don't need to dvander@1096: * clean anything else. dvander@1096: */ dvander@1096: KillWorkerThread(); dvander@1096: dvander@858: for (size_t i=0; i::iterator iter; dvander@868: for (iter=m_confs.begin(); iter!=m_confs.end(); iter++) dvander@868: { dvander@868: ConfDbInfo &db = (*iter); dvander@868: if (db.realDriver == pDriver) dvander@868: { dvander@868: db.realDriver = NULL; dvander@868: } dvander@868: } dvander@1096: dvander@1096: /* Now that the driver is gone, we have to test the think queue. dvander@1096: * Whatever happens therein is up to the db op! dvander@1096: */ dvander@1096: Queue::iterator qiter = m_ThinkQueue.begin(); dvander@1096: Queue templist; dvander@1096: while (qiter != m_ThinkQueue.end()) dvander@1096: { dvander@1096: IDBThreadOperation *op = (*qiter); dvander@1096: if (op->GetDriver() == pDriver) dvander@1096: { dvander@1096: templist.push(op); dvander@1096: qiter = m_ThinkQueue.erase(qiter); dvander@1096: } else { dvander@1096: qiter++; dvander@1096: } dvander@1096: } dvander@1096: dvander@1096: for (qiter = templist.begin(); dvander@1096: qiter != templist.end(); dvander@1096: qiter++) dvander@1096: { dvander@1096: IDBThreadOperation *op = (*qiter); dvander@1096: op->CancelThinkPart(); dvander@1157: op->Destroy(); dvander@1096: } dvander@868: } dvander@868: dvander@868: IDBDriver *DBManager::GetDefaultDriver() dvander@868: { dvander@868: if (!m_pDefault && m_DefDriver.size() > 0) dvander@868: { dvander@868: m_pDefault = FindOrLoadDriver(m_DefDriver.c_str()); dvander@868: } dvander@868: dvander@868: return m_pDefault; dvander@858: } dvander@858: dvander@858: Handle_t DBManager::CreateHandle(DBHandleType dtype, void *ptr, IdentityToken_t *pToken) dvander@858: { dvander@858: HandleType_t type = 0; dvander@858: dvander@858: if (dtype == DBHandle_Driver) dvander@858: { dvander@858: type = m_DriverType; dvander@858: } else if (dtype == DBHandle_Database) { dvander@858: type = m_DatabaseType; dvander@858: } else { dvander@858: return BAD_HANDLE; dvander@858: } dvander@858: dvander@858: return g_HandleSys.CreateHandle(type, ptr, pToken, g_pCoreIdent, NULL); dvander@858: } dvander@858: dvander@858: HandleError DBManager::ReadHandle(Handle_t hndl, DBHandleType dtype, void **ptr) dvander@858: { dvander@858: HandleType_t type = 0; dvander@858: dvander@858: if (dtype == DBHandle_Driver) dvander@858: { dvander@858: type = m_DriverType; dvander@858: } else if (dtype == DBHandle_Database) { dvander@858: type = m_DatabaseType; dvander@858: } else { dvander@858: return HandleError_Type; dvander@858: } dvander@858: dvander@858: HandleSecurity sec(NULL, g_pCoreIdent); dvander@858: dvander@869: return g_HandleSys.ReadHandle(hndl, type, &sec, ptr); dvander@858: } dvander@858: dvander@858: HandleError DBManager::ReleaseHandle(Handle_t hndl, DBHandleType type, IdentityToken_t *token) dvander@858: { dvander@858: HandleSecurity sec(token, g_pCoreIdent); dvander@858: return g_HandleSys.FreeHandle(hndl, &sec); dvander@858: } dvander@858: dvander@858: unsigned int DBManager::GetDriverCount() dvander@858: { dvander@858: return (unsigned int)m_drivers.size(); dvander@858: } dvander@858: dvander@858: IDBDriver *DBManager::GetDriver(unsigned int index) dvander@858: { dvander@858: if (index >= m_drivers.size()) dvander@858: { dvander@858: return NULL; dvander@858: } dvander@858: dvander@858: return m_drivers[index]; dvander@858: } dvander@858: dvander@858: const DatabaseInfo *DBManager::FindDatabaseConf(const char *name) dvander@858: { dvander@868: ConfDbInfo *info = GetDatabaseConf(name); dvander@868: if (!info) dvander@868: { dvander@868: return NULL; dvander@868: } dvander@868: dvander@868: return &info->info; dvander@868: } dvander@868: dvander@868: ConfDbInfo *DBManager::GetDatabaseConf(const char *name) dvander@868: { dvander@868: List::iterator iter; dvander@868: dvander@868: for (iter=m_confs.begin(); iter!=m_confs.end(); iter++) dvander@868: { dvander@868: ConfDbInfo &conf = (*iter); dvander@868: if (strcmp(m_StrTab.GetString(conf.name), name) == 0) dvander@868: { dvander@868: return &conf; dvander@868: } dvander@868: } dvander@868: dvander@858: return NULL; dvander@858: } dvander@868: dvander@868: IDBDriver *DBManager::FindOrLoadDriver(const char *name) dvander@868: { dvander@868: size_t last_size = m_drivers.size(); dvander@868: for (size_t i=0; iGetIdentifier(), name) == 0) dvander@868: { dvander@868: return m_drivers[i]; dvander@868: } dvander@868: } dvander@868: dvander@868: char filename[PLATFORM_MAX_PATH]; dvander@869: UTIL_Format(filename, sizeof(filename), "dbi.%s.ext", name); dvander@868: dvander@868: IExtension *pExt = g_Extensions.LoadAutoExtension(filename); dvander@868: if (!pExt || !pExt->IsLoaded() || m_drivers.size() <= last_size) dvander@868: { dvander@868: return NULL; dvander@868: } dvander@868: dvander@868: /* last_size is now gauranteed to be a valid index. dvander@868: * The identifier must match the name. dvander@868: */ dvander@868: if (strcmp(m_drivers[last_size]->GetIdentifier(), name) == 0) dvander@868: { dvander@868: return m_drivers[last_size]; dvander@868: } dvander@868: dvander@868: return NULL; dvander@868: } dvander@1096: dvander@1096: void DBManager::KillWorkerThread() dvander@1096: { dvander@1096: if (m_pWorker) dvander@1096: { dvander@1096: m_pWorker->Stop(false); dvander@1096: g_pThreader->DestroyWorker(m_pWorker); dvander@1096: m_pWorker = NULL; dvander@1096: s_OneTimeThreaderErrorMsg = false; dvander@1096: } dvander@1096: } dvander@1096: dvander@1157: static IdentityToken_t *s_pAddBlock = NULL; dvander@1157: dvander@1096: bool DBManager::AddToThreadQueue(IDBThreadOperation *op, PrioQueueLevel prio) dvander@1096: { dvander@1157: if (s_pAddBlock && op->GetOwner() == s_pAddBlock) dvander@1157: { dvander@1157: return false; dvander@1157: } dvander@1157: dvander@1096: if (!m_pWorker) dvander@1096: { dvander@1096: m_pWorker = g_pThreader->MakeWorker(this, true); dvander@1096: if (!m_pWorker) dvander@1096: { dvander@1096: if (!s_OneTimeThreaderErrorMsg) dvander@1096: { dvander@1096: g_Logger.LogError("[SM] Unable to create db threader (error unknown)"); dvander@1096: s_OneTimeThreaderErrorMsg = true; dvander@1096: } dvander@1096: return false; dvander@1096: } dvander@1096: if (!m_pWorker->Start()) dvander@1096: { dvander@1096: if (!s_OneTimeThreaderErrorMsg) dvander@1096: { dvander@1096: g_Logger.LogError("[SM] Unable to start db threader (error unknown)"); dvander@1096: s_OneTimeThreaderErrorMsg = true; dvander@1096: } dvander@1096: g_pThreader->DestroyWorker(m_pWorker); dvander@1096: m_pWorker = NULL; dvander@1096: return false; dvander@1096: } dvander@1096: } dvander@1096: dvander@1096: /* Add to the queue */ dvander@1096: { dvander@1096: m_pQueueLock->Lock(); dvander@1096: Queue &queue = m_OpQueue.GetQueue(prio); dvander@1096: queue.push(op); dvander@1096: m_pQueueLock->Unlock(); dvander@1096: } dvander@1096: dvander@1096: /* Make the thread */ dvander@1096: m_pWorker->MakeThread(this); dvander@1096: dvander@1096: return true; dvander@1096: } dvander@1096: dvander@1096: void DBManager::OnWorkerStart(IThreadWorker *pWorker) dvander@1096: { dvander@1096: m_drSafety.clear(); dvander@1096: for (size_t i=0; iIsThreadSafe()) dvander@1096: { dvander@1096: m_drSafety.push_back(m_drivers[i]->InitializeThreadSafety()); dvander@1096: } else { dvander@1096: m_drSafety.push_back(false); dvander@1096: } dvander@1096: } dvander@1096: } dvander@1096: dvander@1096: void DBManager::OnWorkerStop(IThreadWorker *pWorker) dvander@1096: { dvander@1096: for (size_t i=0; iShutdownThreadSafety(); dvander@1096: } dvander@1096: } dvander@1096: m_drSafety.clear(); dvander@1096: } dvander@1096: dvander@1096: void DBManager::RunThread(IThreadHandle *pThread) dvander@1096: { dvander@1096: IDBThreadOperation *op = NULL; dvander@1096: dvander@1096: /* Get something from the queue */ dvander@1096: { dvander@1096: m_pQueueLock->Lock(); dvander@1096: Queue &queue = m_OpQueue.GetLikelyQueue(); dvander@1096: if (!queue.empty()) dvander@1096: { dvander@1096: op = queue.first(); dvander@1096: queue.pop(); dvander@1096: } dvander@1096: m_pQueueLock->Unlock(); dvander@1096: } dvander@1096: dvander@1096: /* whoa. hi. did we get something? we should have. */ dvander@1096: if (!op) dvander@1096: { dvander@1096: /* wtf? */ dvander@1096: return; dvander@1096: } dvander@1096: dvander@1096: op->RunThreadPart(); dvander@1096: dvander@1096: m_pThinkLock->Lock(); dvander@1096: m_ThinkQueue.push(op); dvander@1096: m_pThinkLock->Unlock(); dvander@1096: } dvander@1096: dvander@1096: void DBManager::RunFrame() dvander@1096: { dvander@1096: /* Don't bother if we're empty */ dvander@1096: if (!m_ThinkQueue.size()) dvander@1096: { dvander@1096: return; dvander@1096: } dvander@1096: dvander@1096: /* Dump one thing per-frame so the server stays sane. */ dvander@1096: m_pThinkLock->Lock(); dvander@1096: IDBThreadOperation *op = m_ThinkQueue.first(); dvander@1096: m_ThinkQueue.pop(); dvander@1096: m_pThinkLock->Unlock(); dvander@1096: op->RunThinkPart(); dvander@1157: op->Destroy(); dvander@1096: } dvander@1096: dvander@1096: void DBManager::OnTerminate(IThreadHandle *pThread, bool cancel) dvander@1096: { dvander@1096: /* Do nothing */ dvander@1096: } dvander@1096: dvander@1157: void DBManager::OnSourceModIdentityDropped(IdentityToken_t *pToken) dvander@1157: { dvander@1157: s_pAddBlock = pToken; dvander@1157: dvander@1157: /* Kill the thread so we can flush everything into the think queue... */ dvander@1157: KillWorkerThread(); dvander@1157: dvander@1157: /* Run all of the think operations. dvander@1157: * Unlike the driver unloading example, we'll let these calls go through, dvander@1157: * since a plugin unloading is far more normal. dvander@1157: */ dvander@1157: Queue::iterator iter = m_ThinkQueue.begin(); dvander@1157: Queue templist; dvander@1157: while (iter != m_ThinkQueue.end()) dvander@1157: { dvander@1157: IDBThreadOperation *op = (*iter); dvander@1157: if (op->GetOwner() == pToken) dvander@1157: { dvander@1157: templist.push(op); dvander@1157: iter = m_ThinkQueue.erase(iter); dvander@1157: } else { dvander@1157: iter++; dvander@1157: } dvander@1157: } dvander@1157: dvander@1157: for (iter = templist.begin(); dvander@1157: iter != templist.end(); dvander@1157: iter++) dvander@1157: { dvander@1157: IDBThreadOperation *op = (*iter); dvander@1157: op->RunThinkPart(); dvander@1157: op->Destroy(); dvander@1157: } dvander@1157: dvander@1157: s_pAddBlock = NULL; dvander@1157: } dvander@1157: dvander@1096: void DBManager::OnPluginUnloaded(IPlugin *plugin) dvander@1096: { dvander@1096: /* Kill the thread so we can flush everything into the think queue... */ dvander@1096: KillWorkerThread(); dvander@1096: dvander@1096: /* Mark the plugin as being unloaded so future database calls will ignore threading... */ dvander@1096: plugin->SetProperty("DisallowDBThreads", NULL); dvander@1096: dvander@1096: /* Run all of the think operations. dvander@1096: * Unlike the driver unloading example, we'll let these calls go through, dvander@1096: * since a plugin unloading is far more normal. dvander@1096: */ dvander@1096: Queue::iterator iter = m_ThinkQueue.begin(); dvander@1096: Queue templist; dvander@1096: while (iter != m_ThinkQueue.end()) dvander@1096: { dvander@1096: IDBThreadOperation *op = (*iter); dvander@1157: if (op->GetOwner() == plugin->GetIdentity()) dvander@1096: { dvander@1096: templist.push(op); dvander@1096: iter = m_ThinkQueue.erase(iter); dvander@1096: } else { dvander@1096: iter++; dvander@1096: } dvander@1096: } dvander@1096: dvander@1096: for (iter = templist.begin(); dvander@1096: iter != templist.end(); dvander@1096: iter++) dvander@1096: { dvander@1096: IDBThreadOperation *op = (*iter); dvander@1096: op->RunThinkPart(); dvander@1157: op->Destroy(); dvander@1096: } dvander@1096: } dvander@1096: dvander@1096: void DBManager::LockConfig() dvander@1096: { dvander@1096: m_pConfigLock->Lock(); dvander@1096: } dvander@1096: dvander@1096: void DBManager::UnlockConfig() dvander@1096: { dvander@1096: m_pConfigLock->Unlock(); dvander@1096: } dvander@1096: dvander@1096: const char *DBManager::GetDefaultDriverName() dvander@1096: { dvander@1096: return m_DefDriver.c_str(); dvander@1096: } dvander@2134: dvander@2134: void DBManager::AddDependency(IExtension *myself, IDBDriver *driver) dvander@2134: { dvander@2134: g_Extensions.AddRawDependency(myself, driver->GetIdentity(), driver); dvander@2134: } dvander@2134: