2 * Copyright (c) 2007, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
11 * Write Repo data out to binary file
13 * See doc/README.format for a description
14 * of the binary file format
18 #include <sys/types.h>
27 #include "repo_write.h"
29 /*------------------------------------------------------------------*/
30 /* Id map optimizations */
32 typedef struct needid {
38 #define RELOFF(id) (pool->ss.nstrings + GETRELID(id))
42 * idarray: array of Ids, ID_NULL terminated
43 * needid: array of Id->NeedId
50 incneedid(Pool *pool, Id *idarray, NeedId *needid)
58 while ((id = *idarray++) != 0)
63 Reldep *rd = GETRELDEP(pool, id);
64 needid[RELOFF(id)].need++;
65 if (ISRELDEP(rd->evr))
70 incneedid(pool, ida, needid);
73 needid[rd->evr].need++;
87 needid_cmp_need(const void *ap, const void *bp)
92 r = b->need - a->need;
95 return a->map - b->map;
99 /*------------------------------------------------------------------*/
100 /* output routines */
107 write_u32(FILE *fp, unsigned int x)
109 if (putc(x >> 24, fp) == EOF ||
110 putc(x >> 16, fp) == EOF ||
111 putc(x >> 8, fp) == EOF ||
114 perror("write error");
125 write_u8(FILE *fp, unsigned int x)
127 if (putc(x, fp) == EOF)
129 perror("write error");
140 write_id(FILE *fp, Id x)
145 putc((x >> 28) | 128, fp);
147 putc((x >> 21) | 128, fp);
148 putc((x >> 14) | 128, fp);
151 putc((x >> 7) | 128, fp);
152 if (putc(x & 127, fp) == EOF)
154 perror("write error");
165 write_idarray(FILE *fp, Pool *pool, NeedId *needid, Id *ids)
179 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
181 id = (id & 63) | ((id & ~63) << 1);
187 write_id(fp, id | 64);
197 repo_write(Repo *repo, FILE *fp)
199 Pool *pool = repo->pool;
203 int nstrings, nrels, nkeys, nschemata;
208 int idsizes[RPM_RPMDBID + 1];
209 int id2key[RPM_RPMDBID + 1];
212 Id *schemadata, *schemadatap, *schema, *sp;
215 Id *solvschema; /* schema of our solvables */
217 Id lastschemakey[256];
220 idarraydata = repo->idarraydata;
222 needid = (NeedId *)xcalloc(pool->ss.nstrings + pool->nrels, sizeof(*needid));
224 memset(idsizes, 0, sizeof(idsizes));
226 for (i = repo->start, s = pool->solvables + i; i < repo->end; i++, s++)
231 needid[s->name].need++;
232 needid[s->arch].need++;
233 needid[s->evr].need++;
236 needid[s->vendor].need++;
237 idsizes[SOLVABLE_VENDOR] = 1;
240 idsizes[SOLVABLE_PROVIDES] += incneedid(pool, idarraydata + s->provides, needid);
242 idsizes[SOLVABLE_REQUIRES] += incneedid(pool, idarraydata + s->requires, needid);
244 idsizes[SOLVABLE_CONFLICTS] += incneedid(pool, idarraydata + s->conflicts, needid);
246 idsizes[SOLVABLE_OBSOLETES] += incneedid(pool, idarraydata + s->obsoletes, needid);
248 idsizes[SOLVABLE_RECOMMENDS] += incneedid(pool, idarraydata + s->recommends, needid);
250 idsizes[SOLVABLE_SUGGESTS] += incneedid(pool, idarraydata + s->suggests, needid);
252 idsizes[SOLVABLE_SUPPLEMENTS] += incneedid(pool, idarraydata + s->supplements, needid);
254 idsizes[SOLVABLE_ENHANCES] += incneedid(pool, idarraydata + s->enhances, needid);
256 idsizes[SOLVABLE_FRESHENS] += incneedid(pool, idarraydata + s->freshens, needid);
258 if (nsolvables != repo->nsolvables)
261 idsizes[SOLVABLE_NAME] = 1;
262 idsizes[SOLVABLE_ARCH] = 1;
263 idsizes[SOLVABLE_EVR] = 1;
265 idsizes[RPM_RPMDBID] = 1;
267 for (i = SOLVABLE_NAME; i <= RPM_RPMDBID; i++)
274 needid[pool->ss.nstrings].need = 0;
275 for (i = 0; i < pool->ss.nstrings + pool->nrels; i++)
278 qsort(needid + 1, pool->ss.nstrings - 1, sizeof(*needid), needid_cmp_need);
279 qsort(needid + pool->ss.nstrings, pool->nrels, sizeof(*needid), needid_cmp_need);
282 for (i = 1; i < pool->ss.nstrings; i++)
287 sizeid += strlen(pool->ss.stringspace + pool->ss.strings[needid[i].map]) + 1;
291 for (i = 0; i < nstrings; i++)
292 needid[needid[i].map].need = i;
294 for (i = 0; i < pool->nrels; i++)
296 if (!needid[pool->ss.nstrings + i].need)
299 needid[pool->ss.nstrings + i].need = 0;
303 for (i = 0; i < nrels; i++)
305 needid[needid[pool->ss.nstrings + i].map].need = nstrings + i;
308 /* find the keys we need */
310 memset(id2key, 0, sizeof(id2key));
311 for (i = SOLVABLE_NAME; i <= RPM_RPMDBID; i++)
315 /* find the schemata we need */
316 solvschema = xcalloc(repo->nsolvables, sizeof(Id));
318 memset(lastschema, 0, sizeof(lastschema));
319 memset(lastschemakey, 0, sizeof(lastschemakey));
320 schemadata = xmalloc(256 * sizeof(Id));
322 schemadatap = schemadata;
326 for (i = repo->start, s = pool->solvables + i, n = 0; i < repo->end; i++, s++)
333 if (schemadatalen < 32)
335 int l = schemadatap - schemadata;
336 fprintf(stderr, "growing schemadata\n");
337 schemadata = xrealloc(schemadata, (schemadatap - schemadata + 256) * sizeof(Id));
339 schemadatap = schemadata + l;
341 schema = schemadatap;
342 *schema++ = SOLVABLE_NAME;
343 *schema++ = SOLVABLE_ARCH;
344 *schema++ = SOLVABLE_EVR;
346 *schema++ = SOLVABLE_VENDOR;
348 *schema++ = SOLVABLE_PROVIDES;
350 *schema++ = SOLVABLE_OBSOLETES;
352 *schema++ = SOLVABLE_CONFLICTS;
354 *schema++ = SOLVABLE_REQUIRES;
356 *schema++ = SOLVABLE_RECOMMENDS;
358 *schema++ = SOLVABLE_SUGGESTS;
360 *schema++ = SOLVABLE_SUPPLEMENTS;
362 *schema++ = SOLVABLE_ENHANCES;
364 *schema++ = SOLVABLE_FRESHENS;
366 *schema++ = RPM_RPMDBID;
368 for (sp = schemadatap, h = 0; *sp; )
371 if (lastschema[h] && !memcmp(schemadata + lastschema[h], schemadatap, (schema - schemadatap) * sizeof(Id)))
373 solvschema[n++] = lastschemakey[h];
377 for (sp = schemadata + 1; sp < schemadatap; )
379 if (!memcmp(sp, schemadatap, (schema - schemadatap) * sizeof(Id)))
385 if (sp >= schemadatap)
387 if (schemaid != nschemata)
389 lastschema[h] = schemadatap - schemadata;
390 lastschemakey[h] = schemaid;
391 schemadatalen -= schema - schemadatap;
392 schemadatap = schema;
395 solvschema[n++] = schemaid;
397 /* convert all schemas to keys */
398 for (sp = schemadata; sp < schemadatap; sp++)
401 /* write file header */
402 write_u32(fp, 'S' << 24 | 'O' << 16 | 'L' << 8 | 'V');
403 write_u32(fp, SOLV_VERSION_1);
406 write_u32(fp, nstrings);
407 write_u32(fp, nrels);
408 write_u32(fp, nsolvables);
409 write_u32(fp, nkeys);
410 write_u32(fp, nschemata);
411 write_u32(fp, 0); /* no info block */
413 write_u32(fp, SOLV_FLAG_VERTICAL); /* no flags */
415 write_u32(fp, 0); /* no flags */
421 write_u32(fp, sizeid);
422 for (i = 1; i < nstrings; i++)
424 char *str = pool->ss.stringspace + pool->ss.strings[needid[i].map];
425 if (fwrite(str, strlen(str) + 1, 1, fp) != 1)
427 perror("write error");
435 for (i = 0; i < nrels; i++)
437 ran = pool->rels + (needid[pool->ss.nstrings + i].map - pool->ss.nstrings);
438 write_id(fp, needid[ISRELDEP(ran->name) ? RELOFF(ran->name) : ran->name].need);
439 write_id(fp, needid[ISRELDEP(ran->evr) ? RELOFF(ran->evr) : ran->evr].need);
440 write_u8( fp, ran->flags);
446 for (i = SOLVABLE_NAME; i <= RPM_RPMDBID; i++)
450 write_id(fp, needid[i].need);
451 if (i >= SOLVABLE_PROVIDES && i <= SOLVABLE_FRESHENS)
452 write_id(fp, TYPE_IDARRAY);
453 else if (i == RPM_RPMDBID)
454 write_id(fp, TYPE_U32);
456 write_id(fp, TYPE_ID);
457 write_id(fp, idsizes[i]);
463 write_id(fp, schemadatap - schemadata - 1);
464 for (sp = schemadata + 1; sp < schemadatap; )
466 write_idarray(fp, pool, 0, sp);
476 for (i = 0; i < nsolvables; i++)
477 write_id(fp, solvschema[i]);
478 unsigned char *used = xmalloc(nschemata);
479 for (id = SOLVABLE_NAME; id <= RPM_RPMDBID; id++)
482 memset(used, 0, nschemata);
483 for (sp = schemadata + 1, i = 0; sp < schemadatap; sp++)
490 for (i = repo->start, s = pool->solvables + i, n = 0; i < repo->end; i++, s++)
494 if (!used[solvschema[n++]])
499 write_id(fp, needid[s->name].need);
502 write_id(fp, needid[s->arch].need);
505 write_id(fp, needid[s->evr].need);
507 case SOLVABLE_VENDOR:
508 write_id(fp, needid[s->vendor].need);
511 write_u32(fp, repo->rpmdbid[i - repo->start]);
513 case SOLVABLE_PROVIDES:
514 write_idarray(fp, pool, needid, idarraydata + s->provides);
516 case SOLVABLE_OBSOLETES:
517 write_idarray(fp, pool, needid, idarraydata + s->obsoletes);
519 case SOLVABLE_CONFLICTS:
520 write_idarray(fp, pool, needid, idarraydata + s->conflicts);
522 case SOLVABLE_REQUIRES:
523 write_idarray(fp, pool, needid, idarraydata + s->requires);
525 case SOLVABLE_RECOMMENDS:
526 write_idarray(fp, pool, needid, idarraydata + s->recommends);
528 case SOLVABLE_SUPPLEMENTS:
529 write_idarray(fp, pool, needid, idarraydata + s->supplements);
531 case SOLVABLE_SUGGESTS:
532 write_idarray(fp, pool, needid, idarraydata + s->suggests);
534 case SOLVABLE_ENHANCES:
535 write_idarray(fp, pool, needid, idarraydata + s->enhances);
537 case SOLVABLE_FRESHENS:
538 write_idarray(fp, pool, needid, idarraydata + s->freshens);
555 for (i = repo->start, s = pool->solvables + i, n = 0; i < repo->end; i++, s++)
559 /* keep in sync with schema generation! */
560 write_id(fp, solvschema[n++]);
561 write_id(fp, needid[s->name].need);
562 write_id(fp, needid[s->arch].need);
563 write_id(fp, needid[s->evr].need);
565 write_id(fp, needid[s->vendor].need);
567 write_idarray(fp, pool, needid, idarraydata + s->provides);
569 write_idarray(fp, pool, needid, idarraydata + s->obsoletes);
571 write_idarray(fp, pool, needid, idarraydata + s->conflicts);
573 write_idarray(fp, pool, needid, idarraydata + s->requires);
575 write_idarray(fp, pool, needid, idarraydata + s->recommends);
577 write_idarray(fp, pool, needid, idarraydata + s->suggests);
579 write_idarray(fp, pool, needid, idarraydata + s->supplements);
581 write_idarray(fp, pool, needid, idarraydata + s->enhances);
583 write_idarray(fp, pool, needid, idarraydata + s->freshens);
585 write_u32(fp, repo->rpmdbid[i - repo->start]);