2 * Copyright (c) 2007-2011, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
11 * Write Repo data out to a file in solv format
13 * See doc/README.format for a description
14 * of the binary file format
18 #include <sys/types.h>
29 #include "repo_write.h"
32 /*------------------------------------------------------------------*/
33 /* Id map optimizations */
35 typedef struct needid {
41 #define RELOFF(id) (needid[0].map + GETRELID(id))
45 * idarray: array of Ids, ID_NULL terminated
46 * needid: array of Id->NeedId
48 * return size of array (including trailing zero)
53 incneedid(Pool *pool, Id id, NeedId *needid)
57 Reldep *rd = GETRELDEP(pool, id);
58 needid[RELOFF(id)].need++;
59 if (ISRELDEP(rd->evr))
60 incneedid(pool, rd->evr, needid);
62 needid[rd->evr].need++;
69 incneedidarray(Pool *pool, Id *idarray, NeedId *needid)
76 while ((id = *idarray++) != 0)
81 Reldep *rd = GETRELDEP(pool, id);
82 needid[RELOFF(id)].need++;
83 if (ISRELDEP(rd->evr))
84 incneedid(pool, rd->evr, needid);
86 needid[rd->evr].need++;
100 needid_cmp_need(const void *ap, const void *bp, void *dp)
102 const NeedId *a = ap;
103 const NeedId *b = bp;
105 r = b->need - a->need;
108 return a->map - b->map;
112 needid_cmp_need_s(const void *ap, const void *bp, void *dp)
114 const NeedId *a = ap;
115 const NeedId *b = bp;
116 Stringpool *spool = dp;
121 r = b->need - a->need;
124 as = spool->stringspace + spool->strings[a->map];
125 bs = spool->stringspace + spool->strings[b->map];
126 return strcmp(as, bs);
130 /*------------------------------------------------------------------*/
131 /* output helper routines, used for writing the header */
132 /* (the data itself is accumulated in memory and written with
140 write_u32(Repodata *data, unsigned int x)
145 if (putc(x >> 24, fp) == EOF ||
146 putc(x >> 16, fp) == EOF ||
147 putc(x >> 8, fp) == EOF ||
150 data->error = pool_error(data->repo->pool, -1, "write error u32: %s", strerror(errno));
160 write_u8(Repodata *data, unsigned int x)
164 if (putc(x, data->fp) == EOF)
166 data->error = pool_error(data->repo->pool, -1, "write error u8: %s", strerror(errno));
175 write_blob(Repodata *data, void *blob, int len)
179 if (len && fwrite(blob, len, 1, data->fp) != 1)
181 data->error = pool_error(data->repo->pool, -1, "write error blob: %s", strerror(errno));
190 write_id(Repodata *data, Id x)
198 putc((x >> 28) | 128, fp);
200 putc((x >> 21) | 128, fp);
201 putc((x >> 14) | 128, fp);
204 putc((x >> 7) | 128, fp);
205 if (putc(x & 127, fp) == EOF)
207 data->error = pool_error(data->repo->pool, -1, "write error id: %s", strerror(errno));
212 write_id_eof(Repodata *data, Id x, int eof)
215 x = (x & 63) | ((x & ~63) << 1);
216 write_id(data, x | (eof ? 0 : 64));
222 write_str(Repodata *data, const char *str)
226 if (fputs(str, data->fp) == EOF || putc(0, data->fp) == EOF)
228 data->error = pool_error(data->repo->pool, -1, "write error str: %s", strerror(errno));
237 write_idarray(Repodata *data, Pool *pool, NeedId *needid, Id *ids)
251 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
253 id = (id & 63) | ((id & ~63) << 1);
259 write_id(data, id | 64);
264 cmp_ids(const void *pa, const void *pb, void *dp)
273 write_idarray_sort(Repodata *data, Pool *pool, NeedId *needid, Id *ids, Id marker)
285 for (len = 0; len < 64 && ids[len]; len++)
289 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
294 for (i = len + 1; ids[i]; i++)
296 sids = solv_malloc2(i, sizeof(Id));
297 memcpy(sids, lids, 64 * sizeof(Id));
298 for (; ids[len]; len++)
302 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
309 /* That bloody solvable:prereqmarker needs to stay in position :-( */
311 marker = needid[marker].need;
312 for (i = 0; i < len; i++)
313 if (sids[i] == marker)
316 solv_sort(sids, i, sizeof(Id), cmp_ids, 0);
318 solv_sort(sids + i + 1, len - i - 1, sizeof(Id), cmp_ids, 0);
322 /* The differencing above produces many runs of ones and twos. I tried
323 fairly elaborate schemes to RLE those, but they give only very mediocre
324 improvements in compression, as coding the escapes costs quite some
325 space. Even if they are coded only as bits in IDs. The best improvement
326 was about 2.7% for the whole .solv file. It's probably better to
327 invest some complexity into sharing idarrays, than RLEing. */
328 for (i = 0; i < len - 1; i++)
331 /* Ugly PREREQ handling. A "difference" of 0 is the prereq marker,
332 hence all real differences are offsetted by 1. Otherwise we would
333 have to handle negative differences, which would cost code space for
334 the encoding of the sign. We loose the exact mapping of prereq here,
335 but we know the result, so we can recover from that in the reader. */
343 /* XXX If difference is zero we have multiple equal elements,
344 we might want to skip writing them out. */
346 id = (id & 63) | ((id & ~63) << 1);
347 write_id(data, id | 64);
355 id = (id & 63) | ((id & ~63) << 1);
372 Stringpool *ownspool;
381 Id *schema; /* schema construction space */
382 Id *sp; /* pointer in above */
383 Id *oldschema, *oldsp;
390 struct extdata *extdata;
399 int doingsolvables; /* working on solvables data */
402 #define NEEDED_BLOCK 1023
403 #define SCHEMATA_BLOCK 31
404 #define SCHEMATADATA_BLOCK 255
405 #define EXTDATA_BLOCK 4095
408 data_addid(struct extdata *xd, Id sx)
410 unsigned int x = (unsigned int)sx;
413 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
414 dp = xd->buf + xd->len;
419 *dp++ = (x >> 28) | 128;
421 *dp++ = (x >> 21) | 128;
422 *dp++ = (x >> 14) | 128;
425 *dp++ = (x >> 7) | 128;
427 xd->len = dp - xd->buf;
431 data_addideof(struct extdata *xd, Id sx, int eof)
433 unsigned int x = (unsigned int)sx;
436 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
437 dp = xd->buf + xd->len;
442 *dp++ = (x >> 27) | 128;
444 *dp++ = (x >> 20) | 128;
445 *dp++ = (x >> 13) | 128;
448 *dp++ = (x >> 6) | 128;
449 *dp++ = eof ? (x & 63) : (x & 63) | 64;
450 xd->len = dp - xd->buf;
454 data_addid64(struct extdata *xd, unsigned int x, unsigned int hx)
460 data_addid(xd, (Id)(hx >> 3));
461 xd->buf[xd->len - 1] |= 128;
464 data_addid(xd, (Id)(x | 0x80000000));
465 xd->buf[xd->len - 5] = (x >> 28) | (hx << 4) | 128;
468 data_addid(xd, (Id)x);
472 data_addidarray_sort(struct extdata *xd, Pool *pool, NeedId *needid, Id *ids, Id marker)
485 for (len = 0; len < 64 && ids[len]; len++)
489 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
494 for (i = len + 1; ids[i]; i++)
496 sids = solv_malloc2(i, sizeof(Id));
497 memcpy(sids, lids, 64 * sizeof(Id));
498 for (; ids[len]; len++)
502 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
509 /* That bloody solvable:prereqmarker needs to stay in position :-( */
511 marker = needid[marker].need;
512 for (i = 0; i < len; i++)
513 if (sids[i] == marker)
516 solv_sort(sids, i, sizeof(Id), cmp_ids, 0);
518 solv_sort(sids + i + 1, len - i - 1, sizeof(Id), cmp_ids, 0);
522 /* The differencing above produces many runs of ones and twos. I tried
523 fairly elaborate schemes to RLE those, but they give only very mediocre
524 improvements in compression, as coding the escapes costs quite some
525 space. Even if they are coded only as bits in IDs. The best improvement
526 was about 2.7% for the whole .solv file. It's probably better to
527 invest some complexity into sharing idarrays, than RLEing. */
528 for (i = 0; i < len - 1; i++)
531 /* Ugly PREREQ handling. A "difference" of 0 is the prereq marker,
532 hence all real differences are offsetted by 1. Otherwise we would
533 have to handle negative differences, which would cost code space for
534 the encoding of the sign. We loose the exact mapping of prereq here,
535 but we know the result, so we can recover from that in the reader. */
543 /* XXX If difference is zero we have multiple equal elements,
544 we might want to skip writing them out. */
545 data_addideof(xd, id, 0);
552 data_addideof(xd, id, 1);
558 data_addblob(struct extdata *xd, unsigned char *blob, int len)
560 xd->buf = solv_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
561 memcpy(xd->buf + xd->len, blob, len);
566 data_addu32(struct extdata *xd, unsigned int num)
573 data_addblob(xd, d, 4);
577 putinownpool(struct cbdata *cbdata, Stringpool *ss, Id id)
579 const char *str = stringpool_id2str(ss, id);
580 id = stringpool_str2id(cbdata->ownspool, str, 1);
581 if (id >= cbdata->needid[0].map)
583 int oldoff = cbdata->needid[0].map;
584 int newoff = (id + 1 + NEEDED_BLOCK) & ~NEEDED_BLOCK;
585 int nrels = cbdata->repo->pool->nrels;
586 cbdata->needid = solv_realloc2(cbdata->needid, newoff + nrels, sizeof(NeedId));
588 memmove(cbdata->needid + newoff, cbdata->needid + oldoff, nrels * sizeof(NeedId));
589 memset(cbdata->needid + oldoff, 0, (newoff - oldoff) * sizeof(NeedId));
590 cbdata->needid[0].map = newoff;
596 putinowndirpool(struct cbdata *cbdata, Repodata *data, Dirpool *dp, Id dir)
600 parent = dirpool_parent(dp, dir);
602 parent = putinowndirpool(cbdata, data, dp, parent);
603 compid = dp->dirs[dir];
604 if (cbdata->ownspool && compid > 1)
605 compid = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, compid);
606 return dirpool_add_dir(cbdata->owndirpool, parent, compid, 1);
610 * collect usage information about the dirs
611 * 1: dir used, no child of dir used
612 * 2: dir used as parent of another used dir
615 setdirused(struct cbdata *cbdata, Dirpool *dp, Id dir)
617 if (cbdata->dirused[dir])
619 cbdata->dirused[dir] = 1;
620 while ((dir = dirpool_parent(dp, dir)) != 0)
622 if (cbdata->dirused[dir] == 2)
624 if (cbdata->dirused[dir])
626 cbdata->dirused[dir] = 2;
629 cbdata->dirused[dir] = 2;
631 cbdata->dirused[0] = 2;
636 * collect key/id/dirid usage information, create needed schemas
639 repo_write_collect_needed(struct cbdata *cbdata, Repo *repo, Repodata *data, Repokey *key, KeyValue *kv)
644 if (key->name == REPOSITORY_SOLVABLES)
645 return SEARCH_NEXT_KEY; /* we do not want this one */
647 /* hack: ignore some keys, see BUGS */
648 if (data->repodataid != data->repo->nrepodata - 1)
649 if (key->name == REPOSITORY_ADDEDFILEPROVIDES || key->name == REPOSITORY_EXTERNAL || key->name == REPOSITORY_LOCATION || key->name == REPOSITORY_KEYS || key->name == REPOSITORY_TOOLVERSION)
650 return SEARCH_NEXT_KEY;
652 rm = cbdata->keymap[cbdata->keymapstart[data->repodataid] + (key - data->keys)];
654 return SEARCH_NEXT_KEY; /* we do not want this one */
656 /* record key in schema */
657 if ((key->type != REPOKEY_TYPE_FIXARRAY || kv->eof == 0)
658 && (cbdata->sp == cbdata->schema || cbdata->sp[-1] != rm))
663 case REPOKEY_TYPE_ID:
664 case REPOKEY_TYPE_IDARRAY:
666 if (!ISRELDEP(id) && cbdata->ownspool && id > 1)
667 id = putinownpool(cbdata, data->localpool ? &data->spool : &repo->pool->ss, id);
668 incneedid(repo->pool, id, cbdata->needid);
670 case REPOKEY_TYPE_DIR:
671 case REPOKEY_TYPE_DIRNUMNUMARRAY:
672 case REPOKEY_TYPE_DIRSTRARRAY:
674 if (cbdata->owndirpool)
675 putinowndirpool(cbdata, data, &data->dirpool, id);
677 setdirused(cbdata, &data->dirpool, id);
679 case REPOKEY_TYPE_FIXARRAY:
682 if (cbdata->oldschema)
684 cbdata->target->error = pool_error(cbdata->repo->pool, -1, "nested fixarray structs not yet implemented");
685 return SEARCH_NEXT_KEY;
687 cbdata->oldschema = cbdata->schema;
688 cbdata->oldsp = cbdata->sp;
689 cbdata->schema = solv_calloc(cbdata->target->nkeys, sizeof(Id));
690 cbdata->sp = cbdata->schema;
692 else if (kv->eof == 1)
694 cbdata->current_sub++;
696 cbdata->subschemata = solv_extend(cbdata->subschemata, cbdata->nsubschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
697 cbdata->subschemata[cbdata->nsubschemata++] = repodata_schema2id(cbdata->target, cbdata->schema, 1);
699 fprintf(stderr, "Have schema %d\n", cbdata->subschemata[cbdata->nsubschemata-1]);
701 cbdata->sp = cbdata->schema;
705 solv_free(cbdata->schema);
706 cbdata->schema = cbdata->oldschema;
707 cbdata->sp = cbdata->oldsp;
708 cbdata->oldsp = cbdata->oldschema = 0;
711 case REPOKEY_TYPE_FLEXARRAY:
715 *cbdata->sp++ = 0; /* mark start */
719 /* just finished a schema, rewind */
720 Id *sp = cbdata->sp - 1;
724 cbdata->subschemata = solv_extend(cbdata->subschemata, cbdata->nsubschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
725 cbdata->subschemata[cbdata->nsubschemata++] = repodata_schema2id(cbdata->target, sp, 1);
726 cbdata->sp = kv->eof == 2 ? sp - 1: sp;
736 repo_write_cb_needed(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
738 struct cbdata *cbdata = vcbdata;
739 Repo *repo = data->repo;
743 fprintf(stderr, "solvable %d (%s): key (%d)%s %d\n", s ? s - repo->pool->solvables : 0, s ? pool_id2str(repo->pool, s->name) : "", key->name, pool_id2str(repo->pool, key->name), key->type);
745 return repo_write_collect_needed(cbdata, repo, data, key, kv);
751 * encode all of the data into the correct buffers
755 repo_write_adddata(struct cbdata *cbdata, Repodata *data, Repokey *key, KeyValue *kv)
764 if (key->name == REPOSITORY_SOLVABLES)
765 return SEARCH_NEXT_KEY;
767 /* hack: ignore some keys, see BUGS */
768 if (data->repodataid != data->repo->nrepodata - 1)
769 if (key->name == REPOSITORY_ADDEDFILEPROVIDES || key->name == REPOSITORY_EXTERNAL || key->name == REPOSITORY_LOCATION || key->name == REPOSITORY_KEYS || key->name == REPOSITORY_TOOLVERSION)
770 return SEARCH_NEXT_KEY;
772 rm = cbdata->keymap[cbdata->keymapstart[data->repodataid] + (key - data->keys)];
774 return SEARCH_NEXT_KEY; /* we do not want this one */
776 if (cbdata->target->keys[rm].storage == KEY_STORAGE_VERTICAL_OFFSET)
778 xd = cbdata->extdata + rm; /* vertical buffer */
779 if (cbdata->vstart == -1)
780 cbdata->vstart = xd->len;
783 xd = cbdata->extdata + 0; /* incore buffer */
786 case REPOKEY_TYPE_VOID:
787 case REPOKEY_TYPE_CONSTANT:
788 case REPOKEY_TYPE_CONSTANTID:
790 case REPOKEY_TYPE_ID:
792 if (!ISRELDEP(id) && cbdata->ownspool && id > 1)
793 id = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, id);
794 needid = cbdata->needid;
795 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
798 case REPOKEY_TYPE_IDARRAY:
800 if (!ISRELDEP(id) && cbdata->ownspool && id > 1)
801 id = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, id);
802 needid = cbdata->needid;
803 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
804 data_addideof(xd, id, kv->eof);
806 case REPOKEY_TYPE_STR:
807 data_addblob(xd, (unsigned char *)kv->str, strlen(kv->str) + 1);
809 case REPOKEY_TYPE_MD5:
810 data_addblob(xd, (unsigned char *)kv->str, SIZEOF_MD5);
812 case REPOKEY_TYPE_SHA1:
813 data_addblob(xd, (unsigned char *)kv->str, SIZEOF_SHA1);
815 case REPOKEY_TYPE_SHA256:
816 data_addblob(xd, (unsigned char *)kv->str, SIZEOF_SHA256);
818 case REPOKEY_TYPE_U32:
824 data_addblob(xd, v, 4);
826 case REPOKEY_TYPE_NUM:
827 data_addid64(xd, kv->num, kv->num2);
829 case REPOKEY_TYPE_DIR:
831 if (cbdata->owndirpool)
832 id = putinowndirpool(cbdata, data, &data->dirpool, id);
833 id = cbdata->dirused[id];
836 case REPOKEY_TYPE_BINARY:
837 data_addid(xd, kv->num);
839 data_addblob(xd, (unsigned char *)kv->str, kv->num);
841 case REPOKEY_TYPE_DIRNUMNUMARRAY:
843 if (cbdata->owndirpool)
844 id = putinowndirpool(cbdata, data, &data->dirpool, id);
845 id = cbdata->dirused[id];
847 data_addid(xd, kv->num);
848 data_addideof(xd, kv->num2, kv->eof);
850 case REPOKEY_TYPE_DIRSTRARRAY:
852 if (cbdata->owndirpool)
853 id = putinowndirpool(cbdata, data, &data->dirpool, id);
854 id = cbdata->dirused[id];
855 data_addideof(xd, id, kv->eof);
856 data_addblob(xd, (unsigned char *)kv->str, strlen(kv->str) + 1);
858 case REPOKEY_TYPE_FIXARRAY:
863 data_addid(xd, kv->num);
864 data_addid(xd, cbdata->subschemata[cbdata->current_sub]);
866 fprintf(stderr, "writing %d %d\n", kv->num, cbdata->subschemata[cbdata->current_sub]);
870 else if (kv->eof == 1)
872 cbdata->current_sub++;
875 case REPOKEY_TYPE_FLEXARRAY:
877 data_addid(xd, kv->num);
879 data_addid(xd, cbdata->subschemata[cbdata->current_sub++]);
880 if (xd == cbdata->extdata + 0 && !kv->parent && !cbdata->doingsolvables)
882 if (xd->len - cbdata->lastlen > cbdata->maxdata)
883 cbdata->maxdata = xd->len - cbdata->lastlen;
884 cbdata->lastlen = xd->len;
888 cbdata->target->error = pool_error(cbdata->repo->pool, -1, "unknown type for %d: %d\n", key->name, key->type);
891 if (cbdata->target->keys[rm].storage == KEY_STORAGE_VERTICAL_OFFSET && kv->eof)
893 /* we can re-use old data in the blob here! */
894 data_addid(cbdata->extdata + 0, cbdata->vstart); /* add offset into incore data */
895 data_addid(cbdata->extdata + 0, xd->len - cbdata->vstart); /* add length into incore data */
902 repo_write_cb_adddata(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
904 struct cbdata *cbdata = vcbdata;
905 return repo_write_adddata(cbdata, data, key, kv);
908 /* traverse through directory with first child "dir" */
910 traverse_dirs(Dirpool *dp, Id *dirmap, Id n, Id dir, Id *used)
916 /* special case for '/', which has to come first */
919 for (sib = dir; sib; sib = dirpool_sibling(dp, sib))
921 if (used && !used[sib])
923 if (sib == 1 && parent == 1)
924 continue; /* already did that one above */
928 /* now go through all the siblings we just added and
929 * do recursive calls on them */
931 for (; parent < lastn; parent++)
933 sib = dirmap[parent];
934 if (used && used[sib] != 2) /* 2: used as parent */
936 child = dirpool_child(dp, sib);
939 dirmap[n++] = -parent; /* start new block */
940 n = traverse_dirs(dp, dirmap, n, child, used);
947 write_compressed_page(Repodata *data, unsigned char *page, int len)
950 unsigned char cpage[REPOPAGE_BLOBSIZE];
952 clen = repopagestore_compress_page(page, len, cpage, len - 1);
955 write_u32(data, len * 2);
956 write_blob(data, page, len);
960 write_u32(data, clen * 2 + 1);
961 write_blob(data, cpage, clen);
965 static Id verticals[] = {
967 SOLVABLE_DESCRIPTION,
979 static char *languagetags[] = {
981 "solvable:description:",
982 "solvable:messageins:",
983 "solvable:messagedel:",
989 repo_write_stdkeyfilter(Repo *repo, Repokey *key, void *kfdata)
994 for (i = 0; verticals[i]; i++)
995 if (key->name == verticals[i])
996 return KEY_STORAGE_VERTICAL_OFFSET;
997 keyname = pool_id2str(repo->pool, key->name);
998 for (i = 0; languagetags[i] != 0; i++)
999 if (!strncmp(keyname, languagetags[i], strlen(languagetags[i])))
1000 return KEY_STORAGE_VERTICAL_OFFSET;
1001 return KEY_STORAGE_INCORE;
1009 * the code works the following way:
1011 * 1) find which keys should be written
1012 * 2) collect usage information for keys/ids/dirids, create schema
1014 * 3) use usage information to create mapping tables, so that often
1015 * used ids get a lower number
1016 * 4) encode data into buffers using the mapping tables
1017 * 5) write everything to disk
1020 repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq)
1022 Pool *pool = repo->pool;
1026 int nstrings, nrels;
1027 unsigned int sizeid;
1028 unsigned int solv_flags;
1037 unsigned char *repodataused;
1038 int anyrepodataused = 0;
1039 int anysolvableused = 0;
1041 struct cbdata cbdata;
1044 int poolusage, dirpoolusage, idused, dirused;
1047 Repodata *data, *dirpooldata;
1058 Id type_constantid = REPOKEY_TYPE_CONSTANTID;
1060 unsigned char *prefixcomp;
1061 unsigned int compsum;
1065 memset(&cbdata, 0, sizeof(cbdata));
1067 cbdata.target = ⌖
1069 repodata_initdata(&target, repo, 1);
1071 /* go through all repodata and find the keys we need */
1072 /* also unify keys */
1073 /* keymapstart - maps repo number to keymap offset */
1074 /* keymap - maps repo key to my key, 0 -> not used */
1076 /* start with all KEY_STORAGE_SOLVABLE ids */
1078 n = ID_NUM_INTERNAL;
1079 FOR_REPODATAS(repo, i, data)
1081 cbdata.keymap = solv_calloc(n, sizeof(Id));
1082 cbdata.keymapstart = solv_calloc(repo->nrepodata, sizeof(Id));
1083 repodataused = solv_calloc(repo->nrepodata, 1);
1088 /* add keys for STORAGE_SOLVABLE */
1089 for (i = SOLVABLE_NAME; i <= RPM_RPMDBID; i++)
1093 if (i < SOLVABLE_PROVIDES)
1094 keyd.type = REPOKEY_TYPE_ID;
1095 else if (i < RPM_RPMDBID)
1096 keyd.type = REPOKEY_TYPE_REL_IDARRAY;
1098 keyd.type = REPOKEY_TYPE_NUM;
1100 keyd.storage = KEY_STORAGE_SOLVABLE;
1103 keyd.storage = keyfilter(repo, &keyd, kfdata);
1104 if (keyd.storage == KEY_STORAGE_DROPPED)
1106 keyd.storage = KEY_STORAGE_SOLVABLE;
1110 cbdata.keymap[keyd.name] = repodata_key2id(&target, &keyd, 1);
1113 if (repo->nsolvables)
1116 keyd.name = REPOSITORY_SOLVABLES;
1117 keyd.type = REPOKEY_TYPE_FLEXARRAY;
1119 keyd.storage = KEY_STORAGE_INCORE;
1120 cbdata.keymap[keyd.name] = repodata_key2id(&target, &keyd, 1);
1128 n = ID_NUM_INTERNAL;
1129 FOR_REPODATAS(repo, i, data)
1131 cbdata.keymapstart[i] = n;
1132 cbdata.keymap[n++] = 0; /* key 0 */
1138 /* check if we want this repodata */
1139 memset(&keyd, 0, sizeof(keyd));
1143 if (keyfilter(repo, &keyd, kfdata) == -1)
1146 for (j = 1; j < data->nkeys; j++, n++)
1148 key = data->keys + j;
1149 if (key->name == REPOSITORY_SOLVABLES && key->type == REPOKEY_TYPE_FLEXARRAY)
1151 cbdata.keymap[n] = cbdata.keymap[key->name];
1154 if (key->type == REPOKEY_TYPE_DELETED)
1156 cbdata.keymap[n] = 0;
1159 if (key->type == REPOKEY_TYPE_CONSTANTID && data->localpool)
1161 Repokey keyd = *key;
1162 keyd.size = repodata_globalize_id(data, key->size, 1);
1163 id = repodata_key2id(&target, &keyd, 0);
1166 id = repodata_key2id(&target, key, 0);
1169 Repokey keyd = *key;
1170 keyd.storage = KEY_STORAGE_INCORE;
1171 if (keyd.type == REPOKEY_TYPE_CONSTANTID)
1172 keyd.size = repodata_globalize_id(data, key->size, 1);
1173 else if (keyd.type != REPOKEY_TYPE_CONSTANT)
1177 keyd.storage = keyfilter(repo, &keyd, kfdata);
1178 if (keyd.storage == KEY_STORAGE_DROPPED)
1180 cbdata.keymap[n] = 0;
1184 id = repodata_key2id(&target, &keyd, 1);
1186 cbdata.keymap[n] = id;
1187 /* load repodata if not already loaded */
1188 if (data->state == REPODATA_STUB)
1190 if (data->loadcallback)
1191 data->loadcallback(data);
1193 data->state = REPODATA_ERROR;
1194 if (data->state != REPODATA_ERROR)
1196 /* redo this repodata! */
1198 n = cbdata.keymapstart[i];
1202 if (data->state == REPODATA_ERROR)
1205 cbdata.keymap[n] = 0;
1209 repodataused[i] = 1;
1210 anyrepodataused = 1;
1211 if (key->type == REPOKEY_TYPE_CONSTANTID || key->type == REPOKEY_TYPE_ID ||
1212 key->type == REPOKEY_TYPE_IDARRAY || key->type == REPOKEY_TYPE_REL_IDARRAY)
1214 else if (key->type == REPOKEY_TYPE_DIR || key->type == REPOKEY_TYPE_DIRNUMNUMARRAY || key->type == REPOKEY_TYPE_DIRSTRARRAY)
1216 idused = 1; /* dirs also use ids */
1222 if (data->localpool)
1225 poolusage = 3; /* need own pool */
1229 spool = &data->spool;
1236 else if (poolusage != 1)
1237 poolusage = 3; /* need own pool */
1243 dirpoolusage = 3; /* need own dirpool */
1247 dirpool = &data->dirpool;
1254 /* 0: no pool needed at all */
1255 /* 1: use global pool */
1256 /* 2: use repodata local pool */
1257 /* 3: need own pool */
1260 spool = &target.spool;
1261 /* hack: reuse global pool data so we don't have to map pool ids */
1264 stringpool_free(spool);
1265 stringpool_clone(spool, &pool->ss);
1267 cbdata.ownspool = spool;
1269 else if (poolusage == 0 || poolusage == 1)
1275 if (dirpoolusage == 3)
1277 dirpool = &target.dirpool;
1279 cbdata.owndirpool = dirpool;
1282 cbdata.dirused = solv_calloc(dirpool->ndirs, sizeof(Id));
1285 /********************************************************************/
1287 fprintf(stderr, "poolusage: %d\n", poolusage);
1288 fprintf(stderr, "dirpoolusage: %d\n", dirpoolusage);
1289 fprintf(stderr, "nkeys: %d\n", target.nkeys);
1290 for (i = 1; i < target.nkeys; i++)
1291 fprintf(stderr, " %2d: %s[%d] %d %d %d\n", i, pool_id2str(pool, target.keys[i].name), target.keys[i].name, target.keys[i].type, target.keys[i].size, target.keys[i].storage);
1294 /* copy keys if requested */
1298 for (i = 1; i < target.nkeys; i++)
1299 queue_push2(keyq, target.keys[i].name, target.keys[i].type);
1304 /* put all the keys we need in our string pool */
1305 /* put mapped ids right into target.keys */
1306 for (i = 1, key = target.keys + i; i < target.nkeys; i++, key++)
1308 key->name = stringpool_str2id(spool, pool_id2str(pool, key->name), 1);
1309 if (key->type == REPOKEY_TYPE_CONSTANTID)
1311 key->type = stringpool_str2id(spool, pool_id2str(pool, key->type), 1);
1312 type_constantid = key->type;
1313 key->size = stringpool_str2id(spool, pool_id2str(pool, key->size), 1);
1316 key->type = stringpool_str2id(spool, pool_id2str(pool, key->type), 1);
1319 stringpool_freehash(spool); /* free some mem */
1323 /********************************************************************/
1325 /* set needed count of all strings and rels,
1326 * find which keys are used in the solvables
1327 * put all strings in own spool
1330 reloff = spool->nstrings;
1332 reloff = (reloff + NEEDED_BLOCK) & ~NEEDED_BLOCK;
1334 needid = calloc(reloff + pool->nrels, sizeof(*needid));
1335 needid[0].map = reloff;
1337 cbdata.needid = needid;
1338 cbdata.schema = solv_calloc(target.nkeys, sizeof(Id));
1339 cbdata.sp = cbdata.schema;
1340 cbdata.solvschemata = solv_calloc(repo->nsolvables, sizeof(Id));
1342 /* create main schema */
1343 cbdata.sp = cbdata.schema;
1344 /* collect all other data from all repodatas */
1345 /* XXX: merge arrays of equal keys? */
1346 FOR_REPODATAS(repo, j, data)
1348 if (!repodataused[j])
1350 repodata_search(data, SOLVID_META, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_needed, &cbdata);
1353 /* add solvables if needed (may revert later) */
1354 if (repo->nsolvables)
1356 *sp++ = cbdata.keymap[REPOSITORY_SOLVABLES];
1357 target.keys[cbdata.keymap[REPOSITORY_SOLVABLES]].size++;
1360 mainschema = repodata_schema2id(cbdata.target, cbdata.schema, 1);
1362 idarraydata = repo->idarraydata;
1364 anysolvableused = 0;
1365 cbdata.doingsolvables = 1;
1366 for (i = repo->start, s = pool->solvables + i, n = 0; i < repo->end; i++, s++)
1368 if (s->repo != repo)
1371 /* set schema info, keep in sync with further down */
1373 if (cbdata.keymap[SOLVABLE_NAME])
1375 *sp++ = cbdata.keymap[SOLVABLE_NAME];
1376 needid[s->name].need++;
1378 if (cbdata.keymap[SOLVABLE_ARCH])
1380 *sp++ = cbdata.keymap[SOLVABLE_ARCH];
1381 needid[s->arch].need++;
1383 if (cbdata.keymap[SOLVABLE_EVR])
1385 *sp++ = cbdata.keymap[SOLVABLE_EVR];
1386 needid[s->evr].need++;
1388 if (s->vendor && cbdata.keymap[SOLVABLE_VENDOR])
1390 *sp++ = cbdata.keymap[SOLVABLE_VENDOR];
1391 needid[s->vendor].need++;
1393 if (s->provides && cbdata.keymap[SOLVABLE_PROVIDES])
1395 *sp++ = cbdata.keymap[SOLVABLE_PROVIDES];
1396 target.keys[cbdata.keymap[SOLVABLE_PROVIDES]].size += incneedidarray(pool, idarraydata + s->provides, needid);
1398 if (s->obsoletes && cbdata.keymap[SOLVABLE_OBSOLETES])
1400 *sp++ = cbdata.keymap[SOLVABLE_OBSOLETES];
1401 target.keys[cbdata.keymap[SOLVABLE_OBSOLETES]].size += incneedidarray(pool, idarraydata + s->obsoletes, needid);
1403 if (s->conflicts && cbdata.keymap[SOLVABLE_CONFLICTS])
1405 *sp++ = cbdata.keymap[SOLVABLE_CONFLICTS];
1406 target.keys[cbdata.keymap[SOLVABLE_CONFLICTS]].size += incneedidarray(pool, idarraydata + s->conflicts, needid);
1408 if (s->requires && cbdata.keymap[SOLVABLE_REQUIRES])
1410 *sp++ = cbdata.keymap[SOLVABLE_REQUIRES];
1411 target.keys[cbdata.keymap[SOLVABLE_REQUIRES]].size += incneedidarray(pool, idarraydata + s->requires, needid);
1413 if (s->recommends && cbdata.keymap[SOLVABLE_RECOMMENDS])
1415 *sp++ = cbdata.keymap[SOLVABLE_RECOMMENDS];
1416 target.keys[cbdata.keymap[SOLVABLE_RECOMMENDS]].size += incneedidarray(pool, idarraydata + s->recommends, needid);
1418 if (s->suggests && cbdata.keymap[SOLVABLE_SUGGESTS])
1420 *sp++ = cbdata.keymap[SOLVABLE_SUGGESTS];
1421 target.keys[cbdata.keymap[SOLVABLE_SUGGESTS]].size += incneedidarray(pool, idarraydata + s->suggests, needid);
1423 if (s->supplements && cbdata.keymap[SOLVABLE_SUPPLEMENTS])
1425 *sp++ = cbdata.keymap[SOLVABLE_SUPPLEMENTS];
1426 target.keys[cbdata.keymap[SOLVABLE_SUPPLEMENTS]].size += incneedidarray(pool, idarraydata + s->supplements, needid);
1428 if (s->enhances && cbdata.keymap[SOLVABLE_ENHANCES])
1430 *sp++ = cbdata.keymap[SOLVABLE_ENHANCES];
1431 target.keys[cbdata.keymap[SOLVABLE_ENHANCES]].size += incneedidarray(pool, idarraydata + s->enhances, needid);
1433 if (repo->rpmdbid && cbdata.keymap[RPM_RPMDBID])
1435 *sp++ = cbdata.keymap[RPM_RPMDBID];
1436 target.keys[cbdata.keymap[RPM_RPMDBID]].size++;
1440 if (anyrepodataused)
1442 FOR_REPODATAS(repo, j, data)
1444 if (!repodataused[j])
1446 if (i < data->start || i >= data->end)
1448 repodata_search(data, i, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_needed, &cbdata);
1449 needid = cbdata.needid;
1453 cbdata.solvschemata[n] = repodata_schema2id(cbdata.target, cbdata.schema, 1);
1454 if (cbdata.solvschemata[n])
1455 anysolvableused = 1;
1458 cbdata.doingsolvables = 0;
1459 assert(n == repo->nsolvables);
1461 if (repo->nsolvables && !anysolvableused)
1463 /* strip off solvable from the main schema */
1464 target.keys[cbdata.keymap[REPOSITORY_SOLVABLES]].size = 0;
1466 for (i = 0; target.schemadata[target.schemata[mainschema] + i]; i++)
1468 *sp = target.schemadata[target.schemata[mainschema] + i];
1469 if (*sp != cbdata.keymap[REPOSITORY_SOLVABLES])
1472 assert(target.schemadatalen == target.schemata[mainschema] + i + 1);
1474 target.schemadatalen = target.schemata[mainschema];
1476 repodata_free_schemahash(&target);
1477 mainschema = repodata_schema2id(cbdata.target, cbdata.schema, 1);
1480 /********************************************************************/
1482 /* remove unused keys */
1483 keyused = solv_calloc(target.nkeys, sizeof(Id));
1484 for (i = 1; i < target.schemadatalen; i++)
1485 keyused[target.schemadata[i]] = 1;
1487 for (n = i = 1; i < target.nkeys; i++)
1494 target.keys[n] = target.keys[i];
1497 keyq->elements[2 * n - 2] = keyq->elements[2 * i - 2];
1498 keyq->elements[2 * n - 1] = keyq->elements[2 * i - 1];
1505 queue_truncate(keyq, 2 * n - 2);
1507 /* update schema data to the new key ids */
1508 for (i = 1; i < target.schemadatalen; i++)
1509 target.schemadata[i] = keyused[target.schemadata[i]];
1510 /* update keymap to the new key ids */
1511 for (i = 0; i < cbdata.nkeymap; i++)
1512 cbdata.keymap[i] = keyused[cbdata.keymap[i]];
1513 keyused = solv_free(keyused);
1515 /* increment needid of the used keys, they are already mapped to
1516 * the correct string pool */
1517 for (i = 1; i < target.nkeys; i++)
1519 if (target.keys[i].type == type_constantid)
1520 needid[target.keys[i].size].need++;
1521 needid[target.keys[i].name].need++;
1522 needid[target.keys[i].type].need++;
1525 /********************************************************************/
1527 if (dirpool && cbdata.dirused && !cbdata.dirused[0])
1529 /* no dirs used at all */
1530 cbdata.dirused = solv_free(cbdata.dirused);
1534 /* increment need id for used dir components */
1537 /* if we have own dirpool, all entries in it are used.
1538 also, all comp ids are already mapped by putinowndirpool(),
1539 so we can simply increment needid.
1540 (owndirpool != 0, dirused == 0, dirpooldata == 0) */
1541 /* else we re-use a dirpool of repodata "dirpooldata".
1542 dirused tells us which of the ids are used.
1543 we need to map comp ids if we generate a new pool.
1544 (owndirpool == 0, dirused != 0, dirpooldata != 0) */
1545 for (i = 1; i < dirpool->ndirs; i++)
1548 fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1);
1550 if (cbdata.dirused && !cbdata.dirused[i])
1552 id = dirpool->dirs[i];
1555 if (dirpooldata && cbdata.ownspool && id > 1)
1557 id = putinownpool(&cbdata, dirpooldata->localpool ? &dirpooldata->spool : &pool->ss, id);
1558 needid = cbdata.needid;
1565 /********************************************************************/
1568 * create mapping table, new keys are sorted by needid[].need
1570 * needid[key].need : old key -> new key
1571 * needid[key].map : new key -> old key
1574 /* zero out id 0 and rel 0 just in case */
1575 reloff = needid[0].map;
1577 needid[reloff].need = 0;
1579 for (i = 1; i < reloff + pool->nrels; i++)
1583 solv_sort(needid + 1, spool->nstrings - 1, sizeof(*needid), needid_cmp_need_s, spool);
1585 /* make first entry '' */
1587 solv_sort(needid + 2, spool->nstrings - 2, sizeof(*needid), needid_cmp_need_s, spool);
1589 solv_sort(needid + reloff, pool->nrels, sizeof(*needid), needid_cmp_need, 0);
1590 /* now needid is in new order, needid[newid].map -> oldid */
1592 /* calculate string space size, also zero out needid[].need */
1594 for (i = 1; i < reloff; i++)
1596 if (!needid[i].need)
1597 break; /* as we have sorted, every entry after this also has need == 0 */
1599 sizeid += strlen(spool->stringspace + spool->strings[needid[i].map]) + 1;
1601 nstrings = i; /* our new string id end */
1603 /* make needid[oldid].need point to newid */
1604 for (i = 1; i < nstrings; i++)
1605 needid[needid[i].map].need = i;
1607 /* same as above for relations */
1608 for (i = 0; i < pool->nrels; i++)
1610 if (!needid[reloff + i].need)
1612 needid[reloff + i].need = 0;
1614 nrels = i; /* our new rel id end */
1616 for (i = 0; i < nrels; i++)
1617 needid[needid[reloff + i].map].need = nstrings + i;
1619 /* now we have: needid[oldid].need -> newid
1620 needid[newid].map -> oldid
1621 both for strings and relations */
1624 /********************************************************************/
1630 /* create our new target directory structure by traversing through all
1631 * used dirs. This will concatenate blocks with the same parent
1632 * directory into single blocks.
1633 * Instead of components, traverse_dirs stores the old dirids,
1634 * we will change this in the second step below */
1635 /* (dirpooldata and dirused are 0 if we have our own dirpool) */
1636 if (cbdata.dirused && !cbdata.dirused[1])
1637 cbdata.dirused[1] = 1; /* always want / entry */
1638 dirmap = solv_calloc(dirpool->ndirs, sizeof(Id));
1640 ndirmap = traverse_dirs(dirpool, dirmap, 1, dirpool_child(dirpool, 0), cbdata.dirused);
1642 /* (re)create dirused, so that it maps from "old dirid" to "new dirid" */
1643 /* change dirmap so that it maps from "new dirid" to "new compid" */
1644 if (!cbdata.dirused)
1645 cbdata.dirused = solv_malloc2(dirpool->ndirs, sizeof(Id));
1646 memset(cbdata.dirused, 0, dirpool->ndirs * sizeof(Id));
1647 for (i = 1; i < ndirmap; i++)
1651 cbdata.dirused[dirmap[i]] = i;
1652 id = dirpool->dirs[dirmap[i]];
1653 if (dirpooldata && cbdata.ownspool && id > 1)
1654 id = putinownpool(&cbdata, dirpooldata->localpool ? &dirpooldata->spool : &pool->ss, id);
1655 dirmap[i] = needid[id].need;
1657 /* now the new target directory structure is complete (dirmap), and we have
1658 * dirused[olddirid] -> newdirid */
1661 /********************************************************************/
1664 * we use extdata[0] for incore data and extdata[keyid] for vertical data
1667 cbdata.extdata = solv_calloc(target.nkeys, sizeof(struct extdata));
1669 xd = cbdata.extdata;
1670 cbdata.current_sub = 0;
1671 /* add main schema */
1673 data_addid(xd, mainschema);
1676 FOR_REPODATAS(repo, j, data)
1678 if (!repodataused[j])
1680 repodata_search(data, SOLVID_META, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_adddata, &cbdata);
1684 if (xd->len - cbdata.lastlen > cbdata.maxdata)
1685 cbdata.maxdata = xd->len - cbdata.lastlen;
1686 cbdata.lastlen = xd->len;
1688 if (anysolvableused)
1690 data_addid(xd, repo->nsolvables); /* FLEXARRAY nentries */
1691 cbdata.doingsolvables = 1;
1692 for (i = repo->start, s = pool->solvables + i, n = 0; i < repo->end; i++, s++)
1694 if (s->repo != repo)
1696 data_addid(xd, cbdata.solvschemata[n]);
1697 if (cbdata.keymap[SOLVABLE_NAME])
1698 data_addid(xd, needid[s->name].need);
1699 if (cbdata.keymap[SOLVABLE_ARCH])
1700 data_addid(xd, needid[s->arch].need);
1701 if (cbdata.keymap[SOLVABLE_EVR])
1702 data_addid(xd, needid[s->evr].need);
1703 if (s->vendor && cbdata.keymap[SOLVABLE_VENDOR])
1704 data_addid(xd, needid[s->vendor].need);
1705 if (s->provides && cbdata.keymap[SOLVABLE_PROVIDES])
1706 data_addidarray_sort(xd, pool, needid, idarraydata + s->provides, SOLVABLE_FILEMARKER);
1707 if (s->obsoletes && cbdata.keymap[SOLVABLE_OBSOLETES])
1708 data_addidarray_sort(xd, pool, needid, idarraydata + s->obsoletes, 0);
1709 if (s->conflicts && cbdata.keymap[SOLVABLE_CONFLICTS])
1710 data_addidarray_sort(xd, pool, needid, idarraydata + s->conflicts, 0);
1711 if (s->requires && cbdata.keymap[SOLVABLE_REQUIRES])
1712 data_addidarray_sort(xd, pool, needid, idarraydata + s->requires, SOLVABLE_PREREQMARKER);
1713 if (s->recommends && cbdata.keymap[SOLVABLE_RECOMMENDS])
1714 data_addidarray_sort(xd, pool, needid, idarraydata + s->recommends, 0);
1715 if (s->suggests && cbdata.keymap[SOLVABLE_SUGGESTS])
1716 data_addidarray_sort(xd, pool, needid, idarraydata + s->suggests, 0);
1717 if (s->supplements && cbdata.keymap[SOLVABLE_SUPPLEMENTS])
1718 data_addidarray_sort(xd, pool, needid, idarraydata + s->supplements, 0);
1719 if (s->enhances && cbdata.keymap[SOLVABLE_ENHANCES])
1720 data_addidarray_sort(xd, pool, needid, idarraydata + s->enhances, 0);
1721 if (repo->rpmdbid && cbdata.keymap[RPM_RPMDBID])
1722 data_addid(xd, repo->rpmdbid[i - repo->start]);
1723 if (anyrepodataused)
1726 FOR_REPODATAS(repo, j, data)
1728 if (!repodataused[j])
1730 if (i < data->start || i >= data->end)
1732 repodata_search(data, i, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_adddata, &cbdata);
1735 if (xd->len - cbdata.lastlen > cbdata.maxdata)
1736 cbdata.maxdata = xd->len - cbdata.lastlen;
1737 cbdata.lastlen = xd->len;
1740 cbdata.doingsolvables = 0;
1743 assert(cbdata.current_sub == cbdata.nsubschemata);
1744 if (cbdata.subschemata)
1746 cbdata.subschemata = solv_free(cbdata.subschemata);
1747 cbdata.nsubschemata = 0;
1750 /********************************************************************/
1756 /* write file header */
1757 write_u32(&target, 'S' << 24 | 'O' << 16 | 'L' << 8 | 'V');
1758 write_u32(&target, SOLV_VERSION_8);
1762 write_u32(&target, nstrings);
1763 write_u32(&target, nrels);
1764 write_u32(&target, ndirmap);
1765 write_u32(&target, anysolvableused ? repo->nsolvables : 0);
1766 write_u32(&target, target.nkeys);
1767 write_u32(&target, target.nschemata);
1769 solv_flags |= SOLV_FLAG_PREFIX_POOL;
1770 solv_flags |= SOLV_FLAG_SIZE_BYTES;
1771 write_u32(&target, solv_flags);
1774 * calculate prefix encoding of the strings
1776 prefixcomp = solv_malloc(nstrings);
1781 for (i = 1; i < nstrings; i++)
1783 char *str = spool->stringspace + spool->strings[needid[i].map];
1785 for (same = 0; same < 255; same++)
1786 if (!old_str[same] || old_str[same] != str[same])
1788 prefixcomp[i] = same;
1796 write_u32(&target, sizeid);
1797 /* we save compsum bytes but need 1 extra byte for every string */
1798 write_u32(&target, sizeid + (nstrings ? nstrings - 1 : 0) - compsum);
1799 if (sizeid + (nstrings ? nstrings - 1 : 0) != compsum)
1801 for (i = 1; i < nstrings; i++)
1803 char *str = spool->stringspace + spool->strings[needid[i].map];
1804 write_u8(&target, prefixcomp[i]);
1805 write_str(&target, str + prefixcomp[i]);
1808 solv_free(prefixcomp);
1811 /* Build the prefix-encoding of the string pool. We need to know
1812 the size of that before writing it to the file, so we have to
1813 build a separate buffer for that. As it's temporarily possible
1814 that this actually is an expansion we can't easily reuse the
1815 stringspace for this. The max expansion per string is 1 byte,
1816 so it will fit into sizeid+nstrings bytes. */
1817 char *prefix = solv_malloc(sizeid + nstrings);
1820 for (i = 1; i < nstrings; i++)
1822 char *str = spool->stringspace + spool->strings[needid[i].map];
1825 for (same = 0; same < 255; same++)
1826 if (!old_str[same] || !str[same] || old_str[same] != str[same])
1829 len = strlen(str + same) + 1;
1830 memcpy(pp, str + same, len);
1838 write_u32(&target, sizeid);
1839 write_u32(&target, pp - prefix);
1840 write_blob(&target, prefix, pp - prefix);
1847 for (i = 0; i < nrels; i++)
1849 ran = pool->rels + (needid[reloff + i].map - reloff);
1850 write_id(&target, needid[ISRELDEP(ran->name) ? RELOFF(ran->name) : ran->name].need);
1851 write_id(&target, needid[ISRELDEP(ran->evr) ? RELOFF(ran->evr) : ran->evr].need);
1852 write_u8(&target, ran->flags);
1856 * write dirs (skip both root and / entry)
1858 for (i = 2; i < ndirmap; i++)
1861 write_id(&target, dirmap[i]);
1863 write_id(&target, nstrings - dirmap[i]);
1870 for (i = 1; i < target.nkeys; i++)
1872 write_id(&target, needid[target.keys[i].name].need);
1873 write_id(&target, needid[target.keys[i].type].need);
1874 if (target.keys[i].storage != KEY_STORAGE_VERTICAL_OFFSET)
1876 if (target.keys[i].type == type_constantid)
1877 write_id(&target, needid[target.keys[i].size].need);
1879 write_id(&target, target.keys[i].size);
1882 write_id(&target, cbdata.extdata[i].len);
1883 write_id(&target, target.keys[i].storage);
1889 write_id(&target, target.schemadatalen); /* XXX -1? */
1890 for (i = 1; i < target.nschemata; i++)
1891 write_idarray(&target, pool, 0, repodata_id2schema(&target, i));
1893 /********************************************************************/
1895 write_id(&target, cbdata.maxdata);
1896 write_id(&target, cbdata.extdata[0].len);
1897 if (cbdata.extdata[0].len)
1898 write_blob(&target, cbdata.extdata[0].buf, cbdata.extdata[0].len);
1899 solv_free(cbdata.extdata[0].buf);
1901 /* do we have vertical data? */
1902 for (i = 1; i < target.nkeys; i++)
1903 if (cbdata.extdata[i].len)
1905 if (i < target.nkeys)
1907 /* yes, write it in pages */
1908 unsigned char *dp, vpage[REPOPAGE_BLOBSIZE];
1909 int l, ll, lpage = 0;
1911 write_u32(&target, REPOPAGE_BLOBSIZE);
1912 for (i = 1; i < target.nkeys; i++)
1914 if (!cbdata.extdata[i].len)
1916 l = cbdata.extdata[i].len;
1917 dp = cbdata.extdata[i].buf;
1920 ll = REPOPAGE_BLOBSIZE - lpage;
1923 memcpy(vpage + lpage, dp, ll);
1927 if (lpage == REPOPAGE_BLOBSIZE)
1929 write_compressed_page(&target, vpage, lpage);
1935 write_compressed_page(&target, vpage, lpage);
1938 for (i = 1; i < target.nkeys; i++)
1939 solv_free(cbdata.extdata[i].buf);
1940 solv_free(cbdata.extdata);
1943 repodata_freedata(&target);
1946 solv_free(cbdata.solvschemata);
1947 solv_free(cbdata.schema);
1949 solv_free(cbdata.keymap);
1950 solv_free(cbdata.keymapstart);
1951 solv_free(cbdata.dirused);
1952 solv_free(repodataused);
1953 return target.error;
1956 struct repodata_write_data {
1957 int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata);
1963 repodata_write_keyfilter(Repo *repo, Repokey *key, void *kfdata)
1965 struct repodata_write_data *wd = kfdata;
1967 /* XXX: special repodata selection hack */
1968 if (key->name == 1 && key->size != wd->repodataid)
1970 if (key->storage == KEY_STORAGE_SOLVABLE)
1971 return KEY_STORAGE_DROPPED; /* not part of this repodata */
1973 return (*wd->keyfilter)(repo, key, wd->kfdata);
1974 return key->storage;
1978 repodata_write_filtered(Repodata *data, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq)
1980 struct repodata_write_data wd;
1982 wd.keyfilter = keyfilter;
1984 wd.repodataid = data->repodataid;
1985 return repo_write_filtered(data->repo, fp, repodata_write_keyfilter, &wd, keyq);
1989 repodata_write(Repodata *data, FILE *fp)
1991 return repodata_write_filtered(data, fp, repo_write_stdkeyfilter, 0, 0);
1995 repo_write(Repo *repo, FILE *fp)
1997 return repo_write_filtered(repo, fp, repo_write_stdkeyfilter, 0, 0);