Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
scheduler: only split upgrade jobs if needed
Isaac Freund committed 8 months ago
commit 829033df799d62c41df0b0dc0baea9d93f9a5d2c
parent 24d66e6
2 files changed +45 -18
modified libpkg/pkg_jobs_schedule.c
@@ -403,23 +403,52 @@ int pkg_jobs_schedule(struct pkg_jobs *j)

		dbg(3, "job scheduling graph cycle found");
		assert(path != NULL);
+
		assert(path->path_prev != NULL);
		assert(path != cycle);

-
		/* Choose an arbitrary upgrade job in the cycle to split in order
-
		 * to break the cycle.
+
		/* Close the path into a cycle to eliminate some edge cases in the loop. */
+
		cycle->path_prev = path;
+

+
		/* Not all upgrade jobs would break the cycle if split.
+
		 * It is helpful to think of each upgrade job as two separate
+
		 * nodes, the remove half and the install half. If a cycle only
+
		 * involved one half of the upgrade job, splitting the upgrade
+
		 * job would not break the cycle or even change its length.
		 *
-
		 * TODO: Does it truly not matter which upgrade job in the cycle we
-
		 * choose to split? I'm relatively confident that splitting any upgrade job
-
		 * will break the given cycle but is it possible that one of the choices
-
		 * would break additional cycles as well?
+
		 * Furthermore, since there is an edge from the remove half of
+
		 * an upgrade job to the install half, the install half must
+
		 * come *before* the remove half in the cycle. Otherwise
+
		 * splitting the upgrade job will only make the cycle one node
+
		 * longer.
		 */
-
		while (path->type != PKG_SOLVED_UPGRADE) {
+
		enum pkg_jobs_schedule_graph_edge_type out =
+
		    pkg_jobs_schedule_graph_edge(path, cycle);
+
		assert(out != PKG_SCHEDULE_EDGE_NONE);
+
		enum pkg_jobs_schedule_graph_edge_type in =
+
		    pkg_jobs_schedule_graph_edge(path->path_prev, path);
+
		assert(in != PKG_SCHEDULE_EDGE_NONE);
+
		while (true) {
+
			if (path->type == PKG_SOLVED_UPGRADE) {
+
				assert(out != PKG_SCHEDULE_EDGE_SPLIT_UPGRADE);
+
				assert(in != PKG_SCHEDULE_EDGE_SPLIT_UPGRADE);
+
				if ((out == PKG_SCHEDULE_EDGE_OLD_DEP_OLD ||
+
				     out == PKG_SCHEDULE_EDGE_OLD_CONFLICT_NEW) &&
+
				    (in == PKG_SCHEDULE_EDGE_NEW_DEP_NEW ||
+
				     in == PKG_SCHEDULE_EDGE_OLD_CONFLICT_NEW)) {
+
					/* Found an upgrade job that would break
+
					 * the cycle if split. */
+
					break;
+
				}
+
			}
			if (path == cycle) {
-
				pkg_emit_error("found job scheduling cycle without upgrade job");
+
				pkg_emit_error("failed to break job scheduling cycle");
			 	return (EPKG_FATAL);
			}
			path = path->path_prev;
			assert(path != NULL);
+
			out = in;
+
			in = pkg_jobs_schedule_graph_edge(path->path_prev, path);
+
			assert(in != PKG_SCHEDULE_EDGE_NONE);
		}

		/* path is now the upgrade job chosen to be split */
modified tests/frontend/conflicts.sh
@@ -590,16 +590,14 @@ Installed packages to be REINSTALLED:
Number of packages to be installed: 1
Number of packages to be upgraded: 1
Number of packages to be reinstalled: 1
-
${JAILED}[1/5] Deinstalling testb-2...
-
${JAILED}[1/5] Deleting files for testb-2:  done
-
${JAILED}[2/5] Deinstalling testa-2.0...
-
${JAILED}[2/5] Deleting files for testa-2.0:  done
-
${JAILED}[3/5] Installing testa-lib-2.0...
-
${JAILED}[3/5] Extracting testa-lib-2.0:  done
-
${JAILED}[4/5] Installing testa-2.1...
-
${JAILED}[4/5] Extracting testa-2.1:  done
-
${JAILED}[5/5] Installing testb-2...
-
${JAILED}[5/5] Extracting testb-2:  done
+
${JAILED}[1/4] Deinstalling testb-2...
+
${JAILED}[1/4] Deleting files for testb-2:  done
+
${JAILED}[2/4] Upgrading testa from 2.0 to 2.1...
+
${JAILED}[2/4] Extracting testa-2.1:  done
+
${JAILED}[3/4] Installing testa-lib-2.0...
+
${JAILED}[3/4] Extracting testa-lib-2.0:  done
+
${JAILED}[4/4] Installing testb-2...
+
${JAILED}[4/4] Extracting testb-2:  done
"
	atf_check \
		-o inline:"${OUTPUT}" \