diff --git a/0002-Add-repodata_lookup_dirstrarray_uninternalized-metho.patch b/0002-Add-repodata_lookup_dirstrarray_uninternalized-metho.patch new file mode 100644 index 0000000..d0fc869 --- /dev/null +++ b/0002-Add-repodata_lookup_dirstrarray_uninternalized-metho.patch @@ -0,0 +1,79 @@ +From f362259ac2f92c6c1914974032f2f7c436ac00d4 Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Fri, 26 Feb 2016 11:45:09 +0100 +Subject: [PATCH 1/9] Add repodata_lookup_dirstrarray_uninternalized method + +Needed for next commit. +--- + src/libsolv.ver | 1 + + src/repodata.c | 25 +++++++++++++++++++++++++ + src/repodata.h | 3 +++ + 3 files changed, 29 insertions(+) + +diff --git a/src/libsolv.ver b/src/libsolv.ver +index 6508288..cc79704 100644 +--- a/src/libsolv.ver ++++ b/src/libsolv.ver +@@ -201,6 +201,7 @@ SOLV_1.0 { + repodata_key2id; + repodata_localize_id; + repodata_lookup_bin_checksum; ++ repodata_lookup_bin_checksum_uninternalized; + repodata_lookup_binary; + repodata_lookup_dirstrarray_uninternalized; + repodata_lookup_id; +diff --git a/src/repodata.c b/src/repodata.c +index ad3e71a..b611afc 100644 +--- a/src/repodata.c ++++ b/src/repodata.c +@@ -881,6 +881,31 @@ repodata_lookup_dirstrarray_uninternalized(Repodata *data, Id solvid, Id keyname + return 0; + } + ++const unsigned char * ++repodata_lookup_bin_checksum_uninternalized(Repodata *data, Id solvid, Id keyname, Id *typep) ++{ ++ Id *ap; ++ if (!data->attrs) ++ return 0; ++ ap = data->attrs[solvid - data->start]; ++ if (!ap) ++ return 0; ++ for (; *ap; ap += 2) ++ { ++ if (data->keys[*ap].name != keyname) ++ continue; ++ switch (data->keys[*ap].type) ++ { ++ case_CHKSUM_TYPES: ++ *typep = data->keys[*ap].type; ++ return (const unsigned char *)data->attrdata + ap[1]; ++ default: ++ break; ++ } ++ } ++ return 0; ++} ++ + /************************************************************************ + * data search + */ +diff --git a/src/repodata.h b/src/repodata.h +index c18c688..d72c60f 100644 +--- a/src/repodata.h ++++ b/src/repodata.h +@@ -300,8 +300,11 @@ const char *repodata_chk2str(Repodata *data, Id type, const unsigned char *buf); + void repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file); + void repodata_set_deltalocation(Repodata *data, Id handle, int medianr, const char *dir, const char *file); + void repodata_set_sourcepkg(Repodata *data, Id solvid, const char *sourcepkg); ++ ++/* uninternalized data lookup */ + Id repodata_lookup_id_uninternalized(Repodata *data, Id solvid, Id keyname, Id voidid); + const char *repodata_lookup_dirstrarray_uninternalized(Repodata *data, Id solvid, Id keyname, Id *didp, Id *iterp); ++const unsigned char *repodata_lookup_bin_checksum_uninternalized(Repodata *data, Id solvid, Id keyname, Id *typep); + + /* stats */ + unsigned int repodata_memused(Repodata *data); +-- +2.5.0 + diff --git a/0003-Do-not-create-a-checksum-hash-when-we-re-not-extendi.patch b/0003-Do-not-create-a-checksum-hash-when-we-re-not-extendi.patch new file mode 100644 index 0000000..de4b9d7 --- /dev/null +++ b/0003-Do-not-create-a-checksum-hash-when-we-re-not-extendi.patch @@ -0,0 +1,272 @@ +From 0280a6a08344a11c8fd0e0226263cc8a808fd4c1 Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Fri, 26 Feb 2016 11:45:27 +0100 +Subject: [PATCH 2/9] Do not create a checksum hash when we're not extending + +Many repos don't have extension data, so we postpone the +hash creation until we need it. +--- + ext/repo_rpmmd.c | 165 +++++++++++++++++++++++++++++++++++++++---------------- + 1 file changed, 117 insertions(+), 48 deletions(-) + +diff --git a/ext/repo_rpmmd.c b/ext/repo_rpmmd.c +index a45d491..cc54b3e 100644 +--- a/ext/repo_rpmmd.c ++++ b/ext/repo_rpmmd.c +@@ -258,12 +258,18 @@ struct parsedata { + + Id changelog_handle; + +- /** Hash to maps checksums to solv */ ++ int extending; /* are we extending an existing solvable? */ ++ ++ /* first solvable we added */ ++ int first; ++ /* cspool ok to use */ ++ int cshash_filled; ++ /* Hash to maps checksums to solv */ + Stringpool cspool; +- /** Cache of known checksums to solvable id */ +- Id *cscache; ++ /* Cache of known checksums to solvable id */ ++ Id *cshash; + /* the current longest index in the table */ +- int ncscache; ++ int ncshash; + }; + + static Id +@@ -576,6 +582,83 @@ set_description_author(Repodata *data, Id handle, char *str, struct parsedata *p + } + + ++ ++static void ++init_cshash(struct parsedata *pd) ++{ ++ /* initialize the string pool where we will store ++ the package checksums we know about, to get an Id ++ we can use in a cache */ ++ stringpool_init_empty(&pd->cspool); ++} ++ ++static void ++free_cshash(struct parsedata *pd) ++{ ++ stringpool_free(&pd->cspool); ++ solv_free(pd->cshash); ++} ++ ++/* save the checksum as key to solvable id relationship for ++ metadata extension */ ++static void ++put_in_cshash(struct parsedata *pd, const char *key, Id id) ++{ ++ Id index = stringpool_str2id(&pd->cspool, key, 1); ++ if (index >= pd->ncshash) ++ { ++ pd->cshash = solv_zextend(pd->cshash, pd->ncshash, index + 1 - pd->ncshash, sizeof(Id), 255); ++ pd->ncshash = index + 1; ++ } ++ /* add the checksum to the cache */ ++ pd->cshash[index] = id; ++} ++ ++static Id ++lookup_cshash(struct parsedata *pd, const char *key) ++{ ++ Id index = stringpool_str2id(&pd->cspool, key, 0); ++ if (!index || index >= pd->ncshash || !pd->cshash[index]) ++ return 0; ++ return pd->cshash[index]; ++} ++ ++static void ++fill_cshash_from_repo(struct parsedata *pd) ++{ ++ Dataiterator di; ++ /* setup join data */ ++ dataiterator_init(&di, pd->pool, pd->repo, 0, SOLVABLE_CHECKSUM, 0, 0); ++ while (dataiterator_step(&di)) ++ { ++ const char *str; ++ ++ if (!solv_chksum_len(di.key->type)) ++ continue; ++ str = repodata_chk2str(di.data, di.key->type, (const unsigned char *)di.kv.str); ++ put_in_cshash(pd, str, di.solvid); ++ } ++ dataiterator_free(&di); ++} ++ ++static void ++fill_cshash_from_new_solvables(struct parsedata *pd) ++{ ++ Pool *pool = pd->pool; ++ Id cstype; ++ unsigned const char *cs; ++ int i; ++ ++ for (i = pd->first; i < pool->nsolvables; i++) ++ { ++ if (pool->solvables[i].repo != pd->repo) ++ continue; ++ cs = repodata_lookup_bin_checksum_uninternalized(pd->data, i, SOLVABLE_CHECKSUM, &cstype); ++ if (cs) ++ put_in_cshash(pd, repodata_chk2str(pd->data, cstype, cs), i); ++ } ++} ++ + /*-----------------------------------------------*/ + /* XML callbacks */ + +@@ -664,26 +747,35 @@ startElement(void *userData, const char *name, const char **atts) + a new solvable but just append the attributes to the existing + one. + */ ++ pd->extending = 0; + if ((pkgid = find_attr("pkgid", atts)) != NULL) + { ++ if (!pd->cshash_filled) ++ { ++ pd->cshash_filled = 1; ++ fill_cshash_from_new_solvables(pd); ++ } + /* look at the checksum cache */ +- Id index = stringpool_str2id(&pd->cspool, pkgid, 0); +- if (!index || index >= pd->ncscache || !pd->cscache[index]) ++ handle = lookup_cshash(pd, pkgid); ++ if (!handle) + { + pool_debug(pool, SOLV_WARN, "the repository specifies extra information about package with checksum '%s', which does not exist in the repository.\n", pkgid); +- pd->solvable = 0; + pd->handle = 0; ++ pd->solvable = 0; + break; + } +- pd->solvable = pool_id2solvable(pool, pd->cscache[index]); ++ pd->extending = 1; + } + else + { + /* this is a new package */ +- pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo)); ++ handle = repo_add_solvable(pd->repo); ++ if (!pd->first) ++ pd->first = handle; + pd->freshens = 0; + } +- pd->handle = handle = pd->solvable - pool->solvables; ++ pd->handle = handle; ++ pd->solvable = pool_id2solvable(pool, handle); + if (pd->kind && pd->kind[1] == 'r') + { + /* products can have a type */ +@@ -697,6 +789,8 @@ startElement(void *userData, const char *name, const char **atts) + + break; + case STATE_VERSION: ++ if (pd->extending && s->evr) ++ break; /* ignore version tag repetition in extend data */ + s->evr = makeevr_atts(pool, pd, atts); + break; + case STATE_PROVIDES: +@@ -923,6 +1017,11 @@ endElement(void *userData, const char *name) + switch (pd->state) + { + case STATE_SOLVABLE: ++ if (pd->extending) ++ { ++ pd->solvable = 0; ++ break; ++ } + if (pd->kind && !s->name) /* add namespace in case of NULL name */ + s->name = pool_str2id(pool, join2(&pd->jd, pd->kind, ":", 0), 1); + if (!s->arch) +@@ -935,7 +1034,7 @@ endElement(void *userData, const char *name) + s->conflicts = repo_fix_conflicts(repo, s->conflicts); + pd->freshens = 0; + pd->kind = 0; +- pd->solvable = s = 0; ++ pd->solvable = 0; + break; + case STATE_NAME: + if (pd->kind) +@@ -957,8 +1056,6 @@ endElement(void *userData, const char *name) + break; + case STATE_CHECKSUM: + { +- Id index; +- + if (!pd->chksumtype) + break; + if (strlen(pd->content) != 2 * solv_chksum_len(pd->chksumtype)) +@@ -967,16 +1064,9 @@ endElement(void *userData, const char *name) + break; + } + repodata_set_checksum(pd->data, handle, SOLVABLE_CHECKSUM, pd->chksumtype, pd->content); +- /* we save the checksum to solvable id relationship for extended +- metadata */ +- index = stringpool_str2id(&pd->cspool, pd->content, 1 /* create it */); +- if (index >= pd->ncscache) +- { +- pd->cscache = solv_zextend(pd->cscache, pd->ncscache, index + 1 - pd->ncscache, sizeof(Id), 255); +- pd->ncscache = index + 1; +- } +- /* add the checksum to the cache */ +- pd->cscache[index] = s - pool->solvables; ++ /* we save the checksum to solvable id relationship for extending metadata */ ++ if (pd->cshash_filled) ++ put_in_cshash(pd, pd->content, s - pool->solvables); + break; + } + case STATE_FILE: +@@ -1165,32 +1255,12 @@ repo_add_rpmmd(Repo *repo, FILE *fp, const char *language, int flags) + pd.kind = 0; + pd.language = language && *language && strcmp(language, "en") != 0 ? language : 0; + +- /* initialize the string pool where we will store +- the package checksums we know about, to get an Id +- we can use in a cache */ +- stringpool_init_empty(&pd.cspool); ++ init_cshash(&pd); + if ((flags & REPO_EXTEND_SOLVABLES) != 0) + { + /* setup join data */ +- Dataiterator di; +- dataiterator_init(&di, pool, repo, 0, SOLVABLE_CHECKSUM, 0, 0); +- while (dataiterator_step(&di)) +- { +- const char *str; +- int index; +- +- if (!solv_chksum_len(di.key->type)) +- continue; +- str = repodata_chk2str(di.data, di.key->type, (const unsigned char *)di.kv.str); +- index = stringpool_str2id(&pd.cspool, str, 1); +- if (index >= pd.ncscache) +- { +- pd.cscache = solv_zextend(pd.cscache, pd.ncscache, index + 1 - pd.ncscache, sizeof(Id), 255); +- pd.ncscache = index + 1; +- } +- pd.cscache[index] = di.solvid; +- } +- dataiterator_free(&di); ++ pd.cshash_filled = 1; ++ fill_cshash_from_repo(&pd); + } + + parser = XML_ParserCreate(NULL); +@@ -1213,8 +1283,7 @@ repo_add_rpmmd(Repo *repo, FILE *fp, const char *language, int flags) + solv_free(pd.content); + solv_free(pd.lastdirstr); + join_freemem(&pd.jd); +- stringpool_free(&pd.cspool); +- solv_free(pd.cscache); ++ free_cshash(&pd); + repodata_free_dircache(data); + + if (!(flags & REPO_NO_INTERNALIZE)) +-- +2.5.0 + diff --git a/0004-solv_hex2bin-don-t-eat-nibbles.patch b/0004-solv_hex2bin-don-t-eat-nibbles.patch new file mode 100644 index 0000000..f027832 --- /dev/null +++ b/0004-solv_hex2bin-don-t-eat-nibbles.patch @@ -0,0 +1,34 @@ +From 4cebb81db05fd9281a6d482adce25c93605ed5da Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Fri, 26 Feb 2016 13:40:28 +0100 +Subject: [PATCH 3/9] solv_hex2bin: don't eat nibbles + +--- + src/util.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/util.c b/src/util.c +index d611297..b2e9179 100644 +--- a/src/util.c ++++ b/src/util.c +@@ -235,7 +235,7 @@ solv_hex2bin(const char **strp, unsigned char *buf, int bufl) + d = c - ('A' - 10); + else + break; +- c = *++str; ++ c = str[1]; + d <<= 4; + if (c >= '0' && c <= '9') + d |= c - '0'; +@@ -246,7 +246,7 @@ solv_hex2bin(const char **strp, unsigned char *buf, int bufl) + else + break; + buf[i] = d; +- ++str; ++ str += 2; + } + *strp = str; + return i; +-- +2.5.0 + diff --git a/0005-Use-less-memory-when-extending-packages.patch b/0005-Use-less-memory-when-extending-packages.patch new file mode 100644 index 0000000..f8eaa49 --- /dev/null +++ b/0005-Use-less-memory-when-extending-packages.patch @@ -0,0 +1,265 @@ +From d06562f7b70f6ceb7d52e717efd1963ce6e8ecf0 Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Mon, 29 Feb 2016 13:49:48 +0100 +Subject: [PATCH 4/9] Use less memory when extending packages + +Implement a hash instead of mis-using a string pool. +--- + ext/repo_rpmmd.c | 166 +++++++++++++++++++++++++++++++++++++++++-------------- + 1 file changed, 126 insertions(+), 40 deletions(-) + +diff --git a/ext/repo_rpmmd.c b/ext/repo_rpmmd.c +index cc54b3e..77366c2 100644 +--- a/ext/repo_rpmmd.c ++++ b/ext/repo_rpmmd.c +@@ -264,12 +264,12 @@ struct parsedata { + int first; + /* cspool ok to use */ + int cshash_filled; +- /* Hash to maps checksums to solv */ +- Stringpool cspool; +- /* Cache of known checksums to solvable id */ +- Id *cshash; +- /* the current longest index in the table */ +- int ncshash; ++ ++ Hashtable cshash; /* checksum hash -> offset into csdata */ ++ Hashval cshashm; /* hash mask */ ++ int ncshash; /* entries used */ ++ unsigned char *csdata; /* [len, checksum, id] */ ++ int ncsdata; /* used bytes */ + }; + + static Id +@@ -582,45 +582,125 @@ set_description_author(Repodata *data, Id handle, char *str, struct parsedata *p + } + + ++/*-----------------------------------------------*/ ++/* checksum hash functions ++ * ++ * used to look up a solvable with the checksum for solvable extension purposes. ++ * ++ */ + + static void + init_cshash(struct parsedata *pd) + { +- /* initialize the string pool where we will store +- the package checksums we know about, to get an Id +- we can use in a cache */ +- stringpool_init_empty(&pd->cspool); + } + + static void + free_cshash(struct parsedata *pd) + { +- stringpool_free(&pd->cspool); ++ pd->cshash = solv_free(pd->cshash); ++ pd->ncshash = 0; ++ pd->cshashm = 0; ++ pd->csdata = solv_free(pd->csdata); ++ pd->ncsdata = 0; ++} ++ ++static inline Hashval ++hashkey(const unsigned char *key, int keyl) ++{ ++ return key[0] << 24 | key[1] << 16 | key[2] << 8 | key[3]; ++} ++ ++static void ++rebuild_cshash(struct parsedata *pd) ++{ ++ Hashval h, hh, hm; ++ Hashtable ht; ++ unsigned char *d, *de; ++ ++ hm = pd->cshashm; ++#if 0 ++ fprintf(stderr, "rebuild cshash with mask 0x%x\n", hm); ++#endif + solv_free(pd->cshash); ++ ht = pd->cshash = (Hashtable)solv_calloc(hm + 1, sizeof(Id)); ++ d = pd->csdata; ++ de = d + pd->ncsdata; ++ while (d != de) ++ { ++ h = hashkey(d + 1, d[0] + 1) & hm; ++ hh = HASHCHAIN_START; ++ while (ht[h]) ++ h = HASHCHAIN_NEXT(h, hh, hm); ++ ht[h] = d + 1 - pd->csdata; ++ d += 2 + d[0] + sizeof(Id); ++ } + } + +-/* save the checksum as key to solvable id relationship for +- metadata extension */ + static void +-put_in_cshash(struct parsedata *pd, const char *key, Id id) ++put_in_cshash(struct parsedata *pd, const unsigned char *key, int keyl, Id id) + { +- Id index = stringpool_str2id(&pd->cspool, key, 1); +- if (index >= pd->ncshash) ++ Hashtable ht; ++ Hashval h, hh, hm; ++ unsigned char *d; ++ ++ if (keyl < 4 || keyl > 256) ++ return; ++ ht = pd->cshash; ++ hm = pd->cshashm; ++ h = hashkey(key, keyl) & hm; ++ hh = HASHCHAIN_START; ++ if (ht) + { +- pd->cshash = solv_zextend(pd->cshash, pd->ncshash, index + 1 - pd->ncshash, sizeof(Id), 255); +- pd->ncshash = index + 1; ++ while (ht[h]) ++ { ++ unsigned char *d = pd->csdata + ht[h]; ++ if (d[-1] == keyl && !memcmp(key, d, keyl)) ++ return; /* XXX: first id wins... */ ++ h = HASHCHAIN_NEXT(h, hh, hm); ++ } + } +- /* add the checksum to the cache */ +- pd->cshash[index] = id; ++ /* a new entry. put in csdata */ ++ pd->csdata = solv_extend(pd->csdata, pd->ncsdata, 1, 1 + keyl + sizeof(Id), 4095); ++ d = pd->csdata + pd->ncsdata; ++ d[0] = keyl - 1; ++ memcpy(d + 1, key, keyl); ++ memcpy(d + 1 + keyl, &id, sizeof(Id)); ++ pd->ncsdata += 1 + keyl + sizeof(Id); ++ if ((Hashval)++pd->ncshash * 2 > hm) ++ { ++ pd->cshashm = pd->cshashm ? (2 * pd->cshashm + 1) : 4095; ++ rebuild_cshash(pd); ++ } ++ else ++ ht[h] = pd->ncsdata - (keyl + sizeof(Id)); + } + + static Id +-lookup_cshash(struct parsedata *pd, const char *key) ++lookup_cshash(struct parsedata *pd, const unsigned char *key, int keyl) + { +- Id index = stringpool_str2id(&pd->cspool, key, 0); +- if (!index || index >= pd->ncshash || !pd->cshash[index]) ++ Hashtable ht; ++ Hashval h, hh, hm; ++ ++ if (keyl < 4 || keyl > 256) ++ return 0; ++ ht = pd->cshash; ++ if (!ht) + return 0; +- return pd->cshash[index]; ++ hm = pd->cshashm; ++ h = hashkey(key, keyl) & hm; ++ hh = HASHCHAIN_START; ++ while (ht[h]) ++ { ++ unsigned char *d = pd->csdata + ht[h]; ++ if (d[-1] == keyl - 1 && !memcmp(key, d, keyl)) ++ { ++ Id id; ++ memcpy(&id, d + keyl, sizeof(Id)); ++ return id; ++ } ++ h = HASHCHAIN_NEXT(h, hh, hm); ++ } ++ return 0; + } + + static void +@@ -630,14 +710,7 @@ fill_cshash_from_repo(struct parsedata *pd) + /* setup join data */ + dataiterator_init(&di, pd->pool, pd->repo, 0, SOLVABLE_CHECKSUM, 0, 0); + while (dataiterator_step(&di)) +- { +- const char *str; +- +- if (!solv_chksum_len(di.key->type)) +- continue; +- str = repodata_chk2str(di.data, di.key->type, (const unsigned char *)di.kv.str); +- put_in_cshash(pd, str, di.solvid); +- } ++ put_in_cshash(pd, (const unsigned char *)di.kv.str, solv_chksum_len(di.key->type), di.solvid); + dataiterator_free(&di); + } + +@@ -645,7 +718,7 @@ static void + fill_cshash_from_new_solvables(struct parsedata *pd) + { + Pool *pool = pd->pool; +- Id cstype; ++ Id cstype = 0; + unsigned const char *cs; + int i; + +@@ -655,7 +728,7 @@ fill_cshash_from_new_solvables(struct parsedata *pd) + continue; + cs = repodata_lookup_bin_checksum_uninternalized(pd->data, i, SOLVABLE_CHECKSUM, &cstype); + if (cs) +- put_in_cshash(pd, repodata_chk2str(pd->data, cstype, cs), i); ++ put_in_cshash(pd, cs, solv_chksum_len(cstype), i); + } + } + +@@ -750,13 +823,23 @@ startElement(void *userData, const char *name, const char **atts) + pd->extending = 0; + if ((pkgid = find_attr("pkgid", atts)) != NULL) + { ++ unsigned char chk[256]; ++ int l; ++ const char *str = pkgid; + if (!pd->cshash_filled) + { + pd->cshash_filled = 1; + fill_cshash_from_new_solvables(pd); + } ++ handle = 0; ++ /* convert into bin checksum */ ++ l = solv_hex2bin(&str, chk, sizeof(chk)); + /* look at the checksum cache */ +- handle = lookup_cshash(pd, pkgid); ++ if (l >= 4 && !pkgid[2 * l]) ++ handle = lookup_cshash(pd, chk, l); ++#if 0 ++ fprintf(stderr, "Lookup %s -> %d\n", pkgid, handle); ++#endif + if (!handle) + { + pool_debug(pool, SOLV_WARN, "the repository specifies extra information about package with checksum '%s', which does not exist in the repository.\n", pkgid); +@@ -1056,17 +1139,20 @@ endElement(void *userData, const char *name) + break; + case STATE_CHECKSUM: + { +- if (!pd->chksumtype) ++ unsigned char chk[256]; ++ int l = solv_chksum_len(pd->chksumtype); ++ const char *str = pd->content; ++ if (!l || l > sizeof(chk)) + break; +- if (strlen(pd->content) != 2 * solv_chksum_len(pd->chksumtype)) ++ if (solv_hex2bin(&str, chk, l) != l || pd->content[2 * l]) + { +- pd->ret = pool_error(pool, -1, "line %d: invalid checksum length for %s", (unsigned int)XML_GetCurrentLineNumber(*pd->parser), solv_chksum_type2str(pd->chksumtype)); ++ pd->ret = pool_error(pool, -1, "line %u: invalid %s checksum", (unsigned int)XML_GetCurrentLineNumber(*pd->parser), solv_chksum_type2str(pd->chksumtype)); + break; + } +- repodata_set_checksum(pd->data, handle, SOLVABLE_CHECKSUM, pd->chksumtype, pd->content); ++ repodata_set_bin_checksum(pd->data, handle, SOLVABLE_CHECKSUM, pd->chksumtype, chk); + /* we save the checksum to solvable id relationship for extending metadata */ + if (pd->cshash_filled) +- put_in_cshash(pd, pd->content, s - pool->solvables); ++ put_in_cshash(pd, chk, l, s - pool->solvables); + break; + } + case STATE_FILE: +-- +2.5.0 + diff --git a/0006-Fix-comments.patch b/0006-Fix-comments.patch new file mode 100644 index 0000000..97b7352 --- /dev/null +++ b/0006-Fix-comments.patch @@ -0,0 +1,30 @@ +From 4bcff7d8e7fadcc0b314aa654ce97579db3bbe1a Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Mon, 29 Feb 2016 14:14:05 +0100 +Subject: [PATCH 5/9] Fix comments + +--- + ext/repo_rpmmd.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/ext/repo_rpmmd.c b/ext/repo_rpmmd.c +index 77366c2..5ef5c25 100644 +--- a/ext/repo_rpmmd.c ++++ b/ext/repo_rpmmd.c +@@ -259,11 +259,8 @@ struct parsedata { + Id changelog_handle; + + int extending; /* are we extending an existing solvable? */ +- +- /* first solvable we added */ +- int first; +- /* cspool ok to use */ +- int cshash_filled; ++ int first; /* first solvable we added */ ++ int cshash_filled; /* hash is filled with data */ + + Hashtable cshash; /* checksum hash -> offset into csdata */ + Hashval cshashm; /* hash mask */ +-- +2.5.0 + diff --git a/0007-rpmmd-diskusage-prepend-a-to-the-dir-if-not-already-.patch b/0007-rpmmd-diskusage-prepend-a-to-the-dir-if-not-already-.patch new file mode 100644 index 0000000..40a13cf --- /dev/null +++ b/0007-rpmmd-diskusage-prepend-a-to-the-dir-if-not-already-.patch @@ -0,0 +1,50 @@ +From 5218114520e47f50bef59606d32d9434ee4b6f47 Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Thu, 3 Mar 2016 12:59:18 +0100 +Subject: [PATCH 6/9] rpmmd diskusage: prepend a '/' to the dir if not already + there + +Makes the code consistent with repo_susetags. +--- + ext/repo_rpmmd.c | 23 ++++++++++++++++------- + 1 file changed, 16 insertions(+), 7 deletions(-) + +diff --git a/ext/repo_rpmmd.c b/ext/repo_rpmmd.c +index 5ef5c25..78264cc 100644 +--- a/ext/repo_rpmmd.c ++++ b/ext/repo_rpmmd.c +@@ -1014,15 +1014,24 @@ startElement(void *userData, const char *name, const char **atts) + { + long filesz = 0, filenum = 0; + Id dirid; +- if ((str = find_attr("name", atts)) != 0) +- dirid = repodata_str2dir(pd->data, str, 1); +- else +- { ++ if ((str = find_attr("name", atts)) == 0) ++ { + pd->ret = pool_error(pool, -1, " tag without 'name' attribute"); + break; +- } +- if (!dirid) +- dirid = repodata_str2dir(pd->data, "/", 1); ++ } ++ if (*str != '/') ++ { ++ int l = strlen(str) + 2; ++ if (l > pd->acontent) ++ { ++ pd->content = solv_realloc(pd->content, l + 256); ++ pd->acontent = l + 256; ++ } ++ *pd->content = '/'; ++ strcpy(pd->content + 1, str); ++ str = pd->content; ++ } ++ dirid = repodata_str2dir(pd->data, str, 1); + if ((str = find_attr("size", atts)) != 0) + filesz = strtol(str, 0, 0); + if ((str = find_attr("count", atts)) != 0) +-- +2.5.0 + diff --git a/0008-Split-diskusage-and-fileprovides-code-into-separate-.patch b/0008-Split-diskusage-and-fileprovides-code-into-separate-.patch new file mode 100644 index 0000000..195b5a6 --- /dev/null +++ b/0008-Split-diskusage-and-fileprovides-code-into-separate-.patch @@ -0,0 +1,1465 @@ +From e77926c355afff8be62e401ff3c4446fcbaaace5 Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Thu, 3 Mar 2016 15:08:38 +0100 +Subject: [PATCH 7/9] Split diskusage and fileprovides code into separate files + +--- + src/CMakeLists.txt | 3 +- + src/diskusage.c | 348 +++++++++++++++++++++++++++ + src/fileprovides.c | 373 +++++++++++++++++++++++++++++ + src/pool.c | 676 ----------------------------------------------------- + 4 files changed, 723 insertions(+), 677 deletions(-) + create mode 100644 src/diskusage.c + create mode 100644 src/fileprovides.c + +diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt +index a2c0098..241890d 100644 +--- a/src/CMakeLists.txt ++++ b/src/CMakeLists.txt +@@ -18,7 +18,8 @@ SET (libsolv_SRCS + solver.c solverdebug.c repo_solv.c repo_write.c evr.c pool.c + queue.c repo.c repodata.c repopage.c util.c policy.c solvable.c + transaction.c order.c rules.c problems.c linkedpkg.c cplxdeps.c +- chksum.c md5.c sha1.c sha2.c solvversion.c selection.c) ++ chksum.c md5.c sha1.c sha2.c solvversion.c selection.c ++ fileprovides.c diskusage.c) + + SET (libsolv_HEADERS + bitmap.h evr.h hash.h policy.h poolarch.h poolvendor.h pool.h +diff --git a/src/diskusage.c b/src/diskusage.c +new file mode 100644 +index 0000000..b764b98 +--- /dev/null ++++ b/src/diskusage.c +@@ -0,0 +1,348 @@ ++/* ++ * Copyright (c) 2007-2016, SUSE LLC ++ * ++ * This program is licensed under the BSD license, read LICENSE.BSD ++ * for further information ++ */ ++ ++/* ++ * diskusage.c ++ * ++ * calculate needed space on partitions ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "pool.h" ++#include "poolarch.h" ++#include "repo.h" ++#include "util.h" ++#include "bitmap.h" ++ ++ ++struct mptree { ++ Id sibling; ++ Id child; ++ const char *comp; ++ int compl; ++ Id mountpoint; ++}; ++ ++struct ducbdata { ++ DUChanges *mps; ++ struct mptree *mptree; ++ int addsub; ++ int hasdu; ++ ++ Id *dirmap; ++ int nmap; ++ Repodata *olddata; ++}; ++ ++ ++static int ++solver_fill_DU_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value) ++{ ++ struct ducbdata *cbd = cbdata; ++ Id mp; ++ ++ if (data != cbd->olddata) ++ { ++ Id dn, mp, comp, *dirmap, *dirs; ++ int i, compl; ++ const char *compstr; ++ struct mptree *mptree; ++ ++ /* create map from dir to mptree */ ++ cbd->dirmap = solv_free(cbd->dirmap); ++ cbd->nmap = 0; ++ dirmap = solv_calloc(data->dirpool.ndirs, sizeof(Id)); ++ mptree = cbd->mptree; ++ mp = 0; ++ for (dn = 2, dirs = data->dirpool.dirs + dn; dn < data->dirpool.ndirs; dn++) ++ { ++ comp = *dirs++; ++ if (comp <= 0) ++ { ++ mp = dirmap[-comp]; ++ continue; ++ } ++ if (mp < 0) ++ { ++ /* unconnected */ ++ dirmap[dn] = mp; ++ continue; ++ } ++ if (!mptree[mp].child) ++ { ++ dirmap[dn] = -mp; ++ continue; ++ } ++ if (data->localpool) ++ compstr = stringpool_id2str(&data->spool, comp); ++ else ++ compstr = pool_id2str(data->repo->pool, comp); ++ compl = strlen(compstr); ++ for (i = mptree[mp].child; i; i = mptree[i].sibling) ++ if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl)) ++ break; ++ dirmap[dn] = i ? i : -mp; ++ } ++ /* change dirmap to point to mountpoint instead of mptree */ ++ for (dn = 0; dn < data->dirpool.ndirs; dn++) ++ { ++ mp = dirmap[dn]; ++ dirmap[dn] = mptree[mp > 0 ? mp : -mp].mountpoint; ++ } ++ cbd->dirmap = dirmap; ++ cbd->nmap = data->dirpool.ndirs; ++ cbd->olddata = data; ++ } ++ cbd->hasdu = 1; ++ if (value->id < 0 || value->id >= cbd->nmap) ++ return 0; ++ mp = cbd->dirmap[value->id]; ++ if (mp < 0) ++ return 0; ++ if (cbd->addsub > 0) ++ { ++ cbd->mps[mp].kbytes += value->num; ++ cbd->mps[mp].files += value->num2; ++ } ++ else if (!(cbd->mps[mp].flags & DUCHANGES_ONLYADD)) ++ { ++ cbd->mps[mp].kbytes -= value->num; ++ cbd->mps[mp].files -= value->num2; ++ } ++ return 0; ++} ++ ++static void ++propagate_mountpoints(struct mptree *mptree, int pos, Id mountpoint) ++{ ++ int i; ++ if (mptree[pos].mountpoint == -1) ++ mptree[pos].mountpoint = mountpoint; ++ else ++ mountpoint = mptree[pos].mountpoint; ++ for (i = mptree[pos].child; i; i = mptree[i].sibling) ++ propagate_mountpoints(mptree, i, mountpoint); ++} ++ ++#define MPTREE_BLOCK 15 ++ ++static struct mptree * ++create_mptree(DUChanges *mps, int nmps) ++{ ++ int i, nmptree; ++ struct mptree *mptree; ++ int pos, compl; ++ int mp; ++ const char *p, *path, *compstr; ++ ++ mptree = solv_extend_resize(0, 1, sizeof(struct mptree), MPTREE_BLOCK); ++ ++ /* our root node */ ++ mptree[0].sibling = 0; ++ mptree[0].child = 0; ++ mptree[0].comp = 0; ++ mptree[0].compl = 0; ++ mptree[0].mountpoint = -1; ++ nmptree = 1; ++ ++ /* create component tree */ ++ for (mp = 0; mp < nmps; mp++) ++ { ++ mps[mp].kbytes = 0; ++ mps[mp].files = 0; ++ pos = 0; ++ path = mps[mp].path; ++ while(*path == '/') ++ path++; ++ while (*path) ++ { ++ if ((p = strchr(path, '/')) == 0) ++ { ++ compstr = path; ++ compl = strlen(compstr); ++ path += compl; ++ } ++ else ++ { ++ compstr = path; ++ compl = p - path; ++ path = p + 1; ++ while(*path == '/') ++ path++; ++ } ++ for (i = mptree[pos].child; i; i = mptree[i].sibling) ++ if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl)) ++ break; ++ if (!i) ++ { ++ /* create new node */ ++ mptree = solv_extend(mptree, nmptree, 1, sizeof(struct mptree), MPTREE_BLOCK); ++ i = nmptree++; ++ mptree[i].sibling = mptree[pos].child; ++ mptree[i].child = 0; ++ mptree[i].comp = compstr; ++ mptree[i].compl = compl; ++ mptree[i].mountpoint = -1; ++ mptree[pos].child = i; ++ } ++ pos = i; ++ } ++ mptree[pos].mountpoint = mp; ++ } ++ ++ propagate_mountpoints(mptree, 0, mptree[0].mountpoint); ++ ++#if 0 ++ for (i = 0; i < nmptree; i++) ++ { ++ printf("#%d sibling: %d\n", i, mptree[i].sibling); ++ printf("#%d child: %d\n", i, mptree[i].child); ++ printf("#%d comp: %s\n", i, mptree[i].comp); ++ printf("#%d compl: %d\n", i, mptree[i].compl); ++ printf("#%d mountpont: %d\n", i, mptree[i].mountpoint); ++ } ++#endif ++ ++ return mptree; ++} ++ ++void ++pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps) ++{ ++ struct mptree *mptree; ++ struct ducbdata cbd; ++ Solvable *s; ++ int i, sp; ++ Map ignoredu; ++ Repo *oldinstalled = pool->installed; ++ int haveonlyadd = 0; ++ ++ map_init(&ignoredu, 0); ++ mptree = create_mptree(mps, nmps); ++ ++ for (i = 0; i < nmps; i++) ++ if ((mps[i].flags & DUCHANGES_ONLYADD) != 0) ++ haveonlyadd = 1; ++ cbd.mps = mps; ++ cbd.dirmap = 0; ++ cbd.nmap = 0; ++ cbd.olddata = 0; ++ cbd.mptree = mptree; ++ cbd.addsub = 1; ++ for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++) ++ { ++ if (!s->repo || (oldinstalled && s->repo == oldinstalled)) ++ continue; ++ if (!MAPTST(installedmap, sp)) ++ continue; ++ cbd.hasdu = 0; ++ repo_search(s->repo, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); ++ if (!cbd.hasdu && oldinstalled) ++ { ++ Id op, opp; ++ int didonlyadd = 0; ++ /* no du data available, ignore data of all installed solvables we obsolete */ ++ if (!ignoredu.size) ++ map_grow(&ignoredu, oldinstalled->end - oldinstalled->start); ++ FOR_PROVIDES(op, opp, s->name) ++ { ++ Solvable *s2 = pool->solvables + op; ++ if (!pool->implicitobsoleteusesprovides && s->name != s2->name) ++ continue; ++ if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, s2)) ++ continue; ++ if (op >= oldinstalled->start && op < oldinstalled->end) ++ { ++ MAPSET(&ignoredu, op - oldinstalled->start); ++ if (haveonlyadd && pool->solvables[op].repo == oldinstalled && !didonlyadd) ++ { ++ repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); ++ cbd.addsub = -1; ++ repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); ++ cbd.addsub = 1; ++ didonlyadd = 1; ++ } ++ } ++ } ++ if (s->obsoletes) ++ { ++ Id obs, *obsp = s->repo->idarraydata + s->obsoletes; ++ while ((obs = *obsp++) != 0) ++ FOR_PROVIDES(op, opp, obs) ++ { ++ Solvable *s2 = pool->solvables + op; ++ if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, s2, obs)) ++ continue; ++ if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2)) ++ continue; ++ if (op >= oldinstalled->start && op < oldinstalled->end) ++ { ++ MAPSET(&ignoredu, op - oldinstalled->start); ++ if (haveonlyadd && pool->solvables[op].repo == oldinstalled && !didonlyadd) ++ { ++ repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); ++ cbd.addsub = -1; ++ repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); ++ cbd.addsub = 1; ++ didonlyadd = 1; ++ } ++ } ++ } ++ } ++ } ++ } ++ cbd.addsub = -1; ++ if (oldinstalled) ++ { ++ /* assumes we allways have du data for installed solvables */ ++ FOR_REPO_SOLVABLES(oldinstalled, sp, s) ++ { ++ if (MAPTST(installedmap, sp)) ++ continue; ++ if (ignoredu.map && MAPTST(&ignoredu, sp - oldinstalled->start)) ++ continue; ++ repo_search(oldinstalled, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); ++ } ++ } ++ map_free(&ignoredu); ++ solv_free(cbd.dirmap); ++ solv_free(mptree); ++} ++ ++int ++pool_calc_installsizechange(Pool *pool, Map *installedmap) ++{ ++ Id sp; ++ Solvable *s; ++ int change = 0; ++ Repo *oldinstalled = pool->installed; ++ ++ for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++) ++ { ++ if (!s->repo || (oldinstalled && s->repo == oldinstalled)) ++ continue; ++ if (!MAPTST(installedmap, sp)) ++ continue; ++ change += solvable_lookup_sizek(s, SOLVABLE_INSTALLSIZE, 0); ++ } ++ if (oldinstalled) ++ { ++ FOR_REPO_SOLVABLES(oldinstalled, sp, s) ++ { ++ if (MAPTST(installedmap, sp)) ++ continue; ++ change -= solvable_lookup_sizek(s, SOLVABLE_INSTALLSIZE, 0); ++ } ++ } ++ return change; ++} ++ +diff --git a/src/fileprovides.c b/src/fileprovides.c +new file mode 100644 +index 0000000..11ff4f5 +--- /dev/null ++++ b/src/fileprovides.c +@@ -0,0 +1,373 @@ ++/* ++ * Copyright (c) 2007-2016, SUSE LLC ++ * ++ * This program is licensed under the BSD license, read LICENSE.BSD ++ * for further information ++ */ ++ ++/* ++ * fileprovides.c ++ * ++ * Add missing file dependencies to the package provides ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "pool.h" ++#include "repo.h" ++#include "util.h" ++#include "bitmap.h" ++ ++struct searchfiles { ++ Id *ids; ++ int nfiles; ++ Map seen; ++}; ++ ++#define SEARCHFILES_BLOCK 127 ++ ++static void ++pool_addfileprovides_dep(Pool *pool, Id *ida, struct searchfiles *sf, struct searchfiles *isf) ++{ ++ Id dep, sid; ++ const char *s; ++ struct searchfiles *csf; ++ ++ while ((dep = *ida++) != 0) ++ { ++ csf = sf; ++ while (ISRELDEP(dep)) ++ { ++ Reldep *rd; ++ sid = pool->ss.nstrings + GETRELID(dep); ++ if (MAPTST(&csf->seen, sid)) ++ { ++ dep = 0; ++ break; ++ } ++ MAPSET(&csf->seen, sid); ++ rd = GETRELDEP(pool, dep); ++ if (rd->flags < 8) ++ dep = rd->name; ++ else if (rd->flags == REL_NAMESPACE) ++ { ++ if (rd->name == NAMESPACE_SPLITPROVIDES) ++ { ++ csf = isf; ++ if (!csf || MAPTST(&csf->seen, sid)) ++ { ++ dep = 0; ++ break; ++ } ++ MAPSET(&csf->seen, sid); ++ } ++ dep = rd->evr; ++ } ++ else if (rd->flags == REL_FILECONFLICT) ++ { ++ dep = 0; ++ break; ++ } ++ else ++ { ++ Id ids[2]; ++ ids[0] = rd->name; ++ ids[1] = 0; ++ pool_addfileprovides_dep(pool, ids, csf, isf); ++ dep = rd->evr; ++ } ++ } ++ if (!dep) ++ continue; ++ if (MAPTST(&csf->seen, dep)) ++ continue; ++ MAPSET(&csf->seen, dep); ++ s = pool_id2str(pool, dep); ++ if (*s != '/') ++ continue; ++ if (csf != isf && pool->addedfileprovides == 1 && !repodata_filelistfilter_matches(0, s)) ++ continue; /* skip non-standard locations csf == isf: installed case */ ++ csf->ids = solv_extend(csf->ids, csf->nfiles, 1, sizeof(Id), SEARCHFILES_BLOCK); ++ csf->ids[csf->nfiles++] = dep; ++ } ++} ++ ++struct addfileprovides_cbdata { ++ int nfiles; ++ Id *ids; ++ char **dirs; ++ char **names; ++ ++ Id *dids; ++ ++ Map providedids; ++ ++ Map useddirs; ++}; ++ ++static int ++addfileprovides_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value) ++{ ++ struct addfileprovides_cbdata *cbd = cbdata; ++ int i; ++ ++ if (!cbd->useddirs.size) ++ { ++ map_init(&cbd->useddirs, data->dirpool.ndirs + 1); ++ if (!cbd->dirs) ++ { ++ cbd->dirs = solv_malloc2(cbd->nfiles, sizeof(char *)); ++ cbd->names = solv_malloc2(cbd->nfiles, sizeof(char *)); ++ for (i = 0; i < cbd->nfiles; i++) ++ { ++ char *s = solv_strdup(pool_id2str(data->repo->pool, cbd->ids[i])); ++ cbd->dirs[i] = s; ++ s = strrchr(s, '/'); ++ *s = 0; ++ cbd->names[i] = s + 1; ++ } ++ } ++ for (i = 0; i < cbd->nfiles; i++) ++ { ++ Id did; ++ if (MAPTST(&cbd->providedids, cbd->ids[i])) ++ { ++ cbd->dids[i] = 0; ++ continue; ++ } ++ did = repodata_str2dir(data, cbd->dirs[i], 0); ++ cbd->dids[i] = did; ++ if (did) ++ MAPSET(&cbd->useddirs, did); ++ } ++ repodata_free_dircache(data); ++ } ++ if (value->id >= data->dirpool.ndirs || !MAPTST(&cbd->useddirs, value->id)) ++ return 0; ++ for (i = 0; i < cbd->nfiles; i++) ++ if (cbd->dids[i] == value->id && !strcmp(cbd->names[i], value->str)) ++ s->provides = repo_addid_dep(s->repo, s->provides, cbd->ids[i], SOLVABLE_FILEMARKER); ++ return 0; ++} ++ ++static void ++pool_addfileprovides_search(Pool *pool, struct addfileprovides_cbdata *cbd, struct searchfiles *sf, Repo *repoonly) ++{ ++ Id p; ++ Repodata *data; ++ Repo *repo; ++ Queue fileprovidesq; ++ int i, j, repoid, repodataid; ++ int provstart, provend; ++ Map donemap; ++ int ndone, incomplete; ++ ++ if (!pool->urepos) ++ return; ++ ++ cbd->nfiles = sf->nfiles; ++ cbd->ids = sf->ids; ++ cbd->dirs = 0; ++ cbd->names = 0; ++ cbd->dids = solv_realloc2(cbd->dids, sf->nfiles, sizeof(Id)); ++ map_init(&cbd->providedids, pool->ss.nstrings); ++ ++ repoid = 1; ++ repo = repoonly ? repoonly : pool->repos[repoid]; ++ map_init(&donemap, pool->nsolvables); ++ queue_init(&fileprovidesq); ++ provstart = provend = 0; ++ for (;;) ++ { ++ if (!repo || repo->disabled) ++ { ++ if (repoonly || ++repoid == pool->nrepos) ++ break; ++ repo = pool->repos[repoid]; ++ continue; ++ } ++ ndone = 0; ++ FOR_REPODATAS(repo, repodataid, data) ++ { ++ if (ndone >= repo->nsolvables) ++ break; ++ ++ if (repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &fileprovidesq)) ++ { ++ map_empty(&cbd->providedids); ++ for (i = 0; i < fileprovidesq.count; i++) ++ MAPSET(&cbd->providedids, fileprovidesq.elements[i]); ++ provstart = data->start; ++ provend = data->end; ++ for (i = 0; i < cbd->nfiles; i++) ++ if (!MAPTST(&cbd->providedids, cbd->ids[i])) ++ break; ++ if (i == cbd->nfiles) ++ { ++ /* great! no need to search files */ ++ for (p = data->start; p < data->end; p++) ++ if (pool->solvables[p].repo == repo) ++ { ++ if (MAPTST(&donemap, p)) ++ continue; ++ MAPSET(&donemap, p); ++ ndone++; ++ } ++ continue; ++ } ++ } ++ ++ if (!repodata_has_keyname(data, SOLVABLE_FILELIST)) ++ continue; ++ ++ if (data->start < provstart || data->end > provend) ++ { ++ map_empty(&cbd->providedids); ++ provstart = provend = 0; ++ } ++ ++ /* check if the data is incomplete */ ++ incomplete = 0; ++ if (data->state == REPODATA_AVAILABLE) ++ { ++ for (j = 1; j < data->nkeys; j++) ++ if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST) ++ break; ++ if (j < data->nkeys) ++ { ++#if 0 ++ for (i = 0; i < cbd->nfiles; i++) ++ if (!MAPTST(&cbd->providedids, cbd->ids[i]) && !repodata_filelistfilter_matches(data, pool_id2str(pool, cbd->ids[i]))) ++ printf("need complete filelist because of %s\n", pool_id2str(pool, cbd->ids[i])); ++#endif ++ for (i = 0; i < cbd->nfiles; i++) ++ if (!MAPTST(&cbd->providedids, cbd->ids[i]) && !repodata_filelistfilter_matches(data, pool_id2str(pool, cbd->ids[i]))) ++ break; ++ if (i < cbd->nfiles) ++ incomplete = 1; ++ } ++ } ++ ++ /* do the search */ ++ map_init(&cbd->useddirs, 0); ++ for (p = data->start; p < data->end; p++) ++ if (pool->solvables[p].repo == repo) ++ { ++ if (MAPTST(&donemap, p)) ++ continue; ++ repodata_search(data, p, SOLVABLE_FILELIST, 0, addfileprovides_cb, cbd); ++ if (!incomplete) ++ { ++ MAPSET(&donemap, p); ++ ndone++; ++ } ++ } ++ map_free(&cbd->useddirs); ++ } ++ ++ if (repoonly || ++repoid == pool->nrepos) ++ break; ++ repo = pool->repos[repoid]; ++ } ++ map_free(&donemap); ++ queue_free(&fileprovidesq); ++ map_free(&cbd->providedids); ++ if (cbd->dirs) ++ { ++ for (i = 0; i < cbd->nfiles; i++) ++ solv_free(cbd->dirs[i]); ++ cbd->dirs = solv_free(cbd->dirs); ++ cbd->names = solv_free(cbd->names); ++ } ++} ++ ++void ++pool_addfileprovides_queue(Pool *pool, Queue *idq, Queue *idqinst) ++{ ++ Solvable *s; ++ Repo *installed, *repo; ++ struct searchfiles sf, isf, *isfp; ++ struct addfileprovides_cbdata cbd; ++ int i; ++ unsigned int now; ++ ++ installed = pool->installed; ++ now = solv_timems(0); ++ memset(&sf, 0, sizeof(sf)); ++ map_init(&sf.seen, pool->ss.nstrings + pool->nrels); ++ memset(&isf, 0, sizeof(isf)); ++ map_init(&isf.seen, pool->ss.nstrings + pool->nrels); ++ pool->addedfileprovides = pool->addfileprovidesfiltered ? 1 : 2; ++ ++ if (idq) ++ queue_empty(idq); ++ if (idqinst) ++ queue_empty(idqinst); ++ isfp = installed ? &isf : 0; ++ for (i = 1, s = pool->solvables + i; i < pool->nsolvables; i++, s++) ++ { ++ repo = s->repo; ++ if (!repo) ++ continue; ++ if (s->obsoletes) ++ pool_addfileprovides_dep(pool, repo->idarraydata + s->obsoletes, &sf, isfp); ++ if (s->conflicts) ++ pool_addfileprovides_dep(pool, repo->idarraydata + s->conflicts, &sf, isfp); ++ if (s->requires) ++ pool_addfileprovides_dep(pool, repo->idarraydata + s->requires, &sf, isfp); ++ if (s->recommends) ++ pool_addfileprovides_dep(pool, repo->idarraydata + s->recommends, &sf, isfp); ++ if (s->suggests) ++ pool_addfileprovides_dep(pool, repo->idarraydata + s->suggests, &sf, isfp); ++ if (s->supplements) ++ pool_addfileprovides_dep(pool, repo->idarraydata + s->supplements, &sf, isfp); ++ if (s->enhances) ++ pool_addfileprovides_dep(pool, repo->idarraydata + s->enhances, &sf, isfp); ++ } ++ map_free(&sf.seen); ++ map_free(&isf.seen); ++ POOL_DEBUG(SOLV_DEBUG_STATS, "found %d file dependencies, %d installed file dependencies\n", sf.nfiles, isf.nfiles); ++ cbd.dids = 0; ++ if (sf.nfiles) ++ { ++#if 0 ++ for (i = 0; i < sf.nfiles; i++) ++ POOL_DEBUG(SOLV_DEBUG_STATS, "looking up %s in filelist\n", pool_id2str(pool, sf.ids[i])); ++#endif ++ pool_addfileprovides_search(pool, &cbd, &sf, 0); ++ if (idq) ++ for (i = 0; i < sf.nfiles; i++) ++ queue_push(idq, sf.ids[i]); ++ if (idqinst) ++ for (i = 0; i < sf.nfiles; i++) ++ queue_push(idqinst, sf.ids[i]); ++ solv_free(sf.ids); ++ } ++ if (isf.nfiles) ++ { ++#if 0 ++ for (i = 0; i < isf.nfiles; i++) ++ POOL_DEBUG(SOLV_DEBUG_STATS, "looking up %s in installed filelist\n", pool_id2str(pool, isf.ids[i])); ++#endif ++ if (installed) ++ pool_addfileprovides_search(pool, &cbd, &isf, installed); ++ if (installed && idqinst) ++ for (i = 0; i < isf.nfiles; i++) ++ queue_pushunique(idqinst, isf.ids[i]); ++ solv_free(isf.ids); ++ } ++ solv_free(cbd.dids); ++ pool_freewhatprovides(pool); /* as we have added provides */ ++ POOL_DEBUG(SOLV_DEBUG_STATS, "addfileprovides took %d ms\n", solv_timems(now)); ++} ++ ++void ++pool_addfileprovides(Pool *pool) ++{ ++ pool_addfileprovides_queue(pool, 0, 0); ++} ++ +diff --git a/src/pool.c b/src/pool.c +index 85932bf..34fd787 100644 +--- a/src/pool.c ++++ b/src/pool.c +@@ -1412,357 +1412,6 @@ void pool_setnamespacecallback(Pool *pool, Id (*cb)(struct _Pool *, void *, Id, + pool->nscallbackdata = nscbdata; + } + +-/*************************************************************************/ +- +-struct searchfiles { +- Id *ids; +- int nfiles; +- Map seen; +-}; +- +-#define SEARCHFILES_BLOCK 127 +- +-static void +-pool_addfileprovides_dep(Pool *pool, Id *ida, struct searchfiles *sf, struct searchfiles *isf) +-{ +- Id dep, sid; +- const char *s; +- struct searchfiles *csf; +- +- while ((dep = *ida++) != 0) +- { +- csf = sf; +- while (ISRELDEP(dep)) +- { +- Reldep *rd; +- sid = pool->ss.nstrings + GETRELID(dep); +- if (MAPTST(&csf->seen, sid)) +- { +- dep = 0; +- break; +- } +- MAPSET(&csf->seen, sid); +- rd = GETRELDEP(pool, dep); +- if (rd->flags < 8) +- dep = rd->name; +- else if (rd->flags == REL_NAMESPACE) +- { +- if (rd->name == NAMESPACE_SPLITPROVIDES) +- { +- csf = isf; +- if (!csf || MAPTST(&csf->seen, sid)) +- { +- dep = 0; +- break; +- } +- MAPSET(&csf->seen, sid); +- } +- dep = rd->evr; +- } +- else if (rd->flags == REL_FILECONFLICT) +- { +- dep = 0; +- break; +- } +- else +- { +- Id ids[2]; +- ids[0] = rd->name; +- ids[1] = 0; +- pool_addfileprovides_dep(pool, ids, csf, isf); +- dep = rd->evr; +- } +- } +- if (!dep) +- continue; +- if (MAPTST(&csf->seen, dep)) +- continue; +- MAPSET(&csf->seen, dep); +- s = pool_id2str(pool, dep); +- if (*s != '/') +- continue; +- if (csf != isf && pool->addedfileprovides == 1 && !repodata_filelistfilter_matches(0, s)) +- continue; /* skip non-standard locations csf == isf: installed case */ +- csf->ids = solv_extend(csf->ids, csf->nfiles, 1, sizeof(Id), SEARCHFILES_BLOCK); +- csf->ids[csf->nfiles++] = dep; +- } +-} +- +-struct addfileprovides_cbdata { +- int nfiles; +- Id *ids; +- char **dirs; +- char **names; +- +- Id *dids; +- +- Map providedids; +- +- Map useddirs; +-}; +- +-static int +-addfileprovides_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value) +-{ +- struct addfileprovides_cbdata *cbd = cbdata; +- int i; +- +- if (!cbd->useddirs.size) +- { +- map_init(&cbd->useddirs, data->dirpool.ndirs + 1); +- if (!cbd->dirs) +- { +- cbd->dirs = solv_malloc2(cbd->nfiles, sizeof(char *)); +- cbd->names = solv_malloc2(cbd->nfiles, sizeof(char *)); +- for (i = 0; i < cbd->nfiles; i++) +- { +- char *s = solv_strdup(pool_id2str(data->repo->pool, cbd->ids[i])); +- cbd->dirs[i] = s; +- s = strrchr(s, '/'); +- *s = 0; +- cbd->names[i] = s + 1; +- } +- } +- for (i = 0; i < cbd->nfiles; i++) +- { +- Id did; +- if (MAPTST(&cbd->providedids, cbd->ids[i])) +- { +- cbd->dids[i] = 0; +- continue; +- } +- did = repodata_str2dir(data, cbd->dirs[i], 0); +- cbd->dids[i] = did; +- if (did) +- MAPSET(&cbd->useddirs, did); +- } +- repodata_free_dircache(data); +- } +- if (value->id >= data->dirpool.ndirs || !MAPTST(&cbd->useddirs, value->id)) +- return 0; +- for (i = 0; i < cbd->nfiles; i++) +- if (cbd->dids[i] == value->id && !strcmp(cbd->names[i], value->str)) +- s->provides = repo_addid_dep(s->repo, s->provides, cbd->ids[i], SOLVABLE_FILEMARKER); +- return 0; +-} +- +-static void +-pool_addfileprovides_search(Pool *pool, struct addfileprovides_cbdata *cbd, struct searchfiles *sf, Repo *repoonly) +-{ +- Id p; +- Repodata *data; +- Repo *repo; +- Queue fileprovidesq; +- int i, j, repoid, repodataid; +- int provstart, provend; +- Map donemap; +- int ndone, incomplete; +- +- if (!pool->urepos) +- return; +- +- cbd->nfiles = sf->nfiles; +- cbd->ids = sf->ids; +- cbd->dirs = 0; +- cbd->names = 0; +- cbd->dids = solv_realloc2(cbd->dids, sf->nfiles, sizeof(Id)); +- map_init(&cbd->providedids, pool->ss.nstrings); +- +- repoid = 1; +- repo = repoonly ? repoonly : pool->repos[repoid]; +- map_init(&donemap, pool->nsolvables); +- queue_init(&fileprovidesq); +- provstart = provend = 0; +- for (;;) +- { +- if (!repo || repo->disabled) +- { +- if (repoonly || ++repoid == pool->nrepos) +- break; +- repo = pool->repos[repoid]; +- continue; +- } +- ndone = 0; +- FOR_REPODATAS(repo, repodataid, data) +- { +- if (ndone >= repo->nsolvables) +- break; +- +- if (repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &fileprovidesq)) +- { +- map_empty(&cbd->providedids); +- for (i = 0; i < fileprovidesq.count; i++) +- MAPSET(&cbd->providedids, fileprovidesq.elements[i]); +- provstart = data->start; +- provend = data->end; +- for (i = 0; i < cbd->nfiles; i++) +- if (!MAPTST(&cbd->providedids, cbd->ids[i])) +- break; +- if (i == cbd->nfiles) +- { +- /* great! no need to search files */ +- for (p = data->start; p < data->end; p++) +- if (pool->solvables[p].repo == repo) +- { +- if (MAPTST(&donemap, p)) +- continue; +- MAPSET(&donemap, p); +- ndone++; +- } +- continue; +- } +- } +- +- if (!repodata_has_keyname(data, SOLVABLE_FILELIST)) +- continue; +- +- if (data->start < provstart || data->end > provend) +- { +- map_empty(&cbd->providedids); +- provstart = provend = 0; +- } +- +- /* check if the data is incomplete */ +- incomplete = 0; +- if (data->state == REPODATA_AVAILABLE) +- { +- for (j = 1; j < data->nkeys; j++) +- if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST) +- break; +- if (j < data->nkeys) +- { +-#if 0 +- for (i = 0; i < cbd->nfiles; i++) +- if (!MAPTST(&cbd->providedids, cbd->ids[i]) && !repodata_filelistfilter_matches(data, pool_id2str(pool, cbd->ids[i]))) +- printf("need complete filelist because of %s\n", pool_id2str(pool, cbd->ids[i])); +-#endif +- for (i = 0; i < cbd->nfiles; i++) +- if (!MAPTST(&cbd->providedids, cbd->ids[i]) && !repodata_filelistfilter_matches(data, pool_id2str(pool, cbd->ids[i]))) +- break; +- if (i < cbd->nfiles) +- incomplete = 1; +- } +- } +- +- /* do the search */ +- map_init(&cbd->useddirs, 0); +- for (p = data->start; p < data->end; p++) +- if (pool->solvables[p].repo == repo) +- { +- if (MAPTST(&donemap, p)) +- continue; +- repodata_search(data, p, SOLVABLE_FILELIST, 0, addfileprovides_cb, cbd); +- if (!incomplete) +- { +- MAPSET(&donemap, p); +- ndone++; +- } +- } +- map_free(&cbd->useddirs); +- } +- +- if (repoonly || ++repoid == pool->nrepos) +- break; +- repo = pool->repos[repoid]; +- } +- map_free(&donemap); +- queue_free(&fileprovidesq); +- map_free(&cbd->providedids); +- if (cbd->dirs) +- { +- for (i = 0; i < cbd->nfiles; i++) +- solv_free(cbd->dirs[i]); +- cbd->dirs = solv_free(cbd->dirs); +- cbd->names = solv_free(cbd->names); +- } +-} +- +-void +-pool_addfileprovides_queue(Pool *pool, Queue *idq, Queue *idqinst) +-{ +- Solvable *s; +- Repo *installed, *repo; +- struct searchfiles sf, isf, *isfp; +- struct addfileprovides_cbdata cbd; +- int i; +- unsigned int now; +- +- installed = pool->installed; +- now = solv_timems(0); +- memset(&sf, 0, sizeof(sf)); +- map_init(&sf.seen, pool->ss.nstrings + pool->nrels); +- memset(&isf, 0, sizeof(isf)); +- map_init(&isf.seen, pool->ss.nstrings + pool->nrels); +- pool->addedfileprovides = pool->addfileprovidesfiltered ? 1 : 2; +- +- if (idq) +- queue_empty(idq); +- if (idqinst) +- queue_empty(idqinst); +- isfp = installed ? &isf : 0; +- for (i = 1, s = pool->solvables + i; i < pool->nsolvables; i++, s++) +- { +- repo = s->repo; +- if (!repo) +- continue; +- if (s->obsoletes) +- pool_addfileprovides_dep(pool, repo->idarraydata + s->obsoletes, &sf, isfp); +- if (s->conflicts) +- pool_addfileprovides_dep(pool, repo->idarraydata + s->conflicts, &sf, isfp); +- if (s->requires) +- pool_addfileprovides_dep(pool, repo->idarraydata + s->requires, &sf, isfp); +- if (s->recommends) +- pool_addfileprovides_dep(pool, repo->idarraydata + s->recommends, &sf, isfp); +- if (s->suggests) +- pool_addfileprovides_dep(pool, repo->idarraydata + s->suggests, &sf, isfp); +- if (s->supplements) +- pool_addfileprovides_dep(pool, repo->idarraydata + s->supplements, &sf, isfp); +- if (s->enhances) +- pool_addfileprovides_dep(pool, repo->idarraydata + s->enhances, &sf, isfp); +- } +- map_free(&sf.seen); +- map_free(&isf.seen); +- POOL_DEBUG(SOLV_DEBUG_STATS, "found %d file dependencies, %d installed file dependencies\n", sf.nfiles, isf.nfiles); +- cbd.dids = 0; +- if (sf.nfiles) +- { +-#if 0 +- for (i = 0; i < sf.nfiles; i++) +- POOL_DEBUG(SOLV_DEBUG_STATS, "looking up %s in filelist\n", pool_id2str(pool, sf.ids[i])); +-#endif +- pool_addfileprovides_search(pool, &cbd, &sf, 0); +- if (idq) +- for (i = 0; i < sf.nfiles; i++) +- queue_push(idq, sf.ids[i]); +- if (idqinst) +- for (i = 0; i < sf.nfiles; i++) +- queue_push(idqinst, sf.ids[i]); +- solv_free(sf.ids); +- } +- if (isf.nfiles) +- { +-#if 0 +- for (i = 0; i < isf.nfiles; i++) +- POOL_DEBUG(SOLV_DEBUG_STATS, "looking up %s in installed filelist\n", pool_id2str(pool, isf.ids[i])); +-#endif +- if (installed) +- pool_addfileprovides_search(pool, &cbd, &isf, installed); +- if (installed && idqinst) +- for (i = 0; i < isf.nfiles; i++) +- queue_pushunique(idqinst, isf.ids[i]); +- solv_free(isf.ids); +- } +- solv_free(cbd.dids); +- pool_freewhatprovides(pool); /* as we have added provides */ +- POOL_DEBUG(SOLV_DEBUG_STATS, "addfileprovides took %d ms\n", solv_timems(now)); +-} +- +-void +-pool_addfileprovides(Pool *pool) +-{ +- pool_addfileprovides_queue(pool, 0, 0); +-} +- + void + pool_search(Pool *pool, Id p, Id key, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, struct _Repodata *data, struct _Repokey *key, struct _KeyValue *kv), void *cbdata) + { +@@ -1784,7 +1433,6 @@ pool_clear_pos(Pool *pool) + memset(&pool->pos, 0, sizeof(pool->pos)); + } + +- + void + pool_set_languages(Pool *pool, const char **languages, int nlanguages) + { +@@ -1951,330 +1599,6 @@ pool_bin2hex(Pool *pool, const unsigned char *buf, int len) + return s; + } + +-/*******************************************************************/ +- +-struct mptree { +- Id sibling; +- Id child; +- const char *comp; +- int compl; +- Id mountpoint; +-}; +- +-struct ducbdata { +- DUChanges *mps; +- struct mptree *mptree; +- int addsub; +- int hasdu; +- +- Id *dirmap; +- int nmap; +- Repodata *olddata; +-}; +- +- +-static int +-solver_fill_DU_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value) +-{ +- struct ducbdata *cbd = cbdata; +- Id mp; +- +- if (data != cbd->olddata) +- { +- Id dn, mp, comp, *dirmap, *dirs; +- int i, compl; +- const char *compstr; +- struct mptree *mptree; +- +- /* create map from dir to mptree */ +- cbd->dirmap = solv_free(cbd->dirmap); +- cbd->nmap = 0; +- dirmap = solv_calloc(data->dirpool.ndirs, sizeof(Id)); +- mptree = cbd->mptree; +- mp = 0; +- for (dn = 2, dirs = data->dirpool.dirs + dn; dn < data->dirpool.ndirs; dn++) +- { +- comp = *dirs++; +- if (comp <= 0) +- { +- mp = dirmap[-comp]; +- continue; +- } +- if (mp < 0) +- { +- /* unconnected */ +- dirmap[dn] = mp; +- continue; +- } +- if (!mptree[mp].child) +- { +- dirmap[dn] = -mp; +- continue; +- } +- if (data->localpool) +- compstr = stringpool_id2str(&data->spool, comp); +- else +- compstr = pool_id2str(data->repo->pool, comp); +- compl = strlen(compstr); +- for (i = mptree[mp].child; i; i = mptree[i].sibling) +- if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl)) +- break; +- dirmap[dn] = i ? i : -mp; +- } +- /* change dirmap to point to mountpoint instead of mptree */ +- for (dn = 0; dn < data->dirpool.ndirs; dn++) +- { +- mp = dirmap[dn]; +- dirmap[dn] = mptree[mp > 0 ? mp : -mp].mountpoint; +- } +- cbd->dirmap = dirmap; +- cbd->nmap = data->dirpool.ndirs; +- cbd->olddata = data; +- } +- cbd->hasdu = 1; +- if (value->id < 0 || value->id >= cbd->nmap) +- return 0; +- mp = cbd->dirmap[value->id]; +- if (mp < 0) +- return 0; +- if (cbd->addsub > 0) +- { +- cbd->mps[mp].kbytes += value->num; +- cbd->mps[mp].files += value->num2; +- } +- else if (!(cbd->mps[mp].flags & DUCHANGES_ONLYADD)) +- { +- cbd->mps[mp].kbytes -= value->num; +- cbd->mps[mp].files -= value->num2; +- } +- return 0; +-} +- +-static void +-propagate_mountpoints(struct mptree *mptree, int pos, Id mountpoint) +-{ +- int i; +- if (mptree[pos].mountpoint == -1) +- mptree[pos].mountpoint = mountpoint; +- else +- mountpoint = mptree[pos].mountpoint; +- for (i = mptree[pos].child; i; i = mptree[i].sibling) +- propagate_mountpoints(mptree, i, mountpoint); +-} +- +-#define MPTREE_BLOCK 15 +- +-static struct mptree * +-create_mptree(DUChanges *mps, int nmps) +-{ +- int i, nmptree; +- struct mptree *mptree; +- int pos, compl; +- int mp; +- const char *p, *path, *compstr; +- +- mptree = solv_extend_resize(0, 1, sizeof(struct mptree), MPTREE_BLOCK); +- +- /* our root node */ +- mptree[0].sibling = 0; +- mptree[0].child = 0; +- mptree[0].comp = 0; +- mptree[0].compl = 0; +- mptree[0].mountpoint = -1; +- nmptree = 1; +- +- /* create component tree */ +- for (mp = 0; mp < nmps; mp++) +- { +- mps[mp].kbytes = 0; +- mps[mp].files = 0; +- pos = 0; +- path = mps[mp].path; +- while(*path == '/') +- path++; +- while (*path) +- { +- if ((p = strchr(path, '/')) == 0) +- { +- compstr = path; +- compl = strlen(compstr); +- path += compl; +- } +- else +- { +- compstr = path; +- compl = p - path; +- path = p + 1; +- while(*path == '/') +- path++; +- } +- for (i = mptree[pos].child; i; i = mptree[i].sibling) +- if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl)) +- break; +- if (!i) +- { +- /* create new node */ +- mptree = solv_extend(mptree, nmptree, 1, sizeof(struct mptree), MPTREE_BLOCK); +- i = nmptree++; +- mptree[i].sibling = mptree[pos].child; +- mptree[i].child = 0; +- mptree[i].comp = compstr; +- mptree[i].compl = compl; +- mptree[i].mountpoint = -1; +- mptree[pos].child = i; +- } +- pos = i; +- } +- mptree[pos].mountpoint = mp; +- } +- +- propagate_mountpoints(mptree, 0, mptree[0].mountpoint); +- +-#if 0 +- for (i = 0; i < nmptree; i++) +- { +- printf("#%d sibling: %d\n", i, mptree[i].sibling); +- printf("#%d child: %d\n", i, mptree[i].child); +- printf("#%d comp: %s\n", i, mptree[i].comp); +- printf("#%d compl: %d\n", i, mptree[i].compl); +- printf("#%d mountpont: %d\n", i, mptree[i].mountpoint); +- } +-#endif +- +- return mptree; +-} +- +-void +-pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps) +-{ +- struct mptree *mptree; +- struct ducbdata cbd; +- Solvable *s; +- int i, sp; +- Map ignoredu; +- Repo *oldinstalled = pool->installed; +- int haveonlyadd = 0; +- +- map_init(&ignoredu, 0); +- mptree = create_mptree(mps, nmps); +- +- for (i = 0; i < nmps; i++) +- if ((mps[i].flags & DUCHANGES_ONLYADD) != 0) +- haveonlyadd = 1; +- cbd.mps = mps; +- cbd.dirmap = 0; +- cbd.nmap = 0; +- cbd.olddata = 0; +- cbd.mptree = mptree; +- cbd.addsub = 1; +- for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++) +- { +- if (!s->repo || (oldinstalled && s->repo == oldinstalled)) +- continue; +- if (!MAPTST(installedmap, sp)) +- continue; +- cbd.hasdu = 0; +- repo_search(s->repo, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); +- if (!cbd.hasdu && oldinstalled) +- { +- Id op, opp; +- int didonlyadd = 0; +- /* no du data available, ignore data of all installed solvables we obsolete */ +- if (!ignoredu.size) +- map_grow(&ignoredu, oldinstalled->end - oldinstalled->start); +- FOR_PROVIDES(op, opp, s->name) +- { +- Solvable *s2 = pool->solvables + op; +- if (!pool->implicitobsoleteusesprovides && s->name != s2->name) +- continue; +- if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, s2)) +- continue; +- if (op >= oldinstalled->start && op < oldinstalled->end) +- { +- MAPSET(&ignoredu, op - oldinstalled->start); +- if (haveonlyadd && pool->solvables[op].repo == oldinstalled && !didonlyadd) +- { +- repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); +- cbd.addsub = -1; +- repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); +- cbd.addsub = 1; +- didonlyadd = 1; +- } +- } +- } +- if (s->obsoletes) +- { +- Id obs, *obsp = s->repo->idarraydata + s->obsoletes; +- while ((obs = *obsp++) != 0) +- FOR_PROVIDES(op, opp, obs) +- { +- Solvable *s2 = pool->solvables + op; +- if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, s2, obs)) +- continue; +- if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2)) +- continue; +- if (op >= oldinstalled->start && op < oldinstalled->end) +- { +- MAPSET(&ignoredu, op - oldinstalled->start); +- if (haveonlyadd && pool->solvables[op].repo == oldinstalled && !didonlyadd) +- { +- repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); +- cbd.addsub = -1; +- repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); +- cbd.addsub = 1; +- didonlyadd = 1; +- } +- } +- } +- } +- } +- } +- cbd.addsub = -1; +- if (oldinstalled) +- { +- /* assumes we allways have du data for installed solvables */ +- FOR_REPO_SOLVABLES(oldinstalled, sp, s) +- { +- if (MAPTST(installedmap, sp)) +- continue; +- if (ignoredu.map && MAPTST(&ignoredu, sp - oldinstalled->start)) +- continue; +- repo_search(oldinstalled, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); +- } +- } +- map_free(&ignoredu); +- solv_free(cbd.dirmap); +- solv_free(mptree); +-} +- +-int +-pool_calc_installsizechange(Pool *pool, Map *installedmap) +-{ +- Id sp; +- Solvable *s; +- int change = 0; +- Repo *oldinstalled = pool->installed; +- +- for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++) +- { +- if (!s->repo || (oldinstalled && s->repo == oldinstalled)) +- continue; +- if (!MAPTST(installedmap, sp)) +- continue; +- change += solvable_lookup_sizek(s, SOLVABLE_INSTALLSIZE, 0); +- } +- if (oldinstalled) +- { +- FOR_REPO_SOLVABLES(oldinstalled, sp, s) +- { +- if (MAPTST(installedmap, sp)) +- continue; +- change -= solvable_lookup_sizek(s, SOLVABLE_INSTALLSIZE, 0); +- } +- } +- return change; +-} +- + /* map: + * 1: installed + * 2: conflicts with installed +-- +2.5.0 + diff --git a/0009-Make-_Pool_tmpspace-definition-internal.patch b/0009-Make-_Pool_tmpspace-definition-internal.patch new file mode 100644 index 0000000..2a40892 --- /dev/null +++ b/0009-Make-_Pool_tmpspace-definition-internal.patch @@ -0,0 +1,47 @@ +From e1f29013dd6eeb77db7fb0ad6e9343cd880ccbde Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Thu, 3 Mar 2016 15:18:34 +0100 +Subject: [PATCH 8/9] Make _Pool_tmpspace definition internal + +--- + src/pool.h | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/src/pool.h b/src/pool.h +index 4a2089d..b9e2ed6 100644 +--- a/src/pool.h ++++ b/src/pool.h +@@ -34,9 +34,6 @@ extern "C" { + #define SYSTEMSOLVABLE 1 + + +-/* how many strings to maintain (round robin) */ +-#define POOL_TMPSPACEBUF 16 +- + /*----------------------------------------------- */ + + struct _Repo; +@@ -52,12 +49,20 @@ typedef struct _Datapos { + Id dp; + } Datapos; + ++ ++#ifdef LIBSOLV_INTERNAL ++ ++/* how many strings to maintain (round robin) */ ++#define POOL_TMPSPACEBUF 16 ++ + struct _Pool_tmpspace { + char *buf[POOL_TMPSPACEBUF]; + int len[POOL_TMPSPACEBUF]; + int n; + }; + ++#endif ++ + struct _Pool { + void *appdata; /* application private pointer */ + +-- +2.5.0 + diff --git a/0010-Rework-orphan-handling-in-dup-mode.patch b/0010-Rework-orphan-handling-in-dup-mode.patch new file mode 100644 index 0000000..d4ef098 --- /dev/null +++ b/0010-Rework-orphan-handling-in-dup-mode.patch @@ -0,0 +1,311 @@ +From 6c9cef4ef810cd32ffeee20986a16e0871fc0bae Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Mon, 7 Mar 2016 14:09:40 +0100 +Subject: [PATCH 9/9] Rework orphan handling in dup mode + +The old code had problems when the updaters contained other +installed packages. +--- + src/rules.c | 193 +++++++++++++++++++++++++++++++++++++++++++---------------- + src/rules.h | 3 +- + src/solver.c | 7 ++- + 3 files changed, 149 insertions(+), 54 deletions(-) + +diff --git a/src/rules.c b/src/rules.c +index 4cd53d3..0e2c955 100644 +--- a/src/rules.c ++++ b/src/rules.c +@@ -1170,35 +1170,56 @@ solver_addpkgrulesforupdaters(Solver *solv, Solvable *s, Map *m, int allow_all) + *** + ***/ + ++static int ++dup_maykeepinstalled(Solver *solv, Solvable *s) ++{ ++ Pool *pool = solv->pool; ++ Id ip, pp; ++ ++ if (solv->dupmap.size && MAPTST(&solv->dupmap, s - pool->solvables)) ++ return 1; ++ /* is installed identical to a good one? */ ++ FOR_PROVIDES(ip, pp, s->name) ++ { ++ Solvable *is = pool->solvables + ip; ++ if (is->evr != s->evr) ++ continue; ++ if (solv->dupmap.size) ++ { ++ if (!MAPTST(&solv->dupmap, ip)) ++ continue; ++ } ++ else if (is->repo == pool->installed) ++ continue; ++ if (solvable_identical(s, is)) ++ return 1; ++ } ++ return 0; ++} ++ ++ + static Id +-finddistupgradepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all) ++finddistupgradepackages(Solver *solv, Solvable *s, Queue *qs) + { + Pool *pool = solv->pool; +- int i; ++ int i, j; + +- policy_findupdatepackages(solv, s, qs, allow_all ? allow_all : 2); +- if (!qs->count) ++ policy_findupdatepackages(solv, s, qs, 2); ++ if (qs->count) + { +- if (allow_all) +- return 0; /* orphaned, don't create feature rule */ +- /* check if this is an orphaned package */ +- policy_findupdatepackages(solv, s, qs, 1); +- if (!qs->count) +- return 0; /* orphaned, don't create update rule */ +- qs->count = 0; +- return -SYSTEMSOLVABLE; /* supported but not installable */ ++ /* remove installed packages we can't keep */ ++ for (i = j = 0; i < qs->count; i++) ++ { ++ Solvable *ns = pool->solvables + qs->elements[i]; ++ if (ns->repo == pool->installed && !dup_maykeepinstalled(solv, ns)) ++ continue; ++ qs->elements[j++] = qs->elements[i]; ++ } ++ queue_truncate(qs, j); + } +- if (allow_all) +- return s - pool->solvables; + /* check if it is ok to keep the installed package */ +- if (solv->dupmap.size && MAPTST(&solv->dupmap, s - pool->solvables)) ++ if (dup_maykeepinstalled(solv, s)) + return s - pool->solvables; +- for (i = 0; i < qs->count; i++) +- { +- Solvable *ns = pool->solvables + qs->elements[i]; +- if (s->evr == ns->evr && solvable_identical(s, ns)) +- return s - pool->solvables; +- } + /* nope, it must be some other package */ + return -SYSTEMSOLVABLE; + } +@@ -1240,6 +1261,73 @@ set_specialupdaters(Solver *solv, Solvable *s, Id d) + solv->specialupdaters[s - solv->pool->solvables - installed->start] = d; + } + ++#ifdef ENABLE_LINKED_PKGS ++/* Check if this is a linked pseudo package. As it is linked, we do not need an update/feature rule */ ++static inline int ++is_linked_pseudo_package(Solver *solv, Solvable *s) ++{ ++ Pool *pool = solv->pool; ++ if (solv->instbuddy && solv->instbuddy[s - pool->solvables - solv->installed->start]) ++ { ++ const char *name = pool_id2str(pool, s->name); ++ if (strncmp(name, "pattern:", 8) == 0 || strncmp(name, "application:", 12) == 0) ++ return 1; ++ } ++ return 0; ++} ++#endif ++ ++void ++solver_addfeaturerule(Solver *solv, Solvable *s) ++{ ++ Pool *pool = solv->pool; ++ int i; ++ Id p; ++ Queue qs; ++ Id qsbuf[64]; ++ ++#ifdef ENABLE_LINKED_PKGS ++ if (is_linked_pseudo_package(solv, s)) ++ { ++ solver_addrule(solv, 0, 0, 0); /* no feature rules for those */ ++ return; ++ } ++#endif ++ queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf)); ++ p = s - pool->solvables; ++ policy_findupdatepackages(solv, s, &qs, 1); ++ if (solv->dupmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))) ++ { ++ if (!dup_maykeepinstalled(solv, s)) ++ { ++ for (i = 0; i < qs.count; i++) ++ { ++ Solvable *ns = pool->solvables + qs.elements[i]; ++ if (ns->repo != pool->installed || dup_maykeepinstalled(solv, ns)) ++ break; ++ } ++ if (i == qs.count) ++ { ++ solver_addrule(solv, 0, 0, 0); /* this is an orphan */ ++ queue_free(&qs); ++ return; ++ } ++ } ++ } ++ if (qs.count > 1) ++ { ++ Id d = pool_queuetowhatprovides(pool, &qs); ++ queue_free(&qs); ++ solver_addrule(solv, p, 0, d); /* allow update of s */ ++ } ++ else ++ { ++ Id d = qs.count ? qs.elements[0] : 0; ++ queue_free(&qs); ++ solver_addrule(solv, p, d, 0); /* allow update of s */ ++ } ++} ++ + /*------------------------------------------------------------------- + * + * add rule for update +@@ -1249,7 +1337,7 @@ set_specialupdaters(Solver *solv, Solvable *s, Id d) + */ + + void +-solver_addupdaterule(Solver *solv, Solvable *s, int allow_all) ++solver_addupdaterule(Solver *solv, Solvable *s) + { + /* installed packages get a special upgrade allowed rule */ + Pool *pool = solv->pool; +@@ -1257,48 +1345,53 @@ solver_addupdaterule(Solver *solv, Solvable *s, int allow_all) + Queue qs; + Id qsbuf[64]; + int isorphaned = 0; ++ Rule *r; ++ int islinkedpseudo = 0; + +- queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf)); + p = s - pool->solvables; ++#ifdef ENABLE_LINKED_PKGS ++ islinkedpseudo = is_linked_pseudo_package(solv, s); ++#endif ++ ++ /* Orphan detection. We cheat by looking at the feature rule, which ++ * we already calculated */ ++ r = solv->rules + solv->featurerules + (p - solv->installed->start); ++ if (!r->p && !islinkedpseudo) ++ { ++ p = 0; ++ queue_push(&solv->orphaned, s - pool->solvables); /* an orphaned package */ ++ if (solv->keep_orphans && !(solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, s - pool->solvables - solv->installed->start)))) ++ p = s - pool->solvables; /* keep this orphaned package installed */ ++ solver_addrule(solv, p, 0, 0); ++ return; ++ } ++ ++ queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf)); + /* find update candidates for 's' */ + if (solv->dupmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))) +- p = finddistupgradepackages(solv, s, &qs, allow_all); ++ p = finddistupgradepackages(solv, s, &qs); + else +- policy_findupdatepackages(solv, s, &qs, allow_all); ++ policy_findupdatepackages(solv, s, &qs, 0); + + #ifdef ENABLE_LINKED_PKGS +- if (solv->instbuddy && solv->instbuddy[s - pool->solvables - solv->installed->start]) ++ if (islinkedpseudo) + { +- const char *name = pool_id2str(pool, s->name); +- if (strncmp(name, "pattern:", 8) == 0 || strncmp(name, "application:", 12) == 0) ++ /* a linked pseudo package. As it is linked, we do not need an update/feature rule */ ++ /* nevertheless we set specialupdaters so we can update */ ++ solver_addrule(solv, 0, 0, 0); ++ if (qs.count) + { +- /* a linked pseudo package. As it is linked, we do not need an update/feature rule */ +- /* nevertheless we set specialupdaters so we can update */ +- solver_addrule(solv, 0, 0, 0); +- if (!allow_all && qs.count) +- { +- if (p != -SYSTEMSOLVABLE) +- queue_unshift(&qs, p); +- if (qs.count) +- set_specialupdaters(solv, s, pool_queuetowhatprovides(pool, &qs)); +- } +- queue_free(&qs); +- return; ++ if (p != -SYSTEMSOLVABLE) ++ queue_unshift(&qs, p); ++ if (qs.count) ++ set_specialupdaters(solv, s, pool_queuetowhatprovides(pool, &qs)); + } +- } +-#endif +- +- if (!allow_all && !p) /* !p implies qs.count == 0 */ +- { +- queue_push(&solv->orphaned, s - pool->solvables); /* an orphaned package */ +- if (solv->keep_orphans && !(solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, s - pool->solvables - solv->installed->start)))) +- p = s - pool->solvables; /* keep this orphaned package installed */ + queue_free(&qs); +- solver_addrule(solv, p, 0, 0); + return; + } ++#endif + +- if (!allow_all && qs.count && solv->multiversion.size) ++ if (qs.count && solv->multiversion.size) + { + int i, j; + +diff --git a/src/rules.h b/src/rules.h +index 606819b..29325ea 100644 +--- a/src/rules.h ++++ b/src/rules.h +@@ -111,7 +111,8 @@ extern void solver_addpkgrulesforlinked(struct _Solver *solv, Map *m); + extern void solver_addpkgrulesforupdaters(struct _Solver *solv, Solvable *s, Map *m, int allow_all); + + /* update/feature rules */ +-extern void solver_addupdaterule(struct _Solver *solv, Solvable *s, int allow_all); ++extern void solver_addfeaturerule(struct _Solver *solv, Solvable *s); ++extern void solver_addupdaterule(struct _Solver *solv, Solvable *s); + + /* infarch rules */ + extern void solver_addinfarchrules(struct _Solver *solv, Map *addedmap); +diff --git a/src/solver.c b/src/solver.c +index 261f367..15a3114 100644 +--- a/src/solver.c ++++ b/src/solver.c +@@ -3716,7 +3716,7 @@ solver_solve(Solver *solv, Queue *job) + solver_addrule(solv, 0, 0, 0); /* create dummy rule */ + continue; + } +- solver_addupdaterule(solv, s, 1); /* allow s to be updated */ ++ solver_addfeaturerule(solv, s); + } + /* make sure we accounted for all rules */ + assert(solv->nrules - solv->featurerules == installed->end - installed->start); +@@ -3744,7 +3744,7 @@ solver_solve(Solver *solv, Queue *job) + solver_addrule(solv, 0, 0, 0); /* create dummy rule */ + continue; + } +- solver_addupdaterule(solv, s, 0); /* allowall = 0: downgrades not allowed */ ++ solver_addupdaterule(solv, s); + /* + * check for and remove duplicate + */ +@@ -3759,9 +3759,10 @@ solver_solve(Solver *solv, Queue *job) + /* it's also orphaned if the feature rule consists just of the installed package */ + if (!solv->dupmap_all && sr->p == i && !sr->d && !sr->w2) + queue_push(&solv->orphaned, i); ++ + if (!solver_rulecmp(solv, r, sr)) + memset(sr, 0, sizeof(*sr)); /* delete unneeded feature rule */ +- else ++ else if (sr->p) + solver_disablerule(solv, sr); /* disable feature rule for now */ + } + /* consistency check: we added a rule for _every_ installed solvable */ +-- +2.5.0 + diff --git a/libsolv.spec b/libsolv.spec index 2142ae3..a38efc1 100644 --- a/libsolv.spec +++ b/libsolv.spec @@ -30,11 +30,20 @@ Name: libsolv Version: 0.6.19 -Release: 1%{?dist} +Release: 2%{?dist} License: BSD Url: https://github.com/openSUSE/libsolv Source: https://github.com/openSUSE/libsolv/archive/%{version}.tar.gz#/%{name}-%{version}.tar.gz Patch0: 0001-ruby-make-compatible-with-ruby-2.2.patch +Patch1: 0002-Add-repodata_lookup_dirstrarray_uninternalized-metho.patch +Patch2: 0003-Do-not-create-a-checksum-hash-when-we-re-not-extendi.patch +Patch3: 0004-solv_hex2bin-don-t-eat-nibbles.patch +Patch4: 0005-Use-less-memory-when-extending-packages.patch +Patch5: 0006-Fix-comments.patch +Patch6: 0007-rpmmd-diskusage-prepend-a-to-the-dir-if-not-already-.patch +Patch7: 0008-Split-diskusage-and-fileprovides-code-into-separate-.patch +Patch8: 0009-Make-_Pool_tmpspace-definition-internal.patch +Patch9: 0010-Rework-orphan-handling-in-dup-mode.patch Group: Development/Libraries Summary: Package dependency solver @@ -225,6 +234,9 @@ make ARGS="-V" test %endif %changelog +* Tue Mar 8 2016 Jaroslav Mracek - 0.6.19-2 +- Apply 9 patches from upstream + * Sat Feb 27 2016 Igor Gnatenko - 0.6.19-1 - Update to 0.6.19