- solv: fix segfault, add findfastest
authorMichael Schroeder <mls@suse.de>
Wed, 22 Jul 2009 15:34:34 +0000 (17:34 +0200)
committerMichael Schroeder <mls@suse.de>
Wed, 22 Jul 2009 15:34:34 +0000 (17:34 +0200)
examples/solv.c
src/pool.c

index cbca442..f64e0b0 100644 (file)
 #include <time.h>
 #include <sys/time.h>
 
+#include <sys/socket.h>
+#include <netdb.h>
+#include <poll.h>
+#include <errno.h>
+
 #include "pool.h"
 #include "poolarch.h"
 #include "repo.h"
@@ -200,7 +205,7 @@ read_repoinfos(Pool *pool, const char *reposdir, int *nrepoinfosp)
          l = strlen(buf2);
          if (l == 0)
            continue;
-         while (buf2[l - 1] == '\n' || buf2[l - 1] == ' ' || buf2[l - 1] == '\t')
+         while (l && (buf2[l - 1] == '\n' || buf2[l - 1] == ' ' || buf2[l - 1] == '\t'))
            buf2[--l] = 0;
          kp = buf2;
          while (*kp == ' ' || *kp == '\t')
@@ -350,10 +355,148 @@ verify_checksum(int fd, const char *file, const unsigned char *chksum, Id chksum
   return 1;
 }
 
+void
+findfastest(char **urls, int nurls)
+{
+  int i, j, port;
+  int *socks, qc;
+  struct pollfd *fds;
+  char *p, *p2, *q;
+  char portstr[16];
+  struct addrinfo hints, *result;;
+
+  fds = sat_calloc(nurls, sizeof(*fds));
+  socks = sat_calloc(nurls, sizeof(*socks));
+  for (i = 0; i < nurls; i++)
+    {
+      socks[i] = -1;
+      p = strchr(urls[i], '/');
+      if (!p)
+       continue;
+      if (p[1] != '/')
+       continue;
+      p += 2;
+      q = strchr(p, '/');
+      qc = 0;
+      if (q)
+       {
+         qc = *q;
+         *q = 0;
+       }
+      if ((p2 = strchr(p, '@')) != 0)
+       p = p2 + 1;
+      port = 80;
+      if (!strncmp("https:", urls[i], 6))
+       port = 443;
+      else if (!strncmp("ftp:", urls[i], 4))
+       port = 21;
+      if ((p2 = strrchr(p, ':')) != 0)
+       {
+         port = atoi(p2 + 1);
+         if (q)
+           *q = qc;
+         q = p2;
+         qc = *q;
+         *q = 0;
+       }
+      sprintf(portstr, "%d", port);
+      memset(&hints, 0, sizeof(struct addrinfo));
+      hints.ai_family = AF_UNSPEC;
+      hints.ai_socktype = SOCK_STREAM;
+      hints.ai_flags = AI_NUMERICSERV;
+      result = 0;
+      if (!getaddrinfo(p, portstr, &hints, &result))
+       {
+         socks[i] = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
+         if (socks[i] >= 0)
+           {
+             fcntl(socks[i], F_SETFL, O_NONBLOCK);
+             if (connect(socks[i], result->ai_addr, result->ai_addrlen) == -1)
+               {
+                 if (errno != EINPROGRESS)
+                   {
+                     close(socks[i]);
+                     socks[i] = -1;
+                   }
+               }
+           }
+         freeaddrinfo(result);
+       }
+      if (q)
+       *q = qc;
+    }
+  for (;;)
+    {
+      for (i = j = 0; i < nurls; i++)
+       {
+         if (socks[i] < 0)
+           continue;
+         fds[j].fd = socks[i];
+         fds[j].events = POLLOUT;
+         j++;
+       }
+      if (j < 2)
+       {
+         i = j - 1;
+         break;
+       }
+      if (poll(fds, j, 10000) <= 0)
+       {
+         i = -1;       /* something is wrong */
+         break;
+       }
+      for (i = 0; i < j; i++)
+       if ((fds[i].revents & POLLOUT) != 0)
+         {
+           int soe = 0;
+           socklen_t soel = sizeof(int);
+           if (getsockopt(fds[i].fd, SOL_SOCKET, SO_ERROR, &soe, &soel) == -1 || soe != 0)
+             {
+               /* connect failed, kill socket */
+               for (j = 0; j < nurls; j++)
+                 if (socks[j] == fds[i].fd)
+                   {
+                     close(socks[j]);
+                     socks[j] = -1;
+                   }
+               i = j + 1;
+               break;
+             }
+           break;      /* horray! */
+         }
+      if (i == j + 1)
+       continue;
+      if (i == j)
+        i = -1;                /* something is wrong, no bit was set */
+      break;
+    }
+  /* now i contains the fastest fd index */
+  if (i >= 0)
+    {
+      for (j = 0; j < nurls; j++)
+       if (socks[j] == fds[i].fd)
+         break;
+      if (j != 0)
+       {
+         char *url0 = urls[0];
+         urls[0] = urls[j];
+         urls[j] = url0;
+       }
+    }
+  for (i = j = 0; i < nurls; i++)
+    if (socks[i] >= 0)
+      close(socks[i]);
+  free(socks);
+  free(fds);
+}
+
 char *
 findmetalinkurl(FILE *fp, unsigned char *chksump, Id *chksumtypep)
 {
   char buf[4096], *bp, *ep;
+  char **urls = 0;
+  int nurls = 0;
+  int i;
 
   if (chksumtypep)
     *chksumtypep = 0;
@@ -366,7 +509,7 @@ findmetalinkurl(FILE *fp, unsigned char *chksump, Id *chksumtypep)
          int i;
 
          bp += 20;
-         memset(chksumtypep, 0, 32);
+         memset(chksump, 0, 32);
          for (i = 0; i < 64; i++)
            {
              int c = *bp++;
@@ -395,7 +538,26 @@ findmetalinkurl(FILE *fp, unsigned char *chksump, Id *chksumtypep)
       *ep = 0;
       if (strncmp(bp, "http", 4))
        continue;
-      return strdup(bp);
+      urls = sat_extend(urls, nurls, 1, sizeof(*urls), 15);
+      urls[nurls++] = strdup(bp);
+    }
+  if (nurls)
+    {
+      if (nurls > 1)
+        findfastest(urls, nurls > 5 ? 5 : nurls);
+      bp = urls[0];
+      urls[0] = 0;
+      for (i = 0; i < nurls; i++)
+        sat_free(urls[i]);
+      sat_free(urls);
+      ep = strchr(bp, '/');
+      if ((ep = strchr(ep + 2, '/')) != 0)
+       {
+         *ep = 0;
+         printf("[using mirror %s]\n", bp);
+         *ep = '/';
+       }
+      return bp;
     }
   return 0;
 }
@@ -1189,6 +1351,7 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos)
              cinfo->repo = 0;
              break;
            }
+printf("cinfo: %p\n", cinfo);
          calc_checksum_fp(fp, REPOKEY_TYPE_SHA256, cinfo->cookie);
          if (usecachedrepo(repo, 0, cinfo->cookie, 1))
            {
@@ -1235,7 +1398,7 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos)
              fclose(fp);
            }
 
-         data = repo_last_repodata(repo);
+         data = repo_add_repodata(repo, 0);
          if (!repomd_add_ext(repo, data, "deltainfo"))
            repomd_add_ext(repo, data, "prestodelta");
          repomd_add_ext(repo, data, "filelists");
@@ -1306,7 +1469,7 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos)
            break;      /* hopeless */
          repo_add_susetags(repo, fp, defvendor, 0, 0);
          fclose(fp);
-         data = repo_last_repodata(repo);
+         data = repo_add_repodata(repo, 0);
          susetags_add_ext(repo, data);
          repodata_internalize(data);
          if (!badchecksum)
@@ -1673,7 +1836,7 @@ struct fcstate {
 };
 
 static void *
-fc_cb(Pool *pool, Id p, void *cbdata)
+fileconflict_cb(Pool *pool, Id p, void *cbdata)
 {
   struct fcstate *fcstate = cbdata;
   Solvable *s;
@@ -2251,7 +2414,8 @@ rerunsolver:
          if (pool->installed && pool->installed->nsolvables)
            {
              /* try a delta first */
-             dataiterator_init(&di, pool, s->repo, SOLVID_META, DELTA_PACKAGE_NAME, id2str(pool, s->name), SEARCH_STRING);
+             char *matchname = strdup(id2str(pool, s->name));
+             dataiterator_init(&di, pool, s->repo, SOLVID_META, DELTA_PACKAGE_NAME, matchname, SEARCH_STRING);
              dataiterator_prepend_keyname(&di, REPOSITORY_DELTAINFO);
              while (dataiterator_step(&di))
                {
@@ -2285,7 +2449,12 @@ rerunsolver:
                      seqnum = pool_lookup_str(pool, SOLVID_POS, DELTA_SEQ_NUM);
                      seq = pool_tmpjoin(pool, seqname, "-", seqevr);
                      seq = pool_tmpjoin(pool, seq, "-", seqnum);
-                     if (system(pool_tmpjoin(pool, "/usr/bin/applydeltarpm -c -s ", seq, 0)) != 0)
+#ifdef FEDORA
+                     sprintf(cmd, "/usr/bin/applydeltarpm -a %s -c -s ", id2str(pool, s->arch));
+#else
+                     sprintf(cmd, "/usr/bin/applydeltarpm -c -s ");
+#endif
+                     if (system(pool_tmpjoin(pool, cmd, seq, 0)) != 0)
                        continue;       /* didn't match */
                      /* looks good, download delta */
                      chksumtype = 0;
@@ -2300,7 +2469,11 @@ rerunsolver:
                        continue;
                      /* got it, now reconstruct */
                      newfd = opentmpfile();
+#ifdef FEDORA
+                     sprintf(cmd, "applydeltarpm -a %s /dev/fd/%d /dev/fd/%d", id2str(pool, s->arch), fileno(fp), newfd);
+#else
                      sprintf(cmd, "applydeltarpm /dev/fd/%d /dev/fd/%d", fileno(fp), newfd);
+#endif
                      fcntl(fileno(fp), F_SETFD, 0);
                      if (system(cmd))
                        {
@@ -2323,6 +2496,7 @@ rerunsolver:
                    }
                }
              dataiterator_free(&di);
+             sat_free(matchname);
            }
          
          if (newpkgsfps[i])
@@ -2359,7 +2533,7 @@ rerunsolver:
       fcstate.newpkgscnt = newpkgs;
       fcstate.checkq = &checkq;
       fcstate.newpkgsfps = newpkgsfps;
-      pool_findfileconflicts(pool, &checkq, newpkgs, &conflicts, &fc_cb, &fcstate);
+      pool_findfileconflicts(pool, &checkq, newpkgs, &conflicts, &fileconflict_cb, &fcstate);
       if (conflicts.count)
        {
          printf("\n");
index 4bfc2de..ba56b58 100644 (file)
@@ -1036,7 +1036,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));
@@ -1065,8 +1067,7 @@ 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)
@@ -1114,6 +1115,7 @@ pool_addfileprovides_ids(Pool *pool, Repo *installed, Id **idp)
   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