diff options
author | Karen Arutyunov <karen@codesynthesis.com> | 2024-05-21 22:37:35 +0300 |
---|---|---|
committer | Karen Arutyunov <karen@codesynthesis.com> | 2024-05-22 15:56:43 +0300 |
commit | 2d2dc7ccb2fff55fea9d5a87e98411d04f175f16 (patch) | |
tree | 584f2c4d19929a1face728c53e0abf278db42796 | |
parent | 801593731e61efba2141cdad1ff0559e501f97ae (diff) |
Fix post-simulation assertion in pkg-build (GH issue #382)
-rw-r--r-- | bpkg/pkg-build.cxx | 71 |
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); + } + } } } } |