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.

395 lines
12 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name :
  4. rhash.cxx
  5. Abstract:
  6. This file contains type definitions hash table support
  7. Author:
  8. Revision History:
  9. Nimish Khanolkar (NimishK)
  10. --*/
  11. #include "precomp.h"
  12. CRETRY_HASH_TABLE::CRETRY_HASH_TABLE()
  13. {
  14. TraceFunctEnterEx((LPARAM)this,
  15. "CRETRY_HASH_TABLE::CRETRY_HASH_TABLE");
  16. m_TotalEntries = 0;
  17. m_Signature = RETRY_TABLE_SIGNATURE_VALID;
  18. TraceFunctLeaveEx((LPARAM)this);
  19. }
  20. CRETRY_HASH_TABLE::~CRETRY_HASH_TABLE()
  21. {
  22. TraceFunctEnterEx((LPARAM)this,
  23. "CRETRY_HASH_TABLE::~CRETRY_HASH_TABLE");
  24. m_Signature = RETRY_TABLE_SIGNATURE_FREE;
  25. TraceFunctLeaveEx((LPARAM)this);
  26. }
  27. /////////////////////////////////////////////////////////////////////////////////
  28. // CRETRY_HASH_TABLE::DeInitialize
  29. //
  30. // Very Basic.
  31. // By this time there should be no threads adding anything to the hash table
  32. // Frees up all the entries in the hash table
  33. //
  34. /////////////////////////////////////////////////////////////////////////////////
  35. HRESULT CRETRY_HASH_TABLE::DeInitialize(void)
  36. {
  37. //Remove all the entries from the HashTable
  38. RemoveAllEntries();
  39. delete this;
  40. return S_OK;
  41. }
  42. /////////////////////////////////////////////////////////////////////////////////
  43. // CRETRY_HASH_TABLE::RemoveThisEntry
  44. //
  45. // Need to add code to remove entry from retry q as well
  46. //
  47. /////////////////////////////////////////////////////////////////////////////////
  48. void CRETRY_HASH_TABLE::RemoveThisEntry(CRETRY_HASH_ENTRY * pHashEntry,
  49. DWORD BucketNum)
  50. {
  51. TraceFunctEnterEx((LPARAM)this, "CRETRY_HASH_TABLE::RemoveThisEntry");
  52. DebugTrace((LPARAM)this, "removing %s from hash table",
  53. pHashEntry->GetHashKey());
  54. m_HashTable[BucketNum].m_Lock.ExclusiveLock();
  55. RemoveEntryList(&pHashEntry->QueryHListEntry());
  56. m_HashTable[BucketNum].m_Lock.ExclusiveUnlock();
  57. TraceFunctLeaveEx((LPARAM)this);
  58. }
  59. /////////////////////////////////////////////////////////////////////////////////
  60. // CRETRY_HASH_TABLE::RemoveAllEntries
  61. //
  62. // To be clean : Need to add code to remove each entry from retry q as well
  63. // But not really needed as I will not be leaking anything if I simply destroy the
  64. // queue
  65. //
  66. /////////////////////////////////////////////////////////////////////////////////
  67. void CRETRY_HASH_TABLE::RemoveAllEntries(void)
  68. {
  69. DWORD LoopVar = 0;
  70. PLIST_ENTRY HeadOfList = NULL;
  71. PLIST_ENTRY pEntry = NULL;
  72. CRETRY_HASH_ENTRY * pHashEntry = NULL;
  73. TraceFunctEnterEx((LPARAM)this, "CRETRY_HASH_TABLE::RemoveAllEntries");
  74. for (LoopVar = 0; LoopVar < TABLE_SIZE; LoopVar++)
  75. {
  76. m_HashTable[LoopVar].m_Lock.ExclusiveLock();
  77. HeadOfList = &m_HashTable[LoopVar].m_ListHead;
  78. while (!IsListEmpty(HeadOfList))
  79. {
  80. //remove the entries from the list
  81. pEntry = RemoveHeadList (HeadOfList);
  82. pHashEntry = CONTAINING_RECORD(pEntry, CRETRY_HASH_ENTRY, m_HLEntry);
  83. _ASSERT(pHashEntry->IsValid());
  84. DebugTrace((LPARAM)this, "removing %s from hash table. RefCnt = %d",
  85. pHashEntry->GetHashKey(), pHashEntry->QueryRefCount());
  86. pHashEntry->ClearInTable();
  87. pHashEntry->DecRefCount();
  88. //decrement entry counts
  89. m_HashTable[LoopVar].m_NumEntries--;
  90. InterlockedIncrement(&(m_HashTable[LoopVar].m_RefNum));
  91. InterlockedDecrement(&m_TotalEntries);
  92. }
  93. m_HashTable[LoopVar].m_Lock.ExclusiveUnlock();
  94. }
  95. TraceFunctLeaveEx((LPARAM)this);
  96. }
  97. /////////////////////////////////////////////////////////////////////////////////
  98. // CRETRY_HASH_TABLE::PrintAllEntries
  99. //
  100. // Should not use this one - not really useful.
  101. // Instead Use RETRYQ::PrintAllQEntries()
  102. //
  103. /////////////////////////////////////////////////////////////////////////////////
  104. //
  105. void CRETRY_HASH_TABLE::PrintAllEntries(void)
  106. {
  107. DWORD LoopVar = 0;
  108. PLIST_ENTRY HeadOfList = NULL;
  109. PLIST_ENTRY pEntry = NULL;
  110. PLIST_ENTRY pentryNext = NULL;
  111. CRETRY_HASH_ENTRY * pHashEntry = NULL;
  112. for (LoopVar = 0; LoopVar < TABLE_SIZE; LoopVar++)
  113. {
  114. m_HashTable[LoopVar].m_Lock.ExclusiveLock();
  115. HeadOfList = &m_HashTable[LoopVar].m_ListHead;
  116. pEntry = m_HashTable[LoopVar].m_ListHead.Flink;
  117. for(; pEntry != HeadOfList; pEntry = pentryNext)
  118. {
  119. pentryNext = pEntry->Flink;
  120. pHashEntry = CONTAINING_RECORD(pEntry, CRETRY_HASH_ENTRY, m_HLEntry);
  121. printf("%s i n bucket %d\n", pHashEntry->GetHashKey(), LoopVar);
  122. }
  123. m_HashTable[LoopVar].m_Lock.ExclusiveUnlock();
  124. }
  125. }
  126. /////////////////////////////////////////////////////////////////////////////////
  127. // CRETRY_HASH_TABLE::InsertIntoTable
  128. //
  129. // We insert a new entry into the table
  130. // If we find an existing one for the same domain we remove it and add this new
  131. // one
  132. // Adding an entry to the Hash Table also results in adding the entry to the retry
  133. // queue ordered on the RetryTime
  134. //
  135. /////////////////////////////////////////////////////////////////////////////////
  136. //
  137. BOOL CRETRY_HASH_TABLE::InsertIntoTable(CRETRY_HASH_ENTRY * pHashEntry)
  138. {
  139. unsigned int HashValue = 0;
  140. char * NewData = NULL;
  141. char * ExistingData = NULL;
  142. PLIST_ENTRY HeadOfList = NULL;
  143. PLIST_ENTRY ListEntry =NULL;
  144. CRETRY_HASH_ENTRY * pExistingEntry = NULL;
  145. int Result = 0;
  146. TraceFunctEnterEx((LPARAM)this, "CRETRY_HASH_TABLE::InsertIntoTable");
  147. _ASSERT(pHashEntry != NULL);
  148. if(pHashEntry == NULL)
  149. {
  150. TraceFunctLeaveEx((LPARAM)this);
  151. return FALSE;
  152. }
  153. //get the new key
  154. NewData = pHashEntry->GetHashKey();
  155. _ASSERT(NewData != NULL);
  156. if(NewData == NULL)
  157. {
  158. TraceFunctLeaveEx((LPARAM)this);
  159. return FALSE;
  160. }
  161. CharLowerBuff((char *)NewData, lstrlen(NewData));
  162. //get the hash value for it
  163. HashValue = HashFunction (NewData);
  164. //lock the list exclusively
  165. m_HashTable[HashValue].m_Lock.ExclusiveLock();
  166. //insert the head of the list for this bucket
  167. //duplicates are dealt by removing the dup entry and
  168. //adding the new one
  169. HeadOfList = &m_HashTable[HashValue].m_ListHead;
  170. for (ListEntry = HeadOfList->Flink; ListEntry != HeadOfList;
  171. ListEntry = ListEntry->Flink)
  172. {
  173. _ASSERT(ListEntry != NULL);
  174. pExistingEntry = CONTAINING_RECORD(ListEntry, CRETRY_HASH_ENTRY, m_HLEntry);
  175. if(pExistingEntry && pExistingEntry->IsValid())
  176. {
  177. //So we got a valid entry
  178. ExistingData = pExistingEntry->GetHashKey();
  179. }
  180. else
  181. {
  182. m_HashTable[HashValue].m_Lock.ExclusiveUnlock();
  183. SetLastError(ERROR_INVALID_DATA);
  184. //We have a corrupt entry in the hash table
  185. DebugTrace((LPARAM)this, "hash table bucket %d has a currupt entry listEntry ",
  186. HashValue);
  187. _ASSERT(pExistingEntry->IsValid());
  188. TraceFunctLeaveEx((LPARAM)this);
  189. return FALSE;
  190. }
  191. _ASSERT(ExistingData != NULL);
  192. Result = lstrcmpi(NewData, ExistingData);
  193. if(Result < 0)
  194. {
  195. break;
  196. }
  197. else if(Result == 0)
  198. {
  199. //So there is already a Hash Entry
  200. DebugTrace((LPARAM)this, "%s is already in hash table ",
  201. pHashEntry->GetHashKey());
  202. //If we already have an entry in there - we will live with it
  203. //For the time being, we will taking the approach that if something
  204. //makes us establish a new connection before the retry interval and
  205. //we fail the connection, then we simply ignore the failure and stick
  206. //with the original retry interval
  207. //eg at 2:00pm we inserted something for retry at 2:30pm
  208. // at 2:20pm something triggers this domain, but the connection fails
  209. // Instead of updating the retry queue to now retry at 2:50 pm,
  210. // we will instead retry at 2:30pm as orginally planned.
  211. //unlock this bucket
  212. m_HashTable[HashValue].m_Lock.ExclusiveUnlock();
  213. SetLastError(ERROR_FILE_EXISTS);
  214. TraceFunctLeaveEx((LPARAM)this);
  215. return FALSE;
  216. }
  217. }
  218. // Ok, insert the entry here here.
  219. //inc the ref count on the hash entry
  220. pHashEntry->IncRefCount();
  221. //We just added the entry the ref count cannot be anything but 1
  222. _ASSERT(pHashEntry->QueryRefCount() == 1);
  223. _ASSERT(ListEntry != NULL);
  224. //Insert into the hash bucket list before the exisitng entry
  225. InsertTailList(ListEntry, &pHashEntry->QueryHListEntry());
  226. pHashEntry->SetInTable();
  227. //update total entries in this bucket
  228. m_HashTable[HashValue].m_NumEntries++;
  229. DebugTrace((LPARAM)this, "inserted %s into hash table. RefCnt = %d",
  230. pHashEntry->GetHashKey(), pHashEntry->QueryRefCount());
  231. //update numentries in this bucket
  232. InterlockedIncrement(&m_TotalEntries);
  233. //unlock this bucket
  234. m_HashTable[HashValue].m_Lock.ExclusiveUnlock();
  235. TraceFunctLeaveEx((LPARAM)this);
  236. return TRUE;
  237. }
  238. /////////////////////////////////////////////////////////////////////////////////
  239. // CRETRY_HASH_TABLE::RemoveFromTable
  240. //
  241. // We insert a new entry into the table
  242. // If we find an existing one for the same domain we remove it and add this new
  243. // one
  244. // Adding an entry to the Hash Table also results in adding the entry to the retry
  245. // queue ordered on the RetryTime
  246. //
  247. /////////////////////////////////////////////////////////////////////////////////
  248. BOOL CRETRY_HASH_TABLE::RemoveFromTable(const char * SearchData,
  249. PRETRY_HASH_ENTRY *ppExistingEntry)
  250. {
  251. unsigned int HashValue;
  252. char * ExistingData = NULL;
  253. PLIST_ENTRY HeadOfList;
  254. PLIST_ENTRY ListEntry;
  255. int Result = 0;
  256. TraceFunctEnterEx((LPARAM)this, "CRETRY_HASH_TABLE::RemoveFromTable");
  257. _ASSERT(SearchData != NULL);
  258. if(SearchData == NULL)
  259. {
  260. return FALSE;
  261. }
  262. CharLowerBuff((char *)SearchData, lstrlen(SearchData));
  263. //get the hash value
  264. HashValue = HashFunction (SearchData);
  265. m_HashTable[HashValue].m_Lock.ExclusiveLock();
  266. HeadOfList = &m_HashTable[HashValue].m_ListHead;
  267. for (ListEntry = HeadOfList->Flink; ListEntry != HeadOfList;
  268. ListEntry = ListEntry->Flink)
  269. {
  270. _ASSERT(ListEntry != NULL);
  271. *ppExistingEntry = CONTAINING_RECORD(ListEntry, CRETRY_HASH_ENTRY, m_HLEntry);
  272. //ExistingData = (*ppExistingEntry)->GetHashKey();
  273. if((*ppExistingEntry) && (*ppExistingEntry)->IsValid())
  274. {
  275. //So we got a valid entry
  276. ExistingData = (*ppExistingEntry)->GetHashKey();
  277. }
  278. else
  279. {
  280. m_HashTable[HashValue].m_Lock.ExclusiveUnlock();
  281. SetLastError(ERROR_INVALID_DATA);
  282. //We have a corrupt entry in the hash table
  283. DebugTrace((LPARAM)this,
  284. "hash table bucket %d has a currupt entry listEntry ",
  285. HashValue);
  286. _ASSERT((*ppExistingEntry)->IsValid());
  287. TraceFunctLeaveEx((LPARAM)this);
  288. return FALSE;
  289. }
  290. _ASSERT(ExistingData != NULL);
  291. Result = lstrcmpi(SearchData,ExistingData);
  292. if(Result == 0)
  293. {
  294. DebugTrace((LPARAM)this, "Removing %s from hash table", ExistingData);
  295. //found it
  296. //Remove it from this bucket list
  297. RemoveEntryList(ListEntry);
  298. (*ppExistingEntry)->ClearInTable();
  299. m_HashTable[HashValue].m_NumEntries--;
  300. InterlockedDecrement(&m_TotalEntries);
  301. m_HashTable[HashValue].m_Lock.ExclusiveUnlock();
  302. TraceFunctLeaveEx((LPARAM)this);
  303. return TRUE;
  304. }
  305. else if ( Result < 0 )
  306. break;
  307. }
  308. //duplicates are not allowed
  309. SetLastError(ERROR_PATH_NOT_FOUND);
  310. *ppExistingEntry = NULL;
  311. m_HashTable[HashValue].m_Lock.ExclusiveUnlock();
  312. TraceFunctLeaveEx((LPARAM)this);
  313. return FALSE;
  314. }