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.

1728 lines
57 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.p->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. if (0 == m_event) {
  831. WsbAssertHandle(m_event = CreateEvent(NULL, FALSE, FALSE, NULL));
  832. }
  833. // Now that we have prepared, create the thread that will do the scanning!
  834. WsbAffirm((m_threadHandle = CreateThread(0, 0, FsaStartTruncator, (void*) this, 0, &m_threadId)) != 0, HRESULT_FROM_WIN32(GetLastError()));
  835. } WsbCatchAndDo(hr, SetState(HSM_JOB_STATE_FAILED););
  836. } else {
  837. // The thread is still alive, just keep it going. If it is in a state that would
  838. // cause it to exit, then make it active again.
  839. WsbAssert(m_pSession != 0, E_UNEXPECTED);
  840. if ((HSM_JOB_STATE_ACTIVE != m_state) && (HSM_JOB_STATE_PAUSING != m_state) &&
  841. (HSM_JOB_STATE_PAUSED != m_state) && (HSM_JOB_STATE_RESUMING != m_state)) {
  842. WsbAffirmHr(SetState(HSM_JOB_STATE_ACTIVE));
  843. }
  844. }
  845. } WsbCatch(hr);
  846. WsbTraceOut(OLESTR("CFsaTruncator::Start"), OLESTR("hr = <%ls> m_state = <%ls>"), WsbHrAsString(hr), FsaStateAsString( m_state ) );
  847. return(hr);
  848. }
  849. HRESULT
  850. CFsaTruncator::StartScan(
  851. void
  852. )
  853. /*++
  854. --*/
  855. {
  856. ULONG adjustedFreeLevel = 0;
  857. HRESULT hr = S_OK;
  858. HRESULT hr2;
  859. LONGLONG itemOffset;
  860. LONGLONG itemSize = 0;
  861. LONGLONG fileId;
  862. ULONG freeLevel;
  863. ULONG hsmLevel;
  864. BOOL skipFile;
  865. BOOL dummy;
  866. LONGLONG llLastTruncTime = 0;
  867. LONGLONG llRunIntervalTicks;
  868. FILETIME recallTime, currentTime, accessTime, criteriaTime, premRecAccessTime;
  869. LONGLONG totalVolumeSpace;
  870. CComPtr<IFsaResource> pResource;
  871. CComPtr<IFsaResourcePriv> pResourcePriv;
  872. CComPtr<IFsaScanItem> pScanItem;
  873. CComPtr<IFsaPremigratedRec> pPremRec;
  874. CComPtr<IConnectionPointContainer> pCPC;
  875. CComPtr<IConnectionPoint> pCP;
  876. try {
  877. WsbTrace(OLESTR("CFsaTruncator::StartScan - starting loop\n"));
  878. // Increment the ref count so this object (or its session) doesn't
  879. // get released before this thread ends
  880. ((IUnknown *)(IFsaTruncator *)this)->AddRef();
  881. WsbAssert(m_pSession != 0, E_POINTER);
  882. // The thread is running.
  883. WsbAffirmHr(SetState(HSM_JOB_STATE_ACTIVE));
  884. // Get the resource
  885. WsbAffirmHr(m_pSession->GetResource(&pResource));
  886. WsbAffirmHr(pResource->QueryInterface(IID_IFsaResourcePriv, (void**) &pResourcePriv));
  887. WsbAffirmHr(pResource->GetSizes(&totalVolumeSpace, NULL, NULL, NULL));
  888. // Start with the first path.
  889. while ((HSM_JOB_STATE_ACTIVE == m_state) || (HSM_JOB_STATE_PAUSING == m_state) ||
  890. (HSM_JOB_STATE_PAUSED == m_state) || (HSM_JOB_STATE_RESUMING == m_state)) {
  891. WsbTrace(OLESTR("CFsaTruncator::StartScan, top of outside while loop, state = <%ls>\n"),
  892. FsaStateAsString( m_state ) );
  893. // If the truncator is running and the resource does not have enough free space
  894. // check to see if the resource is over the threshold and truncation is needed.
  895. WsbAffirmHr(pResource->GetHsmLevel(&hsmLevel));
  896. WsbAffirmHr(pResource->GetFreeLevel(&freeLevel));
  897. // Because the truncation is asynchronous (FsaPostIt is sent to Engine for
  898. // verification and then returned to FSA for actual truncation), the
  899. // measured freeLevel may not be very accurate if there are truncations
  900. // pending. To compensate for this, we keep an adjustedFreeLevel which
  901. // attempts to take into account the pending truncates. We synchronize the
  902. // adjustedFreeLevel to the measured freeLevel the first time through and
  903. // after we have slept for a while (on the assumption that the pending
  904. // truncates have had time to be performed). This still leaves open the possiblility
  905. // that the measured freeLevel is wrong (because truncates are pending), but
  906. // should be an improvement over just using the measured freeLevel.
  907. llRunIntervalTicks = m_runInterval * (WSB_FT_TICKS_PER_SECOND / 1000);
  908. GetSystemTimeAsFileTime(&currentTime);
  909. if (0 == adjustedFreeLevel ||
  910. ((WsbFTtoLL(currentTime) - llLastTruncTime) > llRunIntervalTicks)) {
  911. adjustedFreeLevel = freeLevel;
  912. WsbTrace(OLESTR("CFsaTruncator::StartScan, resetting adjusted free level, RunInterval = %ls, time diff = %ls\n"),
  913. WsbQuickString(WsbLonglongAsString(llRunIntervalTicks)),
  914. WsbQuickString(WsbLonglongAsString(WsbFTtoLL(currentTime) - llLastTruncTime)));
  915. }
  916. WsbTrace(OLESTR("CFsaTruncator::StartScan, desired level = %u, free level = %u, adjusted free level = %u\n"),
  917. hsmLevel, freeLevel, adjustedFreeLevel);
  918. if (adjustedFreeLevel < hsmLevel && HSM_JOB_STATE_ACTIVE == m_state) {
  919. CComPtr<IWsbDbSession> pDbSession;
  920. CComPtr<IFsaPremigratedDb> pPremDb;
  921. // Open the premigration list, and set the order in which it will be scanned.
  922. WsbAffirmHr(pResourcePriv->GetPremigrated(IID_IFsaPremigratedDb,
  923. (void**) &pPremDb));
  924. WsbAffirmHr(pPremDb->Open(&pDbSession));
  925. try {
  926. WsbAffirmHr(pPremDb->GetEntity(pDbSession, PREMIGRATED_REC_TYPE, IID_IFsaPremigratedRec, (void**) &pPremRec));
  927. // Set the order to get items from the Premigrated List
  928. switch (m_SortOrder) {
  929. case FSA_SORT_PL_BY_SIZE:
  930. WsbAffirmHr(pPremRec->UseKey(PREMIGRATED_SIZE_KEY_TYPE));
  931. break;
  932. case FSA_SORT_PL_BY_PATH_NAME:
  933. // We use the BagId and offsets instead
  934. WsbAffirmHr(pPremRec->UseKey(PREMIGRATED_BAGID_OFFSETS_KEY_TYPE));
  935. break;
  936. case FSA_SORT_PL_BY_SIZE_AND_TIME:
  937. // We don't know how to handle this one yet
  938. WsbThrow(E_UNEXPECTED);
  939. break;
  940. case FSA_SORT_PL_BY_ACCESS_TIME:
  941. default:
  942. WsbAffirmHr(pPremRec->UseKey(PREMIGRATED_ACCESS_TIME_KEY_TYPE));
  943. break;
  944. }
  945. // Make a pass through the list of premigrated files until the
  946. // desired level has been reached. Some items that are on the
  947. // list may be in a state that causes them to be skipped, but left on the list.
  948. WsbAffirmHr(pPremRec->First());
  949. while ((adjustedFreeLevel < hsmLevel) && (HSM_JOB_STATE_ACTIVE == m_state)) {
  950. CComPtr<IFsaRecoveryRec> pRecRec;
  951. WsbTrace(OLESTR("CFsaTruncator::StartScan (top of inside while loop) desired level = %u, adjusted free level = %u\n"),
  952. hsmLevel, adjustedFreeLevel);
  953. try {
  954. skipFile = FALSE;
  955. //
  956. // Get the access time as recorded in the premigrated record
  957. // Note that the real access time cannot be older than the one
  958. // in the premigrated list but it can be newer
  959. //
  960. WsbAffirmHr(pPremRec->GetAccessTime(&premRecAccessTime));
  961. WsbAffirmHr(pResource->GetManageableItemAccessTime(&dummy, &criteriaTime));
  962. if (WsbCompareFileTimes(premRecAccessTime, criteriaTime, TRUE, FALSE) < 0 ) {
  963. if (pPremRec->IsWaitingForClose() == S_FALSE) {
  964. //
  965. // Can skip the current file but NOT break out of the loop since
  966. // files with access time old enough and WaitingForClose flag set
  967. // may still exists in the list
  968. //
  969. skipFile = TRUE;
  970. } else {
  971. //
  972. // The access time in the prem. rec is within the window.
  973. // This means there aren't any other records which are outside the
  974. // user-desired last access window. So break out
  975. //
  976. WsbTrace(OLESTR("CFsaTruncator::StartScan: breaking out of auto-truncator, encountered item with access time not within criteria\n"));
  977. hr = WSB_E_NOTFOUND;
  978. break;
  979. }
  980. }
  981. // Get information about the file that could be truncated.
  982. WsbAffirmHr(pPremRec->GetFileId(&fileId));
  983. WsbAffirmHr(pPremRec->GetOffset(&itemOffset));
  984. WsbAffirmHr(pPremRec->GetSize(&itemSize));
  985. m_currentPath.Free();
  986. WsbAffirmHr(pPremRec->GetPath(&m_currentPath, 0));
  987. WsbAffirmHr(pPremRec->GetRecallTime(&recallTime));
  988. GetSystemTimeAsFileTime(&currentTime);
  989. // Make sure that this file wasn't recently recalled. For now,
  990. // this will check for 1 minute.
  991. if ((! skipFile) &&
  992. ( (pPremRec->IsWaitingForClose() == S_FALSE) ||
  993. ((WsbFTtoLL(currentTime) > WsbFTtoLL(recallTime)) &&
  994. (WsbCompareFileTimes(recallTime, m_keepRecallTime, TRUE, FALSE) >= 0)) )) {
  995. hr = pResource->FindFileId(fileId, m_pSession, &pScanItem);
  996. if (hr == WSB_E_NOTFOUND) {
  997. //
  998. // The file does not exist anymore - remove the record from the list.
  999. //
  1000. WsbAffirmHr(pDbSession->TransactionBegin());
  1001. try {
  1002. // Make sure the record is still in the DB
  1003. WsbAffirmHr(pPremRec->FindEQ());
  1004. WsbAffirmHr(pPremRec->Remove());
  1005. WsbAffirmHr(pResourcePriv->RemovePremigratedSize(itemSize));
  1006. } WsbCatch(hr);
  1007. WsbAffirmHr(pDbSession->TransactionEnd());
  1008. WsbThrow(hr);
  1009. } else if (hr != S_OK) {
  1010. //
  1011. // Any other error is unexpected - log it and continue
  1012. //
  1013. WsbLogEvent(FSA_E_ACCESS_ERROR, 0, NULL, m_currentPath, WsbHrAsString(hr), NULL);
  1014. WsbThrow(hr);
  1015. }
  1016. //
  1017. // Verify that the file is still in a premigrated state
  1018. //
  1019. if (S_OK == pScanItem->IsPremigrated(itemOffset, itemSize)) {
  1020. WsbAffirmHr(pScanItem->GetAccessTime(&accessTime));
  1021. //
  1022. // accessTime is the last access time for the file
  1023. // criteriaTime is the 'not accessed in so many ticks' criteria for truncating
  1024. // the file.
  1025. // So if (currentTime - accessTime) >= criteriaTime, then the file is ok to be truncated
  1026. //
  1027. if (WsbCompareFileTimes(accessTime, criteriaTime, TRUE, FALSE) >=0 ) {
  1028. //
  1029. // The file was not accessed within the last access window
  1030. //
  1031. WsbTrace(OLESTR("CFsaTruncator::StartScan, truncating file <%ls>\n"),
  1032. (WCHAR *)m_currentPath);
  1033. // Try to truncate the file.
  1034. try {
  1035. // Create and save a recovery record in case something goes wrong
  1036. WsbAffirmHr(pPremDb->GetEntity(pDbSession, RECOVERY_REC_TYPE, IID_IFsaRecoveryRec, (void**) &pRecRec));
  1037. WsbAffirmHr(pRecRec->SetPath(m_currentPath));
  1038. // If the record already exists rewrite it, otherwise create a new record.
  1039. hr2 = pRecRec->FindEQ();
  1040. if (WSB_E_NOTFOUND == hr2) {
  1041. hr2 = S_OK;
  1042. WsbAffirmHr(pRecRec->MarkAsNew());
  1043. } else if (FAILED(hr2)) {
  1044. WsbThrow(hr2);
  1045. }
  1046. WsbAffirmHr(pRecRec->SetFileId(fileId));
  1047. WsbAffirmHr(pRecRec->SetOffsetSize(itemOffset, itemSize));
  1048. WsbAffirmHr(pRecRec->SetStatus(FSA_RECOVERY_FLAG_TRUNCATING));
  1049. WsbAffirmHr(pRecRec->Write());
  1050. //
  1051. // Set the waiting for close flag to prevent this file
  1052. // from being selected again while the engine is
  1053. // processing the truncate. Set the recall time to
  1054. // now plus 1 hour so we are sure not to retry this
  1055. // until we have had a chance to truncate it.
  1056. //
  1057. WsbAffirmHr(pPremRec->SetIsWaitingForClose(TRUE));
  1058. WsbAffirmHr(pPremRec->SetRecallTime(WsbLLtoFT(WsbFTtoLL(currentTime) + WSB_FT_TICKS_PER_HOUR)));
  1059. hr2 = pPremRec->Write();
  1060. // Special code to deal with a problem that has been seen
  1061. // but isn't understood
  1062. if (WSB_E_IDB_PRIMARY_KEY_CHANGED == hr2) {
  1063. WsbAffirmHr(pPremRec->Remove());
  1064. WsbAffirmHr(pResourcePriv->RemovePremigratedSize(itemSize));
  1065. // Ignore result from DeletePlaceholder since there's nothing we
  1066. // can do anyway.
  1067. pScanItem->DeletePlaceholder(itemOffset, itemSize);
  1068. WsbThrow(FSA_E_SKIPPED);
  1069. } else {
  1070. WsbAffirmHr(hr2);
  1071. }
  1072. //
  1073. // Set IsWaitingForClose back to false so that the FindGt done later gets the next record.
  1074. // This affects the in memory record only and not the persisted record.
  1075. //
  1076. WsbAffirmHr(pPremRec->SetIsWaitingForClose(FALSE));
  1077. WsbAffirmHr(pScanItem->Truncate(itemOffset, itemSize));
  1078. llLastTruncTime = WsbFTtoLL(currentTime);
  1079. // Add the file size to the adjustedFreeLevel so we know when to
  1080. // stop doing truncations. Unfortunately, the itemSize is in
  1081. // bytes but adjustedFreeLevl is a fixed-point percentage so we
  1082. // have to do a calculation to convert the itemSize
  1083. adjustedFreeLevel += (ULONG) (((double)itemSize /
  1084. (double)totalVolumeSpace) *
  1085. (double)FSA_HSMLEVEL_100);
  1086. } WsbCatchAndDo(hr,
  1087. // Do we need to skip this file for the time being?
  1088. if (FSA_E_SKIPPED == hr) {
  1089. // Do nothing
  1090. } else if ((FSA_E_ITEMCHANGED != hr) && (FSA_E_NOTMANAGED != hr)) {
  1091. // Something unexpected happened, so report the error.
  1092. WsbAffirmHr(m_pSession->ProcessHr(HSM_JOB_PHASE_FSA_ACTION, 0, 0, hr));
  1093. }
  1094. );
  1095. } else {
  1096. //
  1097. // File is premigrated, but skipped because the last access was too recent
  1098. //
  1099. WsbTrace(OLESTR("CFsaTruncator::StartScan, skipping file <%ls> which is premigrated but last access is too recent\n"),
  1100. (WCHAR *)m_currentPath);
  1101. hr = FSA_E_SKIPPED;
  1102. //
  1103. // Update the access time in the db for this file
  1104. //
  1105. WsbAffirmHr(pPremRec->SetAccessTime(accessTime));
  1106. //
  1107. // Commit this
  1108. //
  1109. WsbAffirmHr(pPremRec->Write());
  1110. //
  1111. // Revert the in-memory accessTime to the old access time to
  1112. // let the enumeration continue (so that FindGT will fetch the next record)
  1113. //
  1114. WsbAffirmHr(pPremRec->SetAccessTime(premRecAccessTime));
  1115. }
  1116. } else {
  1117. //
  1118. // If the file is no longer managed by HSM or truncated (may have been modified
  1119. // after it was premigrated) - we remove the record from the list.
  1120. // Note that if we reached this else close, the condition below should be TRUE
  1121. //
  1122. if ( (S_FALSE == pScanItem->IsManaged(itemOffset, itemSize)) ||
  1123. (S_OK == pScanItem->IsTruncated(itemOffset, itemSize)) ) {
  1124. WsbAffirmHr(pDbSession->TransactionBegin());
  1125. try {
  1126. // Make sure the record is still in the DB
  1127. WsbAffirmHr(pPremRec->FindEQ());
  1128. WsbAffirmHr(pPremRec->Remove());
  1129. WsbAffirmHr(pResourcePriv->RemovePremigratedSize(itemSize));
  1130. } WsbCatch(hr);
  1131. WsbAffirmHr(pDbSession->TransactionEnd());
  1132. // Ignore hr of the removal itself (truncated files may have been removed by another thread)
  1133. hr = WSB_E_NOTFOUND;
  1134. WsbThrow(hr);
  1135. }
  1136. }
  1137. // Tell the session we saw the file, and whether we were able to truncate it.
  1138. WsbAffirmHr(m_pSession->ProcessItem(HSM_JOB_PHASE_FSA_ACTION, HSM_JOB_ACTION_TRUNCATE, pScanItem, hr));
  1139. // Don't let this errors stop us from continuing to process the list.
  1140. hr = S_OK;
  1141. } else {
  1142. //
  1143. // File is premigrated, but skipped because the last access was too recent or
  1144. // because it was recalled recently
  1145. //
  1146. WsbTrace(OLESTR("CFsaTruncator::StartScan, skipping file <%ls> since its last access time is too recent or recently recalled\n"),
  1147. (WCHAR *)m_currentPath);
  1148. hr = FSA_E_SKIPPED;
  1149. }
  1150. } WsbCatchAndDo(hr,
  1151. if (WSB_E_NOTFOUND != hr) {
  1152. m_pSession->ProcessHr(HSM_JOB_PHASE_FSA_ACTION, __FILE__, __LINE__, hr);
  1153. }
  1154. // Don't let this errors stop us from continuing to process the list.
  1155. hr = S_OK;
  1156. );
  1157. // If item is skipped - set hr to OK (this is not really an error)
  1158. if (FSA_E_SKIPPED == hr) {
  1159. hr = S_OK;
  1160. }
  1161. // Remove recovery record
  1162. if (pRecRec) {
  1163. WsbAffirmHr(pRecRec->FindEQ());
  1164. WsbAffirmHr(pRecRec->Remove());
  1165. pRecRec = NULL;
  1166. }
  1167. // Get the desired level again in case it changed
  1168. WsbAffirmHr(pResource->GetHsmLevel(&hsmLevel));
  1169. // Free the scan item.
  1170. pScanItem = 0;
  1171. // Whether we removed or skipped the item, go on to the next item.
  1172. WsbAffirmHr(pPremRec->FindGT());
  1173. WsbTrace(OLESTR("CFsaTruncator::StartScan, bottom of inside while loop, state = <%ls>\n"),
  1174. FsaStateAsString( m_state ) );
  1175. } // inner while
  1176. } WsbCatch(hr);
  1177. // Free the premigrated record object and close the data base.
  1178. try {
  1179. pPremRec = 0;
  1180. WsbAffirmHr(pPremDb->Close(pDbSession));
  1181. } WsbCatchAndDo(hr2,
  1182. m_pSession->ProcessHr(HSM_JOB_PHASE_ALL, __FILE__, __LINE__, hr2);
  1183. );
  1184. }
  1185. // Sleep or wait for an event signal.
  1186. // If the event is signaled it means that data was just moved for this
  1187. // volume and there should be something to do.
  1188. if (SUCCEEDED(hr) || WSB_E_NOTFOUND == hr) {
  1189. ULONG l_runInterval;
  1190. // If we got to the end of the list, then wait a little longer. This
  1191. // is because we probably won't be able to do anything when we retry.
  1192. if (WSB_E_NOTFOUND == hr) {
  1193. l_runInterval = m_runInterval * 10;
  1194. } else {
  1195. l_runInterval = m_runInterval;
  1196. }
  1197. WsbTrace(OLESTR("CFsaTruncator::StartScan, sleeping for %lu msec\n"), l_runInterval);
  1198. switch(WaitForSingleObject(m_event, l_runInterval)) {
  1199. case WAIT_FAILED:
  1200. WsbTrace(OLESTR("CFsaTruncator::StartScan, Wait for Single Object returned error %lu\n"),
  1201. GetLastError());
  1202. break;
  1203. case WAIT_TIMEOUT:
  1204. WsbTrace(OLESTR("CFsaTruncator::StartScan, Awakened by timeout.\n"));
  1205. // Set adjustedFreeLevel to zero so it will get reset to current freeLevel;
  1206. adjustedFreeLevel = 0;
  1207. break;
  1208. default:
  1209. WsbTrace(OLESTR("CFsaTruncator::StartScan, Awakened by kick start.\n"));
  1210. break;
  1211. }
  1212. } else {
  1213. WsbThrow(hr);
  1214. }
  1215. WsbTrace(OLESTR("CFsaTruncator::StartScan, bottom of outside while loop, state = <%ls>\n"),
  1216. FsaStateAsString( m_state ) );
  1217. }
  1218. } WsbCatch(hr);
  1219. m_threadHr = hr;
  1220. // The thread is exiting, so tell the session.
  1221. if (FAILED(hr)) {
  1222. hr2 = SetState(HSM_JOB_STATE_FAILED);
  1223. } else {
  1224. hr2 = SetState(HSM_JOB_STATE_DONE);
  1225. }
  1226. if (FAILED(hr2)) {
  1227. m_pSession->ProcessHr(HSM_JOB_PHASE_ALL, __FILE__, __LINE__, hr2);
  1228. }
  1229. // Regardless of how this thread is exiting, we need to unadvise from the session.
  1230. // Indicate that we no longer want to be advised of events.
  1231. if ((m_pSession != 0) && (m_cookie != 0)) {
  1232. try {
  1233. WsbAffirmHr(m_pSession->QueryInterface(IID_IConnectionPointContainer, (void**) &pCPC));
  1234. WsbAffirmHr(pCPC->FindConnectionPoint(IID_IHsmSessionSinkEveryEvent, &pCP));
  1235. pCP->Unadvise(m_cookie);
  1236. m_cookie = 0;
  1237. } WsbCatch(hr);
  1238. }
  1239. // Since we have terminated, we should release the session.
  1240. m_pSession = 0;
  1241. // Clean up after this thread.
  1242. CloseHandle(m_threadHandle);
  1243. m_threadId = 0;
  1244. m_threadHandle = 0;
  1245. // Decrement ref count so this object can be release
  1246. ((IUnknown *)(IFsaTruncator *)this)->Release();
  1247. WsbTrace(OLESTR("CFsaTruncator::StartScan - terminating, hr = <%ls>, m_state = <%ls>\n"),
  1248. WsbHrAsString(hr), FsaStateAsString( m_state ) );
  1249. return(hr);
  1250. }