1.1 --- a/razor.c Mon Sep 03 14:36:59 2007 -0400
1.2 +++ b/razor.c Mon Sep 03 23:13:19 2007 -0400
1.3 @@ -50,6 +50,12 @@
1.4 #define HASHTABLE_VERSION 1
1.5 #define HASHTABLE_BUCKETS 1
1.6 #define HASHTABLE_STRINGS 2
1.7 +#define HASHTABLE_PACKAGES 3
1.8 +
1.9 +struct package {
1.10 + unsigned long name;
1.11 + unsigned long version;
1.12 +};
1.13
1.14 struct hashtable {
1.15 unsigned long *buckets;
1.16 @@ -57,6 +63,9 @@
1.17 char *string_pool;
1.18 int pool_size, pool_alloc;
1.19 struct hashtable_header *header;
1.20 +
1.21 + struct package *packages;
1.22 + int package_count, package_alloc;
1.23 };
1.24
1.25 static void *
1.26 @@ -84,6 +93,10 @@
1.27 ht->pool_size = 1;
1.28 ht->pool_alloc = 4096;
1.29
1.30 + ht->packages = zalloc(4096 * sizeof *ht->packages);
1.31 + ht->package_count = 0;
1.32 + ht->package_alloc = 4096;
1.33 +
1.34 return ht;
1.35 }
1.36
1.37 @@ -120,6 +133,11 @@
1.38 ht->pool_size = size;
1.39 ht->pool_alloc = size;
1.40 break;
1.41 + case HASHTABLE_PACKAGES:
1.42 + ht->packages = (void *) ht->header + offset;
1.43 + ht->package_count = size / sizeof *ht->packages;
1.44 + ht->package_alloc = size / sizeof *ht->packages;
1.45 + break;
1.46 }
1.47 }
1.48 close(fd);
1.49 @@ -149,9 +167,14 @@
1.50 static int
1.51 hashtable_write(struct hashtable *ht, const char *filename)
1.52 {
1.53 - int fd;
1.54 char data[4096];
1.55 struct hashtable_header *header = (struct hashtable_header *) data;
1.56 + int fd, pool_size, package_size;
1.57 +
1.58 + /* Align these to pages sizes */
1.59 + pool_size = (ht->pool_size + 4095) & ~4095;
1.60 + package_size =
1.61 + (ht->package_alloc * sizeof *ht->packages + 4095) & ~4095;
1.62
1.63 memset(data, 0, sizeof data);
1.64 header->magic = HASHTABLE_MAGIC;
1.65 @@ -161,12 +184,14 @@
1.66 header->sections[0].offset = sizeof data;
1.67
1.68 header->sections[1].type = HASHTABLE_STRINGS;
1.69 - header->sections[1].offset =
1.70 - sizeof data + ht->bucket_alloc * sizeof *ht->buckets;
1.71 + header->sections[1].offset = header->sections[0].offset +
1.72 + ht->bucket_alloc * sizeof *ht->buckets;
1.73
1.74 - header->sections[2].type = 0;
1.75 - header->sections[2].offset =
1.76 - header->sections[1].offset + ht->pool_size;
1.77 + header->sections[2].type = HASHTABLE_PACKAGES;
1.78 + header->sections[2].offset = header->sections[1].offset + pool_size;
1.79 +
1.80 + header->sections[3].type = 0;
1.81 + header->sections[3].offset = header->sections[2].offset + package_size;
1.82
1.83 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
1.84 if (fd < 0)
1.85 @@ -174,7 +199,8 @@
1.86
1.87 write_to_fd(fd, data, sizeof data);
1.88 write_to_fd(fd, ht->buckets, ht->bucket_alloc * sizeof *ht->buckets);
1.89 - write_to_fd(fd, ht->string_pool, ht->pool_size);
1.90 + write_to_fd(fd, ht->string_pool, pool_size);
1.91 + write_to_fd(fd, ht->packages, package_size);
1.92
1.93 return 0;
1.94 }
1.95 @@ -297,6 +323,32 @@
1.96 return value;
1.97 }
1.98
1.99 +static unsigned long
1.100 +hashtable_add_package(struct hashtable *ht,
1.101 + unsigned long name, unsigned long version)
1.102 +{
1.103 + struct package *packages;
1.104 + int alloc;
1.105 +
1.106 + alloc = ht->package_alloc;
1.107 + while (alloc < ht->package_count + 1)
1.108 + alloc *= 2;
1.109 + if (ht->package_alloc < alloc) {
1.110 + packages = realloc(ht->packages, alloc * sizeof ht->packages);
1.111 + if (packages == NULL)
1.112 + return 0;
1.113 + ht->packages = packages;
1.114 + ht->package_alloc = alloc;
1.115 + }
1.116 +
1.117 + ht->packages[ht->package_count].name = name;
1.118 + ht->packages[ht->package_count].version = version;
1.119 + ht->package_count++;
1.120 +
1.121 + return 0;
1.122 +}
1.123 +
1.124 +
1.125 struct razor_context {
1.126 struct hashtable *global_ht;
1.127 };
1.128 @@ -335,6 +387,27 @@
1.129 return hashtable_insert(ctx->global_ht, string);
1.130 }
1.131
1.132 +static struct hashtable *qsort_ht;
1.133 +
1.134 +static int
1.135 +compare_packages(const void *p1, const void *p2)
1.136 +{
1.137 + const struct package *pkg1 = p1, *pkg2 = p2;
1.138 +
1.139 + return strcmp(&qsort_ht->string_pool[pkg1->name],
1.140 + &qsort_ht->string_pool[pkg2->name]);
1.141 +}
1.142 +
1.143 +static void
1.144 +razor_context_sort(struct razor_context *ctx)
1.145 +{
1.146 + struct hashtable *ht = ctx->global_ht;
1.147 +
1.148 + qsort_ht = ht;
1.149 + qsort(ht->packages, ht->package_count, sizeof *ht->packages,
1.150 + compare_packages);
1.151 +}
1.152 +
1.153 struct razor_set {
1.154 struct razor_context *ctx;
1.155 };
1.156 @@ -344,11 +417,36 @@
1.157 };
1.158
1.159 static void
1.160 +parse_package(struct parsing_context *ctx, const char **atts)
1.161 +{
1.162 + unsigned long name, version;
1.163 + int i;
1.164 +
1.165 + for (i = 0; atts[i]; i += 2) {
1.166 + if (strcmp(atts[i], "name") == 0)
1.167 + name = razor_context_tokenize(ctx->ctx, atts[i + 1]);
1.168 + else if (strcmp(atts[i], "version") == 0)
1.169 + version = razor_context_tokenize(ctx->ctx, atts[i + 1]);
1.170 + }
1.171 +
1.172 + if (name == 0 || version == 0) {
1.173 + fprintf(stderr, "invalid package tag, "
1.174 + "missing name or version attributes\n");
1.175 + return;
1.176 + }
1.177 +
1.178 + hashtable_add_package(ctx->ctx->global_ht, name, version);
1.179 +}
1.180 +
1.181 +static void
1.182 start_element(void *data, const char *name, const char **atts)
1.183 {
1.184 struct parsing_context *ctx = data;
1.185 int i;
1.186
1.187 + if (strcmp(name, "package") == 0)
1.188 + parse_package(ctx, atts);
1.189 +
1.190 for (i = 0; atts[i]; i += 2)
1.191 razor_context_tokenize(ctx->ctx, atts[i + 1]);
1.192 }
1.193 @@ -432,6 +530,47 @@
1.194 }
1.195
1.196 void
1.197 +razor_context_list_packages(struct razor_context *ctx)
1.198 +{
1.199 + int i;
1.200 + struct hashtable *ht = ctx->global_ht;
1.201 + struct package *p;
1.202 +
1.203 + p = ht->packages;
1.204 + for (i = 0; i < ht->package_count && p->name; i++, p++) {
1.205 + printf("%s %s\n",
1.206 + &ht->string_pool[p->name],
1.207 + &ht->string_pool[p->version]);
1.208 + }
1.209 +}
1.210 +
1.211 +void
1.212 +razor_context_info(struct razor_context *ctx)
1.213 +{
1.214 + struct hashtable *ht = ctx->global_ht;
1.215 + unsigned int offset, size;
1.216 + int i;
1.217 +
1.218 + for (i = 0; i < ht->header->sections[i].type; i++) {
1.219 + offset = ht->header->sections[i].offset;
1.220 + size = ht->header->sections[i + 1].offset - offset;
1.221 +
1.222 + switch (ht->header->sections[i].type) {
1.223 + case HASHTABLE_BUCKETS:
1.224 + printf("bucket section:\t\t%dkb\n", size / 1024);
1.225 + break;
1.226 + case HASHTABLE_STRINGS:
1.227 + printf("string pool:\t\t%dkb\n", size / 1024);
1.228 + break;
1.229 + case HASHTABLE_PACKAGES:
1.230 + printf("package section:\t%dkb\n", size / 1024);
1.231 + break;
1.232 + }
1.233 + }
1.234 +
1.235 +}
1.236 +
1.237 +void
1.238 razor_context_destroy(struct razor_context *ctx)
1.239 {
1.240 hashtable_destroy(ctx->global_ht);
1.241 @@ -441,7 +580,7 @@
1.242 static int
1.243 usage(void)
1.244 {
1.245 - printf("usage: razor [ import FILES | lookup <key> ]\n");
1.246 + printf("usage: razor [ import FILES | lookup <key> | list | info ]\n");
1.247 exit(1);
1.248 }
1.249
1.250 @@ -454,7 +593,7 @@
1.251 struct razor_context *ctx;
1.252 struct stat statbuf;
1.253
1.254 - if (argc < 3) {
1.255 + if (argc < 2) {
1.256 usage();
1.257 } else if (strcmp(argv[1], "import") == 0) {
1.258 if (stat("set", &statbuf) && mkdir("set", 0777)) {
1.259 @@ -472,6 +611,8 @@
1.260 }
1.261 }
1.262
1.263 + razor_context_sort(ctx);
1.264 +
1.265 printf("number of buckets: %d\n",
1.266 ctx->global_ht->bucket_count);
1.267 printf("bucket allocation: %d\n",
1.268 @@ -487,6 +628,14 @@
1.269 printf("%s is %lu\n", argv[2],
1.270 hashtable_lookup(ctx->global_ht, argv[2]));
1.271 razor_context_destroy(ctx);
1.272 + } else if (strcmp(argv[1], "list") == 0) {
1.273 + ctx = razor_context_create_from_file(repo_filename);
1.274 + razor_context_list_packages(ctx);
1.275 + razor_context_destroy(ctx);
1.276 + } else if (strcmp(argv[1], "info") == 0) {
1.277 + ctx = razor_context_create_from_file(repo_filename);
1.278 + razor_context_info(ctx);
1.279 + razor_context_destroy(ctx);
1.280 } else {
1.281 usage();
1.282 }