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.

706 lines
17 KiB

  1. // ***************************************************************************
  2. // Copyright (C) 2000- Microsoft Corporation.
  3. // @File: vdifreeze.cpp
  4. //
  5. // PURPOSE:
  6. //
  7. // Use a coordinated VDI BACKUP WITH SNAPSHOT (SQL2000 and above)
  8. //
  9. // NOTES:
  10. // We'll now support rollforward from the snapshot by providing the
  11. // BACKUP metadata in the BackupComponentsDocument.
  12. //
  13. // The VDI method of freeze/thaw avoids the potential resource deadlock
  14. // which prevents SQLServer from accepting a "dbcc thaw_io" when one or more
  15. // databases is frozen.
  16. //
  17. // Extern dependencies:
  18. // provision of "_Module" and the COM guids....
  19. //
  20. // HISTORY:
  21. //
  22. // @Version: Whistler/Shiloh
  23. // 85581 SRS 08/15/01 Event security
  24. // 76910 SRS 08/08/01 Rollforward from VSS snapshot
  25. // 68228 12/05/00 ntsnap work
  26. // 68202 11/07/00 ntsnap work
  27. //
  28. // @EndHeader@
  29. // ***************************************************************************
  30. #if DISABLE_4786
  31. #pragma warning( disable : 4786)
  32. #endif
  33. #include <stdafx.h>
  34. #include "vdierror.h"
  35. #include "vdiguid.h"
  36. ////////////////////////////////////////////////////////////////////////
  37. // Standard foo for file name aliasing. This code block must be after
  38. // all includes of VSS header files.
  39. //
  40. #ifdef VSS_FILE_ALIAS
  41. #undef VSS_FILE_ALIAS
  42. #endif
  43. #define VSS_FILE_ALIAS "SQLVFRZC"
  44. //
  45. ////////////////////////////////////////////////////////////////////////
  46. Freeze2000::Freeze2000 (
  47. const WString& serverName,
  48. ULONG maxDatabases) :
  49. m_ServerName (serverName),
  50. m_MaxDatabases (maxDatabases),
  51. m_NumDatabases (0),
  52. m_State (Unprepared),
  53. m_AbortCount (0)
  54. {
  55. CVssFunctionTracer(VSSDBG_SQLLIB, L"Freeze2000::Freeze2000");
  56. m_pDBContext = new FrozenDatabase [maxDatabases];
  57. CoCreateGuid (&m_BackupId);
  58. try
  59. {
  60. InitializeCriticalSection (&m_Latch);
  61. }
  62. catch(...)
  63. {
  64. // delete created object if we fail InitializeCriticalSection
  65. delete m_pDBContext;
  66. }
  67. }
  68. //----------------------------------------------------------
  69. // Wait for all the database threads to terminate.
  70. // This is only called by the coordinating thread while
  71. // holding exclusive access on the object.
  72. //
  73. void
  74. Freeze2000::WaitForThreads ()
  75. {
  76. CVssFunctionTracer(VSSDBG_SQLLIB, L"Freeze2000::WaitForThreads");
  77. for (UINT i=0; i<m_NumDatabases; i++)
  78. {
  79. FrozenDatabase* pDb = m_pDBContext+i;
  80. if (pDb->m_hThread != NULL)
  81. {
  82. DWORD status;
  83. do
  84. {
  85. status = WaitForSingleObjectEx (pDb->m_hThread, 2000, TRUE);
  86. if (m_State != Aborted && CheckAbort ())
  87. Abort ();
  88. } while (status != WAIT_OBJECT_0);
  89. CloseHandle (pDb->m_hThread);
  90. pDb->m_hThread = NULL;
  91. }
  92. }
  93. }
  94. //---------------------------------------------------------
  95. // Handle an abort.
  96. // The main thread will already hold the the lock and so
  97. // will always be successful at aborting the operation.
  98. // The database threads will attempt to abort, but won't
  99. // block in order to do so. The abort count is incremented
  100. // and the main thread is ulimately responsible for cleanup.
  101. //
  102. void
  103. Freeze2000::Abort () throw ()
  104. {
  105. CVssFunctionTracer ft(VSSDBG_SQLLIB, L"Freeze2000::Abort");
  106. SetAbort ();
  107. if (TryLock ())
  108. {
  109. m_State = Aborted;
  110. for (UINT i=0; i<m_NumDatabases; i++)
  111. {
  112. if (m_pDBContext[i].m_pIVDSet)
  113. {
  114. m_pDBContext[i].m_pIVDSet->SignalAbort ();
  115. m_pDBContext[i].m_pIVDSet->Close ();
  116. m_pDBContext[i].m_pIVDSet->Release ();
  117. m_pDBContext[i].m_pIVDSet = NULL;
  118. m_pDBContext[i].m_pIVD = NULL;
  119. }
  120. }
  121. Unlock ();
  122. }
  123. }
  124. Freeze2000::~Freeze2000 ()
  125. {
  126. Lock ();
  127. if (m_State != Complete)
  128. {
  129. // Trigger any waiting threads, cleaning up any VDI's.
  130. //
  131. Abort ();
  132. WaitForThreads ();
  133. }
  134. delete[] m_pDBContext;
  135. DeleteCriticalSection (&m_Latch);
  136. }
  137. //-------------------------------------------
  138. // Map the voids and proc call stuff to the real
  139. // thread routine.
  140. //
  141. DWORD WINAPI FreezeThreadProc(
  142. LPVOID lpParameter ) // thread data
  143. {
  144. return Freeze2000::DatabaseThreadStart (lpParameter);
  145. }
  146. DWORD Freeze2000::DatabaseThreadStart (
  147. LPVOID lpParameter ) // thread data
  148. {
  149. FrozenDatabase* pDbContext = (FrozenDatabase*)lpParameter;
  150. return pDbContext->m_pContext->DatabaseThread (pDbContext);
  151. }
  152. //-------------------------------------------
  153. // Add a database to the freeze set.
  154. //
  155. void
  156. Freeze2000::PrepareDatabase (
  157. const WString& dbName)
  158. {
  159. CVssFunctionTracer ft(VSSDBG_SQLLIB, L"Free2000::PrepareDatabase");
  160. // can't backup tempdb!
  161. //
  162. if (dbName == L"tempdb")
  163. return;
  164. Lock ();
  165. try
  166. {
  167. if (m_State == Unprepared)
  168. {
  169. m_State = Preparing;
  170. }
  171. if (m_NumDatabases >= m_MaxDatabases ||
  172. m_State != Preparing)
  173. {
  174. DBG_ASSERT(FALSE && L"Too many databases or not preparing");
  175. THROW_GENERIC;
  176. }
  177. FrozenDatabase* pDbContext = m_pDBContext+m_NumDatabases;
  178. m_NumDatabases++;
  179. pDbContext->m_pContext = this;
  180. #ifdef TESTDRV
  181. ft.hr = CoCreateInstance (
  182. CLSID_MSSQL_ClientVirtualDeviceSet,
  183. NULL,
  184. CLSCTX_INPROC_SERVER,
  185. IID_IClientVirtualDeviceSet2,
  186. (void**)&pDbContext->m_pIVDSet);
  187. #else
  188. ft.CoCreateInstanceWithLog(
  189. VSSDBG_SQLLIB,
  190. CLSID_MSSQL_ClientVirtualDeviceSet,
  191. L"MSSQL_ClientVirtualDeviceSet",
  192. CLSCTX_INPROC_SERVER,
  193. IID_IClientVirtualDeviceSet2,
  194. (IUnknown**)&(pDbContext->m_pIVDSet));
  195. #endif
  196. if (ft.HrFailed())
  197. {
  198. ft.LogError(VSS_ERROR_SQLLIB_CANTCREATEVDS, VSSDBG_SQLLIB << ft.hr);
  199. ft.Throw
  200. (
  201. VSSDBG_SQLLIB,
  202. ft.hr,
  203. L"Failed to create VDS object. hr = 0x%08lx",
  204. ft.hr
  205. );
  206. }
  207. VDConfig config;
  208. memset (&config, 0, sizeof(config));
  209. config.deviceCount = 1;
  210. config.features |= VDF_SnapshotPrepare;
  211. StringFromGUID2 (m_BackupId, pDbContext->m_SetName, sizeof (pDbContext->m_SetName)/sizeof(WCHAR));
  212. swprintf (pDbContext->m_SetName+wcslen(pDbContext->m_SetName), L"%d", m_NumDatabases);
  213. // A "\" indicates a named instance; we need the "raw" instance name
  214. //
  215. WCHAR* pInstance = wcschr (m_ServerName.c_str (), L'\\');
  216. if (pInstance)
  217. {
  218. pInstance++; // step over the separator
  219. }
  220. // Create the virtual device set
  221. //
  222. ft.hr = pDbContext->m_pIVDSet->CreateEx (pInstance, pDbContext->m_SetName, &config);
  223. if (ft.HrFailed())
  224. {
  225. ft.LogError(VSS_ERROR_SQLLIB_CANTCREATEVDS, VSSDBG_SQLLIB << ft.hr);
  226. ft.Throw
  227. (
  228. VSSDBG_SQLLIB,
  229. ft.hr,
  230. L"Failed to create VDS object. hr = 0x%08lx",
  231. ft.hr
  232. );
  233. }
  234. pDbContext->m_VDState = FrozenDatabase::Created;
  235. pDbContext->m_DbName = dbName;
  236. pDbContext->m_IsMaster = (dbName == L"master");
  237. pDbContext->m_hThread = CreateThread (NULL, 0,
  238. FreezeThreadProc, pDbContext, 0, NULL);
  239. if (pDbContext->m_hThread == NULL)
  240. {
  241. ft.hr = HRESULT_FROM_WIN32(GetLastError());
  242. ft.CheckForError(VSSDBG_SQLLIB, L"CreateThread");
  243. }
  244. }
  245. catch (...)
  246. {
  247. Abort ();
  248. Unlock ();
  249. throw;
  250. }
  251. Unlock ();
  252. }
  253. //---------------------------------------------------------
  254. // Prep a database by setting up a BACKUP WITH SNAPSHOT
  255. // Since the backup has no way to stall for the prepare, we stall it by delaying
  256. // the VDI processing until freeze time.
  257. // We use 1024 bytes as the block size because the MTF FLBSize is 1024,
  258. // so we'll see fewer VD commands with no larger resulting MD size.
  259. //
  260. // It would be nice to add a Prepare phase to SQLServer so that the database
  261. // checkpoint could occur during Prepare, rather than during FREEZE.
  262. //
  263. DWORD
  264. Freeze2000::DatabaseThread (
  265. FrozenDatabase* pDbContext)
  266. {
  267. CVssFunctionTracer ft(VSSDBG_XML, L"Freeze2000::DatabaseThread");
  268. try
  269. {
  270. SqlConnection sql;
  271. sql.Connect (m_ServerName);
  272. WCHAR delimitedName [SysNameBufferLen];
  273. FormDelimitedIdentifier (delimitedName, pDbContext->m_DbName.c_str ());
  274. WString command =
  275. L"BACKUP DATABASE " + WString (delimitedName) + L" TO VIRTUAL_DEVICE='" +
  276. pDbContext->m_SetName + L"' WITH SNAPSHOT,BUFFERCOUNT=1,BLOCKSIZE=1024";
  277. sql.SetCommand (command);
  278. sql.ExecCommand ();
  279. pDbContext->m_SuccessDetected = TRUE;
  280. }
  281. catch (...)
  282. {
  283. Abort ();
  284. }
  285. return 0;
  286. }
  287. //---------------------------------------------------------
  288. // Advance the status of each VD.
  289. // Will throw if problems are encountered.
  290. //
  291. // This routine is called in two contexts:
  292. // 1. During the "Prepare" phase, 'targetState' is 'PreparedToFreeze'.
  293. // The goal is to move each VD to an "PreparedToFreeze" state.
  294. //
  295. // 2. During the "Freeze" phase, 'targetState' is 'Frozen'.
  296. // The remaining metadata is consumed, then the BACKUP will freeze
  297. // the database and send the 'VDC_Snapshot' command.
  298. //
  299. // Master must be frozen last, so we skip pulling its VD commands until all other
  300. // databases are complete. If master is frozen before other databases, SQLServer
  301. // can hang.
  302. //
  303. void
  304. Freeze2000::AdvanceVDState (
  305. FrozenDatabase::VDState targetState)
  306. {
  307. CVssFunctionTracer ft(VSSDBG_SQLLIB, L"Freeze2000::AdvanceVDState");
  308. bool oneDatabaseLeft = (m_NumDatabases == 1);
  309. // Poll over the VD's moving them to the target state.
  310. //
  311. while (1)
  312. {
  313. bool didSomething = false;
  314. int nDatabasesReady = 0;
  315. DWORD timeOut = oneDatabaseLeft ? 1000 : 0;
  316. for (UINT i=0; i<m_NumDatabases; i++)
  317. {
  318. FrozenDatabase* pDb = m_pDBContext+i;
  319. if (CheckAbort ())
  320. {
  321. THROW_GENERIC;
  322. }
  323. if (pDb->m_VDState >= targetState)
  324. {
  325. nDatabasesReady++;
  326. if (nDatabasesReady == m_NumDatabases)
  327. return;
  328. if (nDatabasesReady == m_NumDatabases-1)
  329. {
  330. oneDatabaseLeft = true;
  331. }
  332. continue; // with the next database
  333. }
  334. switch (pDb->m_VDState)
  335. {
  336. case FrozenDatabase::Created:
  337. VDConfig config;
  338. ft.hr = pDb->m_pIVDSet->GetConfiguration (timeOut, &config);
  339. if (ft.hr == VD_E_TIMEOUT)
  340. continue; // nothing to do for this database right now
  341. if (ft.HrFailed())
  342. ft.CheckForError(VSSDBG_SQLLIB, L"IClientVirtualDeviceSet2::GetConfiguration");
  343. ft.hr = pDb->m_pIVDSet->OpenDevice (pDb->m_SetName, &pDb->m_pIVD);
  344. if (ft.HrFailed())
  345. ft.CheckForError(VSSDBG_SQLLIB, L"IClientVirtualDeviceSet2::OpenDevice");
  346. pDb->m_VDState = FrozenDatabase::Open;
  347. didSomething = true;
  348. // fall thru
  349. case FrozenDatabase::PreparedToFreeze:
  350. if (pDb->m_IsMaster &&
  351. targetState == FrozenDatabase::Frozen &&
  352. !oneDatabaseLeft)
  353. {
  354. #ifdef DEBUG_PRINTF
  355. printf ("Skipping master\n");
  356. #endif
  357. continue; // try another database
  358. }
  359. if (pDb->m_pSnapshotCmd)
  360. {
  361. // Acknowledge the prepare command, which lets the
  362. // database proceed to frozen.
  363. //
  364. ft.hr = pDb->m_pIVD->CompleteCommand (
  365. pDb->m_pSnapshotCmd, ERROR_SUCCESS, 0, 0);
  366. // only attempt completion once
  367. //
  368. pDb->m_pSnapshotCmd = NULL;
  369. if (ft.HrFailed())
  370. ft.CheckForError(VSSDBG_SQLLIB, L"IClientVirtualDevice::CompletePrepare");
  371. didSomething = true;
  372. }
  373. // fall thru
  374. case FrozenDatabase::Open:
  375. // pull commands until we see a "prepare" or "mountSnapshot"
  376. //
  377. VDC_Command * cmd;
  378. HRESULT hr;
  379. while (SUCCEEDED (hr=pDb->m_pIVD->GetCommand (timeOut, &cmd)))
  380. {
  381. DWORD completionCode;
  382. DWORD bytesTransferred=0;
  383. didSomething = true;
  384. switch (cmd->commandCode)
  385. {
  386. case VDC_Write:
  387. bytesTransferred = cmd->size;
  388. pDb->m_MetaData.Append (cmd->buffer, bytesTransferred);
  389. // fall thru
  390. case VDC_Flush:
  391. completionCode = ERROR_SUCCESS;
  392. ft.hr = pDb->m_pIVD->CompleteCommand (
  393. cmd, completionCode, bytesTransferred, 0);
  394. if (ft.HrFailed())
  395. ft.CheckForError(VSSDBG_SQLLIB, L"IClientVirtualDevice::CompleteCommand");
  396. break;
  397. case VDC_PrepareToFreeze:
  398. // Record the state transition and
  399. // save the command for completion during the freeze phase.
  400. //
  401. DBG_ASSERT (targetState == FrozenDatabase::PreparedToFreeze);
  402. pDb->m_VDState = FrozenDatabase::PreparedToFreeze;
  403. pDb->m_pSnapshotCmd = cmd;
  404. #ifdef DEBUG_PRINTF
  405. printf ("DBPrepared: %ls\n", pDb->m_DbName.c_str ());
  406. #endif
  407. continue;
  408. case VDC_Snapshot:
  409. // Record the state transition and
  410. // save the command for completion during the thaw phase.
  411. //
  412. // Running with SQL2000 prior to SP2 will hit this assert.
  413. // We'll need to tell customers to use SP2 with Whistler snapshots.
  414. // The effect is that the databases will freeze during the prepare
  415. // phase, thus the freeze interval is longer than needed.
  416. //
  417. //DBG_ASSERT (targetState == FrozenDatabase::Frozen);
  418. pDb->m_VDState = FrozenDatabase::Frozen;
  419. pDb->m_pSnapshotCmd = cmd;
  420. #ifdef DEBUG_PRINTF
  421. printf ("DBFrozen: %ls\n", pDb->m_DbName.c_str ());
  422. #endif
  423. continue;
  424. default:
  425. ft.Trace(VSSDBG_SQLLIB, L"Unexpected VDCmd: x%x\n", cmd->commandCode);
  426. THROW_GENERIC;
  427. } // end command switch
  428. } // end command loop
  429. ft.hr = hr;
  430. if (ft.hr == VD_E_TIMEOUT)
  431. break; // no command was ready.
  432. if (ft.HrFailed())
  433. ft.CheckForError(VSSDBG_SQLLIB, L"IClientVirtualDevice::GetCommand");
  434. break;
  435. default:
  436. DBG_ASSERT(FALSE && L"Shouldn't get here");
  437. THROW_GENERIC;
  438. } // end switch to handle this db
  439. } // end loop over each db
  440. // Unless we found something to do,
  441. // delay a bit and try again.
  442. //
  443. if (!didSomething && !oneDatabaseLeft)
  444. {
  445. #ifdef DEBUG_PRINTF
  446. printf ("Sleep(100)\n");
  447. #endif
  448. SleepEx (100, TRUE);
  449. }
  450. } // wait for all databases to go "Ready"
  451. }
  452. //---------------------------------------------------------
  453. // Wait for the databases to finish preparing.
  454. // This waits for the virtual devices to open up
  455. //
  456. void
  457. Freeze2000::WaitForPrepare ()
  458. {
  459. CVssFunctionTracer ft(VSSDBG_SQLLIB, L"Freeze2000::WaitForPrepare");
  460. Lock ();
  461. if (m_State != Preparing || CheckAbort ())
  462. {
  463. Abort ();
  464. Unlock ();
  465. THROW_GENERIC;
  466. }
  467. m_State = Prepared;
  468. try
  469. {
  470. AdvanceVDState (FrozenDatabase::PreparedToFreeze);
  471. }
  472. catch (...)
  473. {
  474. Abort ();
  475. Unlock ();
  476. throw;
  477. }
  478. Unlock ();
  479. }
  480. //------------------------------------------------------------------
  481. // Perform the freeze, waiting for a "Take-snapshot" from each db.
  482. //
  483. void
  484. Freeze2000::Freeze ()
  485. {
  486. CVssFunctionTracer ft(VSSDBG_SQLLIB, L"Freeze2000::Freeze");
  487. Lock ();
  488. if (m_State != Prepared || CheckAbort ())
  489. {
  490. Abort ();
  491. Unlock ();
  492. THROW_GENERIC;
  493. }
  494. try
  495. {
  496. m_State = Frozen;
  497. AdvanceVDState (FrozenDatabase::Frozen);
  498. }
  499. catch (...)
  500. {
  501. Abort ();
  502. Unlock ();
  503. throw;
  504. }
  505. Unlock ();
  506. }
  507. //---------------------------------------------------------
  508. // Perform the thaw.
  509. //
  510. // Return TRUE if the databases were all successfully backed up
  511. // and were thawed out as expected.
  512. // FALSE is returned in any other case.
  513. // No exceptions are thrown (this routine can be used as a cleanup routine).
  514. //
  515. BOOL
  516. Freeze2000::Thaw () throw ()
  517. {
  518. CVssFunctionTracer ft(VSSDBG_SQLLIB, L"Freeze2000::Thaw");
  519. Lock ();
  520. if (m_State != Frozen || CheckAbort ())
  521. {
  522. Abort ();
  523. Unlock ();
  524. return FALSE;
  525. }
  526. try
  527. {
  528. // Send the "snapshot complete" messages.
  529. //
  530. UINT i;
  531. for (i=0; i<m_NumDatabases; i++)
  532. {
  533. FrozenDatabase* pDb = m_pDBContext+i;
  534. DBG_ASSERT (pDb->m_VDState == FrozenDatabase::Frozen);
  535. ft.hr = pDb->m_pIVD->CompleteCommand (pDb->m_pSnapshotCmd, ERROR_SUCCESS, 0, 0);
  536. if (FAILED (ft.hr))
  537. ft.CheckForError(VSSDBG_SQLLIB, L"IClientVirtualDevice::CompleteCommand");
  538. }
  539. // Wait for the BACKUP threads to report success.
  540. //
  541. WaitForThreads ();
  542. for (i=0; i<m_NumDatabases; i++)
  543. {
  544. FrozenDatabase* pDb = m_pDBContext+i;
  545. if (!pDb->m_SuccessDetected)
  546. {
  547. THROW_GENERIC;
  548. }
  549. }
  550. // Pull the "close" message from each VD
  551. //
  552. for (i=0; i<m_NumDatabases; i++)
  553. {
  554. FrozenDatabase* pDb = m_pDBContext+i;
  555. VDC_Command * cmd;
  556. ft.hr=pDb->m_pIVD->GetCommand (INFINITE, &cmd);
  557. if (ft.hr != VD_E_CLOSE)
  558. ft.LogError(VSS_ERROR_SQLLIB_FINALCOMMANDNOTCLOSE, VSSDBG_SQLLIB << ft.hr);
  559. pDb->m_pIVDSet->Close ();
  560. pDb->m_pIVDSet->Release ();
  561. pDb->m_pIVDSet = NULL;
  562. pDb->m_pIVD = NULL;
  563. pDb->m_MetaData.Finalize ();
  564. }
  565. m_State = Complete;
  566. }
  567. catch (...)
  568. {
  569. Abort ();
  570. Unlock ();
  571. return FALSE;
  572. }
  573. Unlock ();
  574. return TRUE;
  575. }
  576. //---------------------------------------------------------
  577. // Fetch the metadata for a database
  578. //
  579. const BYTE*
  580. Freeze2000::GetMetaData (
  581. const WString& dbName,
  582. UINT *pLength) // return area for data length.
  583. {
  584. UINT i;
  585. for (i=0; i<m_NumDatabases; i++)
  586. {
  587. FrozenDatabase* pDb = m_pDBContext+i;
  588. if (pDb->m_DbName == dbName)
  589. {
  590. return pDb->m_MetaData.GetImage (pLength);
  591. }
  592. }
  593. *pLength = 0;
  594. return NULL;
  595. }