aboutsummaryrefslogtreecommitdiff
path: root/bpkg
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2024-05-21 22:37:35 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2024-05-22 15:56:43 +0300
commit2d2dc7ccb2fff55fea9d5a87e98411d04f175f16 (patch)
tree584f2c4d19929a1face728c53e0abf278db42796 /bpkg
parent801593731e61efba2141cdad1ff0559e501f97ae (diff)
Fix post-simulation assertion in pkg-build (GH issue #382)
Diffstat (limited to 'bpkg')
-rw-r--r--bpkg/pkg-build.cxx71
1 files changed, 70 insertions, 1 deletions
diff --git a/bpkg/pkg-build.cxx b/bpkg/pkg-build.cxx
index fac79c2..adf7938 100644
--- a/bpkg/pkg-build.cxx
+++ b/bpkg/pkg-build.cxx
@@ -6871,12 +6871,81 @@ namespace bpkg
//
if (!rescan)
{
+ // Return true if the specified package is loaded as a
+ // prerequisite of some dependent package cached in the session
+ // and contained in a different database. Also unload this
+ // package from all such dependents.
+ //
+ auto unload_prereq = [&ses, &sp_session]
+ (const shared_ptr<selected_package>& sp,
+ const odb::database* db)
+ {
+ bool r (false);
+
+ for (const auto& dps: ses.map ())
+ {
+ // Skip dependents from the same database.
+ //
+ if (dps.first == db)
+ continue;
+
+ if (const selected_packages* sps = sp_session (dps.second))
+ {
+ for (const auto& p: *sps)
+ {
+ for (auto& pr: p.second->prerequisites)
+ {
+ const lazy_shared_ptr<selected_package>& lp (pr.first);
+
+ if (lp.loaded () && lp.get_eager () == sp)
+ {
+ lp.unload ();
+ r = true;
+ }
+ }
+ }
+ }
+ }
+
+ return r;
+ };
+
for (const auto& dps: ses.map ())
{
if (const selected_packages* sps = sp_session (dps.second))
{
if (old_sp.find (dps.first) == old_sp.end ())
- assert (sps->empty ());
+ {
+ // Note that the reason for these packages to still be
+ // present in the session is that they may be referenced
+ // as prerequisites by some dependent packages from other
+ // databases. For example:
+ //
+ // new session: A (D1, 2) -> B (D1, 2) -> C (D2, 2)
+ // old session: A
+ //
+ // Here C is the package in question, package A is present
+ // in both sessions, D* are databases, the numbers are the
+ // package reference counts, and the arrows denote the
+ // loaded prerequisite lazy pointers.
+ //
+ // Let's verify that by unloading these packages from such
+ // dependents and rescan.
+ //
+ if (!sps->empty ())
+ {
+ for (const auto& p: *sps)
+ {
+ if (unload_prereq (p.second, dps.first))
+ rescan = true;
+ }
+
+ // If we didn't unload any of these packages, then we
+ // consider this as a bug.
+ //
+ assert (rescan);
+ }
+ }
}
}
}