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.

413 lines
10 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name :
  4. retrq.cxx
  5. Abstract:
  6. Implements the Retry queue
  7. Author:
  8. Nimish Khanolkar ( NimishK ) 11-Dec-1995
  9. Project:
  10. CRETRY_Q sink
  11. Functions Exported:
  12. Revision History:
  13. --*/
  14. /************************************************************
  15. * Include Headers
  16. ************************************************************/
  17. #include "precomp.h"
  18. //////////////////////////////////////////////////////////////////////////////
  19. //
  20. // Name :
  21. // CRETRY_Q::InitializeQueue
  22. //
  23. // Description:
  24. // This function initializes the class
  25. //
  26. //////////////////////////////////////////////////////////////////////////////
  27. //
  28. HRESULT CRETRY_Q::Initialize(void)
  29. {
  30. TraceFunctEnterEx((LPARAM)this, "CRETRY_Q::InitializeQueue");
  31. //Init the heaad of the queue
  32. InitializeListHead(&m_QHead);
  33. //Init or critical section. This protects the queue and the hash table
  34. InitializeCriticalSection(&m_CritSec);
  35. m_fCritSecInit = TRUE;
  36. TraceFunctLeaveEx((LPARAM)this);
  37. return S_OK;
  38. }
  39. //////////////////////////////////////////////////////////////////////////////
  40. //
  41. // Name :
  42. // CRETRY_Q::CreateQueue
  43. //
  44. // Description:
  45. // This is the static member function that creates the Queue
  46. //
  47. //
  48. ////////////////////////////////////////////////////////////////////////////////
  49. CRETRY_Q * CRETRY_Q::CreateQueue()
  50. {
  51. HRESULT hr;
  52. CRETRY_Q * pRQueue = NULL;
  53. pRQueue = new CRETRY_Q();
  54. if(!pRQueue)
  55. {
  56. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  57. return(NULL);
  58. }
  59. //initialize the queue
  60. hr = pRQueue->Initialize();
  61. if(FAILED(hr))
  62. {
  63. delete pRQueue;
  64. pRQueue = NULL;
  65. }
  66. return pRQueue;
  67. }
  68. /////////////////////////////////////////////////////////////////////////////////
  69. // CRETRY_HASH_TABLE::DeInitialize
  70. //
  71. // Very Basic.
  72. //
  73. /////////////////////////////////////////////////////////////////////////////////
  74. HRESULT CRETRY_Q::DeInitialize(void)
  75. {
  76. PLIST_ENTRY plEntry = NULL;
  77. CRETRY_HASH_ENTRY * pHashEntry = NULL;
  78. //Release all the objects in the queue
  79. // 10/1/98 - MikeSwa
  80. while(!IsListEmpty(&m_QHead))
  81. {
  82. plEntry = RemoveHeadList (&m_QHead);
  83. pHashEntry = CONTAINING_RECORD(plEntry, CRETRY_HASH_ENTRY, m_QLEntry);
  84. pHashEntry->ClearInQ();
  85. //Execute callback on shutdown, so caller can free memory
  86. if (pHashEntry->IsCallback())
  87. pHashEntry->ExecCallback();
  88. pHashEntry->DecRefCount();
  89. }
  90. if (m_fCritSecInit)
  91. DeleteCriticalSection(&m_CritSec);
  92. delete this;
  93. return S_OK;
  94. }
  95. ///////////////////////////////////////////////////////////////////////
  96. //
  97. // Name :
  98. // CRETRY_Q::InsertSortedIntoQueue
  99. //
  100. // Description:
  101. // It takes the list entry for the new RETRY_HASH_ENTRY
  102. // and adds it in the right order based on the Retry time
  103. // for that entry.
  104. // UnLocked operation. The caller has to have the lock
  105. //
  106. // Arguments:
  107. //
  108. // Returns:
  109. //
  110. ///////////////////////////////////////////////////////////////////////
  111. void CRETRY_Q::InsertSortedIntoQueue(PRETRY_HASH_ENTRY pHashEntry,
  112. BOOL *fTopOfQueue )
  113. {
  114. PLIST_ENTRY pCurrentListEntry;
  115. FILETIME CurrentRetryTime;
  116. FILETIME NewRetryTime;
  117. PRETRY_HASH_ENTRY pCurrentHashEntry;
  118. TraceFunctEnterEx((LPARAM)this, "CRETRY_Q::InsertSortedEntry");
  119. *fTopOfQueue = FALSE;
  120. //Initialize
  121. pCurrentListEntry = &m_QHead;
  122. //Look at the next entry to see if we are not at the end of the queue
  123. while(pCurrentListEntry->Flink != &m_QHead)
  124. {
  125. //Get the object pointed by the next entry
  126. pCurrentHashEntry = CONTAINING_RECORD( pCurrentListEntry->Flink,
  127. CRETRY_HASH_ENTRY, m_QLEntry);
  128. CurrentRetryTime = pCurrentHashEntry->GetRetryTime();
  129. NewRetryTime = pHashEntry->GetRetryTime();
  130. //If the new entry has more delay we continue finding a place for it
  131. if(CompareFileTime (&CurrentRetryTime, &NewRetryTime) == -1)
  132. {
  133. pCurrentListEntry = pCurrentListEntry->Flink;
  134. continue;
  135. }
  136. else
  137. { //We found the place
  138. break;
  139. }
  140. }
  141. //insert before the next entry
  142. InsertHeadList(pCurrentListEntry, &pHashEntry->QueryQListEntry());
  143. //set inQ flag
  144. pHashEntry->SetInQ();
  145. pHashEntry->IncRefCount();
  146. if(m_QHead.Flink == &pHashEntry->QueryQListEntry())
  147. *fTopOfQueue = TRUE;
  148. TraceFunctLeaveEx((LPARAM)this);
  149. return;
  150. }
  151. /////////////////////////////////////////////////////////////////////////////////
  152. //
  153. // Name :
  154. // CRETRY_Q::CanRETRYHeadEntry
  155. //
  156. // We look at the entry at the top of the queue
  157. // If it is something that we can retry right now, we remove it from the
  158. // queue and return it to the caller
  159. //
  160. ///////////////////////////////////////////////////////////////////////////////////
  161. //
  162. BOOL CRETRY_Q::CanRETRYHeadEntry(PRETRY_HASH_ENTRY* ppRHEntry,
  163. DWORD* pdwDelay)
  164. {
  165. FILETIME TimeNow; //the time now
  166. FILETIME RetryTime; //time connection should be retried
  167. TraceFunctEnterEx((LPARAM)this, "CRETRY_Q::CanPopHead");
  168. //get the current time
  169. GetSystemTimeAsFileTime(&TimeNow);
  170. //Lock the queue
  171. LockQ();
  172. _ASSERT(m_QHead.Flink);
  173. //Look at the next entry to see if we are not at the end of the queue
  174. if(m_QHead.Flink != &m_QHead)
  175. {
  176. //Get the object pointed by the next entry
  177. *ppRHEntry = CONTAINING_RECORD( m_QHead.Flink, CRETRY_HASH_ENTRY, m_QLEntry);
  178. RetryTime = (*ppRHEntry)->GetRetryTime();
  179. //If the Current time is less than the retry time
  180. // and the time difference is greater than 1 sec then go back to waiting
  181. //else remove the entry
  182. if( (CompareFileTime (&TimeNow, &RetryTime) == -1) &&
  183. (*pdwDelay = ((DWORD)SecFromFtSpan(TimeNow, RetryTime) * 1000)))
  184. {
  185. //We cannnot POP this entry as it is not yet release
  186. _ASSERT(*pdwDelay > 0);
  187. *ppRHEntry = NULL;
  188. //Unlock the queue
  189. UnLockQ();
  190. TraceFunctLeaveEx((LPARAM)this);
  191. return FALSE;
  192. } //end of while
  193. else
  194. {
  195. //We can pop this entry from our retry queue
  196. RemoveEntryList(m_QHead.Flink);
  197. (*ppRHEntry)->ClearInQ();
  198. *pdwDelay = 0;
  199. //Unlock the queue
  200. UnLockQ();
  201. TraceFunctLeaveEx((LPARAM)this);
  202. return TRUE;
  203. }
  204. }
  205. else
  206. {
  207. //Unlock the queue
  208. UnLockQ();
  209. //There is no entry in the queue so go to sleep indefintely.
  210. *ppRHEntry = NULL;
  211. //get the delay to sleep
  212. *pdwDelay = INFINITE;
  213. TraceFunctLeaveEx((LPARAM)this);
  214. return FALSE;
  215. }
  216. }
  217. ////////////////////////////////////////////////////////////////////////////////
  218. //
  219. // CRETRY_Q::RemoveFromQueue(PLISTENTRY pEntry)
  220. //
  221. // This function removes an entry into the queue
  222. //
  223. // Arguments:
  224. //
  225. // none
  226. //
  227. /////////////////////////////////////////////////////////////////////////////////
  228. //
  229. BOOL CRETRY_Q::RemoveFromQueue(PRETRY_HASH_ENTRY pRHEntry)
  230. {
  231. TraceFunctEnterEx((LPARAM)this, "CRETRY_Q::RemoveFromQueue");
  232. _ASSERT( pRHEntry != NULL);
  233. if(pRHEntry == NULL || &pRHEntry->QueryQListEntry() == NULL)
  234. {
  235. TraceFunctLeaveEx((LPARAM)this);
  236. return FALSE;
  237. }
  238. // Remove
  239. if(pRHEntry->GetInQ())
  240. {
  241. RemoveEntryList( &pRHEntry->QueryQListEntry());
  242. pRHEntry->ClearInQ();
  243. TraceFunctLeaveEx((LPARAM)this);
  244. return TRUE;
  245. }
  246. else
  247. {
  248. SetLastError(ERROR_PATH_NOT_FOUND);
  249. TraceFunctLeaveEx((LPARAM)this);
  250. return FALSE;
  251. }
  252. }
  253. ////////////////////////////////////////////////////////////////////////////////
  254. //
  255. // CRETRY_Q::RemoveFromTop()
  256. //
  257. // This function removes an entry into the queue
  258. //
  259. // Arguments:
  260. //
  261. // none
  262. //
  263. /////////////////////////////////////////////////////////////////////////////////
  264. //
  265. PRETRY_HASH_ENTRY CRETRY_Q::RemoveFromTop(void)
  266. {
  267. PLIST_ENTRY plEntry = NULL;
  268. CRETRY_HASH_ENTRY * pHashEntry = NULL;
  269. //get the first item off the queue
  270. if(!IsListEmpty(&m_QHead))
  271. {
  272. plEntry = RemoveHeadList (&m_QHead);
  273. pHashEntry = CONTAINING_RECORD(plEntry, CRETRY_HASH_ENTRY, m_QLEntry);
  274. }
  275. return pHashEntry;
  276. }
  277. /////////////////////////////////////////////////////////////////////////////////
  278. // CRETRY_Q::PrintAllEntries
  279. //
  280. // Walks the retry queue and Prints all the domains and the times
  281. //
  282. /////////////////////////////////////////////////////////////////////////////////
  283. //
  284. void CRETRY_Q::PrintAllEntries(void)
  285. {
  286. PLIST_ENTRY HeadOfList = NULL;
  287. PLIST_ENTRY pEntry = NULL;
  288. PLIST_ENTRY pentryNext = NULL;
  289. CRETRY_HASH_ENTRY * pHashEntry = NULL;
  290. FILETIME ftTime;
  291. SYSTEMTIME stTime;
  292. char szRetryTime[20];
  293. char szInsertedTime[20];
  294. TraceFunctEnterEx((LPARAM)this, "CRETRY_Q::PrintAllEntries");
  295. LockQ();
  296. HeadOfList = &m_QHead;
  297. pEntry = m_QHead.Flink;
  298. for(; pEntry != HeadOfList; pEntry = pentryNext)
  299. {
  300. pentryNext = pEntry->Flink;
  301. pHashEntry = CONTAINING_RECORD(pEntry, CRETRY_HASH_ENTRY, m_QLEntry);
  302. ftTime = pHashEntry->GetRetryTime();
  303. FileTimeToSystemTime(&ftTime, &stTime);
  304. sprintf(szRetryTime, "%d:%d:%d",stTime.wHour,stTime.wMinute, stTime.wSecond);
  305. ftTime = pHashEntry->GetInsertTime();
  306. FileTimeToSystemTime(&ftTime, &stTime);
  307. sprintf(szInsertedTime, "%d:%d:%d",stTime.wHour,stTime.wMinute, stTime.wSecond);
  308. DebugTrace((LPARAM)this,"Domain: %s RTime: %s, ITime: %s",
  309. pHashEntry->GetHashKey(),szRetryTime, szInsertedTime);
  310. }
  311. UnLockQ();
  312. TraceFunctLeaveEx((LPARAM)this);
  313. }
  314. //---[ CRETRY_Q::StealQueueEntries ]-------------------------------------------
  315. //
  316. //
  317. // Description:
  318. // Used to swap entries with tmp queue during config update.
  319. // Parameters:
  320. // pRetryQueue Queue to swap entries with.
  321. // Returns:
  322. // -
  323. // History:
  324. // 10/12/98 - MikeSwa Created
  325. //
  326. //-----------------------------------------------------------------------------
  327. void CRETRY_Q::StealQueueEntries(CRETRY_Q *pRetryQueue)
  328. {
  329. _ASSERT(IsListEmpty(&m_QHead));
  330. //Update our head
  331. if (!IsListEmpty(&(pRetryQueue->m_QHead)))
  332. {
  333. m_QHead.Flink = pRetryQueue->m_QHead.Flink;
  334. m_QHead.Flink->Blink = &m_QHead;
  335. m_QHead.Blink = pRetryQueue->m_QHead.Blink;
  336. m_QHead.Blink->Flink = &m_QHead;
  337. }
  338. //Now mark other queue as empty
  339. InitializeListHead(&(pRetryQueue->m_QHead));
  340. }
  341. /////////////////////////////////////////////////////////////////////////////////////////