2 * Copyright (c) 2007, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
11 * The pool contains information about solvables
12 * stored optimized for memory consumption and fast retrieval.
24 #include "poolid_private.h"
30 #define SOLVABLE_BLOCK 255
33 * list of string constants, so we can do pointer/Id instead of string comparison
34 * index into array matches ID_xxx constants in pool.h
37 static const char *initpool_data[] = {
48 "solvable:recommends",
50 "solvable:supplements",
53 "rpm:dbid", /* direct key into rpmdb */
54 "solvable:prereqmarker",
55 "solvable:filemarker",
56 "namespace:installed",
58 "namespace:splitprovides",
68 "repokey:type:constant",
69 "repokey:type:constantid",
75 "repokey:type:idarray",
76 "repokey:type:relidarray",
77 "repokey:type:dirstrarray",
78 "repokey:type:dirnumnumarray",
81 "solvable:description",
89 "solvable:messageins",
90 "solvable:messagedel",
92 "solvable:installsize",
96 "solvable:installtime",
101 "solvable:downloadsize",
103 "solvable:sourcearch",
104 "solvable:sourcename",
105 "solvable:sourceevr",
107 "solvable:isvisible", /* from susetags */
109 "solvable:patchcategory",
121 pool = (Pool *)sat_calloc(1, sizeof(*pool));
123 stringpool_init (&pool->ss, initpool_data);
125 /* alloc space for ReDep 0 */
126 pool->rels = sat_extend_resize(0, 1, sizeof(Reldep), REL_BLOCK);
128 memset(pool->rels, 0, sizeof(Reldep));
130 /* alloc space for Solvable 0 and system solvable */
131 pool->solvables = sat_extend_resize(0, 2, sizeof(Solvable), SOLVABLE_BLOCK);
132 pool->nsolvables = 2;
133 memset(pool->solvables, 0, 2 * sizeof(Solvable));
134 s = pool->solvables + SYSTEMSOLVABLE;
135 s->name = SYSTEM_SYSTEM;
136 s->arch = ARCH_NOARCH;
139 queue_init(&pool->vendormap);
141 pool->debugmask = SAT_DEBUG_RESULT; /* FIXME */
146 /* free all the resources of our pool */
148 pool_free(Pool *pool)
152 pool_freewhatprovides(pool);
153 pool_freeidhashes(pool);
154 repo_freeallrepos(pool, 1);
155 sat_free(pool->id2arch);
156 sat_free(pool->solvables);
157 sat_free(pool->ss.stringspace);
158 sat_free(pool->ss.strings);
159 sat_free(pool->rels);
160 queue_free(&pool->vendormap);
161 for (i = 0; i < DEP2STRBUF; i++)
162 sat_free(pool->dep2strbuf[i]);
163 for (i = 0; i < pool->nlanguages; i++)
164 free((char *)pool->languages[i]);
165 sat_free(pool->languages);
170 pool_add_solvable(Pool *pool)
172 pool->solvables = sat_extend(pool->solvables, pool->nsolvables, 1, sizeof(Solvable), SOLVABLE_BLOCK);
173 memset(pool->solvables + pool->nsolvables, 0, sizeof(Solvable));
174 return pool->nsolvables++;
178 pool_add_solvable_block(Pool *pool, int count)
180 Id nsolvables = pool->nsolvables;
183 pool->solvables = sat_extend(pool->solvables, pool->nsolvables, count, sizeof(Solvable), SOLVABLE_BLOCK);
184 memset(pool->solvables + nsolvables, 0, sizeof(Solvable) * count);
185 pool->nsolvables += count;
190 pool_free_solvable_block(Pool *pool, Id start, int count, int reuseids)
194 if (reuseids && start + count == pool->nsolvables)
196 /* might want to shrink solvable array */
197 pool->nsolvables = start;
200 memset(pool->solvables + start, 0, sizeof(Solvable) * count);
205 solvable2str(Pool *pool, Solvable *s)
207 int l, nn = pool->dep2strn;
208 const char *n, *e, *a;
209 n = id2str(pool, s->name);
210 e = id2str(pool, s->evr);
211 a = id2str(pool, s->arch);
212 l = strlen(n) + strlen(e) + strlen(a) + 3;
213 if (l > pool->dep2strlen[nn])
215 pool->dep2strbuf[nn] = sat_realloc(pool->dep2strbuf[nn], l + 32);
216 pool->dep2strlen[nn] = l + 32;
218 sprintf(pool->dep2strbuf[nn], "%s-%s.%s", n, e, a);
219 pool->dep2strn = (nn + 1) % DEP2STRBUF;
220 return pool->dep2strbuf[nn];
223 static Pool *pool_shrink_whatprovides_sortcmp_data;
226 pool_shrink_whatprovides_sortcmp(const void *ap, const void *bp)
229 Pool *pool = pool_shrink_whatprovides_sortcmp_data;
231 oa = pool->whatprovides[*(Id *)ap];
232 ob = pool->whatprovides[*(Id *)bp];
234 return *(Id *)ap - *(Id *)bp;
239 da = pool->whatprovidesdata + oa;
240 db = pool->whatprovidesdata + ob;
242 if ((r = (*da++ - *db++)) != 0)
246 return *(Id *)ap - *(Id *)bp;
250 * pool_shrink_whatprovides - unify whatprovides data
252 * whatprovides_rel must be empty for this to work!
256 pool_shrink_whatprovides(Pool *pool)
260 Id lastid, *last, *dp, *lp;
264 if (pool->ss.nstrings < 3)
266 sorted = sat_malloc2(pool->ss.nstrings, sizeof(Id));
267 for (id = 0; id < pool->ss.nstrings; id++)
269 pool_shrink_whatprovides_sortcmp_data = pool;
270 qsort(sorted + 1, pool->ss.nstrings - 1, sizeof(Id), pool_shrink_whatprovides_sortcmp);
273 for (i = 1; i < pool->ss.nstrings; i++)
276 o = pool->whatprovides[id];
277 if (o == 0 || o == 1)
279 dp = pool->whatprovidesdata + o;
293 pool->whatprovides[id] = -lastid;
297 last = pool->whatprovidesdata + o;
301 dp = pool->whatprovidesdata + 2;
302 for (id = 1; id < pool->ss.nstrings; id++)
304 o = pool->whatprovides[id];
305 if (o == 0 || o == 1)
312 pool->whatprovides[id] = pool->whatprovides[i];
315 lp = pool->whatprovidesdata + o;
318 pool->whatprovides[id] = dp - pool->whatprovidesdata;
319 while ((*dp++ = *lp++) != 0)
322 o = dp - pool->whatprovidesdata;
323 POOL_DEBUG(SAT_DEBUG_STATS, "shrunk whatprovidesdata from %d to %d\n", pool->whatprovidesdataoff, o);
324 if (pool->whatprovidesdataoff == o)
326 r = pool->whatprovidesdataoff - o;
327 pool->whatprovidesdataoff = o;
328 pool->whatprovidesdata = sat_realloc(pool->whatprovidesdata, (o + pool->whatprovidesdataleft) * sizeof(Id));
329 if (r > pool->whatprovidesdataleft)
330 r = pool->whatprovidesdataleft;
331 memset(pool->whatprovidesdata + o, 0, r * sizeof(Id));
336 * pool_createwhatprovides()
338 * create hashes over pool of solvables to ease provide lookups
342 pool_createwhatprovides(Pool *pool)
344 int i, num, np, extra;
349 Offset *whatprovides;
350 Id *whatprovidesdata, *d;
352 POOL_DEBUG(SAT_DEBUG_STATS, "number of solvables: %d\n", pool->nsolvables);
353 POOL_DEBUG(SAT_DEBUG_STATS, "number of ids: %d + %d\n", pool->ss.nstrings, pool->nrels);
355 pool_freeidhashes(pool); /* XXX: should not be here! */
356 pool_freewhatprovides(pool);
357 num = pool->ss.nstrings;
358 pool->whatprovides = whatprovides = sat_extend_resize(0, num, sizeof(Offset), WHATPROVIDES_BLOCK);
359 memset(whatprovides, 0, num * sizeof(Offset));
360 pool->whatprovides_rel = sat_extend_resize(0, pool->nrels, sizeof(Offset), WHATPROVIDES_BLOCK);
361 memset(pool->whatprovides_rel, 0, pool->nrels * sizeof(Offset));
363 /* count providers for each name */
364 for (i = 1; i < pool->nsolvables; i++)
367 s = pool->solvables + i;
370 if (!pool_installable(pool, s))
372 pp = s->repo->idarraydata + s->provides;
373 while ((id = *pp++) != ID_NULL)
377 Reldep *rd = GETRELDEP(pool, id);
380 whatprovides[id]++; /* inc count of providers */
384 off = 2; /* first entry is undef, second is empty list */
386 np = 0; /* number of names provided */
387 for (i = 0; i < num; i++, idp++)
390 if (!n) /* no providers */
392 *idp = off; /* move from counts to offsets into whatprovidesdata */
393 off += n + 1; /* make space for all providers + terminating ID_NULL */
394 np++; /* inc # of provider 'slots' */
397 POOL_DEBUG(SAT_DEBUG_STATS, "provide ids: %d\n", np);
399 /* reserve some space for relation data */
400 extra = 2 * pool->nrels;
404 POOL_DEBUG(SAT_DEBUG_STATS, "provide space needed: %d + %d\n", off, extra);
406 /* alloc space for all providers + extra */
407 whatprovidesdata = sat_calloc(off + extra, sizeof(Id));
409 /* now fill data for all provides */
410 for (i = 1; i < pool->nsolvables; i++)
413 s = pool->solvables + i;
416 if (!pool_installable(pool, s))
419 /* for all provides of this solvable */
420 pp = s->repo->idarraydata + s->provides;
421 while ((id = *pp++) != 0)
425 Reldep *rd = GETRELDEP(pool, id);
428 d = whatprovidesdata + whatprovides[id]; /* offset into whatprovidesdata */
432 while (*d) /* find free slot */
437 *d = i; /* put solvable Id into data */
440 pool->whatprovidesdata = whatprovidesdata;
441 pool->whatprovidesdataoff = off;
442 pool->whatprovidesdataleft = extra;
443 pool_shrink_whatprovides(pool);
447 * free all of our whatprovides data
448 * be careful, everything internalized with pool_queuetowhatprovides is gone, too
451 pool_freewhatprovides(Pool *pool)
453 pool->whatprovides = sat_free(pool->whatprovides);
454 pool->whatprovides_rel = sat_free(pool->whatprovides_rel);
455 pool->whatprovidesdata = sat_free(pool->whatprovidesdata);
456 pool->whatprovidesdataoff = 0;
457 pool->whatprovidesdataleft = 0;
461 /******************************************************************************/
464 * pool_queuetowhatprovides - add queue contents to whatprovidesdata
466 * on-demand filling of provider information
467 * move queue data into whatprovidesdata
469 * returns: Offset into whatprovides
473 pool_queuetowhatprovides(Pool *pool, Queue *q)
476 int count = q->count;
478 if (count == 0) /* queue empty -> ID_EMPTY */
481 /* extend whatprovidesdata if needed, +1 for ID_NULL-termination */
482 if (pool->whatprovidesdataleft < count + 1)
484 POOL_DEBUG(SAT_DEBUG_STATS, "growing provides hash data...\n");
485 pool->whatprovidesdata = sat_realloc(pool->whatprovidesdata, (pool->whatprovidesdataoff + count + 4096) * sizeof(Id));
486 pool->whatprovidesdataleft = count + 4096;
489 /* copy queue to next free slot */
490 off = pool->whatprovidesdataoff;
491 memcpy(pool->whatprovidesdata + pool->whatprovidesdataoff, q->elements, count * sizeof(Id));
493 /* adapt count and ID_NULL-terminate */
494 pool->whatprovidesdataoff += count;
495 pool->whatprovidesdata[pool->whatprovidesdataoff++] = ID_NULL;
496 pool->whatprovidesdataleft -= count + 1;
502 /*************************************************************************/
507 * add packages fulfilling the relation to whatprovides array
508 * no exact providers, do range match
513 pool_addrelproviders(Pool *pool, Id d)
515 Reldep *rd = GETRELDEP(pool, d);
521 int flags = rd->flags;
523 Id p, *pp, *pp2, *pp3;
526 queue_init_buffer(&plist, buf, sizeof(buf)/sizeof(*buf));
531 pp = pool_whatprovides(pool, name);
532 pp2 = pool_whatprovides(pool, evr);
533 while ((p = *pp++) != 0)
535 for (pp3 = pp2; *pp3;)
538 queue_push(&plist, p);
544 pp = pool_whatprovides(pool, name);
545 while ((p = *pp++) != 0)
546 queue_push(&plist, p);
547 pp = pool_whatprovides(pool, evr);
548 while ((p = *pp++) != 0)
549 queue_pushunique(&plist, p);
552 if (pool->nscallback)
554 p = pool->nscallback(pool, pool->nscallbackdata, name, evr);
558 pool->whatprovides_rel[d] = p;
559 return pool->whatprovidesdata + p;
562 queue_push(&plist, SYSTEMSOLVABLE);
569 /* convert to whatprovides id */
571 POOL_DEBUG(SAT_DEBUG_STATS, "addrelproviders: what provides %s?\n", dep2str(pool, name));
573 if (flags && flags < 8)
575 FOR_PROVIDES(p, pp, name)
578 POOL_DEBUG(DEBUG_1, "addrelproviders: checking package %s\n", id2str(pool, pool->p[p].name));
580 /* solvable p provides name in some rels */
581 pidp = pool->solvables[p].repo->idarraydata + pool->solvables[p].provides;
582 while ((pid = *pidp++) != 0)
589 #ifdef DEBIAN_SEMANTICS
590 continue; /* unversioned provides can
591 * never match versioned deps */
593 break; /* yes, provides all versions */
597 continue; /* wrong provides name */
598 prd = GETRELDEP(pool, pid);
599 if (prd->name != name)
600 continue; /* wrong provides name */
601 /* right package, both deps are rels */
605 if (flags == 7 || pflags == 7)
606 break; /* included */
607 if ((pflags & flags & 5) != 0)
608 break; /* same direction, match */
612 if ((pflags & flags & 2) != 0)
613 break; /* both have =, match */
617 int f = flags == 5 ? 5 : flags == 2 ? pflags : (flags ^ 5) & (pflags | 5);
618 if ((f & (1 << (1 + evrcmp(pool, pevr, evr, EVRCMP_MATCH_RELEASE)))) != 0)
623 continue; /* no rel match */
624 queue_push(&plist, p);
626 /* make our system solvable provide all unknown rpmlib() stuff */
627 if (plist.count == 0 && !strncmp(id2str(pool, name), "rpmlib(", 7))
628 queue_push(&plist, SYSTEMSOLVABLE);
630 /* add providers to whatprovides */
632 POOL_DEBUG(SAT_DEBUG_STATS, "addrelproviders: adding %d packages to %d\n", plist.count, d);
634 pool->whatprovides_rel[d] = pool_queuetowhatprovides(pool, &plist);
637 return pool->whatprovidesdata + pool->whatprovides_rel[d];
640 /*************************************************************************/
643 pool_debug(Pool *pool, int type, const char *format, ...)
648 if ((type & (SAT_FATAL|SAT_ERROR)) == 0)
650 if ((pool->debugmask & type) == 0)
653 va_start(args, format);
654 if (!pool->debugcallback)
656 if ((type & (SAT_FATAL|SAT_ERROR)) == 0)
657 vprintf(format, args);
659 vfprintf(stderr, format, args);
662 vsnprintf(buf, sizeof(buf), format, args);
663 pool->debugcallback(pool, pool->debugcallbackdata, type, buf);
667 pool_setdebuglevel(Pool *pool, int level)
669 int mask = SAT_DEBUG_RESULT;
671 mask |= SAT_DEBUG_STATS|SAT_DEBUG_ANALYZE|SAT_DEBUG_UNSOLVABLE;
673 mask |= SAT_DEBUG_JOB|SAT_DEBUG_SOLUTIONS|SAT_DEBUG_POLICY;
675 mask |= SAT_DEBUG_PROPAGATE;
677 mask |= SAT_DEBUG_RULE_CREATION;
679 mask |= SAT_DEBUG_SCHUBI;
680 pool->debugmask = mask;
683 /*************************************************************************/
693 #define SEARCHFILES_BLOCK 127
696 pool_addfileprovides_dep(Pool *pool, Id *ida, struct searchfiles *sf, struct searchfiles *isf)
701 while ((dep = *ida++) != 0)
703 while (ISRELDEP(dep))
706 sid = pool->ss.nstrings + GETRELID(dep);
707 if (MAPTST(&sf->seen, sid))
712 MAPSET(&sf->seen, sid);
713 rd = GETRELDEP(pool, dep);
716 else if (rd->flags == REL_NAMESPACE)
718 if (isf && (rd->name == NAMESPACE_INSTALLED || rd->name == NAMESPACE_SPLITPROVIDES))
722 if (MAPTST(&sf->seen, sid))
727 MAPSET(&sf->seen, sid);
736 pool_addfileprovides_dep(pool, ids, sf, isf);
742 if (MAPTST(&sf->seen, dep))
744 MAPSET(&sf->seen, dep);
745 s = id2str(pool, dep);
748 sf->ids = sat_extend(sf->ids, sf->nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK);
749 sf->dirs = sat_extend(sf->dirs, sf->nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK);
750 sf->names = sat_extend(sf->names, sf->nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK);
751 sf->ids[sf->nfiles] = dep;
752 sr = strrchr(s, '/');
753 sf->names[sf->nfiles] = strdup(sr + 1);
754 sf->dirs[sf->nfiles] = sat_malloc(sr - s + 1);
756 strncpy(sf->dirs[sf->nfiles], s, sr - s);
757 sf->dirs[sf->nfiles][sr - s] = 0;
762 struct addfileprovides_cbdata {
774 addfileprovides_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value)
776 struct addfileprovides_cbdata *cbd = cbdata;
779 if (data != cbd->olddata)
781 map_free(&cbd->useddirs);
782 map_init(&cbd->useddirs, data->dirpool.ndirs);
783 for (i = 0; i < cbd->nfiles; i++)
785 Id did = repodata_str2dir(data, cbd->dirs[i], 0);
788 MAPSET(&cbd->useddirs, did);
792 if (!MAPTST(&cbd->useddirs, value->id))
794 for (i = 0; i < cbd->nfiles; i++)
796 if (cbd->dids[i] != value->id)
798 if (!strcmp(cbd->names[i], value->str))
801 if (i == cbd->nfiles)
803 s->provides = repo_addid_dep(s->repo, s->provides, cbd->ids[i], SOLVABLE_FILEMARKER);
808 pool_addfileprovides(Pool *pool, Repo *installed)
812 struct searchfiles sf, isf;
813 struct addfileprovides_cbdata cbd;
816 memset(&sf, 0, sizeof(sf));
817 map_init(&sf.seen, pool->ss.nstrings + pool->nrels);
818 memset(&isf, 0, sizeof(isf));
819 map_init(&isf.seen, pool->ss.nstrings + pool->nrels);
821 for (i = 1, s = pool->solvables + i; i < pool->nsolvables; i++, s++)
827 pool_addfileprovides_dep(pool, repo->idarraydata + s->obsoletes, &sf, &isf);
829 pool_addfileprovides_dep(pool, repo->idarraydata + s->conflicts, &sf, &isf);
831 pool_addfileprovides_dep(pool, repo->idarraydata + s->requires, &sf, &isf);
833 pool_addfileprovides_dep(pool, repo->idarraydata + s->recommends, &sf, &isf);
835 pool_addfileprovides_dep(pool, repo->idarraydata + s->suggests, &sf, &isf);
837 pool_addfileprovides_dep(pool, repo->idarraydata + s->supplements, &sf, &isf);
839 pool_addfileprovides_dep(pool, repo->idarraydata + s->enhances, &sf, &isf);
841 pool_addfileprovides_dep(pool, repo->idarraydata + s->freshens, &sf, &isf);
845 POOL_DEBUG(SAT_DEBUG_STATS, "found %d file dependencies\n", sf.nfiles);
846 POOL_DEBUG(SAT_DEBUG_STATS, "found %d installed file dependencies\n", isf.nfiles);
848 map_init(&cbd.useddirs, 1);
852 for (i = 0; i < sf.nfiles; i++)
853 POOL_DEBUG(SAT_DEBUG_STATS, "looking up %s in filelist\n", id2str(pool, sf.ids[i]));
855 cbd.nfiles = sf.nfiles;
858 cbd.names = sf.names;
860 cbd.dids = sat_realloc2(cbd.dids, sf.nfiles, sizeof(Id));
861 pool_search(pool, 0, SOLVABLE_FILELIST, 0, 0, addfileprovides_cb, &cbd);
863 for (i = 0; i < sf.nfiles; i++)
865 sat_free(sf.dirs[i]);
866 sat_free(sf.names[i]);
871 if (isf.nfiles && installed)
874 for (i = 0; i < isf.nfiles; i++)
875 POOL_DEBUG(SAT_DEBUG_STATS, "looking up %s in installed filelist\n", id2str(pool, isf.ids[i]));
877 cbd.nfiles = isf.nfiles;
880 cbd.names = isf.names;
882 cbd.dids = sat_realloc2(cbd.dids, isf.nfiles, sizeof(Id));
883 repo_search(installed, 0, SOLVABLE_FILELIST, 0, 0, addfileprovides_cb, &cbd);
885 for (i = 0; i < isf.nfiles; i++)
887 sat_free(isf.dirs[i]);
888 sat_free(isf.names[i]);
893 map_free(&cbd.useddirs);
895 pool_freewhatprovides(pool); /* as we have added provides */
899 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)
903 if (pool->solvables[p].repo)
904 repo_search(pool->solvables[p].repo, p, key, match, flags, callback, cbdata);
907 /* FIXME: obey callback return value! */
908 for (p = 1; p < pool->nsolvables; p++)
909 if (pool->solvables[p].repo)
910 repo_search(pool->solvables[p].repo, p, key, match, flags, callback, cbdata);
915 pool_set_languages(Pool *pool, const char **languages, int nlanguages)
919 pool->languagecache = sat_free(pool->languagecache);
920 pool->languagecacheother = 0;
921 if (pool->nlanguages)
923 for (i = 0; i < pool->nlanguages; i++)
924 free((char *)pool->languages[i]);
925 free(pool->languages);
927 pool->nlanguages = nlanguages;
930 pool->languages = sat_calloc(nlanguages, sizeof(const char **));
931 for (i = 0; i < pool->nlanguages; i++)
932 pool->languages[i] = strdup(languages[i]);
936 solvable_lookup_str_lang(Solvable *s, Id keyname)
944 return repo_lookup_str(s, keyname);
945 pool = s->repo->pool;
946 if (!pool->nlanguages)
947 return repo_lookup_str(s, keyname);
948 cols = pool->nlanguages + 1;
949 if (!pool->languagecache)
951 pool->languagecache = sat_calloc(cols * ID_NUM_INTERNAL, sizeof(Id));
952 pool->languagecacheother = 0;
954 if (keyname >= ID_NUM_INTERNAL)
956 row = pool->languagecache + ID_NUM_INTERNAL * cols;
957 for (i = 0; i < pool->languagecacheother; i++, row += cols)
960 if (i >= pool->languagecacheother)
962 pool->languagecache = sat_realloc2(pool->languagecache, pool->languagecacheother + 1, cols * sizeof(Id));
963 pool->languagecacheother++;
964 row = pool->languagecache + cols * (ID_NUM_INTERNAL + pool->languagecacheother++);
968 row = pool->languagecache + keyname * cols;
969 row++; /* skip keyname */
970 for (i = 0; i < pool->nlanguages; i++, row++)
977 kn = id2str(pool, keyname);
978 p = sat_malloc(strlen(kn) + strlen(pool->languages[i]) + 2);
979 sprintf(p, "%s:%s", kn, pool->languages[i]);
980 *row = str2id(pool, p, 1);
982 str = repo_lookup_str(s, *row);
986 return repo_lookup_str(s, keyname);