- fix multiversion handling for real
[platform/upstream/libsolv.git] / src / pool.c
index 4988b0a..21c52c2 100644 (file)
@@ -751,7 +751,7 @@ pool_debug(Pool *pool, int type, const char *format, ...)
   va_start(args, format);
   if (!pool->debugcallback)
     {
-      if ((type & (SAT_FATAL|SAT_ERROR)) == 0 || !(pool->debugmask & SAT_DEBUG_TO_STDERR))
+      if ((type & (SAT_FATAL|SAT_ERROR)) == 0 && !(pool->debugmask & SAT_DEBUG_TO_STDERR))
         vprintf(format, args);
       else
         vfprintf(stderr, format, args);
@@ -870,8 +870,10 @@ struct addfileprovides_cbdata {
   char **dirs;
   char **names;
 
-  Repodata *olddata;
   Id *dids;
+
+  Map providedids;
+
   Map useddirs;
 };
 
@@ -881,18 +883,22 @@ addfileprovides_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyV
   struct addfileprovides_cbdata *cbd = cbdata;
   int i;
 
-  if (data != cbd->olddata)
+  if (!cbd->useddirs.size)
     {
-      map_free(&cbd->useddirs);
-      map_init(&cbd->useddirs, data->dirpool.ndirs);
+      map_init(&cbd->useddirs, data->dirpool.ndirs + 1);
       for (i = 0; i < cbd->nfiles; i++)
        {
-         Id did = repodata_str2dir(data, cbd->dirs[i], 0);
-          cbd->dids[i] = did;
+         Id did;
+         if (MAPTST(&cbd->providedids, cbd->ids[i]))
+           {
+             cbd->dids[i] = 0;
+             continue;
+           }
+         did = repodata_str2dir(data, cbd->dirs[i], 0);
+         cbd->dids[i] = did;
          if (did)
            MAPSET(&cbd->useddirs, did);
        }
-      cbd->olddata = data;
     }
   if (!MAPTST(&cbd->useddirs, value->id))
     return 0;
@@ -909,94 +915,133 @@ addfileprovides_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyV
   return 0;
 }
 
-static int
-addfileprovides_setid_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
-{
-  Map *provideids = cbdata;
-  if (key->type != REPOKEY_TYPE_IDARRAY)
-    return 0;
-  MAPSET(provideids, kv->id);
-  return kv->eof ? SEARCH_NEXT_SOLVABLE : 0;
-}
-
-
 static void
 pool_addfileprovides_search(Pool *pool, struct addfileprovides_cbdata *cbd, struct searchfiles *sf, Repo *repoonly)
 {
-  Id p, start, end;
-  Solvable *s;
-  Repodata *data = 0, *nextdata;
-  Repo *oldrepo = 0;
-  int dataincludes = 0;
-  int i, j;
-  Map providedids;
+  Id p;
+  Repodata *data;
+  Repo *repo;
+  Queue fileprovidesq;
+  int i, j, repoid, repodataid;
+  int provstart, provend;
+  Map donemap;
+  int ndone, incomplete;
+
+  if (!pool->nrepos)
+    return;
 
   cbd->nfiles = sf->nfiles;
   cbd->ids = sf->ids;
   cbd->dirs = sf->dirs;
   cbd->names = sf->names;
-  cbd->olddata = 0;
   cbd->dids = sat_realloc2(cbd->dids, sf->nfiles, sizeof(Id));
-  if (repoonly)
+  map_init(&cbd->providedids, pool->ss.nstrings);
+
+  repoid = 0;
+  repo = repoonly ? repoonly : pool->repos[0];
+  map_init(&donemap, pool->nsolvables);
+  queue_init(&fileprovidesq);
+  provstart = provend = 0;
+  for (;;)
     {
-      start = repoonly->start;
-      end = repoonly->end;
-    }
-  else
-    {
-      start = 2;       /* skip system solvable */
-      end = pool->nsolvables;
-    }
-  for (p = start, s = pool->solvables + p; p < end; p++, s++)
-    {
-      if (!s->repo || (repoonly && s->repo != repoonly))
-       continue;
-      /* check if p is in (oldrepo,data) */
-      if (s->repo != oldrepo || (data && p >= data->end))
+      if (repo->disabled)
        {
-         data = 0;
-         oldrepo = 0;
+         if (repoonly || ++repoid == pool->nrepos)
+           break;
+         repo = pool->repos[repoid];
+         continue;
        }
-      if (oldrepo == 0)
+      ndone = 0;
+      for (data = repo->repodata, repodataid = 0; repodataid < repo->nrepodata; repodataid++, data++)
        {
-         /* nope, find new repo/repodata */
-          /* if we don't find a match, set data to the next repodata */
-         nextdata = 0;
-         for (i = 0, data = s->repo->repodata; i < s->repo->nrepodata; i++, data++)
+         if (ndone >= repo->nsolvables)
+           break;
+         if (!repodata_precheck_keyname(data, SOLVABLE_FILELIST))
+           continue;
+         for (j = 1; j < data->nkeys; j++)
+           if (data->keys[j].name == SOLVABLE_FILELIST)
+             break;
+         if (j == data->nkeys)
+           continue;
+         if (repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &fileprovidesq))
            {
-             if (p >= data->end)
-               continue;
-             if (data->state != REPODATA_AVAILABLE)
-               continue;
-             for (j = 1; j < data->nkeys; j++)
-               if (data->keys[j].name == REPOSITORY_ADDEDFILEPROVIDES && data->keys[j].type == REPOKEY_TYPE_IDARRAY)
+             map_empty(&cbd->providedids);
+             for (i = 0; i < fileprovidesq.count; i++)
+               MAPSET(&cbd->providedids, fileprovidesq.elements[i]);
+             provstart = data->start;
+             provend = data->end;
+             for (i = 0; i < cbd->nfiles; i++)
+               if (!MAPTST(&cbd->providedids, cbd->ids[i]))
                  break;
-             if (j == data->nkeys)
-               continue;
-             /* great, this repodata contains addedfileprovides */
-             if (!nextdata || nextdata->start > data->start)
-               nextdata = data;
-             if (p >= data->start)
-               break;
+             if (i == cbd->nfiles)
+               {
+                 /* great! no need to search files */
+                 for (p = data->start; p < data->end; p++)
+                   if (pool->solvables[p].repo == repo)
+                     {
+                       if (MAPTST(&donemap, p))
+                         continue;
+                       MAPSET(&donemap, p);
+                       ndone++;
+                     }
+                 continue;
+               }
            }
-         if (i == s->repo->nrepodata)
-           data = nextdata;    /* no direct hit, use next repodata */
-         if (data)
+          else
            {
-             map_init(&providedids, pool->ss.nstrings);
-             repodata_search(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, 0, addfileprovides_setid_cb, &providedids);
-             for (i = 0; i < cbd->nfiles; i++)
-               if (!MAPTST(&providedids, cbd->ids[i]))
+             if (data->start < provstart || data->end > provend)
+               {
+                 map_empty(&cbd->providedids);
+                 provstart = provend = 0;
+               }
+           }
+
+         /* check if the data is incomplete */
+         incomplete = 0;
+         if (data->state == REPODATA_AVAILABLE)
+           {
+             for (j = 1; j < data->nkeys; j++)
+               if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
                  break;
-             map_free(&providedids);
-             dataincludes = i == cbd->nfiles;
+             if (j < data->nkeys)
+               {
+#if 0
+                 for (i = 0; i < cbd->nfiles; i++)
+                   if (!MAPTST(&cbd->providedids, cbd->ids[i]) && !repodata_filelistfilter_matches(data, id2str(pool, cbd->ids[i])))
+                     printf("need complete filelist because of %s\n", id2str(pool, cbd->ids[i]));
+#endif
+                 for (i = 0; i < cbd->nfiles; i++)
+                   if (!MAPTST(&cbd->providedids, cbd->ids[i]) && !repodata_filelistfilter_matches(data, id2str(pool, cbd->ids[i])))
+                     break;
+                 if (i < cbd->nfiles)
+                   incomplete = 1;
+               }
            }
-         oldrepo = s->repo;
+
+         /* do the search */
+         map_init(&cbd->useddirs, 0);
+         for (p = data->start; p < data->end; p++)
+           if (pool->solvables[p].repo == repo)
+             {
+               if (MAPTST(&donemap, p))
+                 continue;
+               repodata_search(data, p, SOLVABLE_FILELIST, 0, addfileprovides_cb, cbd);
+               if (!incomplete)
+                 {
+                   MAPSET(&donemap, p);
+                   ndone++;
+                 }
+             }
+         map_free(&cbd->useddirs);
        }
-      if (data && p >= data->start && dataincludes)
-       continue;
-      repo_search(s->repo, p, SOLVABLE_FILELIST, 0, 0, addfileprovides_cb, cbd);
+
+      if (repoonly || ++repoid == pool->nrepos)
+       break;
+      repo = pool->repos[repoid];
     }
+  map_free(&donemap);
+  queue_free(&fileprovidesq);
+  map_free(&cbd->providedids);
 }
 
 void
@@ -1007,7 +1052,9 @@ pool_addfileprovides_ids(Pool *pool, Repo *installed, Id **idp)
   struct searchfiles sf, isf, *isfp;
   struct addfileprovides_cbdata cbd;
   int i;
+  unsigned int now;
 
+  now = sat_timems(0);
   memset(&sf, 0, sizeof(sf));
   map_init(&sf.seen, pool->ss.nstrings + pool->nrels);
   memset(&isf, 0, sizeof(isf));
@@ -1036,10 +1083,8 @@ pool_addfileprovides_ids(Pool *pool, Repo *installed, Id **idp)
     }
   map_free(&sf.seen);
   map_free(&isf.seen);
-  POOL_DEBUG(SAT_DEBUG_STATS, "found %d file dependencies\n", sf.nfiles);
-  POOL_DEBUG(SAT_DEBUG_STATS, "found %d installed file dependencies\n", isf.nfiles);
+  POOL_DEBUG(SAT_DEBUG_STATS, "found %d file dependencies, %d installed file dependencies\n", sf.nfiles, isf.nfiles);
   cbd.dids = 0;
-  map_init(&cbd.useddirs, 1);
   if (idp)
     *idp = 0;
   if (sf.nfiles)
@@ -1082,9 +1127,9 @@ pool_addfileprovides_ids(Pool *pool, Repo *installed, Id **idp)
       sat_free(isf.dirs);
       sat_free(isf.names);
     }
-  map_free(&cbd.useddirs);
   sat_free(cbd.dids);
   pool_freewhatprovides(pool); /* as we have added provides */
+  POOL_DEBUG(SAT_DEBUG_STATS, "addfileprovides took %d ms\n", sat_timems(now));
 }
 
 void
@@ -1499,7 +1544,7 @@ static inline Id dep2name(Pool *pool, Id dep)
   return dep;
 }
 
-static int providedbyinstalled_multiversion(Pool *pool, unsigned char *map, Id n, Id dep
+static int providedbyinstalled_multiversion(Pool *pool, unsigned char *map, Id n, Id con
 {
   Id p, pp;
   Solvable *sn = pool->solvables + n; 
@@ -1509,9 +1554,12 @@ static int providedbyinstalled_multiversion(Pool *pool, unsigned char *map, Id n
       Solvable *s = pool->solvables + p; 
       if (s->name != sn->name || s->arch != sn->arch)
         continue;
-      if ((map[p] & 9) == 9)
-        return 1;
-    }    
+      if ((map[p] & 9) != 9)
+        continue;
+      if (pool_match_nevr(pool, pool->solvables + p, con))
+       continue;
+      return 1;                /* found installed package that doesn't conflict */
+    }
   return 0;
 }