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>
28 #include "repo_write.h"
31 /*------------------------------------------------------------------*/
32 /* Id map optimizations */
34 typedef struct needid {
40 #define RELOFF(id) (needid[0].map + GETRELID(id))
44 * idarray: array of Ids, ID_NULL terminated
45 * needid: array of Id->NeedId
47 * return size of array (including trailing zero)
52 incneedid(Pool *pool, Id id, NeedId *needid)
56 Reldep *rd = GETRELDEP(pool, id);
57 needid[RELOFF(id)].need++;
58 if (ISRELDEP(rd->evr))
59 incneedid(pool, rd->evr, needid);
61 needid[rd->evr].need++;
68 incneedidarray(Pool *pool, Id *idarray, NeedId *needid)
75 while ((id = *idarray++) != 0)
80 Reldep *rd = GETRELDEP(pool, id);
81 needid[RELOFF(id)].need++;
82 if (ISRELDEP(rd->evr))
83 incneedid(pool, rd->evr, needid);
85 needid[rd->evr].need++;
99 needid_cmp_need(const void *ap, const void *bp, void *dp)
101 const NeedId *a = ap;
102 const NeedId *b = bp;
104 r = b->need - a->need;
107 return a->map - b->map;
111 needid_cmp_need_s(const void *ap, const void *bp, void *dp)
113 const NeedId *a = ap;
114 const NeedId *b = bp;
115 Stringpool *spool = dp;
120 r = b->need - a->need;
123 as = spool->stringspace + spool->strings[a->map];
124 bs = spool->stringspace + spool->strings[b->map];
125 return strcmp(as, bs);
129 /*------------------------------------------------------------------*/
130 /* output helper routines, used for writing the header */
131 /* (the data itself is accumulated in memory and written with
139 write_u32(FILE *fp, unsigned int x)
141 if (putc(x >> 24, fp) == EOF ||
142 putc(x >> 16, fp) == EOF ||
143 putc(x >> 8, fp) == EOF ||
146 perror("write error u32");
157 write_u8(FILE *fp, unsigned int x)
159 if (putc(x, fp) == EOF)
161 perror("write error u8");
171 write_blob(FILE *fp, void *data, int len)
173 if (len && fwrite(data, len, 1, fp) != 1)
175 perror("write error blob");
185 write_id(FILE *fp, Id x)
190 putc((x >> 28) | 128, fp);
192 putc((x >> 21) | 128, fp);
193 putc((x >> 14) | 128, fp);
196 putc((x >> 7) | 128, fp);
197 if (putc(x & 127, fp) == EOF)
199 perror("write error id");
205 write_id_eof(FILE *fp, Id x, int eof)
208 x = (x & 63) | ((x & ~63) << 1);
209 write_id(fp, x | (eof ? 0 : 64));
215 write_str(FILE *fp, const char *str)
217 if (fputs(str, fp) == EOF || putc(0, fp) == EOF)
219 perror("write error str");
229 write_idarray(FILE *fp, Pool *pool, NeedId *needid, Id *ids)
243 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
245 id = (id & 63) | ((id & ~63) << 1);
251 write_id(fp, id | 64);
256 cmp_ids(const void *pa, const void *pb, void *dp)
265 write_idarray_sort(FILE *fp, Pool *pool, NeedId *needid, Id *ids, Id marker)
277 for (len = 0; len < 64 && ids[len]; len++)
281 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
286 for (i = len + 1; ids[i]; i++)
288 sids = solv_malloc2(i, sizeof(Id));
289 memcpy(sids, lids, 64 * sizeof(Id));
290 for (; ids[len]; len++)
294 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
301 /* That bloody solvable:prereqmarker needs to stay in position :-( */
303 marker = needid[marker].need;
304 for (i = 0; i < len; i++)
305 if (sids[i] == marker)
308 solv_sort(sids, i, sizeof(Id), cmp_ids, 0);
310 solv_sort(sids + i + 1, len - i - 1, sizeof(Id), cmp_ids, 0);
314 /* The differencing above produces many runs of ones and twos. I tried
315 fairly elaborate schemes to RLE those, but they give only very mediocre
316 improvements in compression, as coding the escapes costs quite some
317 space. Even if they are coded only as bits in IDs. The best improvement
318 was about 2.7% for the whole .solv file. It's probably better to
319 invest some complexity into sharing idarrays, than RLEing. */
320 for (i = 0; i < len - 1; i++)
323 /* Ugly PREREQ handling. A "difference" of 0 is the prereq marker,
324 hence all real differences are offsetted by 1. Otherwise we would
325 have to handle negative differences, which would cost code space for
326 the encoding of the sign. We loose the exact mapping of prereq here,
327 but we know the result, so we can recover from that in the reader. */
335 /* XXX If difference is zero we have multiple equal elements,
336 we might want to skip writing them out. */
338 id = (id & 63) | ((id & ~63) << 1);
339 write_id(fp, id | 64);
347 id = (id & 63) | ((id & ~63) << 1);
364 Stringpool *ownspool;
373 Id *schema; /* schema construction space */
374 Id *sp; /* pointer in above */
375 Id *oldschema, *oldsp;
382 struct extdata *extdata;
391 int doingsolvables; /* working on solvables data */
394 #define NEEDED_BLOCK 1023
395 #define SCHEMATA_BLOCK 31
396 #define SCHEMATADATA_BLOCK 255
397 #define EXTDATA_BLOCK 4095
400 data_addid(struct extdata *xd, Id sx)
402 unsigned int x = (unsigned int)sx;
404 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
405 dp = xd->buf + xd->len;
410 *dp++ = (x >> 28) | 128;
412 *dp++ = (x >> 21) | 128;
413 *dp++ = (x >> 14) | 128;
416 *dp++ = (x >> 7) | 128;
418 xd->len = dp - xd->buf;
422 data_addideof(struct extdata *xd, Id x, int eof)
425 x = (x & 63) | ((x & ~63) << 1);
426 data_addid(xd, (eof ? x: x | 64));
430 data_addidarray_sort(struct extdata *xd, Pool *pool, NeedId *needid, Id *ids, Id marker)
443 for (len = 0; len < 64 && ids[len]; len++)
447 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
452 for (i = len + 1; ids[i]; i++)
454 sids = solv_malloc2(i, sizeof(Id));
455 memcpy(sids, lids, 64 * sizeof(Id));
456 for (; ids[len]; len++)
460 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
467 /* That bloody solvable:prereqmarker needs to stay in position :-( */
469 marker = needid[marker].need;
470 for (i = 0; i < len; i++)
471 if (sids[i] == marker)
474 solv_sort(sids, i, sizeof(Id), cmp_ids, 0);
476 solv_sort(sids + i + 1, len - i - 1, sizeof(Id), cmp_ids, 0);
480 /* The differencing above produces many runs of ones and twos. I tried
481 fairly elaborate schemes to RLE those, but they give only very mediocre
482 improvements in compression, as coding the escapes costs quite some
483 space. Even if they are coded only as bits in IDs. The best improvement
484 was about 2.7% for the whole .solv file. It's probably better to
485 invest some complexity into sharing idarrays, than RLEing. */
486 for (i = 0; i < len - 1; i++)
489 /* Ugly PREREQ handling. A "difference" of 0 is the prereq marker,
490 hence all real differences are offsetted by 1. Otherwise we would
491 have to handle negative differences, which would cost code space for
492 the encoding of the sign. We loose the exact mapping of prereq here,
493 but we know the result, so we can recover from that in the reader. */
501 /* XXX If difference is zero we have multiple equal elements,
502 we might want to skip writing them out. */
504 id = (id & 63) | ((id & ~63) << 1);
505 data_addid(xd, id | 64);
513 id = (id & 63) | ((id & ~63) << 1);
520 data_addblob(struct extdata *xd, unsigned char *blob, int len)
522 xd->buf = solv_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
523 memcpy(xd->buf + xd->len, blob, len);
528 data_addu32(struct extdata *xd, unsigned int num)
535 data_addblob(xd, d, 4);
539 putinownpool(struct cbdata *cbdata, Stringpool *ss, Id id)
541 const char *str = stringpool_id2str(ss, id);
542 id = stringpool_str2id(cbdata->ownspool, str, 1);
543 if (id >= cbdata->needid[0].map)
545 int oldoff = cbdata->needid[0].map;
546 int newoff = (id + 1 + NEEDED_BLOCK) & ~NEEDED_BLOCK;
547 int nrels = cbdata->repo->pool->nrels;
548 cbdata->needid = solv_realloc2(cbdata->needid, newoff + nrels, sizeof(NeedId));
550 memmove(cbdata->needid + newoff, cbdata->needid + oldoff, nrels * sizeof(NeedId));
551 memset(cbdata->needid + oldoff, 0, (newoff - oldoff) * sizeof(NeedId));
552 cbdata->needid[0].map = newoff;
558 putinowndirpool(struct cbdata *cbdata, Repodata *data, Dirpool *dp, Id dir)
562 parent = dirpool_parent(dp, dir);
564 parent = putinowndirpool(cbdata, data, dp, parent);
565 compid = dp->dirs[dir];
566 if (cbdata->ownspool && compid > 1)
567 compid = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, compid);
568 return dirpool_add_dir(cbdata->owndirpool, parent, compid, 1);
572 * collect usage information about the dirs
573 * 1: dir used, no child of dir used
574 * 2: dir used as parent of another used dir
577 setdirused(struct cbdata *cbdata, Dirpool *dp, Id dir)
579 if (cbdata->dirused[dir])
581 cbdata->dirused[dir] = 1;
582 while ((dir = dirpool_parent(dp, dir)) != 0)
584 if (cbdata->dirused[dir] == 2)
586 if (cbdata->dirused[dir])
588 cbdata->dirused[dir] = 2;
591 cbdata->dirused[dir] = 2;
593 cbdata->dirused[0] = 2;
598 * collect key/id/dirid usage information, create needed schemas
601 repo_write_collect_needed(struct cbdata *cbdata, Repo *repo, Repodata *data, Repokey *key, KeyValue *kv)
606 if (key->name == REPOSITORY_SOLVABLES)
607 return SEARCH_NEXT_KEY; /* we do not want this one */
609 /* hack: ignore some keys, see BUGS */
610 if (data->repodataid != data->repo->nrepodata - 1)
611 if (key->name == REPOSITORY_ADDEDFILEPROVIDES || key->name == REPOSITORY_EXTERNAL || key->name == REPOSITORY_LOCATION || key->name == REPOSITORY_KEYS || key->name == REPOSITORY_TOOLVERSION)
612 return SEARCH_NEXT_KEY;
614 rm = cbdata->keymap[cbdata->keymapstart[data->repodataid] + (key - data->keys)];
616 return SEARCH_NEXT_KEY; /* we do not want this one */
618 /* record key in schema */
619 if ((key->type != REPOKEY_TYPE_FIXARRAY || kv->eof == 0)
620 && (cbdata->sp == cbdata->schema || cbdata->sp[-1] != rm))
625 case REPOKEY_TYPE_ID:
626 case REPOKEY_TYPE_IDARRAY:
628 if (!ISRELDEP(id) && cbdata->ownspool && id > 1)
629 id = putinownpool(cbdata, data->localpool ? &data->spool : &repo->pool->ss, id);
630 incneedid(repo->pool, id, cbdata->needid);
632 case REPOKEY_TYPE_DIR:
633 case REPOKEY_TYPE_DIRNUMNUMARRAY:
634 case REPOKEY_TYPE_DIRSTRARRAY:
636 if (cbdata->owndirpool)
637 putinowndirpool(cbdata, data, &data->dirpool, id);
639 setdirused(cbdata, &data->dirpool, id);
641 case REPOKEY_TYPE_FIXARRAY:
644 if (cbdata->oldschema)
646 fprintf(stderr, "nested structs not yet implemented\n");
649 cbdata->oldschema = cbdata->schema;
650 cbdata->oldsp = cbdata->sp;
651 cbdata->schema = solv_calloc(cbdata->target->nkeys, sizeof(Id));
652 cbdata->sp = cbdata->schema;
654 else if (kv->eof == 1)
656 cbdata->current_sub++;
658 cbdata->subschemata = solv_extend(cbdata->subschemata, cbdata->nsubschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
659 cbdata->subschemata[cbdata->nsubschemata++] = repodata_schema2id(cbdata->target, cbdata->schema, 1);
661 fprintf(stderr, "Have schema %d\n", cbdata->subschemata[cbdata->nsubschemata-1]);
663 cbdata->sp = cbdata->schema;
667 solv_free(cbdata->schema);
668 cbdata->schema = cbdata->oldschema;
669 cbdata->sp = cbdata->oldsp;
670 cbdata->oldsp = cbdata->oldschema = 0;
673 case REPOKEY_TYPE_FLEXARRAY:
677 *cbdata->sp++ = 0; /* mark start */
681 /* just finished a schema, rewind */
682 Id *sp = cbdata->sp - 1;
686 cbdata->subschemata = solv_extend(cbdata->subschemata, cbdata->nsubschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
687 cbdata->subschemata[cbdata->nsubschemata++] = repodata_schema2id(cbdata->target, sp, 1);
688 cbdata->sp = kv->eof == 2 ? sp - 1: sp;
698 repo_write_cb_needed(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
700 struct cbdata *cbdata = vcbdata;
701 Repo *repo = data->repo;
705 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);
707 return repo_write_collect_needed(cbdata, repo, data, key, kv);
713 * encode all of the data into the correct buffers
717 repo_write_adddata(struct cbdata *cbdata, Repodata *data, Repokey *key, KeyValue *kv)
726 if (key->name == REPOSITORY_SOLVABLES)
727 return SEARCH_NEXT_KEY;
729 /* hack: ignore some keys, see BUGS */
730 if (data->repodataid != data->repo->nrepodata - 1)
731 if (key->name == REPOSITORY_ADDEDFILEPROVIDES || key->name == REPOSITORY_EXTERNAL || key->name == REPOSITORY_LOCATION || key->name == REPOSITORY_KEYS || key->name == REPOSITORY_TOOLVERSION)
732 return SEARCH_NEXT_KEY;
734 rm = cbdata->keymap[cbdata->keymapstart[data->repodataid] + (key - data->keys)];
736 return SEARCH_NEXT_KEY; /* we do not want this one */
738 if (cbdata->target->keys[rm].storage == KEY_STORAGE_VERTICAL_OFFSET)
740 xd = cbdata->extdata + rm; /* vertical buffer */
741 if (cbdata->vstart == -1)
742 cbdata->vstart = xd->len;
745 xd = cbdata->extdata + 0; /* incore buffer */
748 case REPOKEY_TYPE_VOID:
749 case REPOKEY_TYPE_CONSTANT:
750 case REPOKEY_TYPE_CONSTANTID:
752 case REPOKEY_TYPE_ID:
754 if (!ISRELDEP(id) && cbdata->ownspool && id > 1)
755 id = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, id);
756 needid = cbdata->needid;
757 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
760 case REPOKEY_TYPE_IDARRAY:
762 if (!ISRELDEP(id) && cbdata->ownspool && id > 1)
763 id = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, id);
764 needid = cbdata->needid;
765 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
766 data_addideof(xd, id, kv->eof);
768 case REPOKEY_TYPE_STR:
769 data_addblob(xd, (unsigned char *)kv->str, strlen(kv->str) + 1);
771 case REPOKEY_TYPE_MD5:
772 data_addblob(xd, (unsigned char *)kv->str, SIZEOF_MD5);
774 case REPOKEY_TYPE_SHA1:
775 data_addblob(xd, (unsigned char *)kv->str, SIZEOF_SHA1);
777 case REPOKEY_TYPE_SHA256:
778 data_addblob(xd, (unsigned char *)kv->str, SIZEOF_SHA256);
780 case REPOKEY_TYPE_U32:
786 data_addblob(xd, v, 4);
788 case REPOKEY_TYPE_NUM:
789 data_addid(xd, kv->num);
791 case REPOKEY_TYPE_DIR:
793 if (cbdata->owndirpool)
794 id = putinowndirpool(cbdata, data, &data->dirpool, id);
795 id = cbdata->dirused[id];
798 case REPOKEY_TYPE_BINARY:
799 data_addid(xd, kv->num);
801 data_addblob(xd, (unsigned char *)kv->str, kv->num);
803 case REPOKEY_TYPE_DIRNUMNUMARRAY:
805 if (cbdata->owndirpool)
806 id = putinowndirpool(cbdata, data, &data->dirpool, id);
807 id = cbdata->dirused[id];
809 data_addid(xd, kv->num);
810 data_addideof(xd, kv->num2, kv->eof);
812 case REPOKEY_TYPE_DIRSTRARRAY:
814 if (cbdata->owndirpool)
815 id = putinowndirpool(cbdata, data, &data->dirpool, id);
816 id = cbdata->dirused[id];
817 data_addideof(xd, id, kv->eof);
818 data_addblob(xd, (unsigned char *)kv->str, strlen(kv->str) + 1);
820 case REPOKEY_TYPE_FIXARRAY:
825 data_addid(xd, kv->num);
826 data_addid(xd, cbdata->subschemata[cbdata->current_sub]);
828 fprintf(stderr, "writing %d %d\n", kv->num, cbdata->subschemata[cbdata->current_sub]);
832 else if (kv->eof == 1)
834 cbdata->current_sub++;
837 case REPOKEY_TYPE_FLEXARRAY:
839 data_addid(xd, kv->num);
841 data_addid(xd, cbdata->subschemata[cbdata->current_sub++]);
842 if (xd == cbdata->extdata + 0 && !kv->parent && !cbdata->doingsolvables)
844 if (xd->len - cbdata->lastlen > cbdata->maxdata)
845 cbdata->maxdata = xd->len - cbdata->lastlen;
846 cbdata->lastlen = xd->len;
850 fprintf(stderr, "unknown type for %d: %d\n", key->name, key->type);
853 if (cbdata->target->keys[rm].storage == KEY_STORAGE_VERTICAL_OFFSET && kv->eof)
855 /* we can re-use old data in the blob here! */
856 data_addid(cbdata->extdata + 0, cbdata->vstart); /* add offset into incore data */
857 data_addid(cbdata->extdata + 0, xd->len - cbdata->vstart); /* add length into incore data */
864 repo_write_cb_adddata(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
866 struct cbdata *cbdata = vcbdata;
867 return repo_write_adddata(cbdata, data, key, kv);
870 /* traverse through directory with first child "dir" */
872 traverse_dirs(Dirpool *dp, Id *dirmap, Id n, Id dir, Id *used)
878 /* special case for '/', which has to come first */
881 for (sib = dir; sib; sib = dirpool_sibling(dp, sib))
883 if (used && !used[sib])
885 if (sib == 1 && parent == 1)
886 continue; /* already did that one above */
890 /* now go through all the siblings we just added and
891 * do recursive calls on them */
893 for (; parent < lastn; parent++)
895 sib = dirmap[parent];
896 if (used && used[sib] != 2) /* 2: used as parent */
898 child = dirpool_child(dp, sib);
901 dirmap[n++] = -parent; /* start new block */
902 n = traverse_dirs(dp, dirmap, n, child, used);
909 write_compressed_page(FILE *fp, unsigned char *page, int len)
912 unsigned char cpage[REPOPAGE_BLOBSIZE];
914 clen = repopagestore_compress_page(page, len, cpage, len - 1);
917 write_u32(fp, len * 2);
918 write_blob(fp, page, len);
922 write_u32(fp, clen * 2 + 1);
923 write_blob(fp, cpage, clen);
927 static Id verticals[] = {
929 SOLVABLE_DESCRIPTION,
938 static char *languagetags[] = {
940 "solvable:description:",
941 "solvable:messageins:",
942 "solvable:messagedel:",
948 repo_write_stdkeyfilter(Repo *repo, Repokey *key, void *kfdata)
953 for (i = 0; verticals[i]; i++)
954 if (key->name == verticals[i])
955 return KEY_STORAGE_VERTICAL_OFFSET;
956 keyname = pool_id2str(repo->pool, key->name);
957 for (i = 0; languagetags[i] != 0; i++)
958 if (!strncmp(keyname, languagetags[i], strlen(languagetags[i])))
959 return KEY_STORAGE_VERTICAL_OFFSET;
960 return KEY_STORAGE_INCORE;
968 * the code works the following way:
970 * 1) find which keys should be written
971 * 2) collect usage information for keys/ids/dirids, create schema
973 * 3) use usage information to create mapping tables, so that often
974 * used ids get a lower number
975 * 4) encode data into buffers using the mapping tables
976 * 5) write everything to disk
979 repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq)
981 Pool *pool = repo->pool;
987 unsigned int solv_flags;
996 unsigned char *repodataused;
997 int anyrepodataused = 0;
998 int anysolvableused = 0;
1000 struct cbdata cbdata;
1003 int poolusage, dirpoolusage, idused, dirused;
1006 Repodata *data, *dirpooldata;
1017 Id type_constantid = REPOKEY_TYPE_CONSTANTID;
1019 unsigned char *prefixcomp;
1020 unsigned int compsum;
1024 memset(&cbdata, 0, sizeof(cbdata));
1026 cbdata.target = ⌖
1028 repodata_initdata(&target, repo, 1);
1030 /* go through all repodata and find the keys we need */
1031 /* also unify keys */
1032 /* keymapstart - maps repo number to keymap offset */
1033 /* keymap - maps repo key to my key, 0 -> not used */
1035 /* start with all KEY_STORAGE_SOLVABLE ids */
1037 n = ID_NUM_INTERNAL;
1038 FOR_REPODATAS(repo, i, data)
1040 cbdata.keymap = solv_calloc(n, sizeof(Id));
1041 cbdata.keymapstart = solv_calloc(repo->nrepodata, sizeof(Id));
1042 repodataused = solv_calloc(repo->nrepodata, 1);
1047 /* add keys for STORAGE_SOLVABLE */
1048 for (i = SOLVABLE_NAME; i <= RPM_RPMDBID; i++)
1052 if (i < SOLVABLE_PROVIDES)
1053 keyd.type = REPOKEY_TYPE_ID;
1054 else if (i < RPM_RPMDBID)
1055 keyd.type = REPOKEY_TYPE_REL_IDARRAY;
1057 keyd.type = REPOKEY_TYPE_U32;
1059 keyd.storage = KEY_STORAGE_SOLVABLE;
1062 keyd.storage = keyfilter(repo, &keyd, kfdata);
1063 if (keyd.storage == KEY_STORAGE_DROPPED)
1065 keyd.storage = KEY_STORAGE_SOLVABLE;
1069 cbdata.keymap[keyd.name] = repodata_key2id(&target, &keyd, 1);
1072 if (repo->nsolvables)
1075 keyd.name = REPOSITORY_SOLVABLES;
1076 keyd.type = REPOKEY_TYPE_FLEXARRAY;
1078 keyd.storage = KEY_STORAGE_INCORE;
1079 cbdata.keymap[keyd.name] = repodata_key2id(&target, &keyd, 1);
1087 n = ID_NUM_INTERNAL;
1088 FOR_REPODATAS(repo, i, data)
1090 cbdata.keymapstart[i] = n;
1091 cbdata.keymap[n++] = 0; /* key 0 */
1097 /* check if we want this repodata */
1098 memset(&keyd, 0, sizeof(keyd));
1102 if (keyfilter(repo, &keyd, kfdata) == -1)
1105 for (j = 1; j < data->nkeys; j++, n++)
1107 key = data->keys + j;
1108 if (key->name == REPOSITORY_SOLVABLES && key->type == REPOKEY_TYPE_FLEXARRAY)
1110 cbdata.keymap[n] = cbdata.keymap[key->name];
1113 if (key->type == REPOKEY_TYPE_DELETED)
1115 cbdata.keymap[n] = 0;
1118 if (key->type == REPOKEY_TYPE_CONSTANTID && data->localpool)
1120 Repokey keyd = *key;
1121 keyd.size = repodata_globalize_id(data, key->size, 1);
1122 id = repodata_key2id(&target, &keyd, 0);
1125 id = repodata_key2id(&target, key, 0);
1128 Repokey keyd = *key;
1129 keyd.storage = KEY_STORAGE_INCORE;
1130 if (keyd.type == REPOKEY_TYPE_CONSTANTID)
1131 keyd.size = repodata_globalize_id(data, key->size, 1);
1132 else if (keyd.type != REPOKEY_TYPE_CONSTANT)
1136 keyd.storage = keyfilter(repo, &keyd, kfdata);
1137 if (keyd.storage == KEY_STORAGE_DROPPED)
1139 cbdata.keymap[n] = 0;
1143 id = repodata_key2id(&target, &keyd, 1);
1145 cbdata.keymap[n] = id;
1146 /* load repodata if not already loaded */
1147 if (data->state == REPODATA_STUB)
1149 if (data->loadcallback)
1150 data->loadcallback(data);
1152 data->state = REPODATA_ERROR;
1153 if (data->state != REPODATA_ERROR)
1155 /* redo this repodata! */
1157 n = cbdata.keymapstart[i];
1161 if (data->state == REPODATA_ERROR)
1164 cbdata.keymap[n] = 0;
1168 repodataused[i] = 1;
1169 anyrepodataused = 1;
1170 if (key->type == REPOKEY_TYPE_CONSTANTID || key->type == REPOKEY_TYPE_ID ||
1171 key->type == REPOKEY_TYPE_IDARRAY || key->type == REPOKEY_TYPE_REL_IDARRAY)
1173 else if (key->type == REPOKEY_TYPE_DIR || key->type == REPOKEY_TYPE_DIRNUMNUMARRAY || key->type == REPOKEY_TYPE_DIRSTRARRAY)
1175 idused = 1; /* dirs also use ids */
1181 if (data->localpool)
1184 poolusage = 3; /* need own pool */
1188 spool = &data->spool;
1195 else if (poolusage != 1)
1196 poolusage = 3; /* need own pool */
1202 dirpoolusage = 3; /* need own dirpool */
1206 dirpool = &data->dirpool;
1213 /* 0: no pool needed at all */
1214 /* 1: use global pool */
1215 /* 2: use repodata local pool */
1216 /* 3: need own pool */
1219 spool = &target.spool;
1220 /* hack: reuse global pool data so we don't have to map pool ids */
1223 stringpool_free(spool);
1224 stringpool_clone(spool, &pool->ss);
1226 cbdata.ownspool = spool;
1228 else if (poolusage == 0 || poolusage == 1)
1234 if (dirpoolusage == 3)
1236 dirpool = &target.dirpool;
1238 cbdata.owndirpool = dirpool;
1241 cbdata.dirused = solv_calloc(dirpool->ndirs, sizeof(Id));
1244 /********************************************************************/
1246 fprintf(stderr, "poolusage: %d\n", poolusage);
1247 fprintf(stderr, "dirpoolusage: %d\n", dirpoolusage);
1248 fprintf(stderr, "nkeys: %d\n", target.nkeys);
1249 for (i = 1; i < target.nkeys; i++)
1250 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);
1253 /* copy keys if requested */
1257 for (i = 1; i < target.nkeys; i++)
1258 queue_push2(keyq, target.keys[i].name, target.keys[i].type);
1263 /* put all the keys we need in our string pool */
1264 /* put mapped ids right into target.keys */
1265 for (i = 1, key = target.keys + i; i < target.nkeys; i++, key++)
1267 key->name = stringpool_str2id(spool, pool_id2str(pool, key->name), 1);
1268 if (key->type == REPOKEY_TYPE_CONSTANTID)
1270 key->type = stringpool_str2id(spool, pool_id2str(pool, key->type), 1);
1271 type_constantid = key->type;
1272 key->size = stringpool_str2id(spool, pool_id2str(pool, key->size), 1);
1275 key->type = stringpool_str2id(spool, pool_id2str(pool, key->type), 1);
1278 stringpool_freehash(spool); /* free some mem */
1282 /********************************************************************/
1284 /* set needed count of all strings and rels,
1285 * find which keys are used in the solvables
1286 * put all strings in own spool
1289 reloff = spool->nstrings;
1291 reloff = (reloff + NEEDED_BLOCK) & ~NEEDED_BLOCK;
1293 needid = calloc(reloff + pool->nrels, sizeof(*needid));
1294 needid[0].map = reloff;
1296 cbdata.needid = needid;
1297 cbdata.schema = solv_calloc(target.nkeys, sizeof(Id));
1298 cbdata.sp = cbdata.schema;
1299 cbdata.solvschemata = solv_calloc(repo->nsolvables, sizeof(Id));
1301 /* create main schema */
1302 cbdata.sp = cbdata.schema;
1303 /* collect all other data from all repodatas */
1304 /* XXX: merge arrays of equal keys? */
1305 FOR_REPODATAS(repo, j, data)
1307 if (!repodataused[j])
1309 repodata_search(data, SOLVID_META, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_needed, &cbdata);
1312 /* add solvables if needed (may revert later) */
1313 if (repo->nsolvables)
1315 *sp++ = cbdata.keymap[REPOSITORY_SOLVABLES];
1316 target.keys[cbdata.keymap[REPOSITORY_SOLVABLES]].size++;
1319 mainschema = repodata_schema2id(cbdata.target, cbdata.schema, 1);
1321 idarraydata = repo->idarraydata;
1323 anysolvableused = 0;
1324 cbdata.doingsolvables = 1;
1325 for (i = repo->start, s = pool->solvables + i, n = 0; i < repo->end; i++, s++)
1327 if (s->repo != repo)
1330 /* set schema info, keep in sync with further down */
1332 if (cbdata.keymap[SOLVABLE_NAME])
1334 *sp++ = cbdata.keymap[SOLVABLE_NAME];
1335 needid[s->name].need++;
1337 if (cbdata.keymap[SOLVABLE_ARCH])
1339 *sp++ = cbdata.keymap[SOLVABLE_ARCH];
1340 needid[s->arch].need++;
1342 if (cbdata.keymap[SOLVABLE_EVR])
1344 *sp++ = cbdata.keymap[SOLVABLE_EVR];
1345 needid[s->evr].need++;
1347 if (s->vendor && cbdata.keymap[SOLVABLE_VENDOR])
1349 *sp++ = cbdata.keymap[SOLVABLE_VENDOR];
1350 needid[s->vendor].need++;
1352 if (s->provides && cbdata.keymap[SOLVABLE_PROVIDES])
1354 *sp++ = cbdata.keymap[SOLVABLE_PROVIDES];
1355 target.keys[cbdata.keymap[SOLVABLE_PROVIDES]].size += incneedidarray(pool, idarraydata + s->provides, needid);
1357 if (s->obsoletes && cbdata.keymap[SOLVABLE_OBSOLETES])
1359 *sp++ = cbdata.keymap[SOLVABLE_OBSOLETES];
1360 target.keys[cbdata.keymap[SOLVABLE_OBSOLETES]].size += incneedidarray(pool, idarraydata + s->obsoletes, needid);
1362 if (s->conflicts && cbdata.keymap[SOLVABLE_CONFLICTS])
1364 *sp++ = cbdata.keymap[SOLVABLE_CONFLICTS];
1365 target.keys[cbdata.keymap[SOLVABLE_CONFLICTS]].size += incneedidarray(pool, idarraydata + s->conflicts, needid);
1367 if (s->requires && cbdata.keymap[SOLVABLE_REQUIRES])
1369 *sp++ = cbdata.keymap[SOLVABLE_REQUIRES];
1370 target.keys[cbdata.keymap[SOLVABLE_REQUIRES]].size += incneedidarray(pool, idarraydata + s->requires, needid);
1372 if (s->recommends && cbdata.keymap[SOLVABLE_RECOMMENDS])
1374 *sp++ = cbdata.keymap[SOLVABLE_RECOMMENDS];
1375 target.keys[cbdata.keymap[SOLVABLE_RECOMMENDS]].size += incneedidarray(pool, idarraydata + s->recommends, needid);
1377 if (s->suggests && cbdata.keymap[SOLVABLE_SUGGESTS])
1379 *sp++ = cbdata.keymap[SOLVABLE_SUGGESTS];
1380 target.keys[cbdata.keymap[SOLVABLE_SUGGESTS]].size += incneedidarray(pool, idarraydata + s->suggests, needid);
1382 if (s->supplements && cbdata.keymap[SOLVABLE_SUPPLEMENTS])
1384 *sp++ = cbdata.keymap[SOLVABLE_SUPPLEMENTS];
1385 target.keys[cbdata.keymap[SOLVABLE_SUPPLEMENTS]].size += incneedidarray(pool, idarraydata + s->supplements, needid);
1387 if (s->enhances && cbdata.keymap[SOLVABLE_ENHANCES])
1389 *sp++ = cbdata.keymap[SOLVABLE_ENHANCES];
1390 target.keys[cbdata.keymap[SOLVABLE_ENHANCES]].size += incneedidarray(pool, idarraydata + s->enhances, needid);
1392 if (repo->rpmdbid && cbdata.keymap[RPM_RPMDBID])
1394 *sp++ = cbdata.keymap[RPM_RPMDBID];
1395 target.keys[cbdata.keymap[RPM_RPMDBID]].size++;
1399 if (anyrepodataused)
1401 FOR_REPODATAS(repo, j, data)
1403 if (!repodataused[j])
1405 if (i < data->start || i >= data->end)
1407 repodata_search(data, i, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_needed, &cbdata);
1408 needid = cbdata.needid;
1412 cbdata.solvschemata[n] = repodata_schema2id(cbdata.target, cbdata.schema, 1);
1413 if (cbdata.solvschemata[n])
1414 anysolvableused = 1;
1417 cbdata.doingsolvables = 0;
1418 assert(n == repo->nsolvables);
1420 if (repo->nsolvables && !anysolvableused)
1422 /* strip off solvable from the main schema */
1423 target.keys[cbdata.keymap[REPOSITORY_SOLVABLES]].size = 0;
1425 for (i = 0; target.schemadata[target.schemata[mainschema] + i]; i++)
1427 *sp = target.schemadata[target.schemata[mainschema] + i];
1428 if (*sp != cbdata.keymap[REPOSITORY_SOLVABLES])
1431 assert(target.schemadatalen == target.schemata[mainschema] + i + 1);
1433 target.schemadatalen = target.schemata[mainschema];
1435 repodata_free_schemahash(&target);
1436 mainschema = repodata_schema2id(cbdata.target, cbdata.schema, 1);
1439 /********************************************************************/
1441 /* remove unused keys */
1442 keyused = solv_calloc(target.nkeys, sizeof(Id));
1443 for (i = 1; i < target.schemadatalen; i++)
1444 keyused[target.schemadata[i]] = 1;
1446 for (n = i = 1; i < target.nkeys; i++)
1453 target.keys[n] = target.keys[i];
1456 keyq->elements[2 * n - 2] = keyq->elements[2 * i - 2];
1457 keyq->elements[2 * n - 1] = keyq->elements[2 * i - 1];
1464 queue_truncate(keyq, 2 * n - 2);
1466 /* update schema data to the new key ids */
1467 for (i = 1; i < target.schemadatalen; i++)
1468 target.schemadata[i] = keyused[target.schemadata[i]];
1469 /* update keymap to the new key ids */
1470 for (i = 0; i < cbdata.nkeymap; i++)
1471 cbdata.keymap[i] = keyused[cbdata.keymap[i]];
1472 keyused = solv_free(keyused);
1474 /* increment needid of the used keys, they are already mapped to
1475 * the correct string pool */
1476 for (i = 1; i < target.nkeys; i++)
1478 if (target.keys[i].type == type_constantid)
1479 needid[target.keys[i].size].need++;
1480 needid[target.keys[i].name].need++;
1481 needid[target.keys[i].type].need++;
1484 /********************************************************************/
1486 if (dirpool && cbdata.dirused && !cbdata.dirused[0])
1488 /* no dirs used at all */
1489 cbdata.dirused = solv_free(cbdata.dirused);
1493 /* increment need id for used dir components */
1496 /* if we have own dirpool, all entries in it are used.
1497 also, all comp ids are already mapped by putinowndirpool(),
1498 so we can simply increment needid.
1499 (owndirpool != 0, dirused == 0, dirpooldata == 0) */
1500 /* else we re-use a dirpool of repodata "dirpooldata".
1501 dirused tells us which of the ids are used.
1502 we need to map comp ids if we generate a new pool.
1503 (owndirpool == 0, dirused != 0, dirpooldata != 0) */
1504 for (i = 1; i < dirpool->ndirs; i++)
1507 fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1);
1509 if (cbdata.dirused && !cbdata.dirused[i])
1511 id = dirpool->dirs[i];
1514 if (dirpooldata && cbdata.ownspool && id > 1)
1516 id = putinownpool(&cbdata, dirpooldata->localpool ? &dirpooldata->spool : &pool->ss, id);
1517 needid = cbdata.needid;
1524 /********************************************************************/
1527 * create mapping table, new keys are sorted by needid[].need
1529 * needid[key].need : old key -> new key
1530 * needid[key].map : new key -> old key
1533 /* zero out id 0 and rel 0 just in case */
1534 reloff = needid[0].map;
1536 needid[reloff].need = 0;
1538 for (i = 1; i < reloff + pool->nrels; i++)
1542 solv_sort(needid + 1, spool->nstrings - 1, sizeof(*needid), needid_cmp_need_s, spool);
1544 /* make first entry '' */
1546 solv_sort(needid + 2, spool->nstrings - 2, sizeof(*needid), needid_cmp_need_s, spool);
1548 solv_sort(needid + reloff, pool->nrels, sizeof(*needid), needid_cmp_need, 0);
1549 /* now needid is in new order, needid[newid].map -> oldid */
1551 /* calculate string space size, also zero out needid[].need */
1553 for (i = 1; i < reloff; i++)
1555 if (!needid[i].need)
1556 break; /* as we have sorted, every entry after this also has need == 0 */
1558 sizeid += strlen(spool->stringspace + spool->strings[needid[i].map]) + 1;
1560 nstrings = i; /* our new string id end */
1562 /* make needid[oldid].need point to newid */
1563 for (i = 1; i < nstrings; i++)
1564 needid[needid[i].map].need = i;
1566 /* same as above for relations */
1567 for (i = 0; i < pool->nrels; i++)
1569 if (!needid[reloff + i].need)
1571 needid[reloff + i].need = 0;
1573 nrels = i; /* our new rel id end */
1575 for (i = 0; i < nrels; i++)
1576 needid[needid[reloff + i].map].need = nstrings + i;
1578 /* now we have: needid[oldid].need -> newid
1579 needid[newid].map -> oldid
1580 both for strings and relations */
1583 /********************************************************************/
1589 /* create our new target directory structure by traversing through all
1590 * used dirs. This will concatenate blocks with the same parent
1591 * directory into single blocks.
1592 * Instead of components, traverse_dirs stores the old dirids,
1593 * we will change this in the second step below */
1594 /* (dirpooldata and dirused are 0 if we have our own dirpool) */
1595 if (cbdata.dirused && !cbdata.dirused[1])
1596 cbdata.dirused[1] = 1; /* always want / entry */
1597 dirmap = solv_calloc(dirpool->ndirs, sizeof(Id));
1599 ndirmap = traverse_dirs(dirpool, dirmap, 1, dirpool_child(dirpool, 0), cbdata.dirused);
1601 /* (re)create dirused, so that it maps from "old dirid" to "new dirid" */
1602 /* change dirmap so that it maps from "new dirid" to "new compid" */
1603 if (!cbdata.dirused)
1604 cbdata.dirused = solv_malloc2(dirpool->ndirs, sizeof(Id));
1605 memset(cbdata.dirused, 0, dirpool->ndirs * sizeof(Id));
1606 for (i = 1; i < ndirmap; i++)
1610 cbdata.dirused[dirmap[i]] = i;
1611 id = dirpool->dirs[dirmap[i]];
1612 if (dirpooldata && cbdata.ownspool && id > 1)
1613 id = putinownpool(&cbdata, dirpooldata->localpool ? &dirpooldata->spool : &pool->ss, id);
1614 dirmap[i] = needid[id].need;
1616 /* now the new target directory structure is complete (dirmap), and we have
1617 * dirused[olddirid] -> newdirid */
1620 /********************************************************************/
1623 * we use extdata[0] for incore data and extdata[keyid] for vertical data
1626 cbdata.extdata = solv_calloc(target.nkeys, sizeof(struct extdata));
1628 xd = cbdata.extdata;
1629 cbdata.current_sub = 0;
1630 /* add main schema */
1632 data_addid(xd, mainschema);
1635 FOR_REPODATAS(repo, j, data)
1637 if (!repodataused[j])
1639 repodata_search(data, SOLVID_META, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_adddata, &cbdata);
1643 if (xd->len - cbdata.lastlen > cbdata.maxdata)
1644 cbdata.maxdata = xd->len - cbdata.lastlen;
1645 cbdata.lastlen = xd->len;
1647 if (anysolvableused)
1649 data_addid(xd, repo->nsolvables); /* FLEXARRAY nentries */
1650 cbdata.doingsolvables = 1;
1651 for (i = repo->start, s = pool->solvables + i, n = 0; i < repo->end; i++, s++)
1653 if (s->repo != repo)
1655 data_addid(xd, cbdata.solvschemata[n]);
1656 if (cbdata.keymap[SOLVABLE_NAME])
1657 data_addid(xd, needid[s->name].need);
1658 if (cbdata.keymap[SOLVABLE_ARCH])
1659 data_addid(xd, needid[s->arch].need);
1660 if (cbdata.keymap[SOLVABLE_EVR])
1661 data_addid(xd, needid[s->evr].need);
1662 if (s->vendor && cbdata.keymap[SOLVABLE_VENDOR])
1663 data_addid(xd, needid[s->vendor].need);
1664 if (s->provides && cbdata.keymap[SOLVABLE_PROVIDES])
1665 data_addidarray_sort(xd, pool, needid, idarraydata + s->provides, SOLVABLE_FILEMARKER);
1666 if (s->obsoletes && cbdata.keymap[SOLVABLE_OBSOLETES])
1667 data_addidarray_sort(xd, pool, needid, idarraydata + s->obsoletes, 0);
1668 if (s->conflicts && cbdata.keymap[SOLVABLE_CONFLICTS])
1669 data_addidarray_sort(xd, pool, needid, idarraydata + s->conflicts, 0);
1670 if (s->requires && cbdata.keymap[SOLVABLE_REQUIRES])
1671 data_addidarray_sort(xd, pool, needid, idarraydata + s->requires, SOLVABLE_PREREQMARKER);
1672 if (s->recommends && cbdata.keymap[SOLVABLE_RECOMMENDS])
1673 data_addidarray_sort(xd, pool, needid, idarraydata + s->recommends, 0);
1674 if (s->suggests && cbdata.keymap[SOLVABLE_SUGGESTS])
1675 data_addidarray_sort(xd, pool, needid, idarraydata + s->suggests, 0);
1676 if (s->supplements && cbdata.keymap[SOLVABLE_SUPPLEMENTS])
1677 data_addidarray_sort(xd, pool, needid, idarraydata + s->supplements, 0);
1678 if (s->enhances && cbdata.keymap[SOLVABLE_ENHANCES])
1679 data_addidarray_sort(xd, pool, needid, idarraydata + s->enhances, 0);
1680 if (repo->rpmdbid && cbdata.keymap[RPM_RPMDBID])
1681 data_addu32(xd, repo->rpmdbid[i - repo->start]);
1682 if (anyrepodataused)
1685 FOR_REPODATAS(repo, j, data)
1687 if (!repodataused[j])
1689 if (i < data->start || i >= data->end)
1691 repodata_search(data, i, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_adddata, &cbdata);
1694 if (xd->len - cbdata.lastlen > cbdata.maxdata)
1695 cbdata.maxdata = xd->len - cbdata.lastlen;
1696 cbdata.lastlen = xd->len;
1699 cbdata.doingsolvables = 0;
1702 assert(cbdata.current_sub == cbdata.nsubschemata);
1703 if (cbdata.subschemata)
1705 cbdata.subschemata = solv_free(cbdata.subschemata);
1706 cbdata.nsubschemata = 0;
1709 /********************************************************************/
1713 /* write file header */
1714 write_u32(fp, 'S' << 24 | 'O' << 16 | 'L' << 8 | 'V');
1715 write_u32(fp, SOLV_VERSION_8);
1719 write_u32(fp, nstrings);
1720 write_u32(fp, nrels);
1721 write_u32(fp, ndirmap);
1722 write_u32(fp, anysolvableused ? repo->nsolvables : 0);
1723 write_u32(fp, target.nkeys);
1724 write_u32(fp, target.nschemata);
1726 solv_flags |= SOLV_FLAG_PREFIX_POOL;
1727 write_u32(fp, solv_flags);
1730 * calculate prefix encoding of the strings
1732 prefixcomp = solv_malloc(nstrings);
1737 for (i = 1; i < nstrings; i++)
1739 char *str = spool->stringspace + spool->strings[needid[i].map];
1741 for (same = 0; same < 255; same++)
1742 if (!old_str[same] || old_str[same] != str[same])
1744 prefixcomp[i] = same;
1752 write_u32(fp, sizeid);
1753 /* we save compsum bytes but need 1 extra byte for every string */
1754 write_u32(fp, sizeid + (nstrings ? nstrings - 1 : 0) - compsum);
1755 if (sizeid + (nstrings ? nstrings - 1 : 0) != compsum)
1757 for (i = 1; i < nstrings; i++)
1759 char *str = spool->stringspace + spool->strings[needid[i].map];
1760 write_u8(fp, prefixcomp[i]);
1761 write_str(fp, str + prefixcomp[i]);
1764 solv_free(prefixcomp);
1767 /* Build the prefix-encoding of the string pool. We need to know
1768 the size of that before writing it to the file, so we have to
1769 build a separate buffer for that. As it's temporarily possible
1770 that this actually is an expansion we can't easily reuse the
1771 stringspace for this. The max expansion per string is 1 byte,
1772 so it will fit into sizeid+nstrings bytes. */
1773 char *prefix = solv_malloc(sizeid + nstrings);
1776 for (i = 1; i < nstrings; i++)
1778 char *str = spool->stringspace + spool->strings[needid[i].map];
1781 for (same = 0; same < 255; same++)
1782 if (!old_str[same] || !str[same] || old_str[same] != str[same])
1785 len = strlen(str + same) + 1;
1786 memcpy(pp, str + same, len);
1794 write_u32(fp, sizeid);
1795 write_u32(fp, pp - prefix);
1798 if (fwrite(prefix, pp - prefix, 1, fp) != 1)
1800 perror("write error prefix");
1810 for (i = 0; i < nrels; i++)
1812 ran = pool->rels + (needid[reloff + i].map - reloff);
1813 write_id(fp, needid[ISRELDEP(ran->name) ? RELOFF(ran->name) : ran->name].need);
1814 write_id(fp, needid[ISRELDEP(ran->evr) ? RELOFF(ran->evr) : ran->evr].need);
1815 write_u8(fp, ran->flags);
1819 * write dirs (skip both root and / entry)
1821 for (i = 2; i < ndirmap; i++)
1824 write_id(fp, dirmap[i]);
1826 write_id(fp, nstrings - dirmap[i]);
1833 for (i = 1; i < target.nkeys; i++)
1835 write_id(fp, needid[target.keys[i].name].need);
1836 write_id(fp, needid[target.keys[i].type].need);
1837 if (target.keys[i].storage != KEY_STORAGE_VERTICAL_OFFSET)
1839 if (target.keys[i].type == type_constantid)
1840 write_id(fp, needid[target.keys[i].size].need);
1842 write_id(fp, target.keys[i].size);
1845 write_id(fp, cbdata.extdata[i].len);
1846 write_id(fp, target.keys[i].storage);
1852 write_id(fp, target.schemadatalen); /* XXX -1? */
1853 for (i = 1; i < target.nschemata; i++)
1854 write_idarray(fp, pool, 0, repodata_id2schema(&target, i));
1856 /********************************************************************/
1858 write_id(fp, cbdata.maxdata);
1859 write_id(fp, cbdata.extdata[0].len);
1860 if (cbdata.extdata[0].len)
1861 write_blob(fp, cbdata.extdata[0].buf, cbdata.extdata[0].len);
1862 solv_free(cbdata.extdata[0].buf);
1864 /* do we have vertical data? */
1865 for (i = 1; i < target.nkeys; i++)
1866 if (cbdata.extdata[i].len)
1868 if (i < target.nkeys)
1870 /* yes, write it in pages */
1871 unsigned char *dp, vpage[REPOPAGE_BLOBSIZE];
1872 int l, ll, lpage = 0;
1874 write_u32(fp, REPOPAGE_BLOBSIZE);
1875 for (i = 1; i < target.nkeys; i++)
1877 if (!cbdata.extdata[i].len)
1879 l = cbdata.extdata[i].len;
1880 dp = cbdata.extdata[i].buf;
1883 ll = REPOPAGE_BLOBSIZE - lpage;
1886 memcpy(vpage + lpage, dp, ll);
1890 if (lpage == REPOPAGE_BLOBSIZE)
1892 write_compressed_page(fp, vpage, lpage);
1898 write_compressed_page(fp, vpage, lpage);
1901 for (i = 1; i < target.nkeys; i++)
1902 solv_free(cbdata.extdata[i].buf);
1903 solv_free(cbdata.extdata);
1905 repodata_freedata(&target);
1908 solv_free(cbdata.solvschemata);
1909 solv_free(cbdata.schema);
1911 solv_free(cbdata.keymap);
1912 solv_free(cbdata.keymapstart);
1913 solv_free(cbdata.dirused);
1914 solv_free(repodataused);
1918 struct repodata_write_data {
1919 int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata);
1925 repodata_write_keyfilter(Repo *repo, Repokey *key, void *kfdata)
1927 struct repodata_write_data *wd = kfdata;
1929 /* XXX: special repodata selection hack */
1930 if (key->name == 1 && key->size != wd->repodataid)
1932 if (key->storage == KEY_STORAGE_SOLVABLE)
1933 return KEY_STORAGE_DROPPED; /* not part of this repodata */
1935 return (*wd->keyfilter)(repo, key, wd->kfdata);
1936 return key->storage;
1940 repodata_write_filtered(Repodata *data, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq)
1942 struct repodata_write_data wd;
1944 wd.keyfilter = keyfilter;
1946 wd.repodataid = data->repodataid;
1947 return repo_write_filtered(data->repo, fp, repodata_write_keyfilter, &wd, keyq);
1951 repodata_write(Repodata *data, FILE *fp)
1953 return repodata_write_filtered(data, fp, repo_write_stdkeyfilter, 0, 0);
1957 repo_write(Repo *repo, FILE *fp)
1959 return repo_write_filtered(repo, fp, repo_write_stdkeyfilter, 0, 0);