librazor/razor.c
changeset 418 33b825d3128d
parent 411 b1dcf22c0418
child 422 6fa783097ca1
     1.1 --- a/librazor/razor.c	Wed Feb 01 12:47:50 2012 +0000
     1.2 +++ b/librazor/razor.c	Thu Feb 09 20:45:27 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  {