diff options
Diffstat (limited to 'ext')
-rw-r--r-- | ext/repo_rpmdb.c | 81 | ||||
-rw-r--r-- | ext/repo_rpmmd.c | 283 | ||||
-rw-r--r-- | ext/testcase.c | 17 |
3 files changed, 293 insertions, 88 deletions
diff --git a/ext/repo_rpmdb.c b/ext/repo_rpmdb.c index d49f9d8..308cfe5 100644 --- a/ext/repo_rpmdb.c +++ b/ext/repo_rpmdb.c @@ -407,18 +407,27 @@ setutf8string(Repodata *repodata, Id handle, Id tag, const char *str) repodata_set_str(repodata, handle, tag, str); } +static int +ignq_sortcmp(const void *va, const void *vb, void *dp) +{ + int r = *(Id *)va - *(Id *)vb; + if (!r) + r = ((Id *)va)[1] - ((Id *)vb)[1]; + return r; +} + /* * strong: 0: ignore strongness * 1: filter to strong * 2: filter to weak */ static unsigned int -makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf, int flags) +makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf, int flags, Queue *ignq) { char **n, **v; unsigned int *f; int i, cc, nc, vc, fc; - int haspre, premask; + int haspre, premask, has_ign; unsigned int olddeps; Id *ida; int strong = 0; @@ -512,6 +521,8 @@ makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf, cc += haspre; /* add slot for the prereq marker */ olddeps = repo_reserve_ids(repo, 0, cc); ida = repo->idarraydata + olddeps; + + has_ign = 0; for (i = 0; ; i++) { Id id; @@ -564,12 +575,33 @@ makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf, id = pool_rel2id(pool, id, evr, fl, 1); } *ida++ = id; + if (haspre == 2 && ignq) + { + int is_ign = (f[i] & DEP_PRE_IN) != 0 && (f[i] & DEP_PRE_UN) == 0 ? 1 : 0; + has_ign |= is_ign; + queue_push2(ignq, id, is_ign); + } } *ida++ = 0; repo->idarraysize += cc + 1; solv_free(n); solv_free(v); solv_free(f); + if (has_ign && ignq->count > 2) + { + Id id, lastid = 0; + int j; + + solv_sort(ignq->elements, ignq->count / 2, sizeof(Id) * 2, ignq_sortcmp, 0); + for (i = j = 0; i < ignq->count; i += 2) + { + id = ignq->elements[i]; + if (id != lastid && ignq->elements[i + 1] > 0) + ignq->elements[j++] = id; + lastid = id; + } + queue_truncate(ignq, j); + } return olddeps; } @@ -909,6 +941,8 @@ rpm2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, char *name; char *evr; char *sourcerpm; + Queue ignq; + Id ignqbuf[64]; name = headstring(rpmhead, TAG_NAME); if (!name) @@ -935,21 +969,27 @@ rpm2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, s->evr = pool_str2id(pool, evr, 1); s->vendor = pool_str2id(pool, headstring(rpmhead, TAG_VENDOR), 1); - s->provides = makedeps(pool, repo, rpmhead, TAG_PROVIDENAME, TAG_PROVIDEVERSION, TAG_PROVIDEFLAGS, 0); + queue_init_buffer(&ignq, ignqbuf, sizeof(ignqbuf)/sizeof(*ignqbuf)); + + s->provides = makedeps(pool, repo, rpmhead, TAG_PROVIDENAME, TAG_PROVIDEVERSION, TAG_PROVIDEFLAGS, 0, 0); if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC) s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0); - s->requires = makedeps(pool, repo, rpmhead, TAG_REQUIRENAME, TAG_REQUIREVERSION, TAG_REQUIREFLAGS, flags); - s->conflicts = makedeps(pool, repo, rpmhead, TAG_CONFLICTNAME, TAG_CONFLICTVERSION, TAG_CONFLICTFLAGS, 0); - s->obsoletes = makedeps(pool, repo, rpmhead, TAG_OBSOLETENAME, TAG_OBSOLETEVERSION, TAG_OBSOLETEFLAGS, 0); + s->requires = makedeps(pool, repo, rpmhead, TAG_REQUIRENAME, TAG_REQUIREVERSION, TAG_REQUIREFLAGS, flags, &ignq); + s->conflicts = makedeps(pool, repo, rpmhead, TAG_CONFLICTNAME, TAG_CONFLICTVERSION, TAG_CONFLICTFLAGS, 0, 0); + s->obsoletes = makedeps(pool, repo, rpmhead, TAG_OBSOLETENAME, TAG_OBSOLETEVERSION, TAG_OBSOLETEFLAGS, 0, 0); - s->recommends = makedeps(pool, repo, rpmhead, TAG_RECOMMENDNAME, TAG_RECOMMENDVERSION, TAG_RECOMMENDFLAGS, 0); - s->suggests = makedeps(pool, repo, rpmhead, TAG_SUGGESTNAME, TAG_SUGGESTVERSION, TAG_SUGGESTFLAGS, 0); - s->supplements = makedeps(pool, repo, rpmhead, TAG_SUPPLEMENTNAME, TAG_SUPPLEMENTVERSION, TAG_SUPPLEMENTFLAGS, 0); - s->enhances = makedeps(pool, repo, rpmhead, TAG_ENHANCENAME, TAG_ENHANCEVERSION, TAG_ENHANCEFLAGS, 0); + s->recommends = makedeps(pool, repo, rpmhead, TAG_RECOMMENDNAME, TAG_RECOMMENDVERSION, TAG_RECOMMENDFLAGS, 0, 0); + s->suggests = makedeps(pool, repo, rpmhead, TAG_SUGGESTNAME, TAG_SUGGESTVERSION, TAG_SUGGESTFLAGS, 0, 0); + s->supplements = makedeps(pool, repo, rpmhead, TAG_SUPPLEMENTNAME, TAG_SUPPLEMENTVERSION, TAG_SUPPLEMENTFLAGS, 0, 0); + s->enhances = makedeps(pool, repo, rpmhead, TAG_ENHANCENAME, TAG_ENHANCEVERSION, TAG_ENHANCEFLAGS, 0, 0); s->supplements = repo_fix_supplements(repo, s->provides, s->supplements, 0); s->conflicts = repo_fix_conflicts(repo, s->conflicts); + if (data && ignq.count) + repodata_set_idarray(data, s - pool->solvables, SOLVABLE_PREREQ_IGNOREINST, &ignq); + queue_free(&ignq); + if (data) { Id handle; @@ -1014,24 +1054,11 @@ rpm2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, repodata_set_sourcepkg(data, handle, sourcerpm); if ((flags & RPM_ADD_TRIGGERS) != 0) { - Id id, lastid; - unsigned int ida = makedeps(pool, repo, rpmhead, TAG_TRIGGERNAME, TAG_TRIGGERVERSION, TAG_TRIGGERFLAGS, 0); - - lastid = 0; - for (; (id = repo->idarraydata[ida]) != 0; ida++) - { - /* we currently do not support rel ids in incore data, so - * strip off versioning information */ - while (ISRELDEP(id)) - { - Reldep *rd = GETRELDEP(pool, id); - id = rd->name; - } - if (id == lastid) - continue; + unsigned int ida = makedeps(pool, repo, rpmhead, TAG_TRIGGERNAME, TAG_TRIGGERVERSION, TAG_TRIGGERFLAGS, 0, 0); + Id id, lastid = 0; + for (lastid = 0; (id = repo->idarraydata[ida]) != 0; ida++, lastid = id) + if (id != lastid) repodata_add_idarray(data, handle, SOLVABLE_TRIGGERS, id); - lastid = id; - } } if ((flags & RPM_ADD_NO_FILELIST) == 0) addfilelist(data, handle, rpmhead, flags); diff --git a/ext/repo_rpmmd.c b/ext/repo_rpmmd.c index a45d491..78264cc 100644 --- a/ext/repo_rpmmd.c +++ b/ext/repo_rpmmd.c @@ -258,12 +258,15 @@ struct parsedata { Id changelog_handle; - /** Hash to maps checksums to solv */ - Stringpool cspool; - /** Cache of known checksums to solvable id */ - Id *cscache; - /* the current longest index in the table */ - int ncscache; + int extending; /* are we extending an existing solvable? */ + 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 */ + int ncshash; /* entries used */ + unsigned char *csdata; /* [len, checksum, id] */ + int ncsdata; /* used bytes */ }; static Id @@ -577,6 +580,156 @@ 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) +{ +} + +static void +free_cshash(struct parsedata *pd) +{ + 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); + } +} + +static void +put_in_cshash(struct parsedata *pd, const unsigned char *key, int keyl, Id id) +{ + 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) + { + 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); + } + } + /* 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 unsigned char *key, int keyl) +{ + Hashtable ht; + Hashval h, hh, hm; + + if (keyl < 4 || keyl > 256) + return 0; + ht = pd->cshash; + if (!ht) + return 0; + 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 +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)) + put_in_cshash(pd, (const unsigned char *)di.kv.str, solv_chksum_len(di.key->type), di.solvid); + dataiterator_free(&di); +} + +static void +fill_cshash_from_new_solvables(struct parsedata *pd) +{ + Pool *pool = pd->pool; + Id cstype = 0; + 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, cs, solv_chksum_len(cstype), i); + } +} + +/*-----------------------------------------------*/ /* XML callbacks */ /* @@ -664,26 +817,45 @@ 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) { + 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 */ - Id index = stringpool_str2id(&pd->cspool, pkgid, 0); - if (!index || index >= pd->ncscache || !pd->cscache[index]) + 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); - 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 +869,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: @@ -840,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, "<dir .../> 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) @@ -923,6 +1106,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 +1123,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,26 +1145,20 @@ endElement(void *userData, const char *name) break; case STATE_CHECKSUM: { - Id index; - - 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); - /* 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; + 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, chk, l, s - pool->solvables); break; } case STATE_FILE: @@ -1165,32 +1347,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 +1375,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)) diff --git a/ext/testcase.c b/ext/testcase.c index b9fddef..536875c 100644 --- a/ext/testcase.c +++ b/ext/testcase.c @@ -1190,8 +1190,10 @@ testcase_write_testtags(Repo *repo, FILE *fp) const char *release; const char *tmp; unsigned int ti; + Queue q; fprintf(fp, "=Ver: 3.0\n"); + queue_init(&q); FOR_REPO_SOLVABLES(repo, p, s) { name = pool_id2str(pool, s->name); @@ -1212,6 +1214,14 @@ testcase_write_testtags(Repo *repo, FILE *fp) writedeps(repo, fp, "Sup:", SOLVABLE_SUPPLEMENTS, s, s->supplements); writedeps(repo, fp, "Sug:", SOLVABLE_SUGGESTS, s, s->suggests); writedeps(repo, fp, "Enh:", SOLVABLE_ENHANCES, s, s->enhances); + if (solvable_lookup_idarray(s, SOLVABLE_PREREQ_IGNOREINST, &q)) + { + int i; + fprintf(fp, "+Ipr:\n"); + for (i = 0; i < q.count; i++) + fprintf(fp, "%s\n", testcase_dep2str(pool, q.elements[i])); + fprintf(fp, "-Ipr:\n"); + } if (s->vendor) fprintf(fp, "=Vnd: %s\n", pool_id2str(pool, s->vendor)); ti = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0); @@ -1219,6 +1229,7 @@ testcase_write_testtags(Repo *repo, FILE *fp) fprintf(fp, "=Tim: %u\n", ti); writefilelist(repo, fp, "Fls:", s); } + queue_free(&q); return 0; } @@ -1417,6 +1428,12 @@ testcase_add_testtags(Repo *repo, FILE *fp, int flags) case 'E' << 16 | 'n' << 8 | 'h': s->enhances = adddep(repo, s->enhances, line + 6, 0); break; + case 'I' << 16 | 'p' << 8 | 'r': + { + Id id = line[6] == '/' ? pool_str2id(pool, line + 6, 1) : testcase_str2dep(pool, line + 6); + repodata_add_idarray(data, s - pool->solvables, SOLVABLE_PREREQ_IGNOREINST, id); + break; + } default: break; } |