Bug 1063635 Part 2 - Call native writeAtomic code instead of JS backend when applicable, draft
authorMilindL <i.milind.luthra@gmail.com>
Thu, 27 Jul 2017 19:41:00 +0530
changeset 642623 d2d27020770d6a649c2374d07f3883df95cf8825
parent 642622 e4aa2bd0039b8359fb824891e33cc05c5d68d48a
child 725066 24d3924fe15a4b4cb3c653606a9514be2b28945d
push id72831
push userbmo:i.milind.luthra@gmail.com
push dateTue, 08 Aug 2017 16:39:14 +0000
bugs1063635
milestone56.0a1
Bug 1063635 Part 2 - Call native writeAtomic code instead of JS backend when applicable, MozReview-Commit-ID: fiIS2xPc2r
toolkit/components/osfile/modules/osfile_async_front.jsm
toolkit/components/osfile/modules/osfile_native.jsm
--- a/toolkit/components/osfile/modules/osfile_async_front.jsm
+++ b/toolkit/components/osfile/modules/osfile_async_front.jsm
@@ -1179,32 +1179,40 @@ File.exists = function exists(path) {
  * If the process or the operating system freezes or crashes
  * during the short window between these operations,
  * the destination file will have been moved to its backup.
  *
  * @return {promise}
  * @resolves {number} The number of bytes actually written.
  */
 File.writeAtomic = function writeAtomic(path, buffer, options = {}) {
+  const useNativeImplementation = nativeWheneverAvailable && !options.compression;
   // Copy |options| to avoid modifying the original object but preserve the
   // reference to |outExecutionDuration|, |outSerializationDuration| option if it is passed.
   options = clone(options, ["outExecutionDuration", "outSerializationDuration"]);
-  // As options.tmpPath is a path, we need to encode it as |Type.path| message
-  if ("tmpPath" in options) {
+  // As options.tmpPath is a path, we need to encode it as |Type.path| message, but only
+  // if we are not using the native implementation.
+  if ("tmpPath" in options && !useNativeImplementation) {
     options.tmpPath = Type.path.toMsg(options.tmpPath);
   };
   if (isTypedArray(buffer) && (!("bytes" in options))) {
     options.bytes = buffer.byteLength;
   };
   let refObj = {};
+  let promise;
   TelemetryStopwatch.start("OSFILE_WRITEATOMIC_JANK_MS", refObj);
-  let promise = Scheduler.post("writeAtomic",
+  if (useNativeImplementation) {
+    promise = Scheduler.push(() => Native.writeAtomic(path, buffer, options));
+  }
+  else {
+  promise = Scheduler.post("writeAtomic",
     [Type.path.toMsg(path),
      Type.void_t.in_ptr.toMsg(buffer),
      options], [options, buffer, path]);
+  }
   TelemetryStopwatch.finish("OSFILE_WRITEATOMIC_JANK_MS", refObj);
   return promise;
 };
 
 File.removeDir = function(path, options = {}) {
   return Scheduler.post("removeDir",
     [Type.path.toMsg(path), options], path);
 };
--- a/toolkit/components/osfile/modules/osfile_native.jsm
+++ b/toolkit/components/osfile/modules/osfile_native.jsm
@@ -62,8 +62,48 @@ this.read = function(path, options = {})
         resolve(success.result);
       },
       function onError(operation, oserror) {
         reject(new SysAll.Error(operation, oserror, path));
       }
     );
   });
 };
+
+this.writeAtomic = function(path, buffer, options = {}) {
+  // Sanity check on types of options
+  if ("encoding" in options && typeof options.encoding !== "string") {
+    return Promise.reject(new TypeError("Invalid type for option encoding"));
+  }
+  if ("compression" in options && typeof options.compression !== "string") {
+    return Promise.reject(new TypeError("Invalid type for option compression"));
+  }
+  if ("tmpPath" in options && typeof options.tmpPath !== "string") {
+    return Promise.reject(new TypeError("Invalid type for option tmpPath"));
+  }
+  if ("backupTo" in options && typeof options.backupTo !== "string") {
+    return Promise.reject(new TypeError("Invalid type for option backupTo"));
+  }
+  if ("bytes" in options && typeof options.bytes !== "number") {
+    return Promise.reject(new TypeError("Invalid type for option bytes"));
+  }
+  if ("noOverwrite" in options && typeof options.noOverwrite !== "boolean") {
+    return Promise.reject(new TypeError("Invalid type for option noOverwrite"));
+  }
+  if ("flush" in options && typeof options.flush !== "boolean") {
+    return Promise.reject(new TypeError("Invalid type for option flush"));
+  }
+
+  return new Promise((resolve, reject) => {
+    Internals.writeAtomic(
+      path,
+      buffer,
+      options,
+      function onSuccess(success) {
+        success.QueryInterface(Ci.nsINativeOSFileResult);
+        resolve(success.result);
+      },
+      function onError(operation, oserror) {
+        reject(new SysAll.Error(operation, oserror, path));
+      }
+    );
+  });
+};