Bug 943422 - Implement FileUtils.openAtomicFileOutputStream. r=Yoric
authorPeiyong Lin <pylaurent1314@gmail.com>
Tue, 17 Dec 2013 10:57:03 -0500
changeset 160829 935b34e51fed5d2991574ab2d558bc921c1a4fec
parent 160828 389cde952ba5babb290fd11a5fd9da39b3b3d5c3
child 160830 7c1b16d368f1215c9706e1c1d3da0ab91079313e
push id37718
push userryanvm@gmail.com
push dateTue, 17 Dec 2013 16:00:43 +0000
treeherdermozilla-inbound@7c1b16d368f1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersYoric
bugs943422
milestone29.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 943422 - Implement FileUtils.openAtomicFileOutputStream. r=Yoric
toolkit/modules/FileUtils.jsm
toolkit/modules/tests/xpcshell/test_FileUtils.js
--- a/toolkit/modules/FileUtils.jsm
+++ b/toolkit/modules/FileUtils.jsm
@@ -90,16 +90,34 @@ this.FileUtils = {
    */
   openFileOutputStream: function FileUtils_openFileOutputStream(file, modeFlags) {
     var fos = Cc["@mozilla.org/network/file-output-stream;1"].
               createInstance(Ci.nsIFileOutputStream);
     return this._initFileOutputStream(fos, file, modeFlags);
   },
 
   /**
+   * Opens an atomic file output stream for writing.
+   * @param   file
+   *          The file to write to.
+   * @param   modeFlags
+   *          (optional) File open flags. Can be undefined.
+   * @returns nsIFileOutputStream to write to.
+   * @note The stream is initialized with the DEFER_OPEN behavior flag.
+   *       See nsIFileOutputStream.
+   *       OpeanAtomicFileOutputStream is generally better than openSafeFileOutputStream
+   *       baecause flushing is not needed in most of the issues.
+   */
+  openAtomicFileOutputStream: function FileUtils_openAtomicFileOutputStream(file, modeFlags) {
+    var fos = Cc["@mozilla.org/network/atomic-file-output-stream;1"].
+              createInstance(Ci.nsIFileOutputStream);
+    return this._initFileOutputStream(fos, file, modeFlags);
+  },
+
+  /**
    * Opens a safe file output stream for writing.
    * @param   file
    *          The file to write to.
    * @param   modeFlags
    *          (optional) File open flags. Can be undefined.
    * @returns nsIFileOutputStream to write to.
    * @note The stream is initialized with the DEFER_OPEN behavior flag.
    *       See nsIFileOutputStream.
@@ -113,16 +131,33 @@ this.FileUtils = {
  _initFileOutputStream: function FileUtils__initFileOutputStream(fos, file, modeFlags) {
     if (modeFlags === undefined)
       modeFlags = this.MODE_WRONLY | this.MODE_CREATE | this.MODE_TRUNCATE;
     fos.init(file, modeFlags, this.PERMS_FILE, fos.DEFER_OPEN);
     return fos;
   },
 
   /**
+   * Closes an atomic file output stream.
+   * @param   stream
+   *          The stream to close.
+   */
+  closeAtomicFileOutputStream: function FileUtils_closeAtomicFileOutputStream(stream) {
+    if (stream instanceof Ci.nsISafeOutputStream) {
+      try {
+        stream.finish();
+        return;
+      }
+      catch (e) {
+      }
+    }
+    stream.close();
+  },
+
+  /**
    * Closes a safe file output stream.
    * @param   stream
    *          The stream to close.
    */
   closeSafeFileOutputStream: function FileUtils_closeSafeFileOutputStream(stream) {
     if (stream instanceof Ci.nsISafeOutputStream) {
       try {
         stream.finish();
--- a/toolkit/modules/tests/xpcshell/test_FileUtils.js
+++ b/toolkit/modules/tests/xpcshell/test_FileUtils.js
@@ -86,107 +86,134 @@ add_test(function test_getDir_shouldCrea
   other.append("d");
   do_check_true(other.isDirectory());
   other.append("foodir");
   do_check_true(dir.equals(other));
 
   run_next_test();
 });
 
-add_test(function test_openFileOutputStream_defaultFlags() {
-  let file = FileUtils.getFile("ProfD", ["george"]);
-  let fos = FileUtils.openFileOutputStream(file);
+let openFileOutputStream_defaultFlags = function (aKind, aFileName) {
+  let file = FileUtils.getFile("ProfD", [aFileName]);
+  let fos;
+  do_check_true(aKind == "atomic" || aKind == "safe" || aKind == "");
+  if (aKind == "atomic") {
+    fos = FileUtils.openAtomicFileOutputStream(file);
+  } else if (aKind == "safe") {
+    fos = FileUtils.openSafeFileOutputStream(file);
+  } else {
+    fos = FileUtils.openFileOutputStream(file);
+  }
   do_check_true(fos instanceof Components.interfaces.nsIFileOutputStream);
+  if (aKind == "atomic" || aKind == "safe") {
+    do_check_true(fos instanceof Components.interfaces.nsISafeOutputStream);
+  }
 
-  // FileUtils.openFileOutputStream() opens the stream with DEFER_OPEN
+  // FileUtils.openFileOutputStream or FileUtils.openAtomicFileOutputStream()
+  // or FileUtils.openSafeFileOutputStream() opens the stream with DEFER_OPEN
   // which means the file will not be open until we write to it.
   do_check_false(file.exists());
 
-  let data = "imagine";
+  let data = "test_default_flags";
   fos.write(data, data.length);
   do_check_true(file.exists());
 
   // No nsIXULRuntime in xpcshell, so use this trick to determine whether we're
   // on Windows.
   if ("@mozilla.org/windows-registry-key;1" in Components.classes) {
     do_check_eq(file.permissions, 0666);
   } else {
     do_check_eq(file.permissions, FileUtils.PERMS_FILE);
   }
 
   run_next_test();
-});
+};
 
-// openFileOutputStream will uses MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE
-// as the default mode flags, but we can pass in our own if we want to.
-add_test(function test_openFileOutputStream_modeFlags() {
-  let file = FileUtils.getFile("ProfD", ["ringo"]);
-  let fos = FileUtils.openFileOutputStream(file, FileUtils.MODE_WRONLY);
-  let data = "yesterday";
+let openFileOutputStream_modeFlags = function(aKind, aFileName) {
+  let file = FileUtils.getFile("ProfD", [aFileName]);
+  let fos;
+  do_check_true(aKind == "atomic" || aKind == "safe" || aKind == "");
+  if (aKind == "atomic") {
+    fos = FileUtils.openAtomicFileOutputStream(file, FileUtils.MODE_WRONLY);
+  } else if (aKind == "safe") {
+    fos = FileUtils.openSafeFileOutputStream(file, FileUtils.MODE_WRONLY);
+  } else {
+    fos = FileUtils.openFileOutputStream(file, FileUtils.MODE_WRONLY);
+  }
+  let data = "test_modeFlags";
   do_check_throws(function () {
     fos.write(data, data.length);
   }, Components.results.NS_ERROR_FILE_NOT_FOUND);
   do_check_false(file.exists());
 
   run_next_test();
+};
+
+let closeFileOutputStream = function(aKind, aFileName) {
+  let file = FileUtils.getFile("ProfD", [aFileName]);
+  let fos;
+  do_check_true(aKind == "atomic" || aKind == "safe");
+  if (aKind == "atomic") {
+    fos = FileUtils.openAtomicFileOutputStream(file);
+  } else if (aKind == "safe") {
+    fos = FileUtils.openSafeFileOutputStream(file);
+  }
+
+  // We can write data to the stream just fine while it's open.
+  let data = "testClose";
+  fos.write(data, data.length);
+
+  // But once we close it, we can't anymore.
+  if (aKind == "atomic") {
+    FileUtils.closeAtomicFileOutputStream(fos);
+  } else if (aKind == "safe"){
+    FileUtils.closeSafeFileOutputStream(fos);
+  }
+  do_check_throws(function () {
+    fos.write(data, data.length);
+  }, Components.results.NS_BASE_STREAM_CLOSED);
+  run_next_test();
+};
+
+add_test(function test_openFileOutputStream_defaultFlags() {
+  openFileOutputStream_defaultFlags("", "george");
+});
+
+// openFileOutputStream will uses MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE
+// as the default mode flags, but we can pass in our own if we want to.
+add_test(function test_openFileOutputStream_modeFlags() {
+  openFileOutputStream_modeFlags("", "ringo");
+});
+
+add_test(function test_openAtomicFileOutputStream_defaultFlags() {
+  openFileOutputStream_defaultFlags("atomic", "peiyong");
+});
+
+// openAtomicFileOutputStream will uses MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE
+// as the default mode flags, but we can pass in our own if we want to.
+add_test(function test_openAtomicFileOutputStream_modeFlags() {
+  openFileOutputStream_modeFlags("atomic", "lin");
+});
+
+add_test(function test_closeAtomicFileOutputStream() {
+  closeFileOutputStream("atomic", "peiyonglin");
 });
 
 add_test(function test_openSafeFileOutputStream_defaultFlags() {
-  let file = FileUtils.getFile("ProfD", ["john"]);
-  let fos = FileUtils.openSafeFileOutputStream(file);
-  do_check_true(fos instanceof Components.interfaces.nsIFileOutputStream);
-  do_check_true(fos instanceof Components.interfaces.nsISafeOutputStream);
-
-  // FileUtils.openSafeFileOutputStream() opens the stream with DEFER_OPEN
-  // which means the file will not be open until we write to it.
-  do_check_false(file.exists());
-
-  let data = "imagine";
-  fos.write(data, data.length);
-  do_check_true(file.exists());
-
-  // No nsIXULRuntime in xpcshell, so use this trick to determine whether we're
-  // on Windows.
-  if ("@mozilla.org/windows-registry-key;1" in Components.classes) {
-    do_check_eq(file.permissions, 0666);
-  } else {
-    do_check_eq(file.permissions, FileUtils.PERMS_FILE);
-  }
-
-  run_next_test();
+  openFileOutputStream_defaultFlags("safe", "john");
 });
 
 // openSafeFileOutputStream will uses MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE
 // as the default mode flags, but we can pass in our own if we want to.
 add_test(function test_openSafeFileOutputStream_modeFlags() {
-  let file = FileUtils.getFile("ProfD", ["paul"]);
-  let fos = FileUtils.openSafeFileOutputStream(file, FileUtils.MODE_WRONLY);
-  let data = "yesterday";
-  do_check_throws(function () {
-    fos.write(data, data.length);
-  }, Components.results.NS_ERROR_FILE_NOT_FOUND);
-  do_check_false(file.exists());
-
-  run_next_test();
+  openFileOutputStream_modeFlags("safe", "paul");
 });
 
 add_test(function test_closeSafeFileOutputStream() {
-  let file = FileUtils.getFile("ProfD", ["george"]);
-  let fos = FileUtils.openSafeFileOutputStream(file);
-
-  // We can write data to the stream just fine while it's open.
-  let data = "here comes the sun";
-  fos.write(data, data.length);
-
-  // But once we close it, we can't anymore.
-  FileUtils.closeSafeFileOutputStream(fos);
-  do_check_throws(function () {
-    fos.write(data, data.length);
-  }, Components.results.NS_BASE_STREAM_CLOSED);
-  run_next_test();
+  closeFileOutputStream("safe", "georgee");
 });
 
 add_test(function test_newFile() {
   let testfile = FileUtils.getFile("ProfD", ["test"]);
   let testpath = testfile.path;
   let file = new FileUtils.File(testpath);
   do_check_true(file instanceof Components.interfaces.nsILocalFile);
   do_check_true(file.equals(testfile));