- do not add rules that are always fulfilled
[platform/upstream/libsolv.git] / src / pool.c
1 /*
2  * pool.c
3  * 
4  * The pool contains information about solvables
5  * stored optimized for memory consumption and fast retrieval.
6  */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <string.h>
12
13 #include "pool.h"
14 #include "poolid.h"
15 #include "poolid_private.h"
16 #include "poolarch.h"
17 #include "util.h"
18 #include "evr.h"
19
20
21 // reset all whatprovides
22 // 
23 void
24 pool_freewhatprovides(Pool *pool)
25 {
26   pool->whatprovides = xfree(pool->whatprovides);
27   pool->whatprovidesdata = xfree(pool->whatprovidesdata);
28   pool->whatprovidesdataoff = 0;
29   pool->whatprovidesdataleft = 0;
30 }
31
32
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
35
36 static char *initpool_data[] = {
37   "<NULL>",                   // ID_NULL
38   "",                         // ID_EMPTY
39   "solvable:name",
40   "solvable:arch",
41   "solvable:evr",
42   "solvable:provides",
43   "solvable:obsoletes",
44   "solvable:conflicts",
45   "solvable:requires",
46   "solvable:recommends",
47   "solvable:suggests",
48   "solvable:supplements",
49   "solvable:enhances",
50   "solvable:freshens",
51   "rpm:dbid",                          /* direct key into rpmdb */
52   "solvable:prereqmarker",
53   "solvable:filemarker",
54   "namespace:installed",
55   "namespace:modalias",
56   "system:system",
57   "src",
58   "nosrc",
59   "noarch"
60 };
61
62 // create pool
63 // 
64 Pool *
65 pool_create(void)
66 {
67   int count, totalsize = 0;
68   Pool *pool;
69   Solvable *s;
70
71   pool = (Pool *)xcalloc(1, sizeof(*pool));
72
73   // count number and total size of predefined strings
74   for (count = 0; count < sizeof(initpool_data)/sizeof(*initpool_data); count++)
75     totalsize += strlen(initpool_data[count]) + 1;
76
77   // alloc appropriate space
78   pool->stringspace = (char *)xmalloc((totalsize + STRINGSPACE_BLOCK) & ~STRINGSPACE_BLOCK);
79   pool->strings = (Offset *)xmalloc(((count + STRING_BLOCK) & ~STRING_BLOCK) * sizeof(Offset));
80
81   // now copy predefined strings into allocated space
82   pool->sstrings = 0;
83   for (count = 0; count < sizeof(initpool_data)/sizeof(*initpool_data); count++)
84     {
85       strcpy(pool->stringspace + pool->sstrings, initpool_data[count]);
86       pool->strings[count] = pool->sstrings;
87       pool->sstrings += strlen(initpool_data[count]) + 1;
88     }
89   pool->nstrings = count;
90
91   // pre-alloc space for a RelDep
92   pool->rels = (Reldep *)xcalloc(1 + REL_BLOCK, sizeof(Reldep));
93   pool->nrels = 1;
94
95   // pre-alloc space for a Solvable
96   pool->solvables = (Solvable *)xcalloc(2, sizeof(Solvable));
97   pool->nsolvables = 2;
98   s = pool->solvables + SYSTEMSOLVABLE;
99   s->name = SYSTEM_SYSTEM;
100   s->arch = ARCH_NOARCH;
101   s->evr = ID_EMPTY;
102   return pool;
103 }
104
105
106 // empty the pool
107 // 
108 void
109 pool_free(Pool *pool)
110 {
111   int i;
112   Source *source;
113
114   pool_freewhatprovides(pool);
115   pool_freeidhashes(pool);
116   for (i = 0; i < pool->nsources; i++)
117     {
118       source = pool->sources[i];
119       xfree(source->idarraydata);
120       xfree(source->rpmdbid);
121       xfree(source);
122     }
123   xfree(pool->solvables);
124   xfree(pool->sources);
125   xfree(pool->stringspace);
126   xfree(pool->strings);
127   xfree(pool->rels);
128   xfree(pool);
129 }
130
131
132 static Pool *pool_shrink_whatprovides_sortcmp_data;
133
134 static int
135 pool_shrink_whatprovides_sortcmp(const void *ap, const void *bp)
136 {
137   int r;
138   Pool *pool = pool_shrink_whatprovides_sortcmp_data;
139   Id oa, ob, *da, *db;
140   oa = pool->whatprovides[*(Id *)ap];
141   ob = pool->whatprovides[*(Id *)bp];
142   if (oa == ob)
143     return *(Id *)ap - *(Id *)bp;
144   if (!oa)
145     return -1;
146   if (!ob)
147     return 1;
148   da = pool->whatprovidesdata + oa;
149   db = pool->whatprovidesdata + ob;
150   while (*db)
151     if ((r = (*da++ - *db++)) != 0)
152       return r;
153   if (*da)
154     return *da;
155   return *(Id *)ap - *(Id *)bp;
156 }
157
158 static void
159 pool_shrink_whatprovides(Pool *pool)
160 {
161   Id i, id;
162   Id *sorted;
163   Id lastid, *last, *dp, *lp;
164   Offset o;
165   int r;
166
167   if (pool->nstrings < 3)
168     return;
169   sorted = xmalloc2(pool->nstrings, sizeof(Id));
170   for (id = 0; id < pool->nstrings; id++)
171     sorted[id] = id;
172   pool_shrink_whatprovides_sortcmp_data = pool;
173   qsort(sorted + 1, pool->nstrings - 1, sizeof(Id), pool_shrink_whatprovides_sortcmp);
174   last = 0;
175   lastid = 0;
176   for (i = 1; i < pool->nstrings; i++)
177     {
178       id = sorted[i];
179       o = pool->whatprovides[id];
180       if (o == 0 || o == 1)
181         continue;
182       dp = pool->whatprovidesdata + o;
183       if (last)
184         {
185           lp = last;
186           while (*dp)   
187             if (*dp++ != *lp++)
188               {
189                 last = 0;
190                 break;
191               }
192           if (last && *lp)
193             last = 0;
194           if (last)
195             {
196               pool->whatprovides[id] = -lastid;
197               continue;
198             }
199         }
200       last = pool->whatprovidesdata + o;
201       lastid = id;
202     }
203   xfree(sorted);
204   dp = pool->whatprovidesdata + 2;
205   for (id = 1; id < pool->nstrings; id++)
206     {
207       o = pool->whatprovides[id];
208       if (o == 0 || o == 1)
209         continue;
210       if ((Id)o < 0)
211         {
212           i = -(Id)o;
213           if (i >= id)
214             abort();
215           pool->whatprovides[id] = pool->whatprovides[i];
216           continue;
217         }
218       lp = pool->whatprovidesdata + o;
219       if (lp < dp)
220         abort();
221       pool->whatprovides[id] = dp - pool->whatprovidesdata;
222       while ((*dp++ = *lp++) != 0)
223         ;
224     }
225   o = dp - pool->whatprovidesdata;
226   if (pool->verbose)
227     printf("shrunk whatprovidesdata from %d to %d\n", pool->whatprovidesdataoff, o);
228   if (pool->whatprovidesdataoff == o)
229     return;
230   r = pool->whatprovidesdataoff - o;
231   pool->whatprovidesdataoff = o;
232   pool->whatprovidesdata = xrealloc(pool->whatprovidesdata, (o + pool->whatprovidesdataleft) * sizeof(Id));
233   if (r > pool->whatprovidesdataleft)
234     r = pool->whatprovidesdataleft;
235   memset(pool->whatprovidesdata + o, 0, r * sizeof(Id));
236 }
237
238
239 /*
240  * pool_prepare()
241  * 
242  * create hashes over complete pool to ease lookups
243  * 
244  */
245
246 void
247 pool_prepare(Pool *pool)
248 {
249   int i, num, np, extra;
250   unsigned int n;
251   Offset off;
252   Solvable *s;
253   Id id;
254   Offset *idp;
255   Offset *whatprovides;
256   Id *whatprovidesdata, *d;
257
258   if (pool->verbose)
259     printf("number of solvables: %d\n", pool->nsolvables);
260   if (pool->verbose)
261     printf("number of ids: %d + %d\n", pool->nstrings, pool->nrels);
262
263   pool_freeidhashes(pool);
264   pool_freewhatprovides(pool);
265   num = pool->nstrings + pool->nrels;
266   whatprovides = (Offset *)xcalloc(num, sizeof(Offset));
267
268   /* count providers for each name */
269   for (i = 1; i < pool->nsolvables; i++)
270     {
271       Id *pp;
272       s = pool->solvables + i;
273       if (!s->provides)
274         continue;
275       if (!pool_installable(pool, s))
276         continue;
277       pp = s->source->idarraydata + s->provides;
278       while ((id = *pp++) != ID_NULL)
279         {
280           if (ISRELDEP(id))
281             {
282               Reldep *rd = GETRELDEP(pool, id);
283               id = rd->name;
284             }
285           whatprovides[id]++;          /* inc count of providers */
286         }
287     }
288
289   off = 2;      /* first entry is undef, second is empty list */
290   idp = whatprovides;
291   np = 0;                              /* number of names provided */
292   for (i = 0; i < num; i++, idp++)
293     {
294       n = *idp;
295       if (!n)                          /* no providers */
296         continue;
297       *idp = off;                      /* move from counts to offsets into whatprovidesdata */
298       off += n + 1;                    /* make space for all providers + terminating ID_NULL */
299       np++;                            /* inc # of provider 'slots' */
300     }
301
302   if (pool->verbose)
303     printf("provide ids: %d\n", np);
304   extra = 2 * pool->nrels;
305
306   if (extra < 256)
307     extra = 256;
308
309   if (pool->verbose)
310     printf("provide space needed: %d + %d\n", off, extra);
311
312   /* alloc space for all providers + extra */
313   whatprovidesdata = (Id *)xcalloc(off + extra, sizeof(Id));
314
315   /* now fill data for all provides */
316   for (i = 1; i < pool->nsolvables; i++)
317     {
318       Id *pp;
319       s = pool->solvables + i;
320       if (!s->provides)
321         continue;
322       if (!pool_installable(pool, s))
323         continue;
324
325       /* for all provides of this solvable */
326       pp = s->source->idarraydata + s->provides;
327       while ((id = *pp++) != 0)
328         {
329           if (ISRELDEP(id))
330             {
331               Reldep *rd = GETRELDEP(pool, id);
332               id = rd->name;
333             }
334           d = whatprovidesdata + whatprovides[id];   /* offset into whatprovidesdata */
335           if (*d)
336             {
337               d++;
338               while (*d)               /* find free slot */
339                 d++;
340               if (d[-1] == i)
341                 {
342 #if 0
343                   if (pool->verbose) printf("duplicate entry for %s in package %s.%s\n", id2str(pool, id), id2str(pool, s->name), id2str(pool, s->arch));
344 #endif
345                   continue;
346                 }
347             }
348           *d = i;                      /* put solvable Id into data */
349         }
350     }
351   pool->whatprovides = whatprovides;
352   pool->whatprovidesdata = whatprovidesdata;
353   pool->whatprovidesdataoff = off;
354   pool->whatprovidesdataleft = extra;
355   pool_shrink_whatprovides(pool);
356 }
357
358
359 /******************************************************************************/
360
361 /*
362  * pool_queuetowhatprovides
363  * 
364  * on-demand filling of provider information
365  * move queue data into whatprovidesdata
366  * q: queue of Ids
367  * returns: Offset into whatprovides
368  */
369
370 Id
371 pool_queuetowhatprovides(Pool *pool, Queue *q)
372 {
373   Offset off;
374   int count = q->count;
375
376   if (count == 0)                      /* queue empty -> ID_EMPTY */
377     return ID_EMPTY;
378
379   /* extend whatprovidesdata if needed, +1 for ID_NULL-termination */
380   if (pool->whatprovidesdataleft < count + 1)
381     {
382       if (pool->verbose)
383         printf("growing provides hash data...\n");
384       pool->whatprovidesdata = (Id *)xrealloc(pool->whatprovidesdata, (pool->whatprovidesdataoff + count + 4096) * sizeof(Id));
385       pool->whatprovidesdataleft = count + 4096;
386     }
387
388   /* copy queue to next free slot */
389   off = pool->whatprovidesdataoff;
390   memcpy(pool->whatprovidesdata + pool->whatprovidesdataoff, q->elements, count * sizeof(Id));
391
392   /* adapt count and ID_NULL-terminate */
393   pool->whatprovidesdataoff += count;
394   pool->whatprovidesdata[pool->whatprovidesdataoff++] = ID_NULL;
395   pool->whatprovidesdataleft -= count + 1;
396
397   return (Id)off;
398 }
399
400
401 /******************************************************************************/
402
403 /*
404  * addrelproviders
405  * 
406  * add packages fulfilling the relation to whatprovides array
407  * no exact providers, do range match
408  * 
409  */
410
411 Id *
412 pool_addrelproviders(Pool *pool, Id d)
413 {
414   Reldep *rd = GETRELDEP(pool, d);
415   Reldep *prd;
416   Queue plist;
417   Id buf[16];
418   Id name = rd->name;
419   Id evr = rd->evr;
420   int flags = rd->flags;
421   Id pid, *pidp;
422   Id p, *pp, *pp2, *pp3;
423
424   d = GETRELID(pool, d);
425   queueinit_buffer(&plist, buf, sizeof(buf)/sizeof(*buf));
426   switch (flags)
427     {
428     case REL_AND:
429     case REL_WITH:
430       pp = GET_PROVIDESP(name, p);
431       pp2 = GET_PROVIDESP(evr, p);
432       while ((p = *pp++) != 0)
433         {
434           for (pp3 = pp2; *pp3;)
435             if (*pp3++ == p)
436               {
437                 queuepush(&plist, p);
438                 break;
439               }
440         }
441       break;
442     case REL_OR:
443       pp = GET_PROVIDESP(name, p);
444       while ((p = *pp++) != 0)
445         queuepush(&plist, p);
446       pp = GET_PROVIDESP(evr, p);
447       while ((p = *pp++) != 0)
448         queuepushunique(&plist, p);
449       break;
450     case REL_NAMESPACE:
451       if (pool->nscallback)
452         {
453           p = pool->nscallback(pool, pool->nscallbackdata, name, evr);
454           if (p > 1)
455             {
456               queuefree(&plist);
457               pool->whatprovides[d] = p;
458               return pool->whatprovidesdata + p;
459             }
460           if (p == 1)
461             queuepush(&plist, SYSTEMSOLVABLE);
462         }
463       break;
464     default:
465       break;
466     }
467
468   /* convert to whatprovides id */
469 #if 0
470   if (pool->verbose)
471     printf("addrelproviders: what provides %s?\n", id2str(pool, name));
472 #endif
473   if (flags && flags < 8)
474     {
475       FOR_PROVIDES(p, pp, name)
476         {
477 #if 0
478           if (pool->verbose)
479             printf("addrelproviders: checking package %s\n", id2str(pool, pool->p[p].name));
480 #endif
481           /* solvable p provides name in some rels */
482           pidp = pool->solvables[p].source->idarraydata + pool->solvables[p].provides;
483           while ((pid = *pidp++) != 0)
484             {
485               int pflags;
486               Id pevr;
487
488               if (pid == name)
489                 break;          /* yes, provides all versions */
490               if (!ISRELDEP(pid))
491                 continue;               /* wrong provides name */
492               prd = GETRELDEP(pool, pid);
493               if (prd->name != name)
494                 continue;               /* wrong provides name */
495               /* right package, both deps are rels */
496               pflags = prd->flags;
497               if (!pflags)
498                 continue;
499               if (flags == 7 || pflags == 7)
500                 break; /* included */
501               if ((pflags & flags & 5) != 0)
502                 break; /* same direction, match */
503               pevr = prd->evr;
504               if (pevr == evr)
505                 {
506                   if ((pflags & flags & 2) != 0)
507                     break; /* both have =, match */
508                 }
509               else
510                 {
511                   int f = flags == 5 ? 5 : flags == 2 ? pflags : (flags ^ 5) & (pflags | 5);
512                   if ((f & (1 << (1 + evrcmp(pool, pevr, evr)))) != 0)
513                     break;
514                 }
515             }
516           if (!pid)
517             continue;   /* no rel match */
518           queuepush(&plist, p);
519         }
520       /* make our system solvable provide all unknown rpmlib() stuff */
521       if (plist.count == 0 && !strncmp(id2str(pool, name), "rpmlib(", 7))
522         queuepush(&plist, SYSTEMSOLVABLE);
523     }
524   /* add providers to whatprovides */
525 #if 0
526   if (pool->verbose) printf("addrelproviders: adding %d packages to %d\n", plist.count, d);
527 #endif
528   pool->whatprovides[d] = pool_queuetowhatprovides(pool, &plist);
529   queuefree(&plist);
530
531   return pool->whatprovidesdata + pool->whatprovides[d];
532 }
533
534 // EOF