diff --git a/README.md b/README.md
index 91b38d3d7..38ac14641 100644
--- a/README.md
+++ b/README.md
@@ -25,3 +25,4 @@ This repository contains the PanelSwWix4: A custom WiX Toolset codebase
- Support sending custom messages on embedded pipe
- Best effort to log premature termination of companion process
- Monitor UX folder and re-extract any UX payloads that were deleted for any reason
+- Reorder cache actions: moves non-executing package caching to the end of the plan. This optimizes run time as packages that are cached but not executed will not stand in the way of executing packages.
\ No newline at end of file
diff --git a/src/burn/engine/apply.cpp b/src/burn/engine/apply.cpp
index 26fb398bd..5ef3e6293 100644
--- a/src/burn/engine/apply.cpp
+++ b/src/burn/engine/apply.cpp
@@ -662,6 +662,10 @@ extern "C" HRESULT ApplyCache(
}
break;
+ case BURN_CACHE_ACTION_TYPE_DELAYABLE_START:
+ case BURN_CACHE_ACTION_TYPE_DELAYABLE_END:
+ break;
+
default:
AssertSz(FALSE, "Unknown cache action.");
break;
@@ -2407,7 +2411,6 @@ static void DoRollbackCache(
__in DWORD dwCheckpoint
)
{
- HRESULT hr = S_OK;
BURN_PACKAGE* pPackage = NULL;
DWORD dwLastCheckpoint = 0;
@@ -2432,7 +2435,7 @@ static void DoRollbackCache(
{
if (dwLastCheckpoint <= dwCheckpoint) // only rollback when it was attempted to be cached.
{
- hr = CleanPackage(pPlan->pCache, hPipe, pPackage);
+ CleanPackage(pPlan->pCache, hPipe, pPackage);
}
}
else if (pPackage->fCanAffectRegistration)
diff --git a/src/burn/engine/engine.mc b/src/burn/engine/engine.mc
index 0cd4cfffe..e7a12b328 100644
--- a/src/burn/engine/engine.mc
+++ b/src/burn/engine/engine.mc
@@ -1321,5 +1321,5 @@ MessageId=707
Severity=Success
SymbolicName=MSG_REORDERING_PACKAGE
Language=English
-Moving packages '%1!ls!' to the end of the queue since it is not planned to execute.
+Moving packages '%1!ls!' caching to the end of the queue since it is not planned to execute.
.
diff --git a/src/burn/engine/package.cpp b/src/burn/engine/package.cpp
index 3af5ee877..06496d5d5 100644
--- a/src/burn/engine/package.cpp
+++ b/src/burn/engine/package.cpp
@@ -142,8 +142,6 @@ extern "C" HRESULT PackagesParseFromXml(
{
BURN_PACKAGE* pPackage = &pPackages->rgPackages[i];
- pPackage->dwPackageIndex = i;
-
hr = XmlNextElement(pixnNodes, &pixnNode, &bstrNodeName);
ExitOnFailure(hr, "Failed to get next node.");
diff --git a/src/burn/engine/package.h b/src/burn/engine/package.h
index bf62e690f..3a17e1f0f 100644
--- a/src/burn/engine/package.h
+++ b/src/burn/engine/package.h
@@ -285,8 +285,6 @@ typedef struct _BURN_PACKAGE
DWORD64 qwInstallSize;
DWORD64 qwSize;
- DWORD dwPackageIndex;
-
BURN_ROLLBACK_BOUNDARY* pRollbackBoundaryForward; // used during install and repair.
BURN_ROLLBACK_BOUNDARY* pRollbackBoundaryBackward; // used during uninstall.
diff --git a/src/burn/engine/plan.cpp b/src/burn/engine/plan.cpp
index cd116c1e2..f10a7e75e 100644
--- a/src/burn/engine/plan.cpp
+++ b/src/burn/engine/plan.cpp
@@ -42,14 +42,6 @@ static HRESULT PlanPackagesHelper(
__in BURN_LOGGING* pLog,
__in BURN_VARIABLES* pVariables
);
-static void PlanReorderPackages(
- __in BURN_PACKAGE* rgPackages,
- __in DWORD cPackages
- );
-static void PlanRestorePackagesOrder(
- __in BURN_PACKAGE* rgPackages,
- __in DWORD cPackages
- );
static HRESULT InitializePackage(
__in BURN_PLAN* pPlan,
__in BURN_USER_EXPERIENCE* pUX,
@@ -154,6 +146,12 @@ static void FinalizePatchActions(
__in BURN_EXECUTE_ACTION* rgActions,
__in DWORD cActions
);
+static void FinalizeCacheActions(
+ __in BURN_CACHE_ACTION* rgCacheActions,
+ __in DWORD cCacheActions,
+ __in BURN_EXECUTE_ACTION* rgActions,
+ __in DWORD cActions
+ );
static void CalculateExpectedRegistrationStates(
__in BURN_PACKAGE* rgPackages,
__in DWORD cPackages
@@ -295,7 +293,6 @@ extern "C" void PlanReset(
{
ResetPlannedPackageState(&pPackages->rgPackages[i]);
}
- PlanRestorePackagesOrder(pPackages->rgPackages, pPackages->cPackages);
}
ResetPlannedPayloadGroupState(pLayoutPayloads);
@@ -883,12 +880,6 @@ static HRESULT PlanPackagesHelper(
}
}
- // Best effort to reorder the packages: Executing packages first. This will ensure cache-only packages will not block executing packages until they get cached
- if (!fReverseOrder)
- {
- PlanReorderPackages(rgPackages, cPackages);
- }
-
// Plan the packages.
for (DWORD i = 0; i < cPackages; ++i)
{
@@ -1067,9 +1058,27 @@ static HRESULT ProcessPackage(
{
if (ForceCache(pPlan, pPackage))
{
+ BURN_CACHE_ACTION* pCacheAction = NULL;
+
+ hr = AppendCacheAction(pPlan, &pCacheAction);
+ ExitOnFailure(hr, "Failed to plan cache action.");
+ pCacheAction->type = BURN_CACHE_ACTION_TYPE_DELAYABLE_START;
+
+ hr = AppendRollbackCacheAction(pPlan, &pCacheAction);
+ ExitOnFailure(hr, "Failed to plan cache action.");
+ pCacheAction->type = BURN_CACHE_ACTION_TYPE_DELAYABLE_START;
+
hr = AddCachePackage(pPlan, pPackage, TRUE);
ExitOnFailure(hr, "Failed to plan cache package.");
+ hr = AppendCacheAction(pPlan, &pCacheAction);
+ ExitOnFailure(hr, "Failed to plan cache action.");
+ pCacheAction->type = BURN_CACHE_ACTION_TYPE_DELAYABLE_END;
+
+ hr = AppendRollbackCacheAction(pPlan, &pCacheAction);
+ ExitOnFailure(hr, "Failed to plan cache action.");
+ pCacheAction->type = BURN_CACHE_ACTION_TYPE_DELAYABLE_END;
+
if (pPackage->fPerMachine)
{
pPlan->fPerMachine = TRUE;
@@ -1294,8 +1303,34 @@ extern "C" HRESULT PlanExecutePackage(
if (BURN_CACHE_PACKAGE_TYPE_NONE != pPackage->executeCacheType || BURN_CACHE_PACKAGE_TYPE_NONE != pPackage->rollbackCacheType)
{
+ if ((pPackage->execute == BOOTSTRAPPER_ACTION_STATE_NONE) && (pPackage->rollback == BOOTSTRAPPER_ACTION_STATE_NONE))
+ {
+ BURN_CACHE_ACTION* pCacheAction = NULL;
+
+ hr = AppendCacheAction(pPlan, &pCacheAction);
+ ExitOnFailure(hr, "Failed to plan cache action.");
+ pCacheAction->type = BURN_CACHE_ACTION_TYPE_DELAYABLE_START;
+
+ hr = AppendRollbackCacheAction(pPlan, &pCacheAction);
+ ExitOnFailure(hr, "Failed to plan cache action.");
+ pCacheAction->type = BURN_CACHE_ACTION_TYPE_DELAYABLE_START;
+ }
+
hr = AddCachePackage(pPlan, pPackage, BURN_CACHE_PACKAGE_TYPE_REQUIRED == pPackage->executeCacheType);
ExitOnFailure(hr, "Failed to plan cache package.");
+
+ if ((pPackage->execute == BOOTSTRAPPER_ACTION_STATE_NONE) && (pPackage->rollback == BOOTSTRAPPER_ACTION_STATE_NONE))
+ {
+ BURN_CACHE_ACTION* pCacheAction = NULL;
+
+ hr = AppendCacheAction(pPlan, &pCacheAction);
+ ExitOnFailure(hr, "Failed to plan cache action.");
+ pCacheAction->type = BURN_CACHE_ACTION_TYPE_DELAYABLE_END;
+
+ hr = AppendRollbackCacheAction(pPlan, &pCacheAction);
+ ExitOnFailure(hr, "Failed to plan cache action.");
+ pCacheAction->type = BURN_CACHE_ACTION_TYPE_DELAYABLE_END;
+ }
}
// Add execute actions.
@@ -1849,6 +1884,10 @@ extern "C" HRESULT PlanFinalizeActions(
RemoveUnnecessaryActions(FALSE, pPlan->rgRollbackActions, pPlan->cRollbackActions);
+ FinalizeCacheActions(pPlan->rgCacheActions, pPlan->cCacheActions, pPlan->rgExecuteActions, pPlan->cExecuteActions);
+
+ FinalizeCacheActions(pPlan->rgRollbackCacheActions, pPlan->cRollbackCacheActions, pPlan->rgRollbackActions, pPlan->cRollbackActions);
+
return hr;
}
@@ -2801,6 +2840,164 @@ static void FinalizePatchActions(
}
}
+static void FinalizeCacheActions(
+ __in BURN_CACHE_ACTION* rgCacheActions,
+ __in DWORD cCacheActions,
+ __in BURN_EXECUTE_ACTION* rgActions,
+ __in DWORD cActions
+ )
+{
+ HRESULT hr = S_OK;
+ DWORD cDelayableCacheActions = 0;
+ DWORD cDelayableExecuteActions = 0;
+ DWORD iNextAction = 0;
+ DWORD iNextDelayableAction = 0;
+ DWORD iFirstDelayedCacheAction = 0;
+ DWORD iFirstDelayedExecuteAction = 0;
+ BURN_CACHE_ACTION* rgReorderedCacheActions = NULL;
+ BURN_EXECUTE_ACTION* rgReorderedActions = NULL;
+ BOOL fDelayable = FALSE;
+
+ for (DWORD i = 0; i < cCacheActions; ++i)
+ {
+ BURN_CACHE_ACTION* pCacheAction = rgCacheActions + i;
+
+ if (pCacheAction->type == BURN_CACHE_ACTION_TYPE_DELAYABLE_START)
+ {
+ ExitOnNull(!fDelayable, hr, E_UNEXPECTED, "Unexpected start delayable cache action");
+ fDelayable = TRUE;
+ }
+
+ if (fDelayable)
+ {
+ ++cDelayableCacheActions;
+
+ if (pCacheAction->type == BURN_CACHE_ACTION_TYPE_SIGNAL_SYNCPOINT)
+ {
+ cDelayableExecuteActions += 2; // Checkpoint + syncpoint
+ }
+ }
+
+ if (pCacheAction->type == BURN_CACHE_ACTION_TYPE_DELAYABLE_END)
+ {
+ ExitOnNull(fDelayable, hr, E_UNEXPECTED, "Unexpected end delayable cache action");
+ fDelayable = FALSE;
+ }
+ }
+
+ if ((cDelayableCacheActions == 0) || (cDelayableCacheActions == cCacheActions))
+ {
+ ExitFunction();
+ }
+
+ iFirstDelayedCacheAction = cCacheActions - cDelayableCacheActions;
+ iFirstDelayedExecuteAction = cActions - cDelayableExecuteActions;
+
+ rgReorderedCacheActions = (BURN_CACHE_ACTION*)MemAlloc(sizeof(BURN_CACHE_ACTION) * cCacheActions, FALSE);
+ ExitOnNull(rgReorderedCacheActions, hr, E_OUTOFMEMORY, "Failed to allocate memory");
+
+ rgReorderedActions = (BURN_EXECUTE_ACTION*)MemAlloc(sizeof(BURN_EXECUTE_ACTION) * cActions, FALSE);
+ ExitOnNull(rgReorderedActions, hr, E_OUTOFMEMORY, "Failed to allocate memory");
+
+ fDelayable = FALSE;
+ iNextAction = 0;
+ iNextDelayableAction = iFirstDelayedCacheAction;
+ for (DWORD i = 0; i < cCacheActions; ++i)
+ {
+ BURN_CACHE_ACTION* pSourceAction = rgCacheActions + i;
+ BURN_CACHE_ACTION* pDestAction = NULL;
+
+ if (pSourceAction->type == BURN_CACHE_ACTION_TYPE_DELAYABLE_START)
+ {
+ fDelayable = TRUE;
+ }
+
+ if (fDelayable)
+ {
+ if (pSourceAction->type == BURN_CACHE_ACTION_TYPE_PACKAGE)
+ {
+ LogId(REPORT_STANDARD, MSG_REORDERING_PACKAGE, pSourceAction->package.pPackage->sczId);
+ }
+
+ pDestAction = rgReorderedCacheActions + iNextDelayableAction;
+ ++iNextDelayableAction;
+ }
+ else
+ {
+ pDestAction = rgReorderedCacheActions + iNextAction;
+ ++iNextAction;
+ }
+
+ if (pSourceAction->type == BURN_CACHE_ACTION_TYPE_DELAYABLE_END)
+ {
+ fDelayable = FALSE;
+ }
+
+ memcpy_s(pDestAction, sizeof(BURN_CACHE_ACTION), pSourceAction, sizeof(BURN_CACHE_ACTION));
+ }
+ ExitOnNull((iNextDelayableAction == cCacheActions), hr, E_UNEXPECTED, "Unexpected last delayable cache location: %u instead of %u", iNextDelayableAction, cCacheActions);
+
+ // Delay cache sync actions in the execute sequence
+ iNextAction = 0;
+ iNextDelayableAction = iFirstDelayedExecuteAction;
+ for (DWORD i = 0; i < cActions; ++i)
+ {
+ BURN_EXECUTE_ACTION* pSourceAction = rgActions + i;
+ BURN_EXECUTE_ACTION* pDestAction = NULL;
+ fDelayable = FALSE;
+
+ if ((i < (cActions - 1)) && (pSourceAction->type == BURN_EXECUTE_ACTION_TYPE_CHECKPOINT) && (rgActions[i + 1].type == BURN_EXECUTE_ACTION_TYPE_WAIT_CACHE_PACKAGE))
+ {
+ for (DWORD j = iFirstDelayedCacheAction; j < cCacheActions; ++j)
+ {
+ BURN_CACHE_ACTION* pCacheAction = rgReorderedCacheActions + j;
+ if ((pCacheAction->type == BURN_CACHE_ACTION_TYPE_SIGNAL_SYNCPOINT) && (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pCacheAction->syncpoint.pPackage->sczId, -1, rgActions[i + 1].waitCachePackage.pPackage->sczId, -1)))
+ {
+ fDelayable = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (fDelayable)
+ {
+ // When we're delaying, we move both actions to the back
+ pDestAction = rgReorderedActions + iNextDelayableAction;
+ memcpy_s(pDestAction, 2 * sizeof(BURN_EXECUTE_ACTION), pSourceAction, 2 * sizeof(BURN_EXECUTE_ACTION));
+
+ iNextDelayableAction += 2;
+ ++i;
+ }
+ else
+ {
+ pDestAction = rgReorderedActions + iNextAction;
+ memcpy_s(pDestAction, sizeof(BURN_EXECUTE_ACTION), pSourceAction, sizeof(BURN_EXECUTE_ACTION));
+
+ ++iNextAction;
+ }
+ }
+ ExitOnNull((iNextDelayableAction == cActions), hr, E_UNEXPECTED, "Unexpected last delayable execute location: %u instead of %u", iNextDelayableAction, cActions);
+
+ // Nullify rollback boundaries in delayed execute checkpoints. Otherwise we might rollback past boudaries
+ for (DWORD i = 0; i < cActions; ++i)
+ {
+ BURN_EXECUTE_ACTION* pAction = rgActions + i;
+
+ if (pAction->type == BURN_EXECUTE_ACTION_TYPE_CHECKPOINT)
+ {
+ //TODO: Need to set new checkpoint numbers?
+ pAction->checkpoint.pActiveRollbackBoundary = NULL;
+ }
+ }
+
+ memcpy_s(rgCacheActions, cCacheActions * sizeof(BURN_CACHE_ACTION), rgReorderedCacheActions, cCacheActions * sizeof(BURN_CACHE_ACTION));
+ memcpy_s(rgActions, cActions * sizeof(BURN_EXECUTE_ACTION), rgReorderedActions, cActions * sizeof(BURN_EXECUTE_ACTION));
+
+LExit:
+ ReleaseMem(rgReorderedCacheActions);
+ ReleaseMem(rgReorderedActions);
+}
+
static void CalculateExpectedRegistrationStates(
__in BURN_PACKAGE* rgPackages,
__in DWORD cPackages
@@ -3055,6 +3252,14 @@ static void CacheActionLog(
LogStringLine(PlanDumpLevel, "%ls action[%u]: SIGNAL_SYNCPOINT package id: %ls, event handle: 0x%p", wzBase, iAction, pAction->syncpoint.pPackage->sczId, pAction->syncpoint.pPackage->hCacheEvent);
break;
+ case BURN_CACHE_ACTION_TYPE_DELAYABLE_START:
+ LogStringLine(PlanDumpLevel, "%ls action[%u]: delayable start", wzBase, iAction);
+ break;
+
+ case BURN_CACHE_ACTION_TYPE_DELAYABLE_END:
+ LogStringLine(PlanDumpLevel, "%ls action[%u]: delayable end", wzBase, iAction);
+ break;
+
default:
AssertSz(FALSE, "Unknown cache action type.");
break;
@@ -3278,87 +3483,3 @@ extern "C" void PlanDump(
LogStringLine(PlanDumpLevel, "--- End plan dump ---");
}
-
-// Reorder the packages: Executing packages first. This will ensure cache-only packages will not block executing packages until they get cached
-static void PlanReorderPackages(
- __in BURN_PACKAGE* rgPackages,
- __in DWORD cPackages
-)
-{
- HRESULT hr = S_OK;
- BURN_PACKAGE* rgOrderedPackages = NULL;
- DWORD iNextExecutingLocation = 0;
- DWORD iNextNonExecutingLocation = 0;
- DWORD cExecutingPackages = 0;
-
- if (cPackages < 2)
- {
- ExitFunction();
- }
-
- rgOrderedPackages = (BURN_PACKAGE*)MemAlloc(cPackages * sizeof(BURN_PACKAGE), TRUE);
- ExitOnNull(rgOrderedPackages, hr, E_OUTOFMEMORY, "Failed to allocate memory to reorder packages");
-
- // Count the packages that can be moved to the end
- for (DWORD i = 0; i < cPackages; ++i)
- {
- BOOL fExecuting = rgPackages[i].compatiblePackage.fRequested || (BOOTSTRAPPER_REQUEST_STATE_NONE != rgPackages[i].requested && BOOTSTRAPPER_REQUEST_STATE_CACHE != rgPackages[i].requested);
- if (fExecuting)
- {
- ++cExecutingPackages;
- }
- }
- if ((cExecutingPackages == 0) || (cExecutingPackages == cPackages))
- {
- ExitFunction();
- }
-
- // Reorder the packages on the temporary array
- iNextExecutingLocation = 0;
- iNextNonExecutingLocation = cExecutingPackages;
- for (DWORD i = 0; i < cPackages; ++i)
- {
- BOOL fExecuting = rgPackages[i].compatiblePackage.fRequested || (BOOTSTRAPPER_REQUEST_STATE_NONE != rgPackages[i].requested && BOOTSTRAPPER_REQUEST_STATE_CACHE != rgPackages[i].requested);
- if (fExecuting)
- {
- memcpy_s(&rgOrderedPackages[iNextExecutingLocation], sizeof(BURN_PACKAGE), &rgPackages[i], sizeof(BURN_PACKAGE));
- ++iNextExecutingLocation;
- }
- else
- {
- LogId(REPORT_STANDARD, MSG_REORDERING_PACKAGE, rgPackages[i].sczId);
-
- memcpy_s(&rgOrderedPackages[iNextNonExecutingLocation], sizeof(BURN_PACKAGE), &rgPackages[i], sizeof(BURN_PACKAGE));
- ++iNextNonExecutingLocation;
- }
- }
-
- // Copy temp array to original
- memcpy_s(rgPackages, cPackages * sizeof(BURN_PACKAGE), rgOrderedPackages, cPackages * sizeof(BURN_PACKAGE));
-
-LExit:
- ReleaseMem(rgOrderedPackages);
-}
-
-// Unlike PlanReorderPackages, this must succeed. Otherwise a wrong order may be planned on a re-plan
-static void PlanRestorePackagesOrder(
- __in BURN_PACKAGE* rgPackages,
- __in DWORD cPackages
-)
-{
- for (DWORD i = 0; i < cPackages; ++i)
- {
- // https://en.wikipedia.org/wiki/100_prisoners_problem
- // In the worst case scenario, this loop would take cPackages cycles, after which all packages would be in place
- // In the common case, each time this loop would take just a few cycles which would order some of the packages
- // The entire for+while loops can take no longer than 2*cPackages cycles
- while (rgPackages[i].dwPackageIndex != i)
- {
- BURN_PACKAGE tmpPackage = {};
-
- memcpy_s(&tmpPackage, sizeof(BURN_PACKAGE), &rgPackages[i], sizeof(BURN_PACKAGE));
- memcpy_s(&rgPackages[i], sizeof(BURN_PACKAGE), &rgPackages[tmpPackage.dwPackageIndex], sizeof(BURN_PACKAGE));
- memcpy_s(&rgPackages[tmpPackage.dwPackageIndex], sizeof(BURN_PACKAGE), &tmpPackage, sizeof(BURN_PACKAGE));
- }
- }
-}
diff --git a/src/burn/engine/plan.h b/src/burn/engine/plan.h
index 60bfabbd9..1cdcb8349 100644
--- a/src/burn/engine/plan.h
+++ b/src/burn/engine/plan.h
@@ -35,6 +35,8 @@ enum BURN_CACHE_ACTION_TYPE
BURN_CACHE_ACTION_TYPE_ROLLBACK_PACKAGE,
BURN_CACHE_ACTION_TYPE_SIGNAL_SYNCPOINT,
BURN_CACHE_ACTION_TYPE_CONTAINER,
+ BURN_CACHE_ACTION_TYPE_DELAYABLE_START,
+ BURN_CACHE_ACTION_TYPE_DELAYABLE_END,
};
enum BURN_EXECUTE_ACTION_TYPE
diff --git a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj
index c86c1e483..6554fd208 100644
--- a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj
+++ b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj
@@ -91,6 +91,7 @@
+
diff --git a/src/burn/test/BurnUnitTest/PlanTest.cpp b/src/burn/test/BurnUnitTest/PlanTest.cpp
index 3564fa36f..afa4e0c34 100644
--- a/src/burn/test/BurnUnitTest/PlanTest.cpp
+++ b/src/burn/test/BurnUnitTest/PlanTest.cpp
@@ -18,6 +18,7 @@ static LPCWSTR wzSingleMsiManifestFileName = L"BasicFunctionality_BundleA_manife
static LPCWSTR wzSingleMsuManifestFileName = L"MsuPackageFixture_manifest.xml";
static LPCWSTR wzSlipstreamManifestFileName = L"Slipstream_BundleA_manifest.xml";
static LPCWSTR wzSlipstreamModifiedManifestFileName = L"Slipstream_BundleA_modified_manifest.xml";
+static LPCWSTR wzCacheReorderManifestFileName = L"CacheReorder_BundleAv1_manifest.xml";
static BOOL vfUsePackageRequestState = FALSE;
static BOOTSTRAPPER_REQUEST_STATE vPackageRequestState = BOOTSTRAPPER_REQUEST_STATE_NONE;
@@ -659,6 +660,159 @@ namespace Bootstrapper
ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[2], L"PackageC", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT);
}
+ [Fact]
+ void CacheReorderInstallTest()
+ {
+ HRESULT hr = S_OK;
+ BURN_ENGINE_STATE engineState = { };
+ BURN_ENGINE_STATE* pEngineState = &engineState;
+ BURN_PLAN* pPlan = &engineState.plan;
+
+ InitializeEngineStateForCorePlan(wzCacheReorderManifestFileName, pEngineState);
+ DetectPackagesAsAbsent(pEngineState);
+ DetectPackageAsPresentAndCached(&pEngineState->packages.rgPackages[1]);
+
+ hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL);
+ NativeAssert::Succeeded(hr, "CorePlan failed");
+
+ Assert::Equal(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action);
+ NativeAssert::StringEqual(L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", pPlan->wzBundleId);
+ NativeAssert::StringEqual(L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", pPlan->wzBundleProviderKey);
+ Assert::Equal(FALSE, pPlan->fEnabledForwardCompatibleBundle);
+ Assert::Equal(TRUE, pPlan->fPerMachine);
+ Assert::Equal(TRUE, pPlan->fCanAffectMachineState);
+ Assert::Equal(FALSE, pPlan->fDisableRollback);
+ Assert::Equal(FALSE, pPlan->fDisallowRemoval);
+ Assert::Equal(FALSE, pPlan->fDowngrade);
+ Assert::Equal(BURN_REGISTRATION_ACTION_OPERATIONS_CACHE_BUNDLE | BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_PROVIDER_KEY, pPlan->dwRegistrationOperations);
+
+ BOOL fRollback = FALSE;
+ DWORD dwIndex = 0;
+ ValidateDependentRegistrationAction(pPlan, fRollback, dwIndex++, TRUE, L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}");
+ Assert::Equal(dwIndex, pPlan->cRegistrationActions);
+
+ fRollback = TRUE;
+ dwIndex = 0;
+ ValidateDependentRegistrationAction(pPlan, fRollback, dwIndex++, FALSE, L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}");
+ Assert::Equal(dwIndex, pPlan->cRollbackRegistrationActions);
+
+ fRollback = FALSE;
+ dwIndex = 0;
+ ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
+ ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE);
+ ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA");
+ ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 12);
+ ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageC", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE);
+ ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageC");
+ ValidateCacheDelayableStart(pPlan, fRollback, dwIndex++);
+ ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 7);
+ ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageB", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE);
+ ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageB");
+ ValidateCacheDelayableEnd(pPlan, fRollback, dwIndex++);
+ Assert::Equal(dwIndex, pPlan->cCacheActions);
+
+ fRollback = TRUE;
+ dwIndex = 0;
+ ValidateCacheRollbackPackage(pPlan, fRollback, dwIndex++, L"PackageA");
+ ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
+ ValidateCacheRollbackPackage(pPlan, fRollback, dwIndex++, L"PackageC");
+ ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 12);
+ ValidateCacheDelayableStart(pPlan, fRollback, dwIndex++);
+ ValidateCacheRollbackPackage(pPlan, fRollback, dwIndex++, L"PackageB");
+ ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 7);
+ ValidateCacheDelayableEnd(pPlan, fRollback, dwIndex++);
+ Assert::Equal(dwIndex, pPlan->cRollbackCacheActions);
+
+ Assert::Equal(522548ull, pPlan->qwCacheSizeTotal);
+
+ fRollback = FALSE;
+ dwIndex = 0;
+ DWORD dwExecuteCheckpointId = 2;
+ ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE);
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"PackageA");
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", registerActions1, 1);
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, BOOTSTRAPPER_MSI_FILE_VERSIONING_MISSING_OR_OLDER, 0);
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", registerActions1, 1);
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ dwExecuteCheckpointId += 2; // skip delayed package cache
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageB", registerActions1, 1);
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageB", L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", registerActions1, 1);
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ dwExecuteCheckpointId += 1; // cache checkpoints
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"PackageC");
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageC", registerActions1, 1);
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageC", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, BOOTSTRAPPER_MSI_FILE_VERSIONING_MISSING_OR_OLDER, 0);
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageC", L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", registerActions1, 1);
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ dwExecuteCheckpointId += 1; // cache checkpoints
+ ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++);
+ dwExecuteCheckpointId = 8; // Delayed cache checkpoint
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"PackageB");
+ Assert::Equal(dwIndex, pPlan->cExecuteActions);
+
+ fRollback = TRUE;
+ dwIndex = 0;
+ dwExecuteCheckpointId = 2;
+ ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE);
+ ValidateExecuteUncachePackage(pPlan, fRollback, dwIndex++, L"PackageA");
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", unregisterActions1, 1);
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, BOOTSTRAPPER_MSI_FILE_VERSIONING_MISSING_OR_OLDER, 0);
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", unregisterActions1, 1);
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ ValidateExecuteUncachePackage(pPlan, fRollback, dwIndex++, L"PackageB");
+ dwExecuteCheckpointId += 1; // cache checkpoints
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageB", unregisterActions1, 1);
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageB", L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", unregisterActions1, 1);
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ ValidateExecuteUncachePackage(pPlan, fRollback, dwIndex++, L"PackageC");
+ dwExecuteCheckpointId += 1; // cache checkpoints
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageC", unregisterActions1, 1);
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageC", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, BOOTSTRAPPER_MSI_FILE_VERSIONING_MISSING_OR_OLDER, 0);
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageC", L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", unregisterActions1, 1);
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++);
+ Assert::Equal(dwIndex, pPlan->cRollbackActions);
+
+ Assert::Equal(2ul, pPlan->cExecutePackagesTotal);
+ Assert::Equal(5ul, pPlan->cOverallProgressTicksTotal);
+
+ dwIndex = 0;
+ Assert::Equal(dwIndex, pPlan->cCleanActions);
+
+ UINT uIndex = 0;
+ ValidatePlannedProvider(pPlan, uIndex++, L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", NULL);
+ Assert::Equal(uIndex, pPlan->cPlannedProviders);
+
+ Assert::Equal(3ul, pEngineState->packages.cPackages);
+ ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT);
+ ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[1], L"PackageB", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT);
+ ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[2], L"PackageC", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT);
+ }
+
[Fact]
void MsiTransactionUninstallTest()
{
@@ -1686,15 +1840,19 @@ namespace Bootstrapper
fRollback = FALSE;
dwIndex = 0;
+ ValidateCacheDelayableStart(pPlan, fRollback, dwIndex++);
ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE);
ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA");
+ ValidateCacheDelayableEnd(pPlan, fRollback, dwIndex++);
Assert::Equal(dwIndex, pPlan->cCacheActions);
fRollback = TRUE;
dwIndex = 0;
+ ValidateCacheDelayableStart(pPlan, fRollback, dwIndex++);
ValidateCacheRollbackPackage(pPlan, fRollback, dwIndex++, L"PackageA");
ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
+ ValidateCacheDelayableEnd(pPlan, fRollback, dwIndex++);
Assert::Equal(dwIndex, pPlan->cRollbackCacheActions);
Assert::Equal(168715ull, pPlan->qwCacheSizeTotal);
@@ -2757,33 +2915,34 @@ namespace Bootstrapper
fRollback = FALSE;
dwIndex = 0;
- ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
- ValidateCachePackage(pPlan, fRollback, dwIndex++, L"NetFx48Web", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE);
- ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"NetFx48Web");
ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 3);
ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PatchA", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE);
ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PatchA");
ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 5);
ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE);
ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA");
+ ValidateCacheDelayableStart(pPlan, fRollback, dwIndex++);
+ ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
+ ValidateCachePackage(pPlan, fRollback, dwIndex++, L"NetFx48Web", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE);
+ ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"NetFx48Web");
+ ValidateCacheDelayableEnd(pPlan, fRollback, dwIndex++);
Assert::Equal(dwIndex, pPlan->cCacheActions);
fRollback = TRUE;
dwIndex = 0;
+ ValidateCacheDelayableStart(pPlan, fRollback, dwIndex++);
+ ValidateCacheDelayableEnd(pPlan, fRollback, dwIndex++);
Assert::Equal(dwIndex, pPlan->cRollbackCacheActions);
Assert::Equal(6130592ull, pPlan->qwCacheSizeTotal);
fRollback = FALSE;
dwIndex = 0;
- DWORD dwExecuteCheckpointId = 2;
+ DWORD dwExecuteCheckpointId = 4;
BURN_EXECUTE_ACTION* pExecuteAction = NULL;
ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE);
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
dwExecuteCheckpointId += 1; // cache checkpoints
- ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"NetFx48Web");
- ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
- dwExecuteCheckpointId += 1; // cache checkpoints
ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"PatchA");
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"PackageA");
@@ -2803,6 +2962,9 @@ namespace Bootstrapper
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++);
+ dwExecuteCheckpointId = 2; // Delayed cache checkpoint
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
+ ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"NetFx48Web");
Assert::Equal(dwIndex, pPlan->cExecuteActions);
fRollback = TRUE;
@@ -3535,6 +3697,26 @@ namespace Bootstrapper
return (fRollback ? pPlan->rgRollbackCacheActions : pPlan->rgCacheActions) + dwIndex;
}
+ void ValidateCacheDelayableStart(
+ __in BURN_PLAN* pPlan,
+ __in BOOL fRollback,
+ __in DWORD dwIndex
+ )
+ {
+ BURN_CACHE_ACTION* pAction = ValidateCacheActionExists(pPlan, fRollback, dwIndex);
+ Assert::Equal(BURN_CACHE_ACTION_TYPE_DELAYABLE_START, pAction->type);
+ }
+
+ void ValidateCacheDelayableEnd(
+ __in BURN_PLAN* pPlan,
+ __in BOOL fRollback,
+ __in DWORD dwIndex
+ )
+ {
+ BURN_CACHE_ACTION* pAction = ValidateCacheActionExists(pPlan, fRollback, dwIndex);
+ Assert::Equal(BURN_CACHE_ACTION_TYPE_DELAYABLE_END, pAction->type);
+ }
+
void ValidateCacheCheckpoint(
__in BURN_PLAN* pPlan,
__in BOOL fRollback,
diff --git a/src/burn/test/BurnUnitTest/TestData/PlanTest/CacheReorder_BundleAv1_manifest.xml b/src/burn/test/BurnUnitTest/TestData/PlanTest/CacheReorder_BundleAv1_manifest.xml
new file mode 100644
index 000000000..75351e2ee
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/TestData/PlanTest/CacheReorder_BundleAv1_manifest.xml
@@ -0,0 +1 @@
+