The following commit has been merged in the master branch:
commit 9cd41fdda1c27169c52d73b3b3ce71991d724994
Author: Guillem Jover <[email protected]>
Date:   Sun Mar 21 09:23:09 2010 +0100

    dpkg: Defer the fsync and rename for normal files in tar extraction
    
    This way it's done in one pass afterwards, to avoid massive I/O
    degradation due to the serialization from each write + fsync. This
    restores extraction times to numbers closer to the ones before the
    fsync patch introduced in 1.15.6.

diff --git a/debian/changelog b/debian/changelog
index a17d260..60aefd2 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -12,6 +12,10 @@ dpkg (1.15.6.1) UNRELEASED; urgency=low
     the code to use STL's min() and max() instead of preprocessor macros, to
     avoid multiple evaluation of arguments. Regression introduced in 1.15.6.
     Based on a patch by Robert Luberda <[email protected]>. Closes: #574816
+  * Defer the fsync and rename for normal files in tar extraction so that
+    it's done in one pass afterwards, to avoid massive I/O degradation due to
+    the serialization from each write + fsync. This restores extraction times
+    to numbers closer to the ones before the fsync patch introduced in 1.15.6.
 
   [ Raphaƫl Hertzog ]
   * Accept source packages without "Format" field for compatibility with very
diff --git a/src/archives.c b/src/archives.c
index 1f3663f..79fef4e 100644
--- a/src/archives.c
+++ b/src/archives.c
@@ -661,8 +661,10 @@ int tarobject(struct TarInfo *ti) {
     am=(nifd->namenode->statoverride ? nifd->namenode->statoverride->mode : 
ti->Mode) & ~S_IFMT;
     if (fchmod(fd,am))
       ohshite(_("error setting permissions of `%.255s'"),ti->Name);
-    if (fsync(fd))
-      ohshite(_("unable to sync file '%.255s'"), ti->Name);
+
+    /* Postpone the fsync, to try to avoid massive I/O degradation. */
+    nifd->namenode->flags |= fnnf_deferred_fsync;
+
     pop_cleanup(ehflag_normaltidy); /* fd= open(fnamenewvb.buf) */
     if (close(fd))
       ohshite(_("error closing/writing `%.255s'"),ti->Name);
@@ -777,22 +779,82 @@ int tarobject(struct TarInfo *ti) {
    * in dpkg-new.
    */
 
-  if (rename(fnamenewvb.buf,fnamevb.buf))
-    ohshite(_("unable to install new version of `%.255s'"),ti->Name);
+  if (ti->Type == NormalFile0 || ti->Type == NormalFile0) {
+    nifd->namenode->flags |= fnnf_deferred_rename;
 
-  /* CLEANUP: now the new file is in the destination file, and the
-   * old file is in dpkg-tmp to be cleaned up later.  We now need
-   * to take a different attitude to cleanup, because we need to
-   * remove the new file.
-   */
+    debug(dbg_eachfiledetail, "tarobject done and installation deferred");
+  } else {
+    if (rename(fnamenewvb.buf, fnamevb.buf))
+      ohshite(_("unable to install new version of `%.255s'"), ti->Name);
 
-  nifd->namenode->flags |= fnnf_placed_on_disk;
-  nifd->namenode->flags |= fnnf_elide_other_lists;
+    /* CLEANUP: now the new file is in the destination file, and the
+     * old file is in dpkg-tmp to be cleaned up later.  We now need
+     * to take a different attitude to cleanup, because we need to
+     * remove the new file. */
+
+    nifd->namenode->flags |= fnnf_placed_on_disk;
+    nifd->namenode->flags |= fnnf_elide_other_lists;
+
+    debug(dbg_eachfiledetail, "tarobject done and installed");
+  }
 
-  debug(dbg_eachfiledetail,"tarobject done and installed");
   return 0;
 }
 
+void
+tar_deferred_extract(struct pkginfo *pkg)
+{
+  struct fileinlist *cfile;
+  struct filenamenode *usenode;
+  const char *usename;
+
+  for (cfile = pkg->clientdata->files; cfile; cfile = cfile->next) {
+    debug(dbg_eachfile, "deferred extract of '%.255s'", cfile->namenode->name);
+
+    if (!(cfile->namenode->flags & fnnf_deferred_rename))
+      continue;
+
+    debug(dbg_eachfiledetail, "deferred extract needs rename");
+
+    usenode = namenodetouse(cfile->namenode, pkg);
+    usename = usenode->name + 1; /* Skip the leading '/'. */
+
+    setupfnamevbs(usename);
+
+    if (cfile->namenode->flags & fnnf_deferred_fsync) {
+      int fd;
+
+      debug(dbg_eachfiledetail, "deferred extract needs fsync");
+
+      fd = open(fnamenewvb.buf, O_WRONLY);
+      if (fd < 0)
+        ohshite(_("unable to open '%.255s'"), fnamenewvb.buf);
+      if (fsync(fd))
+        ohshite(_("unable to sync file '%.255s'"), fnamenewvb.buf);
+      if (close(fd))
+        ohshite(_("error closing/writing `%.255s'"), fnamenewvb.buf);
+
+      cfile->namenode->flags &= ~fnnf_deferred_fsync;
+    }
+
+    if (rename(fnamenewvb.buf, fnamevb.buf))
+      ohshite(_("unable to install new version of `%.255s'"),
+              cfile->namenode->name);
+
+    cfile->namenode->flags &= ~fnnf_deferred_rename;
+
+    /* CLEANUP: now the new file is in the destination file, and the
+     * old file is in dpkg-tmp to be cleaned up later.  We now need
+     * to take a different attitude to cleanup, because we need to
+     * remove the new file. */
+
+    cfile->namenode->flags |= fnnf_placed_on_disk;
+    cfile->namenode->flags |= fnnf_elide_other_lists;
+
+    debug(dbg_eachfiledetail, "deferred extract done and installed");
+  }
+}
+
 static int
 try_deconfigure_can(bool (*force_p)(struct deppossi *), struct pkginfo *pkg,
                     struct deppossi *pdep, const char *action,
diff --git a/src/archives.h b/src/archives.h
index 7da1561..2390bb8 100644
--- a/src/archives.h
+++ b/src/archives.h
@@ -66,6 +66,7 @@ int unlinkorrmdir(const char *filename);
 
 int tarobject(struct TarInfo *ti);
 int tarfileread(void *ud, char *buf, int len);
+void tar_deferred_extract(struct pkginfo *pkg);
 
 bool filesavespackage(struct fileinlist *, struct pkginfo *,
                       struct pkginfo *pkgbeinginstalled);
diff --git a/src/filesdb.h b/src/filesdb.h
index ac7c274..45a3bf5 100644
--- a/src/filesdb.h
+++ b/src/filesdb.h
@@ -69,6 +69,8 @@ struct filenamenode {
     fnnf_elide_other_lists=   000010, /* must remove from other packages' 
lists */
     fnnf_no_atomic_overwrite= 000020, /* >=1 instance is a dir, cannot rename 
over */
     fnnf_placed_on_disk=      000040, /* new file has been placed on the disk 
*/
+    fnnf_deferred_fsync =     000200,
+    fnnf_deferred_rename =    000400,
   } flags; /* Set to zero when a new node is created. */
   const char *oldhash; /* valid iff this namenode is in the newconffiles list 
*/
   struct stat *filestat;
diff --git a/src/processarc.c b/src/processarc.c
index 9a0fa15..fe5ca1f 100644
--- a/src/processarc.c
+++ b/src/processarc.c
@@ -639,6 +639,8 @@ void process_archive(const char *filename) {
   p1[0] = -1;
   subproc_wait_check(c1, BACKEND " --fsys-tarfile", PROCPIPE);
 
+  tar_deferred_extract(pkg);
+
   if (oldversionstatus == stat_halfinstalled || oldversionstatus == 
stat_unpacked) {
     /* Packages that were in `installed' and `postinstfailed' have been reduced
      * to `unpacked' by now, by the running of the prerm script.

-- 
dpkg's main repository


-- 
To UNSUBSCRIBE, email to [email protected]
with a subject of "unsubscribe". Trouble? Contact [email protected]

Reply via email to