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.

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