Source code of Windows XP (NT5)
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.

549 lines
16 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 1999
  5. //
  6. // File: filidmap.cxx
  7. //
  8. // Contents: FileId to wid mapping using hashed access
  9. //
  10. // History: 07-May-97 SitaramR Created
  11. //
  12. // Notes: Only ntfs 5.0 wids are added to the file id map because all
  13. // non-ntfs 5.0 wids map to fileIdInvalid, which means that there
  14. // will be too many collisions on fileIdInvalid, which will degrade
  15. // the performance of the hashed access. One drawback of mapping
  16. // only ntfs 5.0 wids is that the count of wids in fileid map and
  17. // property store cannot be checked for equality to detect
  18. // corruption as is done for the strings table. However, there is a
  19. // correlation between a count mismatch in strings table and in
  20. // file id map table because the file id map table is flushed before
  21. // the strings table. As a result, when a corruption is detected
  22. // in strings table, a corruption error is thrown and the processing
  23. // for that corruption error reinitializes both strings table and the
  24. // file id map table.
  25. //
  26. //----------------------------------------------------------------------------
  27. #include <pch.cxx>
  28. #pragma hdrstop
  29. #include <filidmap.hxx>
  30. #include <mmstrm.hxx>
  31. #include <cistore.hxx>
  32. #include <prpstmgr.hxx>
  33. #include <propiter.hxx>
  34. #include <cicat.hxx>
  35. //+---------------------------------------------------------------------------
  36. //
  37. // Member: CFileIdMap::CFileIdMap
  38. //
  39. // Synopsis: Constructor
  40. //
  41. // Arguments: [propStoreMgr] -- Property store
  42. // [cicat] -- CiCat
  43. //
  44. // History: 07-May-97 SitaramR Created
  45. //
  46. //----------------------------------------------------------------------------
  47. CFileIdMap::CFileIdMap( CPropStoreManager &propStoreMgr )
  48. : CPersHash( propStoreMgr, FALSE ),
  49. _cCacheEntries( 0 )
  50. #if CIDBG == 1
  51. , _cCacheHits( 0 ),
  52. _cCacheNegativeHits( 0 ),
  53. _cCacheMisses( 0 ),
  54. _cCacheNegativeMisses( 0 )
  55. #endif
  56. {
  57. }
  58. //+---------------------------------------------------------------------------
  59. //
  60. // Member: CFileIdMap::FastInit
  61. //
  62. // Synopsis: Fast initialization
  63. //
  64. // Arguments: [pStorage] -- Ci storage
  65. // [pwcsCatDir] -- Catalog directory
  66. // [pwcsFile] -- File id file name
  67. // [version] -- Content index version
  68. //
  69. // History: 28-Jul-97 SitaramR Created
  70. // 13-Mar-98 KitmanH Passed in True to
  71. // CPerHash::FastInit to specify
  72. // that a FileIdMap is wanted
  73. //
  74. //----------------------------------------------------------------------------
  75. BOOL CFileIdMap::FastInit( CiStorage * pStorage,
  76. ULONG version )
  77. {
  78. return CPersHash::FastInit(pStorage, version, TRUE);
  79. }
  80. //+---------------------------------------------------------------------------
  81. //
  82. // Member: CFileIdMap::LongInit
  83. //
  84. // Synopsis: Initialization that may take a long time
  85. //
  86. // Arguments: [version] -- CI version
  87. // [fDirtyShutdown] -- Set to TRUE if the previous shutdown
  88. // was dirty.
  89. //
  90. // History: 28-Jul-97 SitaramR Created
  91. //
  92. //----------------------------------------------------------------------------
  93. void CFileIdMap::LongInit ( ULONG version, BOOL fDirtyShutdown )
  94. {
  95. CPersHash::LongInit( version, fDirtyShutdown );
  96. }
  97. //+---------------------------------------------------------------------------
  98. //
  99. // Member: CFileIdMap::LokFlush
  100. //
  101. // Synopsis: Flushes fileid map
  102. //
  103. // History: 28-Jul-97 SitaramR Created
  104. // 27-Feb-98 KitmanH Don't flush if catalog is
  105. // read-only
  106. //
  107. //----------------------------------------------------------------------------
  108. void CFileIdMap::LokFlush()
  109. {
  110. if ( !_fIsReadOnly )
  111. CPersHash::LokFlush();
  112. } //LokFlush
  113. //+-------------------------------------------------------------------------
  114. //
  115. // Member: CFileIdMap::AddToCache, private
  116. //
  117. // Synopsis: Adds an entry to the cache, or overwrites wid if the
  118. // entry currently exists. The oldest entry is bumped out.
  119. // Caching an entry with widInvalid is valid.
  120. //
  121. // Arguments: [fileId] -- FileId to add
  122. // [wid] -- VolumeId to add
  123. // [volumeId] -- VolumeId to add
  124. //
  125. // History: 22-Jul-98 dlee Created
  126. //
  127. //--------------------------------------------------------------------------
  128. void CFileIdMap::AddToCache(
  129. FILEID & fileId,
  130. WORKID wid,
  131. VOLUMEID volumeId )
  132. {
  133. // First look for the fileid/volumeid currently in the cache
  134. for ( unsigned iCache = 0; iCache < _cCacheEntries; iCache++ )
  135. {
  136. if ( _aCache[ iCache ].fileId == fileId &&
  137. _aCache[ iCache ].volumeId == volumeId )
  138. {
  139. _aCache[ iCache ].wid = wid;
  140. return;
  141. }
  142. }
  143. Win4Assert( _cCacheEntries <= cFileIdMapCacheEntries );
  144. // Bump out the oldest item and put the new item first in the array
  145. unsigned cToMove;
  146. if ( _cCacheEntries == cFileIdMapCacheEntries )
  147. {
  148. cToMove = cFileIdMapCacheEntries - 1;
  149. }
  150. else
  151. {
  152. cToMove = _cCacheEntries;
  153. _cCacheEntries++;
  154. }
  155. RtlMoveMemory( & _aCache[ 1 ],
  156. & _aCache[ 0 ],
  157. sizeof SFileIdMapEntry * cToMove );
  158. _aCache[0].fileId = fileId;
  159. _aCache[0].volumeId = volumeId;
  160. _aCache[0].wid = wid;
  161. } //AddToCache
  162. //+-------------------------------------------------------------------------
  163. //
  164. // Member: CFileIdMap::FindInCache, private
  165. //
  166. // Synopsis: Locates a workid in the cache given a fileid and volumeid
  167. //
  168. // Arguments: [fileId] -- FileId of entry to find
  169. // [volumeId] -- VolumeId of entry to find
  170. // [wid] -- Returns the workid if found
  171. //
  172. // Returns: TRUE if found or FALSE if not found
  173. //
  174. // History: 22-Jul-98 dlee Created
  175. //
  176. //--------------------------------------------------------------------------
  177. BOOL CFileIdMap::FindInCache(
  178. FILEID & fileId,
  179. VOLUMEID volumeId,
  180. WORKID & wid )
  181. {
  182. for ( unsigned iCache = 0; iCache < _cCacheEntries; iCache++ )
  183. {
  184. if ( _aCache[ iCache ].fileId == fileId &&
  185. _aCache[ iCache ].volumeId == volumeId )
  186. {
  187. wid = _aCache[ iCache ].wid;
  188. #if CIDBG == 1
  189. ciDebugOut(( DEB_USN,
  190. "fim::find cache worked %#I64x %#x, vol %wc\n",
  191. fileId, wid, volumeId ));
  192. _cCacheHits++;
  193. if ( widInvalid == wid )
  194. _cCacheNegativeHits++;
  195. #endif
  196. return TRUE;
  197. }
  198. }
  199. return FALSE;
  200. } //FindInCache
  201. //+-------------------------------------------------------------------------
  202. //
  203. // Member: CFileIdMap::RemoveFromCache, private
  204. //
  205. // Synopsis: Removes the item from the cache if it exists
  206. //
  207. // Arguments: [fileId] -- FileId of entry to remove (only used for assert)
  208. // [wid] -- Workid of entry to remove
  209. //
  210. // History: 22-Jul-98 dlee Created
  211. //
  212. //--------------------------------------------------------------------------
  213. void CFileIdMap::RemoveFromCache(
  214. FILEID & fileId,
  215. WORKID wid )
  216. {
  217. for ( unsigned iCache = 0; iCache < _cCacheEntries; iCache++ )
  218. {
  219. if ( _aCache[ iCache ].wid == wid )
  220. {
  221. Win4Assert( _aCache[ iCache ].fileId == fileId );
  222. RtlCopyMemory( & _aCache[ iCache ],
  223. & _aCache[ iCache + 1 ],
  224. sizeof SFileIdMapEntry * ( _cCacheEntries - iCache - 1 ) );
  225. _cCacheEntries--;
  226. break;
  227. }
  228. }
  229. } //RemoveFromCache
  230. //+-------------------------------------------------------------------------
  231. //
  232. // Member: CFileIdMap::LokFind, private
  233. //
  234. // Synopsis: Given fileId, find workid.
  235. //
  236. // Arguments: [fileId] - FileId to locate
  237. // [volumeId] - Volume id of fileid
  238. //
  239. // Returns: Workid of FileId
  240. //
  241. // History: 07-May-97 SitaramR Created
  242. //
  243. // Notes: File ids are not unique across different volumes, hence the
  244. // need for volume ids.
  245. //
  246. //--------------------------------------------------------------------------
  247. WORKID CFileIdMap::LokFind( FILEID fileId, VOLUMEID volumeId )
  248. {
  249. Win4Assert( _fFullInit );
  250. WORKID wid;
  251. if ( FindInCache( fileId, volumeId, wid ) )
  252. return wid;
  253. #if CIDBG == 1
  254. _cCacheMisses++;
  255. #endif
  256. #ifdef DO_STATS
  257. unsigned cSearchLen = 0;
  258. #endif
  259. CShortWidList list( HashFun(fileId), _hTable );
  260. for ( wid = list.WorkId(); wid != widInvalid; wid = list.NextWorkId() )
  261. {
  262. #ifdef DO_STATS
  263. cSearchLen++;
  264. #endif
  265. XPrimaryRecord rec( _PropStoreMgr, wid );
  266. PROPVARIANT propVar;
  267. BOOL fFound = _PropStoreMgr.ReadProperty( rec.GetReference(),
  268. pidFileIndex,
  269. propVar );
  270. ciDebugOut(( DEB_ITRACE, "trying wid %#x, fFound %d, fid %#I64x\n",
  271. wid, fFound, propVar.uhVal.QuadPart ));
  272. if ( fFound && propVar.uhVal.QuadPart == fileId )
  273. {
  274. Win4Assert( propVar.vt == VT_UI8 );
  275. BOOL fFound = _PropStoreMgr.ReadProperty( rec.GetReference(),
  276. pidVolumeId,
  277. propVar );
  278. if ( fFound && propVar.ulVal == volumeId )
  279. {
  280. Win4Assert( propVar.vt == VT_UI4 );
  281. #ifdef DO_STATS
  282. _hTable.UpdateStats( cSearchLen );
  283. #endif
  284. ciDebugOut(( DEB_USN, "fim::find worked %#I64x %#x, vol %wc\n",
  285. fileId, wid, volumeId ));
  286. AddToCache( fileId, wid, volumeId );
  287. return wid;
  288. }
  289. else
  290. {
  291. ciDebugOut(( DEB_USN, "fim::find fileid match, but not volid: %#x, %#x\n",
  292. propVar.ulVal, volumeId ));
  293. }
  294. }
  295. }
  296. ciDebugOut(( DEB_USN, "fim::find failed %#I64x, vol %wc\n", fileId, volumeId ));
  297. #if CIDBG == 1
  298. _cCacheNegativeMisses++;
  299. #endif
  300. //
  301. // Often, a new file is looked up multiple times before it is added, so
  302. // add the widInvalid entry to the cache. Negative lookups are slow.
  303. //
  304. AddToCache( fileId, widInvalid, volumeId );
  305. return widInvalid;
  306. } //LokFind
  307. //+-------------------------------------------------------------------------
  308. //
  309. // Member: CFileIdMap::LokAdd
  310. //
  311. // Synopsis: Add a new fileid to wid mapping
  312. //
  313. // Arguments: [fileId] -- File Id
  314. // [wid] -- Workid
  315. //
  316. // History: 07-May-97 SitaramR Created
  317. //
  318. //--------------------------------------------------------------------------
  319. void CFileIdMap::LokAdd( FILEID fileId, WORKID wid, VOLUMEID volumeId )
  320. {
  321. ciDebugOut(( DEB_USN, "Adding map fileid %#I64x -> wid %x, vol %wc\n",
  322. fileId, wid, volumeId ));
  323. Win4Assert( fileIdInvalid != fileId );
  324. Win4Assert( _fFullInit );
  325. //
  326. // Must grow hash table first, as it grovels through property store.
  327. //
  328. if ( _hTable.IsFull() )
  329. GrowHashTable();
  330. AddToCache( fileId, wid, volumeId );
  331. _hTable.Add ( HashFun(fileId), wid );
  332. } //LokAdd
  333. //+---------------------------------------------------------------------------
  334. //
  335. // Member: CFileIdMap::LokDelete
  336. //
  337. // Synopsis: Delete file id from table
  338. //
  339. // Arguments: [fileId] -- FileId to remove
  340. // [wid] -- Workid to remove
  341. //
  342. // History: 07-May-97 SitaramR Created.
  343. //
  344. //----------------------------------------------------------------------------
  345. void CFileIdMap::LokDelete( FILEID fileId, WORKID wid )
  346. {
  347. ciDebugOut(( DEB_USN, "Removing map fileid %#I64x, %#x\n", fileId, wid ));
  348. RemoveFromCache( fileId, wid );
  349. _hTable.Remove( HashFun( fileId ), wid, TRUE );
  350. } //LokDelete
  351. //+---------------------------------------------------------------------------
  352. //
  353. // Member: CFileIdMap::HashAll
  354. //
  355. // Synopsis: Re-hash all fileId's (after hash table growth)
  356. //
  357. // History: 07-May-97 May Created
  358. //
  359. //----------------------------------------------------------------------------
  360. void CFileIdMap::HashAll()
  361. {
  362. // Count the number of hash table entries and grow the hash table
  363. {
  364. CPropertyStoreWids iter( _PropStoreMgr );
  365. unsigned cWids = 0;
  366. for ( WORKID wid = iter.WorkId(); wid != widInvalid; wid = iter.NextWorkId() )
  367. {
  368. if ( _fAbort )
  369. {
  370. ciDebugOut(( DEB_WARN,
  371. "Stopping FileIdMap::HashAll because of shutdown\n" ));
  372. THROW( CException(STATUS_TOO_LATE) );
  373. }
  374. PROPVARIANT propVar;
  375. BOOL fFound = _PropStoreMgr.ReadPrimaryProperty( wid, pidFileIndex, propVar );
  376. // Only ntfs 5.0 wids have valid fileid's
  377. if ( fFound &&
  378. ( VT_UI8 == propVar.vt ) &&
  379. ( fileIdInvalid != propVar.uhVal.QuadPart ) )
  380. cWids++;
  381. }
  382. GrowToSize( cWids );
  383. }
  384. // Add the wids to the hash table
  385. CPropertyStoreWids iter( _PropStoreMgr );
  386. for ( WORKID wid = iter.WorkId(); wid != widInvalid; wid = iter.NextWorkId() )
  387. {
  388. if ( _fAbort )
  389. {
  390. ciDebugOut(( DEB_WARN,
  391. "Stopping FileIdMap::HashAll because of shutdown\n" ));
  392. THROW( CException(STATUS_TOO_LATE) );
  393. }
  394. PROPVARIANT propVar;
  395. BOOL fFound = _PropStoreMgr.ReadPrimaryProperty( wid, pidFileIndex, propVar );
  396. //
  397. // Only ntfs 5.0 wids have valid fileid's
  398. //
  399. if ( fFound &&
  400. ( VT_UI8 == propVar.vt ) &&
  401. ( fileIdInvalid != propVar.uhVal.QuadPart ) )
  402. _hTable.Add ( HashFun( propVar.uhVal.QuadPart ), wid );
  403. }
  404. #if 0
  405. //
  406. // Look-up every file to see what the hashing looks like.
  407. //
  408. {
  409. CPropertyStoreWids iter( _PropStoreMgr );
  410. unsigned cWids = 0;
  411. for ( WORKID wid = iter.WorkId(); wid != widInvalid; wid = iter.NextWorkId() )
  412. {
  413. XPrimaryRecord rec( _PropStoreMgr, wid );
  414. PROPVARIANT propVar;
  415. BOOL fFound = _PropStoreMgr.ReadProperty( rec.GetReference(),
  416. pidFileIndex,
  417. propVar );
  418. // Only ntfs 5.0 wids have valid fileid's
  419. if ( fFound &&
  420. ( VT_UI8 == propVar.vt ) &&
  421. ( fileIdInvalid != propVar.uhVal.QuadPart ) )
  422. {
  423. FILEID fid = propVar.uhVal.QuadPart;
  424. _PropStoreMgr.ReadProperty( rec.GetReference(),
  425. pidVolumeId,
  426. propVar );
  427. LokFind( fid, propVar.ulVal );
  428. }
  429. }
  430. ciDebugOut(( DEB_FORCE,
  431. "hash: size %d count %d maxchain %d searches %d length %d\n",
  432. _hTable.Size(),
  433. _hTable.Count(),
  434. _hTable._cMaxChainLen,
  435. _hTable._cTotalSearches,
  436. _hTable._cTotalLength ));
  437. }
  438. #endif
  439. } //HashAll
  440. //+-------------------------------------------------------------------------
  441. //
  442. // Member: CFileIdMap::HashFun
  443. //
  444. // Synopsis: Hash function for fileid's
  445. //
  446. // Arguments: [fileId] - FileId to hash
  447. //
  448. // History: 07-May-97 SitaramR Created
  449. //
  450. //--------------------------------------------------------------------------
  451. unsigned CFileIdMap::HashFun( FILEID fileId )
  452. {
  453. //
  454. // The lower 32 bits of the fileid are unique at any given time. The
  455. // upper 32 bits of the fileid represent a sequence number that is
  456. // incremented every time one of the lower 32 bits number is reused.
  457. // So, a good hash function is to simply use the lower 32 bits.
  458. //
  459. return (unsigned) fileId;
  460. } //HashFun