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;
405 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
406 dp = xd->buf + xd->len;
411 *dp++ = (x >> 28) | 128;
413 *dp++ = (x >> 21) | 128;
414 *dp++ = (x >> 14) | 128;
417 *dp++ = (x >> 7) | 128;
419 xd->len = dp - xd->buf;
423 data_addideof(struct extdata *xd, Id sx, int eof)
425 unsigned int x = (unsigned int)sx;
428 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
429 dp = xd->buf + xd->len;
434 *dp++ = (x >> 27) | 128;
436 *dp++ = (x >> 20) | 128;
437 *dp++ = (x >> 13) | 128;
440 *dp++ = (x >> 6) | 128;
441 *dp++ = eof ? (x & 63) : (x & 63) | 64;
442 xd->len = dp - xd->buf;
446 data_addid64(struct extdata *xd, unsigned int x, unsigned int hx)
452 data_addid(xd, (Id)(hx >> 3));
453 xd->buf[xd->len - 1] |= 128;
456 data_addid(xd, (Id)(x | 0x80000000));
457 xd->buf[xd->len - 5] = (x >> 28) | (hx << 4) | 128;
460 data_addid(xd, (Id)x);
464 data_addidarray_sort(struct extdata *xd, Pool *pool, NeedId *needid, Id *ids, Id marker)
477 for (len = 0; len < 64 && ids[len]; len++)
481 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
486 for (i = len + 1; ids[i]; i++)
488 sids = solv_malloc2(i, sizeof(Id));
489 memcpy(sids, lids, 64 * sizeof(Id));
490 for (; ids[len]; len++)
494 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
501 /* That bloody solvable:prereqmarker needs to stay in position :-( */
503 marker = needid[marker].need;
504 for (i = 0; i < len; i++)
505 if (sids[i] == marker)
508 solv_sort(sids, i, sizeof(Id), cmp_ids, 0);
510 solv_sort(sids + i + 1, len - i - 1, sizeof(Id), cmp_ids, 0);
514 /* The differencing above produces many runs of ones and twos. I tried
515 fairly elaborate schemes to RLE those, but they give only very mediocre
516 improvements in compression, as coding the escapes costs quite some
517 space. Even if they are coded only as bits in IDs. The best improvement
518 was about 2.7% for the whole .solv file. It's probably better to
519 invest some complexity into sharing idarrays, than RLEing. */
520 for (i = 0; i < len - 1; i++)
523 /* Ugly PREREQ handling. A "difference" of 0 is the prereq marker,
524 hence all real differences are offsetted by 1. Otherwise we would
525 have to handle negative differences, which would cost code space for
526 the encoding of the sign. We loose the exact mapping of prereq here,
527 but we know the result, so we can recover from that in the reader. */
535 /* XXX If difference is zero we have multiple equal elements,
536 we might want to skip writing them out. */
537 data_addideof(xd, id, 0);
544 data_addideof(xd, id, 1);
550 data_addblob(struct extdata *xd, unsigned char *blob, int len)
552 xd->buf = solv_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
553 memcpy(xd->buf + xd->len, blob, len);
558 data_addu32(struct extdata *xd, unsigned int num)
565 data_addblob(xd, d, 4);
569 putinownpool(struct cbdata *cbdata, Stringpool *ss, Id id)
571 const char *str = stringpool_id2str(ss, id);
572 id = stringpool_str2id(cbdata->ownspool, str, 1);
573 if (id >= cbdata->needid[0].map)
575 int oldoff = cbdata->needid[0].map;
576 int newoff = (id + 1 + NEEDED_BLOCK) & ~NEEDED_BLOCK;
577 int nrels = cbdata->repo->pool->nrels;
578 cbdata->needid = solv_realloc2(cbdata->needid, newoff + nrels, sizeof(NeedId));
580 memmove(cbdata->needid + newoff, cbdata->needid + oldoff, nrels * sizeof(NeedId));
581 memset(cbdata->needid + oldoff, 0, (newoff - oldoff) * sizeof(NeedId));
582 cbdata->needid[0].map = newoff;
588 putinowndirpool(struct cbdata *cbdata, Repodata *data, Dirpool *dp, Id dir)
592 parent = dirpool_parent(dp, dir);
594 parent = putinowndirpool(cbdata, data, dp, parent);
595 compid = dp->dirs[dir];
596 if (cbdata->ownspool && compid > 1)
597 compid = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, compid);
598 return dirpool_add_dir(cbdata->owndirpool, parent, compid, 1);
602 * collect usage information about the dirs
603 * 1: dir used, no child of dir used
604 * 2: dir used as parent of another used dir
607 setdirused(struct cbdata *cbdata, Dirpool *dp, Id dir)
609 if (cbdata->dirused[dir])
611 cbdata->dirused[dir] = 1;
612 while ((dir = dirpool_parent(dp, dir)) != 0)
614 if (cbdata->dirused[dir] == 2)
616 if (cbdata->dirused[dir])
618 cbdata->dirused[dir] = 2;
621 cbdata->dirused[dir] = 2;
623 cbdata->dirused[0] = 2;
628 * collect key/id/dirid usage information, create needed schemas
631 repo_write_collect_needed(struct cbdata *cbdata, Repo *repo, Repodata *data, Repokey *key, KeyValue *kv)
636 if (key->name == REPOSITORY_SOLVABLES)
637 return SEARCH_NEXT_KEY; /* we do not want this one */
639 /* hack: ignore some keys, see BUGS */
640 if (data->repodataid != data->repo->nrepodata - 1)
641 if (key->name == REPOSITORY_ADDEDFILEPROVIDES || key->name == REPOSITORY_EXTERNAL || key->name == REPOSITORY_LOCATION || key->name == REPOSITORY_KEYS || key->name == REPOSITORY_TOOLVERSION)
642 return SEARCH_NEXT_KEY;
644 rm = cbdata->keymap[cbdata->keymapstart[data->repodataid] + (key - data->keys)];
646 return SEARCH_NEXT_KEY; /* we do not want this one */
648 /* record key in schema */
649 if ((key->type != REPOKEY_TYPE_FIXARRAY || kv->eof == 0)
650 && (cbdata->sp == cbdata->schema || cbdata->sp[-1] != rm))
655 case REPOKEY_TYPE_ID:
656 case REPOKEY_TYPE_IDARRAY:
658 if (!ISRELDEP(id) && cbdata->ownspool && id > 1)
659 id = putinownpool(cbdata, data->localpool ? &data->spool : &repo->pool->ss, id);
660 incneedid(repo->pool, id, cbdata->needid);
662 case REPOKEY_TYPE_DIR:
663 case REPOKEY_TYPE_DIRNUMNUMARRAY:
664 case REPOKEY_TYPE_DIRSTRARRAY:
666 if (cbdata->owndirpool)
667 putinowndirpool(cbdata, data, &data->dirpool, id);
669 setdirused(cbdata, &data->dirpool, id);
671 case REPOKEY_TYPE_FIXARRAY:
674 if (cbdata->oldschema)
676 fprintf(stderr, "nested structs not yet implemented\n");
679 cbdata->oldschema = cbdata->schema;
680 cbdata->oldsp = cbdata->sp;
681 cbdata->schema = solv_calloc(cbdata->target->nkeys, sizeof(Id));
682 cbdata->sp = cbdata->schema;
684 else if (kv->eof == 1)
686 cbdata->current_sub++;
688 cbdata->subschemata = solv_extend(cbdata->subschemata, cbdata->nsubschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
689 cbdata->subschemata[cbdata->nsubschemata++] = repodata_schema2id(cbdata->target, cbdata->schema, 1);
691 fprintf(stderr, "Have schema %d\n", cbdata->subschemata[cbdata->nsubschemata-1]);
693 cbdata->sp = cbdata->schema;
697 solv_free(cbdata->schema);
698 cbdata->schema = cbdata->oldschema;
699 cbdata->sp = cbdata->oldsp;
700 cbdata->oldsp = cbdata->oldschema = 0;
703 case REPOKEY_TYPE_FLEXARRAY:
707 *cbdata->sp++ = 0; /* mark start */
711 /* just finished a schema, rewind */
712 Id *sp = cbdata->sp - 1;
716 cbdata->subschemata = solv_extend(cbdata->subschemata, cbdata->nsubschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
717 cbdata->subschemata[cbdata->nsubschemata++] = repodata_schema2id(cbdata->target, sp, 1);
718 cbdata->sp = kv->eof == 2 ? sp - 1: sp;
728 repo_write_cb_needed(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
730 struct cbdata *cbdata = vcbdata;
731 Repo *repo = data->repo;
735 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);
737 return repo_write_collect_needed(cbdata, repo, data, key, kv);
743 * encode all of the data into the correct buffers
747 repo_write_adddata(struct cbdata *cbdata, Repodata *data, Repokey *key, KeyValue *kv)
756 if (key->name == REPOSITORY_SOLVABLES)
757 return SEARCH_NEXT_KEY;
759 /* hack: ignore some keys, see BUGS */
760 if (data->repodataid != data->repo->nrepodata - 1)
761 if (key->name == REPOSITORY_ADDEDFILEPROVIDES || key->name == REPOSITORY_EXTERNAL || key->name == REPOSITORY_LOCATION || key->name == REPOSITORY_KEYS || key->name == REPOSITORY_TOOLVERSION)
762 return SEARCH_NEXT_KEY;
764 rm = cbdata->keymap[cbdata->keymapstart[data->repodataid] + (key - data->keys)];
766 return SEARCH_NEXT_KEY; /* we do not want this one */
768 if (cbdata->target->keys[rm].storage == KEY_STORAGE_VERTICAL_OFFSET)
770 xd = cbdata->extdata + rm; /* vertical buffer */
771 if (cbdata->vstart == -1)
772 cbdata->vstart = xd->len;
775 xd = cbdata->extdata + 0; /* incore buffer */
778 case REPOKEY_TYPE_VOID:
779 case REPOKEY_TYPE_CONSTANT:
780 case REPOKEY_TYPE_CONSTANTID:
782 case REPOKEY_TYPE_ID:
784 if (!ISRELDEP(id) && cbdata->ownspool && id > 1)
785 id = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, id);
786 needid = cbdata->needid;
787 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
790 case REPOKEY_TYPE_IDARRAY:
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;
796 data_addideof(xd, id, kv->eof);
798 case REPOKEY_TYPE_STR:
799 data_addblob(xd, (unsigned char *)kv->str, strlen(kv->str) + 1);
801 case REPOKEY_TYPE_MD5:
802 data_addblob(xd, (unsigned char *)kv->str, SIZEOF_MD5);
804 case REPOKEY_TYPE_SHA1:
805 data_addblob(xd, (unsigned char *)kv->str, SIZEOF_SHA1);
807 case REPOKEY_TYPE_SHA256:
808 data_addblob(xd, (unsigned char *)kv->str, SIZEOF_SHA256);
810 case REPOKEY_TYPE_U32:
816 data_addblob(xd, v, 4);
818 case REPOKEY_TYPE_NUM:
819 data_addid64(xd, kv->num, kv->num2);
821 case REPOKEY_TYPE_DIR:
823 if (cbdata->owndirpool)
824 id = putinowndirpool(cbdata, data, &data->dirpool, id);
825 id = cbdata->dirused[id];
828 case REPOKEY_TYPE_BINARY:
829 data_addid(xd, kv->num);
831 data_addblob(xd, (unsigned char *)kv->str, kv->num);
833 case REPOKEY_TYPE_DIRNUMNUMARRAY:
835 if (cbdata->owndirpool)
836 id = putinowndirpool(cbdata, data, &data->dirpool, id);
837 id = cbdata->dirused[id];
839 data_addid(xd, kv->num);
840 data_addideof(xd, kv->num2, kv->eof);
842 case REPOKEY_TYPE_DIRSTRARRAY:
844 if (cbdata->owndirpool)
845 id = putinowndirpool(cbdata, data, &data->dirpool, id);
846 id = cbdata->dirused[id];
847 data_addideof(xd, id, kv->eof);
848 data_addblob(xd, (unsigned char *)kv->str, strlen(kv->str) + 1);
850 case REPOKEY_TYPE_FIXARRAY:
855 data_addid(xd, kv->num);
856 data_addid(xd, cbdata->subschemata[cbdata->current_sub]);
858 fprintf(stderr, "writing %d %d\n", kv->num, cbdata->subschemata[cbdata->current_sub]);
862 else if (kv->eof == 1)
864 cbdata->current_sub++;
867 case REPOKEY_TYPE_FLEXARRAY:
869 data_addid(xd, kv->num);
871 data_addid(xd, cbdata->subschemata[cbdata->current_sub++]);
872 if (xd == cbdata->extdata + 0 && !kv->parent && !cbdata->doingsolvables)
874 if (xd->len - cbdata->lastlen > cbdata->maxdata)
875 cbdata->maxdata = xd->len - cbdata->lastlen;
876 cbdata->lastlen = xd->len;
880 fprintf(stderr, "unknown type for %d: %d\n", key->name, key->type);
883 if (cbdata->target->keys[rm].storage == KEY_STORAGE_VERTICAL_OFFSET && kv->eof)
885 /* we can re-use old data in the blob here! */
886 data_addid(cbdata->extdata + 0, cbdata->vstart); /* add offset into incore data */
887 data_addid(cbdata->extdata + 0, xd->len - cbdata->vstart); /* add length into incore data */
894 repo_write_cb_adddata(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
896 struct cbdata *cbdata = vcbdata;
897 return repo_write_adddata(cbdata, data, key, kv);
900 /* traverse through directory with first child "dir" */
902 traverse_dirs(Dirpool *dp, Id *dirmap, Id n, Id dir, Id *used)
908 /* special case for '/', which has to come first */
911 for (sib = dir; sib; sib = dirpool_sibling(dp, sib))
913 if (used && !used[sib])
915 if (sib == 1 && parent == 1)
916 continue; /* already did that one above */
920 /* now go through all the siblings we just added and
921 * do recursive calls on them */
923 for (; parent < lastn; parent++)
925 sib = dirmap[parent];
926 if (used && used[sib] != 2) /* 2: used as parent */
928 child = dirpool_child(dp, sib);
931 dirmap[n++] = -parent; /* start new block */
932 n = traverse_dirs(dp, dirmap, n, child, used);
939 write_compressed_page(FILE *fp, unsigned char *page, int len)
942 unsigned char cpage[REPOPAGE_BLOBSIZE];
944 clen = repopagestore_compress_page(page, len, cpage, len - 1);
947 write_u32(fp, len * 2);
948 write_blob(fp, page, len);
952 write_u32(fp, clen * 2 + 1);
953 write_blob(fp, cpage, clen);
957 static Id verticals[] = {
959 SOLVABLE_DESCRIPTION,
971 static char *languagetags[] = {
973 "solvable:description:",
974 "solvable:messageins:",
975 "solvable:messagedel:",
981 repo_write_stdkeyfilter(Repo *repo, Repokey *key, void *kfdata)
986 for (i = 0; verticals[i]; i++)
987 if (key->name == verticals[i])
988 return KEY_STORAGE_VERTICAL_OFFSET;
989 keyname = pool_id2str(repo->pool, key->name);
990 for (i = 0; languagetags[i] != 0; i++)
991 if (!strncmp(keyname, languagetags[i], strlen(languagetags[i])))
992 return KEY_STORAGE_VERTICAL_OFFSET;
993 return KEY_STORAGE_INCORE;
1001 * the code works the following way:
1003 * 1) find which keys should be written
1004 * 2) collect usage information for keys/ids/dirids, create schema
1006 * 3) use usage information to create mapping tables, so that often
1007 * used ids get a lower number
1008 * 4) encode data into buffers using the mapping tables
1009 * 5) write everything to disk
1012 repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq)
1014 Pool *pool = repo->pool;
1018 int nstrings, nrels;
1019 unsigned int sizeid;
1020 unsigned int solv_flags;
1029 unsigned char *repodataused;
1030 int anyrepodataused = 0;
1031 int anysolvableused = 0;
1033 struct cbdata cbdata;
1036 int poolusage, dirpoolusage, idused, dirused;
1039 Repodata *data, *dirpooldata;
1050 Id type_constantid = REPOKEY_TYPE_CONSTANTID;
1052 unsigned char *prefixcomp;
1053 unsigned int compsum;
1057 memset(&cbdata, 0, sizeof(cbdata));
1059 cbdata.target = ⌖
1061 repodata_initdata(&target, repo, 1);
1063 /* go through all repodata and find the keys we need */
1064 /* also unify keys */
1065 /* keymapstart - maps repo number to keymap offset */
1066 /* keymap - maps repo key to my key, 0 -> not used */
1068 /* start with all KEY_STORAGE_SOLVABLE ids */
1070 n = ID_NUM_INTERNAL;
1071 FOR_REPODATAS(repo, i, data)
1073 cbdata.keymap = solv_calloc(n, sizeof(Id));
1074 cbdata.keymapstart = solv_calloc(repo->nrepodata, sizeof(Id));
1075 repodataused = solv_calloc(repo->nrepodata, 1);
1080 /* add keys for STORAGE_SOLVABLE */
1081 for (i = SOLVABLE_NAME; i <= RPM_RPMDBID; i++)
1085 if (i < SOLVABLE_PROVIDES)
1086 keyd.type = REPOKEY_TYPE_ID;
1087 else if (i < RPM_RPMDBID)
1088 keyd.type = REPOKEY_TYPE_REL_IDARRAY;
1090 keyd.type = REPOKEY_TYPE_NUM;
1092 keyd.storage = KEY_STORAGE_SOLVABLE;
1095 keyd.storage = keyfilter(repo, &keyd, kfdata);
1096 if (keyd.storage == KEY_STORAGE_DROPPED)
1098 keyd.storage = KEY_STORAGE_SOLVABLE;
1102 cbdata.keymap[keyd.name] = repodata_key2id(&target, &keyd, 1);
1105 if (repo->nsolvables)
1108 keyd.name = REPOSITORY_SOLVABLES;
1109 keyd.type = REPOKEY_TYPE_FLEXARRAY;
1111 keyd.storage = KEY_STORAGE_INCORE;
1112 cbdata.keymap[keyd.name] = repodata_key2id(&target, &keyd, 1);
1120 n = ID_NUM_INTERNAL;
1121 FOR_REPODATAS(repo, i, data)
1123 cbdata.keymapstart[i] = n;
1124 cbdata.keymap[n++] = 0; /* key 0 */
1130 /* check if we want this repodata */
1131 memset(&keyd, 0, sizeof(keyd));
1135 if (keyfilter(repo, &keyd, kfdata) == -1)
1138 for (j = 1; j < data->nkeys; j++, n++)
1140 key = data->keys + j;
1141 if (key->name == REPOSITORY_SOLVABLES && key->type == REPOKEY_TYPE_FLEXARRAY)
1143 cbdata.keymap[n] = cbdata.keymap[key->name];
1146 if (key->type == REPOKEY_TYPE_DELETED)
1148 cbdata.keymap[n] = 0;
1151 if (key->type == REPOKEY_TYPE_CONSTANTID && data->localpool)
1153 Repokey keyd = *key;
1154 keyd.size = repodata_globalize_id(data, key->size, 1);
1155 id = repodata_key2id(&target, &keyd, 0);
1158 id = repodata_key2id(&target, key, 0);
1161 Repokey keyd = *key;
1162 keyd.storage = KEY_STORAGE_INCORE;
1163 if (keyd.type == REPOKEY_TYPE_CONSTANTID)
1164 keyd.size = repodata_globalize_id(data, key->size, 1);
1165 else if (keyd.type != REPOKEY_TYPE_CONSTANT)
1169 keyd.storage = keyfilter(repo, &keyd, kfdata);
1170 if (keyd.storage == KEY_STORAGE_DROPPED)
1172 cbdata.keymap[n] = 0;
1176 id = repodata_key2id(&target, &keyd, 1);
1178 cbdata.keymap[n] = id;
1179 /* load repodata if not already loaded */
1180 if (data->state == REPODATA_STUB)
1182 if (data->loadcallback)
1183 data->loadcallback(data);
1185 data->state = REPODATA_ERROR;
1186 if (data->state != REPODATA_ERROR)
1188 /* redo this repodata! */
1190 n = cbdata.keymapstart[i];
1194 if (data->state == REPODATA_ERROR)
1197 cbdata.keymap[n] = 0;
1201 repodataused[i] = 1;
1202 anyrepodataused = 1;
1203 if (key->type == REPOKEY_TYPE_CONSTANTID || key->type == REPOKEY_TYPE_ID ||
1204 key->type == REPOKEY_TYPE_IDARRAY || key->type == REPOKEY_TYPE_REL_IDARRAY)
1206 else if (key->type == REPOKEY_TYPE_DIR || key->type == REPOKEY_TYPE_DIRNUMNUMARRAY || key->type == REPOKEY_TYPE_DIRSTRARRAY)
1208 idused = 1; /* dirs also use ids */
1214 if (data->localpool)
1217 poolusage = 3; /* need own pool */
1221 spool = &data->spool;
1228 else if (poolusage != 1)
1229 poolusage = 3; /* need own pool */
1235 dirpoolusage = 3; /* need own dirpool */
1239 dirpool = &data->dirpool;
1246 /* 0: no pool needed at all */
1247 /* 1: use global pool */
1248 /* 2: use repodata local pool */
1249 /* 3: need own pool */
1252 spool = &target.spool;
1253 /* hack: reuse global pool data so we don't have to map pool ids */
1256 stringpool_free(spool);
1257 stringpool_clone(spool, &pool->ss);
1259 cbdata.ownspool = spool;
1261 else if (poolusage == 0 || poolusage == 1)
1267 if (dirpoolusage == 3)
1269 dirpool = &target.dirpool;
1271 cbdata.owndirpool = dirpool;
1274 cbdata.dirused = solv_calloc(dirpool->ndirs, sizeof(Id));
1277 /********************************************************************/
1279 fprintf(stderr, "poolusage: %d\n", poolusage);
1280 fprintf(stderr, "dirpoolusage: %d\n", dirpoolusage);
1281 fprintf(stderr, "nkeys: %d\n", target.nkeys);
1282 for (i = 1; i < target.nkeys; i++)
1283 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);
1286 /* copy keys if requested */
1290 for (i = 1; i < target.nkeys; i++)
1291 queue_push2(keyq, target.keys[i].name, target.keys[i].type);
1296 /* put all the keys we need in our string pool */
1297 /* put mapped ids right into target.keys */
1298 for (i = 1, key = target.keys + i; i < target.nkeys; i++, key++)
1300 key->name = stringpool_str2id(spool, pool_id2str(pool, key->name), 1);
1301 if (key->type == REPOKEY_TYPE_CONSTANTID)
1303 key->type = stringpool_str2id(spool, pool_id2str(pool, key->type), 1);
1304 type_constantid = key->type;
1305 key->size = stringpool_str2id(spool, pool_id2str(pool, key->size), 1);
1308 key->type = stringpool_str2id(spool, pool_id2str(pool, key->type), 1);
1311 stringpool_freehash(spool); /* free some mem */
1315 /********************************************************************/
1317 /* set needed count of all strings and rels,
1318 * find which keys are used in the solvables
1319 * put all strings in own spool
1322 reloff = spool->nstrings;
1324 reloff = (reloff + NEEDED_BLOCK) & ~NEEDED_BLOCK;
1326 needid = calloc(reloff + pool->nrels, sizeof(*needid));
1327 needid[0].map = reloff;
1329 cbdata.needid = needid;
1330 cbdata.schema = solv_calloc(target.nkeys, sizeof(Id));
1331 cbdata.sp = cbdata.schema;
1332 cbdata.solvschemata = solv_calloc(repo->nsolvables, sizeof(Id));
1334 /* create main schema */
1335 cbdata.sp = cbdata.schema;
1336 /* collect all other data from all repodatas */
1337 /* XXX: merge arrays of equal keys? */
1338 FOR_REPODATAS(repo, j, data)
1340 if (!repodataused[j])
1342 repodata_search(data, SOLVID_META, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_needed, &cbdata);
1345 /* add solvables if needed (may revert later) */
1346 if (repo->nsolvables)
1348 *sp++ = cbdata.keymap[REPOSITORY_SOLVABLES];
1349 target.keys[cbdata.keymap[REPOSITORY_SOLVABLES]].size++;
1352 mainschema = repodata_schema2id(cbdata.target, cbdata.schema, 1);
1354 idarraydata = repo->idarraydata;
1356 anysolvableused = 0;
1357 cbdata.doingsolvables = 1;
1358 for (i = repo->start, s = pool->solvables + i, n = 0; i < repo->end; i++, s++)
1360 if (s->repo != repo)
1363 /* set schema info, keep in sync with further down */
1365 if (cbdata.keymap[SOLVABLE_NAME])
1367 *sp++ = cbdata.keymap[SOLVABLE_NAME];
1368 needid[s->name].need++;
1370 if (cbdata.keymap[SOLVABLE_ARCH])
1372 *sp++ = cbdata.keymap[SOLVABLE_ARCH];
1373 needid[s->arch].need++;
1375 if (cbdata.keymap[SOLVABLE_EVR])
1377 *sp++ = cbdata.keymap[SOLVABLE_EVR];
1378 needid[s->evr].need++;
1380 if (s->vendor && cbdata.keymap[SOLVABLE_VENDOR])
1382 *sp++ = cbdata.keymap[SOLVABLE_VENDOR];
1383 needid[s->vendor].need++;
1385 if (s->provides && cbdata.keymap[SOLVABLE_PROVIDES])
1387 *sp++ = cbdata.keymap[SOLVABLE_PROVIDES];
1388 target.keys[cbdata.keymap[SOLVABLE_PROVIDES]].size += incneedidarray(pool, idarraydata + s->provides, needid);
1390 if (s->obsoletes && cbdata.keymap[SOLVABLE_OBSOLETES])
1392 *sp++ = cbdata.keymap[SOLVABLE_OBSOLETES];
1393 target.keys[cbdata.keymap[SOLVABLE_OBSOLETES]].size += incneedidarray(pool, idarraydata + s->obsoletes, needid);
1395 if (s->conflicts && cbdata.keymap[SOLVABLE_CONFLICTS])
1397 *sp++ = cbdata.keymap[SOLVABLE_CONFLICTS];
1398 target.keys[cbdata.keymap[SOLVABLE_CONFLICTS]].size += incneedidarray(pool, idarraydata + s->conflicts, needid);
1400 if (s->requires && cbdata.keymap[SOLVABLE_REQUIRES])
1402 *sp++ = cbdata.keymap[SOLVABLE_REQUIRES];
1403 target.keys[cbdata.keymap[SOLVABLE_REQUIRES]].size += incneedidarray(pool, idarraydata + s->requires, needid);
1405 if (s->recommends && cbdata.keymap[SOLVABLE_RECOMMENDS])
1407 *sp++ = cbdata.keymap[SOLVABLE_RECOMMENDS];
1408 target.keys[cbdata.keymap[SOLVABLE_RECOMMENDS]].size += incneedidarray(pool, idarraydata + s->recommends, needid);
1410 if (s->suggests && cbdata.keymap[SOLVABLE_SUGGESTS])
1412 *sp++ = cbdata.keymap[SOLVABLE_SUGGESTS];
1413 target.keys[cbdata.keymap[SOLVABLE_SUGGESTS]].size += incneedidarray(pool, idarraydata + s->suggests, needid);
1415 if (s->supplements && cbdata.keymap[SOLVABLE_SUPPLEMENTS])
1417 *sp++ = cbdata.keymap[SOLVABLE_SUPPLEMENTS];
1418 target.keys[cbdata.keymap[SOLVABLE_SUPPLEMENTS]].size += incneedidarray(pool, idarraydata + s->supplements, needid);
1420 if (s->enhances && cbdata.keymap[SOLVABLE_ENHANCES])
1422 *sp++ = cbdata.keymap[SOLVABLE_ENHANCES];
1423 target.keys[cbdata.keymap[SOLVABLE_ENHANCES]].size += incneedidarray(pool, idarraydata + s->enhances, needid);
1425 if (repo->rpmdbid && cbdata.keymap[RPM_RPMDBID])
1427 *sp++ = cbdata.keymap[RPM_RPMDBID];
1428 target.keys[cbdata.keymap[RPM_RPMDBID]].size++;
1432 if (anyrepodataused)
1434 FOR_REPODATAS(repo, j, data)
1436 if (!repodataused[j])
1438 if (i < data->start || i >= data->end)
1440 repodata_search(data, i, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_needed, &cbdata);
1441 needid = cbdata.needid;
1445 cbdata.solvschemata[n] = repodata_schema2id(cbdata.target, cbdata.schema, 1);
1446 if (cbdata.solvschemata[n])
1447 anysolvableused = 1;
1450 cbdata.doingsolvables = 0;
1451 assert(n == repo->nsolvables);
1453 if (repo->nsolvables && !anysolvableused)
1455 /* strip off solvable from the main schema */
1456 target.keys[cbdata.keymap[REPOSITORY_SOLVABLES]].size = 0;
1458 for (i = 0; target.schemadata[target.schemata[mainschema] + i]; i++)
1460 *sp = target.schemadata[target.schemata[mainschema] + i];
1461 if (*sp != cbdata.keymap[REPOSITORY_SOLVABLES])
1464 assert(target.schemadatalen == target.schemata[mainschema] + i + 1);
1466 target.schemadatalen = target.schemata[mainschema];
1468 repodata_free_schemahash(&target);
1469 mainschema = repodata_schema2id(cbdata.target, cbdata.schema, 1);
1472 /********************************************************************/
1474 /* remove unused keys */
1475 keyused = solv_calloc(target.nkeys, sizeof(Id));
1476 for (i = 1; i < target.schemadatalen; i++)
1477 keyused[target.schemadata[i]] = 1;
1479 for (n = i = 1; i < target.nkeys; i++)
1486 target.keys[n] = target.keys[i];
1489 keyq->elements[2 * n - 2] = keyq->elements[2 * i - 2];
1490 keyq->elements[2 * n - 1] = keyq->elements[2 * i - 1];
1497 queue_truncate(keyq, 2 * n - 2);
1499 /* update schema data to the new key ids */
1500 for (i = 1; i < target.schemadatalen; i++)
1501 target.schemadata[i] = keyused[target.schemadata[i]];
1502 /* update keymap to the new key ids */
1503 for (i = 0; i < cbdata.nkeymap; i++)
1504 cbdata.keymap[i] = keyused[cbdata.keymap[i]];
1505 keyused = solv_free(keyused);
1507 /* increment needid of the used keys, they are already mapped to
1508 * the correct string pool */
1509 for (i = 1; i < target.nkeys; i++)
1511 if (target.keys[i].type == type_constantid)
1512 needid[target.keys[i].size].need++;
1513 needid[target.keys[i].name].need++;
1514 needid[target.keys[i].type].need++;
1517 /********************************************************************/
1519 if (dirpool && cbdata.dirused && !cbdata.dirused[0])
1521 /* no dirs used at all */
1522 cbdata.dirused = solv_free(cbdata.dirused);
1526 /* increment need id for used dir components */
1529 /* if we have own dirpool, all entries in it are used.
1530 also, all comp ids are already mapped by putinowndirpool(),
1531 so we can simply increment needid.
1532 (owndirpool != 0, dirused == 0, dirpooldata == 0) */
1533 /* else we re-use a dirpool of repodata "dirpooldata".
1534 dirused tells us which of the ids are used.
1535 we need to map comp ids if we generate a new pool.
1536 (owndirpool == 0, dirused != 0, dirpooldata != 0) */
1537 for (i = 1; i < dirpool->ndirs; i++)
1540 fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1);
1542 if (cbdata.dirused && !cbdata.dirused[i])
1544 id = dirpool->dirs[i];
1547 if (dirpooldata && cbdata.ownspool && id > 1)
1549 id = putinownpool(&cbdata, dirpooldata->localpool ? &dirpooldata->spool : &pool->ss, id);
1550 needid = cbdata.needid;
1557 /********************************************************************/
1560 * create mapping table, new keys are sorted by needid[].need
1562 * needid[key].need : old key -> new key
1563 * needid[key].map : new key -> old key
1566 /* zero out id 0 and rel 0 just in case */
1567 reloff = needid[0].map;
1569 needid[reloff].need = 0;
1571 for (i = 1; i < reloff + pool->nrels; i++)
1575 solv_sort(needid + 1, spool->nstrings - 1, sizeof(*needid), needid_cmp_need_s, spool);
1577 /* make first entry '' */
1579 solv_sort(needid + 2, spool->nstrings - 2, sizeof(*needid), needid_cmp_need_s, spool);
1581 solv_sort(needid + reloff, pool->nrels, sizeof(*needid), needid_cmp_need, 0);
1582 /* now needid is in new order, needid[newid].map -> oldid */
1584 /* calculate string space size, also zero out needid[].need */
1586 for (i = 1; i < reloff; i++)
1588 if (!needid[i].need)
1589 break; /* as we have sorted, every entry after this also has need == 0 */
1591 sizeid += strlen(spool->stringspace + spool->strings[needid[i].map]) + 1;
1593 nstrings = i; /* our new string id end */
1595 /* make needid[oldid].need point to newid */
1596 for (i = 1; i < nstrings; i++)
1597 needid[needid[i].map].need = i;
1599 /* same as above for relations */
1600 for (i = 0; i < pool->nrels; i++)
1602 if (!needid[reloff + i].need)
1604 needid[reloff + i].need = 0;
1606 nrels = i; /* our new rel id end */
1608 for (i = 0; i < nrels; i++)
1609 needid[needid[reloff + i].map].need = nstrings + i;
1611 /* now we have: needid[oldid].need -> newid
1612 needid[newid].map -> oldid
1613 both for strings and relations */
1616 /********************************************************************/
1622 /* create our new target directory structure by traversing through all
1623 * used dirs. This will concatenate blocks with the same parent
1624 * directory into single blocks.
1625 * Instead of components, traverse_dirs stores the old dirids,
1626 * we will change this in the second step below */
1627 /* (dirpooldata and dirused are 0 if we have our own dirpool) */
1628 if (cbdata.dirused && !cbdata.dirused[1])
1629 cbdata.dirused[1] = 1; /* always want / entry */
1630 dirmap = solv_calloc(dirpool->ndirs, sizeof(Id));
1632 ndirmap = traverse_dirs(dirpool, dirmap, 1, dirpool_child(dirpool, 0), cbdata.dirused);
1634 /* (re)create dirused, so that it maps from "old dirid" to "new dirid" */
1635 /* change dirmap so that it maps from "new dirid" to "new compid" */
1636 if (!cbdata.dirused)
1637 cbdata.dirused = solv_malloc2(dirpool->ndirs, sizeof(Id));
1638 memset(cbdata.dirused, 0, dirpool->ndirs * sizeof(Id));
1639 for (i = 1; i < ndirmap; i++)
1643 cbdata.dirused[dirmap[i]] = i;
1644 id = dirpool->dirs[dirmap[i]];
1645 if (dirpooldata && cbdata.ownspool && id > 1)
1646 id = putinownpool(&cbdata, dirpooldata->localpool ? &dirpooldata->spool : &pool->ss, id);
1647 dirmap[i] = needid[id].need;
1649 /* now the new target directory structure is complete (dirmap), and we have
1650 * dirused[olddirid] -> newdirid */
1653 /********************************************************************/
1656 * we use extdata[0] for incore data and extdata[keyid] for vertical data
1659 cbdata.extdata = solv_calloc(target.nkeys, sizeof(struct extdata));
1661 xd = cbdata.extdata;
1662 cbdata.current_sub = 0;
1663 /* add main schema */
1665 data_addid(xd, mainschema);
1668 FOR_REPODATAS(repo, j, data)
1670 if (!repodataused[j])
1672 repodata_search(data, SOLVID_META, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_adddata, &cbdata);
1676 if (xd->len - cbdata.lastlen > cbdata.maxdata)
1677 cbdata.maxdata = xd->len - cbdata.lastlen;
1678 cbdata.lastlen = xd->len;
1680 if (anysolvableused)
1682 data_addid(xd, repo->nsolvables); /* FLEXARRAY nentries */
1683 cbdata.doingsolvables = 1;
1684 for (i = repo->start, s = pool->solvables + i, n = 0; i < repo->end; i++, s++)
1686 if (s->repo != repo)
1688 data_addid(xd, cbdata.solvschemata[n]);
1689 if (cbdata.keymap[SOLVABLE_NAME])
1690 data_addid(xd, needid[s->name].need);
1691 if (cbdata.keymap[SOLVABLE_ARCH])
1692 data_addid(xd, needid[s->arch].need);
1693 if (cbdata.keymap[SOLVABLE_EVR])
1694 data_addid(xd, needid[s->evr].need);
1695 if (s->vendor && cbdata.keymap[SOLVABLE_VENDOR])
1696 data_addid(xd, needid[s->vendor].need);
1697 if (s->provides && cbdata.keymap[SOLVABLE_PROVIDES])
1698 data_addidarray_sort(xd, pool, needid, idarraydata + s->provides, SOLVABLE_FILEMARKER);
1699 if (s->obsoletes && cbdata.keymap[SOLVABLE_OBSOLETES])
1700 data_addidarray_sort(xd, pool, needid, idarraydata + s->obsoletes, 0);
1701 if (s->conflicts && cbdata.keymap[SOLVABLE_CONFLICTS])
1702 data_addidarray_sort(xd, pool, needid, idarraydata + s->conflicts, 0);
1703 if (s->requires && cbdata.keymap[SOLVABLE_REQUIRES])
1704 data_addidarray_sort(xd, pool, needid, idarraydata + s->requires, SOLVABLE_PREREQMARKER);
1705 if (s->recommends && cbdata.keymap[SOLVABLE_RECOMMENDS])
1706 data_addidarray_sort(xd, pool, needid, idarraydata + s->recommends, 0);
1707 if (s->suggests && cbdata.keymap[SOLVABLE_SUGGESTS])
1708 data_addidarray_sort(xd, pool, needid, idarraydata + s->suggests, 0);
1709 if (s->supplements && cbdata.keymap[SOLVABLE_SUPPLEMENTS])
1710 data_addidarray_sort(xd, pool, needid, idarraydata + s->supplements, 0);
1711 if (s->enhances && cbdata.keymap[SOLVABLE_ENHANCES])
1712 data_addidarray_sort(xd, pool, needid, idarraydata + s->enhances, 0);
1713 if (repo->rpmdbid && cbdata.keymap[RPM_RPMDBID])
1714 data_addid(xd, repo->rpmdbid[i - repo->start]);
1715 if (anyrepodataused)
1718 FOR_REPODATAS(repo, j, data)
1720 if (!repodataused[j])
1722 if (i < data->start || i >= data->end)
1724 repodata_search(data, i, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_adddata, &cbdata);
1727 if (xd->len - cbdata.lastlen > cbdata.maxdata)
1728 cbdata.maxdata = xd->len - cbdata.lastlen;
1729 cbdata.lastlen = xd->len;
1732 cbdata.doingsolvables = 0;
1735 assert(cbdata.current_sub == cbdata.nsubschemata);
1736 if (cbdata.subschemata)
1738 cbdata.subschemata = solv_free(cbdata.subschemata);
1739 cbdata.nsubschemata = 0;
1742 /********************************************************************/
1746 /* write file header */
1747 write_u32(fp, 'S' << 24 | 'O' << 16 | 'L' << 8 | 'V');
1748 write_u32(fp, SOLV_VERSION_8);
1752 write_u32(fp, nstrings);
1753 write_u32(fp, nrels);
1754 write_u32(fp, ndirmap);
1755 write_u32(fp, anysolvableused ? repo->nsolvables : 0);
1756 write_u32(fp, target.nkeys);
1757 write_u32(fp, target.nschemata);
1759 solv_flags |= SOLV_FLAG_PREFIX_POOL;
1760 write_u32(fp, solv_flags);
1763 * calculate prefix encoding of the strings
1765 prefixcomp = solv_malloc(nstrings);
1770 for (i = 1; i < nstrings; i++)
1772 char *str = spool->stringspace + spool->strings[needid[i].map];
1774 for (same = 0; same < 255; same++)
1775 if (!old_str[same] || old_str[same] != str[same])
1777 prefixcomp[i] = same;
1785 write_u32(fp, sizeid);
1786 /* we save compsum bytes but need 1 extra byte for every string */
1787 write_u32(fp, sizeid + (nstrings ? nstrings - 1 : 0) - compsum);
1788 if (sizeid + (nstrings ? nstrings - 1 : 0) != compsum)
1790 for (i = 1; i < nstrings; i++)
1792 char *str = spool->stringspace + spool->strings[needid[i].map];
1793 write_u8(fp, prefixcomp[i]);
1794 write_str(fp, str + prefixcomp[i]);
1797 solv_free(prefixcomp);
1800 /* Build the prefix-encoding of the string pool. We need to know
1801 the size of that before writing it to the file, so we have to
1802 build a separate buffer for that. As it's temporarily possible
1803 that this actually is an expansion we can't easily reuse the
1804 stringspace for this. The max expansion per string is 1 byte,
1805 so it will fit into sizeid+nstrings bytes. */
1806 char *prefix = solv_malloc(sizeid + nstrings);
1809 for (i = 1; i < nstrings; i++)
1811 char *str = spool->stringspace + spool->strings[needid[i].map];
1814 for (same = 0; same < 255; same++)
1815 if (!old_str[same] || !str[same] || old_str[same] != str[same])
1818 len = strlen(str + same) + 1;
1819 memcpy(pp, str + same, len);
1827 write_u32(fp, sizeid);
1828 write_u32(fp, pp - prefix);
1831 if (fwrite(prefix, pp - prefix, 1, fp) != 1)
1833 perror("write error prefix");
1843 for (i = 0; i < nrels; i++)
1845 ran = pool->rels + (needid[reloff + i].map - reloff);
1846 write_id(fp, needid[ISRELDEP(ran->name) ? RELOFF(ran->name) : ran->name].need);
1847 write_id(fp, needid[ISRELDEP(ran->evr) ? RELOFF(ran->evr) : ran->evr].need);
1848 write_u8(fp, ran->flags);
1852 * write dirs (skip both root and / entry)
1854 for (i = 2; i < ndirmap; i++)
1857 write_id(fp, dirmap[i]);
1859 write_id(fp, nstrings - dirmap[i]);
1866 for (i = 1; i < target.nkeys; i++)
1868 write_id(fp, needid[target.keys[i].name].need);
1869 write_id(fp, needid[target.keys[i].type].need);
1870 if (target.keys[i].storage != KEY_STORAGE_VERTICAL_OFFSET)
1872 if (target.keys[i].type == type_constantid)
1873 write_id(fp, needid[target.keys[i].size].need);
1875 write_id(fp, target.keys[i].size);
1878 write_id(fp, cbdata.extdata[i].len);
1879 write_id(fp, target.keys[i].storage);
1885 write_id(fp, target.schemadatalen); /* XXX -1? */
1886 for (i = 1; i < target.nschemata; i++)
1887 write_idarray(fp, pool, 0, repodata_id2schema(&target, i));
1889 /********************************************************************/
1891 write_id(fp, cbdata.maxdata);
1892 write_id(fp, cbdata.extdata[0].len);
1893 if (cbdata.extdata[0].len)
1894 write_blob(fp, cbdata.extdata[0].buf, cbdata.extdata[0].len);
1895 solv_free(cbdata.extdata[0].buf);
1897 /* do we have vertical data? */
1898 for (i = 1; i < target.nkeys; i++)
1899 if (cbdata.extdata[i].len)
1901 if (i < target.nkeys)
1903 /* yes, write it in pages */
1904 unsigned char *dp, vpage[REPOPAGE_BLOBSIZE];
1905 int l, ll, lpage = 0;
1907 write_u32(fp, REPOPAGE_BLOBSIZE);
1908 for (i = 1; i < target.nkeys; i++)
1910 if (!cbdata.extdata[i].len)
1912 l = cbdata.extdata[i].len;
1913 dp = cbdata.extdata[i].buf;
1916 ll = REPOPAGE_BLOBSIZE - lpage;
1919 memcpy(vpage + lpage, dp, ll);
1923 if (lpage == REPOPAGE_BLOBSIZE)
1925 write_compressed_page(fp, vpage, lpage);
1931 write_compressed_page(fp, vpage, lpage);
1934 for (i = 1; i < target.nkeys; i++)
1935 solv_free(cbdata.extdata[i].buf);
1936 solv_free(cbdata.extdata);
1938 repodata_freedata(&target);
1941 solv_free(cbdata.solvschemata);
1942 solv_free(cbdata.schema);
1944 solv_free(cbdata.keymap);
1945 solv_free(cbdata.keymapstart);
1946 solv_free(cbdata.dirused);
1947 solv_free(repodataused);
1951 struct repodata_write_data {
1952 int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata);
1958 repodata_write_keyfilter(Repo *repo, Repokey *key, void *kfdata)
1960 struct repodata_write_data *wd = kfdata;
1962 /* XXX: special repodata selection hack */
1963 if (key->name == 1 && key->size != wd->repodataid)
1965 if (key->storage == KEY_STORAGE_SOLVABLE)
1966 return KEY_STORAGE_DROPPED; /* not part of this repodata */
1968 return (*wd->keyfilter)(repo, key, wd->kfdata);
1969 return key->storage;
1973 repodata_write_filtered(Repodata *data, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq)
1975 struct repodata_write_data wd;
1977 wd.keyfilter = keyfilter;
1979 wd.repodataid = data->repodataid;
1980 return repo_write_filtered(data->repo, fp, repodata_write_keyfilter, &wd, keyq);
1984 repodata_write(Repodata *data, FILE *fp)
1986 return repodata_write_filtered(data, fp, repo_write_stdkeyfilter, 0, 0);
1990 repo_write(Repo *repo, FILE *fp)
1992 return repo_write_filtered(repo, fp, repo_write_stdkeyfilter, 0, 0);