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.

1736 lines
56 KiB

  1. /*++
  2. 1998 Seagate Software, Inc. All rights reserved.
  3. Module Name:
  4. fsatrunc.cpp
  5. Abstract:
  6. This class handles the automatic truncation of files that have already
  7. been premigrated.
  8. Author:
  9. Chuck Bardeen [cbardeen] 20-Feb-1997
  10. Revision History:
  11. --*/
  12. #include "stdafx.h"
  13. #define WSB_TRACE_IS WSB_TRACE_BIT_FSA
  14. #include "wsb.h"
  15. #include "fsa.h"
  16. #include "fsaprem.h"
  17. #include "fsarcvy.h"
  18. #include "fsasrvr.h"
  19. #include "fsatrunc.h"
  20. #include "job.h"
  21. #define DEFAULT_MAX_FILES_PER_RUN 10000
  22. #define DEFAULT_RUN_INTERVAL (15 * 60 * 1000) // 15 minutes in milliseconds
  23. #define STRINGIZE(_str) (OLESTR( #_str ))
  24. #define RETURN_STRINGIZED_CASE(_case) \
  25. case _case: \
  26. return ( STRINGIZE( _case ) );
  27. static const OLECHAR *
  28. FsaStateAsString (
  29. IN HSM_JOB_STATE state
  30. )
  31. /*++
  32. Routine Description:
  33. Gives back a static string representing the connection state.
  34. Arguments:
  35. state - the state to return a string for.
  36. Return Value:
  37. NULL - invalid state passed in.
  38. Otherwise, a valid char *.
  39. --*/
  40. {
  41. //
  42. // Do the Switch
  43. //
  44. switch ( state ) {
  45. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_ACTIVE );
  46. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_CANCELLED );
  47. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_CANCELLING );
  48. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_DONE );
  49. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_FAILED );
  50. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_IDLE );
  51. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_PAUSED );
  52. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_PAUSING );
  53. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_RESUMING );
  54. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_SKIPPED );
  55. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_STARTING );
  56. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_SUSPENDED );
  57. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_SUSPENDING );
  58. default:
  59. return ( OLESTR("Invalid Value") );
  60. }
  61. }
  62. static const OLECHAR *
  63. FsaEventAsString (
  64. IN HSM_JOB_EVENT event
  65. )
  66. /*++
  67. Routine Description:
  68. Gives back a static string representing the connection event.
  69. Arguments:
  70. event - the event to return a string for.
  71. Return Value:
  72. NULL - invalid event passed in.
  73. Otherwise, a valid char *.
  74. --*/
  75. {
  76. //
  77. // Do the Switch
  78. //
  79. switch ( event ) {
  80. RETURN_STRINGIZED_CASE( HSM_JOB_EVENT_CANCEL );
  81. RETURN_STRINGIZED_CASE( HSM_JOB_EVENT_FAIL );
  82. RETURN_STRINGIZED_CASE( HSM_JOB_EVENT_LOWER_PRIORITY );
  83. RETURN_STRINGIZED_CASE( HSM_JOB_EVENT_PAUSE );
  84. RETURN_STRINGIZED_CASE( HSM_JOB_EVENT_RAISE_PRIORITY );
  85. RETURN_STRINGIZED_CASE( HSM_JOB_EVENT_RESUME );
  86. RETURN_STRINGIZED_CASE( HSM_JOB_EVENT_START );
  87. RETURN_STRINGIZED_CASE( HSM_JOB_EVENT_SUSPEND );
  88. default:
  89. return ( OLESTR("Invalid Value") );
  90. }
  91. }
  92. static const OLECHAR *
  93. FsaSortOrderAsString (
  94. IN FSA_PREMIGRATED_SORT_ORDER SortOrder
  95. )
  96. /*++
  97. Routine Description:
  98. Gives back a static string representing the connection SortOrder.
  99. Arguments:
  100. SortOrder - the SortOrder to return a string for.
  101. Return Value:
  102. NULL - invalid SortOrder passed in.
  103. Otherwise, a valid char *.
  104. --*/
  105. {
  106. //
  107. // Do the Switch
  108. //
  109. switch ( SortOrder ) {
  110. RETURN_STRINGIZED_CASE( FSA_SORT_PL_BY_ACCESS_TIME );
  111. RETURN_STRINGIZED_CASE( FSA_SORT_PL_BY_SIZE );
  112. RETURN_STRINGIZED_CASE( FSA_SORT_PL_BY_PATH_NAME );
  113. RETURN_STRINGIZED_CASE( FSA_SORT_PL_BY_SIZE_AND_TIME );
  114. default:
  115. return ( OLESTR("Invalid Value") );
  116. }
  117. }
  118. DWORD FsaStartTruncator(
  119. void* pVoid
  120. )
  121. /*++
  122. --*/
  123. {
  124. return(((CFsaTruncator*) pVoid)->StartScan());
  125. }
  126. HRESULT
  127. CFsaTruncator::Cancel(
  128. HSM_JOB_EVENT event
  129. )
  130. /*++
  131. Implements:
  132. IFsaTruncator::Cancel().
  133. --*/
  134. {
  135. HRESULT hr = S_OK;
  136. WsbTraceIn(OLESTR("CFsaTruncator::Cancel"), OLESTR("event = <%ls>"), FsaEventAsString( event ));
  137. // Lock this object to avoid having the state change between testing its value
  138. // and setting it to a new value
  139. Lock();
  140. try {
  141. // If we have started, but haven't finished, then change the state of the job. The thread
  142. // will exit on it's own.
  143. if ((HSM_JOB_STATE_IDLE != m_state) &&
  144. (HSM_JOB_STATE_DONE != m_state) &&
  145. (HSM_JOB_STATE_FAILED != m_state) &&
  146. (HSM_JOB_STATE_CANCELLED != m_state)) {
  147. if (HSM_JOB_EVENT_CANCEL == event) {
  148. WsbAffirmHr(SetState(HSM_JOB_STATE_CANCELLED));
  149. } else if (HSM_JOB_EVENT_SUSPEND == event) {
  150. WsbAffirmHr(SetState(HSM_JOB_STATE_SUSPENDED));
  151. } else if (HSM_JOB_EVENT_FAIL == event) {
  152. WsbAffirmHr(SetState(HSM_JOB_STATE_FAILED));
  153. } else {
  154. WsbAssert(FALSE, E_UNEXPECTED);
  155. }
  156. }
  157. } WsbCatch(hr);
  158. Unlock();
  159. WsbTraceOut(OLESTR("CFsaTruncator::Cancel"), OLESTR("hr = <%ls> m_state = <%ls>"), WsbHrAsString(hr), FsaStateAsString( m_state ) );
  160. return(hr);
  161. }
  162. HRESULT
  163. CFsaTruncator::FinalConstruct(
  164. void
  165. )
  166. /*++
  167. Implements:
  168. CComObjectRoot::FinalConstruct().
  169. --*/
  170. {
  171. HRESULT hr = S_OK;
  172. WsbTraceIn(OLESTR("CFsaTruncator::FinalConstruct"), OLESTR(""));
  173. try {
  174. WsbAffirmHr(CWsbPersistStream::FinalConstruct());
  175. m_state = HSM_JOB_STATE_IDLE;
  176. m_priority = HSM_JOB_PRIORITY_NORMAL;
  177. m_threadHandle = 0;
  178. m_threadId = 0;
  179. m_threadHr = S_OK;
  180. m_maxFiles = DEFAULT_MAX_FILES_PER_RUN;
  181. m_runInterval = DEFAULT_RUN_INTERVAL;
  182. m_runId = 0;
  183. m_subRunId = 0;
  184. m_pSession = 0;
  185. m_SortOrder = FSA_SORT_PL_BY_ACCESS_TIME;
  186. m_keepRecallTime = WsbLLtoFT(WSB_FT_TICKS_PER_MINUTE);
  187. m_event = 0;
  188. } WsbCatch(hr);
  189. WsbTraceOut(OLESTR("CFsaTruncator::FinalConstruct"), OLESTR(""));
  190. return(hr);
  191. }
  192. HRESULT
  193. CFsaTruncator::FinalRelease(
  194. void
  195. )
  196. /*++
  197. Implements:
  198. CComObjectRoot::FinalRelease().
  199. --*/
  200. {
  201. HRESULT hr = S_OK;
  202. HSM_SYSTEM_STATE SysState;
  203. WsbTraceIn(OLESTR("CFsaTruncator::FinalRelease"), OLESTR(""));
  204. SysState.State = HSM_STATE_SHUTDOWN;
  205. ChangeSysState(&SysState);
  206. CWsbPersistStream::FinalRelease();
  207. // Free String members
  208. // Note: Member objects held in smart-pointers are freed when the
  209. // smart-pointer destructor is being called (as part of this object destruction)
  210. m_currentPath.Free();
  211. WsbTraceOut(OLESTR("CFsaTruncator::FinalRelease"), OLESTR(""));
  212. return(hr);
  213. }
  214. HRESULT
  215. CFsaTruncator::GetClassID(
  216. OUT CLSID* pClsid
  217. )
  218. /*++
  219. Implements:
  220. IPersist::GetClassID().
  221. --*/
  222. {
  223. HRESULT hr = S_OK;
  224. WsbTraceIn(OLESTR("CFsaTruncator::GetClassID"), OLESTR(""));
  225. try {
  226. WsbAssert(0 != pClsid, E_POINTER);
  227. *pClsid = CLSID_CFsaTruncatorNTFS;
  228. } WsbCatch(hr);
  229. WsbTraceOut(OLESTR("CFsaTruncator::GetClassID"), OLESTR("hr = <%ls>, CLSID = <%ls>"), WsbHrAsString(hr), WsbGuidAsString(*pClsid));
  230. return(hr);
  231. }
  232. HRESULT
  233. CFsaTruncator::GetKeepRecallTime(
  234. OUT FILETIME* pTime
  235. )
  236. /*++
  237. Implements:
  238. IFsaTruncator::GetKeepRecallTime().
  239. --*/
  240. {
  241. HRESULT hr = S_OK;
  242. WsbTraceIn(OLESTR("CFsaTruncator::GetKeepRecallTime"), OLESTR(""));
  243. try {
  244. WsbAssert(0 != pTime, E_POINTER);
  245. *pTime = m_keepRecallTime;
  246. } WsbCatch(hr);
  247. WsbTraceOut(OLESTR("CFsaTruncator::GetKeepRecallTime"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  248. return(hr);
  249. }
  250. HRESULT
  251. CFsaTruncator::GetMaxFilesPerRun(
  252. OUT LONGLONG* pMaxFiles
  253. )
  254. /*++
  255. Implements:
  256. IFsaTruncator::GetMaxFilesPerRun().
  257. --*/
  258. {
  259. HRESULT hr = S_OK;
  260. WsbTraceIn(OLESTR("CFsaTruncator::GetMaxFilesPerRun"), OLESTR(""));
  261. try {
  262. WsbAssert(0 != pMaxFiles, E_POINTER);
  263. *pMaxFiles = m_maxFiles;
  264. } WsbCatch(hr);
  265. WsbTraceOut(OLESTR("CFsaTruncator::GetMaxFilesPerRun"), OLESTR("hr = <%ls> maxFiles = <%ls>"), WsbHrAsString(hr), WsbLonglongAsString( *pMaxFiles ) );
  266. return(hr);
  267. }
  268. HRESULT
  269. CFsaTruncator::GetPremigratedSortOrder(
  270. OUT FSA_PREMIGRATED_SORT_ORDER* pSortOrder
  271. )
  272. /*++
  273. Implements:
  274. IFsaTruncator::GetPremigratedSortOrder().
  275. --*/
  276. {
  277. HRESULT hr = S_OK;
  278. WsbTraceIn(OLESTR("CFsaTruncator::GetPremigratedSortOrder"), OLESTR(""));
  279. try {
  280. WsbAssert(0 != pSortOrder, E_POINTER);
  281. *pSortOrder = m_SortOrder;
  282. } WsbCatch(hr);
  283. WsbTraceOut(OLESTR("CFsaTruncator::GetPremigratedSortOrder"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  284. return(hr);
  285. }
  286. HRESULT
  287. CFsaTruncator::GetRunInterval(
  288. OUT ULONG* pMilliseconds
  289. )
  290. /*++
  291. Implements:
  292. IFsaTruncator::GetRunInterval().
  293. --*/
  294. {
  295. HRESULT hr = S_OK;
  296. WsbTraceIn(OLESTR("CFsaTruncator::GetRunInterval"), OLESTR(""));
  297. try {
  298. WsbAssert(0 != pMilliseconds, E_POINTER);
  299. *pMilliseconds = m_runInterval;
  300. } WsbCatch(hr);
  301. WsbTraceOut(OLESTR("CFsaTruncator::GetRunInterval"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  302. return(hr);
  303. }
  304. HRESULT
  305. CFsaTruncator::GetSession(
  306. OUT IHsmSession** ppSession
  307. )
  308. /*++
  309. Implements:
  310. IFsaTruncator::GetSession().
  311. --*/
  312. {
  313. HRESULT hr = S_OK;
  314. WsbTraceIn(OLESTR("CFsaTruncator::GetSession"), OLESTR(""));
  315. try {
  316. WsbAssert(0 != ppSession, E_POINTER);
  317. *ppSession = m_pSession;
  318. if (m_pSession != 0) {
  319. m_pSession->AddRef();
  320. }
  321. } WsbCatch(hr);
  322. WsbTraceOut(OLESTR("CFsaTruncator::GetSession"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  323. return(hr);
  324. }
  325. HRESULT
  326. CFsaTruncator::GetSizeMax(
  327. OUT ULARGE_INTEGER* pSize
  328. )
  329. /*++
  330. Implements:
  331. IPersistStream::GetSizeMax().
  332. --*/
  333. {
  334. HRESULT hr = S_OK;
  335. WsbTraceIn(OLESTR("CFsaTruncator::GetSizeMax"), OLESTR(""));
  336. try {
  337. WsbAssert(0 != pSize, E_POINTER);
  338. // Determine the size for a rule with no criteria.
  339. pSize->QuadPart = WsbPersistSizeOf(LONGLONG) + 3 * WsbPersistSizeOf(ULONG) + WsbPersistSizeOf(FILETIME);
  340. } WsbCatch(hr);
  341. WsbTraceOut(OLESTR("CFsaTruncator::GetSizeMax"), OLESTR("hr = <%ls>, Size = <%ls>"), WsbHrAsString(hr), WsbPtrToUliAsString(pSize));
  342. return(hr);
  343. }
  344. HRESULT
  345. CFsaTruncator::KickStart(
  346. void
  347. )
  348. /*++
  349. Implements:
  350. IFsaTruncator:KickStart
  351. Data was just moved for this volume - wake up the truncator thread in case we need space.
  352. --*/
  353. {
  354. HRESULT hr = S_OK;
  355. CComPtr<IFsaResource> pResource;
  356. ULONG freeLevel;
  357. ULONG hsmLevel;
  358. WsbTraceIn(OLESTR("CFsaTruncator::KickStart"), OLESTR(""));
  359. try {
  360. if (m_pSession) {
  361. WsbAffirmHr(m_pSession->GetResource(&pResource));
  362. // If the truncator is running and the resource does not have enough free space
  363. // check to see if the resource is over the threshold and truncation is needed.
  364. WsbAffirmHr(pResource->GetHsmLevel(&hsmLevel));
  365. WsbAffirmHr(pResource->GetFreeLevel(&freeLevel));
  366. if (freeLevel < hsmLevel) {
  367. WsbTrace(OLESTR("CFsaTruncator::KickStarting truncator.\n"));
  368. SetEvent(m_event);
  369. }
  370. }
  371. } WsbCatch(hr);
  372. WsbTraceOut(OLESTR("CFsaTruncator::KickStart"), OLESTR("hr = <%ls>>"), WsbHrAsString(hr));
  373. return(hr);
  374. }
  375. HRESULT
  376. CFsaTruncator::Load(
  377. IN IStream* pStream
  378. )
  379. /*++
  380. Implements:
  381. IPersistStream::Load().
  382. --*/
  383. {
  384. HRESULT hr = S_OK;
  385. WsbTraceIn(OLESTR("CFsaTruncator::Load"), OLESTR(""));
  386. try {
  387. USHORT us_tmp;
  388. ULONG ul_tmp;
  389. WsbAssert(0 != pStream, E_POINTER);
  390. // Do the easy stuff, but make sure that this order matches the order
  391. // in the save method.
  392. WsbAffirmHr(WsbLoadFromStream(pStream, &ul_tmp));
  393. m_priority = static_cast<HSM_JOB_PRIORITY>(ul_tmp);
  394. WsbAffirmHr(WsbLoadFromStream(pStream, &m_maxFiles));
  395. WsbAffirmHr(WsbLoadFromStream(pStream, &m_runInterval));
  396. WsbAffirmHr(WsbLoadFromStream(pStream, &m_runId));
  397. WsbAffirmHr(WsbLoadFromStream(pStream, &m_keepRecallTime));
  398. WsbAffirmHr(WsbLoadFromStream(pStream, &us_tmp));
  399. m_SortOrder = static_cast<FSA_PREMIGRATED_SORT_ORDER>(us_tmp);
  400. // Check to see if values for maxFiles and runInterval are specified in the registry.
  401. // If so, use these values instead of the ones stored.
  402. {
  403. DWORD sizeGot;
  404. CWsbStringPtr tmpString;
  405. WsbAffirmHr(tmpString.Alloc(256));
  406. if (SUCCEEDED(WsbGetRegistryValueString(NULL, FSA_REGISTRY_PARMS, FSA_REGISTRY_TRUNCATOR_INTERVAL, tmpString, 256, &sizeGot))) {
  407. m_runInterval = 1000 * wcstoul(tmpString, NULL, 10);
  408. } else {
  409. m_runInterval = DEFAULT_RUN_INTERVAL;
  410. }
  411. if (SUCCEEDED(WsbGetRegistryValueString(NULL, FSA_REGISTRY_PARMS, FSA_REGISTRY_TRUNCATOR_FILES, tmpString, 256, &sizeGot))) {
  412. m_maxFiles = (LONGLONG) wcstoul(tmpString, NULL, 10);
  413. } else {
  414. m_maxFiles = DEFAULT_MAX_FILES_PER_RUN;
  415. }
  416. }
  417. } WsbCatch(hr);
  418. WsbTraceOut(OLESTR("CFsaTruncator::Load"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  419. return(hr);
  420. }
  421. HRESULT
  422. CFsaTruncator::LowerPriority(
  423. void
  424. )
  425. /*++
  426. --*/
  427. {
  428. HRESULT hr = S_OK;
  429. WsbTraceIn(OLESTR("CFsaTruncator::LowerPriority"), OLESTR(""));
  430. try {
  431. WsbAssert(0 != m_threadHandle, E_UNEXPECTED);
  432. WsbAssert(m_pSession != 0, E_UNEXPECTED);
  433. switch(m_priority) {
  434. case HSM_JOB_PRIORITY_IDLE:
  435. WsbAffirm(FALSE, E_UNEXPECTED);
  436. break;
  437. case HSM_JOB_PRIORITY_LOWEST:
  438. WsbAffirmStatus(SetThreadPriority(m_threadHandle, THREAD_PRIORITY_IDLE));
  439. m_priority = HSM_JOB_PRIORITY_IDLE;
  440. break;
  441. case HSM_JOB_PRIORITY_LOW:
  442. WsbAffirmStatus(SetThreadPriority(m_threadHandle, THREAD_PRIORITY_LOWEST));
  443. m_priority = HSM_JOB_PRIORITY_LOWEST;
  444. break;
  445. case HSM_JOB_PRIORITY_NORMAL:
  446. WsbAffirmStatus(SetThreadPriority(m_threadHandle, THREAD_PRIORITY_BELOW_NORMAL));
  447. m_priority = HSM_JOB_PRIORITY_LOW;
  448. break;
  449. case HSM_JOB_PRIORITY_HIGH:
  450. WsbAffirmStatus(SetThreadPriority(m_threadHandle, THREAD_PRIORITY_NORMAL));
  451. m_priority = HSM_JOB_PRIORITY_NORMAL;
  452. break;
  453. case HSM_JOB_PRIORITY_HIGHEST:
  454. WsbAffirmStatus(SetThreadPriority(m_threadHandle, THREAD_PRIORITY_ABOVE_NORMAL));
  455. m_priority = HSM_JOB_PRIORITY_HIGH;
  456. break;
  457. default:
  458. case HSM_JOB_PRIORITY_CRITICAL:
  459. WsbAffirmStatus(SetThreadPriority(m_threadHandle, THREAD_PRIORITY_HIGHEST));
  460. m_priority = HSM_JOB_PRIORITY_HIGHEST;
  461. break;
  462. }
  463. WsbAffirmHr(m_pSession->ProcessPriority(HSM_JOB_PHASE_SCAN, m_priority));
  464. } WsbCatch(hr);
  465. WsbTraceOut(OLESTR("CFsaTruncator::LowerPriority"), OLESTR("hr = <%ls>"), WsbHrAsString(hr) );
  466. return(hr);
  467. }
  468. HRESULT
  469. CFsaTruncator::Pause(
  470. void
  471. )
  472. /*++
  473. Implements:
  474. IFsaTruncator::Pause().
  475. --*/
  476. {
  477. HRESULT hr = S_OK;
  478. WsbTraceIn(OLESTR("CFsaTruncator::Pause"), OLESTR("state = %ls"),
  479. FsaStateAsString(m_state));
  480. // Lock this object to avoid having the state change between testing its value
  481. // and setting it to a new value
  482. Lock();
  483. try {
  484. // If we are running, then suspend the thread.
  485. WsbAssert(HSM_JOB_STATE_ACTIVE == m_state, E_UNEXPECTED);
  486. // Set the state & the active thread will not do any work
  487. WsbAffirmHr(SetState(HSM_JOB_STATE_PAUSING));
  488. // We would like to wait until the thread is really inactive, but that's
  489. // hard to tell because it could be in a sleep interval
  490. } WsbCatch(hr);
  491. Unlock();
  492. WsbTraceOut(OLESTR("CFsaTruncator::Pause"), OLESTR("hr = <%ls>"), WsbHrAsString(hr) );
  493. return(hr);
  494. }
  495. HRESULT
  496. CFsaTruncator::ProcessSessionEvent(
  497. IN IHsmSession* pSession,
  498. IN HSM_JOB_PHASE phase,
  499. IN HSM_JOB_EVENT event
  500. )
  501. /*++
  502. --*/
  503. {
  504. HRESULT hr = S_OK;
  505. WsbTraceIn(OLESTR("CFsaTruncator::ProcessSessionEvent"), OLESTR(""));
  506. try {
  507. WsbAssert(0 != pSession, E_POINTER);
  508. // If the phase applies to use (SCAN or ALL), then do any work required by the
  509. // event.
  510. if ((HSM_JOB_PHASE_ALL == phase) || (HSM_JOB_PHASE_SCAN == phase)) {
  511. switch(event) {
  512. case HSM_JOB_EVENT_SUSPEND:
  513. case HSM_JOB_EVENT_CANCEL:
  514. case HSM_JOB_EVENT_FAIL:
  515. WsbAffirmHr(Cancel(event));
  516. break;
  517. case HSM_JOB_EVENT_PAUSE:
  518. WsbAffirmHr(Pause());
  519. break;
  520. case HSM_JOB_EVENT_RESUME:
  521. WsbAffirmHr(Resume());
  522. break;
  523. case HSM_JOB_EVENT_RAISE_PRIORITY:
  524. WsbAffirmHr(RaisePriority());
  525. break;
  526. case HSM_JOB_EVENT_LOWER_PRIORITY:
  527. WsbAffirmHr(LowerPriority());
  528. break;
  529. default:
  530. case HSM_JOB_EVENT_START:
  531. WsbAssert(FALSE, E_UNEXPECTED);
  532. break;
  533. }
  534. }
  535. } WsbCatch(hr);
  536. WsbTraceOut(OLESTR("CFsaTruncator::ProcessSessionEvent"), OLESTR("hr = <%ls>"), WsbHrAsString(hr) );
  537. return(S_OK);
  538. }
  539. HRESULT
  540. CFsaTruncator::RaisePriority(
  541. void
  542. )
  543. /*++
  544. --*/
  545. {
  546. HRESULT hr = S_OK;
  547. try {
  548. WsbAssert(0 != m_threadHandle, E_UNEXPECTED);
  549. WsbAssert(m_pSession != 0, E_UNEXPECTED);
  550. switch(m_priority) {
  551. case HSM_JOB_PRIORITY_IDLE:
  552. WsbAffirmStatus(SetThreadPriority(m_threadHandle, THREAD_PRIORITY_LOWEST));
  553. m_priority = HSM_JOB_PRIORITY_LOWEST;
  554. break;
  555. case HSM_JOB_PRIORITY_LOWEST:
  556. WsbAffirmStatus(SetThreadPriority(m_threadHandle, THREAD_PRIORITY_BELOW_NORMAL));
  557. m_priority = HSM_JOB_PRIORITY_LOW;
  558. break;
  559. case HSM_JOB_PRIORITY_LOW:
  560. WsbAffirmStatus(SetThreadPriority(m_threadHandle, THREAD_PRIORITY_NORMAL));
  561. m_priority = HSM_JOB_PRIORITY_NORMAL;
  562. break;
  563. case HSM_JOB_PRIORITY_NORMAL:
  564. WsbAffirmStatus(SetThreadPriority(m_threadHandle, THREAD_PRIORITY_ABOVE_NORMAL));
  565. m_priority = HSM_JOB_PRIORITY_HIGH;
  566. break;
  567. case HSM_JOB_PRIORITY_HIGH:
  568. WsbAffirmStatus(SetThreadPriority(m_threadHandle, THREAD_PRIORITY_HIGHEST));
  569. m_priority = HSM_JOB_PRIORITY_HIGHEST;
  570. break;
  571. case HSM_JOB_PRIORITY_HIGHEST:
  572. WsbAffirmStatus(SetThreadPriority(m_threadHandle, THREAD_PRIORITY_TIME_CRITICAL));
  573. m_priority = HSM_JOB_PRIORITY_CRITICAL;
  574. break;
  575. default:
  576. case HSM_JOB_PRIORITY_CRITICAL:
  577. WsbAffirm(FALSE, E_UNEXPECTED);
  578. break;
  579. }
  580. WsbAffirmHr(m_pSession->ProcessPriority(HSM_JOB_PHASE_SCAN, m_priority));
  581. } WsbCatch(hr);
  582. return(hr);
  583. }
  584. HRESULT
  585. CFsaTruncator::Resume(
  586. void
  587. )
  588. /*++
  589. Implements:
  590. IFsaTruncator::Resume().
  591. --*/
  592. {
  593. HRESULT hr = S_OK;
  594. WsbTraceIn(OLESTR("CFsaTruncator::Resume"), OLESTR("state = %ls"),
  595. FsaStateAsString(m_state));
  596. // Lock this object to avoid having the state change between testing its value
  597. // and setting it to a new value
  598. Lock();
  599. try {
  600. // We should only see a resume from a paused state, so ignore the resume if we are
  601. // in some other state. NOTE: This used to be an assert, but it scared people since it
  602. // can occur occassionally.
  603. if ((HSM_JOB_STATE_PAUSING == m_state) || (HSM_JOB_STATE_PAUSED == m_state)) {
  604. WsbAffirmHr(SetState(HSM_JOB_STATE_ACTIVE));
  605. }
  606. } WsbCatch(hr);
  607. Unlock();
  608. WsbTraceOut(OLESTR("CFsaTruncator::Resume"), OLESTR("hr = <%ls>"), WsbHrAsString(hr) );
  609. return(hr);
  610. }
  611. HRESULT
  612. CFsaTruncator::Save(
  613. IN IStream* pStream,
  614. IN BOOL clearDirty
  615. )
  616. /*++
  617. Implements:
  618. IPersistStream::Save().
  619. --*/
  620. {
  621. HRESULT hr = S_OK;
  622. WsbTraceIn(OLESTR("CFsaTruncator::Save"), OLESTR("clearDirty = <%ls>"), WsbBoolAsString(clearDirty));
  623. try {
  624. WsbAssert(0 != pStream, E_POINTER);
  625. // Do the easy stuff, but make sure that this order matches the order
  626. // in the save method.
  627. WsbAffirmHr(WsbSaveToStream(pStream, static_cast<ULONG>(m_priority)));
  628. WsbAffirmHr(WsbSaveToStream(pStream, m_maxFiles));
  629. WsbAffirmHr(WsbSaveToStream(pStream, m_runInterval));
  630. WsbAffirmHr(WsbSaveToStream(pStream, m_runId));
  631. WsbAffirmHr(WsbSaveToStream(pStream, m_keepRecallTime));
  632. WsbAffirmHr(WsbSaveToStream(pStream, static_cast<USHORT>(m_SortOrder)));
  633. // If we got it saved and we were asked to clear the dirty bit, then
  634. // do so now.
  635. if (clearDirty) {
  636. m_isDirty = FALSE;
  637. }
  638. } WsbCatch(hr);
  639. WsbTraceOut(OLESTR("CFsaTruncator::Save"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  640. return(hr);
  641. }
  642. HRESULT
  643. CFsaTruncator::SetKeepRecallTime(
  644. IN FILETIME time
  645. )
  646. /*++
  647. Implements:
  648. IFsaTruncator::SetKeepRecallTime().
  649. --*/
  650. {
  651. WsbTraceIn(OLESTR("CFsaTruncator::SetKeepRecallTime"), OLESTR(""));
  652. m_keepRecallTime = time;
  653. WsbTraceOut(OLESTR("CFsaTruncator::SetKeepRecallTime"), OLESTR("hr = <%ls>"), WsbHrAsString(S_OK));
  654. return(S_OK);
  655. }
  656. HRESULT
  657. CFsaTruncator::SetMaxFilesPerRun(
  658. IN LONGLONG maxFiles
  659. )
  660. /*++
  661. Implements:
  662. IFsaTruncator::SetMaxFilesPerRun().
  663. --*/
  664. {
  665. WsbTraceIn(OLESTR("CFsaTruncator::SetMaxFilesPerRun"), OLESTR(""));
  666. m_maxFiles = maxFiles;
  667. WsbTraceOut(OLESTR("CFsaTruncator::SetMaxFilesPerRun"), OLESTR("hr = <%ls>"), WsbHrAsString(S_OK));
  668. return(S_OK);
  669. }
  670. HRESULT
  671. CFsaTruncator::SetPremigratedSortOrder(
  672. IN FSA_PREMIGRATED_SORT_ORDER SortOrder
  673. )
  674. /*++
  675. Implements:
  676. IFsaTruncator::SetSortOrder().
  677. --*/
  678. {
  679. HRESULT hr = S_OK;
  680. WsbTraceIn(OLESTR("CFsaTruncator::SetPremigratedSortOrder"), OLESTR("SortOrder = <%ls>"), FsaSortOrderAsString( SortOrder ) );
  681. // This key has not been implmented yet.
  682. if (FSA_SORT_PL_BY_SIZE_AND_TIME == SortOrder) {
  683. hr = E_NOTIMPL;
  684. } else {
  685. m_SortOrder = SortOrder;
  686. }
  687. WsbTraceOut(OLESTR("CFsaTruncator::SetPremigratedSortOrder"), OLESTR("hr = <%ls> m_SortOrder = <%ls>"), WsbHrAsString(S_OK) , FsaSortOrderAsString( m_SortOrder ) );
  688. return(hr);
  689. }
  690. HRESULT
  691. CFsaTruncator::SetRunInterval(
  692. IN ULONG milliseconds
  693. )
  694. /*++
  695. Implements:
  696. IFsaTruncator::SetRunInterval().
  697. --*/
  698. {
  699. BOOL DoKick = FALSE;
  700. WsbTraceIn(OLESTR("CFsaTruncator::SetRunInterval"), OLESTR("milliseconds = <%ls>"), WsbPtrToUlongAsString( &milliseconds ) );
  701. if (milliseconds < m_runInterval) {
  702. DoKick = TRUE;
  703. }
  704. m_runInterval = milliseconds;
  705. // Wake up the Truncator if the interval has decreased
  706. if (DoKick) {
  707. KickStart();
  708. }
  709. WsbTraceOut(OLESTR("CFsaTruncator::SetRunInterval"), OLESTR("hr = <%ls> m_runInterval = <%ls>"), WsbHrAsString(S_OK), WsbPtrToUlongAsString( &m_runInterval ) );
  710. return(S_OK);
  711. }
  712. HRESULT
  713. CFsaTruncator::SetState(
  714. IN HSM_JOB_STATE state
  715. )
  716. /*++
  717. --*/
  718. {
  719. HRESULT hr = S_OK;
  720. BOOL bLog = FALSE;
  721. WsbTraceIn(OLESTR("CFsaTruncator::SetState"), OLESTR("state = <%ls>"), FsaStateAsString( state ) );
  722. // Change the state and report the change to the session.
  723. Lock();
  724. m_state = state;
  725. Unlock();
  726. hr = m_pSession->ProcessState(HSM_JOB_PHASE_SCAN, m_state, m_currentPath, bLog);
  727. WsbTraceOut(OLESTR("CFsaTruncator::SetState"), OLESTR("hr = <%ls> m_state = <%ls>"), WsbHrAsString(hr), FsaStateAsString( m_state ) );
  728. return(hr);
  729. }
  730. HRESULT
  731. CFsaTruncator::ChangeSysState(
  732. IN OUT HSM_SYSTEM_STATE* pSysState
  733. )
  734. /*++
  735. Implements:
  736. IHsmSystemState::ChangeSysState().
  737. --*/
  738. {
  739. HRESULT hr = S_OK;
  740. WsbTraceIn(OLESTR("CFsaTruncator::ChangeSysState"), OLESTR("thread is %ls"),
  741. (m_threadHandle ? OLESTR("active") : OLESTR("inactive")));
  742. try {
  743. if (pSysState->State & HSM_STATE_SUSPEND) {
  744. if (HSM_JOB_STATE_ACTIVE == m_state) {
  745. Pause();
  746. }
  747. } else if (pSysState->State & HSM_STATE_RESUME) {
  748. if ((HSM_JOB_STATE_PAUSING == m_state) ||
  749. (HSM_JOB_STATE_PAUSED == m_state)) {
  750. Resume();
  751. }
  752. } else if (pSysState->State & HSM_STATE_SHUTDOWN) {
  753. // Make sure the thread is stopped
  754. if (m_threadHandle) {
  755. m_state = HSM_JOB_STATE_DONE;
  756. if (m_event) {
  757. SetEvent(m_event);
  758. }
  759. // Wait for the thread to end
  760. if (m_threadHandle) {
  761. WsbTrace(OLESTR("CFsaTruncator::ChangeSysState, waiting for truncator thread to end\n"));
  762. switch (WaitForSingleObject(m_threadHandle, 120000)) {
  763. case WAIT_FAILED:
  764. WsbTrace(OLESTR("CFsaTruncator::ChangeSysState, WaitforSingleObject returned error %lu\n"),
  765. GetLastError());
  766. break;
  767. case WAIT_TIMEOUT:
  768. WsbTrace(OLESTR("CFsaTruncator::ChangeSysState, timeout.\n"));
  769. break;
  770. default:
  771. break;
  772. }
  773. }
  774. // If the thread is still active, terminate it
  775. if (m_threadHandle) {
  776. WsbTrace(OLESTR("CFsaTruncator::ChangeSysState: calling TerminateThread\n"));
  777. if (!TerminateThread(m_threadHandle, 0)) {
  778. WsbTrace(OLESTR("CFsaTruncator::ChangeSysState: TerminateThread returned error %lu\n"),
  779. GetLastError());
  780. }
  781. }
  782. }
  783. if (m_event) {
  784. CloseHandle(m_event);
  785. m_event = 0;
  786. }
  787. }
  788. } WsbCatch(hr);
  789. WsbTraceOut(OLESTR("CFsaTruncator::ChangeSysState"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  790. return(hr);
  791. }
  792. HRESULT
  793. CFsaTruncator::Start(
  794. IFsaResource* pResource
  795. )
  796. /*++
  797. Implements:
  798. IFsaTruncator::Start().
  799. --*/
  800. {
  801. HRESULT hr = S_OK;
  802. CComPtr<IHsmSession> pSession;
  803. CComPtr<IConnectionPointContainer> pCPC;
  804. CComPtr<IConnectionPoint> pCP;
  805. CComPtr<IHsmSessionSinkEveryEvent> pSink;
  806. CWsbStringPtr name;
  807. WsbTraceIn(OLESTR("CFsaTruncator::Start"), OLESTR("m_state = <%ls>"), FsaStateAsString( m_state ) );
  808. try {
  809. if (0 == m_threadId) {
  810. //
  811. // If the thread is dead, start one.
  812. //
  813. // Make sure that we don't already have a session, and that we haven't started already.
  814. WsbAssert(m_pSession == 0, E_UNEXPECTED);
  815. WsbAssert( (HSM_JOB_STATE_IDLE == m_state) || (HSM_JOB_STATE_DONE == m_state) ||
  816. (HSM_JOB_STATE_CANCELLED == m_state) || (HSM_JOB_STATE_FAILED == m_state), E_UNEXPECTED);
  817. // Get the name for the session, increment the runId, and reset the subRunId.
  818. WsbAffirmHr(name.LoadFromRsc(_Module.m_hInst, IDS_FSA_TRUNCATOR_NAME));
  819. m_runId++;
  820. m_subRunId = 0;
  821. // Begin a Session.
  822. WsbAffirmHr(pResource->BeginSession(name, HSM_JOB_LOG_NONE, m_runId, m_subRunId, &pSession));
  823. m_pSession = pSession;
  824. // Ask the session to advise of every event.
  825. WsbAffirmHr(pSession->QueryInterface(IID_IConnectionPointContainer, (void**) &pCPC));
  826. WsbAffirmHr(pCPC->FindConnectionPoint(IID_IHsmSessionSinkEveryEvent, &pCP));
  827. WsbAffirmHr(((IUnknown*) (IFsaTruncator*) this)->QueryInterface(IID_IHsmSessionSinkEveryEvent, (void**) &pSink));
  828. WsbAffirmHr(pCP->Advise(pSink, &m_cookie));
  829. try {
  830. GUID rscId;
  831. CWsbStringPtr nameString;
  832. // Give the event a unique name, so that we can trace it
  833. // in a dump of open handles.
  834. if (0 == m_event) {
  835. WsbAffirmHr(pResource->GetIdentifier(&rscId));
  836. nameString = rscId;
  837. nameString.Prepend(OLESTR("Truncator Kicker for "));
  838. WsbAssertHandle(m_event = CreateEvent(NULL, FALSE, FALSE, nameString));
  839. }
  840. // Now that we have prepared, create the thread that will do the scanning!
  841. WsbAffirm((m_threadHandle = CreateThread(0, 0, FsaStartTruncator, (void*) this, 0, &m_threadId)) != 0, HRESULT_FROM_WIN32(GetLastError()));
  842. } WsbCatchAndDo(hr, SetState(HSM_JOB_STATE_FAILED););
  843. } else {
  844. // The thread is still alive, just keep it going. If it is in a state that would
  845. // cause it to exit, then make it active again.
  846. WsbAssert(m_pSession != 0, E_UNEXPECTED);
  847. if ((HSM_JOB_STATE_ACTIVE != m_state) && (HSM_JOB_STATE_PAUSING != m_state) &&
  848. (HSM_JOB_STATE_PAUSED != m_state) && (HSM_JOB_STATE_RESUMING != m_state)) {
  849. WsbAffirmHr(SetState(HSM_JOB_STATE_ACTIVE));
  850. }
  851. }
  852. } WsbCatch(hr);
  853. WsbTraceOut(OLESTR("CFsaTruncator::Start"), OLESTR("hr = <%ls> m_state = <%ls>"), WsbHrAsString(hr), FsaStateAsString( m_state ) );
  854. return(hr);
  855. }
  856. HRESULT
  857. CFsaTruncator::StartScan(
  858. void
  859. )
  860. /*++
  861. --*/
  862. {
  863. ULONG adjustedFreeLevel = 0;
  864. HRESULT hr = S_OK;
  865. HRESULT hr2;
  866. LONGLONG itemOffset;
  867. LONGLONG itemSize = 0;
  868. LONGLONG fileId;
  869. ULONG freeLevel;
  870. ULONG hsmLevel;
  871. BOOL skipFile;
  872. BOOL dummy;
  873. LONGLONG llLastTruncTime = 0;
  874. LONGLONG llRunIntervalTicks;
  875. FILETIME recallTime, currentTime, accessTime, criteriaTime, premRecAccessTime;
  876. LONGLONG totalVolumeSpace;
  877. CComPtr<IFsaResource> pResource;
  878. CComPtr<IFsaResourcePriv> pResourcePriv;
  879. CComPtr<IFsaScanItem> pScanItem;
  880. CComPtr<IFsaPremigratedRec> pPremRec;
  881. CComPtr<IConnectionPointContainer> pCPC;
  882. CComPtr<IConnectionPoint> pCP;
  883. try {
  884. WsbTrace(OLESTR("CFsaTruncator::StartScan - starting loop\n"));
  885. // Increment the ref count so this object (or its session) doesn't
  886. // get released before this thread ends
  887. ((IUnknown *)(IFsaTruncator *)this)->AddRef();
  888. WsbAssert(m_pSession != 0, E_POINTER);
  889. // The thread is running.
  890. WsbAffirmHr(SetState(HSM_JOB_STATE_ACTIVE));
  891. // Get the resource
  892. WsbAffirmHr(m_pSession->GetResource(&pResource));
  893. WsbAffirmHr(pResource->QueryInterface(IID_IFsaResourcePriv, (void**) &pResourcePriv));
  894. WsbAffirmHr(pResource->GetSizes(&totalVolumeSpace, NULL, NULL, NULL));
  895. // Start with the first path.
  896. while ((HSM_JOB_STATE_ACTIVE == m_state) || (HSM_JOB_STATE_PAUSING == m_state) ||
  897. (HSM_JOB_STATE_PAUSED == m_state) || (HSM_JOB_STATE_RESUMING == m_state)) {
  898. WsbTrace(OLESTR("CFsaTruncator::StartScan, top of outside while loop, state = <%ls>\n"),
  899. FsaStateAsString( m_state ) );
  900. // If the truncator is running and the resource does not have enough free space
  901. // check to see if the resource is over the threshold and truncation is needed.
  902. WsbAffirmHr(pResource->GetHsmLevel(&hsmLevel));
  903. WsbAffirmHr(pResource->GetFreeLevel(&freeLevel));
  904. // Because the truncation is asynchronous (FsaPostIt is sent to Engine for
  905. // verification and then returned to FSA for actual truncation), the
  906. // measured freeLevel may not be very accurate if there are truncations
  907. // pending. To compensate for this, we keep an adjustedFreeLevel which
  908. // attempts to take into account the pending truncates. We synchronize the
  909. // adjustedFreeLevel to the measured freeLevel the first time through and
  910. // after we have slept for a while (on the assumption that the pending
  911. // truncates have had time to be performed). This still leaves open the possiblility
  912. // that the measured freeLevel is wrong (because truncates are pending), but
  913. // should be an improvement over just using the measured freeLevel.
  914. llRunIntervalTicks = m_runInterval * (WSB_FT_TICKS_PER_SECOND / 1000);
  915. GetSystemTimeAsFileTime(&currentTime);
  916. if (0 == adjustedFreeLevel ||
  917. ((WsbFTtoLL(currentTime) - llLastTruncTime) > llRunIntervalTicks)) {
  918. adjustedFreeLevel = freeLevel;
  919. WsbTrace(OLESTR("CFsaTruncator::StartScan, resetting adjusted free level, RunInterval = %ls, time diff = %ls\n"),
  920. WsbQuickString(WsbLonglongAsString(llRunIntervalTicks)),
  921. WsbQuickString(WsbLonglongAsString(WsbFTtoLL(currentTime) - llLastTruncTime)));
  922. }
  923. WsbTrace(OLESTR("CFsaTruncator::StartScan, desired level = %u, free level = %u, adjusted free level = %u\n"),
  924. hsmLevel, freeLevel, adjustedFreeLevel);
  925. if (adjustedFreeLevel < hsmLevel && HSM_JOB_STATE_ACTIVE == m_state) {
  926. CComPtr<IWsbDbSession> pDbSession;
  927. CComPtr<IFsaPremigratedDb> pPremDb;
  928. // Open the premigration list, and set the order in which it will be scanned.
  929. WsbAffirmHr(pResourcePriv->GetPremigrated(IID_IFsaPremigratedDb,
  930. (void**) &pPremDb));
  931. WsbAffirmHr(pPremDb->Open(&pDbSession));
  932. try {
  933. WsbAffirmHr(pPremDb->GetEntity(pDbSession, PREMIGRATED_REC_TYPE, IID_IFsaPremigratedRec, (void**) &pPremRec));
  934. // Set the order to get items from the Premigrated List
  935. switch (m_SortOrder) {
  936. case FSA_SORT_PL_BY_SIZE:
  937. WsbAffirmHr(pPremRec->UseKey(PREMIGRATED_SIZE_KEY_TYPE));
  938. break;
  939. case FSA_SORT_PL_BY_PATH_NAME:
  940. // We use the BagId and offsets instead
  941. WsbAffirmHr(pPremRec->UseKey(PREMIGRATED_BAGID_OFFSETS_KEY_TYPE));
  942. break;
  943. case FSA_SORT_PL_BY_SIZE_AND_TIME:
  944. // We don't know how to handle this one yet
  945. WsbThrow(E_UNEXPECTED);
  946. break;
  947. case FSA_SORT_PL_BY_ACCESS_TIME:
  948. default:
  949. WsbAffirmHr(pPremRec->UseKey(PREMIGRATED_ACCESS_TIME_KEY_TYPE));
  950. break;
  951. }
  952. // Make a pass through the list of premigrated files until the
  953. // desired level has been reached. Some items that are on the
  954. // list may be in a state that causes them to be skipped, but left on the list.
  955. WsbAffirmHr(pPremRec->First());
  956. while ((adjustedFreeLevel < hsmLevel) && (HSM_JOB_STATE_ACTIVE == m_state)) {
  957. CComPtr<IFsaRecoveryRec> pRecRec;
  958. WsbTrace(OLESTR("CFsaTruncator::StartScan (top of inside while loop) desired level = %u, adjusted free level = %u\n"),
  959. hsmLevel, adjustedFreeLevel);
  960. try {
  961. skipFile = FALSE;
  962. //
  963. // Get the access time as recorded in the premigrated record
  964. // Note that the real access time cannot be older than the one
  965. // in the premigrated list but it can be newer
  966. //
  967. WsbAffirmHr(pPremRec->GetAccessTime(&premRecAccessTime));
  968. WsbAffirmHr(pResource->GetManageableItemAccessTime(&dummy, &criteriaTime));
  969. if (WsbCompareFileTimes(premRecAccessTime, criteriaTime, TRUE, FALSE) < 0 ) {
  970. if (pPremRec->IsWaitingForClose() == S_FALSE) {
  971. //
  972. // Can skip the current file but NOT break out of the loop since
  973. // files with access time old enough and WaitingForClose flag set
  974. // may still exists in the list
  975. //
  976. skipFile = TRUE;
  977. } else {
  978. //
  979. // The access time in the prem. rec is within the window.
  980. // This means there aren't any other records which are outside the
  981. // user-desired last access window. So break out
  982. //
  983. WsbTrace(OLESTR("CFsaTruncator::StartScan: breaking out of auto-truncator, encountered item with access time not within criteria\n"));
  984. hr = WSB_E_NOTFOUND;
  985. break;
  986. }
  987. }
  988. // Get information about the file that could be truncated.
  989. WsbAffirmHr(pPremRec->GetFileId(&fileId));
  990. WsbAffirmHr(pPremRec->GetOffset(&itemOffset));
  991. WsbAffirmHr(pPremRec->GetSize(&itemSize));
  992. m_currentPath.Free();
  993. WsbAffirmHr(pPremRec->GetPath(&m_currentPath, 0));
  994. WsbAffirmHr(pPremRec->GetRecallTime(&recallTime));
  995. GetSystemTimeAsFileTime(&currentTime);
  996. // Make sure that this file wasn't recently recalled. For now,
  997. // this will check for 1 minute.
  998. if ((! skipFile) &&
  999. ( (pPremRec->IsWaitingForClose() == S_FALSE) ||
  1000. ((WsbFTtoLL(currentTime) > WsbFTtoLL(recallTime)) &&
  1001. (WsbCompareFileTimes(recallTime, m_keepRecallTime, TRUE, FALSE) >= 0)) )) {
  1002. hr = pResource->FindFileId(fileId, m_pSession, &pScanItem);
  1003. if (hr == WSB_E_NOTFOUND) {
  1004. //
  1005. // The file does not exist anymore - remove the record from the list.
  1006. //
  1007. WsbAffirmHr(pDbSession->TransactionBegin());
  1008. try {
  1009. // Make sure the record is still in the DB
  1010. WsbAffirmHr(pPremRec->FindEQ());
  1011. WsbAffirmHr(pPremRec->Remove());
  1012. WsbAffirmHr(pResourcePriv->RemovePremigratedSize(itemSize));
  1013. } WsbCatch(hr);
  1014. WsbAffirmHr(pDbSession->TransactionEnd());
  1015. WsbThrow(hr);
  1016. } else if (hr != S_OK) {
  1017. //
  1018. // Any other error is unexpected - log it and continue
  1019. //
  1020. WsbLogEvent(FSA_E_ACCESS_ERROR, 0, NULL, m_currentPath, WsbHrAsString(hr), NULL);
  1021. WsbThrow(hr);
  1022. }
  1023. //
  1024. // Verify that the file is still in a premigrated state
  1025. //
  1026. if (S_OK == pScanItem->IsPremigrated(itemOffset, itemSize)) {
  1027. WsbAffirmHr(pScanItem->GetAccessTime(&accessTime));
  1028. //
  1029. // accessTime is the last access time for the file
  1030. // criteriaTime is the 'not accessed in so many ticks' criteria for truncating
  1031. // the file.
  1032. // So if (currentTime - accessTime) >= criteriaTime, then the file is ok to be truncated
  1033. //
  1034. if (WsbCompareFileTimes(accessTime, criteriaTime, TRUE, FALSE) >=0 ) {
  1035. //
  1036. // The file was not accessed within the last access window
  1037. //
  1038. WsbTrace(OLESTR("CFsaTruncator::StartScan, truncating file <%ls>\n"),
  1039. (WCHAR *)m_currentPath);
  1040. // Try to truncate the file.
  1041. try {
  1042. // Create and save a recovery record in case something goes wrong
  1043. WsbAffirmHr(pPremDb->GetEntity(pDbSession, RECOVERY_REC_TYPE, IID_IFsaRecoveryRec, (void**) &pRecRec));
  1044. WsbAffirmHr(pRecRec->SetPath(m_currentPath));
  1045. // If the record already exists rewrite it, otherwise create a new record.
  1046. hr2 = pRecRec->FindEQ();
  1047. if (WSB_E_NOTFOUND == hr2) {
  1048. hr2 = S_OK;
  1049. WsbAffirmHr(pRecRec->MarkAsNew());
  1050. } else if (FAILED(hr2)) {
  1051. WsbThrow(hr2);
  1052. }
  1053. WsbAffirmHr(pRecRec->SetFileId(fileId));
  1054. WsbAffirmHr(pRecRec->SetOffsetSize(itemOffset, itemSize));
  1055. WsbAffirmHr(pRecRec->SetStatus(FSA_RECOVERY_FLAG_TRUNCATING));
  1056. WsbAffirmHr(pRecRec->Write());
  1057. //
  1058. // Set the waiting for close flag to prevent this file
  1059. // from being selected again while the engine is
  1060. // processing the truncate. Set the recall time to
  1061. // now plus 1 hour so we are sure not to retry this
  1062. // until we have had a chance to truncate it.
  1063. //
  1064. WsbAffirmHr(pPremRec->SetIsWaitingForClose(TRUE));
  1065. WsbAffirmHr(pPremRec->SetRecallTime(WsbLLtoFT(WsbFTtoLL(currentTime) + WSB_FT_TICKS_PER_HOUR)));
  1066. hr2 = pPremRec->Write();
  1067. // Special code to deal with a problem that has been seen
  1068. // but isn't understood
  1069. if (WSB_E_IDB_PRIMARY_KEY_CHANGED == hr2) {
  1070. WsbAffirmHr(pPremRec->Remove());
  1071. WsbAffirmHr(pResourcePriv->RemovePremigratedSize(itemSize));
  1072. // Ignore result from DeletePlaceholder since there's nothing we
  1073. // can do anyway.
  1074. pScanItem->DeletePlaceholder(itemOffset, itemSize);
  1075. WsbThrow(FSA_E_SKIPPED);
  1076. } else {
  1077. WsbAffirmHr(hr2);
  1078. }
  1079. //
  1080. // Set IsWaitingForClose back to false so that the FindGt done later gets the next record.
  1081. // This affects the in memory record only and not the persisted record.
  1082. //
  1083. WsbAffirmHr(pPremRec->SetIsWaitingForClose(FALSE));
  1084. WsbAffirmHr(pScanItem->Truncate(itemOffset, itemSize));
  1085. llLastTruncTime = WsbFTtoLL(currentTime);
  1086. // Add the file size to the adjustedFreeLevel so we know when to
  1087. // stop doing truncations. Unfortunately, the itemSize is in
  1088. // bytes but adjustedFreeLevl is a fixed-point percentage so we
  1089. // have to do a calculation to convert the itemSize
  1090. adjustedFreeLevel += (ULONG) (((double)itemSize /
  1091. (double)totalVolumeSpace) *
  1092. (double)FSA_HSMLEVEL_100);
  1093. } WsbCatchAndDo(hr,
  1094. // Do we need to skip this file for the time being?
  1095. if (FSA_E_SKIPPED == hr) {
  1096. // Do nothing
  1097. } else if ((FSA_E_ITEMCHANGED != hr) && (FSA_E_NOTMANAGED != hr)) {
  1098. // Something unexpected happened, so report the error.
  1099. WsbAffirmHr(m_pSession->ProcessHr(HSM_JOB_PHASE_FSA_ACTION, 0, 0, hr));
  1100. }
  1101. );
  1102. } else {
  1103. //
  1104. // File is premigrated, but skipped because the last access was too recent
  1105. //
  1106. WsbTrace(OLESTR("CFsaTruncator::StartScan, skipping file <%ls> which is premigrated but last access is too recent\n"),
  1107. (WCHAR *)m_currentPath);
  1108. hr = FSA_E_SKIPPED;
  1109. //
  1110. // Update the access time in the db for this file
  1111. //
  1112. WsbAffirmHr(pPremRec->SetAccessTime(accessTime));
  1113. //
  1114. // Commit this
  1115. //
  1116. WsbAffirmHr(pPremRec->Write());
  1117. //
  1118. // Revert the in-memory accessTime to the old access time to
  1119. // let the enumeration continue (so that FindGT will fetch the next record)
  1120. //
  1121. WsbAffirmHr(pPremRec->SetAccessTime(premRecAccessTime));
  1122. }
  1123. } else {
  1124. //
  1125. // If the file is no longer managed by HSM or truncated (may have been modified
  1126. // after it was premigrated) - we remove the record from the list.
  1127. // Note that if we reached this else close, the condition below should be TRUE
  1128. //
  1129. if ( (S_FALSE == pScanItem->IsManaged(itemOffset, itemSize)) ||
  1130. (S_OK == pScanItem->IsTruncated(itemOffset, itemSize)) ) {
  1131. WsbAffirmHr(pDbSession->TransactionBegin());
  1132. try {
  1133. // Make sure the record is still in the DB
  1134. WsbAffirmHr(pPremRec->FindEQ());
  1135. WsbAffirmHr(pPremRec->Remove());
  1136. WsbAffirmHr(pResourcePriv->RemovePremigratedSize(itemSize));
  1137. } WsbCatch(hr);
  1138. WsbAffirmHr(pDbSession->TransactionEnd());
  1139. // Ignore hr of the removal itself (truncated files may have been removed by another thread)
  1140. hr = WSB_E_NOTFOUND;
  1141. WsbThrow(hr);
  1142. }
  1143. }
  1144. // Tell the session we saw the file, and whether we were able to truncate it.
  1145. WsbAffirmHr(m_pSession->ProcessItem(HSM_JOB_PHASE_FSA_ACTION, HSM_JOB_ACTION_TRUNCATE, pScanItem, hr));
  1146. // Don't let this errors stop us from continuing to process the list.
  1147. hr = S_OK;
  1148. } else {
  1149. //
  1150. // File is premigrated, but skipped because the last access was too recent or
  1151. // because it was recalled recently
  1152. //
  1153. WsbTrace(OLESTR("CFsaTruncator::StartScan, skipping file <%ls> since its last access time is too recent or recently recalled\n"),
  1154. (WCHAR *)m_currentPath);
  1155. hr = FSA_E_SKIPPED;
  1156. }
  1157. } WsbCatchAndDo(hr,
  1158. if (WSB_E_NOTFOUND != hr) {
  1159. m_pSession->ProcessHr(HSM_JOB_PHASE_FSA_ACTION, __FILE__, __LINE__, hr);
  1160. }
  1161. // Don't let this errors stop us from continuing to process the list.
  1162. hr = S_OK;
  1163. );
  1164. // If item is skipped - set hr to OK (this is not really an error)
  1165. if (FSA_E_SKIPPED == hr) {
  1166. hr = S_OK;
  1167. }
  1168. // Remove recovery record
  1169. if (pRecRec) {
  1170. WsbAffirmHr(pRecRec->FindEQ());
  1171. WsbAffirmHr(pRecRec->Remove());
  1172. pRecRec = NULL;
  1173. }
  1174. // Get the desired level again in case it changed
  1175. WsbAffirmHr(pResource->GetHsmLevel(&hsmLevel));
  1176. // Free the scan item.
  1177. pScanItem = 0;
  1178. // Whether we removed or skipped the item, go on to the next item.
  1179. WsbAffirmHr(pPremRec->FindGT());
  1180. WsbTrace(OLESTR("CFsaTruncator::StartScan, bottom of inside while loop, state = <%ls>\n"),
  1181. FsaStateAsString( m_state ) );
  1182. } // inner while
  1183. } WsbCatch(hr);
  1184. // Free the premigrated record object and close the data base.
  1185. try {
  1186. pPremRec = 0;
  1187. WsbAffirmHr(pPremDb->Close(pDbSession));
  1188. } WsbCatchAndDo(hr2,
  1189. m_pSession->ProcessHr(HSM_JOB_PHASE_ALL, __FILE__, __LINE__, hr2);
  1190. );
  1191. }
  1192. // Sleep or wait for an event signal.
  1193. // If the event is signaled it means that data was just moved for this
  1194. // volume and there should be something to do.
  1195. if (SUCCEEDED(hr) || WSB_E_NOTFOUND == hr) {
  1196. ULONG l_runInterval;
  1197. // If we got to the end of the list, then wait a little longer. This
  1198. // is because we probably won't be able to do anything when we retry.
  1199. if (WSB_E_NOTFOUND == hr) {
  1200. l_runInterval = m_runInterval * 10;
  1201. } else {
  1202. l_runInterval = m_runInterval;
  1203. }
  1204. WsbTrace(OLESTR("CFsaTruncator::StartScan, sleeping for %lu msec\n"), l_runInterval);
  1205. switch(WaitForSingleObject(m_event, l_runInterval)) {
  1206. case WAIT_FAILED:
  1207. WsbTrace(OLESTR("CFsaTruncator::StartScan, Wait for Single Object returned error %lu\n"),
  1208. GetLastError());
  1209. break;
  1210. case WAIT_TIMEOUT:
  1211. WsbTrace(OLESTR("CFsaTruncator::StartScan, Awakened by timeout.\n"));
  1212. // Set adjustedFreeLevel to zero so it will get reset to current freeLevel;
  1213. adjustedFreeLevel = 0;
  1214. break;
  1215. default:
  1216. WsbTrace(OLESTR("CFsaTruncator::StartScan, Awakened by kick start.\n"));
  1217. break;
  1218. }
  1219. } else {
  1220. WsbThrow(hr);
  1221. }
  1222. WsbTrace(OLESTR("CFsaTruncator::StartScan, bottom of outside while loop, state = <%ls>\n"),
  1223. FsaStateAsString( m_state ) );
  1224. }
  1225. } WsbCatch(hr);
  1226. m_threadHr = hr;
  1227. // The thread is exiting, so tell the session.
  1228. if (FAILED(hr)) {
  1229. hr2 = SetState(HSM_JOB_STATE_FAILED);
  1230. } else {
  1231. hr2 = SetState(HSM_JOB_STATE_DONE);
  1232. }
  1233. if (FAILED(hr2)) {
  1234. m_pSession->ProcessHr(HSM_JOB_PHASE_ALL, __FILE__, __LINE__, hr2);
  1235. }
  1236. // Regardless of how this thread is exiting, we need to unadvise from the session.
  1237. // Indicate that we no longer want to be advised of events.
  1238. if ((m_pSession != 0) && (m_cookie != 0)) {
  1239. try {
  1240. WsbAffirmHr(m_pSession->QueryInterface(IID_IConnectionPointContainer, (void**) &pCPC));
  1241. WsbAffirmHr(pCPC->FindConnectionPoint(IID_IHsmSessionSinkEveryEvent, &pCP));
  1242. pCP->Unadvise(m_cookie);
  1243. m_cookie = 0;
  1244. } WsbCatch(hr);
  1245. }
  1246. // Since we have terminated, we should release the session.
  1247. m_pSession = 0;
  1248. // Clean up after this thread.
  1249. CloseHandle(m_threadHandle);
  1250. m_threadId = 0;
  1251. m_threadHandle = 0;
  1252. // Decrement ref count so this object can be release
  1253. ((IUnknown *)(IFsaTruncator *)this)->Release();
  1254. WsbTrace(OLESTR("CFsaTruncator::StartScan - terminating, hr = <%ls>, m_state = <%ls>\n"),
  1255. WsbHrAsString(hr), FsaStateAsString( m_state ) );
  1256. return(hr);
  1257. }