core/Database.cpp
author Nicholas Hastings <skamonkey@gmail.com>
Mon Aug 05 11:36:59 2013 -0400 (2013-08-05)
changeset 3973 5c5ed57cca88
parent 3872 4c93f74cae51
child 4027 d2c15108b468
permissions -rw-r--r--
Fixed a path not using updated mapcycle file detection (bug 5719).
dvander@667
     1
/**
dvander@667
     2
 * vim: set ts=4 :
ds@1330
     3
 * =============================================================================
dvander@1231
     4
 * SourceMod
ds@1947
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
ds@1330
     6
 * =============================================================================
dvander@667
     7
 *
ds@1330
     8
 * This program is free software; you can redistribute it and/or modify it under
ds@1330
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
ds@1330
    10
 * Free Software Foundation.
dvander@1231
    11
 * 
ds@1330
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1330
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1330
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
ds@1330
    15
 * details.
dvander@1231
    16
 *
ds@1330
    17
 * You should have received a copy of the GNU General Public License along with
ds@1330
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@1231
    19
 *
ds@1330
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
ds@1330
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1330
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1330
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
ds@1330
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
ds@1330
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
ds@1330
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1330
    27
 * or <http://www.sourcemod.net/license.php>.
dvander@667
    28
 *
dvander@667
    29
 * Version: $Id$
dvander@667
    30
 */
dvander@667
    31
dvander@666
    32
#include "Database.h"
dvander@666
    33
#include "sourcemod.h"
dvander@868
    34
#include "sm_stringutil.h"
dvander@868
    35
#include "Logger.h"
dvander@868
    36
#include <stdlib.h>
dvander@2726
    37
#include <IThreader.h>
dvander@3872
    38
#include "logic_bridge.h"
dvander@868
    39
dvander@868
    40
#define DBPARSE_LEVEL_NONE		0
dvander@868
    41
#define DBPARSE_LEVEL_MAIN		1
dvander@868
    42
#define DBPARSE_LEVEL_DATABASE	2
dvander@666
    43
dvander@666
    44
DBManager g_DBMan;
dvander@1096
    45
static bool s_OneTimeThreaderErrorMsg = false;
dvander@666
    46
dvander@868
    47
DBManager::DBManager() 
fyrenmoo@3139
    48
: m_ParseLevel(0), m_ParseState(0), m_pDefault(NULL)
dvander@868
    49
{
dvander@868
    50
}
dvander@868
    51
dvander@666
    52
void DBManager::OnSourceModAllInitialized()
dvander@666
    53
{
dvander@666
    54
	HandleAccess sec;
dvander@666
    55
dvander@3872
    56
	handlesys->InitAccessDefaults(NULL, &sec);
dvander@666
    57
	sec.access[HandleAccess_Delete] |= HANDLE_RESTRICT_IDENTITY;
dvander@666
    58
	sec.access[HandleAccess_Clone] |= HANDLE_RESTRICT_IDENTITY;
dvander@666
    59
	
dvander@3872
    60
	m_DriverType = handlesys->CreateType("IDriver", this, 0, NULL, &sec, g_pCoreIdent, NULL);
dvander@3872
    61
	m_DatabaseType = handlesys->CreateType("IDatabase", this, 0, NULL, NULL, g_pCoreIdent, NULL);
dvander@862
    62
dvander@3872
    63
	sharesys->AddInterface(NULL, this);
dvander@868
    64
dvander@868
    65
	g_SourceMod.BuildPath(Path_SM, m_Filename, sizeof(m_Filename), "configs/databases.cfg");
dvander@1096
    66
dvander@1096
    67
	m_pConfigLock = g_pThreader->MakeMutex();
dvander@1096
    68
	m_pThinkLock = g_pThreader->MakeMutex();
dvander@1096
    69
	m_pQueueLock = g_pThreader->MakeMutex();
dvander@1096
    70
dvander@3872
    71
	scripts->AddPluginsListener(this);
dvander@868
    72
}
dvander@868
    73
dvander@868
    74
void DBManager::OnSourceModLevelChange(const char *mapName)
dvander@868
    75
{
dvander@1656
    76
	SMCError err;
dvander@1656
    77
	SMCStates states = {0, 0};
dvander@1096
    78
dvander@1096
    79
	/* We lock and don't give up the lock until we're done.
dvander@1096
    80
	 * This way the thread's search won't be searching through a
dvander@1096
    81
	 * potentially empty/corrupt list, which would be very bad.
dvander@1096
    82
	 */
dvander@1096
    83
	m_pConfigLock->Lock();
dvander@1656
    84
	if ((err = textparsers->ParseFile_SMC(m_Filename, this, &states)) != SMCError_Okay)
dvander@868
    85
	{
dvander@868
    86
		g_Logger.LogError("[SM] Detected parse error(s) in file \"%s\"", m_Filename);
dvander@1656
    87
		if (err != SMCError_Custom)
dvander@868
    88
		{
dvander@1406
    89
			const char *txt = textparsers->GetSMCErrorString(err);
dvander@1656
    90
			g_Logger.LogError("[SM] Line %d: %s", states.line, txt);
dvander@868
    91
		}
dvander@868
    92
	}
dvander@1096
    93
	m_pConfigLock->Unlock();
dvander@858
    94
}
dvander@858
    95
dvander@858
    96
void DBManager::OnSourceModShutdown()
dvander@858
    97
{
dvander@1096
    98
	KillWorkerThread();
dvander@3872
    99
	scripts->RemovePluginsListener(this);
dvander@1096
   100
	m_pConfigLock->DestroyThis();
dvander@1096
   101
	m_pThinkLock->DestroyThis();
dvander@1096
   102
	m_pQueueLock->DestroyThis();
dvander@3872
   103
	handlesys->RemoveType(m_DatabaseType, g_pCoreIdent);
dvander@3872
   104
	handlesys->RemoveType(m_DriverType, g_pCoreIdent);
dvander@3140
   105
	ClearConfigs();
dvander@858
   106
}
dvander@858
   107
dvander@858
   108
unsigned int DBManager::GetInterfaceVersion()
dvander@858
   109
{
dvander@858
   110
	return SMINTERFACE_DBI_VERSION;
dvander@858
   111
}
dvander@858
   112
dvander@858
   113
const char *DBManager::GetInterfaceName()
dvander@858
   114
{
dvander@858
   115
	return SMINTERFACE_DBI_NAME;
dvander@666
   116
}
dvander@666
   117
dvander@666
   118
void DBManager::OnHandleDestroy(HandleType_t type, void *object)
dvander@666
   119
{
dvander@666
   120
	if (type == m_DriverType)
dvander@666
   121
	{
dvander@666
   122
		/* Ignore */
dvander@666
   123
		return;
dvander@666
   124
	}
dvander@666
   125
dvander@3872
   126
	if (handlesys->TypeCheck(type, m_DatabaseType))
dvander@666
   127
	{
dvander@666
   128
		IDatabase *pdb = (IDatabase *)object;
dvander@666
   129
		pdb->Close();
dvander@666
   130
	}
dvander@666
   131
}
dvander@666
   132
dvander@868
   133
void DBManager::ReadSMC_ParseStart()
dvander@666
   134
{
dvander@3140
   135
	ClearConfigs();
dvander@868
   136
	m_ParseLevel = 0;
dvander@868
   137
	m_ParseState = DBPARSE_LEVEL_NONE;
dvander@868
   138
	m_DefDriver.clear();
dvander@868
   139
}
dvander@666
   140
dvander@3140
   141
void DBManager::ClearConfigs()
dvander@3140
   142
{
dvander@3140
   143
	List<ConfDbInfo *>::iterator iter;
dvander@3140
   144
	for (iter=m_confs.begin(); iter!=m_confs.end(); iter++)
dvander@3140
   145
		delete (*iter);
dvander@3140
   146
	m_confs.clear();
dvander@3140
   147
}
dvander@3140
   148
dvander@868
   149
ConfDbInfo s_CurInfo;
dvander@1656
   150
SMCResult DBManager::ReadSMC_NewSection(const SMCStates *states, const char *name)
dvander@868
   151
{
dvander@868
   152
	if (m_ParseLevel)
dvander@868
   153
	{
dvander@868
   154
		m_ParseLevel++;
dvander@1656
   155
		return SMCResult_Continue;
dvander@868
   156
	}
dvander@868
   157
dvander@868
   158
	if (m_ParseState == DBPARSE_LEVEL_NONE)
dvander@666
   159
	{
dvander@868
   160
		if (strcmp(name, "Databases") == 0)
dvander@666
   161
		{
dvander@868
   162
			m_ParseState = DBPARSE_LEVEL_MAIN;
dvander@868
   163
		} else {
dvander@868
   164
			m_ParseLevel++;
dvander@868
   165
		}
dvander@868
   166
	} else if (m_ParseState == DBPARSE_LEVEL_MAIN) {
dvander@868
   167
		s_CurInfo = ConfDbInfo();
fyrenmoo@3139
   168
		s_CurInfo.name = name;
dvander@868
   169
		m_ParseState = DBPARSE_LEVEL_DATABASE;
dvander@868
   170
	} else if (m_ParseState == DBPARSE_LEVEL_DATABASE) {
dvander@868
   171
		m_ParseLevel++;
dvander@868
   172
	}
dvander@868
   173
dvander@1656
   174
	return SMCResult_Continue;
dvander@868
   175
}
dvander@868
   176
dvander@1656
   177
SMCResult DBManager::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
dvander@868
   178
{
dvander@868
   179
	if (m_ParseLevel)
dvander@868
   180
	{
dvander@1656
   181
		return SMCResult_Continue;
dvander@868
   182
	}
dvander@868
   183
dvander@868
   184
	if (m_ParseState == DBPARSE_LEVEL_MAIN)
dvander@868
   185
	{
dvander@868
   186
		if (strcmp(key, "driver_default") == 0)
dvander@868
   187
		{
dvander@868
   188
			m_DefDriver.assign(value);
dvander@868
   189
		}
dvander@868
   190
	} else if (m_ParseState == DBPARSE_LEVEL_DATABASE) {
dvander@868
   191
		if (strcmp(key, "driver") == 0)
dvander@868
   192
		{
dvander@868
   193
			if (strcmp(value, "default") != 0)
dvander@868
   194
			{
fyrenmoo@3139
   195
				s_CurInfo.driver = value;
dvander@868
   196
			}
dvander@868
   197
		} else if (strcmp(key, "database") == 0) {
fyrenmoo@3139
   198
			s_CurInfo.database = value;
dvander@868
   199
		} else if (strcmp(key, "host") == 0) {
fyrenmoo@3139
   200
			s_CurInfo.host = value;
dvander@868
   201
		} else if (strcmp(key, "user") == 0) {
fyrenmoo@3139
   202
			s_CurInfo.user = value;
dvander@868
   203
		} else if (strcmp(key, "pass") == 0) {
fyrenmoo@3139
   204
			s_CurInfo.pass = value;
dvander@868
   205
		} else if (strcmp(key, "timeout") == 0) {
dvander@868
   206
			s_CurInfo.info.maxTimeout = atoi(value);
dvander@868
   207
		} else if (strcmp(key, "port") == 0) {
dvander@868
   208
			s_CurInfo.info.port = atoi(value);
dvander@666
   209
		}
dvander@666
   210
	}
dvander@666
   211
dvander@1656
   212
	return SMCResult_Continue;
dvander@868
   213
}
dvander@868
   214
dvander@1656
   215
SMCResult DBManager::ReadSMC_LeavingSection(const SMCStates *states)
dvander@868
   216
{
dvander@868
   217
	if (m_ParseLevel)
dvander@868
   218
	{
dvander@868
   219
		m_ParseLevel--;
dvander@1656
   220
		return SMCResult_Continue;
dvander@868
   221
	}
dvander@868
   222
dvander@868
   223
	if (m_ParseState == DBPARSE_LEVEL_DATABASE)
dvander@868
   224
	{
dvander@3140
   225
		ConfDbInfo *cdb = new ConfDbInfo();
dvander@3140
   226
dvander@3140
   227
		cdb->name = s_CurInfo.name;
dvander@3140
   228
		cdb->driver = s_CurInfo.driver;
dvander@3140
   229
		cdb->host = s_CurInfo.host;
dvander@3140
   230
		cdb->user = s_CurInfo.user;
dvander@3140
   231
		cdb->pass = s_CurInfo.pass;
dvander@3140
   232
		cdb->database = s_CurInfo.database;
dvander@3140
   233
		cdb->realDriver = s_CurInfo.realDriver;
dvander@3140
   234
		cdb->info.maxTimeout = s_CurInfo.info.maxTimeout;
dvander@3140
   235
		cdb->info.port = s_CurInfo.info.port;
dvander@3140
   236
dvander@3140
   237
		cdb->info.driver = cdb->driver.c_str();
dvander@3140
   238
		cdb->info.database = cdb->database.c_str();
dvander@3140
   239
		cdb->info.host = cdb->host.c_str();
dvander@3140
   240
		cdb->info.user = cdb->user.c_str();
dvander@3140
   241
		cdb->info.pass = cdb->pass.c_str();
dvander@868
   242
		
dvander@868
   243
		/* Save it.. */
dvander@3140
   244
		m_confs.push_back(cdb);
dvander@868
   245
dvander@868
   246
		/* Go up one level */
dvander@868
   247
		m_ParseState = DBPARSE_LEVEL_MAIN;
dvander@868
   248
	} else if (m_ParseState == DBPARSE_LEVEL_MAIN) {
dvander@868
   249
		m_ParseState = DBPARSE_LEVEL_NONE;
dvander@1656
   250
		return SMCResult_Halt;
dvander@868
   251
	}
dvander@868
   252
dvander@1656
   253
	return SMCResult_Continue;
dvander@868
   254
}
dvander@868
   255
dvander@868
   256
void DBManager::ReadSMC_ParseEnd(bool halted, bool failed)
dvander@868
   257
{
dvander@868
   258
}
dvander@868
   259
dvander@868
   260
bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent, char *error, size_t maxlength)
dvander@868
   261
{
dvander@868
   262
	ConfDbInfo *pInfo = GetDatabaseConf(name);
dvander@868
   263
dvander@868
   264
	if (!pInfo)
dvander@868
   265
	{
dvander@868
   266
		if (pdr)
dvander@868
   267
		{
dvander@868
   268
			*pdr = NULL;
dvander@868
   269
		}
dvander@868
   270
		*pdb = NULL;
dvander@868
   271
		UTIL_Format(error, maxlength, "Configuration \"%s\" not found", name);
dvander@868
   272
		return false;
dvander@868
   273
	}
dvander@868
   274
dvander@869
   275
	const char *dname = pInfo->info.driver;
dvander@868
   276
	if (!pInfo->realDriver)
dvander@868
   277
	{
dvander@868
   278
		/* Try to assign a real driver pointer */
dvander@868
   279
		if (pInfo->info.driver[0] == '\0')
dvander@868
   280
		{
dvander@868
   281
			if (!m_pDefault && m_DefDriver.size() > 0)
dvander@868
   282
			{
dvander@868
   283
				m_pDefault = FindOrLoadDriver(m_DefDriver.c_str());
dvander@868
   284
			}
dvander@869
   285
			dname = m_DefDriver.size() ? m_DefDriver.c_str() : "default";
dvander@868
   286
			pInfo->realDriver = m_pDefault;
dvander@868
   287
		} else {
dvander@868
   288
			pInfo->realDriver = FindOrLoadDriver(pInfo->info.driver);
dvander@868
   289
		}
dvander@868
   290
	}
dvander@868
   291
dvander@868
   292
	if (pInfo->realDriver)
dvander@868
   293
	{
dvander@868
   294
		if (pdr)
dvander@868
   295
		{
dvander@868
   296
			*pdr = pInfo->realDriver;
dvander@868
   297
		}
dvander@868
   298
		*pdb = pInfo->realDriver->Connect(&pInfo->info, persistent, error, maxlength);
dvander@868
   299
		return (*pdb != NULL);
dvander@868
   300
	}
dvander@868
   301
dvander@868
   302
	if (pdr)
dvander@868
   303
	{
dvander@868
   304
		*pdr = NULL;
dvander@868
   305
	}
dvander@666
   306
	*pdb = NULL;
dvander@666
   307
dvander@869
   308
	UTIL_Format(error, maxlength, "Driver \"%s\" not found", dname);
dvander@868
   309
dvander@666
   310
	return false;
dvander@666
   311
}
dvander@858
   312
dvander@858
   313
void DBManager::AddDriver(IDBDriver *pDriver)
dvander@858
   314
{
dvander@1096
   315
	 /* Let's kill the worker.  Join the thread and let the queries flush.
dvander@1096
   316
	  * This is kind of stupid but we just want to unload safely.
dvander@1096
   317
	  * Rather than recreate the worker, we'll wait until someone throws 
dvander@1096
   318
	  * another query through.
dvander@1096
   319
	  */
dvander@1096
   320
	KillWorkerThread();
dvander@1096
   321
dvander@858
   322
	 m_drivers.push_back(pDriver);
dvander@858
   323
}
dvander@858
   324
dvander@858
   325
void DBManager::RemoveDriver(IDBDriver *pDriver)
dvander@858
   326
{
dvander@1096
   327
	/* Again, we're forced to kill the worker.  How rude!
dvander@1096
   328
	 * Doing this flushes the queue, and thus we don't need to 
dvander@1096
   329
	 * clean anything else.  
dvander@1096
   330
	 */
dvander@1096
   331
	KillWorkerThread();
dvander@1096
   332
dvander@858
   333
	for (size_t i=0; i<m_drivers.size(); i++)
dvander@858
   334
	{
dvander@858
   335
		if (m_drivers[i] == pDriver)
dvander@858
   336
		{
dvander@858
   337
			m_drivers.erase(m_drivers.iterAt(i));
dvander@1201
   338
			break;
dvander@858
   339
		}
dvander@858
   340
	}
dvander@868
   341
dvander@868
   342
	/* Make sure NOTHING references this! */
dvander@3140
   343
	List<ConfDbInfo *>::iterator iter;
dvander@868
   344
	for (iter=m_confs.begin(); iter!=m_confs.end(); iter++)
dvander@868
   345
	{
dvander@3140
   346
		ConfDbInfo &db = *(*iter);
dvander@868
   347
		if (db.realDriver == pDriver)
dvander@868
   348
		{
dvander@868
   349
			db.realDriver = NULL;
dvander@868
   350
		}
dvander@868
   351
	}
dvander@1096
   352
dvander@1096
   353
	/* Now that the driver is gone, we have to test the think queue.
dvander@1096
   354
	 * Whatever happens therein is up to the db op!
dvander@1096
   355
	 */
dvander@1096
   356
	Queue<IDBThreadOperation *>::iterator qiter = m_ThinkQueue.begin();
dvander@1096
   357
	Queue<IDBThreadOperation *> templist;
dvander@1096
   358
	while (qiter != m_ThinkQueue.end())
dvander@1096
   359
	{
dvander@1096
   360
		IDBThreadOperation *op = (*qiter);
dvander@1096
   361
		if (op->GetDriver() == pDriver)
dvander@1096
   362
		{
dvander@1096
   363
			templist.push(op);
dvander@1096
   364
			qiter = m_ThinkQueue.erase(qiter);
dvander@1096
   365
		} else {
dvander@1096
   366
			qiter++;
dvander@1096
   367
		}
dvander@1096
   368
	}
dvander@1096
   369
dvander@1096
   370
	for (qiter = templist.begin();
dvander@1096
   371
		 qiter != templist.end();
dvander@1096
   372
		 qiter++)
dvander@1096
   373
	{
dvander@1096
   374
		IDBThreadOperation *op = (*qiter);
dvander@1096
   375
		op->CancelThinkPart();
dvander@1157
   376
		op->Destroy();
dvander@1096
   377
	}
dvander@868
   378
}
dvander@868
   379
dvander@868
   380
IDBDriver *DBManager::GetDefaultDriver()
dvander@868
   381
{
dvander@868
   382
	if (!m_pDefault && m_DefDriver.size() > 0)
dvander@868
   383
	{
dvander@868
   384
		m_pDefault = FindOrLoadDriver(m_DefDriver.c_str());
dvander@868
   385
	}
dvander@868
   386
dvander@868
   387
	return m_pDefault;
dvander@858
   388
}
dvander@858
   389
dvander@858
   390
Handle_t DBManager::CreateHandle(DBHandleType dtype, void *ptr, IdentityToken_t *pToken)
dvander@858
   391
{
dvander@858
   392
	HandleType_t type = 0;
dvander@858
   393
dvander@858
   394
	if (dtype == DBHandle_Driver)
dvander@858
   395
	{
dvander@858
   396
		type = m_DriverType;
dvander@858
   397
	} else if (dtype == DBHandle_Database) {
dvander@858
   398
		type = m_DatabaseType;
dvander@858
   399
	} else {
dvander@858
   400
		return BAD_HANDLE;
dvander@858
   401
	}
dvander@858
   402
dvander@3872
   403
	return handlesys->CreateHandle(type, ptr, pToken, g_pCoreIdent, NULL);
dvander@858
   404
}
dvander@858
   405
dvander@858
   406
HandleError DBManager::ReadHandle(Handle_t hndl, DBHandleType dtype, void **ptr)
dvander@858
   407
{
dvander@858
   408
	HandleType_t type = 0;
dvander@858
   409
dvander@858
   410
	if (dtype == DBHandle_Driver)
dvander@858
   411
	{
dvander@858
   412
		type = m_DriverType;
dvander@858
   413
	} else if (dtype == DBHandle_Database) {
dvander@858
   414
		type = m_DatabaseType;
dvander@858
   415
	} else {
dvander@858
   416
		return HandleError_Type;
dvander@858
   417
	}
dvander@858
   418
dvander@858
   419
	HandleSecurity sec(NULL, g_pCoreIdent);
dvander@858
   420
dvander@3872
   421
	return handlesys->ReadHandle(hndl, type, &sec, ptr);
dvander@858
   422
}
dvander@858
   423
dvander@858
   424
HandleError DBManager::ReleaseHandle(Handle_t hndl, DBHandleType type, IdentityToken_t *token)
dvander@858
   425
{
dvander@858
   426
	HandleSecurity sec(token, g_pCoreIdent);
dvander@3872
   427
	return handlesys->FreeHandle(hndl, &sec);
dvander@858
   428
}
dvander@858
   429
dvander@858
   430
unsigned int DBManager::GetDriverCount()
dvander@858
   431
{
dvander@858
   432
	return (unsigned int)m_drivers.size();
dvander@858
   433
}
dvander@858
   434
dvander@858
   435
IDBDriver *DBManager::GetDriver(unsigned int index)
dvander@858
   436
{
dvander@858
   437
	if (index >= m_drivers.size())
dvander@858
   438
	{
dvander@858
   439
		return NULL;
dvander@858
   440
	}
dvander@858
   441
dvander@858
   442
	return m_drivers[index];
dvander@858
   443
}
dvander@858
   444
dvander@858
   445
const DatabaseInfo *DBManager::FindDatabaseConf(const char *name)
dvander@858
   446
{
dvander@868
   447
	ConfDbInfo *info = GetDatabaseConf(name);
dvander@868
   448
	if (!info)
dvander@868
   449
	{
dvander@868
   450
		return NULL;
dvander@868
   451
	}
dvander@868
   452
dvander@868
   453
	return &info->info;
dvander@868
   454
}
dvander@868
   455
dvander@868
   456
ConfDbInfo *DBManager::GetDatabaseConf(const char *name)
dvander@868
   457
{
dvander@3140
   458
	List<ConfDbInfo *>::iterator iter;
dvander@868
   459
dvander@868
   460
	for (iter=m_confs.begin(); iter!=m_confs.end(); iter++)
dvander@868
   461
	{
dvander@3140
   462
		ConfDbInfo &conf = *(*iter);
fyrenmoo@3139
   463
		if (conf.name == name)
dvander@868
   464
		{
dvander@868
   465
			return &conf;
dvander@868
   466
		}
dvander@868
   467
	}
dvander@868
   468
dvander@858
   469
	return NULL;
dvander@858
   470
}
dvander@868
   471
dvander@868
   472
IDBDriver *DBManager::FindOrLoadDriver(const char *name)
dvander@868
   473
{
dvander@868
   474
	size_t last_size = m_drivers.size();
dvander@868
   475
	for (size_t i=0; i<last_size; i++)
dvander@868
   476
	{
dvander@868
   477
		if (strcmp(m_drivers[i]->GetIdentifier(), name) == 0)
dvander@868
   478
		{
dvander@868
   479
			return m_drivers[i];
dvander@868
   480
		}
dvander@868
   481
	}
dvander@868
   482
dvander@868
   483
	char filename[PLATFORM_MAX_PATH];
dvander@869
   484
	UTIL_Format(filename, sizeof(filename), "dbi.%s.ext", name);
dvander@868
   485
dvander@3872
   486
	IExtension *pExt = extsys->LoadAutoExtension(filename);
dvander@868
   487
	if (!pExt || !pExt->IsLoaded() || m_drivers.size() <= last_size)
dvander@868
   488
	{
dvander@868
   489
		return NULL;
dvander@868
   490
	}
dvander@868
   491
dvander@868
   492
	/* last_size is now gauranteed to be a valid index.
dvander@868
   493
	 * The identifier must match the name.
dvander@868
   494
	 */
dvander@868
   495
	if (strcmp(m_drivers[last_size]->GetIdentifier(), name) == 0)
dvander@868
   496
	{
dvander@868
   497
		return m_drivers[last_size];
dvander@868
   498
	}
dvander@868
   499
dvander@868
   500
	return NULL;
dvander@868
   501
}
dvander@1096
   502
dvander@1096
   503
void DBManager::KillWorkerThread()
dvander@1096
   504
{
dvander@1096
   505
	if (m_pWorker)
dvander@1096
   506
	{
dvander@1096
   507
		m_pWorker->Stop(false);
dvander@1096
   508
		g_pThreader->DestroyWorker(m_pWorker);
dvander@1096
   509
		m_pWorker = NULL;
dvander@1096
   510
		s_OneTimeThreaderErrorMsg = false;
dvander@1096
   511
	}
dvander@1096
   512
}
dvander@1096
   513
dvander@1157
   514
static IdentityToken_t *s_pAddBlock = NULL;
dvander@1157
   515
dvander@1096
   516
bool DBManager::AddToThreadQueue(IDBThreadOperation *op, PrioQueueLevel prio)
dvander@1096
   517
{
dvander@1157
   518
	if (s_pAddBlock && op->GetOwner() == s_pAddBlock)
dvander@1157
   519
	{
dvander@1157
   520
		return false;
dvander@1157
   521
	}
dvander@1157
   522
dvander@1096
   523
	if (!m_pWorker)
dvander@1096
   524
	{
dvander@1096
   525
		m_pWorker = g_pThreader->MakeWorker(this, true);
dvander@1096
   526
		if (!m_pWorker)
dvander@1096
   527
		{
dvander@1096
   528
			if (!s_OneTimeThreaderErrorMsg)
dvander@1096
   529
			{
dvander@1096
   530
				g_Logger.LogError("[SM] Unable to create db threader (error unknown)");
dvander@1096
   531
				s_OneTimeThreaderErrorMsg = true;
dvander@1096
   532
			}
dvander@1096
   533
			return false;
dvander@1096
   534
		}
dvander@1096
   535
		if (!m_pWorker->Start())
dvander@1096
   536
		{
dvander@1096
   537
			if (!s_OneTimeThreaderErrorMsg)
dvander@1096
   538
			{
dvander@1096
   539
				g_Logger.LogError("[SM] Unable to start db threader (error unknown)");
dvander@1096
   540
				s_OneTimeThreaderErrorMsg = true;
dvander@1096
   541
			}
dvander@1096
   542
			g_pThreader->DestroyWorker(m_pWorker);
dvander@1096
   543
			m_pWorker = NULL;
dvander@1096
   544
			return false;
dvander@1096
   545
		}
dvander@1096
   546
	}
dvander@1096
   547
dvander@1096
   548
	/* Add to the queue */
dvander@1096
   549
	{
dvander@1096
   550
		m_pQueueLock->Lock();
dvander@1096
   551
		Queue<IDBThreadOperation *> &queue = m_OpQueue.GetQueue(prio);
dvander@1096
   552
		queue.push(op);
dvander@1096
   553
		m_pQueueLock->Unlock();
dvander@1096
   554
	}
dvander@1096
   555
dvander@1096
   556
	/* Make the thread */
dvander@1096
   557
	m_pWorker->MakeThread(this);
dvander@1096
   558
dvander@1096
   559
	return true;
dvander@1096
   560
}
dvander@1096
   561
dvander@1096
   562
void DBManager::OnWorkerStart(IThreadWorker *pWorker)
dvander@1096
   563
{
dvander@1096
   564
	m_drSafety.clear();
dvander@1096
   565
	for (size_t i=0; i<m_drivers.size(); i++)
dvander@1096
   566
	{
dvander@1096
   567
		if (m_drivers[i]->IsThreadSafe())
dvander@1096
   568
		{
dvander@1096
   569
			m_drSafety.push_back(m_drivers[i]->InitializeThreadSafety());
dvander@1096
   570
		} else {
dvander@1096
   571
			m_drSafety.push_back(false);
dvander@1096
   572
		}
dvander@1096
   573
	}
dvander@1096
   574
}
dvander@1096
   575
dvander@1096
   576
void DBManager::OnWorkerStop(IThreadWorker *pWorker)
dvander@1096
   577
{
dvander@1096
   578
	for (size_t i=0; i<m_drivers.size(); i++)
dvander@1096
   579
	{
dvander@1096
   580
		if (m_drSafety[i])
dvander@1096
   581
		{
dvander@1096
   582
			m_drivers[i]->ShutdownThreadSafety();
dvander@1096
   583
		}
dvander@1096
   584
	}
dvander@1096
   585
	m_drSafety.clear();
dvander@1096
   586
}
dvander@1096
   587
dvander@1096
   588
void DBManager::RunThread(IThreadHandle *pThread)
dvander@1096
   589
{
dvander@1096
   590
	IDBThreadOperation *op = NULL;
dvander@1096
   591
dvander@1096
   592
	/* Get something from the queue */
dvander@1096
   593
	{
dvander@1096
   594
		m_pQueueLock->Lock();
dvander@1096
   595
		Queue<IDBThreadOperation *> &queue = m_OpQueue.GetLikelyQueue();
dvander@1096
   596
		if (!queue.empty())
dvander@1096
   597
		{
dvander@1096
   598
			op = queue.first();
dvander@1096
   599
			queue.pop();
dvander@1096
   600
		}
dvander@1096
   601
		m_pQueueLock->Unlock();
dvander@1096
   602
	}
dvander@1096
   603
dvander@1096
   604
	/* whoa.  hi.  did we get something? we should have. */
dvander@1096
   605
	if (!op)
dvander@1096
   606
	{
dvander@1096
   607
		/* wtf? */
dvander@1096
   608
		return;
dvander@1096
   609
	}
dvander@1096
   610
dvander@1096
   611
	op->RunThreadPart();
dvander@1096
   612
dvander@1096
   613
	m_pThinkLock->Lock();
dvander@1096
   614
	m_ThinkQueue.push(op);
dvander@1096
   615
	m_pThinkLock->Unlock();
dvander@1096
   616
}
dvander@1096
   617
dvander@1096
   618
void DBManager::RunFrame()
dvander@1096
   619
{
dvander@1096
   620
	/* Don't bother if we're empty */
dvander@1096
   621
	if (!m_ThinkQueue.size())
dvander@1096
   622
	{
dvander@1096
   623
		return;
dvander@1096
   624
	}
dvander@1096
   625
dvander@1096
   626
	/* Dump one thing per-frame so the server stays sane. */
dvander@1096
   627
	m_pThinkLock->Lock();
dvander@1096
   628
	IDBThreadOperation *op = m_ThinkQueue.first();
dvander@1096
   629
	m_ThinkQueue.pop();
dvander@1096
   630
	m_pThinkLock->Unlock();
dvander@1096
   631
	op->RunThinkPart();
dvander@1157
   632
	op->Destroy();
dvander@1096
   633
}
dvander@1096
   634
dvander@1096
   635
void DBManager::OnTerminate(IThreadHandle *pThread, bool cancel)
dvander@1096
   636
{
dvander@1096
   637
	/* Do nothing */
dvander@1096
   638
}
dvander@1096
   639
dvander@1157
   640
void DBManager::OnSourceModIdentityDropped(IdentityToken_t *pToken)
dvander@1157
   641
{
dvander@1157
   642
	s_pAddBlock = pToken;
dvander@1157
   643
dvander@1157
   644
	/* Kill the thread so we can flush everything into the think queue... */
dvander@1157
   645
	KillWorkerThread();
dvander@1157
   646
dvander@1157
   647
	/* Run all of the think operations.
dvander@1157
   648
 	 * Unlike the driver unloading example, we'll let these calls go through, 
dvander@1157
   649
	 * since a plugin unloading is far more normal.
dvander@1157
   650
	 */
dvander@1157
   651
	Queue<IDBThreadOperation *>::iterator iter = m_ThinkQueue.begin();
dvander@1157
   652
	Queue<IDBThreadOperation *> templist;
dvander@1157
   653
	while (iter != m_ThinkQueue.end())
dvander@1157
   654
	{
dvander@1157
   655
		IDBThreadOperation *op = (*iter);
dvander@1157
   656
		if (op->GetOwner() == pToken)
dvander@1157
   657
		{
dvander@1157
   658
			templist.push(op);
dvander@1157
   659
			iter = m_ThinkQueue.erase(iter);
dvander@1157
   660
		} else {
dvander@1157
   661
			iter++;
dvander@1157
   662
		}
dvander@1157
   663
	}
dvander@1157
   664
dvander@1157
   665
	for (iter = templist.begin();
dvander@1157
   666
		iter != templist.end();
dvander@1157
   667
		iter++)
dvander@1157
   668
	{
dvander@1157
   669
		IDBThreadOperation *op = (*iter);
dvander@1157
   670
		op->RunThinkPart();
dvander@1157
   671
		op->Destroy();
dvander@1157
   672
	}
dvander@1157
   673
dvander@1157
   674
	s_pAddBlock = NULL;
dvander@1157
   675
}
dvander@1157
   676
dvander@1096
   677
void DBManager::OnPluginUnloaded(IPlugin *plugin)
dvander@1096
   678
{
dvander@1096
   679
	/* Kill the thread so we can flush everything into the think queue... */
dvander@1096
   680
	KillWorkerThread();
dvander@1096
   681
dvander@1096
   682
	/* Mark the plugin as being unloaded so future database calls will ignore threading... */
dvander@1096
   683
	plugin->SetProperty("DisallowDBThreads", NULL);
dvander@1096
   684
dvander@1096
   685
	/* Run all of the think operations.
dvander@1096
   686
	 * Unlike the driver unloading example, we'll let these calls go through, 
dvander@1096
   687
	 * since a plugin unloading is far more normal.
dvander@1096
   688
	 */
dvander@1096
   689
	Queue<IDBThreadOperation *>::iterator iter = m_ThinkQueue.begin();
dvander@1096
   690
	Queue<IDBThreadOperation *> templist;
dvander@1096
   691
	while (iter != m_ThinkQueue.end())
dvander@1096
   692
	{
dvander@1096
   693
		IDBThreadOperation *op = (*iter);
dvander@1157
   694
		if (op->GetOwner() == plugin->GetIdentity())
dvander@1096
   695
		{
dvander@1096
   696
			templist.push(op);
dvander@1096
   697
			iter = m_ThinkQueue.erase(iter);
dvander@1096
   698
		} else {
dvander@1096
   699
			iter++;
dvander@1096
   700
		}
dvander@1096
   701
	}
dvander@1096
   702
dvander@1096
   703
	for (iter = templist.begin();
dvander@1096
   704
		 iter != templist.end();
dvander@1096
   705
		 iter++)
dvander@1096
   706
	{
dvander@1096
   707
		IDBThreadOperation *op = (*iter);
dvander@1096
   708
		op->RunThinkPart();
dvander@1157
   709
		op->Destroy();
dvander@1096
   710
	}
dvander@1096
   711
}
dvander@1096
   712
dvander@1096
   713
void DBManager::LockConfig()
dvander@1096
   714
{
dvander@1096
   715
	m_pConfigLock->Lock();
dvander@1096
   716
}
dvander@1096
   717
dvander@1096
   718
void DBManager::UnlockConfig()
dvander@1096
   719
{
dvander@1096
   720
	m_pConfigLock->Unlock();
dvander@1096
   721
}
dvander@1096
   722
dvander@1096
   723
const char *DBManager::GetDefaultDriverName()
dvander@1096
   724
{
dvander@1096
   725
	return m_DefDriver.c_str();
dvander@1096
   726
}
dvander@2134
   727
dvander@2134
   728
void DBManager::AddDependency(IExtension *myself, IDBDriver *driver)
dvander@2134
   729
{
dvander@3872
   730
	extsys->AddRawDependency(myself, driver->GetIdentity(), driver);
dvander@2134
   731
}
dvander@2134
   732