core/Database.cpp
author David Anderson <dvander@alliedmods.net>
Thu Jul 19 03:22:10 2007 +0000 (2007-07-19)
changeset 1134 68e8b8d386ff
parent 1096 8e11b2ebdc22
child 1157 61c7092246c6
permissions -rw-r--r--
fixed another translator cache issue
dvander@667
     1
/**
dvander@667
     2
 * vim: set ts=4 :
dvander@667
     3
 * ===============================================================
dvander@667
     4
 * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
dvander@667
     5
 * ===============================================================
dvander@667
     6
 *
dvander@667
     7
 * This file is not open source and may not be copied without explicit
dvander@667
     8
 * written permission of AlliedModders LLC.  This file may not be redistributed 
dvander@667
     9
 * in whole or significant part.
dvander@667
    10
 * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
dvander@667
    11
 *
dvander@667
    12
 * Version: $Id$
dvander@667
    13
 */
dvander@667
    14
dvander@666
    15
#include "Database.h"
dvander@666
    16
#include "HandleSys.h"
dvander@862
    17
#include "ShareSys.h"
dvander@666
    18
#include "sourcemod.h"
dvander@868
    19
#include "sm_stringutil.h"
dvander@868
    20
#include "TextParsers.h"
dvander@868
    21
#include "Logger.h"
dvander@868
    22
#include "ExtensionSys.h"
dvander@868
    23
#include <stdlib.h>
dvander@1096
    24
#include "ThreadSupport.h"
dvander@868
    25
dvander@868
    26
#define DBPARSE_LEVEL_NONE		0
dvander@868
    27
#define DBPARSE_LEVEL_MAIN		1
dvander@868
    28
#define DBPARSE_LEVEL_DATABASE	2
dvander@666
    29
dvander@666
    30
DBManager g_DBMan;
dvander@1096
    31
static bool s_OneTimeThreaderErrorMsg = false;
dvander@666
    32
dvander@868
    33
DBManager::DBManager() 
dvander@868
    34
: m_StrTab(512), m_ParseLevel(0), m_ParseState(0), m_pDefault(NULL)
dvander@868
    35
{
dvander@868
    36
}
dvander@868
    37
dvander@666
    38
void DBManager::OnSourceModAllInitialized()
dvander@666
    39
{
dvander@666
    40
	HandleAccess sec;
dvander@666
    41
dvander@666
    42
	g_HandleSys.InitAccessDefaults(NULL, &sec);
dvander@666
    43
	sec.access[HandleAccess_Delete] |= HANDLE_RESTRICT_IDENTITY;
dvander@666
    44
	sec.access[HandleAccess_Clone] |= HANDLE_RESTRICT_IDENTITY;
dvander@666
    45
	
dvander@666
    46
	m_DriverType = g_HandleSys.CreateType("IDriver", this, 0, NULL, &sec, g_pCoreIdent, NULL);
dvander@666
    47
	m_DatabaseType = g_HandleSys.CreateType("IDatabase", this, 0, NULL, NULL, g_pCoreIdent, NULL);
dvander@862
    48
dvander@862
    49
	g_ShareSys.AddInterface(NULL, this);
dvander@868
    50
dvander@868
    51
	g_SourceMod.BuildPath(Path_SM, m_Filename, sizeof(m_Filename), "configs/databases.cfg");
dvander@1096
    52
dvander@1096
    53
	m_pConfigLock = g_pThreader->MakeMutex();
dvander@1096
    54
	m_pThinkLock = g_pThreader->MakeMutex();
dvander@1096
    55
	m_pQueueLock = g_pThreader->MakeMutex();
dvander@1096
    56
dvander@1096
    57
	g_PluginSys.AddPluginsListener(this);
dvander@868
    58
}
dvander@868
    59
dvander@868
    60
void DBManager::OnSourceModLevelChange(const char *mapName)
dvander@868
    61
{
dvander@868
    62
	SMCParseError err;
dvander@868
    63
	unsigned int line = 0;
dvander@1096
    64
dvander@1096
    65
	/* We lock and don't give up the lock until we're done.
dvander@1096
    66
	 * This way the thread's search won't be searching through a
dvander@1096
    67
	 * potentially empty/corrupt list, which would be very bad.
dvander@1096
    68
	 */
dvander@1096
    69
	m_pConfigLock->Lock();
dvander@868
    70
	if ((err = g_TextParser.ParseFile_SMC(m_Filename, this, &line, NULL)) != SMCParse_Okay)
dvander@868
    71
	{
dvander@868
    72
		g_Logger.LogError("[SM] Detected parse error(s) in file \"%s\"", m_Filename);
dvander@868
    73
		if (err != SMCParse_Custom)
dvander@868
    74
		{
dvander@868
    75
			const char *txt = g_TextParser.GetSMCErrorString(err);
dvander@868
    76
			g_Logger.LogError("[SM] Line %d: %s", line, txt);
dvander@868
    77
		}
dvander@868
    78
	}
dvander@1096
    79
	m_pConfigLock->Unlock();
dvander@1096
    80
dvander@1096
    81
	g_PluginSys.RemovePluginsListener(this);
dvander@858
    82
}
dvander@858
    83
dvander@858
    84
void DBManager::OnSourceModShutdown()
dvander@858
    85
{
dvander@1096
    86
	KillWorkerThread();
dvander@1096
    87
	m_pConfigLock->DestroyThis();
dvander@1096
    88
	m_pThinkLock->DestroyThis();
dvander@1096
    89
	m_pQueueLock->DestroyThis();
dvander@858
    90
	g_HandleSys.RemoveType(m_DatabaseType, g_pCoreIdent);
dvander@858
    91
	g_HandleSys.RemoveType(m_DriverType, g_pCoreIdent);
dvander@858
    92
}
dvander@858
    93
dvander@858
    94
unsigned int DBManager::GetInterfaceVersion()
dvander@858
    95
{
dvander@858
    96
	return SMINTERFACE_DBI_VERSION;
dvander@858
    97
}
dvander@858
    98
dvander@858
    99
const char *DBManager::GetInterfaceName()
dvander@858
   100
{
dvander@858
   101
	return SMINTERFACE_DBI_NAME;
dvander@666
   102
}
dvander@666
   103
dvander@666
   104
void DBManager::OnHandleDestroy(HandleType_t type, void *object)
dvander@666
   105
{
dvander@666
   106
	if (type == m_DriverType)
dvander@666
   107
	{
dvander@666
   108
		/* Ignore */
dvander@666
   109
		return;
dvander@666
   110
	}
dvander@666
   111
dvander@858
   112
	if (g_HandleSys.TypeCheck(type, m_DatabaseType))
dvander@666
   113
	{
dvander@666
   114
		IDatabase *pdb = (IDatabase *)object;
dvander@666
   115
		pdb->Close();
dvander@666
   116
	}
dvander@666
   117
}
dvander@666
   118
dvander@868
   119
void DBManager::ReadSMC_ParseStart()
dvander@666
   120
{
dvander@868
   121
	m_confs.clear();
dvander@868
   122
	m_ParseLevel = 0;
dvander@868
   123
	m_ParseState = DBPARSE_LEVEL_NONE;
dvander@868
   124
	m_StrTab.Reset();
dvander@868
   125
	m_DefDriver.clear();
dvander@868
   126
}
dvander@666
   127
dvander@868
   128
ConfDbInfo s_CurInfo;
dvander@868
   129
SMCParseResult DBManager::ReadSMC_NewSection(const char *name, bool opt_quotes)
dvander@868
   130
{
dvander@868
   131
	if (m_ParseLevel)
dvander@868
   132
	{
dvander@868
   133
		m_ParseLevel++;
dvander@868
   134
		return SMCParse_Continue;
dvander@868
   135
	}
dvander@868
   136
dvander@868
   137
	if (m_ParseState == DBPARSE_LEVEL_NONE)
dvander@666
   138
	{
dvander@868
   139
		if (strcmp(name, "Databases") == 0)
dvander@666
   140
		{
dvander@868
   141
			m_ParseState = DBPARSE_LEVEL_MAIN;
dvander@868
   142
		} else {
dvander@868
   143
			m_ParseLevel++;
dvander@868
   144
		}
dvander@868
   145
	} else if (m_ParseState == DBPARSE_LEVEL_MAIN) {
dvander@868
   146
		s_CurInfo = ConfDbInfo();
dvander@869
   147
		s_CurInfo.name = m_StrTab.AddString(name);
dvander@868
   148
		m_ParseState = DBPARSE_LEVEL_DATABASE;
dvander@868
   149
	} else if (m_ParseState == DBPARSE_LEVEL_DATABASE) {
dvander@868
   150
		m_ParseLevel++;
dvander@868
   151
	}
dvander@868
   152
dvander@868
   153
	return SMCParse_Continue;
dvander@868
   154
}
dvander@868
   155
dvander@868
   156
SMCParseResult DBManager::ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes)
dvander@868
   157
{
dvander@868
   158
	if (m_ParseLevel)
dvander@868
   159
	{
dvander@868
   160
		return SMCParse_Continue;
dvander@868
   161
	}
dvander@868
   162
dvander@868
   163
	if (m_ParseState == DBPARSE_LEVEL_MAIN)
dvander@868
   164
	{
dvander@868
   165
		if (strcmp(key, "driver_default") == 0)
dvander@868
   166
		{
dvander@868
   167
			m_DefDriver.assign(value);
dvander@868
   168
		}
dvander@868
   169
	} else if (m_ParseState == DBPARSE_LEVEL_DATABASE) {
dvander@868
   170
		if (strcmp(key, "driver") == 0)
dvander@868
   171
		{
dvander@868
   172
			if (strcmp(value, "default") != 0)
dvander@868
   173
			{
dvander@868
   174
				s_CurInfo.driver = m_StrTab.AddString(value);
dvander@868
   175
			}
dvander@868
   176
		} else if (strcmp(key, "database") == 0) {
dvander@868
   177
			s_CurInfo.database = m_StrTab.AddString(value);
dvander@868
   178
		} else if (strcmp(key, "host") == 0) {
dvander@868
   179
			s_CurInfo.host = m_StrTab.AddString(value);
dvander@868
   180
		} else if (strcmp(key, "user") == 0) {
dvander@868
   181
			s_CurInfo.user = m_StrTab.AddString(value);
dvander@868
   182
		} else if (strcmp(key, "pass") == 0) {
dvander@868
   183
			s_CurInfo.pass = m_StrTab.AddString(value);
dvander@868
   184
		} else if (strcmp(key, "timeout") == 0) {
dvander@868
   185
			s_CurInfo.info.maxTimeout = atoi(value);
dvander@868
   186
		} else if (strcmp(key, "port") == 0) {
dvander@868
   187
			s_CurInfo.info.port = atoi(value);
dvander@666
   188
		}
dvander@666
   189
	}
dvander@666
   190
dvander@868
   191
	return SMCParse_Continue;
dvander@868
   192
}
dvander@868
   193
dvander@868
   194
#define ASSIGN_VAR(var) \
dvander@868
   195
	if (s_CurInfo.var == -1) { \
dvander@868
   196
		s_CurInfo.info.var = ""; \
dvander@868
   197
	} else { \
dvander@868
   198
		s_CurInfo.info.var = m_StrTab.GetString(s_CurInfo.var); \
dvander@868
   199
	}
dvander@868
   200
dvander@868
   201
SMCParseResult DBManager::ReadSMC_LeavingSection()
dvander@868
   202
{
dvander@868
   203
	if (m_ParseLevel)
dvander@868
   204
	{
dvander@868
   205
		m_ParseLevel--;
dvander@868
   206
		return SMCParse_Continue;
dvander@868
   207
	}
dvander@868
   208
dvander@868
   209
	if (m_ParseState == DBPARSE_LEVEL_DATABASE)
dvander@868
   210
	{
dvander@868
   211
		/* Set all of the info members to either a blank string
dvander@868
   212
		 * or the string pointer from the string table.
dvander@868
   213
		 */
dvander@868
   214
		ASSIGN_VAR(driver);
dvander@868
   215
		ASSIGN_VAR(database);
dvander@868
   216
		ASSIGN_VAR(host);
dvander@868
   217
		ASSIGN_VAR(user);
dvander@868
   218
		ASSIGN_VAR(pass);
dvander@868
   219
		
dvander@868
   220
		/* Save it.. */
dvander@868
   221
		m_confs.push_back(s_CurInfo);
dvander@868
   222
dvander@868
   223
		/* Go up one level */
dvander@868
   224
		m_ParseState = DBPARSE_LEVEL_MAIN;
dvander@868
   225
	} else if (m_ParseState == DBPARSE_LEVEL_MAIN) {
dvander@868
   226
		m_ParseState = DBPARSE_LEVEL_NONE;
dvander@868
   227
		return SMCParse_Halt;
dvander@868
   228
	}
dvander@868
   229
dvander@868
   230
	return SMCParse_Continue;
dvander@868
   231
}
dvander@868
   232
#undef ASSIGN_VAR
dvander@868
   233
dvander@868
   234
void DBManager::ReadSMC_ParseEnd(bool halted, bool failed)
dvander@868
   235
{
dvander@868
   236
}
dvander@868
   237
dvander@868
   238
bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent, char *error, size_t maxlength)
dvander@868
   239
{
dvander@868
   240
	ConfDbInfo *pInfo = GetDatabaseConf(name);
dvander@868
   241
dvander@868
   242
	if (!pInfo)
dvander@868
   243
	{
dvander@868
   244
		if (pdr)
dvander@868
   245
		{
dvander@868
   246
			*pdr = NULL;
dvander@868
   247
		}
dvander@868
   248
		*pdb = NULL;
dvander@868
   249
		UTIL_Format(error, maxlength, "Configuration \"%s\" not found", name);
dvander@868
   250
		return false;
dvander@868
   251
	}
dvander@868
   252
dvander@869
   253
	const char *dname = pInfo->info.driver;
dvander@868
   254
	if (!pInfo->realDriver)
dvander@868
   255
	{
dvander@868
   256
		/* Try to assign a real driver pointer */
dvander@868
   257
		if (pInfo->info.driver[0] == '\0')
dvander@868
   258
		{
dvander@868
   259
			if (!m_pDefault && m_DefDriver.size() > 0)
dvander@868
   260
			{
dvander@868
   261
				m_pDefault = FindOrLoadDriver(m_DefDriver.c_str());
dvander@868
   262
			}
dvander@869
   263
			dname = m_DefDriver.size() ? m_DefDriver.c_str() : "default";
dvander@868
   264
			pInfo->realDriver = m_pDefault;
dvander@868
   265
		} else {
dvander@868
   266
			pInfo->realDriver = FindOrLoadDriver(pInfo->info.driver);
dvander@868
   267
		}
dvander@868
   268
	}
dvander@868
   269
dvander@868
   270
	if (pInfo->realDriver)
dvander@868
   271
	{
dvander@868
   272
		if (pdr)
dvander@868
   273
		{
dvander@868
   274
			*pdr = pInfo->realDriver;
dvander@868
   275
		}
dvander@868
   276
		*pdb = pInfo->realDriver->Connect(&pInfo->info, persistent, error, maxlength);
dvander@868
   277
		return (*pdb != NULL);
dvander@868
   278
	}
dvander@868
   279
dvander@868
   280
	if (pdr)
dvander@868
   281
	{
dvander@868
   282
		*pdr = NULL;
dvander@868
   283
	}
dvander@666
   284
	*pdb = NULL;
dvander@666
   285
dvander@869
   286
	UTIL_Format(error, maxlength, "Driver \"%s\" not found", dname);
dvander@868
   287
dvander@666
   288
	return false;
dvander@666
   289
}
dvander@858
   290
dvander@858
   291
void DBManager::AddDriver(IDBDriver *pDriver)
dvander@858
   292
{
dvander@1096
   293
	 /* Let's kill the worker.  Join the thread and let the queries flush.
dvander@1096
   294
	  * This is kind of stupid but we just want to unload safely.
dvander@1096
   295
	  * Rather than recreate the worker, we'll wait until someone throws 
dvander@1096
   296
	  * another query through.
dvander@1096
   297
	  */
dvander@1096
   298
	KillWorkerThread();
dvander@1096
   299
dvander@858
   300
	 m_drivers.push_back(pDriver);
dvander@858
   301
}
dvander@858
   302
dvander@858
   303
void DBManager::RemoveDriver(IDBDriver *pDriver)
dvander@858
   304
{
dvander@1096
   305
	/* Again, we're forced to kill the worker.  How rude!
dvander@1096
   306
	 * Doing this flushes the queue, and thus we don't need to 
dvander@1096
   307
	 * clean anything else.  
dvander@1096
   308
	 */
dvander@1096
   309
	KillWorkerThread();
dvander@1096
   310
dvander@858
   311
	for (size_t i=0; i<m_drivers.size(); i++)
dvander@858
   312
	{
dvander@858
   313
		if (m_drivers[i] == pDriver)
dvander@858
   314
		{
dvander@858
   315
			m_drivers.erase(m_drivers.iterAt(i));
dvander@858
   316
			return;
dvander@858
   317
		}
dvander@858
   318
	}
dvander@868
   319
dvander@868
   320
	/* Make sure NOTHING references this! */
dvander@868
   321
	List<ConfDbInfo>::iterator iter;
dvander@868
   322
	for (iter=m_confs.begin(); iter!=m_confs.end(); iter++)
dvander@868
   323
	{
dvander@868
   324
		ConfDbInfo &db = (*iter);
dvander@868
   325
		if (db.realDriver == pDriver)
dvander@868
   326
		{
dvander@868
   327
			db.realDriver = NULL;
dvander@868
   328
		}
dvander@868
   329
	}
dvander@1096
   330
dvander@1096
   331
	/* Now that the driver is gone, we have to test the think queue.
dvander@1096
   332
	 * Whatever happens therein is up to the db op!
dvander@1096
   333
	 */
dvander@1096
   334
	Queue<IDBThreadOperation *>::iterator qiter = m_ThinkQueue.begin();
dvander@1096
   335
	Queue<IDBThreadOperation *> templist;
dvander@1096
   336
	while (qiter != m_ThinkQueue.end())
dvander@1096
   337
	{
dvander@1096
   338
		IDBThreadOperation *op = (*qiter);
dvander@1096
   339
		if (op->GetDriver() == pDriver)
dvander@1096
   340
		{
dvander@1096
   341
			templist.push(op);
dvander@1096
   342
			qiter = m_ThinkQueue.erase(qiter);
dvander@1096
   343
		} else {
dvander@1096
   344
			qiter++;
dvander@1096
   345
		}
dvander@1096
   346
	}
dvander@1096
   347
dvander@1096
   348
	for (qiter = templist.begin();
dvander@1096
   349
		 qiter != templist.end();
dvander@1096
   350
		 qiter++)
dvander@1096
   351
	{
dvander@1096
   352
		IDBThreadOperation *op = (*qiter);
dvander@1096
   353
		op->CancelThinkPart();
dvander@1096
   354
	}
dvander@868
   355
}
dvander@868
   356
dvander@868
   357
IDBDriver *DBManager::GetDefaultDriver()
dvander@868
   358
{
dvander@868
   359
	if (!m_pDefault && m_DefDriver.size() > 0)
dvander@868
   360
	{
dvander@868
   361
		m_pDefault = FindOrLoadDriver(m_DefDriver.c_str());
dvander@868
   362
	}
dvander@868
   363
dvander@868
   364
	return m_pDefault;
dvander@858
   365
}
dvander@858
   366
dvander@858
   367
Handle_t DBManager::CreateHandle(DBHandleType dtype, void *ptr, IdentityToken_t *pToken)
dvander@858
   368
{
dvander@858
   369
	HandleType_t type = 0;
dvander@858
   370
dvander@858
   371
	if (dtype == DBHandle_Driver)
dvander@858
   372
	{
dvander@858
   373
		type = m_DriverType;
dvander@858
   374
	} else if (dtype == DBHandle_Database) {
dvander@858
   375
		type = m_DatabaseType;
dvander@858
   376
	} else {
dvander@858
   377
		return BAD_HANDLE;
dvander@858
   378
	}
dvander@858
   379
dvander@858
   380
	return g_HandleSys.CreateHandle(type, ptr, pToken, g_pCoreIdent, NULL);
dvander@858
   381
}
dvander@858
   382
dvander@858
   383
HandleError DBManager::ReadHandle(Handle_t hndl, DBHandleType dtype, void **ptr)
dvander@858
   384
{
dvander@858
   385
	HandleType_t type = 0;
dvander@858
   386
dvander@858
   387
	if (dtype == DBHandle_Driver)
dvander@858
   388
	{
dvander@858
   389
		type = m_DriverType;
dvander@858
   390
	} else if (dtype == DBHandle_Database) {
dvander@858
   391
		type = m_DatabaseType;
dvander@858
   392
	} else {
dvander@858
   393
		return HandleError_Type;
dvander@858
   394
	}
dvander@858
   395
dvander@858
   396
	HandleSecurity sec(NULL, g_pCoreIdent);
dvander@858
   397
dvander@869
   398
	return g_HandleSys.ReadHandle(hndl, type, &sec, ptr);
dvander@858
   399
}
dvander@858
   400
dvander@858
   401
HandleError DBManager::ReleaseHandle(Handle_t hndl, DBHandleType type, IdentityToken_t *token)
dvander@858
   402
{
dvander@858
   403
	HandleSecurity sec(token, g_pCoreIdent);
dvander@858
   404
	return g_HandleSys.FreeHandle(hndl, &sec);
dvander@858
   405
}
dvander@858
   406
dvander@858
   407
unsigned int DBManager::GetDriverCount()
dvander@858
   408
{
dvander@858
   409
	return (unsigned int)m_drivers.size();
dvander@858
   410
}
dvander@858
   411
dvander@858
   412
IDBDriver *DBManager::GetDriver(unsigned int index)
dvander@858
   413
{
dvander@858
   414
	if (index >= m_drivers.size())
dvander@858
   415
	{
dvander@858
   416
		return NULL;
dvander@858
   417
	}
dvander@858
   418
dvander@858
   419
	return m_drivers[index];
dvander@858
   420
}
dvander@858
   421
dvander@858
   422
const DatabaseInfo *DBManager::FindDatabaseConf(const char *name)
dvander@858
   423
{
dvander@868
   424
	ConfDbInfo *info = GetDatabaseConf(name);
dvander@868
   425
	if (!info)
dvander@868
   426
	{
dvander@868
   427
		return NULL;
dvander@868
   428
	}
dvander@868
   429
dvander@868
   430
	return &info->info;
dvander@868
   431
}
dvander@868
   432
dvander@868
   433
ConfDbInfo *DBManager::GetDatabaseConf(const char *name)
dvander@868
   434
{
dvander@868
   435
	List<ConfDbInfo>::iterator iter;
dvander@868
   436
dvander@868
   437
	for (iter=m_confs.begin(); iter!=m_confs.end(); iter++)
dvander@868
   438
	{
dvander@868
   439
		ConfDbInfo &conf = (*iter);
dvander@868
   440
		if (strcmp(m_StrTab.GetString(conf.name), name) == 0)
dvander@868
   441
		{
dvander@868
   442
			return &conf;
dvander@868
   443
		}
dvander@868
   444
	}
dvander@868
   445
dvander@858
   446
	return NULL;
dvander@858
   447
}
dvander@868
   448
dvander@868
   449
IDBDriver *DBManager::FindOrLoadDriver(const char *name)
dvander@868
   450
{
dvander@868
   451
	size_t last_size = m_drivers.size();
dvander@868
   452
	for (size_t i=0; i<last_size; i++)
dvander@868
   453
	{
dvander@868
   454
		if (strcmp(m_drivers[i]->GetIdentifier(), name) == 0)
dvander@868
   455
		{
dvander@868
   456
			return m_drivers[i];
dvander@868
   457
		}
dvander@868
   458
	}
dvander@868
   459
dvander@868
   460
	char filename[PLATFORM_MAX_PATH];
dvander@869
   461
	UTIL_Format(filename, sizeof(filename), "dbi.%s.ext", name);
dvander@868
   462
dvander@868
   463
	IExtension *pExt = g_Extensions.LoadAutoExtension(filename);
dvander@868
   464
	if (!pExt || !pExt->IsLoaded() || m_drivers.size() <= last_size)
dvander@868
   465
	{
dvander@868
   466
		return NULL;
dvander@868
   467
	}
dvander@868
   468
dvander@868
   469
	/* last_size is now gauranteed to be a valid index.
dvander@868
   470
	 * The identifier must match the name.
dvander@868
   471
	 */
dvander@868
   472
	if (strcmp(m_drivers[last_size]->GetIdentifier(), name) == 0)
dvander@868
   473
	{
dvander@868
   474
		return m_drivers[last_size];
dvander@868
   475
	}
dvander@868
   476
dvander@868
   477
	return NULL;
dvander@868
   478
}
dvander@1096
   479
dvander@1096
   480
void DBManager::KillWorkerThread()
dvander@1096
   481
{
dvander@1096
   482
	if (m_pWorker)
dvander@1096
   483
	{
dvander@1096
   484
		m_pWorker->Stop(false);
dvander@1096
   485
		g_pThreader->DestroyWorker(m_pWorker);
dvander@1096
   486
		m_pWorker = NULL;
dvander@1096
   487
		s_OneTimeThreaderErrorMsg = false;
dvander@1096
   488
	}
dvander@1096
   489
}
dvander@1096
   490
dvander@1096
   491
bool DBManager::AddToThreadQueue(IDBThreadOperation *op, PrioQueueLevel prio)
dvander@1096
   492
{
dvander@1096
   493
	if (!m_pWorker)
dvander@1096
   494
	{
dvander@1096
   495
		m_pWorker = g_pThreader->MakeWorker(this, true);
dvander@1096
   496
		if (!m_pWorker)
dvander@1096
   497
		{
dvander@1096
   498
			if (!s_OneTimeThreaderErrorMsg)
dvander@1096
   499
			{
dvander@1096
   500
				g_Logger.LogError("[SM] Unable to create db threader (error unknown)");
dvander@1096
   501
				s_OneTimeThreaderErrorMsg = true;
dvander@1096
   502
			}
dvander@1096
   503
			return false;
dvander@1096
   504
		}
dvander@1096
   505
		if (!m_pWorker->Start())
dvander@1096
   506
		{
dvander@1096
   507
			if (!s_OneTimeThreaderErrorMsg)
dvander@1096
   508
			{
dvander@1096
   509
				g_Logger.LogError("[SM] Unable to start db threader (error unknown)");
dvander@1096
   510
				s_OneTimeThreaderErrorMsg = true;
dvander@1096
   511
			}
dvander@1096
   512
			g_pThreader->DestroyWorker(m_pWorker);
dvander@1096
   513
			m_pWorker = NULL;
dvander@1096
   514
			return false;
dvander@1096
   515
		}
dvander@1096
   516
	}
dvander@1096
   517
dvander@1096
   518
	/* Add to the queue */
dvander@1096
   519
	{
dvander@1096
   520
		m_pQueueLock->Lock();
dvander@1096
   521
		Queue<IDBThreadOperation *> &queue = m_OpQueue.GetQueue(prio);
dvander@1096
   522
		queue.push(op);
dvander@1096
   523
		m_pQueueLock->Unlock();
dvander@1096
   524
	}
dvander@1096
   525
dvander@1096
   526
	/* Make the thread */
dvander@1096
   527
	m_pWorker->MakeThread(this);
dvander@1096
   528
dvander@1096
   529
	return true;
dvander@1096
   530
}
dvander@1096
   531
dvander@1096
   532
void DBManager::OnWorkerStart(IThreadWorker *pWorker)
dvander@1096
   533
{
dvander@1096
   534
	m_drSafety.clear();
dvander@1096
   535
	for (size_t i=0; i<m_drivers.size(); i++)
dvander@1096
   536
	{
dvander@1096
   537
		if (m_drivers[i]->IsThreadSafe())
dvander@1096
   538
		{
dvander@1096
   539
			m_drSafety.push_back(m_drivers[i]->InitializeThreadSafety());
dvander@1096
   540
		} else {
dvander@1096
   541
			m_drSafety.push_back(false);
dvander@1096
   542
		}
dvander@1096
   543
	}
dvander@1096
   544
}
dvander@1096
   545
dvander@1096
   546
void DBManager::OnWorkerStop(IThreadWorker *pWorker)
dvander@1096
   547
{
dvander@1096
   548
	for (size_t i=0; i<m_drivers.size(); i++)
dvander@1096
   549
	{
dvander@1096
   550
		if (m_drSafety[i])
dvander@1096
   551
		{
dvander@1096
   552
			m_drivers[i]->ShutdownThreadSafety();
dvander@1096
   553
		}
dvander@1096
   554
	}
dvander@1096
   555
	m_drSafety.clear();
dvander@1096
   556
}
dvander@1096
   557
dvander@1096
   558
void DBManager::RunThread(IThreadHandle *pThread)
dvander@1096
   559
{
dvander@1096
   560
	IDBThreadOperation *op = NULL;
dvander@1096
   561
dvander@1096
   562
	/* Get something from the queue */
dvander@1096
   563
	{
dvander@1096
   564
		m_pQueueLock->Lock();
dvander@1096
   565
		Queue<IDBThreadOperation *> &queue = m_OpQueue.GetLikelyQueue();
dvander@1096
   566
		if (!queue.empty())
dvander@1096
   567
		{
dvander@1096
   568
			op = queue.first();
dvander@1096
   569
			queue.pop();
dvander@1096
   570
		}
dvander@1096
   571
		m_pQueueLock->Unlock();
dvander@1096
   572
	}
dvander@1096
   573
dvander@1096
   574
	/* whoa.  hi.  did we get something? we should have. */
dvander@1096
   575
	if (!op)
dvander@1096
   576
	{
dvander@1096
   577
		/* wtf? */
dvander@1096
   578
		return;
dvander@1096
   579
	}
dvander@1096
   580
dvander@1096
   581
	op->RunThreadPart();
dvander@1096
   582
dvander@1096
   583
	m_pThinkLock->Lock();
dvander@1096
   584
	m_ThinkQueue.push(op);
dvander@1096
   585
	m_pThinkLock->Unlock();
dvander@1096
   586
}
dvander@1096
   587
dvander@1096
   588
void DBManager::RunFrame()
dvander@1096
   589
{
dvander@1096
   590
	/* Don't bother if we're empty */
dvander@1096
   591
	if (!m_ThinkQueue.size())
dvander@1096
   592
	{
dvander@1096
   593
		return;
dvander@1096
   594
	}
dvander@1096
   595
dvander@1096
   596
	/* Dump one thing per-frame so the server stays sane. */
dvander@1096
   597
	m_pThinkLock->Lock();
dvander@1096
   598
	IDBThreadOperation *op = m_ThinkQueue.first();
dvander@1096
   599
	m_ThinkQueue.pop();
dvander@1096
   600
	m_pThinkLock->Unlock();
dvander@1096
   601
	op->RunThinkPart();
dvander@1096
   602
}
dvander@1096
   603
dvander@1096
   604
void DBManager::OnTerminate(IThreadHandle *pThread, bool cancel)
dvander@1096
   605
{
dvander@1096
   606
	/* Do nothing */
dvander@1096
   607
}
dvander@1096
   608
dvander@1096
   609
void DBManager::OnPluginUnloaded(IPlugin *plugin)
dvander@1096
   610
{
dvander@1096
   611
	/* Kill the thread so we can flush everything into the think queue... */
dvander@1096
   612
	KillWorkerThread();
dvander@1096
   613
dvander@1096
   614
	/* Mark the plugin as being unloaded so future database calls will ignore threading... */
dvander@1096
   615
	plugin->SetProperty("DisallowDBThreads", NULL);
dvander@1096
   616
dvander@1096
   617
	/* Run all of the think operations.
dvander@1096
   618
	 * Unlike the driver unloading example, we'll let these calls go through, 
dvander@1096
   619
	 * since a plugin unloading is far more normal.
dvander@1096
   620
	 */
dvander@1096
   621
	Queue<IDBThreadOperation *>::iterator iter = m_ThinkQueue.begin();
dvander@1096
   622
	Queue<IDBThreadOperation *> templist;
dvander@1096
   623
	while (iter != m_ThinkQueue.end())
dvander@1096
   624
	{
dvander@1096
   625
		IDBThreadOperation *op = (*iter);
dvander@1096
   626
		if (op->GetPlugin() == plugin)
dvander@1096
   627
		{
dvander@1096
   628
			templist.push(op);
dvander@1096
   629
			iter = m_ThinkQueue.erase(iter);
dvander@1096
   630
		} else {
dvander@1096
   631
			iter++;
dvander@1096
   632
		}
dvander@1096
   633
	}
dvander@1096
   634
dvander@1096
   635
	for (iter = templist.begin();
dvander@1096
   636
		 iter != templist.end();
dvander@1096
   637
		 iter++)
dvander@1096
   638
	{
dvander@1096
   639
		IDBThreadOperation *op = (*iter);
dvander@1096
   640
		op->RunThinkPart();
dvander@1096
   641
	}
dvander@1096
   642
}
dvander@1096
   643
dvander@1096
   644
void DBManager::LockConfig()
dvander@1096
   645
{
dvander@1096
   646
	m_pConfigLock->Lock();
dvander@1096
   647
}
dvander@1096
   648
dvander@1096
   649
void DBManager::UnlockConfig()
dvander@1096
   650
{
dvander@1096
   651
	m_pConfigLock->Unlock();
dvander@1096
   652
}
dvander@1096
   653
dvander@1096
   654
const char *DBManager::GetDefaultDriverName()
dvander@1096
   655
{
dvander@1096
   656
	return m_DefDriver.c_str();
dvander@1096
   657
}