- fix arch handling
[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   "src",
57   "nosrc",
58   "noarch"
59 };
60
61 // create pool
62 // 
63 Pool *
64 pool_create(void)
65 {
66   int count, totalsize = 0;
67   Pool *pool;
68
69   pool = (Pool *)xcalloc(1, sizeof(*pool));
70
71   // count number and total size of predefined strings
72   for (count = 0; count < sizeof(initpool_data)/sizeof(*initpool_data); count++)
73     totalsize += strlen(initpool_data[count]) + 1;
74
75   // alloc appropriate space
76   pool->stringspace = (char *)xmalloc((totalsize + STRINGSPACE_BLOCK) & ~STRINGSPACE_BLOCK);
77   pool->strings = (Offset *)xmalloc(((count + STRING_BLOCK) & ~STRING_BLOCK) * sizeof(Offset));
78
79   // now copy predefined strings into allocated space
80   pool->sstrings = 0;
81   for (count = 0; count < sizeof(initpool_data)/sizeof(*initpool_data); count++)
82     {
83       strcpy(pool->stringspace + pool->sstrings, initpool_data[count]);
84       pool->strings[count] = pool->sstrings;
85       pool->sstrings += strlen(initpool_data[count]) + 1;
86     }
87   pool->nstrings = count;
88
89   // pre-alloc space for a RelDep
90   pool->rels = (Reldep *)xcalloc(1 + REL_BLOCK, sizeof(Reldep));
91   pool->nrels = 1;
92
93   // pre-alloc space for a Solvable
94   pool->solvables = (Solvable *)xcalloc(1, sizeof(Solvable));
95   pool->nsolvables = 1;
96
97   return pool;
98 }
99
100
101 // empty the pool
102 // 
103 void
104 pool_free(Pool *pool)
105 {
106   int i;
107   Source *source;
108
109   pool_freewhatprovides(pool);
110   pool_freeidhashes(pool);
111   for (i = 0; i < pool->nsources; i++)
112     {
113       source = pool->sources[i];
114       xfree(source->idarraydata);
115       xfree(source->rpmdbid);
116       xfree(source);
117     }
118   xfree(pool->solvables);
119   xfree(pool->sources);
120   xfree(pool->stringspace);
121   xfree(pool->strings);
122   xfree(pool->rels);
123   xfree(pool);
124 }
125
126
127 /*
128  * pool_prepare()
129  * 
130  * create hashes over complete pool to ease lookups
131  * 
132  */
133
134 void
135 pool_prepare(Pool *pool)
136 {
137   int i, num, np, extra;
138   unsigned int n;
139   Offset off;
140   Solvable *s;
141   Id id;
142   Offset *idp;
143   Offset *whatprovides;
144   Id *whatprovidesdata, *d;
145
146   if (pool->verbose)
147     printf("number of solvables: %d\n", pool->nsolvables);
148   if (pool->verbose)
149     printf("number of ids: %d + %d\n", pool->nstrings, pool->nrels);
150
151   pool_freeidhashes(pool);
152   pool_freewhatprovides(pool);
153   num = pool->nstrings + pool->nrels;
154   whatprovides = (Offset *)xcalloc(num, sizeof(Offset));
155
156   /* count providers for each name */
157
158   for (i = 1; i < pool->nsolvables; i++)   /* loop over all, but first, solvables */
159     {
160       Id *pp;
161       s = pool->solvables + i;
162       if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
163         continue;               /* sources do not provide anything */
164       if (pool->id2arch && (s->arch > pool->lastarch || !pool->id2arch[s->arch]))
165         continue;               /* architecture not installable */
166       pp = s->provides;
167       if (!pp)                  /* solvable does not provide anything */
168         continue;
169       while ((id = *pp++) != ID_NULL)
170         {
171           if (ISRELDEP(id))
172             {
173               Reldep *rd = GETRELDEP(pool, id);
174               id = rd->name;
175             }
176           whatprovides[id]++;          /* inc count of providers */
177         }
178     }
179
180   off = 2;      /* first entry is undef, second is empty list */
181   idp = whatprovides;
182   np = 0;                              /* number of names provided */
183   for (i = 0; i < num; i++, idp++)
184     {
185       n = *idp;
186       if (!n)                          /* no providers */
187         continue;
188       *idp = off;                      /* move from counts to offsets into whatprovidesdata */
189       off += n + 1;                    /* make space for all providers + terminating ID_NULL */
190       np++;                            /* inc # of provider 'slots' */
191     }
192
193   if (pool->verbose)
194     printf("provide ids: %d\n", np);
195   extra = 2 * pool->nrels;
196
197   if (extra < 256)
198     extra = 256;
199
200   if (pool->verbose)
201     printf("provide space needed: %d + %d\n", off, extra);
202
203   /* alloc space for all providers + extra */
204   whatprovidesdata = (Id *)xcalloc(off + extra, sizeof(Id));
205
206   /* now fill data for all provides */
207   for (i = 1; i < pool->nsolvables; i++)
208     {
209       Id *pp;
210       s = pool->solvables + i;
211       if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
212         continue;               /* sources do not provide anything */
213       if (pool->id2arch && (s->arch > pool->lastarch || !pool->id2arch[s->arch]))
214         continue;               /* architecture not installable */
215       pp = s->provides;
216       if (!pp)                         /* solvable does not provide anything */
217         continue;
218
219       /* for all provides of this solvable */
220       while ((id = *pp++) != 0)
221         {
222           if (ISRELDEP(id))
223             {
224               Reldep *rd = GETRELDEP(pool, id);
225               id = rd->name;
226             }
227           d = whatprovidesdata + whatprovides[id];   /* offset into whatprovidesdata */
228           if (*d)
229             {
230               d++;
231               while (*d)               /* find free slot */
232                 d++;
233               if (d[-1] == i)
234                 {
235 #if 0
236                   if (pool->verbose) printf("duplicate entry for %s in package %s.%s\n", id2str(pool, id), id2str(pool, s->name), id2str(pool, s->arch));
237 #endif
238                   continue;
239                 }
240             }
241           *d = i;                      /* put solvable Id into data */
242         }
243     }
244
245   pool->whatprovides = whatprovides;
246   pool->whatprovidesdata = whatprovidesdata;
247   pool->whatprovidesdataoff = off;
248   pool->whatprovidesdataleft = extra;
249 }
250
251 /******************************************************************************/
252
253 /*
254  * pool_queuetowhatprovides
255  * 
256  * on-demand filling of provider information
257  * move queue data into whatprovidesdata
258  * q: queue of Ids
259  * returns: Offset into whatprovides
260  */
261
262 Id
263 pool_queuetowhatprovides(Pool *pool, Queue *q)
264 {
265   Offset off;
266   int count = q->count;
267
268   if (count == 0)                      /* queue empty -> ID_EMPTY */
269     return ID_EMPTY;
270
271   /* extend whatprovidesdata if needed, +1 for ID_NULL-termination */
272   if (pool->whatprovidesdataleft < count + 1)
273     {
274       if (pool->verbose)
275         printf("growing provides hash data...\n");
276       pool->whatprovidesdata = (Id *)xrealloc(pool->whatprovidesdata, (pool->whatprovidesdataoff + count + 4096) * sizeof(Id));
277       pool->whatprovidesdataleft = count + 4096;
278     }
279
280   /* copy queue to next free slot */
281   off = pool->whatprovidesdataoff;
282   memcpy(pool->whatprovidesdata + pool->whatprovidesdataoff, q->elements, count * sizeof(Id));
283
284   /* adapt count and ID_NULL-terminate */
285   pool->whatprovidesdataoff += count;
286   pool->whatprovidesdata[pool->whatprovidesdataoff++] = ID_NULL;
287   pool->whatprovidesdataleft -= count + 1;
288
289   return (Id)off;
290 }
291
292
293 /*
294  * addrangedep
295  * 
296  * add RangeDep to whatprovides
297  * no exact providers, do range match
298  * 
299  */
300
301 Id *
302 addrelproviders(Pool *pool, Id d)
303 {
304   Reldep *rd = GETRELDEP(pool, d);
305   Reldep *prd;
306   Queue plist;
307   Id buf[16];
308   Id name = rd->name;
309   Id evr = rd->evr;
310   int flags = rd->flags;
311   Id pid, *pidp;
312   Id p, *pp, *pp2, *pp3;
313
314   d = GETRELID(pool, d);
315   queueinit_buffer(&plist, buf, sizeof(buf)/sizeof(*buf));
316   switch (flags)
317     {
318     case REL_AND:
319     case REL_WITH:
320       pp = GET_PROVIDESP(name, p);
321       pp2 = GET_PROVIDESP(evr, p);
322       while ((p = *pp++) != 0)
323         {
324           for (pp3 = pp2; *pp3;)
325             if (*pp3++ == p)
326               {
327                 queuepush(&plist, p);
328                 break;
329               }
330         }
331       break;
332     case REL_OR:
333       pp = GET_PROVIDESP(name, p);
334       while ((p = *pp++) != 0)
335         queuepush(&plist, p);
336       pp = GET_PROVIDESP(evr, p);
337       while ((p = *pp++) != 0)
338         queuepushunique(&plist, p);
339       break;
340     case REL_NAMESPACE:
341 #if 0
342       /* unknown namespace, just pass through */
343       pp = GET_PROVIDESP(evr, p);
344       while ((p = *pp++) != 0)
345         queuepush(&plist, p);
346 #endif
347       break;
348     default:
349       break;
350     }
351
352   /* convert to whatprovides id */
353 #if 0
354   if (pool->verbose)
355     printf("addrelproviders: what provides %s?\n", id2str(pool, name));
356 #endif
357   if (flags && flags < 8)
358     {
359       FOR_PROVIDES(p, pp, name)
360         {
361 #if 0
362           if (pool->verbose)
363             printf("addrelproviders: checking package %s\n", id2str(pool, pool->p[p].name));
364 #endif
365           /* solvable p provides name in some rels */
366           for (pidp = pool->solvables[p].provides; (pid = *pidp++) != 0; )
367             {
368               int pflags;
369               Id pevr;
370
371               if (pid == name)
372                 break;          /* yes, provides all versions */
373               if (!ISRELDEP(pid))
374                 continue;               /* wrong provides name */
375               prd = GETRELDEP(pool, pid);
376               if (prd->name != name)
377                 continue;               /* wrong provides name */
378               /* right package, both deps are rels */
379               pflags = prd->flags;
380               if (!pflags)
381                 continue;
382               if (flags == 7 || pflags == 7)
383                 break; /* included */
384               if ((pflags & flags & 5) != 0)
385                 break; /* same direction, match */
386               pevr = prd->evr;
387               if (pevr == evr)
388                 {
389                   if ((pflags & flags & 2) != 0)
390                     break; /* both have =, match */
391                 }
392               else
393                 {
394                   int f = flags == 5 ? 5 : flags == 2 ? pflags : (flags ^ 5) & (pflags | 5);
395                   if ((f & (1 << (1 + evrcmp(pool, pevr, evr)))) != 0)
396                     break;
397                 }
398             }
399           if (!pid)
400             continue;   /* no rel match */
401           queuepush(&plist, p);
402         }
403     }
404   /* add providers to whatprovides */
405 #if 0
406   if (pool->verbose) printf("addrelproviders: adding %d packages to %d\n", plist.count, d);
407 #endif
408   pool->whatprovides[d] = pool_queuetowhatprovides(pool, &plist);
409   queuefree(&plist);
410
411   return pool->whatprovidesdata + pool->whatprovides[d];
412 }
413
414
415 /*
416  * return source of solvable
417  * or NULL
418  */
419
420 Source *
421 pool_source(Pool *pool, Solvable *s)
422 {
423   int i;
424   Source *source;
425   int off = s - pool->solvables;
426
427   for (i = 0; i < pool->nsources; i++)
428     {
429       source = pool->sources[i];
430       if (off >= source->start
431           && off < source->start+source->nsolvables)
432       {
433         return source;
434       }
435     }
436   return NULL;
437 }
438
439 // EOF