Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

429 lines
9.4 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. odbcpool.cxx
  5. Abstract:
  6. Provides simple ODBC connection pooling for IDC. The only keys
  7. used for the connection pooling is the datasource name, the
  8. username and password. ODBC options and other connection state
  9. are not taken into consideration.
  10. Author:
  11. John Ludeman (johnl) 01-Apr-1996
  12. Revision History:
  13. --*/
  14. #include "precomp.hxx"
  15. //
  16. // Globals
  17. //
  18. CRITICAL_SECTION g_csPoolLock;
  19. LIST_ENTRY g_PoolList;
  20. DWORD g_dwTimeoutID = 0;
  21. //
  22. // Various counters
  23. //
  24. DWORD g_cFree;
  25. DWORD g_cUsed;
  26. ALLOC_CACHE_HANDLER * ODBC_CONN_POOL::sm_pachOdbcConnPools;
  27. //static
  28. HRESULT
  29. ODBC_CONN_POOL::Initialize(
  30. VOID
  31. )
  32. /*++
  33. Routine Description:
  34. Initialize ODBC_CONN_POOL lookaside
  35. Arguments:
  36. None
  37. Return Value:
  38. HRESULT
  39. --*/
  40. {
  41. ALLOC_CACHE_CONFIGURATION acConfig;
  42. acConfig.nConcurrency = 1;
  43. acConfig.nThreshold = 100;
  44. acConfig.cbSize = sizeof( ODBC_CONN_POOL );
  45. DBG_ASSERT( sm_pachOdbcConnPools == NULL );
  46. sm_pachOdbcConnPools = new ALLOC_CACHE_HANDLER( "ODBC_CONN_POOL",
  47. &acConfig );
  48. if ( sm_pachOdbcConnPools == NULL )
  49. {
  50. return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  51. }
  52. return NO_ERROR;
  53. }
  54. //static
  55. VOID
  56. ODBC_CONN_POOL::Terminate(
  57. VOID
  58. )
  59. /*++
  60. Routine Description:
  61. Terminate ODBC_CONN_POOL lookaside
  62. Arguments:
  63. None
  64. Return Value:
  65. None
  66. --*/
  67. {
  68. if ( sm_pachOdbcConnPools != NULL )
  69. {
  70. delete sm_pachOdbcConnPools;
  71. sm_pachOdbcConnPools = NULL;
  72. }
  73. }
  74. VOID
  75. WINAPI
  76. IDCPoolScavenger(
  77. PVOID pContext
  78. );
  79. BOOL
  80. InitializeOdbcPool(
  81. VOID
  82. )
  83. {
  84. InitializeListHead( &g_PoolList );
  85. INITIALIZE_CRITICAL_SECTION( &g_csPoolLock );
  86. //
  87. // Kick off the pool scavenger
  88. //
  89. g_dwTimeoutID = ScheduleWorkItem( IDCPoolScavenger,
  90. NULL,
  91. IDC_POOL_TIMEOUT * 1000,
  92. TRUE );
  93. return TRUE;
  94. }
  95. VOID
  96. TerminateOdbcPool(
  97. VOID
  98. )
  99. {
  100. ODBC_CONN_POOL * pOCPool;
  101. if ( g_dwTimeoutID )
  102. {
  103. RemoveWorkItem( g_dwTimeoutID );
  104. g_dwTimeoutID = 0;
  105. }
  106. EnterCriticalSection( &g_csPoolLock );
  107. while ( !IsListEmpty( &g_PoolList ))
  108. {
  109. LIST_ENTRY * pEntry = g_PoolList.Flink;
  110. RemoveEntryList( pEntry );
  111. pOCPool = CONTAINING_RECORD( pEntry,
  112. ODBC_CONN_POOL,
  113. m_ListEntry );
  114. delete pOCPool;
  115. pOCPool = NULL;
  116. }
  117. LeaveCriticalSection( &g_csPoolLock );
  118. DeleteCriticalSection( &g_csPoolLock );
  119. }
  120. HRESULT
  121. OpenConnection(
  122. IN ODBC_CONNECTION * podbcconnNonPooled,
  123. OUT ODBC_CONNECTION * * ppodbcconnToUse,
  124. IN DWORD csecPoolTimeout,
  125. IN const CHAR * pszDataSource,
  126. IN const CHAR * pszUsername,
  127. IN const CHAR * pszPassword,
  128. IN const CHAR * pszLoggedOnUser
  129. )
  130. /*++
  131. Routine Description:
  132. This function opens an odbc connection, optionally from a pool of
  133. ODBC connections.
  134. Arguments:
  135. podbcconnNonPooled - If pooling wasn't requested or the open
  136. failed, we use this odbc connection object
  137. ppodbcconnToUse - Receives pointer to either a pooled ODBC
  138. connection object or podbcconnNonPooled if a
  139. pooled object couldn't be used
  140. csecPoolTimeout - Amount of time to pool a connection, 0 to not
  141. pool
  142. pszDataSource - ODBC Datasource
  143. pszUsername - Username for datasource access
  144. pszPassword - Password for use with this username
  145. pszLoggedOnUser - The NT account this user is running under
  146. Return Value:
  147. HRESULT
  148. ppodbcconnToUse will be set to the ODBC connection to use for the
  149. request
  150. --*/
  151. {
  152. LIST_ENTRY * pEntry;
  153. ODBC_CONN_POOL * pOCPool;
  154. HRESULT hr;
  155. //
  156. // Don't pool this connection if it wasn't requested
  157. //
  158. if ( !csecPoolTimeout )
  159. {
  160. *ppodbcconnToUse = podbcconnNonPooled;
  161. return podbcconnNonPooled->Open( pszDataSource,
  162. pszUsername,
  163. pszPassword );
  164. }
  165. //
  166. // Look in the pool cache for an existing connection
  167. //
  168. EnterCriticalSection( &g_csPoolLock );
  169. for ( pEntry = g_PoolList.Flink;
  170. pEntry != &g_PoolList;
  171. pEntry = pEntry->Flink )
  172. {
  173. pOCPool = CONTAINING_RECORD( pEntry,
  174. ODBC_CONN_POOL,
  175. m_ListEntry );
  176. if ( pOCPool->IsFree() &&
  177. !lstrcmpiA( pOCPool->QueryDataSource(),
  178. pszDataSource ) &&
  179. !lstrcmpiA( pOCPool->QueryUsername(),
  180. pszUsername ) &&
  181. !lstrcmpiA( pOCPool->QueryLoggedOnUser(),
  182. pszLoggedOnUser ) &&
  183. !strcmp( pOCPool->QueryPassword(),
  184. pszPassword ))
  185. {
  186. //
  187. // We have a match
  188. //
  189. pOCPool->MarkAsUsed();
  190. *ppodbcconnToUse = pOCPool->QueryOdbcConnection();
  191. pOCPool->SetTTL( csecPoolTimeout );
  192. LeaveCriticalSection( &g_csPoolLock );
  193. return S_OK;
  194. }
  195. }
  196. LeaveCriticalSection( &g_csPoolLock );
  197. //
  198. // Allocate a new connection pool and if we connect successfully,
  199. // put it in the pool list
  200. //
  201. pOCPool = new ODBC_CONN_POOL();
  202. if( pOCPool == NULL )
  203. {
  204. return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  205. }
  206. hr = pOCPool->Create( pszDataSource,
  207. pszUsername,
  208. pszPassword,
  209. pszLoggedOnUser );
  210. if( FAILED( hr ) )
  211. {
  212. DBGPRINTF(( DBG_CONTEXT,
  213. "Error creating pool connection, hr = 0x%x.\n",
  214. hr ));
  215. return hr;
  216. }
  217. if ( FAILED( pOCPool->Open() ) )
  218. {
  219. delete pOCPool;
  220. pOCPool = NULL;
  221. *ppodbcconnToUse = podbcconnNonPooled;
  222. return podbcconnNonPooled->Open( pszDataSource,
  223. pszUsername,
  224. pszPassword );
  225. }
  226. *ppodbcconnToUse = pOCPool->QueryOdbcConnection();
  227. EnterCriticalSection( &g_csPoolLock );
  228. //
  229. // Account for the new pool item but we have to do it
  230. // with in the critical section
  231. //
  232. g_cFree++;
  233. pOCPool->MarkAsUsed();
  234. pOCPool->SetTTL( csecPoolTimeout );
  235. InsertHeadList( &g_PoolList, &pOCPool->m_ListEntry );
  236. LeaveCriticalSection( &g_csPoolLock );
  237. return S_OK;
  238. }
  239. VOID
  240. CloseConnection(
  241. IN ODBC_CONNECTION * podbcconnPooled,
  242. IN BOOL fDelete
  243. )
  244. /*++
  245. Routine Description:
  246. This routine frees an ODBC connection back to the pool,
  247. optionally deleting it
  248. Arguments:
  249. podbcconnPooled - ODBC connection that is pooled, can be NULL
  250. fDelete - TRUE if the item should be delete rather then returned
  251. to the pool
  252. --*/
  253. {
  254. LIST_ENTRY * pEntry;
  255. ODBC_CONN_POOL * pOCPool;
  256. if ( !podbcconnPooled )
  257. {
  258. return;
  259. }
  260. //
  261. // Look in the pool list to mark it as free
  262. //
  263. EnterCriticalSection( &g_csPoolLock );
  264. for ( pEntry = g_PoolList.Flink;
  265. pEntry != &g_PoolList;
  266. pEntry = pEntry->Flink )
  267. {
  268. pOCPool = CONTAINING_RECORD( pEntry,
  269. ODBC_CONN_POOL,
  270. m_ListEntry );
  271. if ( podbcconnPooled == pOCPool->QueryOdbcConnection() )
  272. {
  273. pOCPool->MarkAsFree();
  274. if ( fDelete )
  275. {
  276. RemoveEntryList( pEntry );
  277. g_cFree--;
  278. delete pOCPool;
  279. pOCPool = NULL;
  280. }
  281. break;
  282. }
  283. }
  284. LeaveCriticalSection( &g_csPoolLock );
  285. }
  286. VOID
  287. WINAPI
  288. IDCPoolScavenger(
  289. PVOID pContext
  290. )
  291. /*++
  292. Routine Description:
  293. Walks the list of pooled connections and removes any that have
  294. timed out
  295. --*/
  296. {
  297. LIST_ENTRY * pEntry;
  298. LIST_ENTRY * pNext;
  299. ODBC_CONN_POOL * pOCPool;
  300. //
  301. // Look through the list and remove any old items
  302. //
  303. EnterCriticalSection( &g_csPoolLock );
  304. for ( pEntry = g_PoolList.Flink;
  305. pEntry != &g_PoolList;
  306. pEntry = pNext )
  307. {
  308. pNext = pEntry->Flink;
  309. pOCPool = CONTAINING_RECORD( pEntry,
  310. ODBC_CONN_POOL,
  311. m_ListEntry );
  312. if ( pOCPool->IsFree() && !pOCPool->DecrementTTL() )
  313. {
  314. RemoveEntryList( pEntry );
  315. g_cFree--;
  316. delete pOCPool;
  317. pOCPool = NULL;
  318. }
  319. }
  320. LeaveCriticalSection( &g_csPoolLock );
  321. }