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