Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2416 lines
74 KiB

  1. /*++
  2. Module Name:
  3. hsmreclq.cpp
  4. Abstract:
  5. This class represents the HSM Demand Recall Queue manager
  6. It handles recalls initiated by users accessing HSM managed
  7. files. Based on the regular HSM queue manager (CHsmWorkQueue)
  8. Author:
  9. Ravisankar Pudipeddi [ravisp] 1 Oct. 1999
  10. Revision History:
  11. --*/
  12. #include "stdafx.h"
  13. #define WSB_TRACE_IS WSB_TRACE_BIT_HSMTSKMGR
  14. static USHORT iCount = 0;
  15. #include "fsa.h"
  16. #include "rms.h"
  17. #include "metadef.h"
  18. #include "jobint.h"
  19. #include "hsmconn.h"
  20. #include "wsb.h"
  21. #include "hsmeng.h"
  22. #include "mover.h"
  23. #include "hsmreclq.h"
  24. #include "engine.h"
  25. #include "task.h"
  26. #include "tskmgr.h"
  27. #include "segdb.h"
  28. #define STRINGIZE(_str) (OLESTR( #_str ))
  29. #define RETURN_STRINGIZED_CASE(_case) \
  30. case _case: \
  31. return ( STRINGIZE( _case ) );
  32. // Local prototypes
  33. DWORD HsmRecallQueueThread(void *pVoid);
  34. static const OLECHAR * JobStateAsString (HSM_JOB_STATE state);
  35. static const OLECHAR *
  36. JobStateAsString (
  37. IN HSM_JOB_STATE state
  38. )
  39. /*++
  40. Routine Description:
  41. Gives back a static string representing the connection state.
  42. Arguments:
  43. state - the state to return a string for.
  44. Return Value:
  45. NULL - invalid state passed in.
  46. Otherwise, a valid char *.
  47. --*/
  48. {
  49. //
  50. // Do the Switch
  51. //
  52. switch (state) {
  53. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_ACTIVE );
  54. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_CANCELLED );
  55. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_CANCELLING );
  56. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_DONE );
  57. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_FAILED );
  58. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_IDLE );
  59. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_PAUSED );
  60. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_PAUSING );
  61. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_RESUMING );
  62. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_SKIPPED );
  63. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_STARTING );
  64. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_SUSPENDED );
  65. RETURN_STRINGIZED_CASE( HSM_JOB_STATE_SUSPENDING );
  66. default:
  67. return( OLESTR("Invalid Value") );
  68. }
  69. }
  70. HRESULT
  71. CHsmRecallQueue::FinalConstruct(
  72. void
  73. )
  74. /*++
  75. Routine Description:
  76. This method does some initialization of the object that is necessary
  77. after construction.
  78. Arguments:
  79. None.
  80. Return Value:
  81. S_OK
  82. Anything returned by CWsbCollectable::FinalConstruct().
  83. --*/
  84. {
  85. HRESULT hr = S_OK;
  86. WsbTraceIn(OLESTR("CHsmRecallQueue::FinalConstruct"),OLESTR(""));
  87. try {
  88. WsbAssertHr(CComObjectRoot::FinalConstruct());
  89. //
  90. // Initialize the member data
  91. //
  92. m_pServer = 0;
  93. m_pHsmServerCreate = 0;
  94. m_pTskMgr = 0;
  95. m_pRmsServer = 0;
  96. m_pRmsCartridge = 0;
  97. m_pDataMover = 0;
  98. m_pWorkToDo = 0;
  99. UnsetMediaInfo();
  100. m_HsmId = GUID_NULL;
  101. m_RmsMediaSetId = GUID_NULL;
  102. m_RmsMediaSetName = OLESTR("");
  103. m_QueueType = HSM_WORK_TYPE_FSA_DEMAND_RECALL;
  104. m_JobPriority = HSM_JOB_PRIORITY_NORMAL;
  105. m_WorkerThread = 0;
  106. m_CurrentPath = OLESTR("");
  107. // Job abort on errors parameters
  108. m_JobAbortMaxConsecutiveErrors = 5;
  109. m_JobAbortMaxTotalErrors = 25;
  110. m_JobConsecutiveErrors = 0;
  111. m_JobTotalErrors = 0;
  112. m_JobAbortSysDiskSpace = 2 * 1024 * 1024;
  113. m_CurrentSeekOffset = 0;
  114. WSB_OBJECT_ADD(CLSID_CHsmRecallQueue, this);
  115. }WsbCatch(hr);
  116. iCount++;
  117. WsbTraceOut(OLESTR("CHsmRecallQueue::FinalConstruct"),OLESTR("hr = <%ls>, Count is <%d>"),
  118. WsbHrAsString(hr), iCount);
  119. return(hr);
  120. }
  121. HRESULT
  122. CHsmRecallQueue::FinalRelease(
  123. void
  124. )
  125. /*++
  126. Routine Description:
  127. This method does some initialization of the object that is necessary
  128. before destruction.
  129. Arguments:
  130. None.
  131. Return Value:
  132. S_OK
  133. Anything returned by CWsbCollection::FinalDestruct().
  134. --*/
  135. {
  136. HRESULT hr = S_OK;
  137. HSM_SYSTEM_STATE SysState;
  138. WsbTraceIn(OLESTR("CHsmRecallQueue::FinalRelease"),OLESTR(""));
  139. SysState.State = HSM_STATE_SHUTDOWN;
  140. ChangeSysState(&SysState);
  141. WSB_OBJECT_SUB(CLSID_CHsmRecallQueue, this);
  142. CComObjectRoot::FinalRelease();
  143. // Free String members
  144. // Note: Member objects held in smart-pointers are freed when the
  145. // smart-pointer destructor is being called (as part of this object destruction)
  146. m_MediaName.Free();
  147. m_MediaBarCode.Free();
  148. m_RmsMediaSetName.Free();
  149. m_CurrentPath.Free();
  150. iCount--;
  151. WsbTraceOut(OLESTR("CHsmRecallQueue::FinalRelease"),OLESTR("hr = <%ls>, Count is <%d>"),
  152. WsbHrAsString(hr), iCount);
  153. return(hr);
  154. }
  155. HRESULT
  156. CHsmRecallQueue::Init(
  157. IUnknown *pServer,
  158. IHsmFsaTskMgr *pTskMgr
  159. )
  160. /*++
  161. Routine Description:
  162. This method does some initialization of the object that is necessary
  163. after construction.
  164. Arguments:
  165. Return Value:
  166. --*/
  167. {
  168. HRESULT hr = S_OK;
  169. LONG rmsCartridgeType;
  170. CComPtr<IRmsCartridge> pMedia;
  171. WsbTraceIn(OLESTR("CHsmRecallQueue::Init"),OLESTR(""));
  172. try {
  173. //
  174. // Establish contact with the server and get the
  175. // databases
  176. //
  177. WsbAffirmHr(pServer->QueryInterface(IID_IHsmServer, (void **)&m_pServer));
  178. //We want a weak link to the server so decrement the reference count
  179. m_pServer->Release();
  180. m_pTskMgr = pTskMgr;
  181. m_pTskMgr->AddRef();
  182. m_QueueType = HSM_WORK_TYPE_FSA_DEMAND_RECALL;
  183. WsbAffirmHr(m_pServer->QueryInterface(IID_IWsbCreateLocalObject, (void **)&m_pHsmServerCreate));
  184. // We want a weak link to the server so decrement the reference count
  185. m_pHsmServerCreate->Release();
  186. WsbAffirmHr(m_pServer->GetID(&m_HsmId));
  187. //
  188. // Make sure our connection to RMS is current
  189. //
  190. WsbAffirmHr(CheckRms());
  191. //
  192. // Get the media type. We assume mediaId is set before this
  193. // is called. Imperative!
  194. //
  195. WsbAffirmHr(m_pRmsServer->FindCartridgeById(m_MediaId, &pMedia));
  196. WsbAffirmHr(pMedia->GetType( &rmsCartridgeType ));
  197. WsbAffirmHr(ConvertRmsCartridgeType(rmsCartridgeType, &m_MediaType));
  198. //
  199. // Make a collection for the work items
  200. //
  201. WsbAffirmHr(m_pHsmServerCreate->CreateInstance(CLSID_CWsbOrderedCollection,
  202. IID_IWsbIndexedCollection,
  203. (void **)&m_pWorkToDo ));
  204. // Check the registry to see if there are changes to default settings
  205. CheckRegistry();
  206. }WsbCatch( hr );
  207. WsbTraceOut(OLESTR("CHsmRecallQueue::Init"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  208. return( hr );
  209. }
  210. HRESULT
  211. CHsmRecallQueue::ContactOk(
  212. void
  213. )
  214. /*++
  215. Routine Description:
  216. This allows the caller to see if the RPC connection
  217. to the task manager is OK
  218. Arguments:
  219. None.
  220. Return Value:
  221. S_OK
  222. --*/ {
  223. return( S_OK );
  224. }
  225. HRESULT
  226. CHsmRecallQueue::ProcessSessionEvent( IHsmSession *pSession,
  227. HSM_JOB_PHASE phase,
  228. HSM_JOB_EVENT event
  229. )
  230. /*++
  231. Routine Description:
  232. Arguments:
  233. Return Value:
  234. --*/
  235. {
  236. HRESULT hr = S_OK;
  237. WsbTraceIn(OLESTR("CHsmRecallQueue::ProcessSessionEvent"),OLESTR(""));
  238. try {
  239. WsbAssert(0 != pSession, E_POINTER);
  240. // If the phase applies to us (MOVER or ALL), then do any work required by the
  241. // event.
  242. if ((HSM_JOB_PHASE_ALL == phase) || (HSM_JOB_PHASE_MOVE_ACTION == phase)) {
  243. switch (event) {
  244. case HSM_JOB_EVENT_SUSPEND:
  245. case HSM_JOB_EVENT_CANCEL:
  246. case HSM_JOB_EVENT_FAIL:
  247. WsbAffirmHr(Cancel(phase, pSession));
  248. break;
  249. case HSM_JOB_EVENT_RAISE_PRIORITY:
  250. WsbAffirmHr(RaisePriority(phase, pSession));
  251. break;
  252. case HSM_JOB_EVENT_LOWER_PRIORITY:
  253. WsbAffirmHr(LowerPriority(phase, pSession));
  254. break;
  255. default:
  256. case HSM_JOB_EVENT_START:
  257. WsbAssert(FALSE, E_UNEXPECTED);
  258. break;
  259. }
  260. }
  261. }WsbCatch(hr);
  262. WsbTraceOut(OLESTR("CHsmRecallQueue::ProcessSessionEvent"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  263. return( S_OK );
  264. }
  265. HRESULT
  266. CHsmRecallQueue::ProcessSessionState(
  267. IHsmSession* /*pSession*/,
  268. IHsmPhase* pPhase,
  269. OLECHAR* /*currentPath*/
  270. )
  271. /*++
  272. Routine Description:
  273. Arguments:
  274. Return Value:
  275. --*/ {
  276. HRESULT hr = S_OK;
  277. HSM_JOB_PHASE phase;
  278. HSM_JOB_STATE state;
  279. WsbTraceIn(OLESTR("CHsmRecallQueue::ProcessSessionState"),OLESTR(""));
  280. try {
  281. WsbAffirmHr(pPhase->GetState(&state));
  282. WsbAffirmHr(pPhase->GetPhase(&phase));
  283. WsbTrace( OLESTR("CHsmRecallQueue::ProcessSessionState - State = <%d>, phase = <%d>\n"), state, phase );
  284. if (HSM_JOB_PHASE_SCAN == phase) {
  285. // If the session has finished, then we have some cleanup to do so that it can go
  286. // away.
  287. if ((state == HSM_JOB_STATE_DONE) || (state == HSM_JOB_STATE_FAILED) || (state == HSM_JOB_STATE_SUSPENDED)) {
  288. WsbTrace( OLESTR("Job is done, failed, or suspended\n") );
  289. //
  290. // Do nothing: when one recall item is done, we don't need to wait
  291. // for the FSA in order to perform cleanup code
  292. //
  293. /*** WsbAffirmHr(MarkWorkItemAsDone(pSession, phase)); ***/
  294. }
  295. }
  296. }WsbCatch( hr );
  297. WsbTraceOut(OLESTR("CHsmRecallQueue::ProcessSessionState"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  298. return( S_OK );
  299. }
  300. HRESULT
  301. CHsmRecallQueue::Add(
  302. IFsaPostIt *pFsaWorkItem,
  303. GUID *pBagId,
  304. LONGLONG dataSetStart
  305. )
  306. /*++
  307. Implements:
  308. IHsmFsaTskMgr::Add
  309. --*/ {
  310. HRESULT hr = S_OK;
  311. CComPtr<IHsmSession> pSession;
  312. CComPtr<IWsbEnum> pEnum;
  313. CComPtr<IHsmRecallItem> pWorkItem, pWorkItem2;
  314. LONGLONG seekOffset, currentSeekOffset, prevSeekOffset;
  315. LARGE_INTEGER remoteFileStart, remoteDataStart;
  316. LONGLONG readOffset;
  317. FSA_PLACEHOLDER placeholder;
  318. HSM_WORK_ITEM_TYPE workType;
  319. BOOL workItemAllocated=FALSE, insert;
  320. CComPtr<IFsaFilterRecall> pRecall;
  321. DWORD index = 0;
  322. BOOL qLocked = FALSE;
  323. WsbTraceIn(OLESTR("CHsmRecallQueue::Add"),OLESTR(""));
  324. try {
  325. //
  326. // Make sure there is a work allocater for this session
  327. //
  328. WsbAffirmHr(pFsaWorkItem->GetSession(&pSession));
  329. //
  330. // Create a work item, load it up and add it to this
  331. // Queue's collection
  332. //
  333. CComPtr<IHsmRecallItem> pWorkItem;
  334. WsbAffirmHr(m_pHsmServerCreate->CreateInstance(CLSID_CHsmRecallItem, IID_IHsmRecallItem,
  335. (void **)&pWorkItem));
  336. workItemAllocated = TRUE;
  337. WsbAffirmHr(pWorkItem->SetWorkType(HSM_WORK_ITEM_FSA_WORK));
  338. WsbAffirmHr(pWorkItem->SetFsaPostIt(pFsaWorkItem));
  339. WsbAffirmHr(CheckSession(pSession, pWorkItem));
  340. WsbAffirmHr(pWorkItem->SetBagId(pBagId));
  341. WsbAffirmHr(pWorkItem->SetDataSetStart(dataSetStart));
  342. if (m_MediaType == HSM_JOB_MEDIA_TYPE_TAPE) {
  343. //
  344. // For sequential media we order the requests to achieve
  345. // optimal perf.
  346. //
  347. WsbAffirmHr(pFsaWorkItem->GetPlaceholder(&placeholder));
  348. remoteFileStart.QuadPart = placeholder.fileStart;
  349. remoteDataStart.QuadPart = placeholder.dataStart;
  350. WsbAffirmHr(pFsaWorkItem->GetFilterRecall(&pRecall));
  351. WsbAffirmHr(pRecall->GetOffset( &readOffset ));
  352. //
  353. // Calculate the offset in the media that needs to be seeked to
  354. // for the recall. This will be only used for ordering the queue
  355. // performance reasons.
  356. //
  357. seekOffset = dataSetStart + remoteFileStart.QuadPart + remoteDataStart.QuadPart + readOffset;
  358. WsbAffirmHr(pWorkItem->SetSeekOffset(seekOffset));
  359. index = 0;
  360. //
  361. // Find a position in the queue to insert it
  362. // First, we lock the queue while we search for the position
  363. // & insert the item into the queue. We make the assumption
  364. // the lock protecting the queue is recursively acquirable.
  365. // If this is not true, the code that adds to the queue will
  366. // deadlock because it tries to lock the queue too!
  367. //
  368. m_pWorkToDo->Lock();
  369. qLocked = TRUE;
  370. WsbAffirmHr(m_pWorkToDo->Enum(&pEnum));
  371. //
  372. // If the seek offset of the item we wish to insert is
  373. // > the current seek offset of the item that is in progress,
  374. // we just insert it in the first monotonic ascending sequence.
  375. // If not, we insert in the *second* monotonic ascending sequence,
  376. // to prevent the head from seeking back prematurely
  377. //
  378. hr = pEnum->First(IID_IHsmRecallItem, (void **)&pWorkItem2);
  379. if (seekOffset > m_CurrentSeekOffset) {
  380. //
  381. // Insert in the first ascending sequence
  382. //
  383. insert = TRUE;
  384. } else {
  385. //
  386. // Skip the first ascending sequence
  387. //
  388. insert = FALSE;
  389. }
  390. prevSeekOffset = 0;
  391. while (hr != WSB_E_NOTFOUND) {
  392. WsbAffirmHr(pWorkItem2->GetWorkType(&workType));
  393. if (workType != HSM_WORK_ITEM_FSA_WORK) {
  394. //
  395. // Not interested in this. Release it before getting the next
  396. //
  397. pWorkItem2 = 0;
  398. hr = pEnum->Next(IID_IHsmRecallItem, (void **)&pWorkItem2);
  399. index++;
  400. continue;
  401. }
  402. WsbAffirmHr(pWorkItem2->GetSeekOffset(&currentSeekOffset));
  403. if (insert && (currentSeekOffset > seekOffset)) {
  404. //
  405. // place to insert the item..
  406. //
  407. break;
  408. }
  409. if (!insert && (currentSeekOffset < prevSeekOffset)) {
  410. //
  411. // Start of second monotone sequence. We wish to insert
  412. // the item in this sequence
  413. //
  414. insert = TRUE;
  415. //
  416. // Check if pWorkItem is eligible to be inserted at this
  417. // index position
  418. //
  419. if (currentSeekOffset > seekOffset) {
  420. //
  421. // place to insert the item..
  422. //
  423. break;
  424. }
  425. } else {
  426. prevSeekOffset = currentSeekOffset;
  427. }
  428. //
  429. // Move on to the next. Release the current item first
  430. //
  431. pWorkItem2 = 0;
  432. hr = pEnum->Next(IID_IHsmRecallItem, (void **)&pWorkItem2);
  433. index++;
  434. }
  435. if (hr == WSB_E_NOTFOUND) {
  436. WsbAffirmHr(m_pWorkToDo->Append(pWorkItem));
  437. } else {
  438. WsbAffirmHr(m_pWorkToDo->AddAt(pWorkItem, index));
  439. }
  440. //
  441. // Safe to unlock the queue
  442. //
  443. m_pWorkToDo->Unlock();
  444. qLocked = FALSE;
  445. } else {
  446. //
  447. // For non-sequential media, we just add it to the queue ...
  448. // No ordering is done, we let the file system do the optimizations
  449. //
  450. WsbAffirmHr(m_pWorkToDo->Append(pWorkItem));
  451. }
  452. hr = S_OK;
  453. }WsbCatchAndDo(hr,
  454. //
  455. // Add code to release queue lock if acquired
  456. //
  457. if (qLocked) {
  458. m_pWorkToDo->Unlock();
  459. }
  460. );
  461. WsbTraceOut(OLESTR("CHsmRecallQueue::Add"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  462. return(hr);
  463. }
  464. HRESULT
  465. CHsmRecallQueue::Start( void )
  466. /*++
  467. Implements:
  468. IHsmRecallQueue::Start
  469. --*/
  470. {
  471. HRESULT hr = S_OK;
  472. DWORD tid;
  473. WsbTraceIn(OLESTR("CHsmRecallQueue::Start"),OLESTR(""));
  474. try {
  475. //
  476. // If the worker thread is already started, just return
  477. //
  478. WsbAffirm(m_WorkerThread == 0, S_OK);
  479. // Launch a thread to do work that is queued
  480. WsbAffirm((m_WorkerThread = CreateThread(0, 0, HsmRecallQueueThread, (void*) this, 0, &tid)) != 0, HRESULT_FROM_WIN32(GetLastError()));
  481. if (m_WorkerThread == NULL) {
  482. WsbAssertHr(E_FAIL); // TBD What error to return here??
  483. }
  484. }WsbCatch (hr);
  485. WsbTraceOut(OLESTR("CHsmRecallQueue::Start"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  486. return(hr);
  487. }
  488. HRESULT
  489. CHsmRecallQueue::Stop( void )
  490. /*++
  491. Implements:
  492. IHsmRecallQueue::Stop
  493. --*/ {
  494. HRESULT hr = S_OK;
  495. WsbTraceIn(OLESTR("CHsmRecallQueue::Stop"),OLESTR(""));
  496. // Stop the thread
  497. if (m_WorkerThread) {
  498. TerminateThread(m_WorkerThread, 0);
  499. }
  500. WsbTraceOut(OLESTR("CHsmRecallQueue::Stop"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  501. return(hr);
  502. }
  503. HRESULT
  504. CHsmRecallQueue::RecallIt(
  505. IHsmRecallItem * pWorkItem
  506. )
  507. {
  508. HRESULT hr = S_OK;
  509. CComPtr<IFsaScanItem> pScanItem;
  510. CComPtr<IFsaPostIt> pFsaWorkItem;
  511. LONGLONG readOffset;
  512. FSA_REQUEST_ACTION requestAction;
  513. ULARGE_INTEGER remoteDataSetStart;
  514. GUID bagId;
  515. CComPtr<IWsbIndexedCollection> pMountingCollection;
  516. CComPtr<IMountingMedia> pMountingMedia;
  517. CComPtr<IMountingMedia> pMediaToFind;
  518. BOOL bMediaMounting = FALSE;
  519. BOOL bMediaMountingAdded = FALSE;
  520. WsbTraceIn(OLESTR("CHsmRecallQueue::RecallIt"),OLESTR(""));
  521. try {
  522. WsbAffirmHr(pWorkItem->GetFsaPostIt(&pFsaWorkItem));
  523. WsbAffirmHr(pFsaWorkItem->GetRequestAction(&requestAction));
  524. GetScanItem(pFsaWorkItem, &pScanItem);
  525. WsbAffirmHr(pWorkItem->GetBagId(&bagId));
  526. WsbAffirmHr(pWorkItem->GetDataSetStart((LONGLONG *) &remoteDataSetStart.QuadPart));
  527. //
  528. // Check if we are mounting a new media: recall-queue is created on a per-media basis, therefore,
  529. // media cannot change. The only test is whether the media for this queue is already mounted
  530. //
  531. if (m_MountedMedia == GUID_NULL) {
  532. // Check if the media is already in the process of mounting
  533. WsbAffirmHr(m_pServer->LockMountingMedias());
  534. try {
  535. // Check if the media to mount is already mounting
  536. WsbAffirmHr(m_pServer->GetMountingMedias(&pMountingCollection));
  537. WsbAffirmHr(CoCreateInstance(CLSID_CMountingMedia, 0, CLSCTX_SERVER, IID_IMountingMedia, (void**)&pMediaToFind));
  538. WsbAffirmHr(pMediaToFind->SetMediaId(m_MediaId));
  539. hr = pMountingCollection->Find(pMediaToFind, IID_IMountingMedia, (void **)&pMountingMedia);
  540. if (hr == S_OK) {
  541. // Media is already mounting...
  542. bMediaMounting = TRUE;
  543. } else if (hr == WSB_E_NOTFOUND) {
  544. // New media to mount - add to the mounting list
  545. hr = S_OK;
  546. WsbAffirmHr(pMediaToFind->Init(m_MediaId, TRUE));
  547. WsbAffirmHr(pMountingCollection->Add(pMediaToFind));
  548. bMediaMountingAdded = TRUE;
  549. } else {
  550. WsbAffirmHr(hr);
  551. }
  552. } WsbCatchAndDo(hr,
  553. // Unlock mounting media
  554. m_pServer->UnlockMountingMedias();
  555. WsbTraceAlways(OLESTR("CHsmRecallQueue::RecallIt: error while trying to find/add mounting media. hr=<%ls>\n"),
  556. WsbHrAsString(hr));
  557. // Bale out
  558. WsbThrow(hr);
  559. );
  560. // Release the lock
  561. WsbAffirmHr(m_pServer->UnlockMountingMedias());
  562. }
  563. //
  564. // If the media is already mounting - wait for the mount event
  565. //
  566. if (bMediaMounting) {
  567. WsbAffirmHr(pMountingMedia->WaitForMount(INFINITE));
  568. pMountingMedia = 0;
  569. }
  570. //
  571. // Get the media mounted (hr is checked only after removing from the mounting-media list)
  572. //
  573. hr = MountMedia(pWorkItem, m_MediaId);
  574. //
  575. // If added to the mounting list - remove
  576. //
  577. if (bMediaMountingAdded) {
  578. HRESULT hrRemove = S_OK;
  579. // No matter how the Mount finished - free waiting clients and remove from the list
  580. hrRemove = m_pServer->LockMountingMedias();
  581. WsbAffirmHr(hrRemove);
  582. try {
  583. WsbAffirmHr(pMediaToFind->MountDone());
  584. WsbAffirmHr(pMountingCollection->RemoveAndRelease(pMediaToFind));
  585. pMediaToFind = 0;
  586. } WsbCatch(hrRemove);
  587. m_pServer->UnlockMountingMedias();
  588. // We don't expect any errors while removing the mounting media -
  589. // The thread that added to the collection is always the one that removes
  590. if (! SUCCEEDED(hrRemove)) {
  591. WsbTraceAlways(OLESTR("CHsmRecallQueue::RecallIt: error while trying to remove a mounting media. hr=<%ls>\n"),
  592. WsbHrAsString(hrRemove));
  593. WsbThrow(hrRemove);
  594. }
  595. }
  596. //
  597. // Check the Mount result
  598. //
  599. WsbAffirmHr(hr);
  600. //
  601. // Copy the data
  602. //
  603. // Build the source path
  604. CWsbStringPtr tmpString;
  605. WsbAffirmHr(GetSource(pFsaWorkItem, &tmpString));
  606. CWsbBstrPtr localName = tmpString;
  607. // Ask the Data mover to store the data
  608. LONGLONG requestSize;
  609. LONGLONG requestStart;
  610. ULARGE_INTEGER localDataStart;
  611. ULARGE_INTEGER localDataSize;
  612. ULARGE_INTEGER remoteFileStart;
  613. ULARGE_INTEGER remoteFileSize;
  614. ULARGE_INTEGER remoteDataStart;
  615. ULARGE_INTEGER remoteDataSize;
  616. ULARGE_INTEGER remoteVerificationData;
  617. ULONG remoteVerificationType;
  618. FSA_PLACEHOLDER placeholder;
  619. WsbAffirmHr(pFsaWorkItem->GetPlaceholder(&placeholder));
  620. WsbAffirmHr(pFsaWorkItem->GetRequestSize(&requestSize));
  621. WsbAffirmHr(pFsaWorkItem->GetRequestOffset(&requestStart));
  622. //
  623. // Build strings
  624. //
  625. CWsbBstrPtr sessionName = HSM_BAG_NAME;
  626. CWsbBstrPtr sessionDescription = HSM_ENGINE_ID;
  627. sessionName.Append(WsbGuidAsString(bagId));
  628. sessionDescription.Append(WsbGuidAsString(m_HsmId));
  629. localDataStart.QuadPart = requestStart;
  630. localDataSize.QuadPart = requestSize;
  631. remoteFileStart.QuadPart = placeholder.fileStart;
  632. remoteFileSize.QuadPart = placeholder.fileSize;
  633. remoteDataStart.QuadPart = placeholder.dataStart;
  634. remoteDataSize.QuadPart = placeholder.dataSize;
  635. remoteVerificationData.QuadPart = placeholder.verificationData;
  636. remoteVerificationType = placeholder.verificationType;
  637. ReportMediaProgress(HSM_JOB_MEDIA_STATE_TRANSFERRING, hr);
  638. CComPtr<IStream> pLocalStream;
  639. CComPtr<IStream> pRemoteStream;
  640. ULARGE_INTEGER offset, read, written;
  641. DWORD verifyType;
  642. //
  643. // We are doing a demand recall, so get the
  644. // recall object's data mover
  645. //
  646. CComPtr<IFsaFilterRecall> pRecall;
  647. WsbAffirmHr(pFsaWorkItem->GetFilterRecall(&pRecall));
  648. WsbAffirmHr(pRecall->CreateLocalStream( &pLocalStream));
  649. WsbAffirmHr(pRecall->GetSize( (LONGLONG *) &remoteDataSize.QuadPart ));
  650. WsbAffirmHr(pRecall->GetOffset( &readOffset ));
  651. if (readOffset == 0) {
  652. verifyType = MVR_VERIFICATION_TYPE_HEADER_CRC;
  653. } else {
  654. verifyType = MVR_VERIFICATION_TYPE_NONE;
  655. }
  656. //
  657. // Set the current seek offset used for ordering items in the queue
  658. //
  659. m_CurrentSeekOffset = remoteDataSetStart.QuadPart + remoteFileStart.QuadPart+remoteDataStart.QuadPart+requestStart;
  660. //
  661. // Create remote data mover stream
  662. // TEMPORARY: Consider removing the NO_CACHING flag for a NO_RECALL recall
  663. //
  664. WsbAssert(0 != remoteDataSetStart.QuadPart, HSM_E_BAD_SEGMENT_INFORMATION);
  665. WsbAffirmHr( m_pDataMover->CreateRemoteStream(
  666. CWsbBstrPtr(L""),
  667. MVR_MODE_READ | MVR_FLAG_HSM_SEMANTICS | MVR_FLAG_NO_CACHING,
  668. sessionName,
  669. sessionDescription,
  670. remoteDataSetStart,
  671. remoteFileStart,
  672. remoteFileSize,
  673. remoteDataStart,
  674. remoteDataSize,
  675. verifyType,
  676. remoteVerificationData,
  677. &pRemoteStream ) );
  678. //
  679. // The offset given here is the offset into the stream itself (readOffset).
  680. // The actual position on remote media will be the bag start plus the file start
  681. // plus the file-data start (all given in CreateRemoteStream) plus this offset.
  682. //
  683. WsbTrace(OLESTR("Setting offset to %I64d reading %I64u\n"), readOffset, remoteDataSize.QuadPart);
  684. offset.QuadPart = readOffset;
  685. WsbAffirmHr( m_pDataMover->SetInitialOffset( offset ) );
  686. //
  687. // Once the remote stream has been created we must make sure we detach it
  688. //
  689. try {
  690. WsbAffirmHr( pRemoteStream->CopyTo( pLocalStream, remoteDataSize, &read, &written ) );
  691. WsbAffirmHr( pLocalStream->Commit( STGC_DEFAULT ) );
  692. //
  693. // The CopyTo succeeded... make sure we got all the bytes
  694. // we asked for.
  695. //
  696. // If we attempt to read from a incomplete Master that
  697. // does not contain the migrated data we'll fail here with
  698. // MVR_S_NO_DATA_DETECTED.
  699. //
  700. WsbAffirm( written.QuadPart == remoteDataSize.QuadPart, HSM_E_VALIDATE_DATA_NOT_ON_MEDIA );
  701. WsbAffirmHr( m_pDataMover->CloseStream() );
  702. }WsbCatchAndDo(hr,
  703. WsbAffirmHr( m_pDataMover->CloseStream() );
  704. );
  705. ReportMediaProgress(HSM_JOB_MEDIA_STATE_TRANSFERRED, hr);
  706. WsbTrace(OLESTR("RecallData returned hr = <%ls>\n"),WsbHrAsString(hr));
  707. }WsbCatch( hr );
  708. // Tell the session whether or not the work was done.
  709. // We don't really care about the return code, there is nothing
  710. // we can do if it fails.
  711. WsbTrace(OLESTR("Tried HSM work, calling Session to Process Item\n"));
  712. if (pScanItem) {
  713. CComPtr<IHsmSession> pSession;
  714. HSM_JOB_PHASE jobPhase;
  715. WsbAffirmHr(pFsaWorkItem->GetSession(&pSession));
  716. WsbAffirmHr(pWorkItem->GetJobPhase(&jobPhase));
  717. pSession->ProcessItem(jobPhase, HSM_JOB_ACTION_RECALL , pScanItem, hr);
  718. }
  719. WsbTraceOut(OLESTR("CHsmRecallQueue::RecallIt"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  720. return( hr );
  721. }
  722. HRESULT
  723. CHsmRecallQueue::RaisePriority(
  724. IN HSM_JOB_PHASE jobPhase,
  725. IN IHsmSession *pSession
  726. )
  727. /*++
  728. --*/
  729. {
  730. HRESULT hr = S_OK;
  731. WsbTraceIn(OLESTR("CHsmRecallQueue::RaisePriority"),OLESTR(""));
  732. try {
  733. WsbAssert(0 != m_WorkerThread, E_UNEXPECTED);
  734. WsbAssert(pSession != 0, E_UNEXPECTED);
  735. switch (m_JobPriority) {
  736. case HSM_JOB_PRIORITY_IDLE:
  737. WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_LOWEST));
  738. m_JobPriority = HSM_JOB_PRIORITY_LOWEST;
  739. break;
  740. case HSM_JOB_PRIORITY_LOWEST:
  741. WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_BELOW_NORMAL));
  742. m_JobPriority = HSM_JOB_PRIORITY_LOW;
  743. break;
  744. case HSM_JOB_PRIORITY_LOW:
  745. WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_NORMAL));
  746. m_JobPriority = HSM_JOB_PRIORITY_NORMAL;
  747. break;
  748. case HSM_JOB_PRIORITY_NORMAL:
  749. WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_ABOVE_NORMAL));
  750. m_JobPriority = HSM_JOB_PRIORITY_HIGH;
  751. break;
  752. case HSM_JOB_PRIORITY_HIGH:
  753. WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_HIGHEST));
  754. m_JobPriority = HSM_JOB_PRIORITY_HIGHEST;
  755. break;
  756. case HSM_JOB_PRIORITY_HIGHEST:
  757. WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_TIME_CRITICAL));
  758. m_JobPriority = HSM_JOB_PRIORITY_CRITICAL;
  759. break;
  760. default:
  761. case HSM_JOB_PRIORITY_CRITICAL:
  762. WsbAffirm(FALSE, E_UNEXPECTED);
  763. break;
  764. }
  765. WsbAffirmHr(pSession->ProcessPriority(jobPhase, m_JobPriority));
  766. }WsbCatch(hr);
  767. WsbTraceOut(OLESTR("CHsmRecallQueue::RaisePriority"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  768. return(hr);
  769. }
  770. HRESULT
  771. CHsmRecallQueue::LowerPriority(
  772. IN HSM_JOB_PHASE jobPhase,
  773. IN IHsmSession *pSession
  774. )
  775. /*++
  776. --*/
  777. {
  778. HRESULT hr = S_OK;
  779. WsbTraceIn(OLESTR("CHsmRecallQueue::LowerPriority"),OLESTR(""));
  780. try {
  781. WsbAssert(0 != m_WorkerThread, E_UNEXPECTED);
  782. WsbAssert(pSession != 0, E_UNEXPECTED);
  783. switch (m_JobPriority) {
  784. case HSM_JOB_PRIORITY_IDLE:
  785. WsbAffirm(FALSE, E_UNEXPECTED);
  786. break;
  787. case HSM_JOB_PRIORITY_LOWEST:
  788. WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_IDLE));
  789. m_JobPriority = HSM_JOB_PRIORITY_IDLE;
  790. break;
  791. case HSM_JOB_PRIORITY_LOW:
  792. WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_LOWEST));
  793. m_JobPriority = HSM_JOB_PRIORITY_LOWEST;
  794. break;
  795. case HSM_JOB_PRIORITY_NORMAL:
  796. WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_BELOW_NORMAL));
  797. m_JobPriority = HSM_JOB_PRIORITY_LOW;
  798. break;
  799. case HSM_JOB_PRIORITY_HIGH:
  800. WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_NORMAL));
  801. m_JobPriority = HSM_JOB_PRIORITY_NORMAL;
  802. break;
  803. case HSM_JOB_PRIORITY_HIGHEST:
  804. WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_ABOVE_NORMAL));
  805. m_JobPriority = HSM_JOB_PRIORITY_HIGH;
  806. break;
  807. default:
  808. case HSM_JOB_PRIORITY_CRITICAL:
  809. WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_HIGHEST));
  810. m_JobPriority = HSM_JOB_PRIORITY_HIGHEST;
  811. break;
  812. }
  813. WsbAffirmHr(pSession->ProcessPriority(jobPhase, m_JobPriority));
  814. }WsbCatch(hr);
  815. WsbTraceOut(OLESTR("CHsmRecallQueue::LowerPriority"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  816. return(hr);
  817. }
  818. HRESULT
  819. CHsmRecallQueue::CheckRms(
  820. void
  821. )
  822. /*++
  823. --*/
  824. {
  825. HRESULT hr = S_OK;
  826. WsbTraceIn(OLESTR("CHsmRecallQueue::CheckRms"),OLESTR(""));
  827. try {
  828. //
  829. // Make sure we can still talk to the RMS
  830. //
  831. if (m_pRmsServer != 0) {
  832. CWsbBstrPtr name;
  833. hr = m_pRmsServer->GetServerName( &name );
  834. if (hr != S_OK) {
  835. m_pRmsServer = 0;
  836. hr = S_OK;
  837. }
  838. }
  839. //
  840. // Get RMS that runs on this machine
  841. //
  842. if (m_pRmsServer == 0) {
  843. WsbAffirmHr(m_pServer->GetHsmMediaMgr(&m_pRmsServer));
  844. // wait for RMS to come ready
  845. // (this may not be needed anymore - if Rms initialization is
  846. // synced with Engine initialization)
  847. CComObject<CRmsSink> *pSink = new CComObject<CRmsSink>;
  848. CComPtr<IUnknown> pSinkUnk = pSink; // holds refcount for use here
  849. WsbAffirmHr( pSink->Construct( m_pRmsServer ) );
  850. WsbAffirmHr( pSink->WaitForReady( ) );
  851. WsbAffirmHr( pSink->DoUnadvise( ) );
  852. }
  853. }WsbCatch( hr );
  854. WsbTraceOut(OLESTR("CHsmRecallQueue::CheckRms"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  855. return(hr);
  856. }
  857. HRESULT
  858. CHsmRecallQueue::CheckSession(
  859. IHsmSession *pSession,
  860. IHsmRecallItem *pWorkItem
  861. )
  862. /*++
  863. --*/ {
  864. HRESULT hr = S_OK;
  865. BOOL bLog = TRUE;
  866. WsbTraceIn(OLESTR("CHsmRecallQueue::CheckSession"),OLESTR(""));
  867. try {
  868. //
  869. // Check to see if we have dealt with this or any other session before.
  870. WsbTrace(OLESTR("New session.\n"));
  871. //
  872. // We have no on going session so we need to establish communication
  873. // with this session.
  874. //
  875. CComPtr<IHsmSessionSinkEveryState> pSinkState;
  876. CComPtr<IHsmSessionSinkEveryEvent> pSinkEvent;
  877. CComPtr<IConnectionPointContainer> pCPC;
  878. CComPtr<IConnectionPoint> pCP;
  879. CComPtr<IFsaResource> pFsaResource;
  880. HSM_JOB_PHASE jobPhase;
  881. DWORD stateCookie, eventCookie;
  882. ULONG refCount;
  883. // Tell the session we are starting up.
  884. pWorkItem->SetJobState(HSM_JOB_STATE_STARTING);
  885. pWorkItem->GetJobPhase(&jobPhase);
  886. WsbTrace(OLESTR("Before Process State.\n"));
  887. refCount = (((IUnknown *) (IHsmFsaTskMgr *) this)->AddRef()) - 1;
  888. ((IUnknown *) (IHsmFsaTskMgr *)this)->Release();
  889. WsbTrace(OLESTR("REFCOUNT for CHsmRecallQueue before 1st process state: %ls \n"), WsbLongAsString((LONG) refCount));
  890. WsbAffirmHr(pSession->ProcessState(jobPhase, HSM_JOB_STATE_STARTING, m_CurrentPath, bLog));
  891. refCount = (((IUnknown *) (IHsmFsaTskMgr *) this)->AddRef()) - 1;
  892. ((IUnknown *) (IHsmFsaTskMgr *)this)->Release();
  893. WsbTrace(OLESTR("REFCOUNT for CHsmRecallQueue after 1st process state: %ls \n"), WsbLongAsString((LONG) refCount));
  894. WsbTrace(OLESTR("After Process State.\n"));
  895. // Get the interface to the callback that the sessions should use.
  896. WsbTrace(OLESTR("Before QI's for sinks.\n"));
  897. WsbAffirmHr(((IUnknown*) (IHsmFsaTskMgr*) this)->QueryInterface(IID_IHsmSessionSinkEveryState, (void**) &pSinkState));
  898. WsbAffirmHr(((IUnknown*) (IHsmFsaTskMgr*) this)->QueryInterface(IID_IHsmSessionSinkEveryEvent, (void**) &pSinkEvent));
  899. WsbTrace(OLESTR("After QI's for sinks.\n"));
  900. // Ask the session to advise of every state changes.
  901. WsbTrace(OLESTR("Before QI for connection point containers.\n"));
  902. WsbAffirmHr(pSession->QueryInterface(IID_IConnectionPointContainer, (void**) &pCPC));
  903. WsbAffirmHr(pCPC->FindConnectionPoint(IID_IHsmSessionSinkEveryState, &pCP));
  904. WsbAffirmHr(pCP->Advise(pSinkState, &stateCookie));
  905. pWorkItem->SetStateCookie(stateCookie);
  906. pCP = 0;
  907. WsbAffirmHr(pCPC->FindConnectionPoint(IID_IHsmSessionSinkEveryEvent, &pCP));
  908. WsbAffirmHr(pCP->Advise(pSinkEvent, &eventCookie));
  909. pWorkItem->SetEventCookie(eventCookie);
  910. pCP = 0;
  911. WsbTrace(OLESTR("After Advises.\n"));
  912. //
  913. // Get the resource for this work from the session
  914. //
  915. WsbAffirmHr(pSession->GetResource(&pFsaResource));
  916. pWorkItem->SetJobState(HSM_JOB_STATE_ACTIVE);
  917. WsbTrace(OLESTR("Before Process State.\n"));
  918. refCount = (((IUnknown *) (IHsmFsaTskMgr *) this)->AddRef()) - 1;
  919. ((IUnknown *) (IHsmFsaTskMgr *)this)->Release();
  920. WsbTrace(OLESTR("REFCOUNT for CHsmRecallQueue before 2nd process state: %ls \n"), WsbLongAsString((LONG) refCount));
  921. WsbAffirmHr(pSession->ProcessState(jobPhase, HSM_JOB_STATE_ACTIVE, m_CurrentPath, bLog));
  922. refCount = (((IUnknown *) (IHsmFsaTskMgr *) this)->AddRef()) - 1;
  923. ((IUnknown *) (IHsmFsaTskMgr *)this)->Release();
  924. WsbTrace(OLESTR("REFCOUNT for CHsmRecallQueue after 2nd process state: %ls \n"), WsbLongAsString((LONG) refCount));
  925. WsbTrace(OLESTR("After Process State.\n"));
  926. }WsbCatch( hr );
  927. WsbTraceOut(OLESTR("CHsmRecallQueue::CheckSession"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  928. return(hr);
  929. }
  930. HRESULT
  931. CHsmRecallQueue::DoWork( void )
  932. /*++
  933. --*/
  934. {
  935. HRESULT hr = S_OK;
  936. CWsbStringPtr path;
  937. CComPtr<IHsmRecallItem> pWorkItem;
  938. HSM_WORK_ITEM_TYPE workType;
  939. BOOLEAN done = FALSE;
  940. HRESULT skipWork = S_FALSE;
  941. WsbTraceIn(OLESTR("CHsmRecallQueue::DoWork"),OLESTR(""));
  942. // Make sure this object isn't released (and our thread killed
  943. // before finishing up in this routine
  944. ((IUnknown*)(IHsmRecallQueue*)this)->AddRef();
  945. try {
  946. while (!done) {
  947. //
  948. // Get the next work to do from the queue
  949. //
  950. hr = m_pWorkToDo->First(IID_IHsmRecallItem, (void **)&pWorkItem);
  951. if (WSB_E_NOTFOUND == hr) {
  952. //
  953. // We might be done with this queue.
  954. // Attempt to destroy it: if we cannot it means there are more items
  955. // that were being added so we continue looping
  956. //
  957. hr = m_pTskMgr->WorkQueueDone(NULL, HSM_WORK_TYPE_FSA_DEMAND_RECALL, &m_MediaId);
  958. if (hr == S_OK) {
  959. //
  960. // Queue is really done - break out of the while loop
  961. //
  962. done = TRUE;
  963. break;
  964. } else if (hr == S_FALSE) {
  965. //
  966. // More items in the queue
  967. //
  968. continue;
  969. } else {
  970. //
  971. // Some sort of error happened, bale out
  972. //
  973. WsbTraceAlways(OLESTR("CHsmRecallQueue::DoWork: WorkQueueDone failed with <%ls> - terminating queue thread\n"),
  974. WsbHrAsString(hr));
  975. WsbAffirmHr(hr);
  976. }
  977. } else {
  978. WsbAffirmHr(hr);
  979. //
  980. // Remove it from the queue
  981. //
  982. Remove(pWorkItem);
  983. }
  984. WsbAffirmHr(pWorkItem->GetWorkType(&workType));
  985. switch (workType) {
  986. case HSM_WORK_ITEM_FSA_DONE: {
  987. //
  988. // TBD:Code path should not be reached
  989. //
  990. WsbTraceAlways(OLESTR("Unexpected: CHsmRecallQueue::DoWork - FSA WORK DONE item\n"));
  991. break;
  992. }
  993. case HSM_WORK_ITEM_FSA_WORK: {
  994. if (S_FALSE == skipWork) {
  995. //
  996. // Get the FSA Work Item and do the work
  997. //
  998. hr = DoFsaWork(pWorkItem);
  999. } else {
  1000. //
  1001. // Skip the work
  1002. //
  1003. try {
  1004. CComPtr<IFsaPostIt> pFsaWorkItem;
  1005. CComPtr<IFsaScanItem> pScanItem;
  1006. CComPtr<IFsaResource> pFsaResource;
  1007. CComPtr<IHsmSession> pSession;
  1008. HSM_JOB_PHASE jobPhase;
  1009. WsbAffirmHr(pWorkItem->GetFsaPostIt(&pFsaWorkItem));
  1010. WsbAffirmHr(pWorkItem->GetJobPhase(&jobPhase));
  1011. WsbAffirmHr(pFsaWorkItem->GetSession(&pSession));
  1012. WsbAffirmHr(pSession->GetResource(&pFsaResource));
  1013. WsbAffirmHr(GetScanItem(pFsaWorkItem, &pScanItem));
  1014. hr = pFsaWorkItem->SetResult(skipWork);
  1015. if (S_OK == hr) {
  1016. WsbTrace(OLESTR("HSM recall (filter, read or recall) complete, calling FSA\n"));
  1017. hr = pFsaResource->ProcessResult(pFsaWorkItem);
  1018. WsbTrace(OLESTR("FSA ProcessResult returned <%ls>\n"), WsbHrAsString(hr));
  1019. }
  1020. (void)pSession->ProcessHr(jobPhase, 0, 0, hr);
  1021. WsbAffirmHr(pSession->ProcessItem(jobPhase,
  1022. HSM_JOB_ACTION_RECALL,
  1023. pScanItem,
  1024. skipWork));
  1025. }WsbCatch( hr );
  1026. }
  1027. EndRecallSession(pWorkItem, FALSE);
  1028. break;
  1029. }
  1030. case HSM_WORK_ITEM_MOVER_CANCELLED: {
  1031. CComPtr<IHsmRecallItem> pWorkItemToCancel;
  1032. WsbTrace(OLESTR("CHsmRecallQueue::DoWork - Mover Cancelled\n"));
  1033. try {
  1034. //
  1035. // Get hold of the work item that needs to be cancelled.
  1036. // This is indicated by the session pointer in the cancel work item
  1037. //
  1038. hr = FindRecallItemToCancel(pWorkItem, &pWorkItemToCancel);
  1039. if (hr == S_OK) {
  1040. EndRecallSession(pWorkItemToCancel, TRUE);
  1041. //
  1042. // Remove the *cancelled* work item
  1043. //
  1044. Remove(pWorkItemToCancel);
  1045. }
  1046. //
  1047. // Remove the cancel work item
  1048. //
  1049. hr = S_OK;
  1050. }WsbCatch( hr );
  1051. //
  1052. // We are done completely with one more work item
  1053. //
  1054. break;
  1055. }
  1056. default: {
  1057. hr = E_UNEXPECTED;
  1058. break;
  1059. }
  1060. }
  1061. pWorkItem = 0;
  1062. }
  1063. }WsbCatch( hr );
  1064. //
  1065. // Dismount the media..
  1066. //
  1067. DismountMedia(FALSE);
  1068. // Pretend everything is OK
  1069. hr = S_OK;
  1070. // Release the thread (the thread should terminate on exit
  1071. // from the routine that called this routine)
  1072. CloseHandle(m_WorkerThread);
  1073. m_WorkerThread = 0;
  1074. // Allow this object to be released
  1075. ((IUnknown*)(IHsmRecallQueue*)this)->Release();
  1076. WsbTraceOut(OLESTR("CHsmRecallQueue::DoWork"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  1077. return(hr);
  1078. }
  1079. HRESULT
  1080. CHsmRecallQueue::DoFsaWork(
  1081. IHsmRecallItem *pWorkItem
  1082. )
  1083. /*++
  1084. --*/
  1085. {
  1086. HRESULT hr = S_OK;
  1087. HRESULT hr2 = S_OK;
  1088. HRESULT workHr = S_OK;
  1089. HSM_JOB_PHASE jobPhase;
  1090. CWsbStringPtr path;
  1091. CComPtr<IFsaPostIt> pFsaWorkItem;
  1092. CComPtr<IHsmSession> pSession;
  1093. CComPtr<IFsaResource> pFsaResource;
  1094. WsbTraceIn(OLESTR("CHsmRecallQueue::DoFsaWork"),OLESTR(""));
  1095. try {
  1096. //
  1097. // Do the work.
  1098. //
  1099. WsbAffirmHr(pWorkItem->GetFsaPostIt(&pFsaWorkItem));
  1100. WsbAffirmHr(pWorkItem->GetJobPhase(&jobPhase));
  1101. WsbAffirmHr(pFsaWorkItem->GetPath(&path, 0));
  1102. WsbAffirmHr(pFsaWorkItem->GetSession(&pSession));
  1103. WsbAffirmHr(pSession->GetResource(&pFsaResource));
  1104. WsbTrace(OLESTR("Handling file <%s>.\n"), WsbAbbreviatePath(path, 120));
  1105. workHr = RecallIt(pWorkItem);
  1106. //
  1107. // Tell the recaller right away about the success or failure
  1108. // of the recall, we do this here so the recall filter can
  1109. // release the open as soon as possible
  1110. //
  1111. hr = pFsaWorkItem->SetResult(workHr);
  1112. if (S_OK == hr) {
  1113. WsbTrace(OLESTR("HSM recall (filter, read or recall) complete, calling FSA\n"));
  1114. hr = pFsaResource->ProcessResult(pFsaWorkItem);
  1115. WsbTrace(OLESTR("FSA ProcessResult returned <%ls>\n"), WsbHrAsString(hr));
  1116. }
  1117. // Note: In case that the recall item is/was canceling at any time, we don't want
  1118. // to report on errors. If the cancel occurred while the recall item was queued,
  1119. // we won't get here at all, but if it was cancelled while being executed, we
  1120. // might end up here with some bad workHr returned by the Mover code
  1121. if ((S_OK != workHr) && (S_OK != pSession->IsCanceling())) {
  1122. // Tell the session how things went if they didn't go well.
  1123. (void) pSession->ProcessHr(jobPhase, 0, 0, workHr);
  1124. }
  1125. }WsbCatch(hr);
  1126. WsbTraceOut(OLESTR("CHsmRecallQueue::DoFsaWork"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  1127. return(hr);
  1128. }
  1129. HRESULT
  1130. CHsmRecallQueue::MountMedia(
  1131. IHsmRecallItem *pWorkItem,
  1132. GUID mediaToMount,
  1133. BOOL bShortWait
  1134. )
  1135. /*++
  1136. --*/
  1137. {
  1138. HRESULT hr = S_OK;
  1139. GUID l_MediaToMount = mediaToMount;
  1140. CComPtr<IRmsDrive> pDrive;
  1141. CWsbBstrPtr pMediaName;
  1142. DWORD dwOptions = RMS_NONE;
  1143. DWORD threadId;
  1144. CComPtr<IFsaPostIt> pFsaWorkItem;
  1145. WsbTraceIn(OLESTR("CHsmRecallQueue::MountMedia"),OLESTR("Display Name = <%ls>"), (WCHAR *)m_MediaName);
  1146. try {
  1147. WsbAffirmHr(pWorkItem->GetFsaPostIt(&pFsaWorkItem));
  1148. WsbAffirmHr(pFsaWorkItem->GetThreadId(&threadId));
  1149. // If we're switching tapes, dismount the current one
  1150. if ((m_MountedMedia != l_MediaToMount) && (m_MountedMedia != GUID_NULL)) {
  1151. WsbAffirmHr(DismountMedia());
  1152. }
  1153. // Ask RMS for short timeout, both for Mount and Allocate
  1154. if (bShortWait) {
  1155. dwOptions |= RMS_SHORT_TIMEOUT;
  1156. }
  1157. dwOptions |= RMS_USE_MOUNT_NO_DEADLOCK;
  1158. if (m_MountedMedia != l_MediaToMount) {
  1159. ReportMediaProgress(HSM_JOB_MEDIA_STATE_MOUNTING, hr);
  1160. hr = m_pRmsServer->MountCartridge( l_MediaToMount, &pDrive, &m_pRmsCartridge, &m_pDataMover, dwOptions, threadId);
  1161. hr = TranslateRmsMountHr(hr);
  1162. //
  1163. // If failure is because cartridge is disabled, need to get media label to put in error.
  1164. //
  1165. if (hr == RMS_E_CARTRIDGE_DISABLED) {
  1166. // Since this is just to get label, if any of these functions fail,
  1167. // don't throw, error will simply have blank label.
  1168. //
  1169. CComPtr<IRmsCartridge> pMedia;
  1170. HRESULT hrName;
  1171. hrName = m_pRmsServer->FindCartridgeById(l_MediaToMount , &pMedia);
  1172. if (hrName == S_OK) {
  1173. pMedia->GetName(&pMediaName);
  1174. }
  1175. if ((hrName != S_OK) || ((WCHAR *)pMediaName == NULL)) {
  1176. // Cannot get media name - set to blanks
  1177. pMediaName = L"";
  1178. }
  1179. WsbThrow(hr);
  1180. }
  1181. WsbAffirmHr(hr);
  1182. m_MountedMedia = l_MediaToMount;
  1183. WsbTrace( OLESTR("Mount completed.\n") );
  1184. WsbAffirmHr(GetMediaParameters());
  1185. }
  1186. }WsbCatchAndDo(hr,
  1187. switch (hr){case HSM_E_STG_PL_NOT_CFGD:case HSM_E_STG_PL_INVALID:
  1188. FailJob(pWorkItem);
  1189. break;case RMS_E_CARTRIDGE_DISABLED:
  1190. WsbLogEvent(HSM_MESSAGE_MEDIA_DISABLED, 0, NULL, pMediaName, NULL);
  1191. break;
  1192. default:
  1193. break;}
  1194. );
  1195. WsbTraceOut(OLESTR("CHsmRecallQueue::MountMedia"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  1196. return(hr);
  1197. }
  1198. HRESULT
  1199. CHsmRecallQueue::GetSource(
  1200. IFsaPostIt *pFsaWorkItem,
  1201. OLECHAR **pSourceString
  1202. )
  1203. /*++
  1204. Routine Description:
  1205. This function builds the Source file name
  1206. Arguments:
  1207. pFsaWorkItem - the item to be migrated
  1208. pSourceString - the Source file name.
  1209. Return Value:
  1210. S_OK
  1211. --*/ {
  1212. HRESULT hr = S_OK;
  1213. CComPtr<IFsaResource> pResource;
  1214. CWsbStringPtr tmpString;
  1215. CComPtr<IHsmSession> pSession;
  1216. CWsbStringPtr path;
  1217. WsbTraceIn(OLESTR("CHsmRecallQueue::GetSource"),OLESTR(""));
  1218. try {
  1219. //
  1220. // Get the real session pointer from the IUnknown
  1221. //
  1222. WsbAffirmHr(pFsaWorkItem->GetSession(&pSession));
  1223. WsbAffirm(pSession != 0, E_POINTER);
  1224. // First get the name of the resource from the session
  1225. WsbAffirmHr(pSession->GetResource(&pResource));
  1226. WsbAffirmHr(pFsaWorkItem->GetPath(&path, 0));
  1227. tmpString.Alloc(1000);
  1228. WsbAffirmHr(pResource->GetPath(&tmpString, 0));
  1229. tmpString.Append(&(path[1]));
  1230. // tmpString.Prepend(OLESTR("\\\\?\\"));
  1231. WsbAffirmHr(tmpString.GiveTo(pSourceString));
  1232. }WsbCatch(hr);
  1233. WsbTraceOut(OLESTR("CHsmRecallQueue::GetSource"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  1234. return(hr);
  1235. }
  1236. HRESULT
  1237. CHsmRecallQueue::GetScanItem(
  1238. IFsaPostIt *pFsaWorkItem,
  1239. IFsaScanItem ** ppIFsaScanItem
  1240. )
  1241. {
  1242. HRESULT hr = S_OK;
  1243. CWsbStringPtr path;
  1244. CComPtr<IHsmSession> pSession;
  1245. CComPtr<IFsaResource> pFsaResource;
  1246. WsbTraceIn(OLESTR("CHsmRecallQueue::GetScanItem"),OLESTR(""));
  1247. try {
  1248. WsbAffirmPointer(ppIFsaScanItem);
  1249. WsbAffirm(!*ppIFsaScanItem, E_INVALIDARG);
  1250. WsbAffirmHr(pFsaWorkItem->GetSession(&pSession));
  1251. WsbAffirmHr(pSession->GetResource(&pFsaResource));
  1252. WsbAffirmHr(pFsaWorkItem->GetPath(&path, 0));
  1253. WsbAffirmHr(pFsaResource->FindFirst(path, pSession, ppIFsaScanItem));
  1254. }WsbCatch (hr)
  1255. WsbTraceOut(OLESTR("CHsmRecallQueue::GetScanItem"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  1256. return( hr );
  1257. }
  1258. DWORD HsmRecallQueueThread(
  1259. void *pVoid
  1260. )
  1261. /*++
  1262. --*/ {
  1263. HRESULT hr;
  1264. hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  1265. hr = ((CHsmRecallQueue*) pVoid)->DoWork();
  1266. CoUninitialize();
  1267. return(hr);
  1268. }
  1269. HRESULT
  1270. CHsmRecallQueue::SetState(
  1271. IN HSM_JOB_STATE state,
  1272. IN HSM_JOB_PHASE phase,
  1273. IN IHsmSession * pSession
  1274. )
  1275. /*++
  1276. --*/
  1277. {
  1278. HRESULT hr = S_OK;
  1279. BOOL bLog = TRUE;
  1280. WsbTraceIn(OLESTR("CHsmRecallQueue:SetState"), OLESTR("state = <%ls>"), JobStateAsString( state ) );
  1281. try {
  1282. //
  1283. // Change the state and report the change to the session. Unless the current state is
  1284. // failed then leave it failed. Is is necessary because when this guy fails, it will
  1285. // cancel all sessions so that no more work is sent in and so we will skip any queued work.
  1286. // If the current state is failed, we don't need to spit out the failed message every time,
  1287. // so we send ProcessState a false fullmessage unless the state is cancelled.
  1288. //
  1289. WsbAffirmHr(pSession->ProcessState(phase, state, m_CurrentPath, TRUE));
  1290. }WsbCatch(hr);
  1291. WsbTraceOut(OLESTR("CHsmRecallQueue::SetState"), OLESTR("hr = <%ls> "), WsbHrAsString(hr));
  1292. return(hr);
  1293. }
  1294. HRESULT
  1295. CHsmRecallQueue::Cancel(
  1296. IN HSM_JOB_PHASE jobPhase,
  1297. IN IHsmSession *pSession
  1298. )
  1299. /*++
  1300. Implements:
  1301. CHsmRecallQueue::Cancel().
  1302. --*/
  1303. {
  1304. HRESULT hr = S_OK;
  1305. UNREFERENCED_PARAMETER(pSession);
  1306. WsbTraceIn(OLESTR("CHsmRecallQueue::Cancel"), OLESTR(""));
  1307. (void)SetState(HSM_JOB_STATE_CANCELLING, jobPhase, pSession);
  1308. try {
  1309. //
  1310. // This needs to be prepended and the queue emptied out!
  1311. //
  1312. CComPtr<IHsmRecallItem> pWorkItem;
  1313. CComPtr<IFsaPostIt> pFsaWorkItem;
  1314. WsbAffirmHr(m_pHsmServerCreate->CreateInstance(CLSID_CHsmRecallItem, IID_IHsmRecallItem,
  1315. (void **)&pWorkItem));
  1316. //
  1317. // Create the minimal postit needed to contain the session so that DoWork
  1318. // can retrieve it from the work item.
  1319. // TBD: make pSession a member of CHsmRecallItem, so that we don't need
  1320. // to keep obtaining it via the IFsaPostIt. Also it saves us the trouble
  1321. // of creating a dummy FsaPostIt here.
  1322. //
  1323. WsbAffirmHr(m_pHsmServerCreate->CreateInstance(CLSID_CFsaPostIt, IID_IFsaPostIt,
  1324. (void **)&pFsaWorkItem));
  1325. WsbAffirmHr(pWorkItem->SetWorkType(HSM_WORK_ITEM_MOVER_CANCELLED));
  1326. WsbAffirmHr(pWorkItem->SetJobPhase(jobPhase));
  1327. WsbAffirmHr(pWorkItem->SetFsaPostIt(pFsaWorkItem));
  1328. WsbAffirmHr(pFsaWorkItem->SetSession(pSession));
  1329. //
  1330. // Our work item is ready now, ship it
  1331. //
  1332. WsbAffirmHr(m_pWorkToDo->Prepend(pWorkItem));
  1333. }WsbCatch(hr);
  1334. WsbTraceOut(OLESTR("CHsmRecallQueue::Cancel"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1335. return(hr);
  1336. }
  1337. HRESULT
  1338. CHsmRecallQueue::FailJob(
  1339. IHsmRecallItem *pWorkItem
  1340. )
  1341. /*++
  1342. Implements:
  1343. CHsmRecallQueue::FailJob().
  1344. --*/
  1345. {
  1346. HRESULT hr = S_OK;
  1347. CComPtr<IHsmSession> pSession;
  1348. CComPtr<IFsaPostIt> pFsaWorkItem;
  1349. HSM_JOB_PHASE jobPhase;
  1350. WsbTraceIn(OLESTR("CHsmRecallQueue::FailJob"), OLESTR(""));
  1351. try {
  1352. //
  1353. // Set our state to failed and then cancel all work
  1354. //
  1355. WsbAffirmHr(pWorkItem->GetFsaPostIt(&pFsaWorkItem));
  1356. WsbAffirmHr(pFsaWorkItem->GetSession(&pSession));
  1357. WsbAffirmHr(pWorkItem->GetJobPhase(&jobPhase));
  1358. WsbAffirmHr(SetState(HSM_JOB_STATE_FAILED, jobPhase, pSession));
  1359. if (pSession != 0) {
  1360. WsbAffirmHr(pSession->Cancel( HSM_JOB_PHASE_ALL ));
  1361. }
  1362. }WsbCatch(hr);
  1363. WsbTraceOut(OLESTR("CHsmRecallQueue::FailJob"), OLESTR("hr = <%ls>"), WsbHrAsString(hr) );
  1364. return(hr);
  1365. }
  1366. void
  1367. CHsmRecallQueue::ReportMediaProgress(
  1368. HSM_JOB_MEDIA_STATE state,
  1369. HRESULT /*status*/
  1370. )
  1371. /*++
  1372. Implements:
  1373. CHsmRecallQueue::ReportMediaProgress().
  1374. --*/
  1375. {
  1376. HRESULT hr = S_OK;
  1377. CWsbStringPtr mediaName;
  1378. HSM_JOB_MEDIA_TYPE mediaType = HSM_JOB_MEDIA_TYPE_UNKNOWN;
  1379. UNREFERENCED_PARAMETER(state);
  1380. WsbTraceIn(OLESTR("CHsmRecallQueue::ReportMediaProgress"), OLESTR(""));
  1381. //
  1382. // TBD : we have to figure out a way to report media progress!
  1383. // Without the session pointer this is tough..
  1384. //
  1385. // Report Progress but we don't really care if it succeeds.
  1386. // hr = m_pSession->ProcessMediaState(m_JobPhase, state, m_MediaName, m_MediaType, 0);
  1387. WsbTraceOut(OLESTR("CHsmRecallQueue::ReportMediaProgress"), OLESTR("hr = <%ls>"), WsbHrAsString(hr) );
  1388. }
  1389. HRESULT
  1390. CHsmRecallQueue::GetMediaParameters( void )
  1391. /*++
  1392. Implements:
  1393. CHsmRecallQueue::GetMediaParameters
  1394. --*/ {
  1395. HRESULT hr = S_OK;
  1396. LONG rmsCartridgeType;
  1397. CWsbBstrPtr barCode;
  1398. WsbTraceIn(OLESTR("CHsmRecallQueue::GetMediaParameters"), OLESTR(""));
  1399. try {
  1400. //
  1401. // Get some information about the media
  1402. //
  1403. WsbAffirmHr(m_pDataMover->GetLargestFreeSpace( &m_MediaFreeSpace, &m_MediaCapacity ));
  1404. WsbAffirmHr(m_pRmsCartridge->GetType( &rmsCartridgeType ));
  1405. WsbAffirmHr(ConvertRmsCartridgeType(rmsCartridgeType, &m_MediaType));
  1406. WsbAffirmHr(m_pRmsCartridge->GetName(&barCode));
  1407. WsbAffirmHr(CoFileTimeNow(&m_MediaUpdate));
  1408. m_MediaBarCode = barCode;
  1409. }WsbCatch(hr);
  1410. WsbTraceOut(OLESTR("CHsmRecallQueue::GetMediaParameters"), OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  1411. return(hr);
  1412. }
  1413. HRESULT
  1414. CHsmRecallQueue::DismountMedia( BOOL bNoDelay)
  1415. /*++
  1416. Implements:
  1417. CHsmRecallQueue::DismountMedia
  1418. --*/ {
  1419. HRESULT hr = S_OK;
  1420. WsbTraceIn(OLESTR("CHsmRecallQueue::DismountMedia"), OLESTR(""));
  1421. try {
  1422. if ((m_pRmsCartridge != 0) && (m_MountedMedia != GUID_NULL)) {
  1423. //
  1424. // End the session with the data mover. If this doesn't work, report
  1425. // the problem but continue with the dismount.
  1426. //
  1427. //
  1428. // Tell the session that we are dismounting media. Ignore any problems
  1429. // with the reporting
  1430. //
  1431. (void )ReportMediaProgress(HSM_JOB_MEDIA_STATE_DISMOUNTING, S_OK);
  1432. //
  1433. // Dismount the cartridge and report progress
  1434. //
  1435. // !!! IMPORTANT NOTE !!!
  1436. //
  1437. // Must free Rms resources used before dismounting...
  1438. //
  1439. m_pRmsCartridge = 0;
  1440. m_pDataMover = 0;
  1441. DWORD dwOptions = RMS_NONE;
  1442. if (bNoDelay) {
  1443. dwOptions |= RMS_DISMOUNT_DEFERRED_ONLY;
  1444. }
  1445. hr = m_pRmsServer->DismountCartridge(m_MountedMedia, dwOptions);
  1446. (void) ReportMediaProgress(HSM_JOB_MEDIA_STATE_DISMOUNTED, hr);
  1447. //
  1448. // Clear out the knowledge of media that was just dismounted
  1449. //
  1450. WsbAffirmHr(UnsetMediaInfo());
  1451. WsbAffirmHr(hr);
  1452. WsbTrace( OLESTR("Dismount completed OK.\n") );
  1453. } else {
  1454. WsbTrace( OLESTR("There is no media to dismount.\n") );
  1455. }
  1456. }WsbCatch(hr);
  1457. WsbTraceOut(OLESTR("CHsmRecallQueue::DismountMedia"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1458. return(hr);
  1459. }
  1460. HRESULT
  1461. CHsmRecallQueue::ConvertRmsCartridgeType(
  1462. LONG rmsCartridgeType,
  1463. HSM_JOB_MEDIA_TYPE *pMediaType
  1464. )
  1465. /*++
  1466. Implements:
  1467. CHsmRecallQueue::ConvertRmsCartridgeType
  1468. --*/ {
  1469. HRESULT hr = S_OK;
  1470. WsbTraceIn(OLESTR("CHsmRecallQueue::ConvertRmsCartridgeType"), OLESTR(""));
  1471. try {
  1472. WsbAssert(0 != pMediaType, E_POINTER);
  1473. switch (rmsCartridgeType) {
  1474. case RmsMedia8mm:
  1475. case RmsMedia4mm:
  1476. case RmsMediaDLT:
  1477. case RmsMediaTape:
  1478. *pMediaType = HSM_JOB_MEDIA_TYPE_TAPE;
  1479. break;
  1480. case RmsMediaOptical:
  1481. case RmsMediaMO35:
  1482. case RmsMediaWORM:
  1483. case RmsMediaCDR:
  1484. case RmsMediaDVD:
  1485. *pMediaType = HSM_JOB_MEDIA_TYPE_OPTICAL;
  1486. break;
  1487. case RmsMediaDisk:
  1488. *pMediaType = HSM_JOB_MEDIA_TYPE_REMOVABLE_MAG;
  1489. break;
  1490. case RmsMediaFixed:
  1491. *pMediaType = HSM_JOB_MEDIA_TYPE_FIXED_MAG;
  1492. break;
  1493. case RmsMediaUnknown:default:
  1494. *pMediaType = HSM_JOB_MEDIA_TYPE_UNKNOWN;
  1495. break;
  1496. }
  1497. }WsbCatch( hr );
  1498. WsbTraceOut(OLESTR("CHsmRecallQueue::ConvertRmsCartridgeType"), OLESTR("hr = <%ls>"),
  1499. WsbHrAsString(hr));
  1500. return(hr);
  1501. }
  1502. HRESULT
  1503. CHsmRecallQueue::MarkWorkItemAsDone(IN IHsmSession *pSession,
  1504. IN HSM_JOB_PHASE jobPhase)
  1505. /*++
  1506. Implements:
  1507. CHsmRecallQueue::MarkWorkItemAsDone
  1508. --*/
  1509. {
  1510. HRESULT hr = S_OK;
  1511. WsbTraceIn(OLESTR("CHsmRecallQueue::MarkWorkItemAsDone"), OLESTR(""));
  1512. try {
  1513. // Create a work item and append it to the work queue to
  1514. // indicate that the job is done
  1515. CComPtr<IHsmRecallItem> pWorkItem;
  1516. CComPtr<IFsaPostIt> pFsaWorkItem;
  1517. WsbAffirmHr(m_pHsmServerCreate->CreateInstance(CLSID_CHsmRecallItem, IID_IHsmRecallItem,
  1518. (void **)&pWorkItem));
  1519. //
  1520. // Create the minimal postit needed to contain the session so that DoWork
  1521. // can retrieve it from the work item.
  1522. // TBD: make pSession a member of CHsmRecallItem, so that we don't need
  1523. // to keep obtaining it via the IFsaPostIt. Also it saves us the trouble
  1524. // of creating a dummy FsaPostIt here.
  1525. //
  1526. WsbAffirmHr(m_pHsmServerCreate->CreateInstance(CLSID_CFsaPostIt, IID_IFsaPostIt,
  1527. (void **)&pFsaWorkItem));
  1528. WsbAffirmHr(pWorkItem->SetWorkType(HSM_WORK_ITEM_FSA_DONE));
  1529. WsbAffirmHr(pWorkItem->SetJobPhase(jobPhase));
  1530. WsbAffirmHr(pWorkItem->SetFsaPostIt(pFsaWorkItem));
  1531. WsbAffirmHr(pFsaWorkItem->SetSession(pSession));
  1532. //
  1533. // Our work item is ready now, ship it
  1534. //
  1535. WsbAffirmHr(m_pWorkToDo->Append(pWorkItem));
  1536. }WsbCatch(hr);
  1537. WsbTraceOut(OLESTR("CHsmRecallQueue::MarkWorkItemAsDone"), OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  1538. return(hr);
  1539. }
  1540. HRESULT
  1541. CHsmRecallQueue::CheckRegistry(void)
  1542. {
  1543. HRESULT hr = S_OK;
  1544. WsbTraceIn(OLESTR("CHsmRecallQueue::CheckRegistry"), OLESTR(""));
  1545. try {
  1546. // Check for change to number of errors to allow before cancelling
  1547. // a job
  1548. WsbAffirmHr(WsbRegistryValueUlongAsString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_JOB_ABORT_CONSECUTIVE_ERRORS,
  1549. &m_JobAbortMaxConsecutiveErrors));
  1550. WsbTrace(OLESTR("CHsmRecallQueue::CheckRegistry: m_JobAbortMaxConsecutiveErrors = %lu\n"),
  1551. m_JobAbortMaxConsecutiveErrors);
  1552. WsbAffirmHr(WsbRegistryValueUlongAsString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_JOB_ABORT_TOTAL_ERRORS,
  1553. &m_JobAbortMaxTotalErrors));
  1554. WsbTrace(OLESTR("CHsmRecallQueue::CheckRegistry: m_JobAbortMaxTotalErrors = %lu\n"),
  1555. m_JobAbortMaxTotalErrors);
  1556. }WsbCatch( hr );
  1557. WsbTraceOut(OLESTR("CHsmRecallQueue::CheckRegistry"), OLESTR("hr = <%ls>"),
  1558. WsbHrAsString(hr));
  1559. return( hr );
  1560. }
  1561. HRESULT
  1562. CHsmRecallQueue::TranslateRmsMountHr(
  1563. HRESULT rmsMountHr
  1564. )
  1565. /*++
  1566. --*/
  1567. {
  1568. HRESULT hr = S_OK;
  1569. WsbTraceIn(OLESTR("CHsmRecallQueue::TranslateRmsMountHr"),OLESTR("rms hr = <%ls>"), WsbHrAsString(rmsMountHr));
  1570. try {
  1571. switch (rmsMountHr) {
  1572. case S_OK:
  1573. hr = S_OK;
  1574. ReportMediaProgress(HSM_JOB_MEDIA_STATE_MOUNTED, hr);
  1575. break;
  1576. case RMS_E_MEDIASET_NOT_FOUND:
  1577. if (m_RmsMediaSetId == GUID_NULL) {
  1578. hr = HSM_E_STG_PL_NOT_CFGD;
  1579. } else {
  1580. hr = HSM_E_STG_PL_INVALID;
  1581. }
  1582. ReportMediaProgress(HSM_JOB_MEDIA_STATE_UNAVAILABLE, hr);
  1583. break;
  1584. case RMS_E_SCRATCH_NOT_FOUND:
  1585. hr = HSM_E_NO_MORE_MEDIA;
  1586. ReportMediaProgress(HSM_JOB_MEDIA_STATE_UNAVAILABLE, hr);
  1587. break;
  1588. case RMS_E_CARTRIDGE_UNAVAILABLE:
  1589. case RMS_E_RESOURCE_UNAVAILABLE:
  1590. case RMS_E_DRIVE_UNAVAILABLE:
  1591. case RMS_E_LIBRARY_UNAVAILABLE:
  1592. hr = HSM_E_MEDIA_NOT_AVAILABLE;
  1593. ReportMediaProgress(HSM_JOB_MEDIA_STATE_UNAVAILABLE, hr);
  1594. break;
  1595. case RMS_E_CARTRIDGE_BUSY:
  1596. case RMS_E_RESOURCE_BUSY:
  1597. case RMS_E_DRIVE_BUSY:
  1598. hr = HSM_E_MEDIA_BUSY;
  1599. ReportMediaProgress(HSM_JOB_MEDIA_STATE_BUSY, hr);
  1600. break;
  1601. case RMS_E_CARTRIDGE_NOT_FOUND:
  1602. case RMS_E_CARTRIDGE_DISABLED:
  1603. case RMS_E_TIMEOUT:
  1604. hr = rmsMountHr;
  1605. ReportMediaProgress(HSM_JOB_MEDIA_STATE_UNAVAILABLE, hr);
  1606. break;
  1607. default:
  1608. hr = rmsMountHr;
  1609. ReportMediaProgress(HSM_JOB_MEDIA_STATE_UNAVAILABLE, hr);
  1610. break;
  1611. }
  1612. }WsbCatch( hr );
  1613. WsbTraceOut(OLESTR("CHsmRecallQueue::TranslateRmsMountHr"),
  1614. OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1615. return(hr);
  1616. }
  1617. HRESULT
  1618. CHsmRecallQueue::Remove(
  1619. IHsmRecallItem *pWorkItem
  1620. )
  1621. /*++
  1622. Implements:
  1623. IHsmFsaTskMgr::Remove
  1624. --*/
  1625. {
  1626. HRESULT hr = S_OK;
  1627. WsbTraceIn(OLESTR("CHsmRecallQueue::Remove"),OLESTR(""));
  1628. try {
  1629. //
  1630. // Remove the item from the queue
  1631. //
  1632. (void)m_pWorkToDo->RemoveAndRelease(pWorkItem);
  1633. }WsbCatch (hr);
  1634. WsbTraceOut(OLESTR("CHsmRecallQueue::Remove"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  1635. return(hr);
  1636. }
  1637. HRESULT
  1638. CHsmRecallQueue::ChangeSysState(
  1639. IN OUT HSM_SYSTEM_STATE* pSysState
  1640. )
  1641. /*++
  1642. Implements:
  1643. IHsmSystemState::ChangeSysState().
  1644. --*/
  1645. {
  1646. HRESULT hr = S_OK;
  1647. WsbTraceIn(OLESTR("CHsmRecallQueue::ChangeSysState"), OLESTR(""));
  1648. try {
  1649. if (pSysState->State & HSM_STATE_SUSPEND) {
  1650. // Should have already been paused via the job}else if (pSysState->State & HSM_STATE_RESUME){
  1651. // Should have already been resumed via the job}else if (pSysState->State & HSM_STATE_SHUTDOWN){
  1652. // Release the thread (we assume it has been stopped already)
  1653. if (m_WorkerThread) {
  1654. CloseHandle(m_WorkerThread);
  1655. m_WorkerThread = 0;
  1656. }
  1657. if (m_pDataMover) {
  1658. //
  1659. // Cancel any active I/O
  1660. //
  1661. (void) m_pDataMover->Cancel();
  1662. }
  1663. /* TBD
  1664. // If Session is valid - unadvise and free session, otherwise, just try to
  1665. // dismount media if it is mounted (which we don't know at this point)
  1666. // Best effort dismount, no error checking so following resources will get released.
  1667. if (m_pSession != 0) {
  1668. EndSessions(FALSE, TRUE);
  1669. } else {
  1670. (void) DismountMedia(TRUE);
  1671. }
  1672. */
  1673. (void) DismountMedia(TRUE);
  1674. }
  1675. }WsbCatch(hr);
  1676. WsbTraceOut(OLESTR("CHsmRecallQueue::ChangeSysState"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1677. return(hr);
  1678. }
  1679. HRESULT
  1680. CHsmRecallQueue::EndRecallSession(
  1681. IN IHsmRecallItem *pWorkItem,
  1682. IN BOOL cancelled
  1683. )
  1684. {
  1685. HRESULT hr = S_OK;
  1686. CComPtr<IFsaPostIt> pFsaWorkItem;
  1687. DWORD stateCookie;
  1688. DWORD eventCookie;
  1689. ULONG refCount;
  1690. WsbTraceIn(OLESTR("CHsmRecallQueue::EndRecallSession"),OLESTR(""));
  1691. try {
  1692. HRESULT dismountHr = S_OK;
  1693. CComPtr<IConnectionPointContainer> pCPC;
  1694. CComPtr<IConnectionPoint> pCP;
  1695. CComPtr<IHsmSession> pSession;
  1696. HSM_JOB_PHASE jobPhase;
  1697. //
  1698. // Get the session
  1699. //
  1700. WsbAffirmHr(pWorkItem->GetFsaPostIt(&pFsaWorkItem));
  1701. WsbAffirmHr(pFsaWorkItem->GetSession(&pSession));
  1702. WsbAffirmHr(pWorkItem->GetStateCookie(&stateCookie));
  1703. WsbAffirmHr(pWorkItem->GetEventCookie(&eventCookie));
  1704. WsbAffirmHr(pWorkItem->GetJobPhase(&jobPhase));
  1705. //
  1706. // Tell the session that we don't want to be advised anymore.
  1707. //
  1708. try {
  1709. WsbAffirmHr(pSession->QueryInterface(IID_IConnectionPointContainer, (void**) &pCPC));
  1710. WsbAffirmHr(pCPC->FindConnectionPoint(IID_IHsmSessionSinkEveryState, &pCP));
  1711. refCount = (((IUnknown *) (IHsmFsaTskMgr *) this)->AddRef()) - 1;
  1712. ((IUnknown *) (IHsmFsaTskMgr *)this)->Release();
  1713. WsbTrace(OLESTR("REFCOUNT for CHsmRecallQueue before stateCookie UnAdvise: %ls \n"), WsbLongAsString((LONG) refCount));
  1714. WsbAffirmHr(pCP->Unadvise(stateCookie));
  1715. }WsbCatch( hr );
  1716. refCount = (((IUnknown *) (IHsmFsaTskMgr *) this)->AddRef()) - 1;
  1717. ((IUnknown *) (IHsmFsaTskMgr *)this)->Release();
  1718. WsbTrace(OLESTR("REFCOUNT for CHsmRecallQueue after stateCookie UnAdvise: %ls \n"), WsbLongAsString((LONG) refCount));
  1719. pCPC = 0;
  1720. pCP = 0;
  1721. refCount = (((IUnknown *) (IHsmFsaTskMgr *) this)->AddRef()) - 1;
  1722. ((IUnknown *) (IHsmFsaTskMgr *)this)->Release();
  1723. WsbTrace(OLESTR("REFCOUNT for CHsmRecallQueue before eventCookie UnAdvise: %ls \n"), WsbLongAsString((LONG) refCount));
  1724. try {
  1725. WsbAffirmHr(pSession->QueryInterface(IID_IConnectionPointContainer, (void**) &pCPC));
  1726. WsbAffirmHr(pCPC->FindConnectionPoint(IID_IHsmSessionSinkEveryEvent, &pCP));
  1727. WsbAffirmHr(pCP->Unadvise(eventCookie));
  1728. }WsbCatch( hr );
  1729. refCount = (((IUnknown *) (IHsmFsaTskMgr *) this)->AddRef()) - 1;
  1730. ((IUnknown *) (IHsmFsaTskMgr *)this)->Release();
  1731. WsbTrace(OLESTR("REFCOUNT for CHsmRecallQueue after eventCookie UnAdvise: %ls \n"), WsbLongAsString((LONG) refCount));
  1732. pCPC = 0;
  1733. pCP = 0;
  1734. WsbTrace( OLESTR("Telling Session Data mover is done\n") );
  1735. if (cancelled) {
  1736. (void)SetState(HSM_JOB_STATE_DONE, jobPhase, pSession);
  1737. } else {
  1738. (void)SetState(HSM_JOB_STATE_CANCELLED, jobPhase, pSession);
  1739. }
  1740. pSession = 0;
  1741. WsbAffirmHr(hr);
  1742. }WsbCatch (hr);
  1743. WsbTraceOut(OLESTR("CHsmRecallQueue::EndRecallSession"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  1744. return(hr);
  1745. }
  1746. HRESULT
  1747. CHsmRecallQueue::UnsetMediaInfo( void )
  1748. /*++
  1749. Routine Description:
  1750. Sets the media data members back to their default (unset) values.
  1751. Arguments:
  1752. None.
  1753. Return Value:
  1754. S_OK: Ok.
  1755. --*/
  1756. {
  1757. HRESULT hr = S_OK;
  1758. WsbTraceIn(OLESTR("CHsmRecallQueue::UnsetMediaInfo"), OLESTR(""));
  1759. m_MediaId = GUID_NULL;
  1760. m_MountedMedia = GUID_NULL;
  1761. m_MediaType = HSM_JOB_MEDIA_TYPE_UNKNOWN;
  1762. m_MediaName = OLESTR("");
  1763. m_MediaBarCode = OLESTR("");
  1764. m_MediaFreeSpace = 0;
  1765. m_MediaCapacity = 0;
  1766. m_MediaReadOnly = FALSE;
  1767. m_MediaUpdate = WsbLLtoFT(0);
  1768. WsbTraceOut(OLESTR("CHsmRecallQueue::UnsetMediaInfo"), OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  1769. return(hr);
  1770. }
  1771. HRESULT
  1772. CHsmRecallQueue::GetMediaId (OUT GUID *mediaId)
  1773. /*++
  1774. Routine Description:
  1775. Gets the media id for the queue
  1776. Arguments:
  1777. None.
  1778. Return Value:
  1779. S_OK: Ok.
  1780. --*/
  1781. {
  1782. HRESULT hr = S_OK;
  1783. WsbTraceIn(OLESTR("CHsmRecallQueue::GetMediaId"), OLESTR(""));
  1784. *mediaId = m_MediaId;
  1785. WsbTraceOut(OLESTR("CHsmRecallQueue::GetMediaId"),OLESTR("hr = <%ls>, Id = <%ls>"),
  1786. WsbHrAsString(hr), WsbPtrToGuidAsString(mediaId));
  1787. return(hr);
  1788. }
  1789. HRESULT
  1790. CHsmRecallQueue::SetMediaId (IN GUID *mediaId)
  1791. /*++
  1792. Routine Description:
  1793. Sets the media id for the queue
  1794. Arguments:
  1795. None.
  1796. Return Value:
  1797. S_OK: Ok.
  1798. --*/
  1799. {
  1800. HRESULT hr = S_OK;
  1801. WsbTraceIn(OLESTR("CHsmRecallQueue::SetMediaId"), OLESTR(""));
  1802. m_MediaId = *mediaId;
  1803. WsbTraceOut(OLESTR("CHsmRecallQueue::SetMediaId"),OLESTR("hr = <%ls>, Id = <%ls>"),
  1804. WsbHrAsString(hr), WsbPtrToGuidAsString(mediaId));
  1805. return(hr);
  1806. }
  1807. HRESULT
  1808. CHsmRecallQueue::IsEmpty ( void )
  1809. /*++
  1810. Routine Description:
  1811. Checks if the queue is empty
  1812. Arguments:
  1813. None.
  1814. Return Value:
  1815. S_OK: Queue is empty
  1816. S_FALSE: Queue is non-empty
  1817. --*/
  1818. {
  1819. HRESULT hr;
  1820. hr = m_pWorkToDo->IsEmpty();
  1821. return(hr);
  1822. }
  1823. HRESULT
  1824. CHsmRecallQueue::FindRecallItemToCancel(
  1825. IHsmRecallItem *pWorkItem,
  1826. IHsmRecallItem **pWorkItemToCancel
  1827. )
  1828. /*++
  1829. Routine Description:
  1830. Pulls the work item that needs to be cancelled
  1831. indicated by pWorkItem and returns it
  1832. (by matching the pSession pointer)
  1833. Arguments:
  1834. None.
  1835. Return Value:
  1836. --*/
  1837. {
  1838. CComPtr<IFsaPostIt> pFsaWorkItem;
  1839. CComPtr<IHsmSession> pSession;
  1840. CComPtr<IHsmSession> pWorkSession;
  1841. HRESULT hr;
  1842. ULONG index = 0;
  1843. WsbTraceIn(OLESTR("CHsmRecallQueue::FindRecallItemToCancel"), OLESTR(""));
  1844. pWorkItem->GetFsaPostIt(&pFsaWorkItem);
  1845. pFsaWorkItem->GetSession(&pSession);
  1846. pFsaWorkItem = 0;
  1847. do {
  1848. hr = m_pWorkToDo->At(index, IID_IHsmRecallItem, (void **)pWorkItemToCancel);
  1849. if (S_OK == hr) {
  1850. (*pWorkItemToCancel)->GetFsaPostIt(&pFsaWorkItem);
  1851. pFsaWorkItem->GetSession(&pWorkSession);
  1852. if ((pWorkItem != (*pWorkItemToCancel)) && (pSession == pWorkSession)) {
  1853. WsbTrace(OLESTR("CHsmRecallQueue::FindRecallItemToCancel: Found item to cancel, pSession = %p\n"), pSession);
  1854. break;
  1855. }
  1856. (*pWorkItemToCancel)->Release();
  1857. (*pWorkItemToCancel) = 0;
  1858. pWorkSession = 0;
  1859. pFsaWorkItem = 0;
  1860. }
  1861. index++;
  1862. } while (S_OK == hr);
  1863. WsbTraceOut(OLESTR("CHsmRecallQueue::FindRecallItemToCancel"), OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  1864. return hr;
  1865. }