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.

5807 lines
208 KiB

  1. /*++
  2. Copyright (c) 1998 Seagate Software, Inc. All rights reserved.
  3. Module Name:
  4. hsmWorkQ.cpp
  5. Abstract:
  6. This class represents the HSM task manager
  7. Author:
  8. Cat Brant [cbrant] 6-Dec-1996
  9. Revision History:
  10. --*/
  11. #include "stdafx.h"
  12. #define WSB_TRACE_IS WSB_TRACE_BIT_HSMTSKMGR
  13. static USHORT icountWorkq = 0;
  14. #include "fsa.h"
  15. #include "rms.h"
  16. #include "metadef.h"
  17. #include "jobint.h"
  18. #include "hsmconn.h"
  19. #include "wsb.h"
  20. #include "hsmeng.h"
  21. #include "mover.h"
  22. #include "hsmWorkQ.h"
  23. #include "engine.h"
  24. #include "task.h"
  25. #include "tskmgr.h"
  26. #include "segdb.h"
  27. #define HSM_STORAGE_OVERHEAD 5000
  28. #define MIN_FREE_SPACE_IN_FULL_MEDIA_DEFAULT 4
  29. #define MAX_FREE_SPACE_IN_FULL_MEDIA_DEFAULT 5
  30. #define STRINGIZE(_str) (OLESTR( #_str ))
  31. #define RETURN_STRINGIZED_CASE(_case) \
  32. case _case: \
  33. return ( STRINGIZE( _case ) );
  34. // Local prototypes
  35. DWORD HsmWorkQueueThread(void *pVoid);
  36. static const OLECHAR * JobStateAsString (HSM_JOB_STATE state);
  37. static const OLECHAR *
  38. JobStateAsString (
  39. IN HSM_JOB_STATE state
  40. )
  41. /*++
  42. Routine Description:
  43. Gives back a static string representing the connection state.
  44. Arguments:
  45. state - the state to return a string for.
  46. Return Value:
  47. NULL - invalid state passed in.
  48. Otherwise, a valid char *.
  49. --*/
  50. {
  51. //
  52. // Do the Switch
  53. //
  54. switch ( state ) {
  55. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_ACTIVE );
  56. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_CANCELLED );
  57. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_CANCELLING );
  58. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_DONE );
  59. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_FAILED );
  60. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_IDLE );
  61. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_PAUSED );
  62. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_PAUSING );
  63. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_RESUMING );
  64. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_SKIPPED );
  65. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_STARTING );
  66. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_SUSPENDED );
  67. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_SUSPENDING );
  68. default:
  69. return ( OLESTR("Invalid Value") );
  70. }
  71. }
  72. HRESULT
  73. CHsmWorkQueue::FinalConstruct(
  74. void
  75. )
  76. /*++
  77. Routine Description:
  78. This method does some initialization of the object that is necessary
  79. after construction.
  80. Arguments:
  81. None.
  82. Return Value:
  83. S_OK
  84. Anything returned by CWsbCollectable::FinalConstruct().
  85. --*/
  86. {
  87. HRESULT hr = S_OK;
  88. WsbTraceIn(OLESTR("CHsmWorkQueue::FinalConstruct"),OLESTR(""));
  89. try {
  90. WsbAssertHr(CComObjectRoot::FinalConstruct());
  91. //
  92. // Initialize the member data
  93. //
  94. m_pServer = 0;
  95. m_pHsmServerCreate = 0;
  96. m_pTskMgr;
  97. m_pFsaResource = 0;
  98. m_pSession = 0;
  99. m_pRmsServer = 0;
  100. m_pRmsCartridge = 0;
  101. m_pDataMover = 0;
  102. m_pSegmentDb = 0;
  103. m_pDbWorkSession = 0;
  104. m_pStoragePools = 0;
  105. m_pWorkToDo = 0;
  106. m_pWorkToCommit = 0;
  107. UnsetMediaInfo();
  108. m_BagId = GUID_NULL;
  109. m_HsmId = GUID_NULL;
  110. m_RemoteDataSetStart.QuadPart = 0;
  111. m_RmsMediaSetId = GUID_NULL;
  112. m_RmsMediaSetName = OLESTR("");
  113. m_RequestAction = FSA_REQUEST_ACTION_NONE;
  114. m_QueueType = HSM_WORK_TYPE_NONE;
  115. m_BeginSessionHr = S_FALSE;
  116. m_StateCookie = 0;
  117. m_EventCookie = 0;
  118. m_JobPriority = HSM_JOB_PRIORITY_NORMAL;
  119. m_JobAction = HSM_JOB_ACTION_UNKNOWN;
  120. m_JobState = HSM_JOB_STATE_IDLE;
  121. m_JobPhase = HSM_JOB_PHASE_MOVE_ACTION;
  122. m_WorkerThread = 0;
  123. m_TerminateQueue = FALSE;
  124. m_CurrentPath = OLESTR("");
  125. // Set threshold defaults
  126. m_MinFilesToMigrate = 100;
  127. m_MinBytesToMigrate = 10000000;
  128. m_FilesBeforeCommit = 2000;
  129. m_MaxBytesBeforeCommit = 750000000;
  130. m_MinBytesBeforeCommit = 10000000;
  131. m_FreeMediaBytesAtEndOfMedia = 10000000;
  132. m_MinFreeSpaceInFullMedia = MIN_FREE_SPACE_IN_FULL_MEDIA_DEFAULT;
  133. m_MaxFreeSpaceInFullMedia = MAX_FREE_SPACE_IN_FULL_MEDIA_DEFAULT;
  134. m_DataCountBeforeCommit = 0;
  135. m_FilesCountBeforeCommit = 0;
  136. m_StoreDatabasesInBags = TRUE;
  137. m_QueueItemsToPause = 500;
  138. m_QueueItemsToResume = 450;
  139. m_ScannerPaused = FALSE;
  140. // Job abort on errors parameters
  141. m_JobAbortMaxConsecutiveErrors = 5;
  142. m_JobAbortMaxTotalErrors = 25;
  143. m_JobConsecutiveErrors = 0;
  144. m_JobTotalErrors = 0;
  145. m_JobAbortSysDiskSpace = 2 * 1024 * 1024;
  146. m_mediaCount = 0;
  147. m_ScratchFailed = FALSE;
  148. m_uErrorReportFlags = 0;
  149. WSB_OBJECT_ADD(CLSID_CHsmWorkQueue, this);
  150. } WsbCatch(hr);
  151. icountWorkq++;
  152. WsbTraceOut(OLESTR("CHsmWorkQueue::FinalConstruct"),OLESTR("hr = <%ls>, Count is <%d>"),
  153. WsbHrAsString(hr), icountWorkq);
  154. return(hr);
  155. }
  156. HRESULT
  157. CHsmWorkQueue::FinalRelease(
  158. void
  159. )
  160. /*++
  161. Routine Description:
  162. This method does some initialization of the object that is necessary
  163. before destruction.
  164. Arguments:
  165. None.
  166. Return Value:
  167. S_OK
  168. Anything returned by CWsbCollection::FinalDestruct().
  169. --*/
  170. {
  171. HRESULT hr = S_OK;
  172. HSM_SYSTEM_STATE SysState;
  173. WsbTraceIn(OLESTR("CHsmWorkQueue::FinalRelease"),OLESTR(""));
  174. SysState.State = HSM_STATE_SHUTDOWN;
  175. ChangeSysState(&SysState);
  176. WSB_OBJECT_SUB(CLSID_CHsmWorkQueue, this);
  177. CComObjectRoot::FinalRelease();
  178. // Free String members
  179. // Note: Member objects held in smart-pointers are freed when the
  180. // smart-pointer destructor is being called (as part of this object destruction)
  181. m_MediaName.Free();
  182. m_MediaBarCode.Free();
  183. m_RmsMediaSetName.Free();
  184. m_CurrentPath.Free();
  185. icountWorkq--;
  186. WsbTraceOut(OLESTR("CHsmWorkQueue::FinalRelease"),OLESTR("hr = <%ls>, Count is <%d>"),
  187. WsbHrAsString(hr), icountWorkq);
  188. return(hr);
  189. }
  190. HRESULT
  191. CHsmWorkQueue::Init(
  192. IUnknown *pServer,
  193. IHsmSession *pSession,
  194. IHsmFsaTskMgr *pTskMgr,
  195. HSM_WORK_QUEUE_TYPE queueType
  196. )
  197. /*++
  198. Routine Description:
  199. This method does some initialization of the object that is necessary
  200. after construction.
  201. Arguments:
  202. None.
  203. Return Value:
  204. S_OK
  205. --*/
  206. {
  207. HRESULT hr = S_OK;
  208. WsbTraceIn(OLESTR("CHsmWorkQueue::Init"),OLESTR(""));
  209. try {
  210. //
  211. // Establish contact with the server and get the
  212. // databases
  213. //
  214. WsbAffirmHr(pServer->QueryInterface(IID_IHsmServer, (void **)&m_pServer));
  215. //We want a weak link to the server so decrement the reference count
  216. m_pServer->Release();
  217. m_pTskMgr = pTskMgr;
  218. m_pTskMgr->AddRef();
  219. m_QueueType = queueType;
  220. WsbAffirmHr(m_pServer->GetSegmentDb(&m_pSegmentDb));
  221. WsbAffirmHr(m_pServer->GetStoragePools(&m_pStoragePools));
  222. WsbAffirmHr(m_pServer->QueryInterface(IID_IWsbCreateLocalObject, (void **)&m_pHsmServerCreate));
  223. // We want a weak link to the server so decrement the reference count
  224. m_pHsmServerCreate->Release();
  225. WsbAffirmHr(m_pServer->GetID(&m_HsmId));
  226. WsbAffirmHr(CheckSession(pSession));
  227. //
  228. // Make a collection for the work items
  229. //
  230. WsbAffirmHr(m_pHsmServerCreate->CreateInstance(CLSID_CWsbOrderedCollection,
  231. IID_IWsbIndexedCollection,
  232. (void **)&m_pWorkToDo ));
  233. WsbAffirmHr(m_pHsmServerCreate->CreateInstance(CLSID_CWsbOrderedCollection,
  234. IID_IWsbIndexedCollection,
  235. (void **)&m_pWorkToCommit ));
  236. //
  237. // Make sure our connection to RMS is current
  238. //
  239. WsbAffirmHr(CheckRms());
  240. // Check the registry to see if there are changes to default settings
  241. CheckRegistry();
  242. } WsbCatch( hr );
  243. WsbTraceOut(OLESTR("CHsmWorkQueue::Init"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  244. return( hr );
  245. }
  246. HRESULT
  247. CHsmWorkQueue::ContactOk(
  248. void
  249. )
  250. /*++
  251. Routine Description:
  252. This allows the caller to see if the RPC connection
  253. to the task manager is OK
  254. Arguments:
  255. None.
  256. Return Value:
  257. S_OK
  258. --*/
  259. {
  260. return( S_OK );
  261. }
  262. HRESULT
  263. CHsmWorkQueue::ProcessSessionEvent(
  264. IHsmSession *pSession,
  265. HSM_JOB_PHASE phase,
  266. HSM_JOB_EVENT event
  267. )
  268. /*++
  269. Routine Description:
  270. Arguments:
  271. Return Value:
  272. --*/
  273. {
  274. HRESULT hr = S_OK;
  275. WsbTraceIn(OLESTR("CHsmWorkQueue::ProcessSessionEvent"),OLESTR(""));
  276. try {
  277. WsbAssert(0 != pSession, E_POINTER);
  278. // If the phase applies to us (MOVER or ALL), then do any work required by the
  279. // event.
  280. if ((HSM_JOB_PHASE_ALL == phase) || (HSM_JOB_PHASE_MOVE_ACTION == phase)) {
  281. switch(event) {
  282. case HSM_JOB_EVENT_SUSPEND:
  283. case HSM_JOB_EVENT_CANCEL:
  284. case HSM_JOB_EVENT_FAIL:
  285. WsbAffirmHr(Cancel());
  286. break;
  287. case HSM_JOB_EVENT_PAUSE:
  288. WsbAffirmHr(Pause());
  289. break;
  290. case HSM_JOB_EVENT_RESUME:
  291. WsbAffirmHr(Resume());
  292. break;
  293. case HSM_JOB_EVENT_RAISE_PRIORITY:
  294. WsbAffirmHr(RaisePriority());
  295. break;
  296. case HSM_JOB_EVENT_LOWER_PRIORITY:
  297. WsbAffirmHr(LowerPriority());
  298. break;
  299. default:
  300. case HSM_JOB_EVENT_START:
  301. WsbAssert(FALSE, E_UNEXPECTED);
  302. break;
  303. }
  304. }
  305. } WsbCatch(hr);
  306. WsbTraceOut(OLESTR("CHsmWorkQueue::ProcessSessionEvent"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  307. return( S_OK );
  308. }
  309. HRESULT
  310. CHsmWorkQueue::ProcessSessionState(
  311. IHsmSession* /*pSession*/,
  312. IHsmPhase* pPhase,
  313. OLECHAR* /*currentPath*/
  314. )
  315. /*++
  316. Routine Description:
  317. Arguments:
  318. Return Value:
  319. --*/
  320. {
  321. HRESULT hr = S_OK;
  322. HSM_JOB_PHASE phase;
  323. HSM_JOB_STATE state;
  324. WsbTraceIn(OLESTR("CHsmWorkQueue::ProcessSessionState"),OLESTR(""));
  325. try {
  326. WsbAffirmHr(pPhase->GetState(&state));
  327. WsbAffirmHr(pPhase->GetPhase(&phase));
  328. WsbTrace( OLESTR("CHsmWorkQueue::ProcessSessionState - State = <%d>, phase = <%d>\n"), state, phase );
  329. if ( HSM_JOB_PHASE_SCAN == phase ) {
  330. // If the session has finished, then we have some cleanup to do so that it can go
  331. // away.
  332. if ((state == HSM_JOB_STATE_DONE) || (state == HSM_JOB_STATE_FAILED) || (state == HSM_JOB_STATE_SUSPENDED) ) {
  333. WsbTrace( OLESTR("Job is done, failed, or suspended\n") );
  334. // Create a work item and append it to the work queue to
  335. // indicate that the job is done
  336. WsbAffirmHr(MarkQueueAsDone());
  337. }
  338. }
  339. } WsbCatch( hr );
  340. WsbTraceOut(OLESTR("CHsmWorkQueue::ProcessSessionState"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  341. return( S_OK );
  342. }
  343. HRESULT
  344. CHsmWorkQueue::Add(
  345. IFsaPostIt *pFsaWorkItem
  346. )
  347. /*++
  348. Implements:
  349. IHsmFsaTskMgr::Add
  350. --*/
  351. {
  352. HRESULT hr = S_OK;
  353. CComPtr<IHsmSession> pSession;
  354. WsbTraceIn(OLESTR("CHsmWorkQueue::Add"),OLESTR(""));
  355. try {
  356. //
  357. // Make sure there is a work allocater for this session
  358. //
  359. WsbAffirmHr(pFsaWorkItem->GetSession(&pSession));
  360. WsbAffirmHr(CheckSession(pSession));
  361. //
  362. // Create a work item, load it up and add it to this
  363. // Queue's collection
  364. //
  365. CComPtr<IHsmWorkItem> pWorkItem;
  366. WsbAffirmHr(m_pHsmServerCreate->CreateInstance(CLSID_CHsmWorkItem, IID_IHsmWorkItem,
  367. (void **)&pWorkItem));
  368. WsbAffirmHr(pWorkItem->SetWorkType(HSM_WORK_ITEM_FSA_WORK));
  369. WsbAffirmHr(pWorkItem->SetFsaPostIt(pFsaWorkItem));
  370. WsbAffirmHr(m_pWorkToDo->Append(pWorkItem));
  371. //
  372. // If adding this item to the queue meets or exceeds the count for pausing
  373. // pause the scanner so there is no more work submitted.
  374. //
  375. ULONG numItems;
  376. WsbAffirmHr(m_pWorkToDo->GetEntries(&numItems));
  377. WsbTrace(OLESTR("CHsmWorkQueue::Add - num items in queue = <%lu>\n"),numItems);
  378. if (numItems >= m_QueueItemsToPause) {
  379. WsbAffirmHr(PauseScanner());
  380. }
  381. } WsbCatch (hr);
  382. WsbTraceOut(OLESTR("CHsmWorkQueue::Add"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  383. return (hr);
  384. }
  385. HRESULT
  386. CHsmWorkQueue::Start( void )
  387. /*++
  388. Implements:
  389. IHsmWorkQueue::Start
  390. --*/
  391. {
  392. HRESULT hr = S_OK;
  393. DWORD tid;
  394. WsbTraceIn(OLESTR("CHsmWorkQueue::Start"),OLESTR(""));
  395. try {
  396. //
  397. // If the worker thread is already started, just return
  398. //
  399. WsbAffirm(m_WorkerThread == 0, S_OK);
  400. // Launch a thread to do work that is queued
  401. WsbAffirm((m_WorkerThread = CreateThread(0, 0, HsmWorkQueueThread, (void*) this, 0, &tid)) != 0, HRESULT_FROM_WIN32(GetLastError()));
  402. if (m_WorkerThread == NULL) {
  403. WsbAssertHr(E_FAIL); // TBD What error to return here??
  404. }
  405. } WsbCatch (hr);
  406. WsbTraceOut(OLESTR("CHsmWorkQueue::Start"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  407. return (hr);
  408. }
  409. HRESULT
  410. CHsmWorkQueue::Stop( void )
  411. /*++
  412. Implements:
  413. IHsmWorkQueue::Stop
  414. --*/
  415. {
  416. HRESULT hr = S_OK;
  417. WsbTraceIn(OLESTR("CHsmWorkQueue::Stop"),OLESTR(""));
  418. // Stop the thread (signal, wait, terminate if it still running)
  419. m_TerminateQueue = TRUE;
  420. if (m_WorkerThread) {
  421. switch (WaitForSingleObject(m_WorkerThread, 20000)) {
  422. case WAIT_FAILED: {
  423. WsbTrace(OLESTR("CHsmWorkQueue::Stop: WaitForSingleObject returned error %lu\n"), GetLastError());
  424. }
  425. // fall through...
  426. case WAIT_TIMEOUT: {
  427. WsbTrace(OLESTR("CHsmWorkQueue::Stop: force terminating of working thread.\n"));
  428. DWORD dwExitCode;
  429. if (GetExitCodeThread( m_WorkerThread, &dwExitCode)) {
  430. if (dwExitCode == STILL_ACTIVE) { // thread still active
  431. if (!TerminateThread (m_WorkerThread, 0)) {
  432. WsbTrace(OLESTR("CHsmWorkQueue::Stop: TerminateThread returned error %lu\n"), GetLastError());
  433. }
  434. }
  435. } else {
  436. WsbTrace(OLESTR("CHsmWorkQueue::Stop: GetExitCodeThread returned error %lu\n"), GetLastError());
  437. }
  438. break;
  439. }
  440. default:
  441. // Thread terminated gracefully
  442. WsbTrace(OLESTR("CHsmWorkQueue::Stop: working thread terminated gracefully\n"));
  443. break;
  444. }
  445. }
  446. WsbTraceOut(OLESTR("CHsmWorkQueue::Stop"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  447. return (hr);
  448. }
  449. HRESULT
  450. CHsmWorkQueue::PremigrateIt(
  451. IFsaPostIt *pFsaWorkItem
  452. )
  453. {
  454. HRESULT hr = S_OK;
  455. GUID mediaToUse;
  456. GUID firstSide;
  457. BOOLEAN done = FALSE;
  458. FSA_PLACEHOLDER placeholder;
  459. LONGLONG requestSize;
  460. LONGLONG requestStart;
  461. LONGLONG fileVersionId;
  462. WsbTraceIn(OLESTR("CHsmWorkQueue::PremigrateIt"),OLESTR(""));
  463. try {
  464. //
  465. // Check to see if anything has changed since the request
  466. //
  467. WsbAffirmHr(CheckForChanges(pFsaWorkItem));
  468. // Check for sufficient space on system volume
  469. WsbAffirmHr(CheckForDiskSpace());
  470. //
  471. // Go to the Storage Pool and get the media set associated
  472. // with this data
  473. //
  474. WsbAffirmHr(GetMediaSet(pFsaWorkItem));
  475. //
  476. // Loop here to try to recover from certain types of errors
  477. //
  478. while (done == FALSE){
  479. CComPtr<IWsbIndexedCollection> pMountingCollection;
  480. CComPtr<IMountingMedia> pMountingMedia;
  481. CComPtr<IMountingMedia> pMediaToFind;
  482. BOOL bMediaMounting = FALSE;
  483. BOOL bMediaMountingAdded = FALSE;
  484. BOOL bMediaChanged = FALSE;
  485. LONGLONG llRequiredSize = 0;
  486. // Lock mounting media while searching for a media to use
  487. WsbAffirmHr(m_pServer->LockMountingMedias());
  488. // Find a media to use and set up interfaces to RMS
  489. try {
  490. WsbAffirmHr(FindMigrateMediaToUse(pFsaWorkItem, &mediaToUse, &firstSide, &bMediaChanged, &llRequiredSize));
  491. // Check if the media-to-use have changed and is a non-scratch media
  492. if ((GUID_NULL != mediaToUse) && bMediaChanged) {
  493. // Check if the media to mount is already mounting
  494. WsbAffirmHr(m_pServer->GetMountingMedias(&pMountingCollection));
  495. WsbAffirmHr(CoCreateInstance(CLSID_CMountingMedia, 0, CLSCTX_SERVER, IID_IMountingMedia, (void**)&pMediaToFind));
  496. WsbAffirmHr(pMediaToFind->SetMediaId(mediaToUse));
  497. hr = pMountingCollection->Find(pMediaToFind, IID_IMountingMedia, (void **)&pMountingMedia);
  498. if (hr == S_OK) {
  499. // Media is already mounting...
  500. bMediaMounting = TRUE;
  501. WsbAffirmHr(pMediaToFind->SetIsReadOnly(FALSE));
  502. } else if (hr == WSB_E_NOTFOUND) {
  503. // New media to mount - add to the mounting list
  504. hr = S_OK;
  505. WsbAffirmHr(pMediaToFind->Init(mediaToUse, FALSE));
  506. WsbAffirmHr(pMountingCollection->Add(pMediaToFind));
  507. bMediaMountingAdded = TRUE;
  508. } else {
  509. WsbAffirmHr(hr);
  510. }
  511. }
  512. } WsbCatchAndDo(hr,
  513. // Unlock mounting media
  514. m_pServer->UnlockMountingMedias();
  515. WsbTraceAlways(OLESTR("CHsmWorkQueue::PremigrateIt: error while trying to find/add mounting media. hr=<%ls>\n"),
  516. WsbHrAsString(hr));
  517. // Bale out
  518. WsbThrow(hr);
  519. );
  520. // Release the lock
  521. WsbAffirmHr(m_pServer->UnlockMountingMedias());
  522. // If the media is mounting - wait for the mount event
  523. if (bMediaMounting) {
  524. WsbAffirmHr(pMountingMedia->WaitForMount(INFINITE));
  525. pMountingMedia = 0;
  526. }
  527. // Mount the media. Ask for short timeout.
  528. hr = MountMedia(pFsaWorkItem, mediaToUse, firstSide, TRUE, TRUE, llRequiredSize);
  529. // If we added a mounting media to the list - remove it once the mount is done
  530. if (bMediaMountingAdded) {
  531. HRESULT hrRemove = S_OK;
  532. // No matter how the Mount finished - free waiting clients and remove from the list
  533. hrRemove = m_pServer->LockMountingMedias();
  534. WsbAffirmHr(hrRemove);
  535. try {
  536. WsbAffirmHr(pMediaToFind->MountDone());
  537. WsbAffirmHr(pMountingCollection->RemoveAndRelease(pMediaToFind));
  538. pMediaToFind = 0;
  539. } WsbCatch(hrRemove);
  540. m_pServer->UnlockMountingMedias();
  541. // We don't expect any errors while removing the mounting media -
  542. // The thread that added to the collection is always the one that removes
  543. if (! SUCCEEDED(hrRemove)) {
  544. WsbTraceAlways(OLESTR("CHsmWorkQueue::PremigrateIt: error while trying to remove a mounting media. hr=<%ls>\n"),
  545. WsbHrAsString(hrRemove));
  546. WsbThrow(hrRemove);
  547. }
  548. }
  549. // Check for job cancellation
  550. if (HSM_JOB_STATE_CANCELLING == m_JobState) {
  551. WsbThrow(HSM_E_WORK_SKIPPED_CANCELLED);
  552. }
  553. //
  554. // Process RMS errors
  555. //
  556. switch (hr) {
  557. case RMS_E_CARTRIDGE_NOT_FOUND: {
  558. // If this media wasn't found, mark it as bad and try a different one
  559. WsbAffirmHr(MarkMediaBad(pFsaWorkItem, m_MediaId, hr));
  560. hr = S_OK;
  561. continue;
  562. }
  563. case RMS_E_TIMEOUT:
  564. case HSM_E_NO_MORE_MEDIA:
  565. case RMS_E_CARTRIDGE_DISABLED:
  566. case HSM_E_MEDIA_NOT_AVAILABLE: {
  567. // In all these cases, let FindMigrateMediaToUse try to find a different media
  568. hr = S_OK;
  569. continue;
  570. }
  571. default: {
  572. WsbAffirmHr(hr);
  573. }
  574. }
  575. //
  576. // Make sure the data has not been modified since the
  577. // FSA determined the migration request
  578. //
  579. hr = CheckForChanges(pFsaWorkItem);
  580. if (S_OK == hr) {
  581. //
  582. // Build the source path
  583. //
  584. CWsbStringPtr tmpString;
  585. WsbAffirmHr(GetSource(pFsaWorkItem, &tmpString));
  586. CWsbBstrPtr localName = tmpString;
  587. //
  588. // Ask the Data mover to store the data
  589. //
  590. ULARGE_INTEGER localDataStart;
  591. ULARGE_INTEGER localDataSize;
  592. ULARGE_INTEGER remoteFileStart;
  593. ULARGE_INTEGER remoteFileSize;
  594. ULARGE_INTEGER remoteDataSetStart;
  595. ULARGE_INTEGER remoteDataStart;
  596. ULARGE_INTEGER remoteDataSize;
  597. ULARGE_INTEGER remoteVerificationData;
  598. ULONG remoteVerificationType;
  599. ULARGE_INTEGER dataStreamCRC;
  600. ULONG dataStreamCRCType;
  601. ULARGE_INTEGER usn;
  602. WsbAffirmHr(pFsaWorkItem->GetPlaceholder(&placeholder));
  603. WsbAffirmHr(pFsaWorkItem->GetRequestSize(&requestSize));
  604. WsbAffirmHr(pFsaWorkItem->GetRequestOffset(&requestStart));
  605. WsbAffirmHr(pFsaWorkItem->GetFileVersionId(&fileVersionId));
  606. localDataStart.QuadPart = requestStart;
  607. localDataSize.QuadPart = requestSize;
  608. ReportMediaProgress(HSM_JOB_MEDIA_STATE_TRANSFERRING, hr);
  609. // Make sure data mover is ready for work.
  610. WsbAffirmPointer(m_pDataMover);
  611. hr = m_pDataMover->StoreData( localName,
  612. localDataStart,
  613. localDataSize,
  614. MVR_FLAG_BACKUP_SEMANTICS | MVR_FLAG_POSIX_SEMANTICS,
  615. &remoteDataSetStart,
  616. &remoteFileStart,
  617. &remoteFileSize,
  618. &remoteDataStart,
  619. &remoteDataSize,
  620. &remoteVerificationType,
  621. &remoteVerificationData,
  622. &dataStreamCRCType,
  623. &dataStreamCRC,
  624. &usn);
  625. WsbTrace(OLESTR("StoreData returned hr = <%ls>\n"),WsbHrAsString(hr));
  626. ReportMediaProgress(HSM_JOB_MEDIA_STATE_TRANSFERRED, hr);
  627. if (S_OK == hr) {
  628. // Save the offset on the tape of the data set if we
  629. // don't have it; confirm it if we do
  630. if (0 == m_RemoteDataSetStart.QuadPart) {
  631. m_RemoteDataSetStart = remoteDataSetStart;
  632. } else {
  633. WsbAssert(m_RemoteDataSetStart.QuadPart ==
  634. remoteDataSetStart.QuadPart,
  635. WSB_E_INVALID_DATA);
  636. }
  637. //
  638. // Fill in the placeholder data
  639. //
  640. placeholder.bagId = m_BagId;
  641. placeholder.hsmId = m_HsmId;
  642. placeholder.fileStart = remoteFileStart.QuadPart;
  643. placeholder.fileSize = remoteFileSize.QuadPart;
  644. placeholder.dataStart = remoteDataStart.QuadPart;
  645. placeholder.dataSize = remoteDataSize.QuadPart;
  646. placeholder.verificationData = remoteVerificationData.QuadPart;
  647. placeholder.verificationType = remoteVerificationType;
  648. placeholder.fileVersionId = fileVersionId;
  649. placeholder.dataStreamCRCType = dataStreamCRCType;
  650. placeholder.dataStreamCRC = dataStreamCRC.QuadPart;
  651. WsbAffirmHr(pFsaWorkItem->SetPlaceholder(&placeholder));
  652. WsbAffirmHr(pFsaWorkItem->SetUSN(usn.QuadPart));
  653. //
  654. // Update media information
  655. WsbAffirmHr(GetMediaParameters());
  656. done = TRUE;
  657. } else {
  658. switch (hr) {
  659. case MVR_E_END_OF_MEDIA:
  660. case MVR_E_DISK_FULL:
  661. //
  662. // We have run out of disk space so mark the media full
  663. // and try again
  664. //
  665. // To really cleanup, we should remove the portion
  666. // written TBD
  667. //
  668. WsbAffirmHr(MarkMediaFull(pFsaWorkItem, m_MediaId));
  669. mediaToUse = GUID_NULL;
  670. break;
  671. case MVR_E_MEDIA_ABORT:
  672. //
  673. // Media is most likely bad - mark it as such, then abort
  674. //
  675. WsbAffirmHr(MarkMediaBad(pFsaWorkItem, m_MediaId, hr));
  676. done = TRUE;
  677. break;
  678. default:
  679. // We failed the copy somehow. Report this error.
  680. done = TRUE;
  681. break;
  682. }
  683. }
  684. } else {
  685. done = TRUE;
  686. }
  687. }
  688. } WsbCatch( hr );
  689. WsbTraceOut(OLESTR("CHsmWorkQueue::PremigrateIt"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  690. return( hr );
  691. }
  692. HRESULT
  693. CHsmWorkQueue::RecallIt(
  694. IFsaPostIt *pFsaWorkItem
  695. )
  696. {
  697. HRESULT hr = S_OK;
  698. GUID mediaToUse = GUID_NULL;
  699. CComPtr<IFsaScanItem> pScanItem;
  700. LONGLONG readOffset;
  701. WsbTraceIn(OLESTR("CHsmWorkQueue::RecallIt"),OLESTR(""));
  702. try {
  703. GetScanItem(pFsaWorkItem, &pScanItem);
  704. if ((m_RequestAction != FSA_REQUEST_ACTION_FILTER_READ) &&
  705. (m_RequestAction != FSA_REQUEST_ACTION_FILTER_RECALL)) {
  706. //
  707. // Non-demand recall - make sure the file has not changed
  708. //
  709. hr = CheckForChanges(pFsaWorkItem);
  710. } else {
  711. //
  712. // For demand recalls we have to assume the file has not changed since we
  713. // recall on the first read or write.
  714. //
  715. hr = S_OK; //CheckForChanges(pFsaWorkItem);
  716. }
  717. if ( S_OK == hr ) {
  718. CComPtr<IWsbIndexedCollection> pMountingCollection;
  719. CComPtr<IMountingMedia> pMountingMedia;
  720. CComPtr<IMountingMedia> pMediaToFind;
  721. BOOL bMediaMounting = FALSE;
  722. BOOL bMediaMountingAdded = FALSE;
  723. BOOL bMediaChanged = FALSE;
  724. // Find the media that contains the file
  725. WsbAffirmHr(FindRecallMediaToUse(pFsaWorkItem, &mediaToUse, &bMediaChanged));
  726. if (bMediaChanged) {
  727. // Check if the media is already in the process of mounting
  728. WsbAffirmHr(m_pServer->LockMountingMedias());
  729. try {
  730. // Check if the media to mount is already mounting
  731. WsbAffirmHr(m_pServer->GetMountingMedias(&pMountingCollection));
  732. WsbAffirmHr(CoCreateInstance(CLSID_CMountingMedia, 0, CLSCTX_SERVER, IID_IMountingMedia, (void**)&pMediaToFind));
  733. WsbAffirmHr(pMediaToFind->SetMediaId(mediaToUse));
  734. hr = pMountingCollection->Find(pMediaToFind, IID_IMountingMedia, (void **)&pMountingMedia);
  735. if (hr == S_OK) {
  736. // Media is already mounting...
  737. bMediaMounting = TRUE;
  738. } else if (hr == WSB_E_NOTFOUND) {
  739. // New media to mount - add to the mounting list
  740. hr = S_OK;
  741. WsbAffirmHr(pMediaToFind->Init(mediaToUse, TRUE));
  742. WsbAffirmHr(pMountingCollection->Add(pMediaToFind));
  743. bMediaMountingAdded = TRUE;
  744. } else {
  745. WsbAffirmHr(hr);
  746. }
  747. } WsbCatchAndDo(hr,
  748. // Unlock mounting media
  749. m_pServer->UnlockMountingMedias();
  750. WsbTraceAlways(OLESTR("CHsmWorkQueue::RecallIt: error while trying to find/add mounting media. hr=<%ls>\n"),
  751. WsbHrAsString(hr));
  752. // Bale out
  753. WsbThrow(hr);
  754. );
  755. // Release the lock
  756. WsbAffirmHr(m_pServer->UnlockMountingMedias());
  757. }
  758. // If the media is mounting - wait for the mount event
  759. if (bMediaMounting) {
  760. WsbAffirmHr(pMountingMedia->WaitForMount(INFINITE));
  761. pMountingMedia = 0;
  762. }
  763. //
  764. // Get the media mounted (hr is checked only after removing from the mounting-media list)
  765. //
  766. hr = MountMedia(pFsaWorkItem, mediaToUse);
  767. // If added to the mounting list - remove
  768. if (bMediaMountingAdded) {
  769. HRESULT hrRemove = S_OK;
  770. // No matter how the Mount finished - free waiting clients and remove from the list
  771. hrRemove = m_pServer->LockMountingMedias();
  772. WsbAffirmHr(hrRemove);
  773. try {
  774. WsbAffirmHr(pMediaToFind->MountDone());
  775. WsbAffirmHr(pMountingCollection->RemoveAndRelease(pMediaToFind));
  776. pMediaToFind = 0;
  777. } WsbCatch(hrRemove);
  778. m_pServer->UnlockMountingMedias();
  779. // We don't expect any errors while removing the mounting media -
  780. // The thread that added to the collection is always the one that removes
  781. if (! SUCCEEDED(hrRemove)) {
  782. WsbTraceAlways(OLESTR("CHsmWorkQueue::RecallIt: error while trying to remove a mounting media. hr=<%ls>\n"),
  783. WsbHrAsString(hrRemove));
  784. WsbThrow(hrRemove);
  785. }
  786. }
  787. //
  788. // Check the Mount result
  789. //
  790. WsbAffirmHr(hr);
  791. //
  792. // Copy the data
  793. //
  794. // Build the source path
  795. CWsbStringPtr tmpString;
  796. WsbAffirmHr(GetSource(pFsaWorkItem, &tmpString));
  797. CWsbBstrPtr localName = tmpString;
  798. // Ask the Data mover to store the data
  799. LONGLONG requestSize;
  800. LONGLONG requestStart;
  801. ULARGE_INTEGER localDataStart;
  802. ULARGE_INTEGER localDataSize;
  803. ULARGE_INTEGER remoteFileStart;
  804. ULARGE_INTEGER remoteFileSize;
  805. ULARGE_INTEGER remoteDataStart;
  806. ULARGE_INTEGER remoteDataSize;
  807. ULARGE_INTEGER remoteVerificationData;
  808. ULONG remoteVerificationType;
  809. FSA_PLACEHOLDER placeholder;
  810. WsbAffirmHr(pFsaWorkItem->GetPlaceholder(&placeholder));
  811. WsbAffirmHr(pFsaWorkItem->GetRequestSize(&requestSize));
  812. WsbAffirmHr(pFsaWorkItem->GetRequestOffset(&requestStart));
  813. //
  814. // Build strings
  815. //
  816. CWsbStringPtr strGuid;
  817. CWsbBstrPtr sessionName = HSM_BAG_NAME;
  818. WsbAffirmHr(WsbSafeGuidAsString(m_BagId, strGuid));
  819. sessionName.Append(strGuid);
  820. CWsbBstrPtr sessionDescription = HSM_ENGINE_ID;
  821. WsbAffirmHr(WsbSafeGuidAsString(m_HsmId, strGuid));
  822. sessionDescription.Append(strGuid);
  823. localDataStart.QuadPart = requestStart;
  824. localDataSize.QuadPart = requestSize;
  825. remoteFileStart.QuadPart = placeholder.fileStart;
  826. remoteFileSize.QuadPart = placeholder.fileSize;
  827. remoteDataStart.QuadPart = placeholder.dataStart;
  828. remoteDataSize.QuadPart = placeholder.dataSize;
  829. remoteVerificationData.QuadPart = placeholder.verificationData;
  830. remoteVerificationType = placeholder.verificationType;
  831. ReportMediaProgress(HSM_JOB_MEDIA_STATE_TRANSFERRING, hr);
  832. CComPtr<IStream> pLocalStream;
  833. CComPtr<IStream> pRemoteStream;
  834. ULARGE_INTEGER offset, read, written;
  835. DWORD verifyType;
  836. if ((m_RequestAction == FSA_REQUEST_ACTION_FILTER_READ) ||
  837. (m_RequestAction == FSA_REQUEST_ACTION_FILTER_RECALL)) {
  838. //
  839. // We are doing a read without recall, so get the
  840. // recall object's data mover
  841. //
  842. CComPtr<IFsaFilterRecall> pRecall;
  843. WsbAffirmHr(pFsaWorkItem->GetFilterRecall(&pRecall));
  844. WsbAffirmHr(pRecall->CreateLocalStream( &pLocalStream));
  845. WsbAffirmHr(pRecall->GetSize( (LONGLONG *) &remoteDataSize.QuadPart ));
  846. WsbAffirmHr(pRecall->GetOffset( &readOffset ));
  847. if (readOffset == 0) {
  848. verifyType = MVR_VERIFICATION_TYPE_HEADER_CRC;
  849. } else {
  850. verifyType = MVR_VERIFICATION_TYPE_NONE;
  851. }
  852. } else {
  853. //
  854. // We are doing a file recall (not a demand recall) so get the FSA data mover
  855. //
  856. verifyType = MVR_VERIFICATION_TYPE_HEADER_CRC;
  857. readOffset = 0;
  858. WsbAffirmPointer(pScanItem);
  859. WsbAffirmHr(pScanItem->CreateLocalStream( &pLocalStream ) );
  860. }
  861. //
  862. // Create remote data mover stream
  863. // TEMPORARY: Consider removing the NO_CACHING flag for a NO_RECALL recall
  864. //
  865. WsbAssert(0 != m_RemoteDataSetStart.QuadPart, HSM_E_BAD_SEGMENT_INFORMATION);
  866. WsbAffirmHr( m_pDataMover->CreateRemoteStream(
  867. CWsbBstrPtr(L""),
  868. MVR_MODE_READ | MVR_FLAG_HSM_SEMANTICS | MVR_FLAG_NO_CACHING,
  869. sessionName,
  870. sessionDescription,
  871. m_RemoteDataSetStart,
  872. remoteFileStart,
  873. remoteFileSize,
  874. remoteDataStart,
  875. remoteDataSize,
  876. verifyType,
  877. remoteVerificationData,
  878. &pRemoteStream ) );
  879. //
  880. // The offset given here is the offset into the stream itself (readOffset).
  881. // The actual position on remote media will be the bag start plus the file start
  882. // plus the file-data start (all given in CreateRemoteStream) plus this offset.
  883. //
  884. WsbTrace(OLESTR("Setting offset to %I64d reading %I64u\n"), readOffset, remoteDataSize.QuadPart);
  885. offset.QuadPart = readOffset;
  886. WsbAffirmHr( m_pDataMover->SetInitialOffset( offset ) );
  887. //
  888. // Once the remote stream has been created we must make sure we detach it
  889. //
  890. try {
  891. WsbAffirmHr( pRemoteStream->CopyTo( pLocalStream, remoteDataSize, &read, &written ) );
  892. WsbAffirmHr( pLocalStream->Commit( STGC_DEFAULT ) );
  893. //
  894. // The CopyTo succeeded... make sure we got all the bytes
  895. // we asked for.
  896. //
  897. // If we attempt to read from a incomplete Master that
  898. // does not contain the migrated data we'll fail here with
  899. // MVR_S_NO_DATA_DETECTED.
  900. //
  901. WsbAffirm( written.QuadPart == remoteDataSize.QuadPart, HSM_E_VALIDATE_DATA_NOT_ON_MEDIA );
  902. WsbAffirmHr( m_pDataMover->CloseStream() );
  903. } WsbCatchAndDo(hr,
  904. WsbAffirmHr( m_pDataMover->CloseStream() );
  905. );
  906. ReportMediaProgress(HSM_JOB_MEDIA_STATE_TRANSFERRED, hr);
  907. WsbTrace(OLESTR("RecallData returned hr = <%ls>\n"),WsbHrAsString(hr));
  908. } else {
  909. //
  910. // The file has changed or is not in the correct state
  911. //
  912. WsbTrace(OLESTR("The file has changed between asking for the recall and the actual recall\n"));
  913. WsbAffirmHr( hr );
  914. }
  915. } WsbCatch( hr );
  916. // Tell the session whether or not the work was done.
  917. // We don't really care about the return code, there is nothing
  918. // we can do if it fails.
  919. WsbTrace(OLESTR("Tried HSM work, calling Session to Process Item\n"));
  920. if (pScanItem) {
  921. m_pSession->ProcessItem(m_JobPhase, m_JobAction, pScanItem, hr);
  922. }
  923. WsbTraceOut(OLESTR("CHsmWorkQueue::RecallIt"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  924. return( hr );
  925. }
  926. HRESULT
  927. CHsmWorkQueue::validateIt(
  928. IFsaPostIt *pFsaWorkItem
  929. )
  930. /*
  931. Routine Description:
  932. This Engine internal helper method is used to validate a scan item which has a
  933. reparse point (found by the FSA during a resource scan).
  934. When this method gets control it already knows the resource (e.g., volume) it is
  935. operating against by virtue of the work queue being tied to a volume. The PostIt
  936. object whose interface pointer has been passed into this method is tied to a
  937. specific scan item (e.g.,file). So on call this method knows both the resource
  938. and scan item it is validating.
  939. Validating a file with a reparse point on it means verifying that this file's info
  940. is properly contained in the HSM databases and that the file's bag is contained on
  941. its master secondary storage media.
  942. After getting basic info (the resource id and the file's placeholder info), the method
  943. first verifies that the placeholder's bag is contained in the Bag Info Table. If so,
  944. the file's segment is then verified as being contained in the Segment Table. Providing
  945. it is, the master media id contained in the Segment Table record is verified as
  946. being contained in the Media Info Table. Finally the Remote Data Set (bag) the file
  947. belongs to is verified as being contained on the master media.
  948. If any of the above verifications fail the PostIt object is marked to request a
  949. Result Action of 'Validate Bad' from the FSA, and the PostIt is sent back to the
  950. FSA to perform that action. (Validate Bad action means that a file in a Premigrated
  951. state will have its placeholder removed, changing it to a normal (unmanaged) file,
  952. and a Truncated file will be deleted.)
  953. If the file validates up to this point, then the PostIt is marked accordingly (which
  954. will cause the FSA to update the Premigrated/Truncated stats as appropriate) and a
  955. couple of final checks are made. First, if the resource the file is presently on
  956. does not agree with the resource stored in the Bag Info Table record (meaning
  957. the reparsed file was moved without being recalled, e.g., backing up the file and
  958. restoring it to another volume), an entry is added to the Volume Assignment Table.
  959. Secondly, if the file is present in the Bag Hole Table (meaning it has been deleted)
  960. it is removed from there.
  961. Arguments:
  962. pFsaWorkItem - Interface pointer to the PostIt object initiated by the FSA. The
  963. PostIt object correlates to a specific scan item.
  964. Return Value:
  965. S_OK - The call succeeded (the specified scan item was validated, and the appropriate
  966. result action was filled into the PostIt, which will be sent back to the
  967. FSA for action).
  968. Any other value - The call failed in one of the embedded Remote Storage API calls.
  969. The result will be specific to the call that failed.
  970. */
  971. {
  972. HRESULT hr = S_OK;
  973. GUID l_BagVolId;
  974. GUID resourceId;
  975. LONGLONG l_FileStart = 0;
  976. FSA_PLACEHOLDER placeholder;
  977. CWsbStringPtr path;
  978. CComQIPtr<ISegDb, &IID_ISegDb> pSegDb = m_pSegmentDb;
  979. CComPtr<IRmsServer> pRmsServer;
  980. CComPtr<IRmsCartridge> pMedia;
  981. GUID mediaSubsystemId;
  982. WsbTraceIn(OLESTR("CHsmWorkQueue::validateIt"),OLESTR(""));
  983. try {
  984. memset(&placeholder, 0, sizeof(FSA_PLACEHOLDER));
  985. //
  986. // Get starting info and set hsm work queue object's bag id to that contained
  987. // in the scan item's placeholder
  988. //
  989. WsbAffirmHr( m_pFsaResource->GetIdentifier( &resourceId ));
  990. WsbAffirmHr( pFsaWorkItem->GetPlaceholder( &placeholder ));
  991. m_BagId = placeholder.bagId;
  992. l_FileStart = placeholder.fileStart;
  993. WsbAffirmHr( pFsaWorkItem->GetPath( &path, 0 ));
  994. WsbTrace( OLESTR("Beginning to validate <%s>.\n"), path );
  995. //
  996. // Make sure the segment is in the Segment Table (seek the segment record
  997. // whose keys (bag id, file start and file size) match what is in the placeholder).
  998. // Note: We need to start with this table since the real BAG is different for indirect segments.
  999. //
  1000. CComPtr<ISegRec> pSegRec;
  1001. GUID l_BagId;
  1002. LONGLONG l_FileSize;
  1003. USHORT l_SegFlags;
  1004. GUID l_PrimPos;
  1005. LONGLONG l_SecPos;
  1006. hr = pSegDb->SegFind( m_pDbWorkSession, m_BagId, placeholder.fileStart,
  1007. placeholder.fileSize, &pSegRec );
  1008. if (S_OK != hr ) {
  1009. hr = HSM_E_VALIDATE_SEGMENT_NOT_FOUND;
  1010. WsbAffirmHr(pFsaWorkItem->SetResult(hr));
  1011. WsbThrow(hr);
  1012. }
  1013. // Segment is in the table. Get segment record since we use l_PrimPos in next step
  1014. WsbTrace( OLESTR("(validateIt) <%s> found in Segment table, continuing...\n"),
  1015. path );
  1016. WsbAffirmHr( pSegRec->GetSegmentRecord( &l_BagId, &l_FileStart, &l_FileSize,
  1017. &l_SegFlags, &l_PrimPos, &l_SecPos ));
  1018. //
  1019. // In case of an indirect record, go to the dirtect record to get real location info
  1020. //
  1021. if (l_SegFlags & SEG_REC_INDIRECT_RECORD) {
  1022. pSegRec = 0;
  1023. hr = pSegDb->SegFind(m_pDbWorkSession, l_PrimPos, l_SecPos,
  1024. placeholder.fileSize, &pSegRec);
  1025. if (S_OK != hr ) {
  1026. // We couldn't find the direct segment record for this segment!
  1027. hr = HSM_E_VALIDATE_SEGMENT_NOT_FOUND;
  1028. WsbAffirmHr(pFsaWorkItem->SetResult(hr));
  1029. WsbThrow(hr);
  1030. }
  1031. WsbTrace( OLESTR("(validateIt) direct segment for <%s> found in Segment table, continuing...\n"),
  1032. path );
  1033. WsbAffirmHr(pSegRec->GetSegmentRecord(&l_BagId, &l_FileStart, &l_FileSize,
  1034. &l_SegFlags, &l_PrimPos, &l_SecPos));
  1035. // Don't support a second indirection for now !!
  1036. if (l_SegFlags & SEG_REC_INDIRECT_RECORD) {
  1037. hr = HSM_E_BAD_SEGMENT_INFORMATION;
  1038. WsbAffirmHr(pFsaWorkItem->SetResult(hr));
  1039. WsbThrow(hr);
  1040. }
  1041. // Change Bag id to the real one
  1042. m_BagId = l_BagId;
  1043. }
  1044. //
  1045. // Make sure the BAG ID is in the Bag Info Table (get the Bag Info Table
  1046. // (entity) in the Segment database, set the key value (bag id) to that
  1047. // contained in the placeholder and get that record. If found, the Bag
  1048. // is in the Bag Info Table).
  1049. //
  1050. CComPtr<IBagInfo> pBagInfo;
  1051. FILETIME l_BirthDate;
  1052. HSM_BAG_STATUS l_BagStatus;
  1053. LONGLONG l_BagLen;
  1054. USHORT l_BagType;
  1055. LONGLONG l_DeletedBagAmount;
  1056. SHORT l_RemoteDataSet;
  1057. WsbAffirmHr( m_pSegmentDb->GetEntity( m_pDbWorkSession, HSM_BAG_INFO_REC_TYPE,
  1058. IID_IBagInfo, (void**)&pBagInfo ));
  1059. GetSystemTimeAsFileTime(&l_BirthDate);
  1060. WsbAffirmHr( pBagInfo->SetBagInfo( HSM_BAG_STATUS_IN_PROGRESS, m_BagId,
  1061. l_BirthDate, 0, 0, GUID_NULL, 0, 0 ));
  1062. hr = pBagInfo->FindEQ();
  1063. if (S_OK != hr ) {
  1064. hr = HSM_E_VALIDATE_BAG_NOT_FOUND;
  1065. WsbAffirmHr(pFsaWorkItem->SetResult(hr));
  1066. WsbThrow(hr);
  1067. }
  1068. // Bag is in the table. Trace, then get bag record since we will use some
  1069. // info later (l_RemoteDataSet, l_BagVolId).
  1070. WsbTrace( OLESTR("(validateIt) <%s> found in Bag Info table, continuing...\n"),
  1071. path );
  1072. WsbAffirmHr( pBagInfo->GetBagInfo( &l_BagStatus, &l_BagId, &l_BirthDate,
  1073. &l_BagLen, &l_BagType, &l_BagVolId,
  1074. &l_DeletedBagAmount, &l_RemoteDataSet ));
  1075. //
  1076. // Make sure the media is in the Media Info table (get Media Info Table, set
  1077. // the key (media id) to what is in the Segment record and get the record).
  1078. // Note that for Sakkara the Primary Position field in the Segment record
  1079. // (l_PrimPos) contains the id (GUID) of the media where the bag/segment is stored.
  1080. //
  1081. CComPtr<IMediaInfo> pMediaInfo;
  1082. WsbAffirmHr( m_pSegmentDb->GetEntity( m_pDbWorkSession, HSM_MEDIA_INFO_REC_TYPE,
  1083. IID_IMediaInfo, (void**)&pMediaInfo ));
  1084. WsbAffirmHr( pMediaInfo->SetId( l_PrimPos ));
  1085. hr = pMediaInfo->FindEQ();
  1086. if (S_OK != hr ) {
  1087. hr = HSM_E_VALIDATE_MEDIA_NOT_FOUND;
  1088. WsbAffirmHr(pFsaWorkItem->SetResult(hr));
  1089. WsbThrow(hr);
  1090. }
  1091. WsbTrace( OLESTR("(validateIt) <%s> found in Media Info table, continuing...\n"),
  1092. path );
  1093. //
  1094. // Media is in the Media Info Table. Next step is to verify that the Remote Data
  1095. // Set (in concept equal to a bag) containing this scan item (e.g., file) is
  1096. // actually on the media.
  1097. //
  1098. SHORT l_MediaNextRemoteDataSet;
  1099. WsbAffirmHr( pMediaInfo->GetNextRemoteDataSet( &l_MediaNextRemoteDataSet ));
  1100. WsbTrace(
  1101. OLESTR("(validateIt) <%ls>: Bag remote dataset <%hd> Media remote dataset <%hd>\n"),
  1102. (OLECHAR*)path, l_RemoteDataSet, l_MediaNextRemoteDataSet );
  1103. if ( l_RemoteDataSet >= l_MediaNextRemoteDataSet ) {
  1104. // Remote data set containing the item is not on the media; we have a validate
  1105. // error, so set up to have FSA delete it
  1106. hr = HSM_E_VALIDATE_DATA_NOT_ON_MEDIA;
  1107. WsbAffirmHr(pFsaWorkItem->SetResult(hr));
  1108. WsbTrace( OLESTR("(validateIt) <%s>: remote data set not on media.\n"),
  1109. path );
  1110. WsbThrow(hr);
  1111. }
  1112. //
  1113. // Now verify that the media manager still knows about the media
  1114. //
  1115. WsbAffirmHr( pMediaInfo->GetMediaSubsystemId( &mediaSubsystemId ));
  1116. if (m_pRmsServer->FindCartridgeById(mediaSubsystemId , &pMedia) != S_OK) {
  1117. hr = HSM_E_VALIDATE_MEDIA_NOT_FOUND;
  1118. WsbAffirmHr(pFsaWorkItem->SetResult(hr));
  1119. WsbThrow(hr);
  1120. }
  1121. } WsbCatch( hr );
  1122. //
  1123. // If item failed to validate it has an invalid reparse point, tell FSA to remove it.
  1124. //
  1125. if (FAILED(hr)) {
  1126. WsbAffirmHr( pFsaWorkItem->SetResultAction( FSA_RESULT_ACTION_VALIDATE_BAD ));
  1127. WsbTrace(OLESTR("<%s> failed validation, result action = Validate Bad.\n"), path);
  1128. // No logging done here. Logging needs to be added to FSA (ProcessResult()).
  1129. // Clean up hr for return (tell caller this method completed).
  1130. hr = S_OK;
  1131. // Item validated, tell the FSA and do final clean-up checks
  1132. } else try {
  1133. WsbAffirmHr( pFsaWorkItem->SetResultAction( FSA_RESULT_ACTION_VALIDATE_OK ));
  1134. WsbTrace(OLESTR("<%s> passed validation, result action = Validate Ok.\n"), path);
  1135. //
  1136. // If the resource (volume) this item is on doesn't match that stored in the Bag
  1137. // Info Table, add an entry to the Volume Assignment Table
  1138. //
  1139. //
  1140. // Note: This code is commented out since nobody uses the Volume Assignment table.
  1141. // See bug 159449 in "Windows Bugs" database for more details.
  1142. //
  1143. // if ( !IsEqualGUID( resourceId, l_BagVolId )) {
  1144. // WsbAffirmHr( pSegDb->VolAssignAdd( m_pDbWorkSession, m_BagId, l_FileStart,
  1145. // placeholder.fileSize, resourceId));
  1146. // WsbTrace(OLESTR("(validateIt) <%s> volume mismatch. Entered in Vol Asgmnt Table\n"),
  1147. // path);
  1148. // }
  1149. } WsbCatch( hr );
  1150. WsbTraceOut(OLESTR("CHsmWorkQueue::validateIt"), OLESTR("hr = <%ls>"),
  1151. WsbHrAsString(hr));
  1152. return( hr );
  1153. }
  1154. HRESULT
  1155. CHsmWorkQueue::CheckForChanges(
  1156. IFsaPostIt *pFsaWorkItem
  1157. )
  1158. {
  1159. HRESULT hr = S_OK;
  1160. WsbTraceIn(OLESTR("CHsmWorkQueue::CheckForChanges"),OLESTR(""));
  1161. //
  1162. // Validate that the file is still migratable. Ask FSA
  1163. // for the latest USN of the file. If they match, then
  1164. // file is migratable, otherwise it is not. If it is
  1165. // not change the FSA_RESULT_ACTION to FSA_RESULT_ACTION_NONE.
  1166. // and quit.
  1167. //
  1168. try {
  1169. CComPtr<IFsaScanItem> pScanItem;
  1170. // Get a current scan item from the FSA for this work item
  1171. hr = GetScanItem(pFsaWorkItem, &pScanItem);
  1172. if (WSB_E_NOTFOUND == hr) {
  1173. //
  1174. // We cannot find the file, so just return not OK
  1175. //
  1176. WsbThrow(S_FALSE);
  1177. }
  1178. //
  1179. // Make sure we did not get some other kind of error.
  1180. //
  1181. WsbAffirmHr(hr);
  1182. // Check to see that the file is in the correct
  1183. // state to do the requested action
  1184. //
  1185. FSA_REQUEST_ACTION workAction;
  1186. WsbAffirmHr(pFsaWorkItem->GetRequestAction(&workAction));
  1187. switch (workAction) {
  1188. case FSA_REQUEST_ACTION_VALIDATE:
  1189. //
  1190. // No Checks required here
  1191. //
  1192. hr = S_OK;
  1193. break;
  1194. case FSA_REQUEST_ACTION_DELETE:
  1195. //
  1196. // Make it is still OK to delete the file
  1197. //
  1198. WsbAffirmHr(pScanItem->IsDeleteOK(pFsaWorkItem) );
  1199. break;
  1200. case FSA_REQUEST_ACTION_PREMIGRATE:
  1201. //
  1202. // Make sure the file is still manageable by asking the FSA
  1203. //
  1204. WsbAffirmHr(pScanItem->IsMigrateOK(pFsaWorkItem));
  1205. break;
  1206. case FSA_REQUEST_ACTION_FILTER_RECALL:
  1207. case FSA_REQUEST_ACTION_RECALL:
  1208. //
  1209. // Make sure the file is recallable by asking the FSA
  1210. //
  1211. WsbAffirmHr(pScanItem->IsRecallOK(pFsaWorkItem));
  1212. break;
  1213. case FSA_REQUEST_ACTION_FILTER_READ:
  1214. //
  1215. // Cannot check for truncated because the file is open
  1216. //
  1217. hr = S_OK;
  1218. break;
  1219. default:
  1220. hr = E_NOTIMPL;
  1221. break;
  1222. }
  1223. } WsbCatch (hr)
  1224. if (FSA_E_FILE_CHANGED == hr ) {
  1225. hr = HSM_E_FILE_CHANGED;
  1226. } else if (FSA_E_FILE_ALREADY_MANAGED == hr ) {
  1227. hr = HSM_E_FILE_ALREADY_MANAGED;
  1228. } else if (FSA_E_FILE_NOT_TRUNCATED == hr ) {
  1229. hr = HSM_E_FILE_NOT_TRUNCATED;
  1230. }
  1231. WsbTraceOut(OLESTR("CHsmWorkQueue::CheckForChanges"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  1232. return( hr );
  1233. }
  1234. HRESULT
  1235. CHsmWorkQueue::RaisePriority(
  1236. void
  1237. )
  1238. /*++
  1239. --*/
  1240. {
  1241. HRESULT hr = S_OK;
  1242. WsbTraceIn(OLESTR("CHsmWorkQueue::RaisePriority"),OLESTR(""));
  1243. try {
  1244. WsbAssert(0 != m_WorkerThread, E_UNEXPECTED);
  1245. WsbAssert(m_pSession != 0, E_UNEXPECTED);
  1246. switch(m_JobPriority) {
  1247. case HSM_JOB_PRIORITY_IDLE:
  1248. WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_LOWEST));
  1249. m_JobPriority = HSM_JOB_PRIORITY_LOWEST;
  1250. break;
  1251. case HSM_JOB_PRIORITY_LOWEST:
  1252. WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_BELOW_NORMAL));
  1253. m_JobPriority = HSM_JOB_PRIORITY_LOW;
  1254. break;
  1255. case HSM_JOB_PRIORITY_LOW:
  1256. WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_NORMAL));
  1257. m_JobPriority = HSM_JOB_PRIORITY_NORMAL;
  1258. break;
  1259. case HSM_JOB_PRIORITY_NORMAL:
  1260. WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_ABOVE_NORMAL));
  1261. m_JobPriority = HSM_JOB_PRIORITY_HIGH;
  1262. break;
  1263. case HSM_JOB_PRIORITY_HIGH:
  1264. WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_HIGHEST));
  1265. m_JobPriority = HSM_JOB_PRIORITY_HIGHEST;
  1266. break;
  1267. case HSM_JOB_PRIORITY_HIGHEST:
  1268. WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_TIME_CRITICAL));
  1269. m_JobPriority = HSM_JOB_PRIORITY_CRITICAL;
  1270. break;
  1271. default:
  1272. case HSM_JOB_PRIORITY_CRITICAL:
  1273. WsbAffirm(FALSE, E_UNEXPECTED);
  1274. break;
  1275. }
  1276. WsbAffirmHr(m_pSession->ProcessPriority(m_JobPhase, m_JobPriority));
  1277. } WsbCatch(hr);
  1278. WsbTraceOut(OLESTR("CHsmWorkQueue::RaisePriority"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  1279. return(hr);
  1280. }
  1281. HRESULT
  1282. CHsmWorkQueue::LowerPriority(
  1283. void
  1284. )
  1285. /*++
  1286. --*/
  1287. {
  1288. HRESULT hr = S_OK;
  1289. WsbTraceIn(OLESTR("CHsmWorkQueue::LowerPriority"),OLESTR(""));
  1290. try {
  1291. WsbAssert(0 != m_WorkerThread, E_UNEXPECTED);
  1292. WsbAssert(m_pSession != 0, E_UNEXPECTED);
  1293. switch(m_JobPriority) {
  1294. case HSM_JOB_PRIORITY_IDLE:
  1295. WsbAffirm(FALSE, E_UNEXPECTED);
  1296. break;
  1297. case HSM_JOB_PRIORITY_LOWEST:
  1298. WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_IDLE));
  1299. m_JobPriority = HSM_JOB_PRIORITY_IDLE;
  1300. break;
  1301. case HSM_JOB_PRIORITY_LOW:
  1302. WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_LOWEST));
  1303. m_JobPriority = HSM_JOB_PRIORITY_LOWEST;
  1304. break;
  1305. case HSM_JOB_PRIORITY_NORMAL:
  1306. WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_BELOW_NORMAL));
  1307. m_JobPriority = HSM_JOB_PRIORITY_LOW;
  1308. break;
  1309. case HSM_JOB_PRIORITY_HIGH:
  1310. WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_NORMAL));
  1311. m_JobPriority = HSM_JOB_PRIORITY_NORMAL;
  1312. break;
  1313. case HSM_JOB_PRIORITY_HIGHEST:
  1314. WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_ABOVE_NORMAL));
  1315. m_JobPriority = HSM_JOB_PRIORITY_HIGH;
  1316. break;
  1317. default:
  1318. case HSM_JOB_PRIORITY_CRITICAL:
  1319. WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_HIGHEST));
  1320. m_JobPriority = HSM_JOB_PRIORITY_HIGHEST;
  1321. break;
  1322. }
  1323. WsbAffirmHr(m_pSession->ProcessPriority(m_JobPhase, m_JobPriority));
  1324. } WsbCatch(hr);
  1325. WsbTraceOut(OLESTR("CHsmWorkQueue::LowerPriority"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  1326. return(hr);
  1327. }
  1328. HRESULT
  1329. CHsmWorkQueue::CheckRms(
  1330. void
  1331. )
  1332. /*++
  1333. --*/
  1334. {
  1335. HRESULT hr = S_OK;
  1336. WsbTraceIn(OLESTR("CHsmWorkQueue::CheckRms"),OLESTR(""));
  1337. try {
  1338. //
  1339. // Make sure we can still talk to the RMS
  1340. //
  1341. if (m_pRmsServer != 0) {
  1342. CWsbBstrPtr name;
  1343. hr = m_pRmsServer->GetServerName( &name );
  1344. if (hr != S_OK) {
  1345. m_pRmsServer = 0;
  1346. hr = S_OK;
  1347. }
  1348. }
  1349. //
  1350. // Get RMS that runs on this machine
  1351. //
  1352. if (m_pRmsServer == 0) {
  1353. WsbAffirmHr(m_pServer->GetHsmMediaMgr(&m_pRmsServer));
  1354. // wait for RMS to come ready
  1355. // (this may not be needed anymore - if Rms initialization is
  1356. // synced with Engine initialization)
  1357. CComObject<CRmsSink> *pSink = new CComObject<CRmsSink>;
  1358. WsbAffirm(0 != pSink, E_OUTOFMEMORY);
  1359. CComPtr<IUnknown> pSinkUnk = pSink; // holds refcount for use here
  1360. WsbAffirmHr( pSink->Construct( m_pRmsServer ) );
  1361. WsbAffirmHr( pSink->WaitForReady( ) );
  1362. WsbAffirmHr( pSink->DoUnadvise( ) );
  1363. }
  1364. } WsbCatch( hr );
  1365. WsbTraceOut(OLESTR("CHsmWorkQueue::CheckRms"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  1366. return(hr);
  1367. }
  1368. HRESULT
  1369. CHsmWorkQueue::CheckSession(
  1370. IHsmSession *pSession
  1371. )
  1372. /*++
  1373. --*/
  1374. {
  1375. HRESULT hr = S_OK;
  1376. BOOL bLog = TRUE;
  1377. WsbTraceIn(OLESTR("CHsmWorkQueue::CheckSession"),OLESTR(""));
  1378. try {
  1379. if ((m_pSession != 0) && (m_pSession != pSession)) {
  1380. //Don't expect this queue guy to switch sessions
  1381. WsbTrace(OLESTR("Not Switching sessions at this time so we are failing.\n"));
  1382. WsbThrow( E_UNEXPECTED );
  1383. }
  1384. //
  1385. // Check to see if we have dealt with this or any other session before.
  1386. if (m_pSession == 0) {
  1387. WsbTrace(OLESTR("New session.\n"));
  1388. //
  1389. // We have no on going session so we need to establish communication
  1390. // with this session.
  1391. //
  1392. CComPtr<IHsmSessionSinkEveryState> pSinkState;
  1393. CComPtr<IHsmSessionSinkEveryEvent> pSinkEvent;
  1394. CComPtr<IConnectionPointContainer> pCPC;
  1395. CComPtr<IConnectionPoint> pCP;
  1396. // Tell the session we are starting up.
  1397. m_JobState = HSM_JOB_STATE_STARTING;
  1398. WsbTrace(OLESTR("Before Process State.\n"));
  1399. WsbAffirmHr(pSession->ProcessState(m_JobPhase, m_JobState, m_CurrentPath, bLog));
  1400. WsbTrace(OLESTR("After Process State.\n"));
  1401. // Get the interface to the callback that the sessions should use.
  1402. WsbTrace(OLESTR("Before QI's for sinks.\n"));
  1403. WsbAffirmHr(((IUnknown*) (IHsmFsaTskMgr*) this)->QueryInterface(IID_IHsmSessionSinkEveryState, (void**) &pSinkState));
  1404. WsbAffirmHr(((IUnknown*) (IHsmFsaTskMgr*) this)->QueryInterface(IID_IHsmSessionSinkEveryEvent, (void**) &pSinkEvent));
  1405. WsbTrace(OLESTR("After QI's for sinks.\n"));
  1406. // Ask the session to advise of every state changes.
  1407. WsbTrace(OLESTR("Before QI for connection point containers.\n"));
  1408. WsbAffirmHr(pSession->QueryInterface(IID_IConnectionPointContainer, (void**) &pCPC));
  1409. WsbAffirmHr(pCPC->FindConnectionPoint(IID_IHsmSessionSinkEveryState, &pCP));
  1410. WsbAffirmHr(pCP->Advise(pSinkState, &m_StateCookie));
  1411. pCP = 0;
  1412. WsbAffirmHr(pCPC->FindConnectionPoint(IID_IHsmSessionSinkEveryEvent, &pCP));
  1413. WsbAffirmHr(pCP->Advise(pSinkEvent, &m_EventCookie));
  1414. pCP = 0;
  1415. WsbTrace(OLESTR("After Advises.\n"));
  1416. //
  1417. // Get the resource for this work from the session
  1418. //
  1419. WsbAffirmHr(pSession->GetResource(&m_pFsaResource));
  1420. // Since this is a new session, reset the counter that has become our bag start
  1421. // location
  1422. m_RemoteDataSetStart.QuadPart = 0;
  1423. m_JobState = HSM_JOB_STATE_ACTIVE;
  1424. WsbTrace(OLESTR("Before Process State.\n"));
  1425. WsbAffirmHr(pSession->ProcessState(m_JobPhase, m_JobState, m_CurrentPath, bLog));
  1426. WsbTrace(OLESTR("After Process State.\n"));
  1427. m_pSession = pSession;
  1428. }
  1429. } WsbCatch( hr );
  1430. WsbTraceOut(OLESTR("CHsmWorkQueue::CheckSession"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  1431. return(hr);
  1432. }
  1433. HRESULT
  1434. CHsmWorkQueue::StartNewBag(
  1435. void
  1436. )
  1437. /*++
  1438. --*/
  1439. {
  1440. HRESULT hr = S_OK;
  1441. CComPtr<IBagInfo> pBagInfo;
  1442. WsbTraceIn(OLESTR("CHsmWorkQueue::StartNewBag"),OLESTR(""));
  1443. try {
  1444. if (0 == m_RemoteDataSetStart.QuadPart) {
  1445. //
  1446. // Get a new ID
  1447. //
  1448. WsbAffirmHr(CoCreateGuid(&m_BagId));
  1449. // Add an entry into the Bag Info Table
  1450. FILETIME birthDate;
  1451. GUID resourceId;
  1452. WsbAffirmHr(m_pFsaResource->GetIdentifier(&resourceId));
  1453. WsbAffirmHr(m_pSegmentDb->GetEntity(m_pDbWorkSession, HSM_BAG_INFO_REC_TYPE, IID_IBagInfo,
  1454. (void**)&pBagInfo));
  1455. GetSystemTimeAsFileTime(&birthDate);
  1456. //??? what is the type for this bag? Need a define for Primary bag and Reorg bag
  1457. WsbAffirmHr(pBagInfo->SetBagInfo(HSM_BAG_STATUS_IN_PROGRESS, m_BagId, birthDate, 0, 0, resourceId, 0, 0));
  1458. WsbAffirmHr(pBagInfo->MarkAsNew());
  1459. WsbAffirmHr(pBagInfo->Write());
  1460. }
  1461. } WsbCatch( hr );
  1462. WsbTraceOut(OLESTR("CHsmWorkQueue::StartNewBag"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  1463. return(hr);
  1464. }
  1465. HRESULT
  1466. CHsmWorkQueue::UpdateBagInfo(
  1467. IHsmWorkItem *pWorkItem
  1468. )
  1469. /*++
  1470. --*/
  1471. {
  1472. HRESULT hr = S_OK;
  1473. CComPtr<IBagInfo> pBagInfo;
  1474. CComPtr<IFsaPostIt> pFsaWorkItem;
  1475. FSA_PLACEHOLDER placeholder;
  1476. WsbTraceIn(OLESTR("CHsmWorkQueue::UpdateBagInfo"),OLESTR(""));
  1477. try {
  1478. //
  1479. // Get the Bag id from the work item. It is in the placeholder
  1480. // information in the postit
  1481. //
  1482. WsbAffirmHr(pWorkItem->GetFsaPostIt(&pFsaWorkItem));
  1483. WsbAffirmHr(pFsaWorkItem->GetPlaceholder(&placeholder));
  1484. //
  1485. // Go to the Bag Info database and get the bag for this work
  1486. //
  1487. FILETIME pDummyFileTime;
  1488. GetSystemTimeAsFileTime(&pDummyFileTime);
  1489. WsbAffirmHr(m_pSegmentDb->GetEntity(m_pDbWorkSession, HSM_BAG_INFO_REC_TYPE, IID_IBagInfo,
  1490. (void**)&pBagInfo));
  1491. WsbAffirmHr(pBagInfo->SetBagInfo(HSM_BAG_STATUS_IN_PROGRESS, placeholder.bagId, pDummyFileTime, 0, 0, GUID_NULL, 0, 0 ));
  1492. WsbAffirmHr(pBagInfo->FindEQ());
  1493. // Update the bag Info table - mostly just change the size of the bag
  1494. FILETIME birthDate;
  1495. USHORT bagType;
  1496. GUID bagVolId;
  1497. LONGLONG bagLength;
  1498. LONGLONG requestSize;
  1499. LONGLONG deletedBagAmount;
  1500. SHORT remoteDataSet;
  1501. HSM_BAG_STATUS bagStatus;
  1502. GUID bagId;
  1503. WsbAffirmHr(pBagInfo->GetBagInfo(&bagStatus, &bagId, &birthDate, &bagLength, &bagType, &bagVolId, &deletedBagAmount, &remoteDataSet));
  1504. WsbAffirmHr(pFsaWorkItem->GetRequestSize(&requestSize));
  1505. bagLength += requestSize;
  1506. WsbAffirmHr(pBagInfo->SetBagInfo(bagStatus, bagId, birthDate, bagLength, bagType, bagVolId, deletedBagAmount, remoteDataSet));
  1507. WsbAffirmHr(pBagInfo->Write());
  1508. } WsbCatch(hr);
  1509. WsbTraceOut(OLESTR("CHsmWorkQueue::UpdateBagInfo"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  1510. return(hr);
  1511. }
  1512. HRESULT
  1513. CHsmWorkQueue::CompleteBag( void )
  1514. /*++
  1515. --*/
  1516. {
  1517. HRESULT hr = S_OK;
  1518. CComPtr<IBagInfo> pBagInfo;
  1519. WsbTraceIn(OLESTR("CHsmWorkQueue::CompleteBag"),OLESTR(""));
  1520. try {
  1521. //
  1522. // Go to the Bag Info database and get the bag for this work
  1523. //
  1524. FILETIME pDummyFileTime;
  1525. GetSystemTimeAsFileTime(&pDummyFileTime);
  1526. WsbAffirmHr(m_pSegmentDb->GetEntity(m_pDbWorkSession, HSM_BAG_INFO_REC_TYPE, IID_IBagInfo,
  1527. (void**)&pBagInfo));
  1528. WsbAffirmHr(pBagInfo->SetBagInfo(HSM_BAG_STATUS_IN_PROGRESS, m_BagId, pDummyFileTime, 0, 0, GUID_NULL, 0, 0 ));
  1529. WsbAffirmHr(pBagInfo->FindEQ());
  1530. // Update the bag Info table - mostly just change the size of the bag
  1531. FILETIME birthDate;
  1532. USHORT bagType;
  1533. GUID bagVolId;
  1534. LONGLONG bagLength;
  1535. LONGLONG deletedBagAmount;
  1536. SHORT remoteDataSet;
  1537. HSM_BAG_STATUS bagStatus;
  1538. GUID bagId;
  1539. WsbAffirmHr(pBagInfo->GetBagInfo(&bagStatus, &bagId, &birthDate, &bagLength, &bagType, &bagVolId, &deletedBagAmount, &remoteDataSet));
  1540. WsbAffirmHr(pBagInfo->SetBagInfo(HSM_BAG_STATUS_COMPLETED, bagId, birthDate, bagLength, bagType, bagVolId, deletedBagAmount, remoteDataSet));
  1541. WsbAffirmHr(pBagInfo->Write());
  1542. } WsbCatch(hr);
  1543. WsbTraceOut(OLESTR("CHsmWorkQueue::CompleteBag"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  1544. return(hr);
  1545. }
  1546. HRESULT
  1547. CHsmWorkQueue::DoWork( void )
  1548. /*++
  1549. --*/
  1550. {
  1551. HRESULT hr = S_OK;
  1552. CWsbStringPtr path;
  1553. CComPtr<IHsmWorkItem> pWorkItem;
  1554. CComPtr<IFsaPostIt> pFsaWorkItem;
  1555. CComPtr<IHsmSession> pSaveSessionPtr;
  1556. HSM_WORK_ITEM_TYPE workType;
  1557. BOOLEAN done = FALSE;
  1558. BOOLEAN OpenedDb = FALSE;
  1559. HRESULT skipWork = S_FALSE;
  1560. WsbTraceIn(OLESTR("CHsmWorkQueue::DoWork"),OLESTR(""));
  1561. // Make sure this object isn't released (and our thread killed
  1562. // before finishing up in this routine
  1563. ((IUnknown*)(IHsmWorkQueue*)this)->AddRef();
  1564. try {
  1565. while (!done) {
  1566. BOOL WaitForMore = FALSE;
  1567. //
  1568. // Get the next work to do from the queue
  1569. //
  1570. hr = m_pWorkToDo->First(IID_IHsmWorkItem, (void **)&pWorkItem);
  1571. if (WSB_E_NOTFOUND == hr) {
  1572. // There are no entries in the queue so sleep and check
  1573. // again later
  1574. WaitForMore = TRUE;
  1575. hr = S_OK;
  1576. } else if (hr == S_OK) {
  1577. hr = CheckMigrateMinimums();
  1578. if (S_FALSE == hr) {
  1579. WaitForMore = TRUE;
  1580. hr = S_OK;
  1581. }
  1582. }
  1583. WsbAffirmHr(hr);
  1584. if (WaitForMore) {
  1585. if (OpenedDb) {
  1586. //
  1587. // Close the db before we wait for more work
  1588. //
  1589. hr = m_pSegmentDb->Close(m_pDbWorkSession);
  1590. OpenedDb = FALSE;
  1591. m_pDbWorkSession = 0;
  1592. }
  1593. Sleep(1000);
  1594. } else {
  1595. if (!OpenedDb) {
  1596. //
  1597. // Open DB for this thread
  1598. //
  1599. hr = m_pSegmentDb->Open(&m_pDbWorkSession);
  1600. if (S_OK == hr) {
  1601. WsbTrace(OLESTR("CHsmWorkQueue::DoWork - Database Opened OK\n"));
  1602. OpenedDb = TRUE;
  1603. } else {
  1604. //
  1605. // We cannot open the database - this is a catastrophic
  1606. // problem. So skip all work in the queue
  1607. //
  1608. WsbTrace(OLESTR("CHsmWorkQueue::DoWork - Database Opened failed with hr = <%ls>\n"), WsbHrAsString(hr));
  1609. skipWork = HSM_E_WORK_SKIPPED_DATABASE_ACCESS;
  1610. hr = S_OK;
  1611. }
  1612. }
  1613. WsbAffirmHr(pWorkItem->GetWorkType(&workType));
  1614. switch (workType) {
  1615. case HSM_WORK_ITEM_FSA_DONE: {
  1616. BOOL bNoDelay = FALSE; // whether to dismount immediately
  1617. //
  1618. // There is no more work to do for this queue
  1619. //
  1620. WsbTrace(OLESTR("CHsmWorkQueue::DoWork - FSA WORK DONE\n"));
  1621. //
  1622. // Finish any work that needs to be committed
  1623. // Mark the bag as complete if we are premigrating
  1624. //
  1625. if (HSM_JOB_ACTION_PREMIGRATE == m_JobAction) {
  1626. try {
  1627. WsbAffirmHr(CommitWork());
  1628. WsbAffirmHr(CompleteBag());
  1629. //
  1630. // Now save the databases at the end of the bag
  1631. // But make sure the begin session was OK.
  1632. // Note: even if there were errors while storing the data, we still want to try
  1633. // keeping the databases on the media, because some files were migrated
  1634. //
  1635. if (m_StoreDatabasesInBags && (S_OK == m_BeginSessionHr)) {
  1636. WsbAffirmHr(StoreDatabasesOnMedia());
  1637. }
  1638. } WsbCatch( hr );
  1639. // In case of premigrate - dismount immediately
  1640. bNoDelay = TRUE;
  1641. }
  1642. if (HSM_E_WORK_SKIPPED_CANCELLED == skipWork) {
  1643. //
  1644. // Let them know we are cancelled
  1645. //
  1646. (void)SetState(HSM_JOB_STATE_CANCELLED);
  1647. } else {
  1648. (void)SetState(HSM_JOB_STATE_DONE);
  1649. }
  1650. pSaveSessionPtr = m_pSession;
  1651. Remove(pWorkItem);
  1652. EndSessions(FALSE, bNoDelay);
  1653. // Close the DB
  1654. if (OpenedDb) {
  1655. WsbTrace(OLESTR("CHsmWorkQueue::DoWork - Closing the database\n"));
  1656. m_pSegmentDb->Close(m_pDbWorkSession);
  1657. OpenedDb = FALSE;
  1658. m_pDbWorkSession = 0;
  1659. }
  1660. m_pTskMgr->WorkQueueDone(pSaveSessionPtr, m_QueueType, NULL);
  1661. done = TRUE;
  1662. break;
  1663. }
  1664. case HSM_WORK_ITEM_FSA_WORK: {
  1665. if (S_FALSE == skipWork) {
  1666. //
  1667. // Get the FSA Work Item and do the work
  1668. //
  1669. hr = DoFsaWork(pWorkItem);
  1670. if (hr == RPC_E_DISCONNECTED) {
  1671. //
  1672. // This is a problem case. This means the FSA has done away with
  1673. // the recall. We would not be able process this recall any more.
  1674. // Just bail out.
  1675. //
  1676. WsbLogEvent(HSM_MESSAGE_ABORTING_RECALL_QUEUE,
  1677. 0, NULL,NULL);
  1678. //
  1679. // Indicate we're done
  1680. //
  1681. (void)SetState(HSM_JOB_STATE_DONE);
  1682. pSaveSessionPtr = m_pSession;
  1683. Remove(pWorkItem);
  1684. // Clear out any remaining items in the queue.
  1685. do {
  1686. hr = m_pWorkToDo->First(IID_IHsmWorkItem, (void **)&pWorkItem) ;
  1687. if (hr == S_OK) {
  1688. Remove(pWorkItem);
  1689. }
  1690. } while (hr == S_OK);
  1691. EndSessions(FALSE, FALSE);
  1692. //
  1693. // Close the DB
  1694. //
  1695. if (OpenedDb) {
  1696. WsbTrace(OLESTR("CHsmWorkQueue::DoWork - Closing the database\n")) ;
  1697. m_pSegmentDb->Close(m_pDbWorkSession);
  1698. OpenedDb = FALSE;
  1699. m_pDbWorkSession = 0;
  1700. }
  1701. //
  1702. // Finish with the queue & get out
  1703. //
  1704. m_pTskMgr->WorkQueueDone(pSaveSessionPtr, m_QueueType, NULL);
  1705. done = TRUE;
  1706. } else {
  1707. (void)Remove(pWorkItem);
  1708. }
  1709. } else {
  1710. //
  1711. // Skip the work
  1712. //
  1713. try {
  1714. CComPtr<IFsaScanItem> pScanItem;
  1715. WsbAffirmHr(pWorkItem->GetFsaPostIt(&pFsaWorkItem));
  1716. WsbAffirmHr(GetScanItem(pFsaWorkItem, &pScanItem));
  1717. WsbAffirmHr(pFsaWorkItem->GetRequestAction(&m_RequestAction));
  1718. if ((m_RequestAction == FSA_REQUEST_ACTION_FILTER_RECALL) ||
  1719. (m_RequestAction == FSA_REQUEST_ACTION_FILTER_READ) ||
  1720. (m_RequestAction == FSA_REQUEST_ACTION_RECALL)) {
  1721. hr = pFsaWorkItem->SetResult(skipWork);
  1722. if (S_OK == hr) {
  1723. WsbTrace(OLESTR("HSM recall (filter, read or recall) complete, calling FSA\n"));
  1724. hr = m_pFsaResource->ProcessResult(pFsaWorkItem);
  1725. WsbTrace(OLESTR("FSA ProcessResult returned <%ls>\n"), WsbHrAsString(hr));
  1726. }
  1727. }
  1728. // Avoid logging errors if job is just cancelled
  1729. if (HSM_E_WORK_SKIPPED_CANCELLED != skipWork) {
  1730. (void)m_pSession->ProcessHr(m_JobPhase, 0, 0, hr);
  1731. }
  1732. WsbAffirmHr(m_pSession->ProcessItem(m_JobPhase,
  1733. m_JobAction, pScanItem, skipWork));
  1734. } WsbCatch( hr );
  1735. (void)Remove(pWorkItem);
  1736. }
  1737. break;
  1738. }
  1739. case HSM_WORK_ITEM_MOVER_CANCELLED: {
  1740. WsbTrace(OLESTR("CHsmWorkQueue::DoWork - Mover Cancelled\n"));
  1741. try {
  1742. //
  1743. // We are cancelled, so skip all of the rest of the
  1744. // work in the queue
  1745. //
  1746. WsbAffirmHr(MarkQueueAsDone());
  1747. //
  1748. // Remove the cancelled work item
  1749. //
  1750. Remove(pWorkItem);
  1751. //
  1752. // Skip any other work to do
  1753. //
  1754. skipWork = HSM_E_WORK_SKIPPED_CANCELLED;
  1755. } WsbCatch( hr );
  1756. break;
  1757. }
  1758. default: {
  1759. hr = E_UNEXPECTED;
  1760. break;
  1761. }
  1762. }
  1763. }
  1764. pSaveSessionPtr = 0;
  1765. pWorkItem = 0;
  1766. pFsaWorkItem = 0;
  1767. if (m_TerminateQueue) {
  1768. // signaled to terminate the working thread (should be trigerred only in shutdown cases)
  1769. done = TRUE;
  1770. }
  1771. }
  1772. } WsbCatch( hr );
  1773. if (OpenedDb) {
  1774. WsbTrace(OLESTR("CHsmWorkQueue::DoWork - Closing the database\n"));
  1775. m_pSegmentDb->Close(m_pDbWorkSession);
  1776. OpenedDb = FALSE;
  1777. m_pDbWorkSession = 0;
  1778. }
  1779. // Pretend everything is OK
  1780. hr = S_OK;
  1781. // Release the thread (the thread should terminate on exit
  1782. // from the routine that called this routine)
  1783. // In case of termination, the terminating thread will close the handle
  1784. if (! m_TerminateQueue) {
  1785. CloseHandle(m_WorkerThread);
  1786. m_WorkerThread = 0;
  1787. }
  1788. // Allow this object to be released
  1789. ((IUnknown*)(IHsmWorkQueue*)this)->Release();
  1790. WsbTraceOut(OLESTR("CHsmWorkQueue::DoWork"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  1791. return(hr);
  1792. }
  1793. HRESULT
  1794. CHsmWorkQueue::DoFsaWork(
  1795. IHsmWorkItem *pWorkItem
  1796. )
  1797. /*++
  1798. --*/
  1799. {
  1800. HRESULT hr = S_OK;
  1801. HRESULT workHr = S_OK;
  1802. HRESULT originalHr = S_OK;
  1803. CWsbStringPtr path;
  1804. FSA_RESULT_ACTION resultAction;
  1805. CComPtr<IFsaPostIt> pFsaWorkItem;
  1806. LONGLONG requestSize;
  1807. WsbTraceIn(OLESTR("CHsmWorkQueue::DoFsaWork"),OLESTR(""));
  1808. try {
  1809. CComPtr<IFsaScanItem> pScanItem;
  1810. //
  1811. // Do the work.
  1812. //
  1813. WsbAffirmHr(pWorkItem->GetFsaPostIt(&pFsaWorkItem));
  1814. try {
  1815. WsbAffirmHr(pFsaWorkItem->GetRequestAction(&m_RequestAction));
  1816. WsbAffirmHr(pFsaWorkItem->GetPath(&path, 0));
  1817. WsbAffirmHr(GetScanItem(pFsaWorkItem, &pScanItem));
  1818. } WsbCatchAndDo (hr,
  1819. originalHr = hr;
  1820. // Not-found error is expected if the file was renamed or deleted after
  1821. // the FSA scanning. There is no need to log an error.
  1822. if (hr != WSB_E_NOTFOUND) {
  1823. if (path == NULL){
  1824. WsbLogEvent(HSM_MESSAGE_PROCESS_WORK_ITEM_ERROR,
  1825. sizeof(m_RequestAction), &m_RequestAction, OLESTR("Path is NULL"),
  1826. WsbHrAsString(hr), NULL);
  1827. } else {
  1828. WsbLogEvent(HSM_MESSAGE_PROCESS_WORK_ITEM_ERROR,
  1829. sizeof(m_RequestAction), &m_RequestAction, (WCHAR *)path,
  1830. WsbHrAsString(hr), NULL);
  1831. }
  1832. }
  1833. // Report back to FSA on the error unless the error indiactes
  1834. // lost of connection with FSA.
  1835. if (hr != RPC_E_DISCONNECTED) {
  1836. hr = pFsaWorkItem->SetResult(hr);
  1837. if (hr != RPC_E_DISCONNECTED) {
  1838. hr = m_pFsaResource->ProcessResult(pFsaWorkItem);
  1839. }
  1840. }
  1841. );
  1842. if (originalHr != S_OK) {
  1843. goto my_try_exit;
  1844. }
  1845. WsbTrace(OLESTR("Handling file <%s>.\n"), WsbAbbreviatePath(path, 120));
  1846. switch (m_RequestAction) {
  1847. case FSA_REQUEST_ACTION_DELETE:
  1848. m_JobAction = HSM_JOB_ACTION_DELETE;
  1849. hr = E_NOTIMPL;
  1850. break;
  1851. case FSA_REQUEST_ACTION_PREMIGRATE:
  1852. m_JobAction = HSM_JOB_ACTION_PREMIGRATE;
  1853. WsbAffirmHr(pFsaWorkItem->GetRequestSize(&requestSize));
  1854. workHr = PremigrateIt(pFsaWorkItem);
  1855. //
  1856. // Fill in the work item, placeholder information in
  1857. // postit is set by premigrate code.
  1858. //
  1859. WsbAffirmHr(pWorkItem->SetResult(workHr));
  1860. if (S_OK == workHr) {
  1861. WsbAffirmHr(pWorkItem->SetMediaInfo(m_MediaId, m_MediaUpdate, m_BadMedia,
  1862. m_MediaReadOnly, m_MediaFreeSpace, m_RemoteDataSet));
  1863. WsbAffirmHr(pWorkItem->SetFsaResource(m_pFsaResource));
  1864. //
  1865. // Copy the work item to the work in waiting queue
  1866. //
  1867. WsbAffirmHr(CopyToWaitingQueue(pWorkItem));
  1868. if (S_OK == TimeToCommit()) {
  1869. workHr = CommitWork();
  1870. }
  1871. } else {
  1872. WsbTrace(OLESTR("Failed premigrate work.\n"));
  1873. if (pScanItem) {
  1874. WsbAffirmHr(m_pSession->ProcessItem(m_JobPhase,
  1875. m_JobAction, pScanItem, workHr));
  1876. }
  1877. //
  1878. // An item that was changed while waiting to be migrated is not really an error -
  1879. // the item is just skipped. Change hr here to avoid unnecessary error message
  1880. // and unnecessary count as error in ShouldJobContinue
  1881. // Same is true for file-too-big error
  1882. //
  1883. if ((HSM_E_FILE_CHANGED == workHr) || (HSM_E_WORK_SKIPPED_FILE_TOO_BIG == workHr)) {
  1884. workHr = S_OK;
  1885. }
  1886. }
  1887. break;
  1888. case FSA_REQUEST_ACTION_FILTER_RECALL:
  1889. case FSA_REQUEST_ACTION_FILTER_READ:
  1890. case FSA_REQUEST_ACTION_RECALL:
  1891. m_JobAction = HSM_JOB_ACTION_RECALL;
  1892. workHr = RecallIt(pFsaWorkItem);
  1893. //
  1894. // Tell the recaller right away about the success or failure
  1895. // of the recall, we do this here so the recall filter can
  1896. // release the open as soon as possible
  1897. //
  1898. hr = pFsaWorkItem->SetResult(workHr);
  1899. if (S_OK == hr) {
  1900. WsbTrace(OLESTR("HSM recall (filter, read or recall) complete, calling FSA\n"));
  1901. hr = m_pFsaResource->ProcessResult(pFsaWorkItem);
  1902. WsbTrace(OLESTR("FSA ProcessResult returned <%ls>\n"), WsbHrAsString(hr));
  1903. }
  1904. break;
  1905. case FSA_REQUEST_ACTION_VALIDATE:
  1906. m_JobAction = HSM_JOB_ACTION_VALIDATE;
  1907. workHr = validateIt(pFsaWorkItem);
  1908. if (S_OK == workHr) {
  1909. WsbAffirmHr(pFsaWorkItem->GetResultAction(&resultAction));
  1910. if (FSA_RESULT_ACTION_NONE != resultAction) {
  1911. WsbTrace(OLESTR("HSM validate complete, calling FSA\n"));
  1912. hr = m_pFsaResource->ProcessResult(pFsaWorkItem);
  1913. WsbTrace(OLESTR("FSA ProcessResult returned <%ls>\n"), WsbHrAsString(hr));
  1914. }
  1915. }
  1916. //
  1917. // Tell the session whether or not the work was done.
  1918. //
  1919. // For validate, we may not have a scan item
  1920. //
  1921. if (pScanItem) {
  1922. WsbTrace(OLESTR("Tried HSM work, calling Session to Process Item\n"));
  1923. m_pSession->ProcessItem(m_JobPhase, m_JobAction, pScanItem, workHr);
  1924. } else {
  1925. WsbTrace(OLESTR("Couldn't get scan item for validation.\n"));
  1926. }
  1927. break;
  1928. case FSA_REQUEST_ACTION_VALIDATE_FOR_TRUNCATE: {
  1929. HRESULT truncateHr = S_OK;
  1930. m_JobAction = HSM_JOB_ACTION_VALIDATE;
  1931. workHr = validateIt(pFsaWorkItem);
  1932. if (S_OK == workHr) {
  1933. WsbAffirmHr(pFsaWorkItem->GetResultAction(&resultAction));
  1934. if (resultAction == FSA_RESULT_ACTION_VALIDATE_BAD) {
  1935. WsbAffirmHr( pFsaWorkItem->SetResultAction( FSA_RESULT_ACTION_VALIDATE_FOR_TRUNCATE_BAD ));
  1936. resultAction = FSA_RESULT_ACTION_VALIDATE_FOR_TRUNCATE_BAD;
  1937. }
  1938. if (resultAction == FSA_RESULT_ACTION_VALIDATE_OK) {
  1939. WsbAffirmHr( pFsaWorkItem->SetResultAction( FSA_RESULT_ACTION_VALIDATE_FOR_TRUNCATE_OK ));
  1940. resultAction = FSA_RESULT_ACTION_VALIDATE_FOR_TRUNCATE_OK;
  1941. }
  1942. if (FSA_RESULT_ACTION_NONE != resultAction) {
  1943. WsbTrace(OLESTR("HSM validate for truncate complete, calling FSA\n"));
  1944. hr = m_pFsaResource->ProcessResult(pFsaWorkItem);
  1945. WsbTrace(OLESTR("FSA ProcessResult returned <%ls>\n"), WsbHrAsString(hr));
  1946. if (resultAction == FSA_RESULT_ACTION_VALIDATE_FOR_TRUNCATE_OK) {
  1947. // Analyze result of truncation: for expected errors, such as file-changed, set to S_FALSE
  1948. // in order to signal skipping, otherwize leave original error/success code
  1949. switch (hr) {
  1950. case FSA_E_ITEMCHANGED:
  1951. case FSA_E_ITEMINUSE:
  1952. case FSA_E_NOTMANAGED:
  1953. case FSA_E_FILE_ALREADY_MANAGED:
  1954. truncateHr = S_FALSE;
  1955. break;
  1956. default:
  1957. truncateHr = hr;
  1958. break;
  1959. }
  1960. } else if (resultAction == FSA_RESULT_ACTION_VALIDATE_FOR_TRUNCATE_BAD) {
  1961. // Set truncateHr to S_FALSE to signal for skipping this file in regards to truncation
  1962. truncateHr = S_FALSE;
  1963. }
  1964. }
  1965. }
  1966. //
  1967. // Tell the session whether or not the work was done.
  1968. //
  1969. // For validate, we may not have a scan item
  1970. //
  1971. if (pScanItem) {
  1972. WsbTrace(OLESTR("Tried HSM work, calling Session to Process Item\n"));
  1973. //
  1974. // For validate, the work-hr is always set to OK, therefore report on the truncate-hr instead
  1975. //
  1976. m_pSession->ProcessItem(m_JobPhase, m_JobAction, pScanItem, truncateHr);
  1977. } else {
  1978. WsbTrace(OLESTR("Couldn't get scan item for validation.\n"));
  1979. }
  1980. break;
  1981. }
  1982. default:
  1983. m_JobAction = HSM_JOB_ACTION_UNKNOWN;
  1984. hr = E_NOTIMPL;
  1985. break;
  1986. }
  1987. if (S_OK != workHr) {
  1988. // Replace to a specific RSS error codes for some errors
  1989. switch (HRESULT_CODE(workHr)) {
  1990. case ERROR_LOCK_VIOLATION:
  1991. workHr = HSM_E_FILE_LOCK_VIOLATION;
  1992. break;
  1993. case ERROR_SHARING_VIOLATION:
  1994. workHr = HSM_E_FILE_SHARING_VIOLATION;
  1995. break;
  1996. }
  1997. // Tell the session how things went if they didn't go well.
  1998. (void) m_pSession->ProcessHr(m_JobPhase, 0, 0, workHr);
  1999. }
  2000. //
  2001. // Now, evaluate the work result to see if we should fail the job.
  2002. //
  2003. (void)ShouldJobContinue(workHr);
  2004. my_try_exit:
  2005. ;
  2006. } WsbCatch(hr);
  2007. WsbTraceOut(OLESTR("CHsmWorkQueue::DoFsaWork"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  2008. return(hr);
  2009. }
  2010. HRESULT
  2011. CHsmWorkQueue::UpdateMetaData(
  2012. IHsmWorkItem *pWorkItem
  2013. )
  2014. /*++
  2015. --*/
  2016. {
  2017. HRESULT hr = S_OK;
  2018. BOOL transactionBegun = FALSE;
  2019. WsbTraceIn(OLESTR("CHsmWorkQueue::UpdateMetaData"),OLESTR(""));
  2020. try {
  2021. //
  2022. // Start transaction
  2023. //
  2024. WsbAffirmHr(m_pDbWorkSession->TransactionBegin());
  2025. transactionBegun = TRUE;
  2026. //
  2027. // Update the various metadata records
  2028. //
  2029. WsbAffirmHr(UpdateBagInfo(pWorkItem));
  2030. WsbAffirmHr(UpdateSegmentInfo(pWorkItem));
  2031. WsbAffirmHr(UpdateMediaInfo(pWorkItem));
  2032. //
  2033. // End transaction
  2034. //
  2035. WsbAffirmHr(m_pDbWorkSession->TransactionEnd());
  2036. transactionBegun = FALSE;
  2037. } WsbCatchAndDo( hr, if (transactionBegun == TRUE) {m_pDbWorkSession->TransactionCancel();});
  2038. WsbTraceOut(OLESTR("CHsmWorkQueue::UpdateMetaData"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  2039. return(hr);
  2040. }
  2041. HRESULT
  2042. CHsmWorkQueue::UpdateSegmentInfo(
  2043. IHsmWorkItem *pWorkItem
  2044. )
  2045. /*++
  2046. --*/
  2047. {
  2048. HRESULT hr = S_OK;
  2049. WsbTraceIn(OLESTR("CHsmWorkQueue::UpdateSegmentInfo"),OLESTR(""));
  2050. try {
  2051. // Add a record to the segment database or extend an existing one
  2052. CComQIPtr<ISegDb, &IID_ISegDb> pSegDb = m_pSegmentDb;
  2053. BOOLEAN done = FALSE;
  2054. FSA_PLACEHOLDER placeholder;
  2055. CComPtr<IFsaPostIt> pFsaWorkItem;
  2056. //
  2057. // Get the placeholder information from the postit in the work item
  2058. //
  2059. WsbAffirmHr(pWorkItem->GetFsaPostIt(&pFsaWorkItem));
  2060. WsbAffirmHr(pFsaWorkItem->GetPlaceholder(&placeholder));
  2061. WsbAssert(0 != m_RemoteDataSetStart.QuadPart, WSB_E_INVALID_DATA);
  2062. WsbTrace(OLESTR("Adding SegmentRecord: <%ls>, <%ls>, <%ls>\n"),
  2063. WsbGuidAsString(placeholder.bagId),
  2064. WsbStringCopy(WsbLonglongAsString(placeholder.fileStart)),
  2065. WsbStringCopy(WsbLonglongAsString(placeholder.fileSize)));
  2066. WsbAffirmHr(pSegDb->SegAdd(m_pDbWorkSession, placeholder.bagId, placeholder.fileStart,
  2067. placeholder.fileSize, m_MediaId, m_RemoteDataSetStart.QuadPart));
  2068. } WsbCatch( hr );
  2069. WsbTraceOut(OLESTR("CHsmWorkQueue::UpdateSegmentInfo"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  2070. return(hr);
  2071. }
  2072. HRESULT
  2073. CHsmWorkQueue::UpdateMediaInfo(
  2074. IHsmWorkItem *pWorkItem
  2075. )
  2076. /*++
  2077. --*/
  2078. {
  2079. HRESULT hr = S_OK;
  2080. WsbTraceIn(OLESTR("CHsmWorkQueue::UpdateMediaInfo"),OLESTR(""));
  2081. try
  2082. {
  2083. LONGLONG mediaCapacity;
  2084. CComPtr<IFsaPostIt> pFsaWorkItem;
  2085. CComPtr<IMediaInfo> pMediaInfo;
  2086. GUID l_MediaId; // HSM Engine Media ID
  2087. FILETIME l_MediaLastUpdate; // Last update of copy
  2088. HRESULT l_MediaLastError; // S_OK or the last exception
  2089. // ..encountered when accessing
  2090. // ..the media
  2091. BOOL l_MediaRecallOnly; // True if no more data is to
  2092. // ..be premigrated to the media
  2093. // ..Set by internal operations,
  2094. // ..may not be changed externally
  2095. LONGLONG l_MediaFreeBytes; // Real free space on media
  2096. short l_MediaRemoteDataSet;
  2097. HRESULT currentMediaLastError;
  2098. //
  2099. // Get the PostIt and the media information for the work item
  2100. //
  2101. WsbAffirmHr(pWorkItem->GetFsaPostIt(&pFsaWorkItem));
  2102. WsbAffirmHr(pWorkItem->GetMediaInfo(&l_MediaId, &l_MediaLastUpdate,
  2103. &l_MediaLastError, &l_MediaRecallOnly,
  2104. &l_MediaFreeBytes, &l_MediaRemoteDataSet));
  2105. //
  2106. // Update the media information with the name, used space, and free space of
  2107. // the media.
  2108. //
  2109. WsbAffirmHr(m_pSegmentDb->GetEntity(m_pDbWorkSession, HSM_MEDIA_INFO_REC_TYPE, IID_IMediaInfo,
  2110. (void**)&pMediaInfo));
  2111. WsbAffirmHr(pMediaInfo->SetId(l_MediaId));
  2112. WsbAffirmHr(pMediaInfo->FindEQ());
  2113. WsbAffirmHr(pMediaInfo->SetUpdate(l_MediaLastUpdate));
  2114. WsbAffirmHr(pMediaInfo->SetFreeBytes(l_MediaFreeBytes));
  2115. WsbAffirmHr(pMediaInfo->SetNextRemoteDataSet(l_MediaRemoteDataSet));
  2116. // Avoid setting last error if the existing one already indicates an error
  2117. WsbAffirmHr(pMediaInfo->GetLastError(&currentMediaLastError));
  2118. if (SUCCEEDED(currentMediaLastError)) {
  2119. WsbAffirmHr(pMediaInfo->SetLastError(l_MediaLastError));
  2120. }
  2121. // Mark the media as RecallOnly if it's mostly full (passed the high watermark level)
  2122. WsbAffirmHr(pMediaInfo->GetCapacity(&mediaCapacity));
  2123. if (l_MediaRecallOnly || (l_MediaFreeBytes < ((mediaCapacity * m_MaxFreeSpaceInFullMedia) / 100) )) {
  2124. WsbAffirmHr(pMediaInfo->SetRecallOnlyStatus(TRUE));
  2125. WsbTrace(OLESTR("CHsmWorkQueue::UpdateMediaInfo: Marking media as Recall Only - Capacity = %I64d, Free Bytes = %I64d\n"),
  2126. mediaCapacity, l_MediaFreeBytes);
  2127. /*** If we like to allocate immediately a second side of a full meida, than the code below should be completed...
  2128. if (S_OK == m_pRmsServer->IsMultipleSidedMedia(m_RmsMediaSetId)) {
  2129. // Check if second size is avalaible for allocation
  2130. // Allocate (non-blocking) the second side
  2131. } ***/
  2132. }
  2133. WsbAffirmHr(pMediaInfo->UpdateLastKnownGoodMaster());
  2134. WsbAffirmHr(pMediaInfo->Write());
  2135. } WsbCatch( hr );
  2136. WsbTraceOut(OLESTR("CHsmWorkQueue::UpdateMediaInfo"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  2137. return(hr);
  2138. }
  2139. HRESULT
  2140. CHsmWorkQueue::GetMediaSet(
  2141. IFsaPostIt *pFsaWorkItem
  2142. )
  2143. /*++
  2144. --*/
  2145. {
  2146. HRESULT hr = S_OK;
  2147. GUID storagePoolId;
  2148. WsbTraceIn(OLESTR("CHsmWorkQueue::GetMediaSet"),OLESTR(""));
  2149. try {
  2150. CComPtr<IHsmStoragePool> pStoragePool1;
  2151. CComPtr<IHsmStoragePool> pStoragePool2;
  2152. WsbAffirmHr(m_pHsmServerCreate->CreateInstance(CLSID_CHsmStoragePool, IID_IHsmStoragePool,
  2153. (void **)&pStoragePool1));
  2154. WsbAffirmHr(pFsaWorkItem->GetStoragePoolId(&storagePoolId));
  2155. WsbAffirmHr(pStoragePool1->SetId(storagePoolId));
  2156. WsbAffirmHr(m_pStoragePools->Find(pStoragePool1, IID_IHsmStoragePool, (void **) &pStoragePool2));
  2157. //
  2158. // If the storage pool cannot be found, make it a meaningful message
  2159. //
  2160. m_RmsMediaSetName.Free();
  2161. hr = pStoragePool2->GetMediaSet(&m_RmsMediaSetId, &m_RmsMediaSetName);
  2162. if (S_OK != hr) {
  2163. hr = HSM_E_STG_PL_NOT_FOUND;
  2164. }
  2165. } WsbCatch( hr );
  2166. WsbTraceOut(OLESTR("CHsmWorkQueue::GetMediaSet"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  2167. return(hr);
  2168. }
  2169. HRESULT
  2170. CHsmWorkQueue::FindMigrateMediaToUse(
  2171. IFsaPostIt *pFsaWorkItem,
  2172. GUID *pMediaToUse,
  2173. GUID *pFirstSideToUse,
  2174. BOOL *pMediaChanged,
  2175. LONGLONG *pRequiredSize
  2176. )
  2177. /*++
  2178. --*/
  2179. {
  2180. HRESULT hr = S_OK;
  2181. WsbTraceIn(OLESTR("CHsmWorkQueue::FindMigrateMediaToUse"),OLESTR(""));
  2182. try {
  2183. BOOLEAN found = FALSE;
  2184. GUID mediaId;
  2185. GUID storageId;
  2186. GUID storagePoolId;
  2187. CComPtr<IMediaInfo> pMediaInfo;
  2188. LONGLONG requestSize;
  2189. DWORD dwMediaCount= 0;
  2190. // data of alternative (offline or busy) media to use
  2191. GUID alternativeMediaId = GUID_NULL;
  2192. GUID alternativeMediaToUse = GUID_NULL;
  2193. CWsbStringPtr alternativeMediaName;
  2194. HSM_JOB_MEDIA_TYPE alternativeMediaType = HSM_JOB_MEDIA_TYPE_UNKNOWN;
  2195. SHORT alternativeRemoteDataSet= 0;
  2196. // data of meida candidates for second-side allocation
  2197. BOOL bTwoSidedMedias = FALSE;
  2198. CComPtr<IWsbCollection> pFirstSideCollection;
  2199. CComPtr<IWsbGuid> pFirstSideGuid;
  2200. GUID firstSideGuid;
  2201. WsbAssert(pMediaToUse != 0, E_POINTER);
  2202. *pMediaToUse = GUID_NULL;
  2203. WsbAssert(pFirstSideToUse != 0, E_POINTER);
  2204. *pFirstSideToUse = GUID_NULL;
  2205. WsbAssert(pMediaChanged != 0, E_POINTER);
  2206. *pMediaChanged = FALSE;
  2207. WsbAssert(pRequiredSize != 0, E_POINTER);
  2208. *pRequiredSize = 0;
  2209. // Determine how much space we need on the media for this file
  2210. // (we add some for overhead)
  2211. WsbAffirmHr(pFsaWorkItem->GetRequestSize(&requestSize));
  2212. requestSize += HSM_STORAGE_OVERHEAD;
  2213. *pRequiredSize = (requestSize * 100) / (100 - m_MinFreeSpaceInFullMedia); // relevant for new media
  2214. WsbTrace(OLESTR("CHsmWorkQueue::FindMigrateMediaToUse: size needed (with overhead) =%ls, free space on media = %ls\n"),
  2215. WsbQuickString(WsbLonglongAsString(requestSize)),
  2216. WsbQuickString(WsbLonglongAsString(m_MediaFreeSpace)));
  2217. // Set up for search
  2218. WsbAffirmHr(m_pSegmentDb->GetEntity(m_pDbWorkSession, HSM_MEDIA_INFO_REC_TYPE, IID_IMediaInfo,
  2219. (void**)&pMediaInfo));
  2220. WsbAffirmHr(pFsaWorkItem->GetStoragePoolId(&storagePoolId));
  2221. // If we already have media mounted, use it if possible
  2222. if (GUID_NULL != m_MountedMedia && !m_MediaReadOnly &&
  2223. (m_MediaFreeSpace > requestSize) &&
  2224. ((m_MediaFreeSpace - requestSize) > ((m_MediaCapacity * m_MinFreeSpaceInFullMedia) / 100)) ) {
  2225. // Make sure the storage pool is correct
  2226. WsbAffirmHr(pMediaInfo->SetId(m_MediaId));
  2227. WsbAffirmHr(pMediaInfo->FindEQ());
  2228. WsbAffirmHr(pMediaInfo->GetStoragePoolId(&storageId));
  2229. if ((storageId == storagePoolId)) {
  2230. found = TRUE;
  2231. }
  2232. }
  2233. if (!found) {
  2234. // Not found ==> going to use a new media
  2235. *pMediaChanged = TRUE;
  2236. // If there's currently a mounted media and we aren't going to use it,
  2237. // make sure work is committed and media is dismounted
  2238. if (GUID_NULL != m_MountedMedia) {
  2239. WsbTrace(OLESTR("CHsmWorkQueue::FindMigrateMediaToUse: Dismounting current media - Capacity = %I64d, Free Bytes = %I64d\n"),
  2240. m_MediaCapacity, m_MediaFreeSpace);
  2241. WsbAffirmHr(CommitWork());
  2242. WsbAffirmHr(DismountMedia(TRUE));
  2243. }
  2244. }
  2245. // Search for a media
  2246. if (!found) {
  2247. LONGLONG freeSpace;
  2248. LONGLONG mediaCapacity;
  2249. BOOL readOnly;
  2250. HRESULT hrLastError;
  2251. BOOL bDataForOffline = FALSE;
  2252. // Check if we deal with two-sided medias
  2253. if (S_OK == m_pRmsServer->IsMultipleSidedMedia(m_RmsMediaSetId)) {
  2254. bTwoSidedMedias = TRUE;
  2255. WsbAffirmHr(m_pHsmServerCreate->CreateInstance(CLSID_CWsbOrderedCollection,
  2256. IID_IWsbCollection, (void **)&pFirstSideCollection));
  2257. }
  2258. // Search media table through all previously used media
  2259. for (hr = pMediaInfo->First(); S_OK == hr;
  2260. hr = pMediaInfo->Next()) {
  2261. // TEMPORARY - Just for debugging
  2262. {
  2263. CWsbStringPtr debugMediaName;
  2264. GUID debugSubsystemId;
  2265. CHAR *buff = NULL;
  2266. WsbAffirmHr(pMediaInfo->GetMediaSubsystemId(&debugSubsystemId));
  2267. debugMediaName.Free();
  2268. WsbAffirmHr(pMediaInfo->GetDescription(&debugMediaName,0));
  2269. WsbTraceAlways(OLESTR("RANK: Checking media <%ls> <%ls>\n"),
  2270. WsbGuidAsString(debugSubsystemId), (WCHAR *)debugMediaName);
  2271. debugMediaName.CopyTo (&buff);
  2272. if (buff)
  2273. WsbFree(buff);
  2274. }
  2275. WsbAffirmHr(pMediaInfo->GetStoragePoolId(&storageId));
  2276. WsbAffirmHr(pMediaInfo->GetFreeBytes(&freeSpace));
  2277. WsbAffirmHr(pMediaInfo->GetRecallOnlyStatus(&readOnly));
  2278. WsbAffirmHr(pMediaInfo->GetCapacity(&mediaCapacity));
  2279. WsbAffirmHr(pMediaInfo->GetLastError(&hrLastError));
  2280. WsbTrace( OLESTR("Looking for storagePool <%ls> and freeSpace <%ls>.\n"),
  2281. WsbGuidAsString(storagePoolId),
  2282. WsbLonglongAsString(requestSize));
  2283. WsbTrace( OLESTR("Found media with storagePool <%ls>, freeSpace <%ls> and read only <%ls>.\n"),
  2284. WsbGuidAsString(storageId),
  2285. WsbLonglongAsString(freeSpace),
  2286. WsbBoolAsString(readOnly));
  2287. // Reject media if it's ReadOnly or not from the right pool
  2288. if ((readOnly && (hrLastError != S_OK)) || (storageId != storagePoolId)) {
  2289. continue;
  2290. }
  2291. // Check full & mostly full condition & free space
  2292. // Note: a medias which is read-only because it's bad, is rejected in the previous if
  2293. if (readOnly || (freeSpace <= requestSize) ||
  2294. ((freeSpace - requestSize) < ((mediaCapacity * m_MinFreeSpaceInFullMedia) / 100)) ) {
  2295. // In case of two-sided medias, such a media is candidate for second side allocation
  2296. // (but only if capacity of first side is large enough...)
  2297. if (bTwoSidedMedias && (*pRequiredSize < mediaCapacity)) {
  2298. WsbAffirmHr(pMediaInfo->GetMediaSubsystemId(&firstSideGuid));
  2299. WsbAffirmHr(m_pHsmServerCreate->CreateInstance(CLSID_CWsbGuid, IID_IWsbGuid, (void**) &pFirstSideGuid));
  2300. WsbAffirmHr(pFirstSideGuid->SetGuid(firstSideGuid));
  2301. WsbAffirmHr(pFirstSideCollection->Add(pFirstSideGuid));
  2302. pFirstSideGuid = 0;
  2303. }
  2304. continue;
  2305. }
  2306. // get media status data
  2307. DWORD dwStatus;
  2308. GUID mediaSubsystemId;
  2309. HRESULT hrStat;
  2310. WsbAffirmHr(pMediaInfo->GetMediaSubsystemId(&mediaSubsystemId));
  2311. hrStat = m_pRmsServer->FindCartridgeStatusById(mediaSubsystemId ,&dwStatus);
  2312. if (hrStat != S_OK) {
  2313. WsbTraceAlways(OLESTR("FindMigrateMediaToUse: Skipping media <%ls> (failed to retrieve its status)\n"),
  2314. WsbGuidAsString(mediaSubsystemId));
  2315. continue;
  2316. }
  2317. // If media disabled - skip it
  2318. if (!(dwStatus & RMS_MEDIA_ENABLED)) {
  2319. continue;
  2320. }
  2321. // From this point, the media is considered as a valid R/W media and should
  2322. // be counted as such
  2323. dwMediaCount++;
  2324. if ((dwStatus & RMS_MEDIA_ONLINE) && (dwStatus & RMS_MEDIA_AVAILABLE)) {
  2325. // Check if media is in the process of mounting:
  2326. // if so, it is also considered a busy media
  2327. CComPtr<IWsbIndexedCollection> pMountingCollection;
  2328. CComPtr<IMountingMedia> pMountingMedia;
  2329. CComPtr<IMountingMedia> pMediaToFind;
  2330. // Lock mounting media while searching the collection
  2331. WsbAffirmHr(m_pServer->LockMountingMedias());
  2332. try {
  2333. WsbAffirmHr(m_pServer->GetMountingMedias(&pMountingCollection));
  2334. WsbAffirmHr(CoCreateInstance(CLSID_CMountingMedia, 0, CLSCTX_SERVER, IID_IMountingMedia, (void**)&pMediaToFind));
  2335. WsbAffirmHr(pMediaToFind->SetMediaId(mediaSubsystemId));
  2336. hr = pMountingCollection->Find(pMediaToFind, IID_IMountingMedia, (void **)&pMountingMedia);
  2337. if (hr == S_OK) {
  2338. // Media is mounting...
  2339. // Consider adding here a check for media type and reason for mounting:
  2340. // If it's direct-access and mounting for read, it's not really busy
  2341. //
  2342. // Problem: for already mounted media, we don't track the mount reason (read or write)
  2343. //
  2344. // Also, one could argue that if we are below the concurrency limit, for better performance,
  2345. // we better use a different media, even if it's a direct-access media mounted for read
  2346. dwStatus &= ~ RMS_MEDIA_AVAILABLE;
  2347. pMountingMedia = 0;
  2348. } else if (hr == WSB_E_NOTFOUND) {
  2349. hr = S_OK;
  2350. }
  2351. } WsbCatch(hr);
  2352. m_pServer->UnlockMountingMedias();
  2353. if (! SUCCEEDED(hr)) {
  2354. WsbTraceAlways(OLESTR("CHsmWorkQueue::FindMigrateMediaToUse: Failed to check mounting media, hr= <%ls>\n"),
  2355. WsbHrAsString(hr));
  2356. }
  2357. }
  2358. if ((dwStatus & RMS_MEDIA_ONLINE) && (dwStatus & RMS_MEDIA_AVAILABLE)) {
  2359. // found a media to use
  2360. found = TRUE;
  2361. break;
  2362. } else {
  2363. // Save up to one offline or one busy media, because we may have to use it...
  2364. // Priority is given to offline medias over busy medias.
  2365. if ((alternativeMediaId != GUID_NULL) && bDataForOffline) {
  2366. // Already Have best alternative media
  2367. continue;
  2368. }
  2369. if ((alternativeMediaId != GUID_NULL) && (dwStatus & RMS_MEDIA_ONLINE)) {
  2370. // Media is busy, can't improve the alternative
  2371. continue;
  2372. }
  2373. // Determine which kind of alternative media are we saving
  2374. if (dwStatus & RMS_MEDIA_ONLINE) {
  2375. bDataForOffline = FALSE;
  2376. } else {
  2377. bDataForOffline = TRUE;
  2378. }
  2379. // Save data for alternative media
  2380. WsbAffirmHr(pMediaInfo->GetId(&alternativeMediaId));
  2381. WsbAffirmHr(pMediaInfo->GetMediaSubsystemId(&alternativeMediaToUse));
  2382. alternativeMediaName.Free();
  2383. WsbAffirmHr(pMediaInfo->GetDescription(&alternativeMediaName,0));
  2384. WsbAffirmHr(pMediaInfo->GetType(&alternativeMediaType));
  2385. WsbAffirmHr(pMediaInfo->GetNextRemoteDataSet(&alternativeRemoteDataSet));
  2386. }
  2387. }
  2388. // If we fell out of the loop because we ran out of media
  2389. // in our list, reset the HRESULT
  2390. if (hr == WSB_E_NOTFOUND) {
  2391. hr = S_OK;
  2392. } else {
  2393. WsbAffirmHr(hr);
  2394. }
  2395. }
  2396. // If we found a media to use, save information
  2397. if (found) {
  2398. WsbAffirmHr(pMediaInfo->GetId(&mediaId));
  2399. WsbAffirmHr(pMediaInfo->GetMediaSubsystemId(pMediaToUse));
  2400. if (mediaId != m_MediaId) {
  2401. m_MediaId = mediaId;
  2402. m_MediaName.Free();
  2403. WsbAffirmHr(pMediaInfo->GetDescription(&m_MediaName,0));
  2404. WsbAffirmHr(pMediaInfo->GetType(&m_MediaType));
  2405. WsbAffirmHr(pMediaInfo->GetNextRemoteDataSet(&m_RemoteDataSet));
  2406. }
  2407. //
  2408. // If we didn't find a media to use, check whether we should
  2409. // 1. Choose to allocate a second side of a full media (only for 2-sided medias)
  2410. // 2. Clear the information so we'll get a new piece of media
  2411. // 2. Return the id of an offline or busy R/W meida
  2412. } else {
  2413. if (bTwoSidedMedias) {
  2414. try {
  2415. // Go over the candidates, look for one with valid and non-allocated second side
  2416. CComPtr<IWsbEnum> pEnumIds;
  2417. GUID secondSideGuid;
  2418. BOOL bValid;
  2419. WsbAffirmHr(pFirstSideCollection->Enum(&pEnumIds));
  2420. for (hr = pEnumIds->First(IID_IWsbGuid, (void**) &pFirstSideGuid);
  2421. (hr == S_OK);
  2422. hr = pEnumIds->Next(IID_IWsbGuid, (void**) &pFirstSideGuid)) {
  2423. WsbAffirmHr(pFirstSideGuid->GetGuid(&firstSideGuid));
  2424. WsbAffirmHr(m_pRmsServer->CheckSecondSide(firstSideGuid, &bValid, &secondSideGuid));
  2425. if (bValid && (GUID_NULL == secondSideGuid)) {
  2426. // Found a valid & non-allocated second side - verify fisrt side status
  2427. DWORD status;
  2428. WsbAffirmHr(m_pRmsServer->FindCartridgeStatusById(firstSideGuid ,&status));
  2429. if ((status & RMS_MEDIA_ENABLED) && (status & RMS_MEDIA_ONLINE)) {
  2430. *pFirstSideToUse = firstSideGuid;
  2431. break;
  2432. }
  2433. }
  2434. pFirstSideGuid = 0;
  2435. }
  2436. if (hr == WSB_E_NOTFOUND) {
  2437. hr = S_OK;
  2438. }
  2439. } WsbCatchAndDo(hr,
  2440. WsbTraceAlways(OLESTR("FindMigrateMediaToUse: Skipping search for second side allocation, hr=<%ls>\n"),
  2441. WsbHrAsString(hr));
  2442. hr = S_OK;
  2443. );
  2444. } // if two sides
  2445. // Get max number for R/W medias
  2446. DWORD dwMaxMedia;
  2447. WsbAffirmHr(m_pServer->GetCopyFilesLimit(&dwMaxMedia));
  2448. if ((*pFirstSideToUse != GUID_NULL) || (dwMediaCount < dwMaxMedia) || (alternativeMediaId == GUID_NULL)) {
  2449. // Allowed to allocate a new piece of media OR no alternative media found OR second side found
  2450. m_MediaType = HSM_JOB_MEDIA_TYPE_UNKNOWN;
  2451. WsbAffirmHr(BuildMediaName(&m_MediaName));
  2452. m_MediaReadOnly = FALSE;
  2453. } else {
  2454. // Use the alternative (which is offline or busy) R/W media
  2455. *pMediaToUse = alternativeMediaToUse;
  2456. if (alternativeMediaId != m_MediaId) {
  2457. m_MediaId = alternativeMediaId;
  2458. m_MediaName.Free();
  2459. alternativeMediaName.CopyTo(&m_MediaName);
  2460. m_MediaType = alternativeMediaType;
  2461. m_RemoteDataSet = alternativeRemoteDataSet;
  2462. }
  2463. }
  2464. }
  2465. alternativeMediaName.Free();
  2466. if (pFirstSideCollection) {
  2467. WsbAffirmHr(pFirstSideCollection->RemoveAllAndRelease());
  2468. }
  2469. } WsbCatch( hr );
  2470. WsbTraceOut(OLESTR("CHsmWorkQueue::FindMigrateMediaToUse"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  2471. return(hr);
  2472. }
  2473. HRESULT
  2474. CHsmWorkQueue::MountMedia(
  2475. IFsaPostIt *pFsaWorkItem,
  2476. GUID mediaToMount,
  2477. GUID firstSide,
  2478. BOOL bShortWait,
  2479. BOOL bSerialize,
  2480. LONGLONG llFreeSpace
  2481. )
  2482. /*++
  2483. --*/
  2484. {
  2485. HRESULT hr = S_OK;
  2486. GUID l_MediaToMount = mediaToMount;
  2487. CComPtr<IRmsDrive> pDrive;
  2488. CWsbBstrPtr pMediaName;
  2489. DWORD dwOptions = RMS_NONE;
  2490. WsbTraceIn(OLESTR("CHsmWorkQueue::MountMedia"),OLESTR("Display Name = <%ls>"), (WCHAR *)m_MediaName);
  2491. try {
  2492. // If we're switching tapes, dismount the current one
  2493. if ((m_MountedMedia != l_MediaToMount) && (m_MountedMedia != GUID_NULL)) {
  2494. WsbAffirmHr(DismountMedia());
  2495. }
  2496. // Ask RMS for short timeout, both for Mount and Allocate
  2497. if (bShortWait) {
  2498. dwOptions |= RMS_SHORT_TIMEOUT;
  2499. }
  2500. // Ask RMS to serialize mounts if required
  2501. if (bSerialize) {
  2502. dwOptions |= RMS_SERIALIZE_MOUNT;
  2503. }
  2504. // Ask RMS to fail scratch media alocation if all free media aren't big enough
  2505. // (In that case, MountScratchCartridge should fail with RMS_E_SCRATCH_NOT_FOUND_TOO_SMALL error)
  2506. dwOptions |= RMS_FAIL_ALLOCATE_ON_SIZE;
  2507. if (l_MediaToMount == GUID_NULL) {
  2508. CComPtr<IRmsCartridge> pCartridge;
  2509. CComPtr<IMediaInfo> pMediaInfo;
  2510. CWsbBstrPtr displayName;
  2511. //
  2512. // We are mounting scratch media so we provide the name and then need to find
  2513. // out the type of what got mounted
  2514. //
  2515. WsbTrace( OLESTR("Mounting Scratch Media <%ls>.\n"), (WCHAR *)m_MediaName );
  2516. displayName = m_MediaName;
  2517. ReportMediaProgress(HSM_JOB_MEDIA_STATE_MOUNTING, hr);
  2518. LONGLONG freeSpace = llFreeSpace; // Get input free space from caller (default is 0)
  2519. hr = m_pRmsServer->MountScratchCartridge( &l_MediaToMount, m_RmsMediaSetId, firstSide, &freeSpace, 0, displayName, &pDrive, &m_pRmsCartridge, &m_pDataMover, dwOptions );
  2520. hr = TranslateRmsMountHr(hr);
  2521. if (FAILED(hr)) {
  2522. m_ScratchFailed = TRUE;
  2523. } else {
  2524. m_ScratchFailed = FALSE;
  2525. }
  2526. // Update max media capacity for future migration jobs (ignore errors)
  2527. DWORD dummy;
  2528. m_pServer->UpdateMediaSizeLimit(&dummy);
  2529. // Check mount-scratch hr
  2530. WsbAffirmHr(hr);
  2531. WsbTrace( OLESTR("Mount Scratch completed.\n") );
  2532. m_MountedMedia = l_MediaToMount;
  2533. //
  2534. // Add a new Media
  2535. //
  2536. WsbAffirmHr(StartNewMedia(pFsaWorkItem));
  2537. if (m_RequestAction == FSA_REQUEST_ACTION_PREMIGRATE) {
  2538. //
  2539. // Start a new Bag to receive data
  2540. //
  2541. WsbAffirmHr(StartNewBag());
  2542. //
  2543. // Start a new session for the bag
  2544. //
  2545. WsbAffirmHr(StartNewSession());
  2546. // Getting media parameters after we start a new session ensures updated data
  2547. // (No need to supply default free-space - if driver doesn't support this info,
  2548. // mover will set free space to capacity. This is what we want for new media).
  2549. WsbAffirmHr(GetMediaParameters());
  2550. }
  2551. //
  2552. // Now check the capacity of the media and the size of the
  2553. // file to see if the file can even fit on this scratch
  2554. // media. If not, return the error.
  2555. //
  2556. LONGLONG requestSize;
  2557. WsbAffirmHr(pFsaWorkItem->GetRequestSize(&requestSize));
  2558. if ((requestSize + HSM_STORAGE_OVERHEAD) > m_MediaCapacity) {
  2559. WsbThrow( HSM_E_WORK_SKIPPED_FILE_BIGGER_MEDIA );
  2560. }
  2561. } else {
  2562. if (m_MountedMedia != l_MediaToMount) {
  2563. ReportMediaProgress(HSM_JOB_MEDIA_STATE_MOUNTING, hr);
  2564. hr = m_pRmsServer->MountCartridge( l_MediaToMount, &pDrive, &m_pRmsCartridge, &m_pDataMover, dwOptions );
  2565. hr = TranslateRmsMountHr(hr);
  2566. //
  2567. // If failure is because cartridge is disabled, need to get media label to put in error.
  2568. //
  2569. if (hr == RMS_E_CARTRIDGE_DISABLED) {
  2570. // Since this is just to get label, if any of these functions fail,
  2571. // don't throw, error will simply have blank label.
  2572. //
  2573. CComPtr<IRmsCartridge> pMedia;
  2574. HRESULT hrName;
  2575. hrName = m_pRmsServer->FindCartridgeById(l_MediaToMount , &pMedia);
  2576. if (hrName == S_OK) {
  2577. hrName = pMedia->GetName(&pMediaName);
  2578. }
  2579. if ((hrName != S_OK) || ((WCHAR *)pMediaName == NULL)) {
  2580. // Cannot get media name - set to blanks
  2581. pMediaName = L"";
  2582. }
  2583. WsbThrow(hr);
  2584. }
  2585. WsbAffirmHr(hr);
  2586. m_MountedMedia = l_MediaToMount;
  2587. WsbTrace( OLESTR("Mount completed.\n") );
  2588. if (m_RequestAction == FSA_REQUEST_ACTION_PREMIGRATE) {
  2589. //
  2590. // Start a new Bag since bags can't yet span media.
  2591. //
  2592. WsbAffirmHr(StartNewBag());
  2593. //
  2594. // Start a session
  2595. WsbAffirmHr(StartNewSession());
  2596. }
  2597. // Getting media parameters after we start a new session ensures updated data
  2598. LONGLONG internalFreeSpace;
  2599. WsbAffirmHr(GetMediaFreeSpace(&internalFreeSpace));
  2600. WsbAffirmHr(GetMediaParameters(internalFreeSpace));
  2601. }
  2602. }
  2603. } WsbCatchAndDo(hr,
  2604. switch (hr) {
  2605. case HSM_E_STG_PL_NOT_CFGD:
  2606. case HSM_E_STG_PL_INVALID:
  2607. FailJob();
  2608. break;
  2609. case RMS_E_CARTRIDGE_DISABLED:
  2610. if ((WCHAR *)pMediaName == NULL) {
  2611. pMediaName = L"";
  2612. }
  2613. WsbLogEvent(HSM_MESSAGE_MEDIA_DISABLED, 0, NULL, pMediaName, NULL);
  2614. break;
  2615. default:
  2616. break;
  2617. }
  2618. );
  2619. WsbTraceOut(OLESTR("CHsmWorkQueue::MountMedia"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  2620. return(hr);
  2621. }
  2622. HRESULT
  2623. CHsmWorkQueue::MarkMediaFull(
  2624. IFsaPostIt* /*pFsaWorkItem*/,
  2625. GUID mediaId
  2626. )
  2627. /*++
  2628. --*/
  2629. {
  2630. HRESULT hr = S_OK;
  2631. WsbTraceIn(OLESTR("CHsmWorkQueue::MarkMediaFull"),OLESTR(""));
  2632. try {
  2633. //
  2634. // Update the media database
  2635. //
  2636. CComPtr<IMediaInfo> pMediaInfo;
  2637. WsbAffirmHr(m_pSegmentDb->GetEntity(m_pDbWorkSession, HSM_MEDIA_INFO_REC_TYPE, IID_IMediaInfo,
  2638. (void**)&pMediaInfo));
  2639. WsbAffirmHr(pMediaInfo->SetId(mediaId));
  2640. WsbAffirmHr(pMediaInfo->FindEQ());
  2641. m_MediaReadOnly = TRUE;
  2642. WsbAffirmHr(pMediaInfo->SetRecallOnlyStatus(m_MediaReadOnly));
  2643. WsbAffirmHr(pMediaInfo->UpdateLastKnownGoodMaster());
  2644. WsbAffirmHr(pMediaInfo->Write());
  2645. /*** If we like to allocate immediately a second side of a full meida, than the code below should be completed...
  2646. if (S_OK == m_pRmsServer->IsMultipleSidedMedia(m_RmsMediaSetId)) {
  2647. // Check if second size is avalaible for allocation
  2648. // Allocate (non-blocking) the second side
  2649. } ***/
  2650. } WsbCatch( hr );
  2651. WsbTraceOut(OLESTR("CHsmWorkQueue::MarkMediaFull"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  2652. return(hr);
  2653. }
  2654. HRESULT
  2655. CHsmWorkQueue::MarkMediaBad(
  2656. IFsaPostIt * /*pFsaWorkItem */,
  2657. GUID mediaId,
  2658. HRESULT lastError
  2659. )
  2660. /*++
  2661. --*/
  2662. {
  2663. HRESULT hr = S_OK;
  2664. WsbTraceIn(OLESTR("CHsmWorkQueue::MarkMediaBad"),OLESTR(""));
  2665. try {
  2666. //
  2667. // Update the media database
  2668. //
  2669. CComPtr<IMediaInfo> pMediaInfo;
  2670. WsbAffirmHr(m_pSegmentDb->GetEntity(m_pDbWorkSession, HSM_MEDIA_INFO_REC_TYPE, IID_IMediaInfo,
  2671. (void**)&pMediaInfo));
  2672. WsbAffirmHr(pMediaInfo->SetId(mediaId));
  2673. WsbAffirmHr(pMediaInfo->FindEQ());
  2674. WsbAffirmHr(pMediaInfo->SetLastError(lastError));
  2675. m_MediaReadOnly = TRUE;
  2676. WsbAffirmHr(pMediaInfo->SetRecallOnlyStatus(m_MediaReadOnly));
  2677. WsbAffirmHr(pMediaInfo->Write());
  2678. } WsbCatch( hr );
  2679. WsbTraceOut(OLESTR("CHsmWorkQueue::MarkMediaBad"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  2680. return(hr);
  2681. }
  2682. HRESULT
  2683. CHsmWorkQueue::FindRecallMediaToUse(
  2684. IFsaPostIt *pFsaWorkItem,
  2685. GUID *pMediaToUse,
  2686. BOOL *pMediaChanged
  2687. )
  2688. /*++
  2689. --*/
  2690. {
  2691. HRESULT hr = S_OK;
  2692. WsbTraceIn(OLESTR("CHsmWorkQueue::FindRecallMediaToUse"),OLESTR(""));
  2693. try {
  2694. WsbAssert(pMediaToUse != 0, E_POINTER);
  2695. *pMediaToUse = GUID_NULL;
  2696. WsbAssert(pMediaChanged != 0, E_POINTER);
  2697. *pMediaChanged = FALSE;
  2698. CComQIPtr<ISegDb, &IID_ISegDb> pSegDb = m_pSegmentDb;
  2699. CComPtr<ISegRec> pSegRec;
  2700. GUID l_BagId;
  2701. LONGLONG l_FileStart;
  2702. LONGLONG l_FileSize;
  2703. USHORT l_SegFlags;
  2704. GUID l_PrimPos;
  2705. LONGLONG l_SecPos;
  2706. GUID storagePoolId;
  2707. FSA_PLACEHOLDER placeholder;
  2708. //
  2709. // Go to the segment database to find out where the data
  2710. // is located.
  2711. //
  2712. WsbAffirmHr(pFsaWorkItem->GetPlaceholder(&placeholder));
  2713. m_BagId = placeholder.bagId;
  2714. WsbAffirmHr(pFsaWorkItem->GetStoragePoolId(&storagePoolId));
  2715. WsbTrace(OLESTR("Finding SegmentRecord: <%ls>, <%ls>, <%ls>\n"),
  2716. WsbGuidAsString(placeholder.bagId),
  2717. WsbStringCopy(WsbLonglongAsString(placeholder.fileStart)),
  2718. WsbStringCopy(WsbLonglongAsString(placeholder.fileSize)));
  2719. hr = pSegDb->SegFind(m_pDbWorkSession, placeholder.bagId, placeholder.fileStart,
  2720. placeholder.fileSize, &pSegRec);
  2721. if (S_OK != hr) {
  2722. //
  2723. // We couldn't find the segment record for this information!
  2724. //
  2725. hr = HSM_E_SEGMENT_INFO_NOT_FOUND;
  2726. WsbAffirmHr(hr);
  2727. }
  2728. WsbAffirmHr(pSegRec->GetSegmentRecord(&l_BagId, &l_FileStart, &l_FileSize, &l_SegFlags,
  2729. &l_PrimPos, &l_SecPos));
  2730. WsbAssert(0 != l_SecPos, HSM_E_BAD_SEGMENT_INFORMATION);
  2731. //
  2732. // In case of an indirect record, go to the dirtect record to get real location info
  2733. //
  2734. if (l_SegFlags & SEG_REC_INDIRECT_RECORD) {
  2735. pSegRec = 0;
  2736. WsbTrace(OLESTR("Finding indirect SegmentRecord: <%ls>, <%ls>, <%ls>\n"),
  2737. WsbGuidAsString(l_PrimPos), WsbStringCopy(WsbLonglongAsString(l_SecPos)),
  2738. WsbStringCopy(WsbLonglongAsString(placeholder.fileSize)));
  2739. hr = pSegDb->SegFind(m_pDbWorkSession, l_PrimPos, l_SecPos,
  2740. placeholder.fileSize, &pSegRec);
  2741. if (S_OK != hr) {
  2742. //
  2743. // We couldn't find the direct segment record for this segment!
  2744. //
  2745. hr = HSM_E_SEGMENT_INFO_NOT_FOUND;
  2746. WsbAffirmHr(hr);
  2747. }
  2748. WsbAffirmHr(pSegRec->GetSegmentRecord(&l_BagId, &l_FileStart, &l_FileSize, &l_SegFlags,
  2749. &l_PrimPos, &l_SecPos));
  2750. WsbAssert(0 != l_SecPos, HSM_E_BAD_SEGMENT_INFORMATION);
  2751. // Don't support a second indirection for now !!
  2752. WsbAssert(0 == (l_SegFlags & SEG_REC_INDIRECT_RECORD), HSM_E_BAD_SEGMENT_INFORMATION);
  2753. }
  2754. //
  2755. // Go to the media database to get the media ID
  2756. //
  2757. CComPtr<IMediaInfo> pMediaInfo;
  2758. GUID l_RmsMediaId;
  2759. WsbAffirmHr(m_pSegmentDb->GetEntity(m_pDbWorkSession, HSM_MEDIA_INFO_REC_TYPE, IID_IMediaInfo,
  2760. (void**)&pMediaInfo));
  2761. WsbAffirmHr(pMediaInfo->SetId(l_PrimPos));
  2762. hr = pMediaInfo->FindEQ();
  2763. if (S_OK != hr) {
  2764. hr = HSM_E_MEDIA_INFO_NOT_FOUND;
  2765. WsbAffirmHr(hr);
  2766. }
  2767. WsbAffirmHr(pMediaInfo->GetMediaSubsystemId(&l_RmsMediaId));
  2768. // If the current tape isn't the one ==> media changed
  2769. if (m_MountedMedia != l_RmsMediaId) {
  2770. *pMediaChanged = TRUE;
  2771. // If there is a current tape and it isn't the one, dismount it
  2772. if (m_MountedMedia != GUID_NULL) {
  2773. WsbAffirmHr(DismountMedia());
  2774. }
  2775. }
  2776. m_RemoteDataSetStart.QuadPart = l_SecPos;
  2777. *pMediaToUse = l_RmsMediaId;
  2778. // Keep HSM id of mounted media
  2779. m_MediaId = l_PrimPos;
  2780. } WsbCatch( hr );
  2781. WsbTraceOut(OLESTR("CHsmWorkQueue::FindRecallMediaToUse"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  2782. return(hr);
  2783. }
  2784. HRESULT
  2785. CHsmWorkQueue::GetSource(
  2786. IFsaPostIt *pFsaWorkItem,
  2787. OLECHAR **pSourceString
  2788. )
  2789. /*++
  2790. Routine Description:
  2791. This function builds the Source file name
  2792. Arguments:
  2793. pFsaWorkItem - the item to be migrated
  2794. pSourceString - the Source file name.
  2795. Return Value:
  2796. S_OK
  2797. --*/
  2798. {
  2799. HRESULT hr = S_OK;
  2800. CComPtr<IFsaResource> pResource;
  2801. CWsbStringPtr tmpString;
  2802. CComPtr<IHsmSession> pSession;
  2803. CWsbStringPtr path;
  2804. WsbTraceIn(OLESTR("CHsmWorkQueue::GetSource"),OLESTR(""));
  2805. try {
  2806. //
  2807. // Get the real session pointer from the IUnknown
  2808. //
  2809. WsbAffirmHr(pFsaWorkItem->GetSession(&pSession));
  2810. WsbAffirm(pSession != 0, E_POINTER);
  2811. // First get the name of the resource from the session
  2812. WsbAffirmHr(pSession->GetResource(&pResource));
  2813. WsbAffirmHr(pFsaWorkItem->GetPath(&path, 0));
  2814. tmpString.Alloc(1000);
  2815. WsbAffirmHr(pResource->GetPath(&tmpString, 0));
  2816. tmpString.Append(&(path[1]));
  2817. // tmpString.Prepend(OLESTR("\\\\?\\"));
  2818. WsbAffirmHr(tmpString.GiveTo(pSourceString));
  2819. } WsbCatch(hr);
  2820. WsbTraceOut(OLESTR("CHsmWorkQueue::GetSource"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  2821. return (hr);
  2822. }
  2823. HRESULT
  2824. CHsmWorkQueue::EndSessions(
  2825. BOOL done,
  2826. BOOL bNoDelay
  2827. )
  2828. {
  2829. HRESULT hr = S_OK;
  2830. WsbTraceIn(OLESTR("CHsmWorkQueue::EndSessions"),OLESTR(""));
  2831. try {
  2832. HRESULT dismountHr = S_OK;
  2833. CComPtr<IConnectionPointContainer> pCPC;
  2834. CComPtr<IConnectionPoint> pCP;
  2835. //
  2836. // Release resources: should be earlier in completion
  2837. //
  2838. dismountHr = DismountMedia(bNoDelay);
  2839. // Tell the session that we don't want to be advised anymore.
  2840. try {
  2841. WsbAffirmHr(m_pSession->QueryInterface(IID_IConnectionPointContainer, (void**) &pCPC));
  2842. WsbAffirmHr(pCPC->FindConnectionPoint(IID_IHsmSessionSinkEveryState, &pCP));
  2843. WsbAffirmHr(pCP->Unadvise(m_StateCookie));
  2844. } WsbCatch( hr );
  2845. pCPC = 0;
  2846. pCP = 0;
  2847. m_StateCookie = 0;
  2848. try {
  2849. WsbAffirmHr(m_pSession->QueryInterface(IID_IConnectionPointContainer, (void**) &pCPC));
  2850. WsbAffirmHr(pCPC->FindConnectionPoint(IID_IHsmSessionSinkEveryEvent, &pCP));
  2851. WsbAffirmHr(pCP->Unadvise(m_EventCookie));
  2852. } WsbCatch( hr );
  2853. pCPC = 0;
  2854. pCP = 0;
  2855. m_EventCookie = 0;
  2856. if (done) {
  2857. try {
  2858. WsbTrace( OLESTR("Telling Session Data mover is done\n") );
  2859. WsbAffirmHr(SetState(HSM_JOB_STATE_DONE));
  2860. } WsbCatch( hr );
  2861. }
  2862. m_pSession = 0;
  2863. m_pFsaResource = 0;
  2864. WsbAffirmHr(dismountHr);
  2865. WsbAffirmHr(hr);
  2866. } WsbCatch (hr);
  2867. WsbTraceOut(OLESTR("CHsmWorkQueue::EndSessions"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  2868. return (hr);
  2869. }
  2870. HRESULT
  2871. CHsmWorkQueue::GetScanItem(
  2872. IFsaPostIt * pFsaWorkItem,
  2873. IFsaScanItem ** ppIFsaScanItem
  2874. )
  2875. {
  2876. HRESULT hr = S_OK;
  2877. CWsbStringPtr path;
  2878. WsbTraceIn(OLESTR("CHsmWorkQueue::GetScanItem"),OLESTR(""));
  2879. try {
  2880. WsbAffirmPointer(ppIFsaScanItem);
  2881. WsbAffirm(!*ppIFsaScanItem, E_INVALIDARG);
  2882. WsbAffirmHr(pFsaWorkItem->GetPath(&path, 0));
  2883. WsbAffirmHr(m_pFsaResource->FindFirst(path, m_pSession, ppIFsaScanItem));
  2884. } WsbCatch (hr)
  2885. WsbTraceOut(OLESTR("CHsmWorkQueue::GetScanItem"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  2886. return( hr );
  2887. }
  2888. HRESULT
  2889. CHsmWorkQueue::GetNumWorkItems (
  2890. ULONG *pNumWorkItems
  2891. )
  2892. {
  2893. HRESULT hr = S_OK;
  2894. CWsbStringPtr path;
  2895. WsbTraceIn(OLESTR("CHsmWorkQueue::GetNumWorkItems"),OLESTR(""));
  2896. try {
  2897. WsbAffirm(0 != pNumWorkItems, E_POINTER);
  2898. *pNumWorkItems = 0;
  2899. WsbAffirmHr(m_pWorkToDo->GetEntries(pNumWorkItems));
  2900. } WsbCatch (hr)
  2901. WsbTraceOut(OLESTR("CHsmWorkQueue::GetNumWorkItems"),OLESTR("hr = <%ls>, NumItems = <%ls>"),
  2902. WsbHrAsString(hr), WsbPtrToUlongAsString(pNumWorkItems));
  2903. return( hr );
  2904. }
  2905. HRESULT
  2906. CHsmWorkQueue::GetCurrentSessionId (
  2907. GUID *pSessionId
  2908. )
  2909. {
  2910. HRESULT hr = S_OK;
  2911. CWsbStringPtr path;
  2912. WsbTraceIn(OLESTR("CsmWorkQueue::GetCurrentSessionId"),OLESTR(""));
  2913. try {
  2914. WsbAffirm(0 != pSessionId, E_POINTER);
  2915. WsbAffirmHr(m_pSession->GetIdentifier(pSessionId));
  2916. } WsbCatch (hr)
  2917. WsbTraceOut(OLESTR("CHsmWorkQueue::GetCurrentSessionId"),OLESTR("hr = <%ls>, Id = <%ls>"),
  2918. WsbHrAsString(hr), WsbPtrToGuidAsString(pSessionId));
  2919. return( hr );
  2920. }
  2921. DWORD HsmWorkQueueThread(
  2922. void *pVoid
  2923. )
  2924. /*++
  2925. --*/
  2926. {
  2927. HRESULT hr;
  2928. hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  2929. hr = ((CHsmWorkQueue*) pVoid)->DoWork();
  2930. CoUninitialize();
  2931. return(hr);
  2932. }
  2933. HRESULT
  2934. CHsmWorkQueue::Pause(
  2935. void
  2936. )
  2937. /*++
  2938. Implements:
  2939. CHsmWorkQueue::Pause().
  2940. --*/
  2941. {
  2942. HRESULT hr = S_OK;
  2943. HSM_JOB_STATE oldState;
  2944. WsbTraceIn(OLESTR("CHsmWorkQueue::Pause"), OLESTR(""));
  2945. try {
  2946. // If we are running, then suspend the thread.
  2947. WsbAffirm((HSM_JOB_STATE_STARTING == m_JobState) ||
  2948. (HSM_JOB_STATE_ACTIVE == m_JobState) ||
  2949. (HSM_JOB_STATE_RESUMING == m_JobState), E_UNEXPECTED);
  2950. oldState = m_JobState;
  2951. WsbAffirmHr(SetState(HSM_JOB_STATE_PAUSING));
  2952. // if we are unable to suspend, then return to the former state.
  2953. try {
  2954. WsbAffirm(0xffffffff != SuspendThread(m_WorkerThread), HRESULT_FROM_WIN32(GetLastError()));
  2955. WsbAffirmHr(SetState(HSM_JOB_STATE_PAUSED));
  2956. } WsbCatchAndDo(hr, SetState(oldState););
  2957. } WsbCatch(hr);
  2958. WsbTraceOut(OLESTR("CHsmWorkQueue::Pause"), OLESTR("hr = <%ls>"), WsbHrAsString(hr) );
  2959. return(hr);
  2960. }
  2961. HRESULT
  2962. CHsmWorkQueue::Resume(
  2963. void
  2964. )
  2965. /*++
  2966. Implements:
  2967. CHsmWorkQueue::Resume().
  2968. --*/
  2969. {
  2970. HRESULT hr = S_OK;
  2971. HSM_JOB_STATE oldState;
  2972. WsbTraceIn(OLESTR("CHsmWorkQueue::Resume"), OLESTR(""));
  2973. try {
  2974. // If we are paused, then suspend the thread.
  2975. WsbAffirm((HSM_JOB_STATE_PAUSING == m_JobState) || (HSM_JOB_STATE_PAUSED == m_JobState), E_UNEXPECTED);
  2976. // If we are running, then suspend the thread.
  2977. oldState = m_JobState;
  2978. WsbAffirmHr(SetState(HSM_JOB_STATE_RESUMING));
  2979. // If we are unable to resume, then return to the former state.
  2980. try {
  2981. WsbAffirm(0xffffffff != ResumeThread(m_WorkerThread), HRESULT_FROM_WIN32(GetLastError()));
  2982. WsbAffirmHr(SetState(HSM_JOB_STATE_ACTIVE));
  2983. } WsbCatchAndDo(hr, SetState(oldState););
  2984. } WsbCatch(hr);
  2985. WsbTraceOut(OLESTR("CHsmWorkQueue::Resume"), OLESTR("hr = <%ls>"), WsbHrAsString(hr) );
  2986. return(hr);
  2987. }
  2988. HRESULT
  2989. CHsmWorkQueue::SetState(
  2990. IN HSM_JOB_STATE state
  2991. )
  2992. /*++
  2993. --*/
  2994. {
  2995. HRESULT hr = S_OK;
  2996. BOOL bLog = TRUE;
  2997. WsbTraceIn(OLESTR("CHsmWorkQueue:SetState"), OLESTR("state = <%ls>"), JobStateAsString( state ) );
  2998. try {
  2999. //
  3000. // Change the state and report the change to the session. Unless the current state is
  3001. // failed then leave it failed. Is is necessary because when this guy fails, it will
  3002. // cancel all sessions so that no more work is sent in and so we will skip any queued work.
  3003. // If the current state is failed, we don't need to spit out the failed message every time,
  3004. // so we send ProcessState a false fullmessage unless the state is cancelled.
  3005. //
  3006. if (HSM_JOB_STATE_FAILED != m_JobState) {
  3007. m_JobState = state;
  3008. }
  3009. if ((HSM_JOB_STATE_FAILED == m_JobState) && (HSM_JOB_STATE_CANCELLED != state)) {
  3010. bLog = FALSE;
  3011. }
  3012. WsbAffirmHr(m_pSession->ProcessState(m_JobPhase, m_JobState, m_CurrentPath, bLog));
  3013. } WsbCatch(hr);
  3014. WsbTraceOut(OLESTR("CHsmWorkQueue::SetState"), OLESTR("hr = <%ls> m_JobState = <%ls>"), WsbHrAsString(hr), JobStateAsString( m_JobState ) );
  3015. return(hr);
  3016. }
  3017. HRESULT
  3018. CHsmWorkQueue::Cancel(
  3019. void
  3020. )
  3021. /*++
  3022. Implements:
  3023. CHsmWorkQueue::Cancel().
  3024. --*/
  3025. {
  3026. HRESULT hr = S_OK;
  3027. WsbTraceIn(OLESTR("CHsmWorkQueue::Cancel"), OLESTR(""));
  3028. try {
  3029. WsbAffirmHr(SetState(HSM_JOB_STATE_CANCELLING));
  3030. //
  3031. // This needs to be prepended and the queue emptied out!
  3032. //
  3033. CComPtr<IHsmWorkItem> pWorkItem;
  3034. WsbAffirmHr(m_pHsmServerCreate->CreateInstance(CLSID_CHsmWorkItem, IID_IHsmWorkItem,
  3035. (void **)&pWorkItem));
  3036. WsbAffirmHr(pWorkItem->SetWorkType(HSM_WORK_ITEM_MOVER_CANCELLED));
  3037. WsbAffirmHr(m_pWorkToDo->Prepend(pWorkItem));
  3038. } WsbCatch(hr);
  3039. WsbTraceOut(OLESTR("CHsmWorkQueue::Cancel"), OLESTR("hr = <%ls>"), WsbHrAsString(hr) );
  3040. return(hr);
  3041. }
  3042. HRESULT
  3043. CHsmWorkQueue::FailJob(
  3044. void
  3045. )
  3046. /*++
  3047. Implements:
  3048. CHsmWorkQueue::FailJob().
  3049. --*/
  3050. {
  3051. HRESULT hr = S_OK;
  3052. WsbTraceIn(OLESTR("CHsmWorkQueue::FailJob"), OLESTR(""));
  3053. try {
  3054. //
  3055. // Set our state to failed and then cancel all work
  3056. //
  3057. WsbAffirmHr(SetState(HSM_JOB_STATE_FAILED));
  3058. if (m_pSession != 0) {
  3059. WsbAffirmHr(m_pSession->Cancel( HSM_JOB_PHASE_ALL ));
  3060. }
  3061. } WsbCatch(hr);
  3062. WsbTraceOut(OLESTR("CHsmWorkQueue::FailJob"), OLESTR("hr = <%ls>"), WsbHrAsString(hr) );
  3063. return(hr);
  3064. }
  3065. HRESULT
  3066. CHsmWorkQueue::PauseScanner(
  3067. void
  3068. )
  3069. /*++
  3070. Implements:
  3071. CHsmWorkQueue::PauseScanner().
  3072. --*/
  3073. {
  3074. HRESULT hr = S_OK;
  3075. WsbTraceIn(OLESTR("CHsmWorkQueue::PauseScanner"), OLESTR(""));
  3076. try {
  3077. //
  3078. // Set our state to failed and then cancel all work
  3079. //
  3080. if (m_pSession != 0) {
  3081. WsbAffirmHr(m_pSession->Pause( HSM_JOB_PHASE_SCAN ));
  3082. m_ScannerPaused = TRUE;
  3083. } else {
  3084. //
  3085. // We should never get here - this means we have been processing work but we
  3086. // have no session established
  3087. //
  3088. WsbThrow(E_POINTER);
  3089. }
  3090. } WsbCatch(hr);
  3091. WsbTraceOut(OLESTR("CHsmWorkQueue::PauseScanner"), OLESTR("hr = <%ls>"), WsbHrAsString(hr) );
  3092. return(hr);
  3093. }
  3094. HRESULT
  3095. CHsmWorkQueue::ResumeScanner(
  3096. void
  3097. )
  3098. /*++
  3099. Implements:
  3100. CHsmWorkQueue::ResumeScanner().
  3101. --*/
  3102. {
  3103. HRESULT hr = S_OK;
  3104. WsbTraceIn(OLESTR("CHsmWorkQueue::ResumeScanner"), OLESTR(""));
  3105. try {
  3106. //
  3107. // Set our state to failed and then cancel all work
  3108. //
  3109. if (m_pSession != 0) {
  3110. if (TRUE == m_ScannerPaused && HSM_JOB_STATE_ACTIVE == m_JobState) {
  3111. WsbAffirmHr(m_pSession->Resume( HSM_JOB_PHASE_SCAN ));
  3112. m_ScannerPaused = FALSE;
  3113. }
  3114. } else {
  3115. //
  3116. // We should never get here - this means we have been processing work but we
  3117. // have no session established
  3118. //
  3119. WsbThrow(E_POINTER);
  3120. }
  3121. } WsbCatch(hr);
  3122. WsbTraceOut(OLESTR("CHsmWorkQueue::ResumeScanner"), OLESTR("hr = <%ls>"), WsbHrAsString(hr) );
  3123. return(hr);
  3124. }
  3125. void
  3126. CHsmWorkQueue::ReportMediaProgress(
  3127. HSM_JOB_MEDIA_STATE state,
  3128. HRESULT /*status*/
  3129. )
  3130. /*++
  3131. Implements:
  3132. CHsmWorkQueue::ReportMediaProgress().
  3133. --*/
  3134. {
  3135. HRESULT hr = S_OK;
  3136. CWsbStringPtr mediaName;
  3137. HSM_JOB_MEDIA_TYPE mediaType = HSM_JOB_MEDIA_TYPE_UNKNOWN;
  3138. WsbTraceIn(OLESTR("CHsmWorkQueue::ReportMediaProgress"), OLESTR(""));
  3139. try {
  3140. // Report Progress but we don't really care if it succeeds.
  3141. hr = m_pSession->ProcessMediaState(m_JobPhase, state, m_MediaName, m_MediaType, 0);
  3142. hr = S_OK;
  3143. // if (status != S_OK) {
  3144. // (void) m_pSession->ProcessHr(m_JobPhase, __FILE__, __LINE__, status);
  3145. // }
  3146. } WsbCatch(hr);
  3147. WsbTraceOut(OLESTR("CHsmWorkQueue::ReportMediaProgress"), OLESTR("hr = <%ls>"), WsbHrAsString(hr) );
  3148. }
  3149. HRESULT
  3150. CHsmWorkQueue::BuildMediaName(
  3151. OLECHAR **pMediaName
  3152. )
  3153. /*++
  3154. Implements:
  3155. CHsmWorkQueue::BuildMediaName
  3156. --*/
  3157. {
  3158. HRESULT hr = S_OK;
  3159. CWsbStringPtr tmpName;
  3160. WsbTraceIn(OLESTR("CHsmWorkQueue::BuildMediaName"), OLESTR(""));
  3161. try {
  3162. ULONG len = 0;
  3163. // Get the next media number only when last scratch mount succeeded
  3164. // (which means, either first time or we need a second media for the same queue)
  3165. if (! m_ScratchFailed) {
  3166. WsbAffirmHr(m_pServer->GetNextMedia(&m_mediaCount));
  3167. }
  3168. WsbAssert(0 != m_mediaCount, E_UNEXPECTED);
  3169. // Use the base name from the registry if available
  3170. WsbAffirmHr(m_MediaBaseName.GetLen(&len));
  3171. if (len) {
  3172. tmpName = m_MediaBaseName;
  3173. } else {
  3174. // Otherwise use the name of the HSM
  3175. tmpName.Realloc(512);
  3176. WsbAffirmHr(m_pServer->GetName(&tmpName));
  3177. tmpName.Prepend("RS-");
  3178. }
  3179. tmpName.Append("-");
  3180. tmpName.Append(WsbLongAsString(m_mediaCount));
  3181. tmpName.GiveTo(pMediaName);
  3182. } WsbCatch(hr);
  3183. WsbTraceOut(OLESTR("CHsmWorkQueue::BuildMediaName"), OLESTR("hr = <%ls>, name = <%ls>"), WsbHrAsString(hr),
  3184. WsbPtrToStringAsString(pMediaName));
  3185. return(hr);
  3186. }
  3187. HRESULT
  3188. CHsmWorkQueue::GetMediaParameters( LONGLONG defaultFreeSpace )
  3189. /*++
  3190. Implements:
  3191. CHsmWorkQueue::GetMediaParameters
  3192. Note:
  3193. The defaultFreeSpace parameter is passed to the mover to maintain internally
  3194. media free space in case that the device doesn't provide this information.
  3195. If the device supports reporting on free space, then this parameter has no affect.
  3196. --*/
  3197. {
  3198. HRESULT hr = S_OK;
  3199. LONG rmsCartridgeType;
  3200. CWsbBstrPtr barCode;
  3201. WsbTraceIn(OLESTR("CHsmWorkQueue::GetMediaParameters"), OLESTR(""));
  3202. try {
  3203. //
  3204. // Get some information about the media
  3205. //
  3206. LARGE_INTEGER tempFreeSpace;
  3207. tempFreeSpace.QuadPart = defaultFreeSpace;
  3208. WsbAffirmHr(m_pDataMover->GetLargestFreeSpace(&m_MediaFreeSpace, &m_MediaCapacity,
  3209. tempFreeSpace.LowPart, tempFreeSpace.HighPart));
  3210. WsbAffirmHr(m_pRmsCartridge->GetType(&rmsCartridgeType));
  3211. WsbAffirmHr(ConvertRmsCartridgeType(rmsCartridgeType, &m_MediaType));
  3212. WsbAffirmHr(m_pRmsCartridge->GetName(&barCode));
  3213. WsbAffirmHr(CoFileTimeNow(&m_MediaUpdate));
  3214. m_MediaBarCode = barCode;
  3215. } WsbCatch(hr);
  3216. WsbTraceOut(OLESTR("CHsmWorkQueue::GetMediaParameters"), OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  3217. return(hr);
  3218. }
  3219. HRESULT
  3220. CHsmWorkQueue::DismountMedia(BOOL bNoDelay)
  3221. /*++
  3222. Implements:
  3223. CHsmWorkQueue::DismountMedia
  3224. --*/
  3225. {
  3226. HRESULT hr = S_OK;
  3227. WsbTraceIn(OLESTR("CHsmWorkQueue::DismountMedia"), OLESTR(""));
  3228. try {
  3229. if ((m_pRmsCartridge != 0) && (m_MountedMedia != GUID_NULL)) {
  3230. //
  3231. // End the session with the data mover. If this doesn't work, report
  3232. // the problem but continue with the dismount.
  3233. //
  3234. try {
  3235. if ((m_RequestAction == FSA_REQUEST_ACTION_PREMIGRATE) && (m_pDataMover != 0)) {
  3236. if (S_OK == m_BeginSessionHr) {
  3237. //
  3238. // Don't do an end session if the Begin didn't work OK
  3239. //
  3240. m_BeginSessionHr = S_FALSE;
  3241. WsbAffirmHr(m_pDataMover->EndSession());
  3242. // Update media free space after all data has been written to the media
  3243. WsbAffirmHr(UpdateMediaFreeSpace());
  3244. }
  3245. }
  3246. } WsbCatchAndDo( hr,
  3247. WsbTraceAlways(OLESTR("CHsmWorkQueue::DismountMedia: End session or DB update failed, hr = <%ls>\n"),
  3248. WsbHrAsString(hr));
  3249. );
  3250. //
  3251. // Tell the session that we are dismounting media. Ignore any problems
  3252. // with the reporting
  3253. //
  3254. (void )ReportMediaProgress(HSM_JOB_MEDIA_STATE_DISMOUNTING, S_OK);
  3255. //
  3256. // Dismount the cartridge and report progress
  3257. //
  3258. // !!! IMPORTANT NOTE !!!
  3259. //
  3260. // Must free Rms resources used before dismounting...
  3261. //
  3262. m_pRmsCartridge = 0;
  3263. m_pDataMover = 0;
  3264. DWORD dwOptions = RMS_NONE;
  3265. if (bNoDelay) {
  3266. dwOptions |= RMS_DISMOUNT_DEFERRED_ONLY;
  3267. }
  3268. hr = m_pRmsServer->DismountCartridge(m_MountedMedia, dwOptions);
  3269. (void) ReportMediaProgress(HSM_JOB_MEDIA_STATE_DISMOUNTED, hr);
  3270. //
  3271. // Clear out the knowledge of media that was just dismounted
  3272. //
  3273. WsbAffirmHr(UnsetMediaInfo());
  3274. WsbAffirmHr(hr);
  3275. WsbTrace( OLESTR("Dismount completed OK.\n") );
  3276. } else {
  3277. WsbTrace( OLESTR("There is no media to dismount.\n") );
  3278. }
  3279. } WsbCatch(hr);
  3280. WsbTraceOut(OLESTR("CHsmWorkQueue::DismountMedia"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  3281. return(hr);
  3282. }
  3283. HRESULT
  3284. CHsmWorkQueue::ConvertRmsCartridgeType(
  3285. LONG rmsCartridgeType,
  3286. HSM_JOB_MEDIA_TYPE *pMediaType
  3287. )
  3288. /*++
  3289. Implements:
  3290. CHsmWorkQueue::ConvertRmsCartridgeType
  3291. --*/
  3292. {
  3293. HRESULT hr = S_OK;
  3294. WsbTraceIn(OLESTR("CHsmWorkQueue::ConvertRmsCartridgeType"), OLESTR(""));
  3295. try {
  3296. WsbAssert(0 != pMediaType, E_POINTER);
  3297. switch (rmsCartridgeType) {
  3298. case RmsMedia8mm:
  3299. case RmsMedia4mm:
  3300. case RmsMediaDLT:
  3301. case RmsMediaTape:
  3302. *pMediaType = HSM_JOB_MEDIA_TYPE_TAPE;
  3303. break;
  3304. case RmsMediaOptical:
  3305. case RmsMediaMO35:
  3306. case RmsMediaWORM:
  3307. case RmsMediaCDR:
  3308. case RmsMediaDVD:
  3309. *pMediaType = HSM_JOB_MEDIA_TYPE_OPTICAL;
  3310. break;
  3311. case RmsMediaDisk:
  3312. *pMediaType = HSM_JOB_MEDIA_TYPE_REMOVABLE_MAG;
  3313. break;
  3314. case RmsMediaFixed:
  3315. *pMediaType = HSM_JOB_MEDIA_TYPE_FIXED_MAG;
  3316. break;
  3317. case RmsMediaUnknown:
  3318. default:
  3319. *pMediaType = HSM_JOB_MEDIA_TYPE_UNKNOWN;
  3320. break;
  3321. }
  3322. } WsbCatch( hr );
  3323. WsbTraceOut(OLESTR("CHsmWorkQueue::ConvertRmsCartridgeType"), OLESTR("hr = <%ls>"),
  3324. WsbHrAsString(hr));
  3325. return(hr);
  3326. }
  3327. HRESULT
  3328. CHsmWorkQueue::MarkQueueAsDone( void )
  3329. /*++
  3330. Implements:
  3331. CHsmWorkQueue::MarkQueueAsDone
  3332. --*/
  3333. {
  3334. HRESULT hr = S_OK;
  3335. WsbTraceIn(OLESTR("CHsmWorkQueue::MarkQueueAsDone"), OLESTR(""));
  3336. try {
  3337. // Create a work item and append it to the work queue to
  3338. // indicate that the job is done
  3339. CComPtr<IHsmWorkItem> pWorkItem;
  3340. WsbAffirmHr(m_pHsmServerCreate->CreateInstance(CLSID_CHsmWorkItem, IID_IHsmWorkItem,
  3341. (void **)&pWorkItem));
  3342. WsbAffirmHr(pWorkItem->SetWorkType(HSM_WORK_ITEM_FSA_DONE));
  3343. WsbAffirmHr(m_pWorkToDo->Append(pWorkItem));
  3344. } WsbCatch(hr);
  3345. WsbTraceOut(OLESTR("CHsmWorkQueue::MarkQueueAsDone"), OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  3346. return(hr);
  3347. }
  3348. HRESULT
  3349. CHsmWorkQueue::CopyToWaitingQueue(
  3350. IHsmWorkItem *pWorkItem
  3351. )
  3352. /*++
  3353. Implements:
  3354. CHsmWorkQueue::CopyToWaitingQueue
  3355. --*/
  3356. {
  3357. HRESULT hr = S_OK;
  3358. CComPtr<IFsaPostIt> pFsaWorkItem;
  3359. FSA_PLACEHOLDER placeholder;
  3360. WsbTraceIn(OLESTR("CHsmWorkQueue::CopyToWaitingQueue"), OLESTR(""));
  3361. try {
  3362. //
  3363. // Append the work item to the end of the waiting queue
  3364. //
  3365. WsbAffirmHr(m_pWorkToCommit->Append(pWorkItem));
  3366. //
  3367. // If adding this item to the waiting queue triggers
  3368. // then cause the commit
  3369. //
  3370. WsbAffirmHr(pWorkItem->GetFsaPostIt(&pFsaWorkItem));
  3371. WsbAffirmHr(pFsaWorkItem->GetPlaceholder(&placeholder));
  3372. m_DataCountBeforeCommit += placeholder.fileSize;
  3373. m_FilesCountBeforeCommit++;
  3374. } WsbCatch(hr);
  3375. WsbTraceOut(OLESTR("CHsmWorkQueue::CopyToWaitingQueue"), OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  3376. return(hr);
  3377. }
  3378. HRESULT
  3379. CHsmWorkQueue::CompleteWorkItem(
  3380. IHsmWorkItem *pWorkItem
  3381. )
  3382. {
  3383. HRESULT hr = S_OK;
  3384. CWsbStringPtr path;
  3385. FSA_RESULT_ACTION resultAction;
  3386. CComPtr<IFsaPostIt> pFsaWorkItem;
  3387. CComPtr<IFsaResource> pFsaResource;
  3388. FSA_REQUEST_ACTION requestAction;
  3389. WsbTraceIn(OLESTR("CHsmWorkQueue::CompleteWorkItem"), OLESTR(""));
  3390. try {
  3391. //
  3392. // Get the stuff
  3393. //
  3394. WsbAffirmHr(pWorkItem->GetFsaPostIt(&pFsaWorkItem));
  3395. WsbAffirmHr(pWorkItem->GetFsaResource(&pFsaResource));
  3396. WsbAffirmHr(pFsaWorkItem->GetPath(&path, 0));
  3397. WsbAffirmHr(pFsaWorkItem->GetRequestAction(&requestAction));
  3398. WsbTrace(OLESTR("Completing work for <%s>.\n"), (OLECHAR *)path);
  3399. //
  3400. // Update the metadata - If this fails don't process
  3401. // results.
  3402. //
  3403. WsbAffirmHr(UpdateMetaData(pWorkItem));
  3404. //
  3405. // Complete the work
  3406. //
  3407. WsbAffirmHr(pFsaWorkItem->GetResultAction(&resultAction));
  3408. if ((resultAction != FSA_RESULT_ACTION_NONE) &&
  3409. (requestAction != FSA_REQUEST_ACTION_FILTER_RECALL) &&
  3410. (requestAction != FSA_REQUEST_ACTION_FILTER_READ) &&
  3411. (requestAction != FSA_REQUEST_ACTION_RECALL) ) {
  3412. WsbTrace(OLESTR("HSM work item complete, calling FSA\n"));
  3413. hr = pFsaResource->ProcessResult(pFsaWorkItem);
  3414. WsbTrace(OLESTR("FSA ProcessResult returned <%ls>\n"), WsbHrAsString(hr));
  3415. //
  3416. // If the process results fails, find out if the reparse point has been written,
  3417. // if not, put the file in the bag hole table.
  3418. //
  3419. if ( FSA_E_REPARSE_NOT_WRITTEN_FILE_CHANGED == hr ) {
  3420. //
  3421. // Put the file in the bag hole table
  3422. //
  3423. }
  3424. WsbAffirmHr(hr);
  3425. }
  3426. } WsbCatch( hr );
  3427. WsbTraceOut(OLESTR("CHsmWorkQueue::CompleteWorkItem"), OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  3428. return( hr );
  3429. }
  3430. HRESULT
  3431. CHsmWorkQueue::TimeToCommit( void )
  3432. {
  3433. HRESULT hr = S_OK;
  3434. // Call the other version since it has the trace in it
  3435. hr = TimeToCommit(0, 0);
  3436. return( hr );
  3437. }
  3438. HRESULT
  3439. CHsmWorkQueue::TimeToCommit(
  3440. LONGLONG numFiles,
  3441. LONGLONG amountOfData
  3442. )
  3443. {
  3444. HRESULT hr = S_FALSE;
  3445. WsbTraceIn(OLESTR("CHsmWorkQueue::TimeToCommit"), OLESTR("numFiles = <%ls>, amountOfData = <%ls>"),
  3446. WsbQuickString(WsbLonglongAsString(numFiles)), WsbQuickString(WsbLonglongAsString(amountOfData)));
  3447. WsbTrace(OLESTR("CHsmWorkQueue::TimeToCommit: m_DataCountBeforeCommit = %ls, ")
  3448. OLESTR("m_FilesCountBeforeCommit = %ls, m_MediaFreeSpace = %ls\n"),
  3449. WsbQuickString(WsbLonglongAsString(m_DataCountBeforeCommit)),
  3450. WsbQuickString(WsbLonglongAsString(m_FilesCountBeforeCommit)),
  3451. WsbQuickString(WsbLonglongAsString(m_MediaFreeSpace)));
  3452. WsbTrace(OLESTR("CHsmWorkQueue::TimeToCommit: m_MaxBytesBeforeCommit = %lu, m_MinBytesBeforeCommit = %lu\n"),
  3453. m_MaxBytesBeforeCommit, m_MinBytesBeforeCommit);
  3454. WsbTrace(OLESTR("CHsmWorkQueue::TimeToCommit: m_FilesBeforeCommit = %lu, m_FreeMediaBytesAtEndOfMedia = %lu\n"),
  3455. m_FilesBeforeCommit, m_FreeMediaBytesAtEndOfMedia);
  3456. try {
  3457. //
  3458. // If we have enough data or enough files then say it is time
  3459. // Check for lots of data written to media:
  3460. if ((m_DataCountBeforeCommit + amountOfData) >= m_MaxBytesBeforeCommit) {
  3461. WsbTrace(OLESTR("CHsmWorkQueue::TimeToCommit: commit because enough data was written\n"));
  3462. hr = S_OK;
  3463. // Check for lots of files written
  3464. } else if (((m_FilesCountBeforeCommit + numFiles) >= m_FilesBeforeCommit) &&
  3465. ((m_DataCountBeforeCommit + amountOfData) >= m_MinBytesBeforeCommit)) {
  3466. WsbTrace(OLESTR("CHsmWorkQueue::TimeToCommit: commit because enough files were written\n"));
  3467. hr = S_OK;
  3468. // Check for shortage of space on the media
  3469. } else if (((m_MediaFreeSpace - amountOfData) <= m_FreeMediaBytesAtEndOfMedia) &&
  3470. ((m_DataCountBeforeCommit + amountOfData) >= m_MinBytesBeforeCommit)) {
  3471. WsbTrace(OLESTR("CHsmWorkQueue::TimeToCommit: commit because end of media is near\n"));
  3472. hr = S_OK;
  3473. }
  3474. } WsbCatch( hr );
  3475. WsbTraceOut(OLESTR("CHsmWorkQueue::TimeToCommit"), OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  3476. return( hr );
  3477. }
  3478. HRESULT
  3479. CHsmWorkQueue::CheckMigrateMinimums(void)
  3480. /*++
  3481. Routine Description:
  3482. Check that there is enough work in the queue to start a migrate session.
  3483. Arguments:
  3484. None.
  3485. Return Value:
  3486. S_OK - There is enough to start a session,
  3487. we hit the end of the queue, or this isn't a migrate queue.
  3488. S_FALSE - There isn't enough yet.
  3489. E_* - An error was encountered.
  3490. --*/
  3491. {
  3492. HRESULT hr = S_FALSE;
  3493. WsbTraceIn(OLESTR("CHsmWorkQueue::CheckMigrateMinimums"), OLESTR(""));
  3494. // Only check if the session has not already started (or been attempted).
  3495. if (S_FALSE != m_BeginSessionHr) {
  3496. WsbTrace(OLESTR("CHsmWorkQueue::CheckMigrateMinimums: session already started\n"));
  3497. hr = S_OK;
  3498. } else {
  3499. try {
  3500. ULONG BytesOfData = 0;
  3501. ULONG NumEntries;
  3502. // Get the number of items in the queue
  3503. WsbAffirmHr(m_pWorkToDo->GetEntries(&NumEntries));
  3504. WsbTrace(OLESTR("CHsmWorkQueue::CheckMigrateMinimums: size of queue = %lu, Min = %lu\n"),
  3505. NumEntries, m_MinFilesToMigrate);
  3506. // If the queue is already large enough, don't check individual
  3507. // items.
  3508. if (NumEntries >= m_MinFilesToMigrate) {
  3509. WsbTrace(OLESTR("CHsmWorkQueue::CheckMigrateMinimums: enough queue items\n"));
  3510. hr = S_OK;
  3511. } else {
  3512. // Loop over the items in the queue
  3513. for (ULONG i = 0; i < NumEntries; i++) {
  3514. CComPtr<IFsaPostIt> pFsaWorkItem;
  3515. CComPtr<IHsmWorkItem> pWorkItem;
  3516. FSA_REQUEST_ACTION RequestAction;
  3517. LONGLONG RequestSize;
  3518. HSM_WORK_ITEM_TYPE workType;
  3519. WsbAffirmHr(m_pWorkToDo->At(i, IID_IHsmWorkItem,
  3520. (void **)&pWorkItem));
  3521. WsbAffirmHr(pWorkItem->GetWorkType(&workType));
  3522. // Check the type of work item
  3523. if (HSM_WORK_ITEM_FSA_WORK != workType) {
  3524. // Hit the end of the queue or some other unusual
  3525. // condition. Allow processing of the queue.
  3526. WsbTrace(OLESTR("CHsmWorkQueue::CheckMigrateMinimums: non-standard work type\n"));
  3527. hr = S_OK;
  3528. break;
  3529. }
  3530. // Make sure this is a migrate queue. (This assumes a queue
  3531. // doesn't contain different types of FSA requests.)
  3532. WsbAffirmHr(pWorkItem->GetFsaPostIt(&pFsaWorkItem));
  3533. WsbAffirmHr(pFsaWorkItem->GetRequestAction(&RequestAction));
  3534. WsbTrace(OLESTR("CHsmWorkQueue::CheckMigrateMinimums: RequestAction = %d\n"),
  3535. static_cast<int>(RequestAction));
  3536. if (FSA_REQUEST_ACTION_PREMIGRATE != RequestAction) {
  3537. WsbTrace(OLESTR("CHsmWorkQueue::CheckMigrateMinimums: item is not migrate\n"));
  3538. hr = S_OK;
  3539. break;
  3540. }
  3541. // Check for minimum amount of data
  3542. WsbAffirmHr(pFsaWorkItem->GetRequestSize(&RequestSize));
  3543. WsbTrace(OLESTR("CHsmWorkQueue::CheckMigrateMinimums: RequestSize = %ls, Min = %lu\n"),
  3544. WsbLonglongAsString(RequestSize), m_MinBytesToMigrate);
  3545. if ((static_cast<LONGLONG>(BytesOfData) + RequestSize) >=
  3546. static_cast<LONGLONG>(m_MinBytesToMigrate)) {
  3547. WsbTrace(OLESTR("CHsmWorkQueue::CheckMigrateMinimums: enough data\n"));
  3548. hr = S_OK;
  3549. break;
  3550. } else {
  3551. BytesOfData += static_cast<ULONG>(RequestSize);
  3552. WsbTrace(OLESTR("CHsmWorkQueue::CheckMigrateMinimums: new BytesOfData = %lu\n"),
  3553. BytesOfData);
  3554. }
  3555. }
  3556. }
  3557. } WsbCatch( hr );
  3558. }
  3559. WsbTraceOut(OLESTR("CHsmWorkQueue::CheckMigrateMinimums"), OLESTR("hr = <%ls>"),
  3560. WsbHrAsString(hr));
  3561. return( hr );
  3562. }
  3563. HRESULT
  3564. CHsmWorkQueue::CheckRegistry(void)
  3565. {
  3566. OLECHAR dataString[100];
  3567. HRESULT hr = S_OK;
  3568. ULONG l_value;
  3569. DWORD sizeGot;
  3570. WsbTraceIn(OLESTR("CHsmWorkQueue::CheckRegistry"), OLESTR(""));
  3571. try {
  3572. // Minimum files to migrate
  3573. WsbAffirmHr(WsbRegistryValueUlongAsString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_MIN_FILES_TO_MIGRATE,
  3574. &m_MinFilesToMigrate));
  3575. WsbTrace(OLESTR("CHsmWorkQueue::CheckRegistry: m_MinFilesToMigrate = %lu\n"),
  3576. m_MinFilesToMigrate);
  3577. // Minimum bytes to migrate
  3578. WsbAffirmHr(WsbRegistryValueUlongAsString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_MIN_BYTES_TO_MIGRATE,
  3579. &m_MinBytesToMigrate));
  3580. WsbTrace(OLESTR("CHsmWorkQueue::CheckRegistry: m_MinBytesToMigrate = %lu\n"),
  3581. m_MinBytesToMigrate);
  3582. // Minimum files before commit
  3583. WsbAffirmHr(WsbRegistryValueUlongAsString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_FILES_BEFORE_COMMIT,
  3584. &m_FilesBeforeCommit));
  3585. WsbTrace(OLESTR("CHsmWorkQueue::CheckRegistry: m_FilesBeforeCommit = %lu\n"),
  3586. m_FilesBeforeCommit);
  3587. // Maximum bytes before commit
  3588. WsbAffirmHr(WsbRegistryValueUlongAsString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_MAX_BYTES_BEFORE_COMMIT,
  3589. &m_MaxBytesBeforeCommit));
  3590. WsbTrace(OLESTR("CHsmWorkQueue::CheckRegistry: m_MaxBytesBeforeCommit = %lu\n"),
  3591. m_MaxBytesBeforeCommit);
  3592. // Minimum bytes before commit
  3593. WsbAffirmHr(WsbRegistryValueUlongAsString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_MIN_BYTES_BEFORE_COMMIT,
  3594. &m_MinBytesBeforeCommit));
  3595. WsbTrace(OLESTR("CHsmWorkQueue::CheckRegistry: m_MinBytesBeforeCommit = %lu\n"),
  3596. m_MinBytesBeforeCommit);
  3597. // Bytes to perserve at end of tape (This is really just for security, we shouldn't reach this threshold at all)
  3598. WsbAffirmHr(WsbRegistryValueUlongAsString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_MIN_BYTES_AT_END_OF_MEDIA,
  3599. &m_FreeMediaBytesAtEndOfMedia));
  3600. WsbTrace(OLESTR("CHsmWorkQueue::CheckRegistry: m_FreeMediaBytesAtEndOfMedia = %lu\n"),
  3601. m_FreeMediaBytesAtEndOfMedia);
  3602. // Minimum percent to preserve as free space in end of meida
  3603. WsbAffirmHr(WsbRegistryValueUlongAsString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_MIN_FREE_SPACE_IN_FULL_MEDIA,
  3604. &m_MinFreeSpaceInFullMedia));
  3605. if (m_MinFreeSpaceInFullMedia >= 100) {
  3606. m_MinFreeSpaceInFullMedia = MIN_FREE_SPACE_IN_FULL_MEDIA_DEFAULT;
  3607. }
  3608. WsbTrace(OLESTR("CHsmWorkQueue::CheckRegistry: m_MinFreeSpaceInFullMedia = %lu\n"),
  3609. m_MinFreeSpaceInFullMedia);
  3610. // Maximum percent to preserve as free space in end of meida
  3611. WsbAffirmHr(WsbRegistryValueUlongAsString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_MAX_FREE_SPACE_IN_FULL_MEDIA,
  3612. &m_MaxFreeSpaceInFullMedia));
  3613. if (m_MaxFreeSpaceInFullMedia >= 100) {
  3614. m_MaxFreeSpaceInFullMedia = MAX_FREE_SPACE_IN_FULL_MEDIA_DEFAULT;
  3615. }
  3616. WsbTrace(OLESTR("CHsmWorkQueue::CheckRegistry: m_MaxFreeSpaceInFullMedia = %lu\n"),
  3617. m_MaxFreeSpaceInFullMedia);
  3618. // Save DBs in dataset? (Note: registry value has opposite meaning!)
  3619. l_value = m_StoreDatabasesInBags ? 0 : 1;
  3620. WsbAffirmHr(WsbRegistryValueUlongAsString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_DONT_SAVE_DATABASES,
  3621. &l_value));
  3622. m_StoreDatabasesInBags = !l_value;
  3623. WsbTrace(OLESTR("CHsmWorkQueue::CheckRegistry: m_StoreDatabasesInBags = <%ls>\n"),
  3624. WsbBoolAsString(m_StoreDatabasesInBags));
  3625. // Queue length to pause scan
  3626. WsbAffirmHr(WsbRegistryValueUlongAsString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_QUEUE_ITEMS_TO_PAUSE,
  3627. &m_QueueItemsToPause));
  3628. WsbTrace(OLESTR("CHsmWorkQueue::CheckRegistry: m_QueueItemsToPause = %lu\n"),
  3629. m_QueueItemsToPause);
  3630. // Queue length to resume scan
  3631. WsbAffirmHr(WsbRegistryValueUlongAsString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_QUEUE_ITEMS_TO_RESUME,
  3632. &m_QueueItemsToResume));
  3633. WsbTrace(OLESTR("CHsmWorkQueue::CheckRegistry: m_QueueItemsToResume = %lu\n"),
  3634. m_QueueItemsToResume);
  3635. // See if the user defined a media base name to use
  3636. if (S_OK == WsbGetRegistryValueString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_MEDIA_BASE_NAME,
  3637. dataString, 100, &sizeGot)) {
  3638. m_MediaBaseName = dataString;
  3639. WsbTrace(OLESTR("CHsmWorkQueue::CheckRegistry: m_MediaBaseName = <%ls>\n"),
  3640. static_cast<OLECHAR *>(m_MediaBaseName));
  3641. }
  3642. // Check for change to number of errors to allow before cancelling
  3643. // a job
  3644. WsbAffirmHr(WsbRegistryValueUlongAsString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_JOB_ABORT_CONSECUTIVE_ERRORS,
  3645. &m_JobAbortMaxConsecutiveErrors));
  3646. WsbTrace(OLESTR("CHsmWorkQueue::CheckRegistry: m_JobAbortMaxConsecutiveErrors = %lu\n"),
  3647. m_JobAbortMaxConsecutiveErrors);
  3648. WsbAffirmHr(WsbRegistryValueUlongAsString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_JOB_ABORT_TOTAL_ERRORS,
  3649. &m_JobAbortMaxTotalErrors));
  3650. WsbTrace(OLESTR("CHsmWorkQueue::CheckRegistry: m_JobAbortMaxTotalErrors = %lu\n"),
  3651. m_JobAbortMaxTotalErrors);
  3652. // Check for amount of system disk space required for a manage job
  3653. WsbAffirmHr(WsbRegistryValueUlongAsString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_JOB_ABORT_SYS_DISK_SPACE,
  3654. &m_JobAbortSysDiskSpace));
  3655. WsbTrace(OLESTR("CHsmWorkQueue::CheckRegistry: m_JobAbortSysDiskSpace = %lu\n"),
  3656. m_JobAbortSysDiskSpace);
  3657. } WsbCatch( hr );
  3658. WsbTraceOut(OLESTR("CHsmWorkQueue::CheckRegistry"), OLESTR("hr = <%ls>"),
  3659. WsbHrAsString(hr));
  3660. return( hr );
  3661. }
  3662. HRESULT
  3663. CHsmWorkQueue::CheckForDiskSpace(void)
  3664. /*++
  3665. Routine Description:
  3666. Check system volume for sufficient space to complete a manage job.
  3667. Arguments:
  3668. None
  3669. Return Value:
  3670. S_OK - There is enough space
  3671. WSB_E_SYSTEM_DISK_FULL - There isn't enough space
  3672. E_* - Some error occurred
  3673. --*/
  3674. {
  3675. HRESULT hr = S_OK;
  3676. ULARGE_INTEGER FreeBytesAvailableToCaller;
  3677. ULARGE_INTEGER TotalNumberOfBytes;
  3678. ULARGE_INTEGER TotalNumberOfFreeBytes;
  3679. WsbTraceIn(OLESTR("CHsmWorkQueue::CheckForDiskSpace"), OLESTR(""));
  3680. if (GetDiskFreeSpaceEx(NULL, &FreeBytesAvailableToCaller,
  3681. &TotalNumberOfBytes, &TotalNumberOfFreeBytes)) {
  3682. if (FreeBytesAvailableToCaller.QuadPart < m_JobAbortSysDiskSpace) {
  3683. hr = WSB_E_SYSTEM_DISK_FULL;
  3684. }
  3685. } else {
  3686. hr = HRESULT_FROM_WIN32(GetLastError());
  3687. }
  3688. WsbTraceOut(OLESTR("CHsmWorkQueue::CheckForDiskSpace"), OLESTR("hr = <%ls>"),
  3689. WsbHrAsString(hr));
  3690. return( hr );
  3691. }
  3692. HRESULT
  3693. CHsmWorkQueue::CommitWork(void)
  3694. {
  3695. HRESULT hr = S_OK;
  3696. HRESULT hrComplete = S_OK;
  3697. HRESULT hrFlush = E_FAIL;
  3698. WsbTraceIn(OLESTR("CHsmWorkQueue::CommitWork"),OLESTR(""));
  3699. try {
  3700. LONGLONG lastByteWritten = -1;
  3701. ULONG numItems;
  3702. CWsbStringPtr path;
  3703. CComPtr<IHsmWorkItem> pWorkItem;
  3704. CComPtr<IFsaPostIt> pFsaWorkItem;
  3705. HSM_WORK_ITEM_TYPE workType;
  3706. BOOLEAN done = FALSE;
  3707. BOOL skipWork = FALSE;
  3708. // Do we actually have work to commit?
  3709. WsbAffirmHr(m_pWorkToCommit->GetEntries(&numItems));
  3710. if (0 == numItems) {
  3711. return(S_OK);
  3712. }
  3713. //
  3714. // We expect the data mover to be ready for work
  3715. //
  3716. WsbAffirm(m_pDataMover != 0, E_UNEXPECTED);
  3717. //
  3718. // If we never got a valid session going, we cannot
  3719. // commit the work. So check here to make sure the
  3720. // session is really established OK
  3721. if (S_OK == m_BeginSessionHr) {
  3722. CComPtr<IStream> pIStream;
  3723. ULARGE_INTEGER position;
  3724. LARGE_INTEGER zero = {0, 0};
  3725. // Force a flush of the buffers
  3726. //
  3727. hrFlush = m_pDataMover->FlushBuffers();
  3728. // Determine where we are on the tape
  3729. WsbAffirmHr(m_pDataMover->QueryInterface(IID_IStream,
  3730. (void **)&pIStream));
  3731. if (S_OK != pIStream->Seek(zero, STREAM_SEEK_END, &position)) {
  3732. // If we didn't get useful information
  3733. // about the amount of data written to media, we'll have
  3734. // to skip everything in the queue
  3735. skipWork = TRUE;
  3736. } else {
  3737. lastByteWritten = position.QuadPart;
  3738. }
  3739. } else {
  3740. // Skip all of the work - none of it gets committed
  3741. skipWork = TRUE;
  3742. }
  3743. WsbTrace(OLESTR("CHsmWorkQueue::CommitWork: hrFlush = <%ls>, lastByteWritten = %ls\n"),
  3744. WsbHrAsString(hrFlush), WsbLonglongAsString(lastByteWritten));
  3745. while ( (!done) && (S_OK == hr) ) {
  3746. //
  3747. // Get the next work item from the queue
  3748. //
  3749. hr = m_pWorkToCommit->First(IID_IHsmWorkItem, (void **)&pWorkItem);
  3750. if (hr == S_OK) {
  3751. //
  3752. // Find out about the work, should be FSA work
  3753. //
  3754. WsbAffirmHr(pWorkItem->GetWorkType(&workType));
  3755. if (HSM_WORK_ITEM_FSA_WORK == workType) {
  3756. try {
  3757. CComPtr<IFsaScanItem> pScanItem;
  3758. WsbAffirmHr(pWorkItem->GetFsaPostIt(&pFsaWorkItem));
  3759. WsbAffirmHr(GetScanItem(pFsaWorkItem, &pScanItem));
  3760. WsbAffirmHr(pFsaWorkItem->GetRequestAction(&m_RequestAction));
  3761. // If FlushBuffers failed, some items may not have
  3762. // gotten written to tape. This code assumes the items
  3763. // in the queue are in the same order they were written
  3764. // onto the media
  3765. if (!skipWork && S_OK != hrFlush) {
  3766. FSA_PLACEHOLDER placeholder;
  3767. WsbAffirmHr(pFsaWorkItem->GetPlaceholder(&placeholder));
  3768. if (((LONGLONG)m_RemoteDataSetStart.QuadPart + placeholder.fileStart +
  3769. placeholder.fileSize) > lastByteWritten) {
  3770. skipWork = TRUE;
  3771. }
  3772. }
  3773. (void) pFsaWorkItem->GetPath(&path, 0);
  3774. if (!skipWork) {
  3775. //
  3776. // Get the FSA Work Item and complete the work
  3777. //
  3778. hr = CompleteWorkItem(pWorkItem);
  3779. //
  3780. // Do the stats counts
  3781. //
  3782. (void)m_pSession->ProcessItem(m_JobPhase, m_JobAction,
  3783. pScanItem, hr);
  3784. //
  3785. // This is not a failure - change to OK
  3786. //
  3787. if ( FSA_E_REPARSE_NOT_WRITTEN_FILE_CHANGED == hr ) {
  3788. hr = S_OK;
  3789. }
  3790. //
  3791. // Quota error should be handled differently - we want to log only once
  3792. // and avoid abortint the job no matter how many such errors we got
  3793. //
  3794. if ( FSA_E_REPARSE_OWNER_PASS_QUOTA == hr ) {
  3795. if (! (m_uErrorReportFlags & QUEUE_REPORT_PASS_QUOTA_LIMIT_FLAG)) {
  3796. WsbLogEvent(HSM_MESSAGE_MANAGE_FAILED_USER_QUOTA,
  3797. 0, NULL, WsbAbbreviatePath(path, 120), NULL);
  3798. m_uErrorReportFlags |= QUEUE_REPORT_PASS_QUOTA_LIMIT_FLAG;
  3799. }
  3800. hr = S_OK;
  3801. }
  3802. //
  3803. // Replace to HSM specific error for some error codes
  3804. //
  3805. switch (HRESULT_CODE(hr)) {
  3806. case ERROR_LOCK_VIOLATION:
  3807. hr = HSM_E_FILE_LOCK_VIOLATION;
  3808. break;
  3809. case ERROR_SHARING_VIOLATION:
  3810. hr = HSM_E_FILE_SHARING_VIOLATION;
  3811. break;
  3812. }
  3813. if (S_OK != hr) {
  3814. // Tell the session how things went if they didn't go well.
  3815. (void) m_pSession->ProcessHr(m_JobPhase, 0, 0, hr);
  3816. }
  3817. // Check if the job needs to be canceled
  3818. if (S_OK != ShouldJobContinue(hr)) {
  3819. // Log a message if the disk is full
  3820. if (FSA_E_REPARSE_NOT_CREATED_DISK_FULL == hr) {
  3821. WsbLogEvent(HSM_MESSAGE_MANAGE_FAILED_DISK_FULL,
  3822. 0, NULL, WsbAbbreviatePath(path, 120), NULL);
  3823. }
  3824. hrComplete = hr;
  3825. skipWork = TRUE;
  3826. }
  3827. WsbAffirmHr(hr);
  3828. } else {
  3829. //
  3830. // Skip the work
  3831. //
  3832. WsbLogEvent(HSM_MESSAGE_WORK_SKIPPED_COMMIT_FAILED,
  3833. 0, NULL, WsbAbbreviatePath(path, 120),
  3834. WsbHrAsString(hr), NULL);
  3835. (void)m_pSession->ProcessItem(m_JobPhase,
  3836. m_JobAction, pScanItem,
  3837. HSM_E_WORK_SKIPPED_COMMIT_FAILED);
  3838. }
  3839. } WsbCatchAndDo(hr, hr = S_OK;);
  3840. (void)m_pWorkToCommit->RemoveAndRelease(pWorkItem);
  3841. } else {
  3842. //
  3843. // Found non fsa work - don't expect that!
  3844. //
  3845. ULONG tmp;
  3846. tmp = (ULONG)workType;
  3847. WsbTrace(OLESTR("Expecting FSA work, found <%lu>\n"), tmp);
  3848. hr = E_UNEXPECTED;
  3849. }
  3850. } else if (WSB_E_NOTFOUND == hr) {
  3851. // There are no more entries in the queue so we are done
  3852. done = TRUE;
  3853. hr = S_OK;
  3854. m_DataCountBeforeCommit = 0;
  3855. m_FilesCountBeforeCommit = 0;
  3856. }
  3857. pWorkItem = 0;
  3858. pFsaWorkItem = 0;
  3859. }
  3860. } WsbCatch(hr);
  3861. if (S_OK != hrFlush) {
  3862. FailJob();
  3863. }
  3864. if (S_OK != hrComplete) {
  3865. hr = hrComplete;
  3866. }
  3867. WsbTraceOut(OLESTR("CHsmWorkQueue::CommitWork"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  3868. return(hr);
  3869. }
  3870. HRESULT
  3871. CHsmWorkQueue::StartNewMedia(
  3872. IFsaPostIt *pFsaWorkItem
  3873. )
  3874. /*++
  3875. --*/
  3876. {
  3877. HRESULT hr = S_OK;
  3878. BOOL dummyBool;
  3879. CComPtr<IMediaInfo> pMediaInfo;
  3880. GUID storagePoolId;
  3881. WsbTraceIn(OLESTR("CHsmWorkQueue::StartNewMedia"),OLESTR(""));
  3882. try {
  3883. WsbAffirmHr(pFsaWorkItem->GetStoragePoolId(&storagePoolId));
  3884. WsbAffirmHr(GetMediaParameters());
  3885. WsbAffirmHr(m_pSegmentDb->GetEntity(m_pDbWorkSession, HSM_MEDIA_INFO_REC_TYPE, IID_IMediaInfo,
  3886. (void**)&pMediaInfo));
  3887. WsbAffirmHr(CoCreateGuid(&m_MediaId));
  3888. WsbAffirmHr(CoFileTimeNow(&m_MediaUpdate));
  3889. WsbAffirmHr(pMediaInfo->GetRecreate(&dummyBool));
  3890. WsbAffirmHr(pMediaInfo->SetMediaInfo(m_MediaId, m_MountedMedia, storagePoolId,
  3891. m_MediaFreeSpace, m_MediaCapacity, m_BadMedia,
  3892. 1, m_MediaName, m_MediaType,
  3893. m_MediaBarCode, m_MediaReadOnly, m_MediaUpdate,
  3894. 0, dummyBool));
  3895. WsbAffirmHr(pMediaInfo->MarkAsNew());
  3896. WsbAffirmHr(pMediaInfo->UpdateLastKnownGoodMaster());
  3897. WsbAffirmHr(pMediaInfo->Write());
  3898. } WsbCatch( hr );
  3899. WsbTraceOut(OLESTR("CHsmWorkQueue::StartNewMedia"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  3900. return(hr);
  3901. }
  3902. HRESULT
  3903. CHsmWorkQueue::StartNewSession( void )
  3904. /*++
  3905. --*/
  3906. {
  3907. HRESULT hr = S_OK;
  3908. HRESULT hrSession = S_OK;
  3909. CComPtr<IMediaInfo> pMediaInfo;
  3910. WsbTraceIn(OLESTR("CHsmWorkQueue::StartNewSession"),OLESTR(""));
  3911. try {
  3912. CWsbStringPtr strGuid;
  3913. CWsbBstrPtr sessionName = HSM_BAG_NAME;
  3914. WsbAffirmHr(WsbSafeGuidAsString(m_BagId, strGuid));
  3915. sessionName.Append(strGuid);
  3916. CWsbBstrPtr sessionDescription = HSM_ENGINE_ID;
  3917. WsbAffirmHr(WsbSafeGuidAsString(m_HsmId, strGuid));
  3918. sessionDescription.Append(strGuid);
  3919. //
  3920. // Find the media record to know the next remote data set
  3921. //
  3922. WsbAffirmHr(m_pSegmentDb->GetEntity(m_pDbWorkSession, HSM_MEDIA_INFO_REC_TYPE, IID_IMediaInfo,
  3923. (void**)&pMediaInfo));
  3924. WsbAffirmHr(pMediaInfo->SetId(m_MediaId));
  3925. WsbAffirmHr(pMediaInfo->FindEQ());
  3926. WsbAffirmHr(pMediaInfo->GetNextRemoteDataSet(&m_RemoteDataSet));
  3927. //
  3928. // Now call the data mover to begin a session. If this doesn't work then
  3929. // we want to mark the media as read only so that we will not overwrite
  3930. // data.
  3931. //
  3932. m_BeginSessionHr = m_pDataMover->BeginSession(sessionName, sessionDescription, m_RemoteDataSet, MVR_SESSION_AS_LAST_DATA_SET);
  3933. if (S_OK != m_BeginSessionHr) {
  3934. try {
  3935. //
  3936. // Check the reason for the failure of the begin session. If it is
  3937. // MVR_E_DATA_SET_MISSING then the last begin session actually failed when
  3938. // it was committed. So, let's decrement the remote data set count and
  3939. // redo the begin session that failed.
  3940. //
  3941. if (MVR_E_DATA_SET_MISSING == m_BeginSessionHr) {
  3942. m_RemoteDataSet--;
  3943. //
  3944. // Try again...
  3945. m_BeginSessionHr = m_pDataMover->BeginSession(sessionName, sessionDescription, m_RemoteDataSet, MVR_SESSION_OVERWRITE_DATA_SET);
  3946. //
  3947. // !!! IMPORTANT NOTE !!!
  3948. //
  3949. // Update the media info to reflect new RemoteDataSet count.
  3950. // This will also correct any out of sync copies.
  3951. WsbAffirmHr(pMediaInfo->SetNextRemoteDataSet(m_RemoteDataSet));
  3952. }
  3953. switch (m_BeginSessionHr) {
  3954. case S_OK:
  3955. case MVR_E_BUS_RESET:
  3956. case MVR_E_MEDIA_CHANGED:
  3957. case MVR_E_NO_MEDIA_IN_DRIVE:
  3958. case MVR_E_DEVICE_REQUIRES_CLEANING:
  3959. case MVR_E_SHARING_VIOLATION:
  3960. case MVR_E_ERROR_IO_DEVICE:
  3961. case MVR_E_ERROR_DEVICE_NOT_CONNECTED:
  3962. case MVR_E_ERROR_NOT_READY:
  3963. break;
  3964. case MVR_E_INVALID_BLOCK_LENGTH:
  3965. case MVR_E_WRITE_PROTECT:
  3966. case MVR_E_CRC:
  3967. default:
  3968. // Note the error
  3969. WsbAffirmHr(pMediaInfo->SetLastError(m_BeginSessionHr));
  3970. // Mark media as read only
  3971. m_MediaReadOnly = TRUE;
  3972. WsbAffirmHr(pMediaInfo->SetRecallOnlyStatus(m_MediaReadOnly));
  3973. // Write this out
  3974. WsbAffirmHr(pMediaInfo->Write());
  3975. break;
  3976. }
  3977. } WsbCatch( hrSession );
  3978. }
  3979. // If the BeginSession() failed, skip everything else.
  3980. WsbAffirmHr(m_BeginSessionHr);
  3981. //
  3982. // Up the count of the remote data set and write it out
  3983. m_RemoteDataSet++;
  3984. WsbAffirmHr(pMediaInfo->SetNextRemoteDataSet(m_RemoteDataSet));
  3985. // Write all of this out
  3986. WsbAffirmHr(pMediaInfo->Write());
  3987. //
  3988. // Now set the Bag remote data set value
  3989. //
  3990. HSM_BAG_STATUS l_BagStatus;
  3991. LONGLONG l_BagLen;
  3992. USHORT l_BagType;
  3993. FILETIME l_BirthDate;
  3994. LONGLONG l_DeletedBagAmount;
  3995. SHORT l_RemoteDataSet;
  3996. GUID l_BagVolId;
  3997. GUID l_BagId;
  3998. CComPtr<IBagInfo> pBagInfo;
  3999. WsbAffirmHr(m_pSegmentDb->GetEntity(m_pDbWorkSession, HSM_BAG_INFO_REC_TYPE, IID_IBagInfo,
  4000. (void**)&pBagInfo));
  4001. GetSystemTimeAsFileTime(&l_BirthDate);
  4002. WsbAffirmHr(pBagInfo->SetBagInfo(HSM_BAG_STATUS_IN_PROGRESS, m_BagId, l_BirthDate,
  4003. 0, 0, GUID_NULL, 0, 0 ));
  4004. WsbAffirmHr(pBagInfo->FindEQ());
  4005. WsbAffirmHr(pBagInfo->GetBagInfo(&l_BagStatus, &l_BagId, &l_BirthDate,
  4006. &l_BagLen, &l_BagType, &l_BagVolId, &l_DeletedBagAmount, &l_RemoteDataSet ));
  4007. WsbAffirmHr(pBagInfo->SetBagInfo(l_BagStatus, l_BagId, l_BirthDate,
  4008. l_BagLen, l_BagType, l_BagVolId, l_DeletedBagAmount, (SHORT)(m_RemoteDataSet - 1)));
  4009. WsbAffirmHr(pBagInfo->Write());
  4010. // Reset error counts
  4011. m_JobConsecutiveErrors = 0;
  4012. m_JobTotalErrors = 0;
  4013. } WsbCatchAndDo(hr,
  4014. FailJob();
  4015. );
  4016. WsbTraceOut(OLESTR("CHsmWorkQueue::StartNewSession"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  4017. return(hr);
  4018. }
  4019. HRESULT
  4020. CHsmWorkQueue::TranslateRmsMountHr(
  4021. HRESULT rmsMountHr
  4022. )
  4023. /*++
  4024. --*/
  4025. {
  4026. HRESULT hr = S_OK;
  4027. WsbTraceIn(OLESTR("CHsmWorkQueue::TranslateRmsMountHr"),OLESTR("rms hr = <%ls>"), WsbHrAsString(rmsMountHr));
  4028. try {
  4029. switch (rmsMountHr) {
  4030. case S_OK:
  4031. hr = S_OK;
  4032. ReportMediaProgress(HSM_JOB_MEDIA_STATE_MOUNTED, hr);
  4033. break;
  4034. case RMS_E_MEDIASET_NOT_FOUND:
  4035. if (m_RmsMediaSetId == GUID_NULL) {
  4036. hr = HSM_E_STG_PL_NOT_CFGD;
  4037. } else {
  4038. hr = HSM_E_STG_PL_INVALID;
  4039. }
  4040. ReportMediaProgress(HSM_JOB_MEDIA_STATE_UNAVAILABLE, hr);
  4041. break;
  4042. case RMS_E_SCRATCH_NOT_FOUND:
  4043. hr = HSM_E_NO_MORE_MEDIA;
  4044. ReportMediaProgress(HSM_JOB_MEDIA_STATE_UNAVAILABLE, hr);
  4045. break;
  4046. case RMS_E_SCRATCH_NOT_FOUND_FINAL:
  4047. hr = HSM_E_NO_MORE_MEDIA_FINAL;
  4048. ReportMediaProgress(HSM_JOB_MEDIA_STATE_UNAVAILABLE, hr);
  4049. break;
  4050. case RMS_E_SCRATCH_NOT_FOUND_TOO_SMALL:
  4051. hr = HSM_E_WORK_SKIPPED_FILE_TOO_BIG;
  4052. ReportMediaProgress(HSM_JOB_MEDIA_STATE_UNAVAILABLE, hr);
  4053. break;
  4054. case RMS_E_CARTRIDGE_UNAVAILABLE:
  4055. case RMS_E_RESOURCE_UNAVAILABLE:
  4056. case RMS_E_DRIVE_UNAVAILABLE:
  4057. case RMS_E_LIBRARY_UNAVAILABLE:
  4058. hr = HSM_E_MEDIA_NOT_AVAILABLE;
  4059. ReportMediaProgress(HSM_JOB_MEDIA_STATE_UNAVAILABLE, hr);
  4060. break;
  4061. case RMS_E_CARTRIDGE_BUSY:
  4062. case RMS_E_RESOURCE_BUSY:
  4063. case RMS_E_DRIVE_BUSY:
  4064. hr = HSM_E_MEDIA_BUSY;
  4065. ReportMediaProgress(HSM_JOB_MEDIA_STATE_BUSY, hr);
  4066. break;
  4067. case RMS_E_CARTRIDGE_NOT_FOUND:
  4068. case RMS_E_CARTRIDGE_DISABLED:
  4069. case RMS_E_TIMEOUT:
  4070. case RMS_E_CANCELLED:
  4071. case ERROR_REQUEST_REFUSED:
  4072. hr = rmsMountHr;
  4073. ReportMediaProgress(HSM_JOB_MEDIA_STATE_UNAVAILABLE, hr);
  4074. break;
  4075. case WSB_E_BAD_MEDIA:
  4076. case WSB_E_WRITE_PROTECTED:
  4077. case WSB_E_CANT_LOCK:
  4078. case WSB_E_BAD_LABEL:
  4079. case WSB_E_CANT_QUICK_FORMAT:
  4080. case WSB_E_IO_ERROR:
  4081. case WSB_E_VOLUME_TOO_SMALL:
  4082. case WSB_E_VOLUME_TOO_BIG:
  4083. case WSB_E_FORMAT_FAILED:
  4084. hr = rmsMountHr;
  4085. ReportMediaProgress(HSM_JOB_MEDIA_STATE_FAILED, hr);
  4086. break;
  4087. default:
  4088. hr = rmsMountHr;
  4089. (void) m_pSession->ProcessHr(m_JobPhase, __FILE__, __LINE__, rmsMountHr);
  4090. ReportMediaProgress(HSM_JOB_MEDIA_STATE_UNAVAILABLE, hr);
  4091. break;
  4092. }
  4093. } WsbCatch( hr );
  4094. WsbTraceOut(OLESTR("CHsmWorkQueue::TranslateRmsMountHr"),
  4095. OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  4096. return(hr);
  4097. }
  4098. HRESULT
  4099. CHsmWorkQueue::StoreDatabasesOnMedia( void )
  4100. /*++
  4101. --*/
  4102. {
  4103. HRESULT hr = S_OK;
  4104. WsbTraceIn(OLESTR("CHsmWorkQueue::StoreDatabasesOnMedia"),OLESTR(""));
  4105. try {
  4106. //
  4107. // For ultimate disaster recovery, write some files to media. We want
  4108. // to save the engine metadata and collection, the rms colleciton, NTMS
  4109. // data and the fsa collection if it exists.
  4110. //
  4111. ULARGE_INTEGER remoteDataSetStart;
  4112. ULARGE_INTEGER remoteFileStart;
  4113. ULARGE_INTEGER remoteFileSize;
  4114. ULARGE_INTEGER remoteDataStart;
  4115. ULARGE_INTEGER remoteDataSize;
  4116. ULARGE_INTEGER remoteVerificationData;
  4117. ULONG remoteVerificationType;
  4118. ULARGE_INTEGER dataStreamCRC;
  4119. ULONG dataStreamCRCType;
  4120. ULARGE_INTEGER usn;
  4121. ULARGE_INTEGER localDataSize;
  4122. ULARGE_INTEGER localDataStart;
  4123. HANDLE handle = INVALID_HANDLE_VALUE;
  4124. WIN32_FIND_DATA findData;
  4125. CWsbStringPtr localName;
  4126. CWsbBstrPtr bStrLocalName;
  4127. CWsbStringPtr rootName;
  4128. BOOL foundFile = TRUE;
  4129. BOOL bFullMessage = TRUE;
  4130. LONG mediaType;
  4131. BOOL bNewSession = FALSE;
  4132. //
  4133. // Force a save of the persistent databases
  4134. // We are not doing FSA here
  4135. //
  4136. try {
  4137. hr = m_pRmsServer->SaveAll();
  4138. hr = m_pServer->SavePersistData();
  4139. } WsbCatch( hr );
  4140. //
  4141. // In case of direct-access media, we terminate the Mover Session and open
  4142. // an additional special metadata session
  4143. WsbAssert(m_pRmsCartridge != 0, E_UNEXPECTED);
  4144. WsbAffirmHr(m_pRmsCartridge->GetType(&mediaType));
  4145. switch (mediaType) {
  4146. case RmsMediaOptical:
  4147. case RmsMediaFixed:
  4148. case RmsMediaDVD:
  4149. bNewSession = TRUE;
  4150. break;
  4151. default:
  4152. bNewSession = FALSE;
  4153. break;
  4154. }
  4155. if (bNewSession) {
  4156. // End current session
  4157. m_BeginSessionHr = S_FALSE;
  4158. WsbAffirmHr(m_pDataMover->EndSession());
  4159. // Start a new one
  4160. CWsbBstrPtr sessionName = HSM_METADATA_NAME;
  4161. CWsbStringPtr strGuid;
  4162. CWsbBstrPtr sessionDescription = HSM_ENGINE_ID;
  4163. WsbAffirmHr(WsbSafeGuidAsString(m_HsmId, strGuid));
  4164. sessionDescription.Append(strGuid);
  4165. m_BeginSessionHr = m_pDataMover->BeginSession(
  4166. sessionName,
  4167. sessionDescription,
  4168. 0,
  4169. MVR_SESSION_METADATA | MVR_SESSION_AS_LAST_DATA_SET);
  4170. if (S_OK != m_BeginSessionHr) {
  4171. HRESULT hrSession = S_OK;
  4172. CComPtr<IMediaInfo> pMediaInfo;
  4173. try {
  4174. // Check the error (some errors requires marking the media is Read Only
  4175. switch (m_BeginSessionHr) {
  4176. case S_OK:
  4177. case MVR_E_BUS_RESET:
  4178. case MVR_E_MEDIA_CHANGED:
  4179. case MVR_E_NO_MEDIA_IN_DRIVE:
  4180. case MVR_E_DEVICE_REQUIRES_CLEANING:
  4181. case MVR_E_SHARING_VIOLATION:
  4182. case MVR_E_ERROR_IO_DEVICE:
  4183. case MVR_E_ERROR_DEVICE_NOT_CONNECTED:
  4184. case MVR_E_ERROR_NOT_READY:
  4185. break;
  4186. case MVR_E_INVALID_BLOCK_LENGTH:
  4187. case MVR_E_WRITE_PROTECT:
  4188. case MVR_E_CRC:
  4189. default:
  4190. // Get the media record
  4191. WsbAffirmHr(m_pSegmentDb->GetEntity(m_pDbWorkSession, HSM_MEDIA_INFO_REC_TYPE,
  4192. IID_IMediaInfo, (void**)&pMediaInfo));
  4193. WsbAffirmHr(pMediaInfo->SetId(m_MediaId));
  4194. WsbAffirmHr(pMediaInfo->FindEQ());
  4195. // Note the error
  4196. WsbAffirmHr(pMediaInfo->SetLastError(m_BeginSessionHr));
  4197. // Mark media as read only
  4198. m_MediaReadOnly = TRUE;
  4199. WsbAffirmHr(pMediaInfo->SetRecallOnlyStatus(m_MediaReadOnly));
  4200. // Write this out
  4201. WsbAffirmHr(pMediaInfo->Write());
  4202. break;
  4203. }
  4204. } WsbCatch( hrSession );
  4205. } // end if BeginSession error
  4206. WsbAffirmHr(m_BeginSessionHr);
  4207. } // end if new mover session
  4208. //
  4209. // Start at the beginning of all files
  4210. //
  4211. localDataStart.LowPart = 0;
  4212. localDataStart.HighPart = 0;
  4213. //
  4214. // First go the the remote storage and save the collections
  4215. //
  4216. try {
  4217. // Get the name of the file
  4218. WsbAffirmHr(m_pServer->GetDbPath(&rootName, 0));
  4219. WsbAffirmHr(rootName.Append(OLESTR("\\")));
  4220. localName = rootName;
  4221. WsbAffirmHr(localName.Append(OLESTR("Rs*.bak")));
  4222. // Find out the file(s)
  4223. handle = FindFirstFile(localName, &findData);
  4224. localName = rootName;
  4225. WsbAffirmHr(localName.Append((OLECHAR *)(findData.cFileName)));
  4226. // Copy each file to tape
  4227. while ((INVALID_HANDLE_VALUE != handle) && (foundFile == TRUE)) {
  4228. if ((FILE_ATTRIBUTE_DIRECTORY & findData.dwFileAttributes) != FILE_ATTRIBUTE_DIRECTORY) {
  4229. localDataSize.LowPart = findData.nFileSizeLow;
  4230. localDataSize.HighPart = findData.nFileSizeHigh;
  4231. bStrLocalName = localName;
  4232. hr = StoreDataWithRetry( bStrLocalName,
  4233. localDataStart,
  4234. localDataSize,
  4235. MVR_FLAG_BACKUP_SEMANTICS,
  4236. &remoteDataSetStart,
  4237. &remoteFileStart,
  4238. &remoteFileSize,
  4239. &remoteDataStart,
  4240. &remoteDataSize,
  4241. &remoteVerificationType,
  4242. &remoteVerificationData,
  4243. &dataStreamCRCType,
  4244. &dataStreamCRC,
  4245. &usn,
  4246. &bFullMessage);
  4247. }
  4248. foundFile = FindNextFile(handle, &findData);
  4249. localName = rootName;
  4250. WsbAffirmHr(localName.Append((OLECHAR *)(findData.cFileName)));
  4251. }
  4252. } WsbCatch(hr);
  4253. if ( INVALID_HANDLE_VALUE != handle ) {
  4254. FindClose(handle);
  4255. handle = INVALID_HANDLE_VALUE;
  4256. }
  4257. //
  4258. // Next save the hsm metadata
  4259. //
  4260. try {
  4261. //
  4262. // First backup the databases since the backup files
  4263. // are the ones that are saved.
  4264. //
  4265. WsbAffirmHr(m_pServer->BackupSegmentDb());
  4266. // Create the search path
  4267. localName = "";
  4268. WsbAffirmHr(m_pServer->GetIDbPath(&rootName, 0));
  4269. WsbAffirmHr(rootName.Append(OLESTR(".bak\\")));
  4270. localName = rootName;
  4271. WsbAffirmHr(localName.Append(OLESTR("*.*")));
  4272. // Find the first file
  4273. handle = FindFirstFile(localName, &findData);
  4274. localName = rootName;
  4275. WsbAffirmHr(localName.Append((OLECHAR *)(findData.cFileName)));
  4276. // Copy each file to tape
  4277. foundFile = TRUE;
  4278. while ((INVALID_HANDLE_VALUE != handle) && (foundFile == TRUE)) {
  4279. if ((FILE_ATTRIBUTE_DIRECTORY & findData.dwFileAttributes) != FILE_ATTRIBUTE_DIRECTORY) {
  4280. localDataSize.LowPart = findData.nFileSizeLow;
  4281. localDataSize.HighPart = findData.nFileSizeHigh;
  4282. bStrLocalName = localName;
  4283. hr = StoreDataWithRetry( bStrLocalName,
  4284. localDataStart,
  4285. localDataSize,
  4286. MVR_FLAG_BACKUP_SEMANTICS,
  4287. &remoteDataSetStart,
  4288. &remoteFileStart,
  4289. &remoteFileSize,
  4290. &remoteDataStart,
  4291. &remoteDataSize,
  4292. &remoteVerificationType,
  4293. &remoteVerificationData,
  4294. &dataStreamCRCType,
  4295. &dataStreamCRC,
  4296. &usn,
  4297. &bFullMessage);
  4298. }
  4299. foundFile = FindNextFile(handle, &findData);
  4300. localName = rootName;
  4301. WsbAffirmHr(localName.Append((OLECHAR *)(findData.cFileName)));
  4302. }
  4303. } WsbCatch(hr);
  4304. if ( INVALID_HANDLE_VALUE != handle ) {
  4305. FindClose(handle);
  4306. handle = INVALID_HANDLE_VALUE;
  4307. }
  4308. //
  4309. // Next go the the NTMS databases and save them
  4310. //
  4311. try {
  4312. DWORD sizeGot;
  4313. //
  4314. // NTMS saves databases in a subdirectory parallel to the
  4315. // RemoteStorage subdirectory. So go there and just take
  4316. // the necessary files.
  4317. //
  4318. localName = "";
  4319. WsbAffirmHr(localName.Realloc(1024));
  4320. //
  4321. // Use the relocatable meta-data path if it's available,
  4322. // otherwise default to the %SystemRoot%\System32\RemoteStorage
  4323. //
  4324. hr = WsbGetRegistryValueString(NULL, WSB_RSM_CONTROL_REGISTRY_KEY, WSB_RSM_METADATA_REGISTRY_VALUE, localName, 256, &sizeGot);
  4325. if (hr == S_OK) {
  4326. WsbAffirmHr(localName.Append(OLESTR("NtmsData\\NTMSDATA.BAK")));
  4327. } else {
  4328. WsbAffirmHr(WsbEnsureRegistryKeyExists(NULL, WSB_CURRENT_VERSION_REGISTRY_KEY));
  4329. WsbAffirmHr(WsbGetRegistryValueString(NULL, WSB_CURRENT_VERSION_REGISTRY_KEY, WSB_SYSTEM_ROOT_REGISTRY_VALUE, localName, 256, &sizeGot));
  4330. WsbAffirmHr(localName.Append(OLESTR("\\system32\\NtmsData\\NTMSDATA.BAK")));
  4331. }
  4332. // Find the first one
  4333. handle = FindFirstFile(localName, &findData);
  4334. // Copy each file to tape
  4335. if (INVALID_HANDLE_VALUE != handle) {
  4336. localDataSize.LowPart = findData.nFileSizeLow;
  4337. localDataSize.HighPart = findData.nFileSizeHigh;
  4338. bStrLocalName = localName;
  4339. hr = StoreDataWithRetry( bStrLocalName,
  4340. localDataStart,
  4341. localDataSize,
  4342. MVR_FLAG_BACKUP_SEMANTICS,
  4343. &remoteDataSetStart,
  4344. &remoteFileStart,
  4345. &remoteFileSize,
  4346. &remoteDataStart,
  4347. &remoteDataSize,
  4348. &remoteVerificationType,
  4349. &remoteVerificationData,
  4350. &dataStreamCRCType,
  4351. &dataStreamCRC,
  4352. &usn,
  4353. &bFullMessage);
  4354. }
  4355. } WsbCatch(hr);
  4356. if ( INVALID_HANDLE_VALUE != handle ) {
  4357. FindClose(handle);
  4358. handle = INVALID_HANDLE_VALUE;
  4359. }
  4360. //
  4361. // Next save the NTMS Export files.
  4362. //
  4363. try {
  4364. DWORD sizeGot;
  4365. //
  4366. // NTMS saves Export files in the EXPORT directory. We take
  4367. // all the files in this dir. StoreData does the findFirst for us.
  4368. //
  4369. localName = "";
  4370. WsbAffirmHr(localName.Realloc(256));
  4371. WsbAffirmHr(WsbEnsureRegistryKeyExists(NULL, WSB_CURRENT_VERSION_REGISTRY_KEY));
  4372. WsbAffirmHr(WsbGetRegistryValueString(NULL, WSB_CURRENT_VERSION_REGISTRY_KEY, WSB_SYSTEM_ROOT_REGISTRY_VALUE, localName, 256, &sizeGot));
  4373. WsbAffirmHr(localName.Append(OLESTR("\\system32\\NtmsData\\Export\\*.*")));
  4374. bStrLocalName = localName;
  4375. localDataStart.QuadPart = 0;
  4376. localDataSize.QuadPart = 0;
  4377. hr = StoreDataWithRetry( bStrLocalName,
  4378. localDataStart,
  4379. localDataSize,
  4380. MVR_FLAG_BACKUP_SEMANTICS,
  4381. &remoteDataSetStart,
  4382. &remoteFileStart,
  4383. &remoteFileSize,
  4384. &remoteDataStart,
  4385. &remoteDataSize,
  4386. &remoteVerificationType,
  4387. &remoteVerificationData,
  4388. &dataStreamCRCType,
  4389. &dataStreamCRC,
  4390. &usn,
  4391. &bFullMessage);
  4392. } WsbCatch(hr);
  4393. } WsbCatch(hr);
  4394. //
  4395. // Whatever happens, return OK
  4396. //
  4397. hr = S_OK;
  4398. WsbTraceOut(OLESTR("CHsmWorkQueue::StoreDatabasesOnMedia"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  4399. return(hr);
  4400. }
  4401. HRESULT
  4402. CHsmWorkQueue::StoreDataWithRetry(
  4403. IN BSTR localName,
  4404. IN ULARGE_INTEGER localDataStart,
  4405. IN ULARGE_INTEGER localDataSize,
  4406. IN DWORD flags,
  4407. OUT ULARGE_INTEGER *pRemoteDataSetStart,
  4408. OUT ULARGE_INTEGER *pRemoteFileStart,
  4409. OUT ULARGE_INTEGER *pRemoteFileSize,
  4410. OUT ULARGE_INTEGER *pRemoteDataStart,
  4411. OUT ULARGE_INTEGER *pRemoteDataSize,
  4412. OUT DWORD *pRemoteVerificationType,
  4413. OUT ULARGE_INTEGER *pRemoteVerificationData,
  4414. OUT DWORD *pDatastreamCRCType,
  4415. OUT ULARGE_INTEGER *pDatastreamCRC,
  4416. OUT ULARGE_INTEGER *pUsn,
  4417. OUT BOOL *bFullMessage
  4418. )
  4419. /*++
  4420. Routine Description:
  4421. Calls StoreData with retries in case the file to write from is in use.
  4422. Arguments:
  4423. Same as StoreData
  4424. Return Value:
  4425. From StoreData
  4426. --*/
  4427. {
  4428. #define MAX_STOREDATA_RETRIES 3
  4429. HRESULT hr = S_OK;
  4430. LONG RetryCount = 0;
  4431. WsbTraceIn(OLESTR("CHsmWorkQueue::StoreDataWithRetry"), OLESTR("file <%ls>"),
  4432. static_cast<OLECHAR *>(localName));
  4433. for (RetryCount = 0; (RetryCount < MAX_STOREDATA_RETRIES) && (hr != E_ABORT) && (hr != MVR_E_MEDIA_ABORT); RetryCount++) {
  4434. if (RetryCount > 0) {
  4435. WsbLogEvent(HSM_MESSAGE_DATABASE_FILE_COPY_RETRY, 0, NULL,
  4436. WsbAbbreviatePath((WCHAR *) localName, 120), NULL);
  4437. }
  4438. // Make sure data mover is ready for work.
  4439. WsbAffirmPointer(m_pDataMover);
  4440. hr = m_pDataMover->StoreData(localName, localDataStart, localDataSize,
  4441. flags, pRemoteDataSetStart, pRemoteFileStart, pRemoteFileSize,
  4442. pRemoteDataStart, pRemoteDataSize, pRemoteVerificationType,
  4443. pRemoteVerificationData, pDatastreamCRCType, pDatastreamCRC,
  4444. pUsn);
  4445. WsbTrace(OLESTR("CHsmWorkQueue::StoreDataWithRetry: StoreData hr = <%ls>\n"),
  4446. WsbHrAsString(hr) );
  4447. if (S_OK == hr) break;
  4448. Sleep(1000);
  4449. }
  4450. if (hr != S_OK) {
  4451. if (*bFullMessage) {
  4452. WsbLogEvent(HSM_MESSAGE_GENERAL_DATABASE_FILE_NOT_COPIED, 0, NULL, WsbHrAsString(hr), NULL);
  4453. *bFullMessage = FALSE;
  4454. }
  4455. WsbLogEvent(HSM_MESSAGE_DATABASE_FILE_NOT_COPIED, 0, NULL,
  4456. WsbAbbreviatePath((WCHAR *) localName, 120), WsbHrAsString(hr), NULL);
  4457. }
  4458. WsbTraceOut(OLESTR("CHsmWorkQueue::StoreDataWithRetry"), OLESTR("hr = <%ls>"),
  4459. WsbHrAsString(hr) );
  4460. return(hr);
  4461. }
  4462. HRESULT
  4463. CHsmWorkQueue::ShouldJobContinue(
  4464. HRESULT problemHr
  4465. )
  4466. /*++
  4467. Implements:
  4468. CHsmWorkQueue::ShouldJobContinue().
  4469. --*/
  4470. {
  4471. HRESULT hr = S_OK;
  4472. WsbTraceIn(OLESTR("CHsmWorkQueue::ShouldJobContinue"), OLESTR("<%ls>"), WsbHrAsString(problemHr));
  4473. try {
  4474. // Collect some error counts and check if we've had too many
  4475. if (S_OK == problemHr) {
  4476. // Reset consecutive error count
  4477. m_JobConsecutiveErrors = 0;
  4478. } else {
  4479. m_JobConsecutiveErrors++;
  4480. m_JobTotalErrors++;
  4481. if (m_JobConsecutiveErrors >= m_JobAbortMaxConsecutiveErrors) {
  4482. WsbLogEvent(HSM_MESSAGE_TOO_MANY_CONSECUTIVE_JOB_ERRORS,
  4483. 0, NULL, WsbLongAsString(m_JobConsecutiveErrors), NULL);
  4484. hr = S_FALSE;
  4485. } else if (m_JobTotalErrors >= m_JobAbortMaxTotalErrors) {
  4486. WsbLogEvent(HSM_MESSAGE_TOO_MANY_TOTAL_JOB_ERRORS,
  4487. 0, NULL, WsbLongAsString(m_JobTotalErrors), NULL);
  4488. hr = S_FALSE;
  4489. }
  4490. }
  4491. //
  4492. // Evaluate the input HR to decide if we should try to continue with the job or if
  4493. // we should abandon the job because the problem is not recoverable.
  4494. //
  4495. if (S_OK == hr) {
  4496. switch (problemHr) {
  4497. case E_ABORT:
  4498. case MVR_E_MEDIA_ABORT:
  4499. case FSA_E_REPARSE_NOT_CREATED_DISK_FULL:
  4500. case WSB_E_SYSTEM_DISK_FULL:
  4501. //
  4502. // we want to cancel the job
  4503. //
  4504. hr = S_FALSE;
  4505. break;
  4506. default:
  4507. // Be optimistic and try to keep going
  4508. hr = S_OK;
  4509. break;
  4510. }
  4511. }
  4512. // Abort the job if necessary
  4513. if (S_FALSE == hr) {
  4514. WsbAffirmHr(FailJob());
  4515. }
  4516. } WsbCatch(hr);
  4517. WsbTraceOut(OLESTR("CHsmWorkQueue::ShouldJobContinue"), OLESTR("hr = <%ls>"), WsbHrAsString(hr) );
  4518. return(hr);
  4519. }
  4520. HRESULT
  4521. CHsmWorkQueue::Remove(
  4522. IHsmWorkItem *pWorkItem
  4523. )
  4524. /*++
  4525. Implements:
  4526. IHsmFsaTskMgr::Remove
  4527. --*/
  4528. {
  4529. HRESULT hr = S_OK;
  4530. WsbTraceIn(OLESTR("CHsmWorkQueue::Remove"),OLESTR(""));
  4531. try {
  4532. //
  4533. // Remove the item from the queue and see if we need to
  4534. // resume the scanner (if it is paused)
  4535. //
  4536. (void)m_pWorkToDo->RemoveAndRelease(pWorkItem);
  4537. ULONG numItems;
  4538. WsbAffirmHr(m_pWorkToDo->GetEntries(&numItems));
  4539. WsbTrace(OLESTR("CHsmWorkQueue::Remove - num items in queue = <%lu>\n"),numItems);
  4540. if (numItems <= m_QueueItemsToResume) {
  4541. WsbAffirmHr(ResumeScanner());
  4542. }
  4543. } WsbCatch (hr);
  4544. WsbTraceOut(OLESTR("CHsmWorkQueue::Remove"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  4545. return (hr);
  4546. }
  4547. HRESULT
  4548. CHsmWorkQueue::ChangeSysState(
  4549. IN OUT HSM_SYSTEM_STATE* pSysState
  4550. )
  4551. /*++
  4552. Implements:
  4553. IHsmSystemState::ChangeSysState().
  4554. --*/
  4555. {
  4556. HRESULT hr = S_OK;
  4557. WsbTraceIn(OLESTR("CHsmWorkQueue::ChangeSysState"), OLESTR(""));
  4558. try {
  4559. if (pSysState->State & HSM_STATE_SUSPEND) {
  4560. // Should have already been paused via the job
  4561. } else if (pSysState->State & HSM_STATE_RESUME) {
  4562. // Should have already been resumed via the job
  4563. } else if (pSysState->State & HSM_STATE_SHUTDOWN) {
  4564. // Release the thread (we assume it has been stopped already)
  4565. if (m_WorkerThread) {
  4566. CloseHandle(m_WorkerThread);
  4567. m_WorkerThread = 0;
  4568. }
  4569. if (m_pDataMover) {
  4570. //
  4571. // Cancel any active I/O
  4572. //
  4573. (void) m_pDataMover->Cancel();
  4574. }
  4575. // If Session is valid - unadvise and free session, otherwise, just try to
  4576. // dismount media if it is mounted (which we don't know at this point)
  4577. // Best effort dismount, no error checking so following resources will get released.
  4578. if (m_pSession != 0) {
  4579. EndSessions(FALSE, TRUE);
  4580. } else {
  4581. (void) DismountMedia(TRUE);
  4582. }
  4583. }
  4584. } WsbCatch(hr);
  4585. WsbTraceOut(OLESTR("CHsmWorkQueue::ChangeSysState"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  4586. return(hr);
  4587. }
  4588. HRESULT
  4589. CHsmWorkQueue::UnsetMediaInfo( void )
  4590. /*++
  4591. Routine Description:
  4592. Sets the media data members back to their default (unset) values.
  4593. Arguments:
  4594. None.
  4595. Return Value:
  4596. S_OK: Ok.
  4597. --*/
  4598. {
  4599. HRESULT hr = S_OK;
  4600. WsbTraceIn(OLESTR("CHsmWorkQueue::UnsetMediaInfo"), OLESTR(""));
  4601. m_MediaId = GUID_NULL;
  4602. m_MountedMedia = GUID_NULL;
  4603. m_MediaType = HSM_JOB_MEDIA_TYPE_UNKNOWN;
  4604. m_MediaName = OLESTR("");
  4605. m_MediaBarCode = OLESTR("");
  4606. m_MediaFreeSpace = 0;
  4607. m_MediaCapacity = 0;
  4608. m_MediaReadOnly = FALSE;
  4609. m_MediaUpdate = WsbLLtoFT(0);
  4610. m_BadMedia = S_OK;
  4611. m_RemoteDataSetStart.QuadPart = 0;
  4612. m_RemoteDataSet = 0;
  4613. WsbTraceOut(OLESTR("CHsmWorkQueue::UnsetMediaInfo"), OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  4614. return(hr);
  4615. }
  4616. HRESULT
  4617. CHsmWorkQueue::UpdateMediaFreeSpace( void )
  4618. /*++
  4619. Routine Description:
  4620. Updates media free space in the database based on Mover current information.
  4621. This method should be called only while the current media is still mounted.
  4622. Arguments:
  4623. None.
  4624. Return Value:
  4625. S_OK: Ok.
  4626. --*/
  4627. {
  4628. HRESULT hr = S_OK;
  4629. WsbTraceIn(OLESTR("CHsmWorkQueue::UpdateMediaFreeSpace"), OLESTR(""));
  4630. try
  4631. {
  4632. CComPtr<IMediaInfo> pMediaInfo;
  4633. LONGLONG currentFreeSpace;
  4634. WsbAssert(GUID_NULL != m_MediaId, E_UNEXPECTED);
  4635. WsbAffirm(m_pDbWorkSession != 0, E_FAIL);
  4636. // Find media record
  4637. WsbAffirmHr(m_pSegmentDb->GetEntity(m_pDbWorkSession, HSM_MEDIA_INFO_REC_TYPE,
  4638. IID_IMediaInfo, (void**)&pMediaInfo));
  4639. WsbAffirmHr(pMediaInfo->SetId(m_MediaId));
  4640. WsbAffirmHr(pMediaInfo->FindEQ());
  4641. // Get updated free space
  4642. WsbAffirmHr(pMediaInfo->GetFreeBytes(&currentFreeSpace));
  4643. WsbAffirmHr(GetMediaParameters(currentFreeSpace));
  4644. // Update in the media table
  4645. WsbAffirmHr(pMediaInfo->SetFreeBytes(m_MediaFreeSpace));
  4646. WsbAffirmHr(pMediaInfo->UpdateLastKnownGoodMaster());
  4647. WsbAffirmHr(pMediaInfo->Write());
  4648. } WsbCatch( hr );
  4649. WsbTraceOut(OLESTR("CHsmWorkQueue::UpdateMediaFreeSpace"), OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  4650. return(hr);
  4651. }
  4652. HRESULT
  4653. CHsmWorkQueue::GetMediaFreeSpace( LONGLONG *pFreeSpace )
  4654. /*++
  4655. Routine Description:
  4656. Retrieves internal free space from HSM DB (media table)
  4657. Arguments:
  4658. None.
  4659. Return Value:
  4660. S_OK: Ok.
  4661. --*/
  4662. {
  4663. HRESULT hr = S_OK;
  4664. WsbTraceIn(OLESTR("CHsmWorkQueue::GetMediaFreeSpace"), OLESTR(""));
  4665. try
  4666. {
  4667. CComPtr<IMediaInfo> pMediaInfo;
  4668. WsbAssert(GUID_NULL != m_MediaId, E_UNEXPECTED);
  4669. WsbAssert(m_pDbWorkSession != 0, E_UNEXPECTED);
  4670. WsbAssertPointer(pFreeSpace);
  4671. *pFreeSpace = 0;
  4672. // Update in the media table
  4673. WsbAffirmHr(m_pSegmentDb->GetEntity(m_pDbWorkSession, HSM_MEDIA_INFO_REC_TYPE,
  4674. IID_IMediaInfo, (void**)&pMediaInfo));
  4675. WsbAffirmHr(pMediaInfo->SetId(m_MediaId));
  4676. WsbAffirmHr(pMediaInfo->FindEQ());
  4677. WsbAffirmHr(pMediaInfo->GetFreeBytes(pFreeSpace));
  4678. } WsbCatch( hr );
  4679. WsbTraceOut(OLESTR("CHsmWorkQueue::GetMediaFreeSpace"), OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  4680. return(hr);
  4681. }