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.

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