librazor/merger.c
author J. Ali Harlow <ali@juiblex.co.uk>
Wed Apr 29 17:00:01 2009 +0100 (2009-04-29)
changeset 361 2523d03a840e
parent 348 3ad2e14e4cb7
child 369 f8c27fe9fe63
permissions -rw-r--r--
Add support for preloading lua modules. This is useful both when
providing lua bindings to applications based on librazor and when
producing static binaries using librazor (where otherwise the lua
POSIX library would need to be included as an additional dynamic
object).
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  *
     5  * This program is free software; you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation; either version 2 of the License, or
     8  * (at your option) any later version.
     9  *
    10  * This program is distributed in the hope that it will be useful,
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  * GNU General Public License for more details.
    14  *
    15  * You should have received a copy of the GNU General Public License along
    16  * with this program; if not, write to the Free Software Foundation, Inc.,
    17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    18  */
    19 
    20 #include <string.h>
    21 #include "razor-internal.h"
    22 #include "razor.h"
    23 
    24 #define UPSTREAM_SOURCE 0x80
    25 
    26 struct source {
    27 	struct razor_set *set;
    28 	uint32_t *property_map;
    29 	uint32_t *file_map;
    30 };
    31 
    32 struct razor_merger {
    33 	struct razor_set *set;
    34 	struct hashtable table;
    35 	struct hashtable file_table;
    36 	struct source source1;
    37 	struct source source2;
    38 };
    39 
    40 struct razor_merger *
    41 razor_merger_create(struct razor_set *set1, struct razor_set *set2)
    42 {
    43 	struct razor_merger *merger;
    44 	int count;
    45 	size_t size;
    46 
    47 	merger = zalloc(sizeof *merger);
    48 	merger->set = razor_set_create();
    49 	hashtable_init(&merger->table, &merger->set->string_pool);
    50 	hashtable_init(&merger->file_table, &merger->set->file_string_pool);
    51 
    52 	merger->source1.set = set1;
    53 	count = set1->properties.size / sizeof (struct razor_property);
    54 	size = count * sizeof merger->source1.property_map[0];
    55 	merger->source1.property_map = zalloc(size);
    56 	count = set1->files.size / sizeof (struct razor_entry);
    57 	size = count * sizeof merger->source1.file_map[0];
    58 	merger->source1.file_map = zalloc(size);
    59 
    60 	merger->source2.set = set2;
    61 	count = set2->properties.size / sizeof (struct razor_property);
    62 	size = count * sizeof merger->source2.property_map[0];
    63 	merger->source2.property_map = zalloc(size);
    64 	count = set2->files.size / sizeof (struct razor_entry);
    65 	size = count * sizeof merger->source2.file_map[0];
    66 	merger->source2.file_map = zalloc(size);
    67 
    68 	return merger;
    69 }
    70 
    71 void
    72 razor_merger_add_package(struct razor_merger *merger,
    73 			 struct razor_package *package)
    74 {
    75 	char *pool;
    76 	struct list *r;
    77 	struct razor_package *p;
    78 	struct razor_set *set1;
    79 	struct source *source;
    80 	uint32_t flags;
    81 
    82 	set1 = merger->source1.set;
    83 	if (set1->packages.data <= (void *) package &&
    84 	    (void *) package < set1->packages.data + set1->packages.size) {
    85 		source = &merger->source1;
    86 		flags = 0;
    87 	} else {
    88 		source = &merger->source2;
    89 		flags = UPSTREAM_SOURCE;
    90 	}
    91 
    92 	pool = source->set->string_pool.data;
    93 	p = array_add(&merger->set->packages, sizeof *p);
    94 	p->name = hashtable_tokenize(&merger->table, &pool[package->name]);
    95 	p->flags = flags;
    96 	p->version = hashtable_tokenize(&merger->table,
    97 					&pool[package->version]);
    98 	p->arch = hashtable_tokenize(&merger->table,
    99 				     &pool[package->arch]);
   100 
   101 	p->properties = package->properties;
   102 	r = list_first(&package->properties, &source->set->property_pool);
   103 	while (r) {
   104 		source->property_map[r->data] = 1;
   105 		r = list_next(r);
   106 	}
   107 
   108 	p->files = package->files;
   109 	r = list_first(&package->files, &source->set->file_pool);
   110 	while (r) {
   111 		source->file_map[r->data] = 1;
   112 		r = list_next(r);
   113 	}
   114 }
   115 
   116 static uint32_t
   117 add_property(struct razor_merger *merger,
   118 	     const char *name, uint32_t flags, const char *version)
   119 {
   120 	struct razor_property *p;
   121 
   122 	p = array_add(&merger->set->properties, sizeof *p);
   123 	p->name = hashtable_tokenize(&merger->table, name);
   124 	p->flags = flags;
   125 	p->version = hashtable_tokenize(&merger->table, version);
   126 
   127 	return p - (struct razor_property *) merger->set->properties.data;
   128 }
   129 
   130 static void
   131 merge_properties(struct razor_merger *merger)
   132 {
   133 	struct razor_property *p1, *p2;
   134 	struct razor_set *set1, *set2;
   135 	uint32_t *map1, *map2;
   136 	int i, j, cmp, count1, count2;
   137 	char *pool1, *pool2;
   138 
   139 	set1 = merger->source1.set;
   140 	set2 = merger->source2.set;
   141 	map1 = merger->source1.property_map;
   142 	map2 = merger->source2.property_map;
   143 
   144 	i = 0;
   145 	j = 0;
   146 	pool1 = set1->string_pool.data;
   147 	pool2 = set2->string_pool.data;
   148 
   149 	count1 = set1->properties.size / sizeof *p1;
   150 	count2 = set2->properties.size / sizeof *p2;
   151 	while (i < count1 || j < count2) {
   152 		if (i < count1 && map1[i] == 0) {
   153 			i++;
   154 			continue;
   155 		}
   156 		if (j < count2 && map2[j] == 0) {
   157 			j++;
   158 			continue;
   159 		}
   160 		p1 = (struct razor_property *) set1->properties.data + i;
   161 		p2 = (struct razor_property *) set2->properties.data + j;
   162 		if (i < count1 && j < count2)
   163 			cmp = strcmp(&pool1[p1->name], &pool2[p2->name]);
   164 		else if (i < count1)
   165 			cmp = -1;
   166 		else
   167 			cmp = 1;
   168 		if (cmp == 0)
   169 			cmp = p1->flags - p2->flags;
   170 		if (cmp == 0)
   171 			cmp = razor_versioncmp(&pool1[p1->version],
   172 					       &pool2[p2->version]);
   173 		if (cmp < 0) {
   174 			map1[i++] = add_property(merger,
   175 						 &pool1[p1->name],
   176 						 p1->flags,
   177 						 &pool1[p1->version]);
   178 		} else if (cmp > 0) {
   179 			map2[j++] = add_property(merger,
   180 						 &pool2[p2->name],
   181 						 p2->flags,
   182 						 &pool2[p2->version]);
   183 		} else  {
   184 			map1[i++] = map2[j++] =
   185 				add_property(merger,
   186 					     &pool1[p1->name],
   187 					     p1->flags,
   188 					     &pool1[p1->version]);
   189 		}
   190 	}
   191 }
   192 
   193 static void
   194 emit_properties(struct list_head *properties, struct array *source_pool,
   195 		uint32_t *map, struct array *pool)
   196 {
   197 	uint32_t r;
   198 	struct list *p, *q;
   199 
   200 	r = pool->size / sizeof *q;
   201 	p = list_first(properties, source_pool);
   202 	while (p) {
   203 		q = array_add(pool, sizeof *q);
   204 		q->data = map[p->data];
   205 		q->flags = p->flags;
   206 		p = list_next(p);
   207 	}
   208 
   209 	list_set_ptr(properties, r);
   210 }
   211 
   212 static uint32_t
   213 add_file(struct razor_merger *merger, const char *name)
   214 {
   215 	struct razor_entry *e;
   216 
   217 	e = array_add(&merger->set->files, sizeof *e);
   218 	e->name = hashtable_tokenize(&merger->file_table, name);
   219 	e->flags = 0;
   220 	e->start = 0;
   221 
   222 	return e - (struct razor_entry *)merger->set->files.data;
   223 }
   224 
   225 /* FIXME. Blah */
   226 static int
   227 fix_file_map(uint32_t *map,
   228 	     struct razor_entry *files,
   229 	     struct razor_entry *top)
   230 {
   231 	uint32_t e;
   232 	int found_file = 0;
   233 
   234 	e = top - files;
   235 	do {
   236 		if (files[e].start &&
   237 		    fix_file_map(map, files, &files[files[e].start]))
   238 			map[e] = 1;
   239 		if (map[e])
   240 			found_file = 1;
   241 	} while (!(files[e++].flags & RAZOR_ENTRY_LAST));
   242 
   243 	return found_file;
   244 }
   245 
   246 struct merge_directory {
   247 	uint32_t merged, dir1, dir2;
   248 };
   249 
   250 static void
   251 merge_one_directory(struct razor_merger *merger, struct merge_directory *md)
   252 {
   253 	struct razor_entry *root1, *root2, *mroot, *e1, *e2;
   254 	struct razor_set *set1, *set2;
   255 	struct array merge_stack;
   256 	struct merge_directory *child_md, *end_md;
   257 	uint32_t *map1, *map2, start, last;
   258 	int cmp;
   259 	char *pool1, *pool2;
   260 
   261 	set1 = merger->source1.set;
   262 	set2 = merger->source2.set;
   263 	map1 = merger->source1.file_map;
   264 	map2 = merger->source2.file_map;
   265 	pool1 = set1->file_string_pool.data;
   266 	pool2 = set2->file_string_pool.data;
   267 	root1 = (struct razor_entry *) set1->files.data;
   268 	root2 = (struct razor_entry *) set2->files.data;
   269 
   270 	array_init(&merge_stack);
   271 
   272 	start = merger->set->files.size / sizeof (struct razor_entry);
   273 	last = 0xFFFFFFFF;
   274 	e1 = md->dir1 != 0xFFFFFFFF ? root1 + md->dir1 : NULL;
   275 	e2 = md->dir2 != 0xFFFFFFFF ? root2 + md->dir2 : NULL;
   276 	while (e1 || e2) {
   277 		if (!e2 && !map1[e1 - root1]) {
   278 			if ((e1++)->flags & RAZOR_ENTRY_LAST)
   279 				e1 = NULL;
   280 			continue;
   281 		}
   282 		if (!e1 && !map2[e2 - root2]) {
   283 			if ((e2++)->flags & RAZOR_ENTRY_LAST)
   284 				e2 = NULL;
   285 			continue;
   286 		}
   287 		if (e1 && !map1[e1 - root1] &&
   288 		    e2 && !map2[e2 - root2]) {
   289 			if ((e1++)->flags & RAZOR_ENTRY_LAST)
   290 				e1 = NULL;
   291 			if ((e2++)->flags & RAZOR_ENTRY_LAST)
   292 				e2 = NULL;
   293 			continue;
   294 		}
   295 
   296 		if (!e1)
   297 			cmp = 1;
   298 		else if (!e2)
   299 			cmp = -1;
   300 		else {
   301 			cmp = strcmp (&pool1[e1->name],
   302 				      &pool2[e2->name]);
   303 		}
   304 
   305 		if (cmp < 0) {
   306 			if (map1[e1 - root1]) {
   307 				map1[e1 - root1] = last =
   308 					add_file(merger, &pool1[e1->name]);
   309 				if (e1->start) {
   310 					child_md = array_add(&merge_stack, sizeof (struct merge_directory));
   311 					child_md->merged = last;
   312 					child_md->dir1 = e1->start;
   313 					child_md->dir2 = 0xFFFFFFFF;
   314 				}
   315 			}
   316 			if ((e1++)->flags & RAZOR_ENTRY_LAST)
   317 				e1 = NULL;
   318 		} else if (cmp > 0) {
   319 			if (map2[e2 - root2]) {
   320 				map2[e2 - root2] = last =
   321 					add_file(merger, &pool2[e2->name]);
   322 				if (e2->start) {
   323 					child_md = array_add(&merge_stack, sizeof (struct merge_directory));
   324 					child_md->merged = last;
   325 					child_md->dir1 = 0xFFFFFFFF;
   326 					child_md->dir2 = e2->start;
   327 				}
   328 			}
   329 			if ((e2++)->flags & RAZOR_ENTRY_LAST)
   330 				e2 = NULL;
   331 		} else {
   332 			map1[e1 - root1] = map2[e2- root2] = last =
   333 				add_file(merger, &pool1[e1->name]);
   334 			if (e1->start || e2->start) {
   335 				child_md = array_add(&merge_stack, sizeof (struct merge_directory));
   336 				child_md->merged = last;
   337 				child_md->dir1 = e1->start ? e1->start : 0xFFFFFFFF;
   338 				child_md->dir2 = e2->start ? e2->start : 0xFFFFFFFF;
   339 			}
   340 			if ((e1++)->flags & RAZOR_ENTRY_LAST)
   341 				e1 = NULL;
   342 			if ((e2++)->flags & RAZOR_ENTRY_LAST)
   343 				e2 = NULL;
   344 		}
   345 	}
   346 
   347 	mroot = (struct razor_entry *)merger->set->files.data;
   348 	if (last != 0xFFFFFFFF) {
   349 		mroot[last].flags = RAZOR_ENTRY_LAST;
   350 		mroot[md->merged].start = start;
   351 	}
   352 
   353 	end_md = merge_stack.data + merge_stack.size;
   354 	for (child_md = merge_stack.data; child_md < end_md; child_md++)
   355 		merge_one_directory(merger, child_md);
   356 	array_release(&merge_stack);
   357 }
   358 
   359 static void
   360 merge_files(struct razor_merger *merger)
   361 {
   362 	struct razor_entry *root;
   363 	struct merge_directory md;
   364 	uint32_t *map1, *map2;
   365 
   366 	map1 = merger->source1.file_map;
   367 	map2 = merger->source2.file_map;
   368 
   369 	md.merged = 0;
   370 
   371 	if (merger->source1.set->files.size) {
   372 		root = (struct razor_entry *) merger->source1.set->files.data;
   373 		if (root->start)
   374 			fix_file_map(map1, root, root);
   375 		md.dir1 = 0;
   376 	} else {
   377 		md.dir1 = 0xFFFFFFFF;
   378 	}
   379 
   380 	if (merger->source2.set->files.size) {
   381 		root = (struct razor_entry *) merger->source2.set->files.data;
   382 		if (root->start)
   383 			fix_file_map(map2, root, root);
   384 		md.dir2 = 0;
   385 	} else {
   386 		md.dir2 = 0xFFFFFFFF;
   387 	}
   388 
   389 	/* Remove the unnamed root which razor_set_create() added */
   390 	array_release(&merger->set->files);
   391 	array_init(&merger->set->files);
   392 
   393 	merge_one_directory(merger, &md);
   394 }
   395 
   396 static void
   397 emit_files(struct list_head *files, struct array *source_pool,
   398 	   uint32_t *map, struct array *pool)
   399 {
   400 	uint32_t r;
   401 	struct list *p, *q;
   402 
   403 	r = pool->size / sizeof *q;
   404 	p = list_first(files, source_pool);
   405 	while (p) {
   406 		q = array_add(pool, sizeof *q);
   407 		q->data = map[p->data];
   408 		q->flags = p->flags;
   409 		p = list_next(p);
   410 	}
   411 
   412 	list_set_ptr(files, r);
   413 }
   414 
   415 /* Rebuild property->packages maps.  We can't just remap these, as a
   416  * property may have lost or gained a number of packages.  Allocate an
   417  * array per property and loop through the packages and add them to
   418  * the arrays for their properties. */
   419 static void
   420 rebuild_property_package_lists(struct razor_set *set)
   421 {
   422 	struct array *pkgs, *a;
   423 	struct razor_package *pkg, *pkg_end;
   424 	struct razor_property *prop, *prop_end;
   425 	struct list *r;
   426 	uint32_t *q;
   427 	int count;
   428 
   429 	count = set->properties.size / sizeof (struct razor_property);
   430 	pkgs = zalloc(count * sizeof *pkgs);
   431 	pkg_end = set->packages.data + set->packages.size;
   432 
   433 	for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
   434 		r = list_first(&pkg->properties, &set->property_pool);
   435 		while (r) {
   436 			q = array_add(&pkgs[r->data], sizeof *q);
   437 			*q = pkg - (struct razor_package *) set->packages.data;
   438 			r = list_next(r);
   439 		}
   440 	}
   441 
   442 	prop_end = set->properties.data + set->properties.size;
   443 	a = pkgs;
   444 	for (prop = set->properties.data; prop < prop_end; prop++, a++) {
   445 		list_set_array(&prop->packages, &set->package_pool, a, 0);
   446 		array_release(a);
   447 	}
   448 	free(pkgs);
   449 }
   450 
   451 static void
   452 rebuild_file_package_lists(struct razor_set *set)
   453 {
   454 	struct array *pkgs, *a;
   455 	struct razor_package *pkg, *pkg_end;
   456 	struct razor_entry *entry, *entry_end;
   457 	struct list *r;
   458 	uint32_t *q;
   459 	int count;
   460 
   461 	count = set->files.size / sizeof (struct razor_entry);
   462 	pkgs = zalloc(count * sizeof *pkgs);
   463 	pkg_end = set->packages.data + set->packages.size;
   464 
   465 	for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
   466 		r = list_first(&pkg->files, &set->file_pool);
   467 		while (r) {
   468 			q = array_add(&pkgs[r->data], sizeof *q);
   469 			*q = pkg - (struct razor_package *) set->packages.data;
   470 			r = list_next(r);
   471 		}
   472 	}
   473 
   474 	entry_end = set->files.data + set->files.size;
   475 	a = pkgs;
   476 	for (entry = set->files.data; entry < entry_end; entry++, a++) {
   477 		list_set_array(&entry->packages, &set->package_pool, a, 0);
   478 		array_release(a);
   479 	}
   480 	free(pkgs);
   481 }
   482 
   483 struct razor_set *
   484 razor_merger_finish(struct razor_merger *merger)
   485 {
   486 	struct razor_set *result;
   487 	struct razor_package *p, *pend;
   488 
   489 	/* As we built the package list, we filled out a bitvector of
   490 	 * the properties that are referenced by the packages in the
   491 	 * new set.  Now we do a parallel loop through the properties
   492 	 * and emit those marked in the bit vector to the new set.  In
   493 	 * the process, we update the bit vector to actually map from
   494 	 * indices in the old property list to indices in the new
   495 	 * property list for both sets. */
   496 
   497 	merge_properties(merger);
   498 	merge_files(merger);
   499 
   500 	/* Now we loop through the packages again and emit the
   501 	 * property lists, remapped to point to the new properties. */
   502 
   503 	pend = merger->set->packages.data + merger->set->packages.size;
   504 	for (p = merger->set->packages.data; p < pend; p++) {
   505 		struct source *src;
   506 
   507 		if (p->flags & UPSTREAM_SOURCE)
   508 			src = &merger->source2;
   509 		else
   510 			src = &merger->source1;
   511 
   512 		emit_properties(&p->properties,
   513 				&src->set->property_pool,
   514 				src->property_map,
   515 				&merger->set->property_pool);
   516 		emit_files(&p->files,
   517 			   &src->set->file_pool,
   518 			   src->file_map,
   519 			   &merger->set->file_pool);
   520 		p->flags &= ~UPSTREAM_SOURCE;
   521 	}
   522 
   523 	rebuild_property_package_lists(merger->set);
   524 	rebuild_file_package_lists(merger->set);
   525 
   526 	result = merger->set;
   527 	hashtable_release(&merger->table);
   528 	hashtable_release(&merger->file_table);
   529 	free(merger);
   530 
   531 	return result;
   532 }