void queue_alloc_one(Queue *q) { if (!q->alloc) { q->alloc = solv_malloc2(q->count + EXTRA_SPACE, sizeof(Id)); if (q->count) memcpy(q->alloc, q->elements, q->count * sizeof(Id)); q->elements = q->alloc; q->left = EXTRA_SPACE; } else if (q->alloc != q->elements) { int l = q->elements - q->alloc; if (q->count) memmove(q->alloc, q->elements, q->count * sizeof(Id)); q->elements -= l; q->left += l; } else { q->elements = q->alloc = solv_realloc2(q->alloc, q->count + EXTRA_SPACE, sizeof(Id)); q->left = EXTRA_SPACE; } }
/* * we support three relations: * * a = b both architectures a and b are treated as equivalent * a > b a is considered a "better" architecture, the solver * should change from a to b, but must not change from b to a * a : b a is considered a "better" architecture, the solver * must not change the architecture from a to b or b to a */ void pool_setarchpolicy(Pool *pool, const char *arch) { unsigned int score = 0x10001; size_t l; char d; Id *id2arch; Id id, lastarch; pool->id2arch = solv_free(pool->id2arch); pool->id2color = solv_free(pool->id2color); if (!arch) { pool->lastarch = 0; return; } id = pool->noarchid; lastarch = id + 255; /* note that we overallocate one element to be compatible with * old versions that accessed id2arch[lastarch]. * id2arch[lastarch] will always be zero */ id2arch = solv_calloc(lastarch + 1, sizeof(Id)); id2arch[id] = 1; /* the "noarch" class */ d = 0; while (*arch) { l = strcspn(arch, ":=>"); if (l) { id = pool_strn2id(pool, arch, l, 1); if (id >= lastarch) { id2arch = solv_realloc2(id2arch, (id + 255 + 1), sizeof(Id)); memset(id2arch + lastarch + 1, 0, (id + 255 - lastarch) * sizeof(Id)); lastarch = id + 255; } if (id2arch[id] == 0) { if (d == ':') score += 0x10000; else if (d == '>') score += 0x00001; id2arch[id] = score; } } arch += l; if ((d = *arch++) == 0) break; } pool->id2arch = id2arch; pool->lastarch = lastarch; }
/* allocate room for n more elements */ void queue_prealloc(Queue *q, int n) { int off; if (n <= 0 || q->left >= n) return; if (!q->alloc) queue_alloc_one(q); off = q->elements - q->alloc; q->alloc = solv_realloc2(q->alloc, off + q->count + n + EXTRA_SPACE, sizeof(Id)); q->elements = q->alloc + off; q->left = n + EXTRA_SPACE; }
/* * we support three relations: * * a = b both architectures a and b are treated as equivalent * a > b a is considered a "better" architecture, the solver * should change from a to b, but must not change from b to a * a : b a is considered a "better" architecture, the solver * must not change the architecture from a to b or b to a */ void pool_setarchpolicy(Pool *pool, const char *arch) { unsigned int score = 0x10001; size_t l; char d; Id *id2arch; Id id, lastarch; pool->id2arch = solv_free(pool->id2arch); pool->id2color = solv_free(pool->id2color); if (!arch) { pool->lastarch = 0; return; } id = pool->noarchid; lastarch = id + 255; id2arch = solv_calloc(lastarch + 1, sizeof(Id)); id2arch[id] = 1; /* the "noarch" class */ d = 0; while (*arch) { l = strcspn(arch, ":=>"); if (l) { id = pool_strn2id(pool, arch, l, 1); if (id > lastarch) { id2arch = solv_realloc2(id2arch, (id + 255 + 1), sizeof(Id)); memset(id2arch + lastarch + 1, 0, (id + 255 - lastarch) * sizeof(Id)); lastarch = id + 255; } if (id2arch[id] == 0) { if (d == ':') score += 0x10000; else if (d == '>') score += 0x00001; id2arch[id] = score; } } arch += l; if ((d = *arch++) == 0) break; } pool->id2arch = id2arch; pool->lastarch = lastarch; }
void queue_insertn(Queue *q, int pos, int n) { if (n <= 0) return; if (pos > q->count) pos = q->count; if (q->left < n) { int off; if (!q->alloc) queue_alloc_one(q); off = q->elements - q->alloc; q->alloc = solv_realloc2(q->alloc, off + q->count + n + EXTRA_SPACE, sizeof(Id)); q->elements = q->alloc + off; q->left = n + EXTRA_SPACE; } if (pos < q->count) memmove(q->elements + pos + n, q->elements + pos, (q->count - pos) * sizeof(Id)); memset(q->elements + pos, 0, n * sizeof(Id)); q->left -= n; q->count += n; }
Repo * repo_create(Pool *pool, const char *name) { Repo *repo; pool_freewhatprovides(pool); repo = (Repo *)solv_calloc(1, sizeof(*repo)); if (!pool->nrepos) { pool->nrepos = 1; /* start with repoid 1 */ pool->repos = (Repo **)solv_calloc(2, sizeof(Repo *)); } else pool->repos = (Repo **)solv_realloc2(pool->repos, pool->nrepos + 1, sizeof(Repo *)); pool->repos[pool->nrepos] = repo; pool->urepos++; repo->repoid = pool->nrepos++; repo->name = name ? solv_strdup(name) : 0; repo->pool = pool; repo->start = pool->nsolvables; repo->end = pool->nsolvables; repo->nsolvables = 0; return repo; }
void pool_addvendorclass(Pool *pool, const char **vendorclass) { int i, j; if (!vendorclass || !vendorclass[0]) return; for (j = 1; vendorclass[j]; j++) ; i = 0; if (pool->vendorclasses) { for (i = 0; pool->vendorclasses[i] || pool->vendorclasses[i + 1]; i++) ; if (i) i++; } pool->vendorclasses = solv_realloc2((void *)pool->vendorclasses, i + j + 2, sizeof(const char *)); for (j = 0; vendorclass[j]; j++) pool->vendorclasses[i++] = solv_strdup(vendorclass[j]); pool->vendorclasses[i++] = 0; pool->vendorclasses[i] = 0; queue_empty(&pool->vendormap); }
Id pool_rel2id(Pool *pool, Id name, Id evr, int flags, int create) { Hashval h, hh, hashmask; int i; Id id; Hashtable hashtbl; Reldep *ran; hashmask = pool->relhashmask; hashtbl = pool->relhashtbl; ran = pool->rels; /* extend hashtable if needed */ if (pool->nrels * 2 > hashmask) { solv_free(pool->relhashtbl); pool->relhashmask = hashmask = mkmask(pool->nrels + REL_BLOCK); pool->relhashtbl = hashtbl = solv_calloc(hashmask + 1, sizeof(Id)); /* rehash all rels into new hashtable */ for (i = 1; i < pool->nrels; i++) { h = relhash(ran[i].name, ran[i].evr, ran[i].flags) & hashmask; hh = HASHCHAIN_START; while (hashtbl[h]) h = HASHCHAIN_NEXT(h, hh, hashmask); hashtbl[h] = i; } } /* compute hash and check for match */ h = relhash(name, evr, flags) & hashmask; hh = HASHCHAIN_START; while ((id = hashtbl[h]) != 0) { if (ran[id].name == name && ran[id].evr == evr && ran[id].flags == flags) break; h = HASHCHAIN_NEXT(h, hh, hashmask); } if (id) return MAKERELDEP(id); if (!create) return ID_NULL; id = pool->nrels++; /* extend rel space if needed */ pool->rels = solv_extend(pool->rels, id, 1, sizeof(Reldep), REL_BLOCK); hashtbl[h] = id; ran = pool->rels + id; ran->name = name; ran->evr = evr; ran->flags = flags; /* extend whatprovides_rel if needed */ if (pool->whatprovides_rel && (id & WHATPROVIDES_BLOCK) == 0) { pool->whatprovides_rel = solv_realloc2(pool->whatprovides_rel, id + (WHATPROVIDES_BLOCK + 1), sizeof(Offset)); memset(pool->whatprovides_rel + id, 0, (WHATPROVIDES_BLOCK + 1) * sizeof(Offset)); } return MAKERELDEP(id); }
static void repo_addfileprovides_search(Repo *repo, struct addfileprovides_cbdata *cbd, struct searchfiles *sf) { Repodata *data; int rdid, p, i; int provstart, provend; Map todo; Map providedids; if (repo->end <= repo->start || !repo->nsolvables || !sf->nfiles) return; /* update search data if changed */ if (cbd->nfiles != sf->nfiles || cbd->ids != sf->ids) { free_dirs_names_array(cbd); cbd->nfiles = sf->nfiles; cbd->ids = sf->ids; cbd->dids = solv_realloc2(cbd->dids, sf->nfiles, sizeof(Id)); } /* create todo map and range */ map_init(&todo, repo->end - repo->start); for (p = repo->start; p < repo->end; p++) if (repo->pool->solvables[p].repo == repo) MAPSET(&todo, p - repo->start); cbd->todo = &todo; cbd->todo_start = repo->start; cbd->todo_end = repo->end; prune_todo_range(repo, cbd); provstart = provend = 0; map_init(&providedids, 0); data = repo_lookup_repodata(repo, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES); if (data) { Queue fileprovidesq; queue_init(&fileprovidesq); if (repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &fileprovidesq)) { map_grow(&providedids, repo->pool->ss.nstrings); cbd->providedids = &providedids; provstart = data->start; provend = data->end; for (i = 0; i < fileprovidesq.count; i++) MAPSET(&providedids, fileprovidesq.elements[i]); for (i = 0; i < cbd->nfiles; i++) if (!MAPTST(&providedids, cbd->ids[i])) break; if (i == cbd->nfiles) { /* all included, clear entries from todo list */ if (provstart <= cbd->todo_start && provend >= cbd->todo_end) cbd->todo_end = cbd->todo_start; /* clear complete range */ else { for (p = provstart; p < provend; p++) MAPCLR(&todo, p - repo->start); prune_todo_range(repo, cbd); } } } queue_free(&fileprovidesq); } if (cbd->todo_start >= cbd->todo_end) { map_free(&todo); cbd->todo = 0; map_free(&providedids); cbd->providedids = 0; return; } /* this is similar to repo_lookup_filelist_repodata in repo.c */ for (rdid = 1, data = repo->repodata + rdid; rdid < repo->nrepodata; rdid++, data++) if (data->filelisttype == REPODATA_FILELIST_FILTERED) break; for (; rdid < repo->nrepodata; rdid++, data++) if (data->filelisttype == REPODATA_FILELIST_EXTENSION) break; if (rdid < repo->nrepodata) { /* have at least one repodata with REPODATA_FILELIST_FILTERED followed by REPODATA_FILELIST_EXTENSION */ Map postpone; map_init(&postpone, 0); for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > 0; rdid--, data--) { if (data->filelisttype != REPODATA_FILELIST_FILTERED) continue; if (!repodata_intersects_todo(data, cbd)) continue; if (data->state != REPODATA_AVAILABLE) { if (data->state != REPODATA_STUB) continue; repodata_load(data); if (data->state != REPODATA_AVAILABLE || data->filelisttype != REPODATA_FILELIST_FILTERED) continue; } repo_addfileprovides_search_filtered(repo, cbd, rdid, &postpone); } if (postpone.size) { /* add postponed entries back to todo */ map_or(&todo, &postpone); cbd->todo_start = repo->start; cbd->todo_end = repo->end; prune_todo_range(repo, cbd); } map_free(&postpone); } /* search remaining entries in the standard way */ if (cbd->todo_start < cbd->todo_end) { for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > 0; rdid--, data--) { if (data->start >= cbd->todo_end || data->end <= cbd->todo_start) continue; if (!repodata_has_keyname(data, SOLVABLE_FILELIST)) continue; if (!repodata_intersects_todo(data, cbd)) continue; repodata_addfileprovides_search(data, cbd); if (cbd->todo_start >= cbd->todo_end) break; } } map_free(&todo); cbd->todo = 0; map_free(&providedids); cbd->providedids = 0; }
/* * Optimization for packages with an excessive amount of provides/requires: * if the number of deps exceed a threshold, we build a hash of the already * seen ids. */ static Offset repo_addid_dep_hash(Repo *repo, Offset olddeps, Id id, Id marker, int size) { Id oid, *oidp; int before; Hashval h, hh; Id hid; before = 0; if (marker) { if (marker < 0) { marker = -marker; before = 1; } if (marker == id) marker = 0; } /* maintain hash and lastmarkerpos */ if (repo->lastidhash_idarraysize != repo->idarraysize || size * 2 > repo->lastidhash_mask || repo->lastmarker != marker) { repo->lastmarkerpos = 0; if (size * 2 > repo->lastidhash_mask) { repo->lastidhash_mask = mkmask(size < REPO_ADDID_DEP_HASHMIN ? REPO_ADDID_DEP_HASHMIN : size); repo->lastidhash = solv_realloc2(repo->lastidhash, repo->lastidhash_mask + 1, sizeof(Id)); } memset(repo->lastidhash, 0, (repo->lastidhash_mask + 1) * sizeof(Id)); for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != 0; oidp++) { h = oid & repo->lastidhash_mask; hh = HASHCHAIN_START; while (repo->lastidhash[h] != 0) h = HASHCHAIN_NEXT(h, hh, repo->lastidhash_mask); repo->lastidhash[h] = oid; if (marker && oid == marker) repo->lastmarkerpos = oidp - repo->idarraydata; } repo->lastmarker = marker; repo->lastidhash_idarraysize = repo->idarraysize; } /* check the hash! */ h = id & repo->lastidhash_mask; hh = HASHCHAIN_START; while ((hid = repo->lastidhash[h]) != 0 && hid != id) h = HASHCHAIN_NEXT(h, hh, repo->lastidhash_mask); /* put new element in hash */ if (!hid) repo->lastidhash[h] = id; else if (marker == SOLVABLE_FILEMARKER && (!before || !repo->lastmarkerpos)) return olddeps; if (marker && !before && !repo->lastmarkerpos) { /* we have to add the marker first */ repo->lastmarkerpos = repo->idarraysize - 1; olddeps = repo_addid(repo, olddeps, marker); /* now put marker in hash */ h = marker & repo->lastidhash_mask; hh = HASHCHAIN_START; while (repo->lastidhash[h] != 0) h = HASHCHAIN_NEXT(h, hh, repo->lastidhash_mask); repo->lastidhash[h] = marker; repo->lastidhash_idarraysize = repo->idarraysize; } if (!hid) { /* new entry, insert in correct position */ if (marker && before && repo->lastmarkerpos) { /* need to add it before the marker */ olddeps = repo_addid(repo, olddeps, id); /* dummy to make room */ memmove(repo->idarraydata + repo->lastmarkerpos + 1, repo->idarraydata + repo->lastmarkerpos, (repo->idarraysize - repo->lastmarkerpos - 2) * sizeof(Id)); repo->idarraydata[repo->lastmarkerpos++] = id; } else { /* just append it to the end */ olddeps = repo_addid(repo, olddeps, id); } repo->lastidhash_idarraysize = repo->idarraysize; return olddeps; } /* we already have it in the hash */ if (!marker) return olddeps; if (marker == SOLVABLE_FILEMARKER) { /* check if it is in the wrong half */ /* (we already made sure that "before" and "lastmarkerpos" are set, see above) */ for (oidp = repo->idarraydata + repo->lastmarkerpos + 1; (oid = *oidp) != 0; oidp++) if (oid == id) break; if (!oid) return olddeps; /* yes, wrong half. copy it over */ memmove(repo->idarraydata + repo->lastmarkerpos + 1, repo->idarraydata + repo->lastmarkerpos, (oidp - (repo->idarraydata + repo->lastmarkerpos)) * sizeof(Id)); repo->idarraydata[repo->lastmarkerpos++] = id; return olddeps; } if (before) return olddeps; /* check if it is in the correct half */ for (oidp = repo->idarraydata + repo->lastmarkerpos + 1; (oid = *oidp) != 0; oidp++) if (oid == id) return olddeps; /* nope, copy it over */ for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != 0; oidp++) if (oid == id) break; if (!oid) return olddeps; /* should not happen */ memmove(oidp, oidp + 1, (repo->idarraydata + repo->idarraysize - oidp - 2) * sizeof(Id)); repo->idarraydata[repo->idarraysize - 2] = id; repo->lastmarkerpos--; /* marker has been moved */ return olddeps; }
int tool_write(Repo *repo, const char *basename, const char *attrname) { Repodata *data; Repodata *info = 0; Repokey *key; char **languages = 0; int nlanguages = 0; int i, j, k, l; Id *addedfileprovides = 0; struct keyfilter_data kd; memset(&kd, 0, sizeof(kd)); info = repo_add_repodata(repo, 0); repodata_set_str(info, SOLVID_META, REPOSITORY_TOOLVERSION, LIBSOLV_TOOLVERSION); pool_addfileprovides_ids(repo->pool, 0, &addedfileprovides); if (addedfileprovides && *addedfileprovides) { kd.haveaddedfileprovides = 1; for (i = 0; addedfileprovides[i]; i++) repodata_add_idarray(info, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, addedfileprovides[i]); } solv_free(addedfileprovides); pool_freeidhashes(repo->pool); /* free some mem */ if (basename) { char fn[4096]; FILE *fp; int has_DU = 0; int has_FL = 0; /* find languages and other info */ FOR_REPODATAS(repo, i, data) { for (j = 1, key = data->keys + j; j < data->nkeys; j++, key++) { const char *keyname = pool_id2str(repo->pool, key->name); if (key->name == SOLVABLE_DISKUSAGE) has_DU = 1; if (key->name == SOLVABLE_FILELIST) has_FL = 1; for (k = 0; languagetags[k] != 0; k++) if (!strncmp(keyname, languagetags[k], strlen(languagetags[k]))) break; if (!languagetags[k]) continue; l = strlen(languagetags[k]); if (strlen(keyname + l) > 5) continue; for (k = 0; k < nlanguages; k++) if (!strcmp(languages[k], keyname + l)) break; if (k < nlanguages) continue; languages = solv_realloc2(languages, nlanguages + 1, sizeof(char *)); languages[nlanguages++] = strdup(keyname + l); } } /* write language subfiles */ for (i = 0; i < nlanguages; i++) { sprintf(fn, "%s.%s.solv", basename, languages[i]); if (!(fp = fopen(fn, "w"))) { perror(fn); exit(1); } write_info(repo, fp, keyfilter_language, languages[i], info, fn); fclose(fp); kd.haveexternal = 1; } /* write DU subfile */ if (has_DU) { sprintf(fn, "%s.DU.solv", basename); if (!(fp = fopen(fn, "w"))) { perror(fn); exit(1); } write_info(repo, fp, keyfilter_DU, 0, info, fn); fclose(fp); kd.haveexternal = 1; } /* write filelist */ if (has_FL) { sprintf(fn, "%s.FL.solv", basename); if (!(fp = fopen(fn, "w"))) { perror(fn); exit(1); } write_info(repo, fp, keyfilter_FL, 0, info, fn); fclose(fp); kd.haveexternal = 1; } /* write everything else */ sprintf(fn, "%s.solv", basename); if (!(fp = fopen(fn, "w"))) { perror(fn); exit(1); } kd.languages = languages; kd.nlanguages = nlanguages; repodata_internalize(info); repo_write(repo, fp, keyfilter_other, &kd, 0); fclose(fp); for (i = 0; i < nlanguages; i++) free(languages[i]); solv_free(languages); repodata_free(info); return 0; } if (attrname) { FILE *fp; test_separate = 1; fp = fopen(attrname, "w"); write_info(repo, fp, keyfilter_attr, 0, info, attrname); fclose(fp); kd.haveexternal = 1; } repodata_internalize(info); repo_write(repo, stdout, keyfilter_solv, &kd, 0); repodata_free(info); return 0; }