[Filesystem] Quick fix to speed up, by not encoding strings 76/166176/1
authorArkadiusz Pietraszek <a.pietraszek@partner.samsung.com>
Thu, 4 Jan 2018 12:01:16 +0000 (13:01 +0100)
committerArkadiusz Pietraszek <a.pietraszek@partner.samsung.com>
Mon, 8 Jan 2018 10:37:47 +0000 (11:37 +0100)
FileStream.write and FilesStream.read API methods has been speed up by
removing encoding and decoding operations when passing string data
through XWalk

[Verification] TCT pass rate is 100%
Automated tests has been run:
tct-archive-tizen-tests
tct-systeminfo-tizen-tests
tct-content-tizen-tests
tct-filesystem-tizen-tests

FilesystemInstance::FileRead method was unused and because of that has
been removed.

Change-Id: Ifa48e73f8b795969b584c362de3744fe774e9501
Signed-off-by: Arkadiusz Pietraszek <a.pietraszek@partner.samsung.com>
src/filesystem/filesystem_file.cc
src/filesystem/filesystem_file.h
src/filesystem/filesystem_instance.cc
src/filesystem/filesystem_manager.cc
src/filesystem/filesystem_manager.h
src/filesystem/js/file.js
src/filesystem/js/file_stream.js

index 904b60944a98259db5ec0b2f0ed2943c9eea96d5..7172f3d887231ce515a326ac1ceeb1a6d7b787ae 100644 (file)
@@ -215,6 +215,59 @@ bool FilesystemFile::Read(FilesystemBuffer* data, size_t offset, size_t length)
   return true;
 }
 
+bool FilesystemFile::ReadString(std::vector<char>* data, size_t offset, size_t length) {
+  ScopeLogger();
+  if (!data) {
+    LoggerE("Missing output buffer");
+    return false;
+  }
+
+  data->resize(length);
+  FILE* file = fopen(path.c_str(), "r");
+  if (!file) {
+    LoggerE("Cannot open file %s to read!", path.c_str());
+    return false;
+  }
+  SCOPE_EXIT {
+    int status = fclose(file);
+    if (status) {
+      LoggerE("Cannot close file!");
+    }
+  };
+  int status;
+  status = fseek(file, offset, SEEK_SET);
+  if (status) {
+    LoggerE("Cannot perform seek!");
+    return false;
+  }
+
+  size_t readed = 0;
+  char* data_p = data->data();
+  size_t data_size = length;
+  while (readed < data->size()) {
+    size_t part = fread(data_p, 1, data_size, file);
+
+    readed += part;
+    data_p += part;
+    data_size -= part;
+
+    LoggerD("Readed part %u bytes", readed);
+
+    if (ferror(file)) {
+      LoggerE("Error during file write!");
+      return false;
+    }
+
+    if (feof(file)) {
+      LoggerD("File is at end before buffer is filled. Finish.");
+      break;
+    }
+  }
+  LoggerD("Readed %u bytes", readed);
+  data->resize(readed);
+  return true;
+}
+
 bool FilesystemFile::Write(const FilesystemBuffer& data, size_t offset, bool rewrite) {
   ScopeLogger();
 
@@ -276,5 +329,68 @@ bool FilesystemFile::Write(const FilesystemBuffer& data, size_t offset, bool rew
 
   return true;
 }
+
+bool FilesystemFile::WriteString(const std::string& data, size_t offset, bool rewrite) {
+  ScopeLogger();
+
+  FILE* file = nullptr;
+  if (rewrite) {
+    file = fopen(path.c_str(), "w");
+  } else {
+    file = fopen(path.c_str(), "r+");
+  }
+
+  if (!file) {
+    LoggerE("Cannot open file %s to write!", path.c_str());
+    return false;
+  }
+
+  SCOPE_EXIT {
+    int status = fclose(file);
+    if (status) {
+      LoggerE("Cannot close file!");
+    }
+  };
+
+  int status;
+  status = fseek(file, offset, SEEK_SET);
+  LoggerD("Offset is %u, writing %i bytes", offset, data.size());
+  if (status) {
+    LoggerE("Cannot perform seek!");
+    return false;
+  }
+
+  size_t written = 0;
+  uint8_t* data_p = (uint8_t*)(data.c_str());
+  size_t data_size = data.size();
+
+  while (written < data.size()) {
+    size_t part = fwrite(data_p, 1, data_size, file);
+
+    if (ferror(file)) {
+      LoggerE("Error during file write!");
+      return false;
+    }
+
+    written += part;
+    data_p += part;
+    data_size -= part;
+  }
+
+  status = fflush(file);
+  if (status) {
+    LoggerE("Cannot flush file!");
+    return false;
+  }
+
+  status = fsync(fileno(file));
+  if (status) {
+    LoggerE("Cannot sync file!");
+    return false;
+  }
+  LoggerD("Written %u bytes", written);
+
+  return true;
+}
 }  // namespace filesystem
 }  // namespace extension
index 124467e9365da64277b4dab34df47acaa949c6ac..1e2d5c8b1ce53f767bdbc28cc2d183a3056f0e55 100644 (file)
@@ -45,7 +45,9 @@ class FilesystemFile {
   FilesystemFile(const std::string& path_);
 
   bool Read(FilesystemBuffer* data, size_t offset, size_t length);
+  bool ReadString(std::vector<char>* data, size_t offset, size_t length);
   bool Write(const FilesystemBuffer& data, size_t offset, bool rewrite);
+  bool WriteString(const std::string& data, size_t offset, bool rewrite);
 };
 
 }  // namespace filesystem
index 7a6e3f01bab02a3bc813bd19bc0b5af5f4178cf8..08c0fe5f4d153309b3e9ac55a827044c1e1ae237 100644 (file)
@@ -51,7 +51,6 @@ FilesystemInstance::FilesystemInstance() {
   REGISTER_SYNC("File_createSync", FileCreateSync);
   REGISTER_ASYNC("File_readDir", ReadDir);
   REGISTER_ASYNC("File_rename", FileRename);
-  REGISTER_ASYNC("File_read", FileRead);
   REGISTER_SYNC("File_readSync", FileReadSync);
   REGISTER_ASYNC("File_write", FileWrite);
   REGISTER_SYNC("File_writeSync", FileWriteSync);
@@ -136,51 +135,18 @@ void FilesystemInstance::FileRename(const picojson::value& args, picojson::objec
       std::bind(&FilesystemManager::Rename, &fsm, oldPath, newPath, onSuccess, onError));
 }
 
-void FilesystemInstance::FileRead(const picojson::value& args, picojson::object& out) {
-  ScopeLogger();
-  CHECK_EXIST(args, "callbackId", out)
-  CHECK_EXIST(args, "location", out)
-  CHECK_EXIST(args, "offset", out)
-  CHECK_EXIST(args, "length", out)
-
-  double callback_id = args.get("callbackId").get<double>();
-  const std::string& location = args.get("location").get<std::string>();
-  size_t offset = static_cast<size_t>(args.get("offset").get<double>());
-  size_t length = static_cast<size_t>(args.get("length").get<double>());
-
-  auto onSuccess = [this, callback_id](const std::string& data) {
-    ScopeLogger("Entered into asynchronous function, onSuccess");
-    picojson::value response = picojson::value(picojson::object());
-    picojson::object& obj = response.get<picojson::object>();
-    obj["callbackId"] = picojson::value(callback_id);
-    ReportSuccess(picojson::value(data), obj);
-    PostMessage(response.serialize().c_str());
-  };
-
-  auto onError = [this, callback_id](FilesystemError e) {
-    ScopeLogger("Entered into asynchronous function, onError");
-    picojson::value response = picojson::value(picojson::object());
-    picojson::object& obj = response.get<picojson::object>();
-    obj["callbackId"] = picojson::value(callback_id);
-    PrepareError(e, obj);
-    PostMessage(response.serialize().c_str());
-  };
-
-  FilesystemManager& fsm = FilesystemManager::GetInstance();
-  common::TaskQueue::GetInstance().Async(
-      std::bind(&FilesystemManager::FileRead, &fsm, location, offset, length, onSuccess, onError));
-}
-
 void FilesystemInstance::FileReadSync(const picojson::value& args, picojson::object& out) {
   ScopeLogger();
   CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
   CHECK_EXIST(args, "location", out)
   CHECK_EXIST(args, "offset", out)
   CHECK_EXIST(args, "length", out)
+  CHECK_EXIST(args, "isString", out)
 
   const std::string& location = args.get("location").get<std::string>();
   size_t offset = static_cast<size_t>(args.get("offset").get<double>());
   size_t length = static_cast<size_t>(args.get("length").get<double>());
+  bool is_string = static_cast<bool>(args.get("isString").get<bool>());
 
   auto onSuccess = [this, &out](const std::string& data) {
     ScopeLogger("Entered into asynchronous function, onSuccess");
@@ -192,7 +158,7 @@ void FilesystemInstance::FileReadSync(const picojson::value& args, picojson::obj
     PrepareError(e, out);
   };
 
-  FilesystemManager::GetInstance().FileRead(location, offset, length, onSuccess, onError);
+  FilesystemManager::GetInstance().FileRead(location, offset, length, is_string, onSuccess, onError);
 }
 
 void FilesystemInstance::FileWrite(const picojson::value& args, picojson::object& out) {
@@ -202,12 +168,14 @@ void FilesystemInstance::FileWrite(const picojson::value& args, picojson::object
   CHECK_EXIST(args, "data", out)
   CHECK_EXIST(args, "offset", out)
   CHECK_EXIST(args, "rewrite", out)
+  CHECK_EXIST(args, "isString", out)
 
   double callback_id = args.get("callbackId").get<double>();
   const std::string& location = args.get("location").get<std::string>();
   const std::string& data = args.get("data").get<std::string>();
   size_t offset = static_cast<size_t>(args.get("location").get<double>());
-  bool rewrite = static_cast<size_t>(args.get("rewrite").get<bool>());
+  bool rewrite = static_cast<bool>(args.get("rewrite").get<bool>());
+  bool is_string = static_cast<bool>(args.get("isString").get<bool>());
 
   auto onSuccess = [this, callback_id]() {
     ScopeLogger("Entered into asynchronous function, onSuccess");
@@ -229,7 +197,8 @@ void FilesystemInstance::FileWrite(const picojson::value& args, picojson::object
 
   FilesystemManager& fsm = FilesystemManager::GetInstance();
   common::TaskQueue::GetInstance().Async(std::bind(&FilesystemManager::FileWrite, &fsm, location,
-                                                   data, offset, rewrite, onSuccess, onError));
+                                                   data, offset, rewrite, is_string, onSuccess,
+                                                   onError));
 }
 
 void FilesystemInstance::FileWriteSync(const picojson::value& args, picojson::object& out) {
@@ -239,11 +208,13 @@ void FilesystemInstance::FileWriteSync(const picojson::value& args, picojson::ob
   CHECK_EXIST(args, "data", out)
   CHECK_EXIST(args, "offset", out)
   CHECK_EXIST(args, "rewrite", out)
+  CHECK_EXIST(args, "isString", out)
 
   const std::string& location = args.get("location").get<std::string>();
   const std::string& data = args.get("data").get<std::string>();
   size_t offset = static_cast<size_t>(args.get("offset").get<double>());
-  bool rewrite = static_cast<size_t>(args.get("rewrite").get<bool>());
+  bool rewrite = static_cast<bool>(args.get("rewrite").get<bool>());
+  bool is_string = static_cast<bool>(args.get("isString").get<bool>());
 
   auto onSuccess = [this, &out]() {
     ScopeLogger("Entered into asynchronous function, onSuccess");
@@ -255,7 +226,8 @@ void FilesystemInstance::FileWriteSync(const picojson::value& args, picojson::ob
     PrepareError(e, out);
   };
 
-  FilesystemManager::GetInstance().FileWrite(location, data, offset, rewrite, onSuccess, onError);
+  FilesystemManager::GetInstance().FileWrite(location, data, offset, rewrite, is_string, onSuccess,
+                                             onError);
 }
 
 void FilesystemInstance::FileStat(const picojson::value& args, picojson::object& out) {
index 7407aa03b1c7a821d22a9f657a49169ac4c05e40..54fcffd8a2eab359f828ccc18de6960915517738 100644 (file)
@@ -398,35 +398,55 @@ void FilesystemManager::RemoveDirectory(const std::string& path,
 }
 
 void FilesystemManager::FileRead(const std::string& path, size_t offset, size_t length,
+                                 bool is_string,
                                  const std::function<void(const std::string&)>& success_cb,
                                  const std::function<void(FilesystemError)>& error_cb) {
   ScopeLogger();
   FilesystemFile file(path);
-  FilesystemBuffer buffer;
-  if (!file.Read(&buffer, offset, length)) {
-    LoggerE("Cannot read file %s", path.c_str());
-    error_cb(FilesystemError::Other);
-    return;
-  }
 
-  std::string out_data = buffer.EncodeData();
-  success_cb(out_data);
+  // Encode data if its type is not string
+  if (!is_string) {
+    FilesystemBuffer buffer;
+    if (!file.Read(&buffer, offset, length)) {
+      LoggerE("Cannot read file %s", path.c_str());
+      error_cb(FilesystemError::Other);
+      return;
+    }
+    std::string out_data = buffer.EncodeData();
+    success_cb(out_data);
+  } else {
+    std::vector<char> buffer(length);
+    if (!file.ReadString(&buffer, offset, length)) {
+      LoggerE("Cannot read file %s", path.c_str());
+      error_cb(FilesystemError::Other);
+      return;
+    }
+    std::string out_data(buffer.begin(), buffer.end());
+    success_cb(out_data);
+  }
 }
 
 void FilesystemManager::FileWrite(const std::string& path, const std::string& data, size_t offset,
-                                  bool rewrite, const std::function<void()>& success_cb,
+                                  bool rewrite, bool is_string,
+                                  const std::function<void()>& success_cb,
                                   const std::function<void(FilesystemError)>& error_cb) {
   ScopeLogger();
   FilesystemFile file(path);
   FilesystemBuffer buffer;
-  // Decode buffer data
-  if (!buffer.DecodeData(data)) {
-    LoggerE("Cannot decode file data!");
-    error_cb(FilesystemError::Other);
-    return;
-  }
-
-  if (file.Write(buffer, offset, rewrite)) {
+  // Decode buffer data if type is not string
+  if (!is_string) {
+    if (!buffer.DecodeData(data)) {
+      LoggerE("Cannot decode file data!");
+      error_cb(FilesystemError::Other);
+      return;
+    }
+    if (file.Write(buffer, offset, rewrite)) {
+      success_cb();
+    } else {
+      LoggerE("Cannot write to file %s!", path.c_str());
+      error_cb(FilesystemError::Other);
+    }
+  } else if (file.WriteString(data, offset, rewrite)) {
     success_cb();
   } else {
     LoggerE("Cannot write to file %s!", path.c_str());
index 41903ce62b26c9a4315ce3cb7cd6f476434460e2..f4e8c7264550cc24b214885102fca1f7407e9c8d 100644 (file)
@@ -83,12 +83,12 @@ class FilesystemManager {
   void RemoveDirectory(const std::string& path, const std::function<void()>& success_cb,
                        const std::function<void(FilesystemError)>& error_cb);
 
-  void FileRead(const std::string& path, size_t offset, size_t length,
+  void FileRead(const std::string& path, size_t offset, size_t length, bool is_string,
                 const std::function<void(const std::string&)>& success_cb,
                 const std::function<void(FilesystemError)>& error_cb);
 
   void FileWrite(const std::string& path, const std::string& data, size_t offset, bool rewrite,
-                 const std::function<void()>& success_cb,
+                 bool is_string, const std::function<void()>& success_cb,
                  const std::function<void(FilesystemError)>& error_cb);
 
   void CopyTo(const std::string& originFilePath, const std::string& destinationFilePath,
index 7622d532ef2ef0f175d319e254f369024d740825..84248264a07a6e05e2f1c1c8892a7724c58c7d90 100644 (file)
@@ -317,31 +317,27 @@ function readAsText() {
     location: commonFS_.toRealPath(this.fullPath),
     offset: 0,
     length: 65536,
-    encoding: args.encoding
+    encoding: args.encoding,
+    isString: true
   };
 
   function readFile() {
     var result, encoded, buffers = [];
 
-    do {
-      result = native_.callSync('File_readSync', data);
-      if (native_.isFailure(result)) {
-        setTimeout(function() {
-          native_.callIfPossible(args.onerror, native_.getErrorObject(result));
-        }, 0);
-        return;
-      }
-      encoded = native_.getResultObject(result);
-      if (encoded.length) {
-        buffers.push( Base64.decode(encoded) );
-        data.offset += data.length;
-      }
-    } while (encoded.length);
-
-    var buffer = Array.prototype.concat.apply([], buffers);
+    result = native_.callSync('File_readSync', data);
+    if (native_.isFailure(result)) {
+      setTimeout(function() {
+        native_.callIfPossible(args.onerror, native_.getErrorObject(result));
+      }, 0);
+      return;
+    }
+    result = native_.getResultObject(result);
+    if (result.length) {
+      data.offset += data.length;
+    }
 
     setTimeout(function() {
-      native_.callIfPossible(args.onsuccess, Base64._utf8_decode(buffer) );
+      native_.callIfPossible(args.onsuccess, result);
     }, 0);
   }
 
index 221f87e11b63c51bee22a044336ee3bb4e8d5eff..2eb097e42826dbbb83760486cc309abc983c76cc 100644 (file)
@@ -135,24 +135,25 @@ function read() {
   var data = {
     location: commonFS_.toRealPath(this._file.fullPath),
     offset: this.position || 0,
-    length: args.charCount > _count ? _count : args.charCount
+    length: args.charCount > _count ? _count : args.charCount,
+    isString: true
   };
 
   var result = native_.callSync('File_readSync', data);
   if (native_.isFailure(result)) {
     throw new WebAPIException(WebAPIException.IO_ERR, 'Could not read');
   }
-  var decoded = Base64.decodeString(native_.getResultObject(result));
+  var outData = native_.getResultObject(result);
 
-  if (decoded.length) {
+  if (outData.length) {
     can_change_size = true;
-    this.position += decoded.length;
+    this.position += outData.length;
     can_change_size = false;
   } else {
     this.position += 1;   // Set EOF
   }
 
-  return decoded;
+  return outData;
 };
 
 FileStream.prototype.read = function() {
@@ -180,7 +181,8 @@ function readBytes() {
   var data = {
     location: commonFS_.toRealPath(this._file.fullPath),
     offset: this.position || 0,
-    length: args.byteCount > _count ? _count : args.byteCount
+    length: args.byteCount > _count ? _count : args.byteCount,
+    isString: false
   };
 
   var result = native_.callSync('File_readSync', data);
@@ -238,7 +240,8 @@ function readBase64() {
   var data = {
     location: commonFS_.toRealPath(this._file.fullPath),
     offset: this.position || 0,
-    length: args.byteCount > _count ? _count : args.byteCount
+    length: args.byteCount > _count ? _count : args.byteCount,
+    isString: false
   };
 
   var result = native_.callSync('File_readSync', data);
@@ -282,8 +285,9 @@ function write() {
   var data = {
     location: commonFS_.toRealPath(this._file.fullPath),
     offset: this.position,
-    data: Base64.encodeString(args.stringData),
-    rewrite: this._rewrite
+    data: args.stringData,
+    rewrite: this._rewrite,
+    isString: true
   };
 
   var result = native_.callSync('File_writeSync', data);
@@ -322,7 +326,8 @@ function writeBytes() {
     location: commonFS_.toRealPath(this._file.fullPath),
     offset: this.position,
     data: Base64.encode(args.byteData),
-    rewrite: this._rewrite
+    rewrite: this._rewrite,
+    isString: false
   };
 
   var result = native_.callSync('File_writeSync', data);
@@ -369,7 +374,8 @@ function writeBase64() {
     location: commonFS_.toRealPath(this._file.fullPath),
     offset: this.position,
     data: args.base64Data,
-    rewrite: this._rewrite
+    rewrite: this._rewrite,
+    isString: false
   };
 
   var result = native_.callSync('File_writeSync', data);