1.1 --- a/librazor/razor.c Wed Feb 01 12:47:50 2012 +0000
1.2 +++ b/librazor/razor.c Sat Feb 11 09:34:40 2012 +0000
1.3 @@ -1,7 +1,7 @@
1.4 /*
1.5 * Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
1.6 * Copyright (C) 2008 Red Hat, Inc
1.7 - * Copyright (C) 2009-2011 J. Ali Harlow <ali@juiblex.co.uk>
1.8 + * Copyright (C) 2009-2012 J. Ali Harlow <ali@juiblex.co.uk>
1.9 *
1.10 * This program is free software; you can redistribute it and/or modify
1.11 * it under the terms of the GNU General Public License as published by
1.12 @@ -992,6 +992,32 @@
1.13 }
1.14 }
1.15
1.16 +/*
1.17 + * Does <package> have a requirement for <script> which is
1.18 + * satisfied by <provider> ?
1.19 + * Note: We already know that <provider> is to be added as part of this install
1.20 + * so there is no need to check the relation.
1.21 + */
1.22 +static int
1.23 +package_script_requires(struct razor_set *set, struct razor_package *package,
1.24 + enum razor_property_flags script,
1.25 + struct razor_package *provider)
1.26 +{
1.27 + struct list *link;
1.28 + struct razor_property *prop;
1.29 +
1.30 + link = list_first(&package->properties, &set->property_pool);
1.31 + for(; link; link = list_next(link)) {
1.32 + prop = set->properties.data;
1.33 + prop += link->data;
1.34 + if ((prop->flags & RAZOR_PROPERTY_SCRIPT_MASK) & script &&
1.35 + (prop->flags & RAZOR_PROPERTY_TYPE_MASK) == RAZOR_PROPERTY_REQUIRES &&
1.36 + provider->name == prop->name)
1.37 + return 1;
1.38 + }
1.39 + return 0;
1.40 +}
1.41 +
1.42 RAZOR_EXPORT struct razor_install_iterator *
1.43 razor_set_create_install_iterator(struct razor_set *set,
1.44 struct razor_set *next)
1.45 @@ -1002,10 +1028,12 @@
1.46 * A->B means action A should follow action B.
1.47 */
1.48 struct graph follows;
1.49 - struct install_action *actions, *ai, *aj;
1.50 + struct install_action *actions, *ai, *aj, *an;
1.51 int i, j, count, vertex_added;
1.52 struct list *link;
1.53 struct razor_set *rs;
1.54 + struct deque *order;
1.55 + int barrier_needed;
1.56
1.57 assert (set != NULL);
1.58 assert (next != NULL);
1.59 @@ -1066,7 +1094,73 @@
1.60 graph_add_edge(&follows, i, i);
1.61 }
1.62
1.63 - ii->order = graph_sort(&follows);
1.64 + /*
1.65 + * Because files are installed and removed using razor_atomic,
1.66 + * but scripts are run with no regard for these, we need some
1.67 + * means for synchronisation between the two. We support this
1.68 + * via transaction barriers which are points where
1.69 + * razor_atomic_commit() should be called so that scripts can
1.70 + * rely on the files they need being present.
1.71 + *
1.72 + * Rules:
1.73 + * 1) Transaction barriers never occur within a dependency
1.74 + * loop. Since we can't guarantee any ordering of actions
1.75 + * within such a loop, they make no sense.
1.76 + * 2) Otherwise the following table applies:
1.77 + * Action I Action J Barrier between I and J iff
1.78 + * ADD P ADD Q %pre(Q) requires P
1.79 + * ADD P REMOVE Q %preun(Q) requires P
1.80 + * REMOVE P ADD Q never
1.81 + * REMOVE P REMOVE Q %postun(P) requires Q
1.82 + *
1.83 + * FIXME:
1.84 + * This should take account of conflicts somehow.
1.85 + */
1.86 + order = graph_sort(&follows);
1.87 + ii->order = deque_new(0);
1.88 + if (!deque_empty(order)) {
1.89 + j = deque_pop(order);
1.90 + deque_unshift(ii->order, j);
1.91 + }
1.92 + while (!deque_empty(order)) {
1.93 + i = j;
1.94 + j = deque_pop(order);
1.95 + ai = actions + i;
1.96 + aj = actions + j;
1.97 + if (graph_is_connected(&follows, i, j) &&
1.98 + graph_is_connected(&follows, j, i))
1.99 + barrier_needed = 0;
1.100 + else if (ai->action == RAZOR_INSTALL_ACTION_ADD &&
1.101 + aj->action == RAZOR_INSTALL_ACTION_ADD &&
1.102 + package_script_requires(next, aj->package,
1.103 + RAZOR_PROPERTY_PRE,
1.104 + ai->package))
1.105 + barrier_needed = 1;
1.106 + else if (ai->action == RAZOR_INSTALL_ACTION_ADD &&
1.107 + aj->action == RAZOR_INSTALL_ACTION_REMOVE &&
1.108 + package_script_requires(set, aj->package,
1.109 + RAZOR_PROPERTY_PREUN,
1.110 + ai->package))
1.111 + barrier_needed = 1;
1.112 + else if (ai->action == RAZOR_INSTALL_ACTION_REMOVE &&
1.113 + aj->action == RAZOR_INSTALL_ACTION_REMOVE &&
1.114 + package_script_requires(set, ai->package,
1.115 + RAZOR_PROPERTY_POSTUN,
1.116 + aj->package))
1.117 + barrier_needed = 1;
1.118 + else
1.119 + barrier_needed = 0;
1.120 + if (barrier_needed) {
1.121 + an = array_add(&ii->actions, sizeof *an);
1.122 + actions = ii->actions.data;
1.123 + an->package = NULL;
1.124 + an->action = RAZOR_INSTALL_ACTION_COMMIT;
1.125 + deque_unshift(ii->order, an - actions);
1.126 + }
1.127 + deque_unshift(ii->order, j);
1.128 + }
1.129 + deque_free(order);
1.130 +
1.131 ii->left = deque_dup(ii->order);
1.132 graph_release(&follows);
1.133
1.134 @@ -1105,12 +1199,99 @@
1.135 (*count)++;
1.136 }
1.137 razor_package_iterator_destroy(pi);
1.138 - } else
1.139 + } else if (a->action == RAZOR_INSTALL_ACTION_ADD)
1.140 *count = 1;
1.141
1.142 return 1;
1.143 }
1.144
1.145 +static int
1.146 +action_is_included(struct razor_install_iterator *ii, struct deque *done,
1.147 + struct razor_package *package,
1.148 + enum razor_install_action action)
1.149 +{
1.150 + struct deque *t;
1.151 + struct install_action *a;
1.152 + int retval;
1.153 +
1.154 + t = deque_dup(done);
1.155 +
1.156 + while(!deque_empty(t)) {
1.157 + a = (struct install_action *)ii->actions.data + deque_pop(t);
1.158 + if (a->package == package && a->action == action)
1.159 + break;
1.160 + }
1.161 + retval = !deque_empty(t);
1.162 +
1.163 + deque_free(t);
1.164 +
1.165 + return retval;
1.166 +}
1.167 +
1.168 +RAZOR_EXPORT struct razor_set *
1.169 +razor_install_iterator_commit_set(struct razor_install_iterator *ii)
1.170 +{
1.171 + struct razor_merger *merger;
1.172 + struct razor_set *set;
1.173 + struct razor_package *n, *nend, *npkgs, *s, *send, *spkgs;
1.174 + struct deque *done;
1.175 + size_t pos;
1.176 + char *npool, *spool;
1.177 + int cmp;
1.178 +
1.179 + done = deque_dup(ii->order);
1.180 + pos = razor_install_iterator_tell(ii);
1.181 + while(deque_length(done) > pos)
1.182 + deque_shift(done);
1.183 +
1.184 + s = ii->set->packages.data;
1.185 + spkgs = ii->set->packages.data;
1.186 + send = ii->set->packages.data + ii->set->packages.size;
1.187 + spool = ii->set->string_pool.data;
1.188 +
1.189 + n = ii->next->packages.data;
1.190 + npkgs = ii->next->packages.data;
1.191 + nend = ii->next->packages.data + ii->next->packages.size;
1.192 + npool = ii->next->string_pool.data;
1.193 +
1.194 + merger = razor_merger_create(ii->set, ii->next);
1.195 + while (s < send || n < nend) {
1.196 + if (s < send && n < nend)
1.197 + cmp = strcmp(&spool[s->name], &npool[n->name]);
1.198 + else if (s < send)
1.199 + cmp = -1;
1.200 + else
1.201 + cmp = 1;
1.202 +
1.203 + if (cmp < 0) {
1.204 + if (!action_is_included(ii, done, s,
1.205 + RAZOR_INSTALL_ACTION_REMOVE))
1.206 + razor_merger_add_package(merger, s);
1.207 + s++;
1.208 + } else if (cmp == 0) {
1.209 + if (!action_is_included(ii, done, s,
1.210 + RAZOR_INSTALL_ACTION_REMOVE))
1.211 + razor_merger_add_package(merger, s);
1.212 + if (action_is_included(ii, done, n,
1.213 + RAZOR_INSTALL_ACTION_ADD))
1.214 + razor_merger_add_package(merger, n);
1.215 +
1.216 + s++;
1.217 + n++;
1.218 + } else {
1.219 + if (action_is_included(ii, done, n,
1.220 + RAZOR_INSTALL_ACTION_ADD))
1.221 + razor_merger_add_package(merger, n);
1.222 + n++;
1.223 + }
1.224 + }
1.225 +
1.226 + set = razor_merger_commit(merger);
1.227 + razor_merger_destroy(merger);
1.228 +
1.229 + return set;
1.230 +}
1.231 +
1.232 RAZOR_EXPORT void
1.233 razor_install_iterator_rewind(struct razor_install_iterator *ii)
1.234 {
1.235 @@ -1118,6 +1299,35 @@
1.236 ii->left=deque_dup(ii->order);
1.237 }
1.238
1.239 +RAZOR_EXPORT size_t
1.240 +razor_install_iterator_tell(struct razor_install_iterator *ii)
1.241 +{
1.242 + return deque_length(ii->order) - deque_length(ii->left);
1.243 +}
1.244 +
1.245 +RAZOR_EXPORT size_t
1.246 +razor_install_iterator_seek(struct razor_install_iterator *ii, size_t pos)
1.247 +{
1.248 + size_t current_pos;
1.249 +
1.250 + if (pos > deque_length(ii->order))
1.251 + pos = deque_length(ii->order);
1.252 +
1.253 + current_pos = razor_install_iterator_tell(ii);
1.254 +
1.255 + if (pos < current_pos) {
1.256 + razor_install_iterator_rewind(ii);
1.257 + current_pos = 0;
1.258 + }
1.259 +
1.260 + while(current_pos < pos) {
1.261 + (void) deque_pop(ii->left);
1.262 + current_pos++;
1.263 + }
1.264 +
1.265 + return current_pos;
1.266 +}
1.267 +
1.268 RAZOR_EXPORT void
1.269 razor_install_iterator_destroy(struct razor_install_iterator *ii)
1.270 {