Cleanup and renaming: hashtable and razor_context combined into razor_set.
It's no longer just a hashtable, it's really a set of packages.
14 write_to_fd(int fd, void *p, size_t size)
20 len = write(fd, p, rest);
30 write_to_file(const char *filename, void *p, size_t size)
34 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
37 err = write_to_fd(fd, p, size);
54 struct razor_set_header {
57 struct { unsigned int type, offset; } sections[0];
60 #define RAZOR_MAGIC 0x7a7a7a7a
61 #define RAZOR_VERSION 1
62 #define RAZOR_BUCKETS 1
63 #define RAZOR_STRINGS 2
64 #define RAZOR_PACKAGES 3
66 struct razor_package {
68 unsigned long version;
72 unsigned long *buckets;
73 int bucket_count, bucket_alloc;
75 int pool_size, pool_alloc;
76 struct razor_set_header *header;
78 struct razor_package *packages;
79 int package_count, package_alloc;
83 razor_set_create(void)
85 struct razor_set *set;
87 set = zalloc(sizeof *set);
88 set->buckets = zalloc(4096 * sizeof *set->buckets);
89 set->bucket_count = 0;
90 set->bucket_alloc = 4096;
92 set->string_pool = zalloc(4096);
94 set->pool_alloc = 4096;
96 set->packages = zalloc(4096 * sizeof *set->packages);
97 set->package_count = 0;
98 set->package_alloc = 4096;
104 razor_set_open(const char *filename)
106 struct razor_set *set;
108 unsigned int size, offset;
111 set = zalloc(sizeof *set);
112 fd = open(filename, O_RDONLY);
113 if (fstat(fd, &stat) < 0)
115 set->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
116 if (set->header == MAP_FAILED) {
121 for (i = 0; i < set->header->sections[i].type; i++) {
122 offset = set->header->sections[i].offset;
123 size = set->header->sections[i + 1].offset - offset;
125 switch (set->header->sections[i].type) {
127 set->buckets = (void *) set->header + offset;
128 set->bucket_count = size / sizeof *set->buckets;
129 set->bucket_alloc = set->bucket_count;
132 set->string_pool = (void *) set->header + offset;
133 set->pool_size = size;
134 set->pool_alloc = size;
137 set->packages = (void *) set->header + offset;
138 set->package_count = size / sizeof *set->packages;
139 set->package_alloc = size / sizeof *set->packages;
149 razor_set_destroy(struct razor_set *set)
155 for (i = 0; set->header->sections[i].type; i++)
157 size = set->header->sections[i].type;
158 munmap(set->header, size);
161 free(set->string_pool);
168 razor_set_write(struct razor_set *set, const char *filename)
171 struct razor_set_header *header = (struct razor_set_header *) data;
172 int fd, pool_size, package_size;
174 /* Align these to pages sizes */
175 pool_size = (set->pool_size + 4095) & ~4095;
177 (set->package_alloc * sizeof *set->packages + 4095) & ~4095;
179 memset(data, 0, sizeof data);
180 header->magic = RAZOR_MAGIC;
181 header->version = RAZOR_VERSION;
183 header->sections[0].type = RAZOR_BUCKETS;
184 header->sections[0].offset = sizeof data;
186 header->sections[1].type = RAZOR_STRINGS;
187 header->sections[1].offset = header->sections[0].offset +
188 set->bucket_alloc * sizeof *set->buckets;
190 header->sections[2].type = RAZOR_PACKAGES;
191 header->sections[2].offset = header->sections[1].offset + pool_size;
193 header->sections[3].type = 0;
194 header->sections[3].offset = header->sections[2].offset + package_size;
196 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
200 write_to_fd(fd, data, sizeof data);
201 write_to_fd(fd, set->buckets, set->bucket_alloc * sizeof *set->buckets);
202 write_to_fd(fd, set->string_pool, pool_size);
203 write_to_fd(fd, set->packages, package_size);
209 hash_string(const char *key)
212 unsigned int hash = 0;
214 for (p = key; *p; p++)
215 hash = (hash << 2) ^ *p;
221 razor_set_lookup(struct razor_set *set, const char *key)
228 mask = set->bucket_alloc - 1;
229 start = hash_string(key) & mask;
232 value = set->buckets[i];
237 if (strcmp(key, &set->string_pool[value]) == 0)
241 } while (i != start);
247 add_to_string_pool(struct razor_set *set, const char *key)
253 len = strlen(key) + 1;
254 alloc = set->pool_alloc;
255 while (alloc < set->pool_size + len)
257 if (set->pool_alloc < alloc) {
258 pool = realloc(set->string_pool, alloc);
261 set->string_pool = pool;
262 set->pool_alloc = alloc;
265 memcpy(set->string_pool + set->pool_size, key, len);
266 value = set->pool_size;
267 set->pool_size += len;
273 do_insert(struct razor_set *set, unsigned long value)
279 key = &set->string_pool[value];
280 mask = set->bucket_alloc - 1;
281 start = hash_string(key) & mask;
284 if (set->buckets[i] == 0) {
285 set->buckets[i] = value;
289 } while (i != start);
293 razor_set_insert(struct razor_set *set, const char *key)
295 unsigned long value, *buckets, *old_buckets;
296 int i, alloc, old_alloc;
298 alloc = set->bucket_alloc;
299 while (alloc < 4 * set->bucket_count)
302 if (alloc != set->bucket_alloc) {
303 buckets = zalloc(alloc * sizeof *set->buckets);
306 old_buckets = set->buckets;
307 set->buckets = buckets;
308 old_alloc = set->bucket_alloc;
309 set->bucket_alloc = alloc;
311 for (i = 0; i < old_alloc; i++) {
312 value = old_buckets[i];
314 do_insert(set, value);
319 value = add_to_string_pool(set, key);
320 do_insert (set, value);
327 razor_set_add_package(struct razor_set *set,
328 unsigned long name, unsigned long version)
330 struct razor_package *packages;
333 /* FIXME: make 0 an illegal pkgs number. */
334 alloc = set->package_alloc;
335 while (alloc < set->package_count + 1)
337 if (set->package_alloc < alloc) {
338 packages = realloc(set->packages, alloc * sizeof set->packages);
339 if (packages == NULL)
341 set->packages = packages;
342 set->package_alloc = alloc;
345 set->packages[set->package_count].name = name;
346 set->packages[set->package_count].version = version;
348 return set->package_count++;
352 razor_set_tokenize(struct razor_set *set, const char *string)
356 token = razor_set_lookup(set, string);
360 return razor_set_insert(set, string);
363 static struct razor_set *qsort_set;
366 compare_packages(const void *p1, const void *p2)
368 const struct razor_package *pkg1 = p1, *pkg2 = p2;
370 return strcmp(&qsort_set->string_pool[pkg1->name],
371 &qsort_set->string_pool[pkg2->name]);
375 razor_set_sort(struct razor_set *set)
378 qsort(set->packages, set->package_count, sizeof *set->packages,
382 struct parsing_context {
383 struct razor_set *set;
388 parse_package(struct parsing_context *ctx, const char **atts)
390 unsigned long name, version;
393 for (i = 0; atts[i]; i += 2) {
394 if (strcmp(atts[i], "name") == 0)
395 name = razor_set_tokenize(ctx->set, atts[i + 1]);
396 else if (strcmp(atts[i], "version") == 0)
397 version = razor_set_tokenize(ctx->set, atts[i + 1]);
400 if (name == 0 || version == 0) {
401 fprintf(stderr, "invalid package tag, "
402 "missing name or version attributes\n");
406 ctx->pkg_id = razor_set_add_package(ctx->set, name, version);
412 start_element(void *data, const char *name, const char **atts)
414 struct parsing_context *ctx = data;
417 if (strcmp(name, "package") == 0)
418 parse_package(ctx, atts);
420 for (i = 0; atts[i]; i += 2)
421 razor_set_tokenize(ctx->set, atts[i + 1]);
425 end_element (void *data, const char *name)
427 struct parsing_context *ctx = data;
429 if (strcmp(name, "package") == 0)
434 sha1_to_hex(const unsigned char *sha1)
437 static char hexbuffer[4][50];
438 static const char hex[] = "0123456789abcdef";
439 char *buffer = hexbuffer[3 & ++bufno], *buf = buffer;
442 for (i = 0; i < 20; i++) {
443 unsigned int val = *sha1++;
444 *buf++ = hex[val >> 4];
445 *buf++ = hex[val & 0xf];
453 razor_set_import(struct razor_set *set, const char *filename)
457 struct parsing_context ctx;
462 unsigned char hash[20];
464 fd = open(filename, O_RDONLY);
465 if (fstat(fd, &stat) < 0)
467 p = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
471 parser = XML_ParserCreate(NULL);
473 XML_SetUserData(parser, &ctx);
474 XML_SetElementHandler(parser, start_element, end_element);
475 if (XML_Parse(parser, p, stat.st_size, 1) == XML_STATUS_ERROR) {
477 "%s at line %d, %s\n",
478 XML_ErrorString(XML_GetErrorCode(parser)),
479 XML_GetCurrentLineNumber(parser),
484 XML_ParserFree(parser);
487 SHA1_Update(&sha1, p, stat.st_size);
488 SHA1_Final(hash, &sha1);
492 snprintf(buf, sizeof buf, "set/%s", sha1_to_hex(hash));
493 if (write_to_file(buf, p, stat.st_size) < 0)
495 munmap(p, stat.st_size);
501 razor_set_list(struct razor_set *set)
504 struct razor_package *p;
507 for (i = 0; i < set->package_count && p->name; i++, p++) {
509 &set->string_pool[p->name],
510 &set->string_pool[p->version]);
515 razor_set_info(struct razor_set *set)
517 unsigned int offset, size;
520 for (i = 0; i < set->header->sections[i].type; i++) {
521 offset = set->header->sections[i].offset;
522 size = set->header->sections[i + 1].offset - offset;
524 switch (set->header->sections[i].type) {
526 printf("bucket section:\t\t%dkb\n", size / 1024);
529 printf("string pool:\t\t%dkb\n", size / 1024);
532 printf("package section:\t%dkb\n", size / 1024);
541 printf("usage: razor [ import FILES | lookup <key> | list | info ]\n");
545 static const char repo_filename[] = "system.repo";
548 main(int argc, char *argv[])
551 struct razor_set *set;
556 } else if (strcmp(argv[1], "import") == 0) {
557 if (stat("set", &statbuf) && mkdir("set", 0777)) {
558 fprintf(stderr, "could not create directory 'set'\n");
562 set = razor_set_create();
564 for (i = 2; i < argc; i++) {
565 if (razor_set_import(set, argv[i]) < 0) {
566 fprintf(stderr, "failed to import %s\n",
574 printf("number of buckets: %d\n",
576 printf("bucket allocation: %d\n",
578 printf("pool size: %d\n", set->pool_size);
579 printf("pool allocation: %d\n", set->pool_alloc);
581 razor_set_write(set, repo_filename);
583 razor_set_destroy(set);
584 } else if (strcmp(argv[1], "lookup") == 0) {
585 set = razor_set_open(repo_filename);
586 printf("%s is %lu\n", argv[2],
587 razor_set_lookup(set, argv[2]));
588 razor_set_destroy(set);
589 } else if (strcmp(argv[1], "list") == 0) {
590 set = razor_set_open(repo_filename);
592 razor_set_destroy(set);
593 } else if (strcmp(argv[1], "info") == 0) {
594 set = razor_set_open(repo_filename);
596 razor_set_destroy(set);