- make addfileprovides faster
authorMichael Schroeder <mls@suse.de>
Wed, 29 Jul 2009 10:16:13 +0000 (12:16 +0200)
committerMichael Schroeder <mls@suse.de>
Wed, 29 Jul 2009 10:16:13 +0000 (12:16 +0200)
- solv: rewrite repos with complete added file provides

examples/solv.c
src/pool.c
src/repodata.c
src/repodata.h
src/solver.c

index cc7d204..03af6ec 100644 (file)
@@ -876,6 +876,7 @@ usecachedrepo(Repo *repo, const char *repoext, unsigned char *cookie, int mark)
 {
   FILE *fp;
   unsigned char mycookie[32];
+  unsigned char myextcookie[32];
   struct repoinfo *cinfo;
   int flags;
 
@@ -892,6 +893,14 @@ usecachedrepo(Repo *repo, const char *repoext, unsigned char *cookie, int mark)
       fclose(fp);
       return 0;
     }
+  if (cinfo && !repoext)
+    {
+      if (fseek(fp, -sizeof(mycookie) * 2, SEEK_END) || fread(myextcookie, sizeof(myextcookie), 1, fp) != 1)
+       {
+         fclose(fp);
+         return 0;
+       }
+    }
   rewind(fp);
 
   flags = 0;
@@ -907,17 +916,8 @@ usecachedrepo(Repo *repo, const char *repoext, unsigned char *cookie, int mark)
     }
   if (cinfo && !repoext)
     {
-      /* set the checksum so that we can use it with the stub loads */
-      struct stat stb;
-      if (!fstat(fileno(fp), &stb))
-       {
-         int i;
-
-         stb.st_mtime = 0;
-          calc_checksum_stat(&stb, REPOKEY_TYPE_SHA256, cinfo->extcookie);
-         for (i = 0; i < 32; i++)
-           cinfo->extcookie[i] ^= cinfo->cookie[i];
-       }
+      memcpy(cinfo->cookie, mycookie, sizeof(mycookie));
+      memcpy(cinfo->extcookie, myextcookie, sizeof(myextcookie));
     }
   if (mark)
     futimes(fileno(fp), 0);    /* try to set modification time */
@@ -928,11 +928,9 @@ usecachedrepo(Repo *repo, const char *repoext, unsigned char *cookie, int mark)
 void
 writecachedrepo(Repo *repo, Repodata *info, const char *repoext, unsigned char *cookie)
 {
-  Id *addedfileprovides = 0;
   FILE *fp;
   int i, fd;
   char *tmpl;
-  int myinfo = 0;
   struct repoinfo *cinfo;
   int onepiece;
 
@@ -961,27 +959,46 @@ writecachedrepo(Repo *repo, Repodata *info, const char *repoext, unsigned char *
   if (i < repo->end)
     onepiece = 0;
 
-  if (!repoext)
+  if (!info)
+    repo_write(repo, fp, repo_write_stdkeyfilter, 0, 0);
+  else if (repoext)
+    repodata_write(info, fp, repo_write_stdkeyfilter, 0);
+  else
     {
-      if (!info)
+      int oldnrepodata = repo->nrepodata;
+      repo->nrepodata = 1;     /* XXX: do this right */
+      repo_write(repo, fp, repo_write_stdkeyfilter, 0, 0);
+      repo->nrepodata = oldnrepodata;
+      onepiece = 0;
+    }
+
+  if (!repoext && cinfo)
+    {
+      if (!cinfo->extcookie[0])
        {
-         info = repo_add_repodata(repo, 0);
-         myinfo = 1;
+         /* create the ext cookie and append it */
+         /* we just need some unique ID */
+         struct stat stb;
+         if (!fstat(fileno(fp), &stb))
+           {
+             int i;
+
+             calc_checksum_stat(&stb, REPOKEY_TYPE_SHA256, cinfo->extcookie);
+             for (i = 0; i < 32; i++)
+               cinfo->extcookie[i] ^= cookie[i];
+           }
+         if (cinfo->extcookie[0] == 0)
+           cinfo->extcookie[0] = 1;
        }
-      pool_addfileprovides_ids(repo->pool, 0, &addedfileprovides);
-      if (addedfileprovides && *addedfileprovides)
+      if (fwrite(cinfo->extcookie, 32, 1, fp) != 1)
        {
-         for (i = 0; addedfileprovides[i]; i++)
-           repodata_add_idarray(info, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, addedfileprovides[i]);
+         fclose(fp);
+         unlink(tmpl);
+         free(tmpl);
+         return;
        }
-      sat_free(addedfileprovides);
-      repodata_internalize(info);
-      repo_write(repo, fp, repo_write_stdkeyfilter, 0, 0);
     }
-  else
-    repodata_write(info, fp, repo_write_stdkeyfilter, 0);
-  if (myinfo)
-    repodata_free(info);
+  /* append our cookie describing the metadata state */
   if (fwrite(cookie, 32, 1, fp) != 1)
     {
       fclose(fp);
@@ -995,20 +1012,6 @@ writecachedrepo(Repo *repo, Repodata *info, const char *repoext, unsigned char *
       free(tmpl);
       return;
     }
-  if (!repoext && cinfo)
-    {
-      /* set the checksum so that we can use it with the stub loads */
-      struct stat stb;
-      if (!stat(tmpl, &stb))
-       {
-         int i;
-
-         stb.st_mtime = 0;
-          calc_checksum_stat(&stb, REPOKEY_TYPE_SHA256, cinfo->extcookie);
-         for (i = 0; i < 32; i++)
-           cinfo->extcookie[i] ^= cinfo->cookie[i];
-       }
-    }
   if (onepiece)
     {
       /* switch to just saved repo to activate paging and save memory */
@@ -1260,7 +1263,7 @@ load_stub(Pool *pool, Repodata *data, void *dp)
          return 1;
        }
 #if 1
-      printf(" loading]\n"); fflush(stdout);
+      printf(" fetching]\n"); fflush(stdout);
 #endif
       defvendor = repo_lookup_id(data->repo, SOLVID_META, SUSETAGS_DEFAULTVENDOR);
       descrdir = repo_lookup_str(data->repo, SOLVID_META, SUSETAGS_DESCRDIR);
@@ -1293,7 +1296,7 @@ load_stub(Pool *pool, Repodata *data, void *dp)
          printf(" cached]\n");fflush(stdout);
          return 1;
        }
-      printf(" loading]\n"); fflush(stdout);
+      printf(" fetching]\n"); fflush(stdout);
       filename = repodata_lookup_str(data, SOLVID_META, REPOSITORY_REPOMD_LOCATION);
       filechksumtype = 0;
       filechksum = repodata_lookup_bin_checksum(data, SOLVID_META, REPOSITORY_REPOMD_CHECKSUM, &filechksumtype);
@@ -1311,6 +1314,8 @@ load_stub(Pool *pool, Repodata *data, void *dp)
   return 0;
 }
 
+static unsigned char installedcookie[32];
+
 void
 read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos)
 {
@@ -1325,7 +1330,6 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos)
   const char *descrdir;
   int defvendor;
   struct stat stb;
-  unsigned char cookie[32];
   Pool *sigpool = 0;
   Repodata *data;
   int badchecksum;
@@ -1335,8 +1339,8 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos)
   printf("rpm database:");
   if (stat("/var/lib/rpm/Packages", &stb))
     memset(&stb, 0, sizeof(&stb));
-  calc_checksum_stat(&stb, REPOKEY_TYPE_SHA256, cookie);
-  if (usecachedrepo(repo, 0, cookie, 0))
+  calc_checksum_stat(&stb, REPOKEY_TYPE_SHA256, installedcookie);
+  if (usecachedrepo(repo, 0, installedcookie, 0))
     printf(" cached\n");
   else
     {
@@ -1360,7 +1364,7 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos)
        }
       if (!done)
         repo_add_rpmdb(repo, 0, 0, REPO_REUSE_REPODATA);
-      writecachedrepo(repo, 0, 0, cookie);
+      writecachedrepo(repo, 0, 0, installedcookie);
     }
   pool_set_installed(pool, repo);
 
@@ -1429,7 +1433,7 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos)
            }
          repo_add_repomdxml(repo, fp, 0);
          fclose(fp);
-         printf(" reading\n");
+         printf(" fetching\n");
          filename = repomd_find(repo, "primary", &filechksum, &filechksumtype);
          if (filename && (fp = curlfopen(cinfo, filename, iscompressed(filename), filechksum, filechksumtype, &badchecksum)) != 0)
            {
@@ -1452,7 +1456,7 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos)
          repomd_add_ext(repo, data, "filelists");
          repodata_internalize(data);
          if (!badchecksum)
-           writecachedrepo(repo, data, 0, cinfo->cookie);
+           writecachedrepo(repo, 0, 0, cinfo->cookie);
          repodata_create_stubs(repo_last_repodata(repo));
          break;
 
@@ -1512,7 +1516,7 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos)
              printf(" no packages file entry, skipped\n");
              break;
            }
-         printf(" reading\n");
+         printf(" fetching\n");
          if ((fp = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), iscompressed(filename), filechksum, filechksumtype, &badchecksum)) == 0)
            break;      /* hopeless */
          repo_add_susetags(repo, fp, defvendor, 0, 0);
@@ -1521,7 +1525,7 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos)
          susetags_add_ext(repo, data);
          repodata_internalize(data);
          if (!badchecksum)
-           writecachedrepo(repo, data, 0, cinfo->cookie);
+           writecachedrepo(repo, 0, 0, cinfo->cookie);
          repodata_create_stubs(repo_last_repodata(repo));
          break;
        default:
@@ -2024,6 +2028,50 @@ addsoftlocks(Pool *pool, Queue *job)
 
 #endif
 
+
+void
+rewrite_repos(Pool *pool, Id *addedfileprovides)
+{
+  Repo *repo;
+  Repodata *data;
+  Map providedids;
+  Queue fileprovidesq;
+  Id id;
+  int i, j, n, nprovidedids;
+  struct repoinfo *cinfo;
+
+  map_init(&providedids, pool->ss.nstrings);
+  queue_init(&fileprovidesq);
+  for (nprovidedids = 0; (id = addedfileprovides[nprovidedids]) != 0; nprovidedids++)
+    MAPSET(&providedids, id);
+  FOR_REPOS(i, repo)
+    {
+      /* make sure this repo has just one main repodata */
+      if (!repo->nrepodata)
+       continue;
+      cinfo = repo->appdata;
+      data = repo->repodata + 0;
+      if (data->store.pagefd == -1)
+       continue;
+      if (repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &fileprovidesq))
+       {
+         n = 0;
+         for (j = 0; j < fileprovidesq.count; j++)
+           if (MAPTST(&providedids, fileprovidesq.elements[j]))
+             n++;
+         if (n == nprovidedids)
+           continue;   /* nothing new added */
+       }
+      /* oh my! */
+      for (j = 0; addedfileprovides[j]; j++)
+       repodata_add_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, addedfileprovides[j]);
+      repodata_internalize(data);
+      writecachedrepo(repo, data, 0, cinfo ? cinfo->cookie : installedcookie);
+    }
+  queue_free(&fileprovidesq);
+  map_free(&providedids);
+}
+
 #define MODE_LIST        0
 #define MODE_INSTALL     1
 #define MODE_ERASE       2
@@ -2072,6 +2120,7 @@ main(int argc, char **argv)
   int allpkgs = 0;
   FILE **newpkgsfps;
   struct fcstate fcstate;
+  Id *addedfileprovides = 0;
 
   argc--;
   argv++;
@@ -2215,7 +2264,11 @@ main(int argc, char **argv)
 
   // FOR_REPOS(i, repo)
   //   printf("%s: %d solvables\n", repo->name, repo->nsolvables);
-  pool_addfileprovides(pool);
+  addedfileprovides = 0;
+  pool_addfileprovides_ids(pool, 0, &addedfileprovides);
+  if (addedfileprovides && *addedfileprovides)
+    rewrite_repos(pool, addedfileprovides);
+  sat_free(addedfileprovides);
   pool_createwhatprovides(pool);
 
   queue_init(&job);
index ba56b58..0702f7f 100644 (file)
@@ -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,123 +915,128 @@ 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 *repo, *oldrepo = 0;
-  int dataincludes = 0;
-  int i, j, flags;
-  Map providedids;
-  Repodata *ffldata = 0;
+  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)
-    {
-      start = repoonly->start;
-      end = repoonly->end;
-    }
-  else
-    {
-      start = 2;       /* skip system solvable */
-      end = pool->nsolvables;
-    }
-  flags = 0;
-  map_init(&providedids, pool->ss.nstrings);
-  for (p = start, s = pool->solvables + p; p < end; p++, s++)
+  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 (;;)
     {
-      repo = s->repo;
-      if (!repo || (repoonly && repo != repoonly))
-       continue;
-      /* check if p is in (oldrepo,data) */
-      if (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 = repo->repodata; i < 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 == repo->nrepodata)
-           data = nextdata;    /* no direct hit, use next repodata */
-         if (data)
+          else
            {
-             map_empty(&providedids);
-             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]))
-                 break;
-             dataincludes = i == cbd->nfiles;
+             if (data->start < provstart || data->end > provend)
+               {
+                 map_empty(&cbd->providedids);
+                 provstart = provend = 0;
+               }
            }
-         oldrepo = repo;
-       }
-      if (data && p >= data->start && dataincludes)
-       continue;
-      if (ffldata == 0 || p < ffldata->start || p >= ffldata->end)
-       {
-         for (i = 0, ffldata = repo->repodata; i < repo->nrepodata; i++, ffldata++)
-           if (p >= ffldata->start && p < ffldata->end)
-             break;
-         if (i == repo->nrepodata)
-           ffldata = 0;
-         flags = 0;
-         if (ffldata)
+
+         /* check if the data is incomplete */
+         incomplete = 0;
+         if (data->state == REPODATA_AVAILABLE)
            {
-             for (i = 0; i < cbd->nfiles; i++)
+             for (j = 1; j < data->nkeys; j++)
+               if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
+                 break;
+             if (j < data->nkeys)
                {
-                 if (data && p >= data->start && MAPTST(&providedids, cbd->ids[i]))
-                   continue;
-                 if (!repodata_filelistfilter_matches(ffldata, id2str(pool, cbd->ids[i])))
-                   {
-  #if 0
-                     printf("Need the complete filelist in repo %s because of %s\n", repo->name, id2str(pool, cbd->ids[i]));
-  #endif
-                     flags = SEARCH_COMPLETE_FILELIST;
+                 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;
                }
            }
+
+         /* 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);
        }
-      repo_search(repo, p, SOLVABLE_FILELIST, 0, flags, addfileprovides_cb, cbd);
+
+      if (repoonly || ++repoid == pool->nrepos)
+       break;
+      repo = pool->repos[repoid];
     }
-  map_free(&providedids);
+  map_free(&donemap);
+  queue_free(&fileprovidesq);
+  map_free(&cbd->providedids);
 }
 
 void
@@ -1069,7 +1080,6 @@ pool_addfileprovides_ids(Pool *pool, Repo *installed, Id **idp)
   map_free(&isf.seen);
   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)
@@ -1112,7 +1122,6 @@ 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));
index dce3e02..28c3ca4 100644 (file)
@@ -642,6 +642,27 @@ repodata_lookup_bin_checksum(Repodata *data, Id solvid, Id keyname, Id *typep)
   return dp;
 }
 
+int
+repodata_lookup_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
+{
+  unsigned char *dp;
+  Repokey *key;
+  Id id;
+  int eof = 0;
+
+  queue_empty(q);
+  dp = find_key_data(data, solvid, keyname, &key);
+  if (!dp)
+    return 0;
+  for (;;)
+    {
+      dp = data_read_ideof(dp, &id, &eof);
+      queue_push(q, id);
+      if (eof)
+       break;
+    }
+  return 1;
+}
 
 /************************************************************************
  * data search
index a224ad7..a7c5920 100644 (file)
@@ -172,7 +172,7 @@ const char *repodata_lookup_str(Repodata *data, Id solvid, Id keyname);
 int repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned int *value);
 int repodata_lookup_void(Repodata *data, Id solvid, Id keyname);
 const unsigned char *repodata_lookup_bin_checksum(Repodata *data, Id solvid, Id keyname, Id *typep);
-
+int repodata_lookup_idarray(Repodata *data, Id solvid, Id keyname, Queue *q);
 
 
 /*-----
index 0aaa3c6..842ad6b 100644 (file)
@@ -1352,11 +1352,12 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
 
   /*
    * here's the main loop:
-   * 1) propagate new decisions (only needed for level 1)
-   * 2) try to keep installed packages
-   * 3) fulfill all unresolved rules
-   * 4) install recommended packages
-   * 5) minimalize solution if we had choices
+   * 1) propagate new decisions (only needed once)
+   * 2) fulfill jobs
+   * 3) try to keep installed packages
+   * 4) fulfill all unresolved rules
+   * 5) install recommended packages
+   * 6) minimalize solution if we had choices
    * if we encounter a problem, we rewind to a safe level and restart
    * with step 1
    */
@@ -1365,7 +1366,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
   for (;;)
     {
       /*
-       * propagate
+       * initial propagation of the assertions
        */
       if (level == 1)
        {
@@ -1380,6 +1381,9 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
            }
        }
 
+      /*
+       * resolve jobs first
+       */
      if (level < systemlevel)
        {
          POOL_DEBUG(SAT_DEBUG_SOLVER, "resolving job rules\n");
@@ -1439,7 +1443,6 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
       /*
        * installed packages
        */
-
       if (level < systemlevel && solv->installed && solv->installed->nsolvables && !solv->installed->disabled)
        {
          Repo *installed = solv->installed;
@@ -1582,7 +1585,6 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
       /*
        * decide
        */
-
       POOL_DEBUG(SAT_DEBUG_POLICY, "deciding unresolved rules\n");
       for (i = 1, n = 1; n < solv->nrules; i++, n++)
        {
@@ -1668,6 +1670,8 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
       if (n != solv->nrules)   /* ran into trouble, restart */
        continue;
 
+      /* at this point we have a consistent system. now do the extras... */
+
       if (doweak)
        {
          int qcount;
@@ -1916,7 +1920,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
                }
              map_free(&dqmap);
 
-             continue;         /* back to main loop */
+             continue;         /* back to main loop so that all deps are checked */
            }
        }
 
@@ -1947,7 +1951,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
                break;
            }
          if (installedone || i < solv->orphaned.count)
-           continue;
+           continue;           /* back to main loop */
        }
 
      if (solv->solution_callback)
@@ -2027,12 +2031,13 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
                  queue_free(&dqs);
                  return;
                }
-             continue;
+             continue;         /* back to main loop */
            }
        }
       /* no minimization found, we're finally finished! */
       break;
     }
+
   POOL_DEBUG(SAT_DEBUG_STATS, "solver statistics: %d learned rules, %d unsolvable, %d minimization steps\n", solv->stats_learned, solv->stats_unsolvable, minimizationsteps);
 
   POOL_DEBUG(SAT_DEBUG_STATS, "done solving.\n\n");