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.

334 lines
8.3 KiB

  1. #ifndef _DFS_SITE_COST_CACHE_HXX__
  2. #define _DFS_SITE_COST_CACHE_HXX__
  3. #include <shash.h>
  4. #include <limits.h>
  5. class DfsSite;
  6. //
  7. // Minimum and maximum values for inter-site costs.
  8. // These values were 0 and 100 once upon a tender time.
  9. //
  10. #define DFS_MIN_COST 0
  11. #define DFS_MAX_COST ULONG_MAX
  12. #define DFS_DEFAULT_SITE_COST_NUM_BUCKETS 16
  13. #define DFS_MAX_SITE_COST_CACHES 64
  14. //
  15. // When we get a cost that's marked with a ValidityStatus != ERROR_SUCCESS
  16. // this is how soon that entry will expire. If the entry is accessed again after this
  17. // interval, we'll query DS again to see if we have better luck with it.
  18. //
  19. #define DFS_DEFAULT_INVALID_COST_RETRY_INTERVAL 60 * 1000
  20. //
  21. // This is the hash entry that maps
  22. // a destination site to its cost.
  23. //
  24. typedef struct _DFS_SITE_COST_DATA {
  25. SHASH_HEADER Header;
  26. DFSSTATUS ValidityStatus; // to account for possible errors in Cost calculations
  27. ULONG AccessTime; // For aging of individual entries.
  28. ULONG Cost; // Cost from a client site to the following destination
  29. DfsSite *pDestinationSite; // The above cost only applies to this destination.
  30. } DFS_SITE_COST_DATA, *PDFS_SITE_COST_DATA;
  31. //
  32. // This maps sitenames of servers to their corresponding costs.
  33. // There is one of these tables per each unique client DfsSite.
  34. //
  35. class DfsSiteCostCache : public DfsGeneric
  36. {
  37. private:
  38. //
  39. // Hash table mapping destination sites and their corresponding costs.
  40. //
  41. PSHASH_TABLE _pSiteCostTable;
  42. public:
  43. DfsSiteCostCache( VOID )
  44. : DfsGeneric( DFS_OBJECT_TYPE_SITECOST_CACHE )
  45. {
  46. _pSiteCostTable = NULL;
  47. }
  48. ~DfsSiteCostCache( VOID )
  49. {
  50. if (_pSiteCostTable != NULL)
  51. {
  52. // we have to throw out individual entries or we'll leak.
  53. InvalidateCache();
  54. ShashTerminateHashTable( _pSiteCostTable );
  55. _pSiteCostTable = NULL;
  56. }
  57. }
  58. DFSSTATUS
  59. Initialize( VOID );
  60. //
  61. // Retry because the entry we have doesn't have a good ValidityStatus.
  62. //
  63. inline BOOLEAN
  64. IsTimeToRetry( PDFS_SITE_COST_DATA pSiteData )
  65. {
  66. DWORD Interval = DFS_DEFAULT_INVALID_COST_RETRY_INTERVAL;
  67. // We should implement a staggered retry here so that we won't
  68. // bombard the DS over and over. BUG:
  69. return IsTime( pSiteData->AccessTime, Interval );
  70. }
  71. //
  72. // Refresh because the entry we have is just plain too old.
  73. //
  74. inline BOOLEAN
  75. IsTimeToRefresh( PDFS_SITE_COST_DATA pSiteData )
  76. {
  77. DWORD Interval = DfsServerGlobalData.SiteSupportRefreshInterval;
  78. return IsTime( pSiteData->AccessTime, Interval );
  79. }
  80. static BOOLEAN
  81. IsTime(
  82. ULONG TimeStamp,
  83. DWORD Interval)
  84. {
  85. DWORD TimeNow = 0;
  86. TimeNow = GetTickCount();
  87. if ((TimeNow > TimeStamp) &&
  88. (TimeNow - TimeStamp) > Interval)
  89. {
  90. return TRUE;
  91. }
  92. if ((TimeNow < TimeStamp) &&
  93. ((TimeNow - 0) + (0xFFFFFFFF - TimeStamp) > Interval))
  94. {
  95. return TRUE;
  96. }
  97. return FALSE;
  98. }
  99. DFSSTATUS
  100. GetCost (
  101. DfsSite *pDestinationSite,
  102. PULONG pCost);
  103. DFSSTATUS
  104. SetCost(
  105. DfsSite *pDestinationSite,
  106. ULONG Cost,
  107. DWORD ValidityStatus);
  108. DFSSTATUS
  109. RemoveCost(
  110. DfsSite *pSite);
  111. //
  112. // Given a target site and the hash structure to insert,
  113. // add the tuple to the table.
  114. //
  115. DFSSTATUS
  116. SetCostData (
  117. DfsSite *pDestinationSite,
  118. PDFS_SITE_COST_DATA pSiteCostData)
  119. {
  120. NTSTATUS NtStatus = STATUS_SUCCESS;
  121. DFSSTATUS Status = ERROR_SUCCESS;
  122. //
  123. // The destination site is the hash key here.
  124. //
  125. NtStatus = SHashInsertKey(_pSiteCostTable,
  126. pSiteCostData,
  127. pDestinationSite,
  128. SHASH_REPLACE_IFFOUND);
  129. Status = RtlNtStatusToDosError(NtStatus);
  130. return Status;
  131. }
  132. //
  133. // Create a DFS_SITE_COST_DATA structure that is ready to
  134. // get inserted in to the SiteCost Cache.
  135. //
  136. DFSSTATUS
  137. CreateCostData (
  138. DfsSite *pDestinationSite,
  139. ULONG Cost,
  140. DFSSTATUS ValidityStatus,
  141. PDFS_SITE_COST_DATA *ppNewData);
  142. // Just delete the cache data entry.
  143. static VOID
  144. DfsDeallocateSiteCostData(PVOID pPointer );
  145. DfsSite *
  146. StartSiteEnumerate( SHASH_ITERATOR *pIter )
  147. {
  148. PDFS_SITE_COST_DATA pData = NULL;
  149. pData = (PDFS_SITE_COST_DATA)SHashStartEnumerate( pIter, _pSiteCostTable );
  150. if (pData == NULL)
  151. {
  152. return NULL;
  153. }
  154. return pData->pDestinationSite;
  155. }
  156. DfsSite *
  157. NextSiteEnumerate( SHASH_ITERATOR *pIter )
  158. {
  159. PDFS_SITE_COST_DATA pData = NULL;
  160. pData = (PDFS_SITE_COST_DATA)SHashNextEnumerate( pIter, _pSiteCostTable );
  161. if (pData == NULL)
  162. {
  163. return NULL;
  164. }
  165. return pData->pDestinationSite;
  166. }
  167. VOID
  168. FinishSiteEnumerate( SHASH_ITERATOR *pIter )
  169. {
  170. SHashFinishEnumerate( pIter, _pSiteCostTable);
  171. }
  172. //
  173. VOID
  174. InvalidateCache( VOID );
  175. };
  176. //
  177. // DfsSiteCostSupport class provides a much needed layer of indirection
  178. // between DfsSites and the DfsSiteCostCaches the DfsSites have a one-to-one
  179. // mapping with. Since references on DfsSites are long lived (~12hrs+), and we
  180. // may get flooded with DfsSiteCostCaches consuming a lot of memory, we need
  181. // to do some trimming based simply on the total number of caches sitting around.
  182. // For that, we need this extra level of indirection. This solves races
  183. // between trimming and lookup/inserts.
  184. //
  185. class DfsSiteCostSupport
  186. {
  187. private:
  188. DfsSiteCostCache *_pCostTable;
  189. CRITICAL_SECTION _SiteCostLock;
  190. LONG _InUseCount;
  191. // For aging of the entire cache.
  192. ULONG _LastAccessTime;
  193. BOOL _CritInit;
  194. //
  195. // The MRU hangs off the DfsServerGlobalData, and is guarded
  196. // by the GlobalDataLock.
  197. //
  198. LIST_ENTRY MruListEntry;
  199. BOOLEAN InMruList;
  200. DfsSiteCostSupport()
  201. {
  202. _pCostTable = NULL;
  203. _InUseCount = 1;
  204. _LastAccessTime = 0;
  205. InitializeListHead( &MruListEntry );
  206. InMruList = FALSE;
  207. _CritInit = FALSE;
  208. }
  209. ULONG
  210. InsertInMruList(VOID);
  211. VOID
  212. MoveToFrontOfMruList(VOID);
  213. BOOLEAN
  214. RemoveFromMruList(VOID);
  215. DFSSTATUS
  216. PopLastTableFromMruList(
  217. DfsSiteCostSupport **pTableToRemove);
  218. ULONG
  219. TrimSiteCostCaches(
  220. ULONG MaxCachesToTrim);
  221. public:
  222. ~DfsSiteCostSupport()
  223. {
  224. // The in-use count is not tied to
  225. // the existence of this structure.
  226. // Rather, the references on this is implicitly the same
  227. // as the unique DfsSite that's pointing to this.
  228. // Hence, there's no need to call its Release() method here.
  229. // That would've happened already, and the CostTable would've already
  230. // gotten deleted.
  231. if(_CritInit)
  232. {
  233. DeleteCriticalSection( &_SiteCostLock );
  234. }
  235. _LastAccessTime = ULONG_MAX; // To help debugging.
  236. }
  237. // Just create the critical section not the table itself.
  238. // Table is created upon demand because the default behavior is
  239. // sitecosting turned off.
  240. DFSSTATUS
  241. Initialize()
  242. {
  243. DFSSTATUS Status = ERROR_SUCCESS;
  244. _CritInit = InitializeCriticalSectionAndSpinCount( &_SiteCostLock, DFS_CRIT_SPIN_COUNT );
  245. if (_CritInit == FALSE)
  246. {
  247. Status = GetLastError();
  248. return Status;
  249. }
  250. return Status;
  251. }
  252. static
  253. DFSSTATUS
  254. DfsCreateSiteCostSupport(
  255. DfsSiteCostSupport **ppSup );
  256. DFSSTATUS
  257. Acquire(
  258. DfsSiteCostCache **ppCache );
  259. VOID
  260. Release( VOID );
  261. VOID
  262. MarkForDeletion( VOID );
  263. BOOLEAN
  264. IsExpired( VOID );
  265. };
  266. #endif