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.

1664 lines
37 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Copyright (c) 1997-1999 Microsoft Corporation
  4. //
  5. // File: wkstore.cpp
  6. //
  7. // Contents: Persistent job store routine.
  8. //
  9. // History:
  10. //
  11. //---------------------------------------------------------------------------
  12. #include "pch.cpp"
  13. #include "server.h"
  14. #include "jobmgr.h"
  15. #include "tlsjob.h"
  16. #include "wkstore.h"
  17. #include "debug.h"
  18. WORKOBJECTINITFUNC g_WorkObjectInitFunList[] = {
  19. {WORKTYPE_RETURN_LICENSE, InitializeCReturnWorkObject }
  20. };
  21. DWORD g_NumWorkObjectInitFunList = sizeof(g_WorkObjectInitFunList) / sizeof(g_WorkObjectInitFunList[0]);
  22. //---------------------------------------------------
  23. //
  24. CLASS_PRIVATE
  25. CWorkObject*
  26. CPersistentWorkStorage::InitializeWorkObject(
  27. IN DWORD dwWorkType,
  28. IN PBYTE pbData,
  29. IN DWORD cbData
  30. )
  31. /*++
  32. --*/
  33. {
  34. DBGPrintf(
  35. DBG_INFORMATION,
  36. DBG_FACILITY_WORKMGR,
  37. DBGLEVEL_FUNCTION_TRACE,
  38. _TEXT("CPersistentWorkStorage::InitializeWorkObject() initializing work %d\n"),
  39. dwWorkType
  40. );
  41. CWorkObject* ptr = NULL;
  42. DWORD dwStatus = ERROR_SUCCESS;
  43. try {
  44. for(DWORD index =0; index < g_NumWorkObjectInitFunList; index ++)
  45. {
  46. if(dwWorkType == g_WorkObjectInitFunList[index].m_WorkType)
  47. {
  48. ptr = (g_WorkObjectInitFunList[index].m_WorkInitFunc)(
  49. GetWorkManager(),
  50. pbData,
  51. cbData
  52. );
  53. break;
  54. }
  55. }
  56. if(index >= g_NumWorkObjectInitFunList)
  57. {
  58. SetLastError(dwStatus = TLS_E_WORKSTORAGE_UNKNOWNWORKTYPE);
  59. }
  60. else
  61. {
  62. TLSWorkManagerSetJobDefaults(ptr);
  63. }
  64. }
  65. catch( SE_Exception e ) {
  66. SetLastError(dwStatus = e.getSeNumber());
  67. TLSLogEvent(
  68. EVENTLOG_ERROR_TYPE,
  69. TLS_E_WORKMANAGERGENERAL,
  70. TLS_E_WORKSTORAGE_INITWORK,
  71. dwWorkType,
  72. dwStatus
  73. );
  74. }
  75. catch(...) {
  76. SetLastError(dwStatus = TLS_E_WORKSTORAGE_INITWORKUNKNOWN);
  77. TLSLogEvent(
  78. EVENTLOG_ERROR_TYPE,
  79. TLS_E_WORKMANAGERGENERAL,
  80. TLS_E_WORKSTORAGE_INITWORKUNKNOWN,
  81. dwWorkType
  82. );
  83. }
  84. if(dwStatus != ERROR_SUCCESS)
  85. {
  86. DBGPrintf(
  87. DBG_ERROR,
  88. DBG_FACILITY_WORKMGR,
  89. DBGLEVEL_FUNCTION_DETAILSIMPLE,
  90. _TEXT("CPersistentWorkStorage::InitializeWorkObject() return 0x%08x\n"),
  91. dwStatus
  92. );
  93. }
  94. return ptr;
  95. }
  96. //---------------------------------------------------
  97. //
  98. CLASS_PRIVATE BOOL
  99. CPersistentWorkStorage::DeleteWorkObject(
  100. IN OUT CWorkObject* ptr
  101. )
  102. /*++
  103. --*/
  104. {
  105. DWORD dwStatus = ERROR_SUCCESS;
  106. DWORD dwWorkType = 0;
  107. DBGPrintf(
  108. DBG_INFORMATION,
  109. DBG_FACILITY_WORKMGR,
  110. DBGLEVEL_FUNCTION_TRACE,
  111. _TEXT("CPersistentWorkStorage::DeleteWorkObject() deleting work %s\n"),
  112. ptr->GetJobDescription()
  113. );
  114. try {
  115. dwWorkType = ptr->GetWorkType();
  116. ptr->SelfDestruct();
  117. }
  118. catch( SE_Exception e ) {
  119. SetLastError(dwStatus = e.getSeNumber());
  120. TLSLogEvent(
  121. EVENTLOG_ERROR_TYPE,
  122. TLS_E_WORKMANAGERGENERAL,
  123. TLS_E_WORKSTORAGE_DELETEWORK,
  124. dwWorkType,
  125. dwStatus
  126. );
  127. }
  128. catch(...) {
  129. SetLastError(dwStatus = TLS_E_WORKSTORAGE_DELETEWORKUNKNOWN);
  130. TLSLogEvent(
  131. EVENTLOG_ERROR_TYPE,
  132. TLS_E_WORKMANAGERGENERAL,
  133. TLS_E_WORKSTORAGE_DELETEWORKUNKNOWN,
  134. dwWorkType
  135. );
  136. }
  137. if(dwStatus != ERROR_SUCCESS)
  138. {
  139. DBGPrintf(
  140. DBG_ERROR,
  141. DBG_FACILITY_WORKMGR,
  142. DBGLEVEL_FUNCTION_DETAILSIMPLE,
  143. _TEXT("CPersistentWorkStorage::DeleteWorkObject() return 0x%08x\n"),
  144. dwStatus
  145. );
  146. }
  147. return dwStatus == ERROR_SUCCESS;
  148. }
  149. //---------------------------------------------------
  150. //
  151. CPersistentWorkStorage::CPersistentWorkStorage(
  152. IN WorkItemTable* pWkItemTable
  153. ) :
  154. m_pWkItemTable(pWkItemTable),
  155. m_dwNumJobs(0),
  156. m_dwJobsInProcesssing(0),
  157. m_dwNextJobTime(INFINITE),
  158. m_pNextWorkObject(NULL)
  159. /*++
  160. --*/
  161. {
  162. }
  163. //---------------------------------------------------
  164. //
  165. CPersistentWorkStorage::~CPersistentWorkStorage()
  166. {
  167. // just make sure we have shutdown
  168. // TLSASSERT(m_pWkItemTable == NULL);
  169. }
  170. //---------------------------------------------------
  171. //
  172. BOOL
  173. CPersistentWorkStorage::DeleteErrorJob(
  174. IN CWorkObject* ptr
  175. )
  176. /*++
  177. --*/
  178. {
  179. BOOL bSuccess = TRUE;
  180. DWORD dwStatus = ERROR_SUCCESS;
  181. PBYTE pbBookmark;
  182. DWORD cbBookmark;
  183. DWORD dwTime;
  184. DWORD dwJobType;
  185. if(IsValidWorkObject(ptr) == FALSE)
  186. {
  187. SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
  188. goto cleanup;
  189. }
  190. bSuccess = ptr->GetJobId(&pbBookmark, &cbBookmark);
  191. if(bSuccess == FALSE)
  192. {
  193. SetLastError(dwStatus = ERROR_INVALID_DATA);
  194. goto cleanup;
  195. }
  196. dwJobType = ptr->GetWorkType();
  197. m_hTableLock.Lock();
  198. bSuccess = UpdateWorkItemEntry(
  199. m_pWkItemTable,
  200. WORKITEM_DELETE,
  201. pbBookmark,
  202. cbBookmark,
  203. INFINITE,
  204. INFINITE,
  205. dwJobType,
  206. NULL,
  207. 0
  208. );
  209. if(bSuccess == FALSE)
  210. {
  211. dwStatus = GetLastError();
  212. }
  213. m_hTableLock.UnLock();
  214. DeleteWorkObject(ptr);
  215. cleanup:
  216. return bSuccess;
  217. }
  218. //---------------------------------------------------
  219. //
  220. CLASS_PRIVATE DWORD
  221. CPersistentWorkStorage::GetCurrentBookmark(
  222. IN WorkItemTable* pTable,
  223. IN PBYTE pbData,
  224. IN OUT PDWORD pcbData
  225. )
  226. /*++
  227. --*/
  228. {
  229. BOOL bSuccess = TRUE;
  230. DWORD dwStatus = ERROR_SUCCESS;
  231. if(pTable != NULL)
  232. {
  233. JET_ERR jbError;
  234. bSuccess = pTable->GetBookmark(pbData, pcbData);
  235. if(bSuccess == FALSE)
  236. {
  237. jbError = pTable->GetLastJetError();
  238. if(jbError == JET_errNoCurrentRecord)
  239. {
  240. *pcbData = 0;
  241. SetLastError(dwStatus = ERROR_NO_DATA);
  242. }
  243. else if(jbError == JET_errBufferTooSmall)
  244. {
  245. SetLastError(dwStatus = ERROR_INSUFFICIENT_BUFFER);
  246. }
  247. else
  248. {
  249. SetLastError(dwStatus = SET_JB_ERROR(jbError));
  250. }
  251. }
  252. }
  253. else
  254. {
  255. SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
  256. TLSASSERT(FALSE);
  257. }
  258. return dwStatus;
  259. }
  260. //-------------------------------------------------------------
  261. //
  262. CLASS_PRIVATE DWORD
  263. CPersistentWorkStorage::GetCurrentBookmarkEx(
  264. IN WorkItemTable* pTable,
  265. IN OUT PBYTE* ppbData,
  266. IN OUT PDWORD pcbData
  267. )
  268. /*++
  269. --*/
  270. {
  271. DWORD dwStatus = ERROR_SUCCESS;
  272. BOOL bSucess = TRUE;
  273. if(ppbData == NULL || pcbData == NULL || pTable == 0)
  274. {
  275. SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
  276. return dwStatus;
  277. }
  278. *ppbData = NULL;
  279. *pcbData = 0;
  280. dwStatus = GetCurrentBookmark(
  281. pTable,
  282. *ppbData,
  283. pcbData
  284. );
  285. if(dwStatus == ERROR_INSUFFICIENT_BUFFER)
  286. {
  287. *ppbData = (PBYTE)AllocateMemory(*pcbData);
  288. if(*ppbData != NULL)
  289. {
  290. dwStatus = GetCurrentBookmark(
  291. pTable,
  292. *ppbData,
  293. pcbData
  294. );
  295. }
  296. }
  297. if(dwStatus != ERROR_SUCCESS)
  298. {
  299. if(*ppbData != NULL)
  300. {
  301. FreeMemory(*ppbData);
  302. }
  303. *ppbData = NULL;
  304. *pcbData = 0;
  305. }
  306. return dwStatus;
  307. }
  308. //------------------------------------------------------
  309. CLASS_PRIVATE DWORD
  310. CPersistentWorkStorage::SetCurrentBookmark(
  311. IN WorkItemTable* pTable,
  312. IN PBYTE pbData,
  313. IN DWORD cbData
  314. )
  315. /*++
  316. --*/
  317. {
  318. BOOL bSuccess;
  319. DWORD dwStatus = ERROR_SUCCESS;
  320. if(pTable != NULL && pbData != NULL && cbData != 0)
  321. {
  322. bSuccess = pTable->GotoBookmark(pbData, cbData);
  323. if(bSuccess == FALSE)
  324. {
  325. if(pTable->GetLastJetError() == JET_errRecordDeleted)
  326. {
  327. SetLastError(dwStatus = ERROR_NO_DATA);
  328. }
  329. else
  330. {
  331. SetLastError(dwStatus = SET_JB_ERROR(pTable->GetLastJetError()));
  332. }
  333. }
  334. }
  335. else
  336. {
  337. SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
  338. TLSASSERT(FALSE);
  339. }
  340. return dwStatus;
  341. }
  342. //---------------------------------------------------
  343. //
  344. BOOL
  345. CPersistentWorkStorage::Shutdown()
  346. {
  347. BOOL bSuccess = TRUE;
  348. //
  349. // CWorkManager will make sure
  350. // no job is in processing state before calling this
  351. // routine and no job can be scheduled.
  352. //
  353. m_hTableLock.Lock();
  354. //
  355. // Timing.
  356. //
  357. TLSASSERT(m_dwJobsInProcesssing == 0);
  358. if(m_pWkItemTable != NULL)
  359. {
  360. bSuccess = m_pWkItemTable->CloseTable();
  361. m_pWkItemTable = NULL;
  362. }
  363. TLSASSERT(bSuccess == TRUE);
  364. m_pWkItemTable = NULL;
  365. m_dwNumJobs = 0;
  366. m_dwNextJobTime = INFINITE;
  367. if(m_pNextWorkObject != NULL)
  368. {
  369. DeleteWorkObject( m_pNextWorkObject );
  370. m_pNextWorkObject = NULL;
  371. }
  372. m_hTableLock.UnLock();
  373. return bSuccess;
  374. }
  375. //---------------------------------------------------
  376. //
  377. DWORD
  378. CPersistentWorkStorage::StartupUpdateExistingJobTime()
  379. {
  380. BOOL bSuccess;
  381. DWORD dwStatus = ERROR_SUCCESS;
  382. DWORD dwTime;
  383. DWORD dwMinTime = INFINITE;
  384. // CWorkObject* ptr = NULL;
  385. BOOL bValidJob = TRUE;
  386. DWORD dwCurrentTime;
  387. m_hTableLock.Lock();
  388. //
  389. //
  390. bSuccess = m_pWkItemTable->MoveToRecord(JET_MoveFirst);
  391. if(bSuccess == FALSE)
  392. {
  393. SetLastError(dwStatus = SET_JB_ERROR(m_pWkItemTable->GetLastJetError()));
  394. }
  395. while(dwStatus == ERROR_SUCCESS)
  396. {
  397. WORKITEMRECORD wkItem;
  398. //if(ptr != NULL)
  399. //{
  400. // DeleteWorkObject(ptr);
  401. // ptr = NULL;
  402. //}
  403. bValidJob = FALSE;
  404. //
  405. // fetch the record
  406. //
  407. bSuccess = m_pWkItemTable->FetchRecord(wkItem);
  408. if(bSuccess == FALSE)
  409. {
  410. SetLastError(dwStatus = SET_JB_ERROR(m_pWkItemTable->GetLastJetError()));
  411. continue;
  412. }
  413. if(wkItem.dwRestartTime != INFINITE && wkItem.dwScheduledTime >= m_dwStartupTime)
  414. {
  415. if(wkItem.dwScheduledTime < dwMinTime)
  416. {
  417. dwMinTime = wkItem.dwScheduledTime;
  418. }
  419. break;
  420. }
  421. //
  422. // invalid data
  423. //
  424. if(wkItem.cbData != 0 && wkItem.pbData != NULL)
  425. {
  426. if(wkItem.dwRestartTime != INFINITE)
  427. {
  428. wkItem.dwScheduledTime = wkItem.dwRestartTime + time(NULL);
  429. wkItem.dwJobType &= ~WORKTYPE_PROCESSING;
  430. bSuccess = m_pWkItemTable->UpdateRecord(
  431. wkItem,
  432. WORKITEM_PROCESS_JOBTIME | WORKITEM_PROCESS_JOBTYPE
  433. );
  434. if(bSuccess == FALSE)
  435. {
  436. SetLastError(dwStatus = SET_JB_ERROR(m_pWkItemTable->GetLastJetError()));
  437. break;
  438. }
  439. if(wkItem.dwScheduledTime < dwMinTime)
  440. {
  441. dwMinTime = wkItem.dwScheduledTime;
  442. }
  443. bValidJob = TRUE;
  444. }
  445. }
  446. if(bValidJob == FALSE)
  447. {
  448. m_pWkItemTable->DeleteRecord();
  449. }
  450. // move the record pointer
  451. bSuccess = m_pWkItemTable->MoveToRecord();
  452. if(bSuccess == FALSE)
  453. {
  454. JET_ERR jetErrCode;
  455. jetErrCode = m_pWkItemTable->GetLastJetError();
  456. if(jetErrCode != JET_errNoCurrentRecord)
  457. {
  458. SetLastError(dwStatus = SET_JB_ERROR(jetErrCode));
  459. }
  460. break;
  461. }
  462. }
  463. if(dwStatus == ERROR_SUCCESS)
  464. {
  465. bSuccess = m_pWkItemTable->MoveToRecord(JET_MoveFirst);
  466. if(bSuccess == FALSE)
  467. {
  468. SetLastError(dwStatus = SET_JB_ERROR(m_pWkItemTable->GetLastJetError()));
  469. }
  470. UpdateNextJobTime(dwMinTime);
  471. }
  472. m_hTableLock.UnLock();
  473. //if(ptr != NULL)
  474. //{
  475. // DeleteWorkObject(ptr);
  476. // ptr = NULL;
  477. //}
  478. return dwStatus;
  479. }
  480. //---------------------------------------------------
  481. //
  482. BOOL
  483. CPersistentWorkStorage::Startup(
  484. IN CWorkManager* pWkMgr
  485. )
  486. /*++
  487. --*/
  488. {
  489. BOOL bSuccess;
  490. DWORD dwStatus = ERROR_SUCCESS;
  491. CWorkStorage::Startup(pWkMgr);
  492. if(IsGood() == TRUE)
  493. {
  494. //
  495. // loop thru all workitem and count number of job
  496. //
  497. m_hTableLock.Lock();
  498. try {
  499. m_dwStartupTime = time(NULL);
  500. //
  501. // Get number of job in queue
  502. //
  503. //
  504. // GetCount() will set index to time column
  505. m_dwNumJobs = m_pWkItemTable->GetCount(
  506. FALSE,
  507. 0,
  508. NULL
  509. );
  510. if(m_dwNumJobs == 0)
  511. {
  512. UpdateNextJobTime(INFINITE);
  513. }
  514. else
  515. {
  516. bSuccess = m_pWkItemTable->BeginTransaction();
  517. if(bSuccess == TRUE)
  518. {
  519. dwStatus = StartupUpdateExistingJobTime();
  520. if(dwStatus == ERROR_SUCCESS)
  521. {
  522. m_pWkItemTable->CommitTransaction();
  523. }
  524. else
  525. {
  526. m_pWkItemTable->RollbackTransaction();
  527. }
  528. }
  529. else
  530. {
  531. dwStatus = GetLastError();
  532. }
  533. //
  534. // constructor set next job time to 0 so
  535. // work manager will immediately try to find next job
  536. //
  537. // Move to first record in table
  538. //bSuccess = m_pWkItemTable->MoveToRecord(JET_MoveFirst);
  539. }
  540. }
  541. catch( SE_Exception e ) {
  542. SetLastError(dwStatus = e.getSeNumber());
  543. }
  544. catch(...) {
  545. SetLastError(dwStatus = TLS_E_WORKMANAGER_INTERNAL);
  546. }
  547. m_hTableLock.UnLock();
  548. }
  549. else
  550. {
  551. SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
  552. }
  553. return (dwStatus == ERROR_SUCCESS);
  554. }
  555. //----------------------------------------------------
  556. //
  557. CLASS_PRIVATE BOOL
  558. CPersistentWorkStorage::IsValidWorkObject(
  559. CWorkObject* ptr
  560. )
  561. /*++
  562. --*/
  563. {
  564. BOOL bSuccess = FALSE;
  565. DWORD dwJobType;
  566. PBYTE pbData;
  567. DWORD cbData;
  568. //
  569. // Validate input parameter
  570. //
  571. if(ptr == NULL)
  572. {
  573. TLSASSERT(FALSE);
  574. goto cleanup;
  575. }
  576. dwJobType = ptr->GetWorkType();
  577. if(dwJobType == WORK_TYPE_UNKNOWN)
  578. {
  579. TLSASSERT(FALSE);
  580. goto cleanup;
  581. }
  582. ptr->GetWorkObjectData(&pbData, &cbData);
  583. if(pbData == NULL || cbData == 0)
  584. {
  585. TLSASSERT(pbData != NULL && cbData != NULL);
  586. goto cleanup;
  587. }
  588. bSuccess = TRUE;
  589. cleanup:
  590. return bSuccess;
  591. }
  592. //----------------------------------------------------
  593. //
  594. BOOL
  595. CPersistentWorkStorage::IsGood()
  596. {
  597. if( m_pWkItemTable == NULL ||
  598. m_hTableLock.IsGood() == FALSE ||
  599. GetWorkManager() == NULL )
  600. {
  601. return FALSE;
  602. }
  603. return m_pWkItemTable->IsValid();
  604. }
  605. //----------------------------------------------------
  606. //
  607. CLASS_PRIVATE BOOL
  608. CPersistentWorkStorage::UpdateJobEntry(
  609. IN WorkItemTable* pTable,
  610. IN PBYTE pbBookmark,
  611. IN DWORD cbBookmark,
  612. IN WORKITEMRECORD& wkItem
  613. )
  614. /*++
  615. --*/
  616. {
  617. BOOL bSuccess = TRUE;
  618. DWORD dwStatus = ERROR_SUCCESS;
  619. dwStatus = SetCurrentBookmark(
  620. pTable,
  621. pbBookmark,
  622. cbBookmark
  623. );
  624. if(dwStatus == ERROR_SUCCESS)
  625. {
  626. bSuccess = pTable->UpdateRecord(wkItem);
  627. }
  628. else
  629. {
  630. bSuccess = FALSE;
  631. TLSASSERT(dwStatus == ERROR_SUCCESS);
  632. }
  633. return bSuccess;
  634. }
  635. //----------------------------------------------------
  636. //
  637. CLASS_PRIVATE BOOL
  638. CPersistentWorkStorage::AddJobEntry(
  639. IN WorkItemTable* pTable,
  640. IN WORKITEMRECORD& wkItem
  641. )
  642. /*++
  643. --*/
  644. {
  645. BOOL bSuccess;
  646. bSuccess = pTable->InsertRecord(wkItem);
  647. if(bSuccess == TRUE)
  648. {
  649. m_dwNumJobs++;
  650. }
  651. return bSuccess;
  652. }
  653. //----------------------------------------------------
  654. //
  655. CLASS_PRIVATE BOOL
  656. CPersistentWorkStorage::DeleteJobEntry(
  657. IN WorkItemTable* pTable,
  658. IN PBYTE pbBookmark,
  659. IN DWORD cbBookmark,
  660. IN WORKITEMRECORD& wkItem
  661. )
  662. /*++
  663. --*/
  664. {
  665. BOOL bSuccess = TRUE;
  666. DWORD dwStatus = ERROR_SUCCESS;
  667. dwStatus = SetCurrentBookmark(
  668. pTable,
  669. pbBookmark,
  670. cbBookmark
  671. );
  672. if(dwStatus == ERROR_SUCCESS)
  673. {
  674. bSuccess = pTable->DeleteRecord();
  675. if(bSuccess == TRUE)
  676. {
  677. m_dwNumJobs--;
  678. }
  679. }
  680. else
  681. {
  682. bSuccess = FALSE;
  683. TLSASSERT(dwStatus == ERROR_SUCCESS);
  684. }
  685. return bSuccess;
  686. }
  687. //----------------------------------------------------
  688. //
  689. CLASS_PRIVATE BOOL
  690. CPersistentWorkStorage::UpdateWorkItemEntry(
  691. IN WorkItemTable* pTable,
  692. IN WORKITEM_OPERATION opCode,
  693. IN PBYTE pbBookmark,
  694. IN DWORD cbBookmark,
  695. IN DWORD dwRestartTime,
  696. IN DWORD dwTime,
  697. IN DWORD dwJobType,
  698. IN PBYTE pbJobData,
  699. IN DWORD cbJobData
  700. )
  701. /*++
  702. --*/
  703. {
  704. BOOL bSuccess = TRUE;
  705. DWORD dwStatus = ERROR_SUCCESS;
  706. WORKITEMRECORD item;
  707. PBYTE pbCurrentBookmark=NULL;
  708. DWORD cbCurrentBookmark=0;
  709. m_hTableLock.Lock();
  710. dwStatus = GetCurrentBookmarkEx(
  711. pTable,
  712. &pbCurrentBookmark,
  713. &cbCurrentBookmark
  714. );
  715. if(dwStatus != ERROR_SUCCESS && dwStatus != ERROR_NO_DATA)
  716. {
  717. goto cleanup;
  718. }
  719. bSuccess = pTable->BeginTransaction();
  720. if(bSuccess == FALSE)
  721. {
  722. dwStatus = GetLastError();
  723. goto cleanup;
  724. }
  725. item.dwScheduledTime = dwTime;
  726. item.dwRestartTime = dwRestartTime;
  727. item.dwJobType = dwJobType;
  728. item.cbData = cbJobData;
  729. item.pbData = pbJobData;
  730. switch(opCode)
  731. {
  732. case WORKITEM_ADD:
  733. TLSASSERT(cbJobData != 0 && pbJobData != NULL);
  734. m_pWkItemTable->SetInsertRepositionBookmark(
  735. (dwTime < (DWORD)m_dwNextJobTime)
  736. );
  737. bSuccess = AddJobEntry(
  738. pTable,
  739. item
  740. );
  741. break;
  742. case WORKITEM_BEGINPROCESSING:
  743. item.dwJobType |= WORKTYPE_PROCESSING;
  744. //
  745. // FALL THRU
  746. //
  747. case WORKITEM_RESCHEDULE:
  748. TLSASSERT(cbJobData != 0 && pbJobData != NULL);
  749. bSuccess = UpdateJobEntry(
  750. pTable,
  751. pbBookmark,
  752. cbBookmark,
  753. item
  754. );
  755. break;
  756. case WORKITEM_DELETE:
  757. bSuccess = DeleteJobEntry(
  758. pTable,
  759. pbBookmark,
  760. cbBookmark,
  761. item
  762. );
  763. break;
  764. default:
  765. TLSASSERT(FALSE);
  766. bSuccess = FALSE;
  767. }
  768. if(bSuccess == TRUE)
  769. {
  770. pTable->CommitTransaction();
  771. dwStatus = ERROR_SUCCESS;
  772. //
  773. // constructor set time to first job 0 so that work manager can immediate kick off
  774. //
  775. if( (opCode != WORKITEM_ADD && opCode != WORKITEM_RESCHEDULE) || dwTime > (DWORD)m_dwNextJobTime )
  776. {
  777. if(pbCurrentBookmark != NULL && cbCurrentBookmark != 0)
  778. {
  779. dwStatus = SetCurrentBookmark(
  780. pTable,
  781. pbCurrentBookmark,
  782. cbCurrentBookmark
  783. );
  784. if(dwStatus == ERROR_NO_DATA)
  785. {
  786. // record already deleted
  787. dwStatus = ERROR_SUCCESS;
  788. }
  789. else
  790. {
  791. TLSASSERT(dwStatus == ERROR_SUCCESS);
  792. }
  793. }
  794. }
  795. else
  796. {
  797. UpdateNextJobTime(dwTime);
  798. }
  799. }
  800. else
  801. {
  802. SetLastError(dwStatus = SET_JB_ERROR(pTable->GetLastJetError()));
  803. pTable->RollbackTransaction();
  804. TLSASSERT(FALSE);
  805. }
  806. cleanup:
  807. m_hTableLock.UnLock();
  808. if(pbCurrentBookmark != NULL)
  809. {
  810. FreeMemory(pbCurrentBookmark);
  811. }
  812. //
  813. // WORKITEMRECORD will try to cleanup memory
  814. //
  815. item.pbData = NULL;
  816. item.cbData = 0;
  817. return dwStatus == ERROR_SUCCESS;
  818. }
  819. //----------------------------------------------------
  820. //
  821. BOOL
  822. CPersistentWorkStorage::AddJob(
  823. IN DWORD dwTime,
  824. IN CWorkObject* ptr
  825. )
  826. /*++
  827. --*/
  828. {
  829. DWORD dwStatus = ERROR_SUCCESS;
  830. BOOL bSuccess = TRUE;
  831. PBYTE pbData;
  832. DWORD cbData;
  833. DBGPrintf(
  834. DBG_INFORMATION,
  835. DBG_FACILITY_WORKMGR,
  836. DBGLEVEL_FUNCTION_TRACE,
  837. _TEXT("CPersistentWorkStorage::AddJob() scheduling job %s at time %d\n"),
  838. ptr->GetJobDescription(),
  839. dwTime
  840. );
  841. if(IsValidWorkObject(ptr) == FALSE)
  842. {
  843. SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
  844. goto cleanup;
  845. }
  846. bSuccess = ptr->GetWorkObjectData(&pbData, &cbData);
  847. if(bSuccess == FALSE)
  848. {
  849. SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
  850. goto cleanup;
  851. }
  852. m_hTableLock.Lock();
  853. if(m_pWkItemTable != NULL)
  854. {
  855. bSuccess = UpdateWorkItemEntry(
  856. m_pWkItemTable,
  857. WORKITEM_ADD,
  858. NULL,
  859. 0,
  860. ptr->GetJobRestartTime(),
  861. dwTime + time(NULL),
  862. ptr->GetWorkType(),
  863. pbData,
  864. cbData
  865. );
  866. if(bSuccess == FALSE)
  867. {
  868. dwStatus = GetLastError();
  869. }
  870. }
  871. m_hTableLock.UnLock();
  872. cleanup:
  873. // Let Calling function delete it.
  874. // DeleteWorkObject(ptr);
  875. return dwStatus == ERROR_SUCCESS;
  876. }
  877. //----------------------------------------------------
  878. //
  879. BOOL
  880. CPersistentWorkStorage::RescheduleJob(
  881. CWorkObject* ptr
  882. )
  883. /*++
  884. --*/
  885. {
  886. BOOL bSuccess = TRUE;
  887. DWORD dwStatus = ERROR_SUCCESS;
  888. PBYTE pbData;
  889. DWORD cbData;
  890. PBYTE pbBookmark;
  891. DWORD cbBookmark;
  892. DWORD dwTime;
  893. DWORD dwJobType;
  894. DBGPrintf(
  895. DBG_INFORMATION,
  896. DBG_FACILITY_WORKMGR,
  897. DBGLEVEL_FUNCTION_TRACE,
  898. _TEXT("CPersistentWorkStorage::RescheduleJob() scheduling job %s\n"),
  899. ptr->GetJobDescription()
  900. );
  901. if(IsValidWorkObject(ptr) == FALSE)
  902. {
  903. SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
  904. goto cleanup;
  905. }
  906. bSuccess = ptr->GetWorkObjectData(&pbData, &cbData);
  907. if(bSuccess == FALSE)
  908. {
  909. SetLastError(dwStatus = ERROR_INVALID_DATA);
  910. goto cleanup;
  911. }
  912. bSuccess = ptr->GetJobId(&pbBookmark, &cbBookmark);
  913. if(bSuccess == FALSE)
  914. {
  915. SetLastError(dwStatus = ERROR_INVALID_DATA);
  916. goto cleanup;
  917. }
  918. dwTime = ptr->GetSuggestedScheduledTime();
  919. dwJobType = ptr->GetWorkType();
  920. m_hTableLock.Lock();
  921. if(m_pWkItemTable != NULL)
  922. {
  923. bSuccess = UpdateWorkItemEntry(
  924. m_pWkItemTable,
  925. (dwTime == INFINITE) ? WORKITEM_DELETE : WORKITEM_RESCHEDULE,
  926. pbBookmark,
  927. cbBookmark,
  928. ptr->GetJobRestartTime(),
  929. (dwTime == INFINITE) ? dwTime : dwTime + time(NULL),
  930. dwJobType,
  931. pbData,
  932. cbData
  933. );
  934. if(bSuccess == FALSE)
  935. {
  936. dwStatus = GetLastError();
  937. }
  938. }
  939. m_hTableLock.UnLock();
  940. cleanup:
  941. DeleteWorkObject(ptr);
  942. return dwStatus == ERROR_SUCCESS;
  943. }
  944. //----------------------------------------------------
  945. //
  946. CLASS_PRIVATE DWORD
  947. CPersistentWorkStorage::FindNextJob()
  948. {
  949. DWORD dwStatus = ERROR_SUCCESS;
  950. BOOL bSuccess = TRUE;
  951. CWorkObject* ptr = NULL;
  952. JET_ERR jetErrCode;
  953. PBYTE pbBookmark = NULL;
  954. DWORD cbBookmark = 0;
  955. m_hTableLock.Lock();
  956. while(dwStatus == ERROR_SUCCESS)
  957. {
  958. WORKITEMRECORD wkItem;
  959. // move the record pointer
  960. bSuccess = m_pWkItemTable->MoveToRecord();
  961. if(bSuccess == FALSE)
  962. {
  963. jetErrCode = m_pWkItemTable->GetLastJetError();
  964. if(jetErrCode == JET_errNoCurrentRecord)
  965. {
  966. // end of table
  967. UpdateNextJobTime(INFINITE);
  968. SetLastError(dwStatus = ERROR_NO_DATA);
  969. continue;
  970. }
  971. }
  972. //
  973. // fetch the record
  974. //
  975. bSuccess = m_pWkItemTable->FetchRecord(wkItem);
  976. if(bSuccess == FALSE)
  977. {
  978. SetLastError(dwStatus = SET_JB_ERROR(m_pWkItemTable->GetLastJetError()));
  979. continue;
  980. }
  981. if(wkItem.dwJobType & WORKTYPE_PROCESSING)
  982. {
  983. // job is been processed, move to next one.
  984. continue;
  985. }
  986. dwStatus = GetCurrentBookmarkEx(
  987. m_pWkItemTable,
  988. &pbBookmark,
  989. &cbBookmark
  990. );
  991. if(dwStatus != ERROR_SUCCESS)
  992. {
  993. // Error...
  994. TLSASSERT(dwStatus == ERROR_SUCCESS);
  995. UpdateNextJobTime(INFINITE);
  996. break;
  997. }
  998. if(wkItem.dwScheduledTime > m_dwStartupTime)
  999. {
  1000. if(pbBookmark != NULL && cbBookmark != 0)
  1001. {
  1002. FreeMemory( pbBookmark );
  1003. pbBookmark = NULL;
  1004. cbBookmark = 0;
  1005. }
  1006. UpdateNextJobTime(wkItem.dwScheduledTime);
  1007. break;
  1008. }
  1009. //
  1010. // job is in queue before system startup, re-schedule
  1011. //
  1012. ptr = InitializeWorkObject(
  1013. wkItem.dwJobType,
  1014. wkItem.pbData,
  1015. wkItem.cbData
  1016. );
  1017. if(ptr == NULL)
  1018. {
  1019. if(pbBookmark != NULL && cbBookmark != 0)
  1020. {
  1021. FreeMemory( pbBookmark );
  1022. pbBookmark = NULL;
  1023. cbBookmark = 0;
  1024. }
  1025. //
  1026. // something is wrong, delete this job
  1027. // and move on to next job
  1028. //
  1029. m_pWkItemTable->DeleteRecord();
  1030. continue;
  1031. }
  1032. //
  1033. // Set Job's storage ID and re-schedule this job
  1034. //
  1035. ptr->SetJobId(pbBookmark, cbBookmark);
  1036. bSuccess = RescheduleJob(ptr);
  1037. if(bSuccess == FALSE)
  1038. {
  1039. dwStatus = GetLastError();
  1040. }
  1041. if(pbBookmark != NULL && cbBookmark != 0)
  1042. {
  1043. FreeMemory( pbBookmark );
  1044. pbBookmark = NULL;
  1045. cbBookmark = 0;
  1046. }
  1047. }
  1048. m_hTableLock.UnLock();
  1049. return dwStatus;
  1050. }
  1051. //----------------------------------------------------
  1052. //
  1053. CLASS_PRIVATE CWorkObject*
  1054. CPersistentWorkStorage::GetCurrentJob(
  1055. PDWORD pdwTime
  1056. )
  1057. /*++
  1058. --*/
  1059. {
  1060. DWORD dwStatus = ERROR_SUCCESS;
  1061. BOOL bSuccess = TRUE;
  1062. WORKITEMRECORD wkItem;
  1063. CWorkObject* ptr = NULL;
  1064. PBYTE pbBookmark=NULL;
  1065. DWORD cbBookmark=0;
  1066. TLSASSERT(IsGood() == TRUE);
  1067. m_hTableLock.Lock();
  1068. while(dwStatus == ERROR_SUCCESS)
  1069. {
  1070. //
  1071. // fetch the record
  1072. //
  1073. bSuccess = m_pWkItemTable->FetchRecord(wkItem);
  1074. TLSASSERT(bSuccess == TRUE);
  1075. //TLSASSERT(!(wkItem.dwJobType & WORKTYPE_PROCESSING));
  1076. if(bSuccess == FALSE)
  1077. {
  1078. SetLastError(dwStatus = SET_JB_ERROR(m_pWkItemTable->GetLastJetError()));
  1079. break;
  1080. }
  1081. if( wkItem.dwScheduledTime < m_dwStartupTime ||
  1082. wkItem.cbData == 0 ||
  1083. wkItem.pbData == NULL )
  1084. {
  1085. // FindNextJob() move record pointer one position down
  1086. m_pWkItemTable->MoveToRecord(JET_MovePrevious);
  1087. dwStatus = FindNextJob();
  1088. continue;
  1089. }
  1090. if( wkItem.dwJobType & WORKTYPE_PROCESSING )
  1091. {
  1092. dwStatus = FindNextJob();
  1093. continue;
  1094. }
  1095. ptr = InitializeWorkObject(
  1096. wkItem.dwJobType,
  1097. wkItem.pbData,
  1098. wkItem.cbData
  1099. );
  1100. dwStatus = GetCurrentBookmarkEx(
  1101. m_pWkItemTable,
  1102. &pbBookmark,
  1103. &cbBookmark
  1104. );
  1105. if(dwStatus != ERROR_SUCCESS)
  1106. {
  1107. // something is wrong, free up memory
  1108. // and exit.
  1109. SetLastError(dwStatus);
  1110. // TLSASSERT(FALSE);
  1111. DeleteWorkObject(ptr);
  1112. ptr = NULL;
  1113. // grab next job
  1114. dwStatus = FindNextJob();
  1115. continue;
  1116. }
  1117. //
  1118. // Set Job's storage ID
  1119. //
  1120. ptr->SetJobId(pbBookmark, cbBookmark);
  1121. //ptr->SetScheduledTime(wkItem.dwScheduledTime);
  1122. *pdwTime = wkItem.dwScheduledTime;
  1123. if(pbBookmark != NULL && cbBookmark != 0)
  1124. {
  1125. FreeMemory( pbBookmark );
  1126. pbBookmark = NULL;
  1127. cbBookmark = 0;
  1128. }
  1129. break;
  1130. }
  1131. m_hTableLock.UnLock();
  1132. return ptr;
  1133. }
  1134. //-----------------------------------------------------
  1135. //
  1136. DWORD
  1137. CPersistentWorkStorage::GetNextJobTime()
  1138. {
  1139. DWORD dwTime;
  1140. dwTime = (DWORD)m_dwNextJobTime;
  1141. return dwTime;
  1142. }
  1143. //-----------------------------------------------------
  1144. //
  1145. CWorkObject*
  1146. CPersistentWorkStorage::GetNextJob(
  1147. PDWORD pdwTime
  1148. )
  1149. /*++
  1150. --*/
  1151. {
  1152. CWorkObject* ptr = NULL;
  1153. if((DWORD)m_dwNextJobTime != INFINITE)
  1154. {
  1155. try {
  1156. m_hTableLock.Lock();
  1157. //
  1158. // Fetch record where current bookmark points to,
  1159. // it is possible that new job arrived after
  1160. // WorkManager already calls GetNextJobTime(),
  1161. // this is OK since in this case this new job
  1162. // needs immediate processing.
  1163. //
  1164. ptr = GetCurrentJob(pdwTime);
  1165. //
  1166. // reposition current record pointer
  1167. //
  1168. FindNextJob();
  1169. }
  1170. catch(...) {
  1171. SetLastError(TLS_E_WORKMANAGER_INTERNAL);
  1172. ptr = NULL;
  1173. }
  1174. m_hTableLock.UnLock();
  1175. }
  1176. return ptr;
  1177. }
  1178. //-----------------------------------------------------
  1179. //
  1180. BOOL
  1181. CPersistentWorkStorage::ReturnJobToQueue(
  1182. IN DWORD dwTime,
  1183. IN CWorkObject* ptr
  1184. )
  1185. /*++
  1186. --*/
  1187. {
  1188. DWORD dwStatus = ERROR_SUCCESS;
  1189. PBYTE pbBookmark;
  1190. DWORD cbBookmark;
  1191. DWORD dwJobType;
  1192. PBYTE pbData;
  1193. DWORD cbData;
  1194. if(IsValidWorkObject(ptr) == FALSE)
  1195. {
  1196. SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
  1197. goto cleanup;
  1198. }
  1199. if(ptr->IsWorkPersistent() == FALSE)
  1200. {
  1201. SetLastError(dwStatus = ERROR_INVALID_DATA);
  1202. TLSASSERT(FALSE);
  1203. goto cleanup;
  1204. }
  1205. if(ptr->GetWorkObjectData(&pbData, &cbData) == FALSE)
  1206. {
  1207. SetLastError(dwStatus = ERROR_INVALID_DATA);
  1208. goto cleanup;
  1209. }
  1210. if(ptr->GetJobId(&pbBookmark, &cbBookmark) == FALSE)
  1211. {
  1212. SetLastError(dwStatus = ERROR_INVALID_DATA);
  1213. goto cleanup;
  1214. }
  1215. m_hTableLock.Lock();
  1216. if(dwTime < (DWORD)m_dwNextJobTime)
  1217. {
  1218. // Position current record
  1219. dwStatus = SetCurrentBookmark(
  1220. m_pWkItemTable,
  1221. pbBookmark,
  1222. cbBookmark
  1223. );
  1224. TLSASSERT(dwStatus == ERROR_SUCCESS);
  1225. if(dwStatus == ERROR_SUCCESS)
  1226. {
  1227. UpdateNextJobTime(dwTime);
  1228. }
  1229. }
  1230. m_hTableLock.UnLock();
  1231. cleanup:
  1232. DeleteWorkObject(ptr);
  1233. return dwStatus == ERROR_SUCCESS;
  1234. }
  1235. //-----------------------------------------------------
  1236. //
  1237. BOOL
  1238. CPersistentWorkStorage::EndProcessingJob(
  1239. IN ENDPROCESSINGJOB_CODE opCode,
  1240. IN DWORD dwOriginalTime,
  1241. IN CWorkObject* ptr
  1242. )
  1243. /*++
  1244. Abstract:
  1245. Parameter:
  1246. opCode : End Processing code.
  1247. ptr : Job has completed processing or been
  1248. returned by workmanager due to time or
  1249. resource constraint.
  1250. Return:
  1251. TRUE/FALSE
  1252. --*/
  1253. {
  1254. BOOL bSuccess = TRUE;
  1255. BYTE pbData = NULL;
  1256. DWORD cbData = 0;
  1257. DBGPrintf(
  1258. DBG_INFORMATION,
  1259. DBG_FACILITY_WORKMGR,
  1260. DBGLEVEL_FUNCTION_TRACE,
  1261. _TEXT("CPersistentWorkStorage::EndProcessingJob() - end processing %s opCode %d\n"),
  1262. ptr->GetJobDescription(),
  1263. opCode
  1264. );
  1265. if(ptr == NULL)
  1266. {
  1267. bSuccess = FALSE;
  1268. SetLastError(ERROR_INVALID_PARAMETER);
  1269. goto cleanup;
  1270. }
  1271. if(ptr->IsWorkPersistent() == FALSE)
  1272. {
  1273. SetLastError(ERROR_INVALID_DATA);
  1274. TLSASSERT(FALSE);
  1275. goto cleanup;
  1276. }
  1277. switch(opCode)
  1278. {
  1279. case ENDPROCESSINGJOB_SUCCESS:
  1280. bSuccess = RescheduleJob(ptr);
  1281. m_dwJobsInProcesssing--;
  1282. break;
  1283. case ENDPROCESSINGJOB_ERROR:
  1284. bSuccess = DeleteErrorJob(ptr);
  1285. m_dwJobsInProcesssing--;
  1286. break;
  1287. case ENDPROCESSINGJOB_RETURN:
  1288. bSuccess = ReturnJobToQueue(dwOriginalTime, ptr);
  1289. break;
  1290. default:
  1291. TLSASSERT(FALSE);
  1292. }
  1293. cleanup:
  1294. return bSuccess;
  1295. }
  1296. //-------------------------------------------------------
  1297. //
  1298. BOOL
  1299. CPersistentWorkStorage::BeginProcessingJob(
  1300. IN CWorkObject* ptr
  1301. )
  1302. /*++
  1303. Abstract:
  1304. Work Manager call this to inform. storage that
  1305. this job is about to be processed.
  1306. Parameter:
  1307. ptr - Job to be process.
  1308. Return:
  1309. TRUE/FALSE
  1310. --*/
  1311. {
  1312. BOOL bSuccess = TRUE;
  1313. DWORD dwStatus = ERROR_SUCCESS;
  1314. PBYTE pbBookmark;
  1315. DWORD cbBookmark;
  1316. DWORD dwTime;
  1317. PBYTE pbData;
  1318. DWORD cbData;
  1319. DBGPrintf(
  1320. DBG_INFORMATION,
  1321. DBG_FACILITY_WORKMGR,
  1322. DBGLEVEL_FUNCTION_TRACE,
  1323. _TEXT("CPersistentWorkStorage::BeginProcessingJob() - beginning processing %s\n"),
  1324. ptr->GetJobDescription()
  1325. );
  1326. if(IsValidWorkObject(ptr) == FALSE)
  1327. {
  1328. SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
  1329. goto cleanup;
  1330. }
  1331. if(ptr->IsWorkPersistent() == FALSE)
  1332. {
  1333. SetLastError(dwStatus = ERROR_INVALID_DATA);
  1334. TLSASSERT(FALSE);
  1335. goto cleanup;
  1336. }
  1337. bSuccess = ptr->GetWorkObjectData(&pbData, &cbData);
  1338. if(bSuccess == FALSE)
  1339. {
  1340. SetLastError(dwStatus = ERROR_INVALID_DATA);
  1341. goto cleanup;
  1342. }
  1343. bSuccess = ptr->GetJobId(&pbBookmark, &cbBookmark);
  1344. if(bSuccess == FALSE)
  1345. {
  1346. SetLastError(dwStatus = ERROR_INVALID_DATA);
  1347. goto cleanup;
  1348. }
  1349. m_hTableLock.Lock();
  1350. bSuccess = UpdateWorkItemEntry(
  1351. m_pWkItemTable,
  1352. WORKITEM_BEGINPROCESSING,
  1353. pbBookmark,
  1354. cbBookmark,
  1355. ptr->GetJobRestartTime(),
  1356. ptr->GetScheduledTime(),
  1357. ptr->GetWorkType(),
  1358. pbData,
  1359. cbData
  1360. );
  1361. if(bSuccess == TRUE)
  1362. {
  1363. m_dwJobsInProcesssing ++;
  1364. }
  1365. else
  1366. {
  1367. dwStatus = GetLastError();
  1368. }
  1369. m_hTableLock.UnLock();
  1370. cleanup:
  1371. return dwStatus == ERROR_SUCCESS;
  1372. }