From: Arkadiusz Pietraszek Date: Thu, 4 Jan 2018 12:01:16 +0000 (+0100) Subject: [Filesystem] Quick fix to speed up, by not encoding strings X-Git-Tag: submit/tizen_3.0/20180116.110805~3 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ce958812096b1da64a98734c1f7d310b1cc28a1b;p=platform%2Fcore%2Fapi%2Fwebapi-plugins.git [Filesystem] Quick fix to speed up, by not encoding strings 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 --- diff --git a/src/filesystem/filesystem_file.cc b/src/filesystem/filesystem_file.cc index 904b6094..7172f3d8 100644 --- a/src/filesystem/filesystem_file.cc +++ b/src/filesystem/filesystem_file.cc @@ -215,6 +215,59 @@ bool FilesystemFile::Read(FilesystemBuffer* data, size_t offset, size_t length) return true; } +bool FilesystemFile::ReadString(std::vector* 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 diff --git a/src/filesystem/filesystem_file.h b/src/filesystem/filesystem_file.h index 124467e9..1e2d5c8b 100644 --- a/src/filesystem/filesystem_file.h +++ b/src/filesystem/filesystem_file.h @@ -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* 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 diff --git a/src/filesystem/filesystem_instance.cc b/src/filesystem/filesystem_instance.cc index 7a6e3f01..08c0fe5f 100644 --- a/src/filesystem/filesystem_instance.cc +++ b/src/filesystem/filesystem_instance.cc @@ -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(); - const std::string& location = args.get("location").get(); - size_t offset = static_cast(args.get("offset").get()); - size_t length = static_cast(args.get("length").get()); - - 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(); - 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(); - 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(); size_t offset = static_cast(args.get("offset").get()); size_t length = static_cast(args.get("length").get()); + bool is_string = static_cast(args.get("isString").get()); 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(); const std::string& location = args.get("location").get(); const std::string& data = args.get("data").get(); size_t offset = static_cast(args.get("location").get()); - bool rewrite = static_cast(args.get("rewrite").get()); + bool rewrite = static_cast(args.get("rewrite").get()); + bool is_string = static_cast(args.get("isString").get()); 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(); const std::string& data = args.get("data").get(); size_t offset = static_cast(args.get("offset").get()); - bool rewrite = static_cast(args.get("rewrite").get()); + bool rewrite = static_cast(args.get("rewrite").get()); + bool is_string = static_cast(args.get("isString").get()); 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) { diff --git a/src/filesystem/filesystem_manager.cc b/src/filesystem/filesystem_manager.cc index 7407aa03..54fcffd8 100644 --- a/src/filesystem/filesystem_manager.cc +++ b/src/filesystem/filesystem_manager.cc @@ -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& success_cb, const std::function& 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 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& success_cb, + bool rewrite, bool is_string, + const std::function& success_cb, const std::function& 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()); diff --git a/src/filesystem/filesystem_manager.h b/src/filesystem/filesystem_manager.h index 41903ce6..f4e8c726 100644 --- a/src/filesystem/filesystem_manager.h +++ b/src/filesystem/filesystem_manager.h @@ -83,12 +83,12 @@ class FilesystemManager { void RemoveDirectory(const std::string& path, const std::function& success_cb, const std::function& 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& success_cb, const std::function& error_cb); void FileWrite(const std::string& path, const std::string& data, size_t offset, bool rewrite, - const std::function& success_cb, + bool is_string, const std::function& success_cb, const std::function& error_cb); void CopyTo(const std::string& originFilePath, const std::string& destinationFilePath, diff --git a/src/filesystem/js/file.js b/src/filesystem/js/file.js index 7622d532..84248264 100644 --- a/src/filesystem/js/file.js +++ b/src/filesystem/js/file.js @@ -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); } diff --git a/src/filesystem/js/file_stream.js b/src/filesystem/js/file_stream.js index 221f87e1..2eb097e4 100644 --- a/src/filesystem/js/file_stream.js +++ b/src/filesystem/js/file_stream.js @@ -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);