Split out hashtable functionality from importer.
23 struct razor_set_section {
29 struct razor_set_header {
32 struct razor_set_section sections[0];
35 #define RAZOR_MAGIC 0x7a7a7a7a
36 #define RAZOR_VERSION 1
38 #define RAZOR_ENTRY_LAST 0x80000000ul
39 #define RAZOR_IMMEDIATE 0x80000000ul
40 #define RAZOR_ENTRY_MASK 0x00fffffful
42 #define RAZOR_STRING_POOL 0
43 #define RAZOR_PACKAGES 1
44 #define RAZOR_PROPERTIES 2
46 #define RAZOR_PACKAGE_POOL 4
47 #define RAZOR_PROPERTY_POOL 5
48 #define RAZOR_FILE_POOL 6
50 struct razor_package {
52 unsigned long version;
53 unsigned long properties;
57 struct razor_property {
59 unsigned long version;
60 unsigned long packages;
66 unsigned long packages;
70 struct array string_pool;
71 struct array packages;
72 struct array properties;
74 struct array package_pool;
75 struct array property_pool;
76 struct array file_pool;
77 struct razor_set_header *header;
81 unsigned long package;
85 struct import_directory {
86 unsigned long name, count;
88 struct array packages;
89 struct import_directory *last;
97 struct razor_importer {
98 struct razor_set *set;
99 struct hashtable table;
100 struct razor_package *package;
101 struct array properties;
106 array_init(struct array *array)
108 memset(array, 0, sizeof *array);
112 array_release(struct array *array)
118 array_add(struct array *array, int size)
123 if (array->alloc > 0)
124 alloc = array->alloc;
128 while (alloc < array->size + size)
131 if (array->alloc < alloc) {
132 data = realloc(array->data, alloc);
136 array->alloc = alloc;
139 p = array->data + array->size;
146 write_to_fd(int fd, void *p, size_t size)
152 len = write(fd, p, rest);
172 struct razor_set_section razor_sections[] = {
173 { RAZOR_STRING_POOL, offsetof(struct razor_set, string_pool) },
174 { RAZOR_PACKAGES, offsetof(struct razor_set, packages) },
175 { RAZOR_PROPERTIES, offsetof(struct razor_set, properties) },
176 { RAZOR_FILES, offsetof(struct razor_set, files) },
177 { RAZOR_PACKAGE_POOL, offsetof(struct razor_set, package_pool) },
178 { RAZOR_PROPERTY_POOL, offsetof(struct razor_set, property_pool) },
179 { RAZOR_FILE_POOL, offsetof(struct razor_set, file_pool) },
183 razor_set_create(void)
185 return zalloc(sizeof(struct razor_set));
189 razor_set_open(const char *filename)
191 struct razor_set *set;
192 struct razor_set_section *s;
197 set = zalloc(sizeof *set);
198 fd = open(filename, O_RDONLY);
199 if (fstat(fd, &stat) < 0)
201 set->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
202 if (set->header == MAP_FAILED) {
207 for (s = set->header->sections; ~s->type; s++) {
208 if (s->type >= ARRAY_SIZE(razor_sections))
210 if (s->type != razor_sections[s->type].type)
212 array = (void *) set + razor_sections[s->type].offset;
213 array->data = (void *) set->header + s->offset;
214 array->size = s->size;
215 array->alloc = s->size;
223 razor_set_destroy(struct razor_set *set)
230 for (i = 0; set->header->sections[i].type; i++)
232 size = set->header->sections[i].type;
233 munmap(set->header, size);
235 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
236 a = (void *) set + razor_sections[i].offset;
245 razor_set_write(struct razor_set *set, const char *filename)
248 struct razor_set_header *header = (struct razor_set_header *) data;
250 unsigned long offset;
253 memset(data, 0, sizeof data);
254 header->magic = RAZOR_MAGIC;
255 header->version = RAZOR_VERSION;
256 offset = sizeof data;
258 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
259 if (razor_sections[i].type != i)
261 a = (void *) set + razor_sections[i].offset;
262 header->sections[i].type = i;
263 header->sections[i].offset = offset;
264 header->sections[i].size = a->size;
265 offset += (a->size + 4095) & ~4095;
268 header->sections[i].type = ~0;
269 header->sections[i].offset = 0;
270 header->sections[i].size = 0;
272 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
276 write_to_fd(fd, data, sizeof data);
277 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
278 if (razor_sections[i].type != i)
280 a = (void *) set + razor_sections[i].offset;
281 write_to_fd(fd, a->data, (a->size + 4095) & ~4095);
290 hash_string(const char *key)
293 unsigned int hash = 0;
295 for (p = key; *p; p++)
296 hash = (hash * 617) ^ *p;
302 hashtable_lookup(struct hashtable *table, const char *key)
304 unsigned int mask, start, i;
308 pool = table->pool->data;
309 mask = table->buckets.alloc - 1;
310 start = hash_string(key) * sizeof(unsigned long);
312 for (i = 0; i < table->buckets.alloc; i += sizeof *b) {
313 b = table->buckets.data + ((start + i) & mask);
318 if (strcmp(key, &pool[*b]) == 0)
326 add_to_string_pool(struct hashtable *table, const char *key)
331 len = strlen(key) + 1;
332 p = array_add(table->pool, len);
335 return p - (char *) table->pool->data;
339 add_to_property_pool(struct array *pool, struct array *properties)
343 p = array_add(pool, properties->size);
344 memcpy(p, properties->data, properties->size);
345 p[properties->size / sizeof *p - 1] |= RAZOR_IMMEDIATE;
347 return p - (unsigned long *) pool->data;
351 do_insert(struct hashtable *table, unsigned long value)
353 unsigned int mask, start, i;
357 key = (char *) table->pool->data + value;
358 mask = table->buckets.alloc - 1;
359 start = hash_string(key) * sizeof(unsigned long);
361 for (i = 0; i < table->buckets.alloc; i += sizeof *b) {
362 b = table->buckets.data + ((start + i) & mask);
371 hashtable_insert(struct hashtable *table, const char *key)
373 unsigned long value, *buckets, *b, *end;
376 alloc = table->buckets.alloc;
377 array_add(&table->buckets, 4 * sizeof *buckets);
378 if (alloc != table->buckets.alloc) {
379 end = table->buckets.data + alloc;
380 memset(end, 0, table->buckets.alloc - alloc);
381 for (b = table->buckets.data; b < end; b++) {
385 do_insert(table, value);
390 value = add_to_string_pool(table, key);
391 do_insert (table, value);
397 hashtable_init(struct hashtable *table, struct array *pool)
399 array_init(&table->buckets);
404 hashtable_release(struct hashtable *table)
406 array_release(&table->buckets);
410 razor_importer_tokenize(struct razor_importer *importer, const char *string)
417 token = hashtable_lookup(&importer->table, string);
421 return hashtable_insert(&importer->table, string);
425 razor_importer_begin_package(struct razor_importer *importer,
426 const char *name, const char *version)
428 struct razor_package *p;
430 p = array_add(&importer->set->packages, sizeof *p);
431 p->name = razor_importer_tokenize(importer, name);
432 p->version = razor_importer_tokenize(importer, version);
434 importer->package = p;
435 array_init(&importer->properties);
439 razor_importer_finish_package(struct razor_importer *importer)
441 struct razor_package *p;
443 p = importer->package;
444 p->properties = add_to_property_pool(&importer->set->property_pool,
445 &importer->properties);
447 array_release(&importer->properties);
451 razor_importer_add_property(struct razor_importer *importer,
452 const char *name, const char *version,
453 enum razor_property_type type)
455 struct razor_property *p;
458 p = array_add(&importer->set->properties, sizeof *p);
459 p->name = razor_importer_tokenize(importer, name) | (type << 30);
460 p->version = razor_importer_tokenize(importer, version);
461 p->packages = importer->package -
462 (struct razor_package *) importer->set->packages.data;
464 r = array_add(&importer->properties, sizeof *r);
465 *r = p - (struct razor_property *) importer->set->properties.data;
469 razor_importer_add_file(struct razor_importer *importer, const char *name)
471 struct import_entry *e;
473 e = array_add(&importer->files, sizeof *e);
475 e->package = importer->package -
476 (struct razor_package *) importer->set->packages.data;
477 e->name = strdup(name);
480 struct razor_importer *
481 razor_importer_new(void)
483 struct razor_importer *importer;
485 importer = zalloc(sizeof *importer);
486 importer->set = razor_set_create();
487 hashtable_init(&importer->table, &importer->set->string_pool);
492 /* Destroy an importer without creating the set. */
494 razor_importer_destroy(struct razor_importer *importer)
496 /* FIXME: write this */
500 typedef int (*compare_with_data_func_t)(const void *p1,
504 struct qsort_context {
506 compare_with_data_func_t compare;
511 qsort_swap(void *p1, void *p2, size_t size)
515 memcpy(buffer, p1, size);
516 memcpy(p1, p2, size);
517 memcpy(p2, buffer, size);
521 __qsort_with_data(void *base, size_t nelem, unsigned long *map,
522 struct qsort_context *ctx)
524 void *p, *start, *end, *pivot;
525 unsigned long *mp, *mstart, *mend, tmp;
526 int left, right, result;
527 size_t size = ctx->size;
531 end = base + nelem * size;
535 pivot = base + (random() % nelem) * size;
538 result = ctx->compare(p, pivot, ctx->data);
540 qsort_swap(p, start, size);
550 } else if (result == 0) {
556 qsort_swap(p, end, size);
565 left = (start - base) / size;
566 right = (base + nelem * size - end) / size;
568 __qsort_with_data(base, left, map, ctx);
570 __qsort_with_data(end, right, mend, ctx);
574 qsort_with_data(void *base, size_t nelem, size_t size,
575 compare_with_data_func_t compare, void *data)
577 struct qsort_context ctx;
585 ctx.compare = compare;
588 map = malloc(nelem * sizeof (unsigned long));
589 for (i = 0; i < nelem; i++)
592 __qsort_with_data(base, nelem, map, &ctx);
598 versioncmp(const char *s1, const char *s2)
604 n1 = strtol(s1, (char **) &p1, 0);
605 n2 = strtol(s2, (char **) &p2, 0);
607 /* Epoch; if one but not the other has an epoch set, default
608 * the epoch-less version to 0. */
609 res = (*p1 == ':') - (*p2 == ':');
614 } else if (res > 0) {
627 if (isdigit(*p1) && isdigit(*p2))
628 return versioncmp(p1, p2);
636 compare_packages(const void *p1, const void *p2, void *data)
638 const struct razor_package *pkg1 = p1, *pkg2 = p2;
639 struct razor_set *set = data;
640 char *pool = set->string_pool.data;
642 if (pkg1->name == pkg2->name)
643 return versioncmp(&pool[pkg1->version], &pool[pkg2->version]);
645 return strcmp(&pool[pkg1->name], &pool[pkg2->name]);
649 compare_properties(const void *p1, const void *p2, void *data)
651 const struct razor_property *prop1 = p1, *prop2 = p2;
652 struct razor_set *set = data;
653 char *pool = set->string_pool.data;
655 if (prop1->name == prop2->name)
656 return versioncmp(&pool[prop1->version],
657 &pool[prop2->version]);
658 else if ((prop1->name & RAZOR_ENTRY_MASK) == (prop2->name & RAZOR_ENTRY_MASK))
659 return (prop1->name >> 30) - (prop2->name >> 30);
661 return strcmp(&pool[prop1->name & RAZOR_ENTRY_MASK],
662 &pool[prop2->name & RAZOR_ENTRY_MASK]);
665 static unsigned long *
666 uniqueify_properties(struct razor_set *set)
668 struct razor_property *rp, *up, *rp_end;
669 struct array *pkgs, *p;
670 unsigned long *map, *rmap, *r;
671 int i, count, unique;
673 count = set->properties.size / sizeof(struct razor_property);
674 map = qsort_with_data(set->properties.data,
676 sizeof(struct razor_property),
680 rp_end = set->properties.data + set->properties.size;
681 rmap = malloc(count * sizeof *map);
682 pkgs = zalloc(count * sizeof *pkgs);
683 for (rp = set->properties.data, up = rp, i = 0; rp < rp_end; rp++, i++) {
684 if (rp->name != up->name || rp->version != up->version) {
687 up->version = rp->version;
690 unique = up - (struct razor_property *) set->properties.data;
691 rmap[map[i]] = unique;
692 r = array_add(&pkgs[unique], sizeof *r);
698 set->properties.size = (void *) up - set->properties.data;
700 for (rp = set->properties.data, p = pkgs; rp < rp_end; rp++, p++) {
701 if (p->size / sizeof *r == 1) {
703 rp->packages = *r | RAZOR_IMMEDIATE;
706 add_to_property_pool(&set->package_pool, p);
717 remap_links(struct array *links, unsigned long *map)
719 unsigned long *p, *end;
721 end = links->data + links->size;
722 for (p = links->data; p < end; p++)
723 *p = map[*p & RAZOR_ENTRY_MASK] | (*p & ~RAZOR_ENTRY_MASK);
727 compare_filenames(const void *p1, const void *p2, void *data)
729 const struct import_entry *e1 = p1;
730 const struct import_entry *e2 = p2;
732 return strcmp(e1->name, e2->name);
736 count_entries(struct import_directory *d)
738 struct import_directory *p, *end;
741 end = d->files.data + d->files.size;
745 d->count += p->count + 1;
751 serialize_files(struct razor_set *set,
752 struct import_directory *d, struct array *array)
754 struct import_directory *p, *end;
755 struct razor_entry *e = NULL;
759 end = d->files.data + d->files.size;
760 s = array->size / sizeof *e + d->files.size / sizeof *p;
762 e = array_add(array, sizeof *e);
764 e->start = p->count > 0 ? s : 0;
767 if (p->packages.size == 0) {
768 /* FIXME: We need to make sure this is handled
769 * correctly as the empty list. */
770 e->packages = 0 | RAZOR_IMMEDIATE;
771 } else if (p->packages.size / sizeof *r == 1) {
772 r = p->packages.data;
773 e->packages = *r | RAZOR_IMMEDIATE;
775 e->packages = add_to_property_pool(&set->package_pool,
778 array_release(&p->packages);
782 e->name |= RAZOR_ENTRY_LAST;
785 end = d->files.data + d->files.size;
787 serialize_files(set, p, array);
793 remap_property_package_links(struct array *properties, unsigned long *rmap)
795 struct razor_property *p, *end;
797 end = properties->data + properties->size;
798 for (p = properties->data; p < end; p++)
799 if (p->packages & RAZOR_IMMEDIATE)
800 p->packages = rmap[p->packages & RAZOR_ENTRY_MASK] |
805 build_file_tree(struct razor_importer *importer)
807 int count, i, length;
808 struct import_entry *filenames;
810 unsigned long name, *r;
812 struct import_directory *d, root;
813 struct razor_entry *e;
815 count = importer->files.size / sizeof (struct import_entry);
816 qsort_with_data(importer->files.data,
818 sizeof (struct import_entry),
822 root.name = razor_importer_tokenize(importer, "");
823 array_init(&root.files);
824 array_init(&root.packages);
827 filenames = importer->files.data;
828 for (i = 0; i < count; i++) {
829 f = filenames[i].name;
836 end = strchr(f, '/');
840 memcpy(dirname, f, length);
841 dirname[length] ='\0';
842 name = razor_importer_tokenize(importer, dirname);
843 if (d->last == NULL || d->last->name != name) {
844 d->last = array_add(&d->files, sizeof *d);
845 d->last->name = name;
846 d->last->last = NULL;
847 array_init(&d->last->files);
848 array_init(&d->last->packages);
856 r = array_add(&d->packages, sizeof *r);
857 *r = filenames[i].package;
858 free(filenames[i].name);
861 count_entries(&root);
862 array_init(&importer->set->files);
864 e = array_add(&importer->set->files, sizeof *e);
865 e->name = root.name | RAZOR_ENTRY_LAST;
869 serialize_files(importer->set, &root, &importer->set->files);
871 array_release(&importer->files);
875 build_package_file_lists(struct razor_set *set, unsigned long *rmap)
877 struct razor_package *p, *packages;
879 struct razor_entry *e, *end;
880 unsigned long *r, *q;
883 count = set->packages.size / sizeof *p;
884 pkgs = zalloc(count * sizeof *pkgs);
887 end = set->files.data + set->files.size;
889 if (e->packages & RAZOR_IMMEDIATE) {
890 e->packages = rmap[e->packages & RAZOR_ENTRY_MASK] |
894 r = (unsigned long *) set->package_pool.data + e->packages;
898 q = array_add(&pkgs[*r & RAZOR_ENTRY_MASK], sizeof *q);
899 *q = e - (struct razor_entry *) set->files.data;
900 if (*r++ & RAZOR_IMMEDIATE)
906 packages = set->packages.data;
907 for (i = 0; i < count; i++) {
909 add_to_property_pool(&set->file_pool, &pkgs[i]);
910 array_release(&pkgs[i]);
916 razor_importer_finish(struct razor_importer *importer)
918 struct razor_set *set;
919 unsigned long *map, *rmap;
922 map = uniqueify_properties(importer->set);
923 remap_links(&importer->set->property_pool, map);
926 count = importer->set->packages.size / sizeof(struct razor_package);
927 map = qsort_with_data(importer->set->packages.data,
929 sizeof(struct razor_package),
933 rmap = malloc(count * sizeof *rmap);
934 for (i = 0; i < count; i++)
938 build_file_tree(importer);
939 remap_links(&importer->set->package_pool, rmap);
940 build_package_file_lists(importer->set, rmap);
941 remap_property_package_links(&importer->set->properties, rmap);
945 hashtable_release(&importer->table);
952 razor_set_list(struct razor_set *set, const char *pattern)
954 struct razor_package *p, *end;
955 int with_version = 0;
958 pool = set->string_pool.data;
959 end = set->packages.data + set->packages.size;
960 for (p = set->packages.data; p < end; p++) {
961 if (pattern && fnmatch(pattern, &pool[p->name], 0) != 0)
964 printf("%s-%s\n", &pool[p->name], &pool[p->version]);
966 printf("%s\n", &pool[p->name]);
970 struct razor_set *bsearch_set;
973 compare_package_name(const void *key, const void *data)
975 const struct razor_package *p = data;
978 pool = bsearch_set->string_pool.data;
980 return strcmp(key, &pool[p->name]);
983 struct razor_package *
984 razor_set_get_package(struct razor_set *set, const char *package)
987 return bsearch(package, set->packages.data,
988 set->packages.size / sizeof(struct razor_package),
989 sizeof(struct razor_package), compare_package_name);
993 compare_property_name(const void *key, const void *data)
995 const struct razor_property *p = data;
998 pool = bsearch_set->string_pool.data;
1000 return strcmp(key, &pool[p->name & RAZOR_ENTRY_MASK]);
1003 struct razor_property *
1004 razor_set_get_property(struct razor_set *set, const char *property)
1006 struct razor_property *p, *start;
1009 p = bsearch(property, set->properties.data,
1010 set->properties.size / sizeof(struct razor_property),
1011 sizeof(struct razor_property), compare_property_name);
1013 start = set->properties.data;
1015 ((p - 1)->name & RAZOR_ENTRY_MASK) ==
1016 (p->name & RAZOR_ENTRY_MASK))
1023 razor_set_list_properties(struct razor_set *set, const char *name,
1024 enum razor_property_type type)
1026 struct razor_property *p, *properties, *end;
1027 struct razor_package *package;
1031 pool = set->string_pool.data;
1034 package = razor_set_get_package(set, name);
1035 r = (unsigned long *) set->property_pool.data +
1036 package->properties;
1037 properties = set->properties.data;
1039 p = &properties[*r & RAZOR_ENTRY_MASK];
1040 if ((p->name >> 30) != type)
1042 if (pool[p->version] == '\0')
1044 &pool[p->name & RAZOR_ENTRY_MASK]);
1047 &pool[p->name & RAZOR_ENTRY_MASK],
1050 if (*r++ & RAZOR_IMMEDIATE)
1054 end = set->properties.data + set->properties.size;
1055 for (p = set->properties.data; p < end; p++) {
1056 if ((p->name >> 30) != type)
1058 if (pool[p->version] == '\0')
1060 &pool[p->name & RAZOR_ENTRY_MASK]);
1063 &pool[p->name & RAZOR_ENTRY_MASK],
1070 razor_set_list_property_packages(struct razor_set *set,
1072 const char *version,
1073 enum razor_property_type type)
1075 struct razor_property *property, *end;
1076 struct razor_package *p, *packages;
1083 property = razor_set_get_property(set, name);
1084 packages = set->packages.data;
1085 pool = set->string_pool.data;
1086 end = set->properties.data + set->properties.size;
1087 while (property < end &&
1088 strcmp(name, &pool[property->name & RAZOR_ENTRY_MASK]) == 0) {
1090 versioncmp(version, &pool[property->version]) != 0)
1092 if (type != (property->name >> 30))
1095 if (property->packages & RAZOR_IMMEDIATE)
1096 r = &property->packages;
1098 r = (unsigned long *)
1099 set->package_pool.data + property->packages;
1101 p = &packages[*r & RAZOR_ENTRY_MASK];
1103 &pool[p->name & RAZOR_ENTRY_MASK],
1105 if (*r++ & RAZOR_IMMEDIATE)
1113 static struct razor_entry *
1114 find_entry(struct razor_set *set, struct razor_entry *dir, const char *pattern)
1116 struct razor_entry *e;
1117 const char *n, *pool = set->string_pool.data;
1120 e = (struct razor_entry *) set->files.data + dir->start;
1122 n = pool + (e->name & RAZOR_ENTRY_MASK);
1123 if (strcmp(pattern + 1, n) == 0)
1126 if (e->start != 0 && strncmp(pattern + 1, n, len) == 0 &&
1127 pattern[len + 1] == '/') {
1128 return find_entry(set, e, pattern + len + 1);
1130 } while (((e++)->name & RAZOR_ENTRY_LAST) == 0);
1136 list_dir(struct razor_set *set, struct razor_entry *dir,
1137 const char *prefix, const char *pattern)
1139 struct razor_entry *e;
1140 const char *n, *pool = set->string_pool.data;
1142 e = (struct razor_entry *) set->files.data + dir->start;
1144 n = pool + (e->name & RAZOR_ENTRY_MASK);
1145 if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
1147 printf("%s/%s%s\n", prefix, n, e->start > 0 ? "/" : "");
1148 } while (((e++)->name & RAZOR_ENTRY_LAST) == 0);
1152 razor_set_list_files(struct razor_set *set, const char *pattern)
1154 struct razor_entry *e;
1155 char buffer[512], *p, *base;
1157 if (pattern == NULL)
1160 strcpy(buffer, pattern);
1161 e = find_entry(set, set->files.data, buffer);
1162 if (e && e->start > 0) {
1165 p = strrchr(buffer, '/');
1173 e = find_entry(set, set->files.data, buffer);
1175 list_dir(set, e, buffer, base);
1179 razor_set_list_file_packages(struct razor_set *set, const char *filename)
1181 struct razor_entry *e;
1182 struct razor_package *packages, *p;
1186 e = find_entry(set, set->files.data, filename);
1190 if (e->packages & RAZOR_IMMEDIATE)
1193 r = (unsigned long *) set->package_pool.data + e->packages;
1195 packages = set->packages.data;
1196 pool = set->string_pool.data;
1198 p = &packages[*r & RAZOR_ENTRY_MASK];
1199 printf("%s-%s\n", &pool[p->name], &pool[p->version]);
1200 if (*r++ & RAZOR_IMMEDIATE)
1205 static unsigned long *
1206 list_package_files(struct razor_set *set, unsigned long *r,
1207 struct razor_entry *dir, unsigned long end,
1210 struct razor_entry *e, *f, *entries;
1215 entries = (struct razor_entry *) set->files.data;
1216 pool = set->string_pool.data;
1218 e = entries + dir->start;
1220 if (entries + *r == e) {
1221 printf("%s/%s\n", prefix,
1222 pool + (e->name & RAZOR_ENTRY_MASK));
1227 } while (((e++)->name & RAZOR_ENTRY_LAST) == 0);
1229 e = entries + dir->start;
1234 if (e->name & RAZOR_ENTRY_LAST)
1238 while (f->start == 0 && !(f->name & RAZOR_ENTRY_LAST))
1246 if (e->start <= *r && *r < next) {
1247 len = strlen(prefix);
1249 strcpy(prefix + len + 1,
1250 pool + (e->name & RAZOR_ENTRY_MASK));
1251 r = list_package_files(set, r, e, next, prefix);
1256 } while (((e++)->name & RAZOR_ENTRY_LAST) == 0);
1262 razor_set_list_package_files(struct razor_set *set, const char *name)
1264 struct razor_package *package;
1265 unsigned long *r, end;
1268 package = razor_set_get_package(set, name);
1270 r = (unsigned long *) set->file_pool.data + package->files;
1271 end = set->files.size / sizeof (struct razor_entry);
1273 list_package_files(set, r, set->files.data, end, buffer);
1277 razor_set_validate(struct razor_set *set, struct array *unsatisfied)
1279 struct razor_property *r, *p, *end;
1283 end = set->properties.data + set->properties.size;
1284 pool = set->string_pool.data;
1286 for (r = set->properties.data, p = r; r < end; r++) {
1287 if (r->name >> 30 != RAZOR_PROPERTY_REQUIRES)
1290 if ((r->name & RAZOR_ENTRY_MASK) != (p->name & RAZOR_ENTRY_MASK)) {
1292 while (p < end && p->name == r->name)
1296 /* If there is more than one version of a provides,
1297 * seek to the end for the highest version. */
1298 /* FIXME: This doesn't work if we have a series of
1299 * requires a = 1, provides a = 1, requires a = 2,
1300 * provides a = 2, as the kernel and kernel-devel
1302 while (p + 1 < end && p->name == (p + 1)->name)
1305 /* FIXME: We need to track property flags (<, <=, =
1306 * etc) to properly determine if a requires is
1307 * satisfied. The current code doesn't track that the
1308 * requires a = 1 isn't satisfied by a = 2 provides. */
1311 (p->name >> 30) != RAZOR_PROPERTY_PROVIDES ||
1312 (r->name & RAZOR_ENTRY_MASK) != (p->name & RAZOR_ENTRY_MASK) ||
1313 versioncmp(&pool[r->version], &pool[p->version]) > 0) {
1314 /* FIXME: We ignore file requires for now. */
1315 if (pool[r->name & RAZOR_ENTRY_MASK] == '/')
1317 u = array_add(unsatisfied, sizeof *u);
1318 *u = r - (struct razor_property *) set->properties.data;
1324 razor_set_list_unsatisfied(struct razor_set *set)
1326 struct array unsatisfied;
1327 struct razor_property *properties, *r;
1328 unsigned long *u, *end;
1331 array_init(&unsatisfied);
1332 razor_set_validate(set, &unsatisfied);
1334 end = unsatisfied.data + unsatisfied.size;
1335 properties = set->properties.data;
1336 pool = set->string_pool.data;
1338 for (u = unsatisfied.data; u < end; u++) {
1339 r = properties + *u;
1340 if (pool[r->version] == '\0')
1341 printf("%ss not satisfied\n",
1342 &pool[r->name & RAZOR_ENTRY_MASK]);
1344 printf("%s-%s not satisfied\n",
1345 &pool[r->name & RAZOR_ENTRY_MASK],
1349 array_release(&unsatisfied);
1352 #define UPSTREAM_SOURCE 0x80000000ul
1353 #define INDEX_MASK 0x00fffffful
1356 struct razor_set *set;
1357 unsigned long *property_map;
1361 prepare_source(struct source *source, struct razor_set *set)
1368 count = set->properties.size / sizeof (struct razor_property);
1369 size = count * sizeof *source->property_map;
1370 source->property_map = zalloc(size);
1374 add_package(struct razor_importer *importer,
1375 struct razor_package *package, struct source *source,
1376 unsigned long flags)
1380 struct razor_package *p;
1382 pool = source->set->string_pool.data;
1383 p = array_add(&importer->set->packages, sizeof *p);
1384 p->name = razor_importer_tokenize(importer, &pool[package->name]);
1386 p->version = razor_importer_tokenize(importer,
1387 &pool[package->version]);
1388 p->properties = package->properties;
1390 if (package->properties & RAZOR_IMMEDIATE)
1391 r = &package->properties;
1393 r = (unsigned long *)
1394 source->set->property_pool.data + package->properties;
1396 source->property_map[*r & RAZOR_ENTRY_MASK] = 1;
1397 if (*r++ & RAZOR_IMMEDIATE)
1403 /* Build the new package list sorted by merging the two package lists.
1404 * Build new string pool as we go. (for now we just re-use that part of
1407 merge_packages(struct razor_importer *importer,
1408 struct source *source1, struct source *source2,
1409 struct array *packages)
1411 struct razor_package *upstream_packages, *p, *s, *send;
1412 char *spool, *upool;
1413 unsigned long *u, *uend;
1416 upstream_packages = source2->set->packages.data;
1419 uend = packages->data + packages->size;
1420 upool = source2->set->string_pool.data;
1422 s = source1->set->packages.data;
1423 send = source1->set->packages.data + source1->set->packages.size;
1424 spool = source1->set->string_pool.data;
1427 p = upstream_packages + *u;
1430 cmp = strcmp(&spool[s->name], &upool[p->name]);
1431 if (u >= uend || cmp < 0) {
1432 add_package(importer, s, source1, 0);
1434 } else if (cmp == 0) {
1435 add_package(importer, p, source2, UPSTREAM_SOURCE);
1439 add_package(importer, p, source2, UPSTREAM_SOURCE);
1445 static unsigned long
1446 add_property(struct razor_importer *importer,
1447 const char *name, const char *version, int type)
1449 struct razor_property *p;
1451 p = array_add(&importer->set->properties, sizeof *p);
1452 p->name = razor_importer_tokenize(importer, name) | (type << 30);
1453 p->version = razor_importer_tokenize(importer, version);
1455 return p - (struct razor_property *) importer->set->properties.data;
1459 merge_properties(struct razor_importer *importer,
1460 struct razor_set *set1,
1461 unsigned long *map1,
1462 struct razor_set *set2,
1463 unsigned long *map2)
1465 struct razor_property *p1, *p2;
1466 int i, j, cmp, count1, count2;
1467 char *pool1, *pool2;
1471 pool1 = set1->string_pool.data;
1472 pool2 = set2->string_pool.data;
1474 count1 = set1->properties.size / sizeof *p1;
1475 count2 = set2->properties.size / sizeof *p2;
1476 while (i < count1 || j < count2) {
1477 if (i < count1 && map1[i] == 0) {
1481 if (j < count2 && map2[j] == 0) {
1485 p1 = (struct razor_property *) set1->properties.data + i;
1486 p2 = (struct razor_property *) set2->properties.data + j;
1487 if (i < count1 && j < count2)
1488 cmp = strcmp(&pool1[p1->name & RAZOR_ENTRY_MASK],
1489 &pool2[p2->name & RAZOR_ENTRY_MASK]);
1490 else if (i < count1)
1495 cmp = versioncmp(&pool1[p1->version],
1496 &pool2[p2->version]);
1498 map1[i++] = add_property(importer,
1499 &pool1[p1->name & RAZOR_ENTRY_MASK],
1500 &pool1[p1->version],
1502 } else if (cmp > 0) {
1503 map2[j++] = add_property(importer,
1504 &pool2[p2->name & RAZOR_ENTRY_MASK],
1505 &pool2[p2->version],
1508 map1[i++] = map2[j++] = add_property(importer,
1509 &pool1[p1->name & RAZOR_ENTRY_MASK],
1510 &pool1[p1->version],
1516 static unsigned long
1517 emit_properties(struct array *source_pool, unsigned long index,
1518 unsigned long *map, struct array *pool)
1520 unsigned long r, *p, *q;
1522 r = pool->size / sizeof *q;
1523 p = (unsigned long *) source_pool->data + index;
1525 q = array_add(pool, sizeof *q);
1526 *q = map[*p & RAZOR_ENTRY_MASK] | (*p & ~RAZOR_ENTRY_MASK);
1527 if (*p++ & RAZOR_ENTRY_LAST)
1534 /* Rebuild property->packages maps. We can't just remap these, as a
1535 * property may have lost or gained a number of packages. Allocate an
1536 * array per property and loop through the packages and add them to
1537 * the arrays for their properties. */
1539 rebuild_package_lists(struct razor_set *set)
1541 struct array *pkgs, *a;
1542 struct razor_package *pkg, *pkg_end;
1543 struct razor_property *prop, *prop_end;
1544 unsigned long *r, *q, *pool;
1547 count = set->properties.size / sizeof (struct razor_property);
1548 pkgs = zalloc(count * sizeof *pkgs);
1549 pkg_end = set->packages.data + set->packages.size;
1550 pool = set->property_pool.data;
1552 for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
1553 for (r = &pool[pkg->properties]; ; r++) {
1554 q = array_add(&pkgs[*r & RAZOR_ENTRY_MASK], sizeof *q);
1555 *q = pkg - (struct razor_package *) set->packages.data;
1556 if (*r & RAZOR_IMMEDIATE)
1561 prop_end = set->properties.data + set->properties.size;
1563 for (prop = set->properties.data; prop < prop_end; prop++, a++) {
1564 if (a->size / sizeof *r == 1) {
1566 prop->packages = *r | RAZOR_IMMEDIATE;
1569 add_to_property_pool(&set->property_pool, a);
1576 /* Add packages from 'upstream' to 'set'. The packages to add are
1577 * specified by the 'packages' array, which is a sorted list of
1578 * package indexes. Returns a newly allocated package set. Does not
1579 * enforce validity of the resulting package set.
1581 * This looks more complicated than it is. An easy way to merge two
1582 * package sets would be to just use a razor_importer, but that
1583 * requires resorting, and is thus O(n log n). We can do this in a
1584 * linear sweep, but it gets a little more complicated.
1587 razor_set_add(struct razor_set *set, struct razor_set *upstream,
1588 struct array *packages)
1590 struct razor_set *result;
1591 struct razor_importer *importer;
1592 struct razor_package *p, *pend;
1593 struct source source, upstream_source;
1595 importer = razor_importer_new();
1597 prepare_source(&upstream_source, upstream);
1598 prepare_source(&source, set);
1600 merge_packages(importer, &source, &upstream_source, packages);
1602 /* As we built the package list, we filled out a bitvector of
1603 * the properties that are referenced by the packages in the
1604 * new set. Now we do a parallel loop through the properties
1605 * and emit those marked in the bit vector to the new set. In
1606 * the process, we update the bit vector to actually map from
1607 * indices in the old property list to indices in the new
1608 * property list for both sets. */
1610 merge_properties(importer,
1611 set, source.property_map,
1612 upstream, upstream_source.property_map);
1614 /* Now we loop through the packages again and emit the
1615 * property lists, remapped to point to the new properties. */
1617 pend = importer->set->packages.data + importer->set->packages.size;
1618 for (p = importer->set->packages.data; p < pend; p++) {
1621 if (p->name & UPSTREAM_SOURCE)
1622 src = &upstream_source;
1626 p->properties = emit_properties(&src->set->property_pool,
1629 &importer->set->property_pool);
1630 p->name &= INDEX_MASK;
1633 rebuild_package_lists(importer->set);
1635 result = importer->set;
1636 hashtable_release(&importer->table);
1643 razor_set_satisfy(struct razor_set *set, struct array *unsatisfied,
1644 struct razor_set *upstream, struct array *list)
1646 struct razor_property *requires, *r;
1647 struct razor_property *p, *pend;
1648 unsigned long *u, *end, *pkg, *package_pool;
1651 end = unsatisfied->data + unsatisfied->size;
1652 requires = set->properties.data;
1653 pool = set->string_pool.data;
1655 p = upstream->properties.data;
1656 pend = upstream->properties.data + upstream->properties.size;
1657 upool = upstream->string_pool.data;
1658 package_pool = upstream->package_pool.data;
1660 for (u = unsatisfied->data; u < end; u++) {
1664 strcmp(&pool[r->name & RAZOR_ENTRY_MASK],
1665 &upool[p->name & RAZOR_ENTRY_MASK]) > 0 &&
1666 (p->name >> 30) != RAZOR_PROPERTY_PROVIDES)
1668 /* If there is more than one version of a provides,
1669 * seek to the end for the highest version. */
1670 while (p + 1 < pend && p->name == (p + 1)->name)
1674 strcmp(&pool[r->name & RAZOR_ENTRY_MASK],
1675 &upool[p->name & RAZOR_ENTRY_MASK]) != 0 ||
1676 versioncmp(&pool[r->version], &upool[p->version]) > 0) {
1677 /* Do we need to track unsatisfiable requires
1678 * as we go, or should we just do a
1679 * razor_set_validate() at the end? */
1681 pkg = array_add(list, sizeof *pkg);
1682 /* We just pull in the first package that provides */
1683 if (p->packages & RAZOR_IMMEDIATE)
1684 *pkg = p->packages & RAZOR_ENTRY_MASK;
1686 *pkg = package_pool[p->packages];
1692 find_packages(struct razor_set *set,
1693 int count, const char **packages, struct array *list)
1695 struct razor_package *p;
1699 /* FIXME: Sort the packages. */
1700 for (i = 0; i < count; i++) {
1701 p = razor_set_get_package(set, packages[i]);
1702 r = array_add(list, sizeof *r);
1703 *r = p - (struct razor_package *) set->packages.data;
1708 find_all_packages(struct razor_set *set,
1709 struct razor_set *upstream, struct array *list)
1711 struct razor_package *p, *u, *pend, *uend;
1715 pend = set->packages.data + set->packages.size;
1716 pool = set->string_pool.data;
1717 u = upstream->packages.data;
1718 uend = upstream->packages.data + upstream->packages.size;
1719 upool = upstream->string_pool.data;
1721 for (p = set->packages.data; p < pend; p++) {
1722 while (u < uend && strcmp(&pool[p->name], &upool[u->name]) > 0)
1724 if (strcmp(&pool[p->name], &upool[u->name]) == 0) {
1725 r = array_add(list, sizeof *r);
1726 *r = u - (struct razor_package *) upstream->packages.data;
1732 razor_set_update(struct razor_set *set, struct razor_set *upstream,
1733 int count, const char **packages)
1735 struct razor_set *new;
1736 struct razor_package *upackages;
1737 struct array list, unsatisfied;
1739 unsigned long *u, *end;
1744 find_packages(upstream, count, packages, &list);
1746 find_all_packages(set, upstream, &list);
1748 end = list.data + list.size;
1749 upackages = upstream->packages.data;
1750 pool = upstream->string_pool.data;
1751 total += list.size / sizeof *u;
1753 while (list.size > 0) {
1754 new = razor_set_add(set, upstream, &list);
1755 array_release(&list);
1756 razor_set_destroy(set);
1759 array_init(&unsatisfied);
1760 razor_set_validate(new, &unsatisfied);
1762 razor_set_satisfy(new, &unsatisfied, upstream, &list);
1763 array_release(&unsatisfied);
1765 end = list.data + list.size;
1766 upackages = upstream->packages.data;
1767 pool = upstream->string_pool.data;
1768 total += list.size / sizeof *u;
1771 array_release(&list);
1776 /* The diff order matters. We should sort the packages so that a
1777 * REMOVE of a package comes before the INSTALL, and so that all
1778 * requires for a package have been installed before the package.
1782 razor_set_diff(struct razor_set *set, struct razor_set *upstream,
1783 razor_package_callback_t callback, void *data)
1785 struct razor_package *p, *pend, *u, *uend;
1786 char *ppool, *upool;
1789 p = set->packages.data;
1790 pend = set->packages.data + set->packages.size;
1791 ppool = set->string_pool.data;
1793 u = upstream->packages.data;
1794 uend = upstream->packages.data + upstream->packages.size;
1795 upool = upstream->string_pool.data;
1797 while (p < pend || u < uend) {
1798 if (p < pend && u < uend) {
1799 res = strcmp(&ppool[p->name], &upool[u->name]);
1801 res = versioncmp(&ppool[p->version],
1802 &upool[u->version]);
1805 if (u == uend || res < 0) {
1806 callback(&ppool[p->name], &ppool[p->version],
1810 } else if (p == pend || res > 0) {
1811 callback(&upool[u->name], NULL, &upool[u->version],