unit: place reservations before merging other's dependencies

With the hashmap implementation that uses chaining the reservations
merely ensure that the merging won't result in long bucket chains.

With a future alternative implementation it will additionally reserve
memory to make sure the merging won't fail.
This commit is contained in:
Michal Schmidt
2014-10-23 17:38:02 +02:00
parent 2d5c93c7af
commit 09a65f9299
+33
View File
@@ -585,6 +585,27 @@ static void merge_names(Unit *u, Unit *other) {
assert_se(hashmap_replace(u->manager->units, t, u) == 0);
}
static int reserve_dependencies(Unit *u, Unit *other, UnitDependency d) {
unsigned n_reserve;
assert(u);
assert(other);
assert(d < _UNIT_DEPENDENCY_MAX);
/*
* If u does not have this dependency set allocated, there is no need
* to reserve anything. In that case other's set will be transfered
* as a whole to u by complete_move().
*/
if (!u->dependencies[d])
return 0;
/* merge_dependencies() will skip a u-on-u dependency */
n_reserve = set_size(other->dependencies[d]) - !!set_get(other->dependencies[d], u);
return set_reserve(u->dependencies[d], n_reserve);
}
static void merge_dependencies(Unit *u, Unit *other, const char *other_id, UnitDependency d) {
Iterator i;
Unit *back;
@@ -627,6 +648,7 @@ static void merge_dependencies(Unit *u, Unit *other, const char *other_id, UnitD
int unit_merge(Unit *u, Unit *other) {
UnitDependency d;
const char *other_id = NULL;
int r;
assert(u);
assert(other);
@@ -660,6 +682,17 @@ int unit_merge(Unit *u, Unit *other) {
if (other->id)
other_id = strdupa(other->id);
/* Make reservations to ensure merge_dependencies() won't fail */
for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) {
r = reserve_dependencies(u, other, d);
/*
* We don't rollback reservations if we fail. We don't have
* a way to undo reservations. A reservation is not a leak.
*/
if (r < 0)
return r;
}
/* Merge names */
merge_names(u, other);