From aae4cf3ac7db3c552ffb12d4ac9653221f344a44 Mon Sep 17 00:00:00 2001 From: Ji-hoon Lee Date: Mon, 20 Nov 2017 13:45:30 +0900 Subject: [PATCH] Encapsulate write operations in a transaction when creating a db file If isf-panel-efl crashes or terminates abnormally while creating a ime_info db file, the db file would contain only the partial information of installed IMEs but it may look normal when trying to read it later. For this reason, it is better to encapsulate all write operations in a transaction. And, since individual insert/delete operation could fail also, we check the number of installed IMEs too. Change-Id: If0c5cf1120f3ac2dd7e9f25f360eeb443622de2b --- ism/extras/efl_panel/isf_panel_efl.cpp | 28 +++++++- ism/src/isf_pkg.cpp | 13 +++- ism/src/isf_query_utility.cpp | 126 +++++++++++++++++++++++++++++++-- ism/src/isf_query_utility.h | 8 ++- 4 files changed, 162 insertions(+), 13 deletions(-) diff --git a/ism/extras/efl_panel/isf_panel_efl.cpp b/ism/extras/efl_panel/isf_panel_efl.cpp index 3593559..f403cec 100644 --- a/ism/extras/efl_panel/isf_panel_efl.cpp +++ b/ism/extras/efl_panel/isf_panel_efl.cpp @@ -2016,9 +2016,35 @@ static bool set_active_ise (const String &uuid, bool launch_ise) bool ise_changed = false, valid = false; + int ime_num = -1; /* If we failed retrieving the number of IMEs installed, assume we need to clear IME related settings */ + pkgmgrinfo_appinfo_filter_h handle; + int ret = pkgmgrinfo_appinfo_filter_create(&handle); + if (ret == PMINFO_R_OK) { + ret = pkgmgrinfo_appinfo_filter_add_string(handle, PMINFO_APPINFO_PROP_APP_CATEGORY, "http://tizen.org/category/ime"); + if (ret == PMINFO_R_OK) { + ret = pkgmgrinfo_appinfo_filter_count(handle, &ime_num); + if (ret != PMINFO_R_OK) { + LOGW("pkgmgrinfo_appinfo_filter_count failed(%d)\n", ret); + } + } + pkgmgrinfo_appinfo_filter_destroy (handle); + } + else { + LOGE ("pkgmgrinfo_appinfo_filter_create failed(%d)", ret); + } + + /* If the ime_num and _ime_info.size() are different, it is likely that the isf-panel-efl was + terminated abnormally while processing package manager's install / uninstall events */ + LOGD("Checking whether db file needs to be re-created : %d %d", ime_num, _ime_info.size()); + if (ime_num != (int)_ime_info.size()) { + _ime_info.clear(); + isf_db_delete_ime_info(); + isf_pkg_reload_ime_info_db(); + isf_pkg_select_all_ime_info_db(_ime_info); + } + if (_ime_info.size () == 0) { #ifdef HAVE_PKGMGR_INFO - pkgmgrinfo_appinfo_filter_h handle; int ret = pkgmgrinfo_appinfo_filter_create (&handle); if (ret == PMINFO_R_OK) { ret = pkgmgrinfo_appinfo_filter_add_string (handle, PMINFO_APPINFO_PROP_APP_CATEGORY, "http://tizen.org/category/ime"); diff --git a/ism/src/isf_pkg.cpp b/ism/src/isf_pkg.cpp index 7aca3a8..5a1832d 100644 --- a/ism/src/isf_pkg.cpp +++ b/ism/src/isf_pkg.cpp @@ -233,10 +233,13 @@ int isf_pkg_ime_app_list_cb (const pkgmgrinfo_appinfo_h handle, void *user_data) } } - ret = isf_db_insert_ime_info (&ime_db); + bool in_transaction = false; + if (isf_db_is_in_transaction ()) in_transaction = true; + + ret = isf_db_insert_ime_info (&ime_db, in_transaction); if (ret < 1) { if (result) { - ret = isf_db_update_ime_info (&ime_db); + ret = isf_db_update_ime_info (&ime_db, in_transaction); if (ret) { *result = 2; // Updated } @@ -269,9 +272,13 @@ void isf_pkg_reload_ime_info_db(void) if (ret == PMINFO_R_OK) { ret = pkgmgrinfo_appinfo_filter_add_string (handle, PMINFO_APPINFO_PROP_APP_CATEGORY, "http://tizen.org/category/ime"); if (ret == PMINFO_R_OK) { + isf_db_begin_transaction(); ret = pkgmgrinfo_appinfo_filter_foreach_appinfo (handle, isf_pkg_ime_app_list_cb, NULL); if (ret != PMINFO_R_OK) { LOGW ("pkgmgrinfo_appinfo_filter_foreach_appinfo failed(%d)\n", ret); + isf_db_rollback_transaction(); + } else { + isf_db_commit_transaction(); } } else { @@ -295,7 +302,7 @@ void isf_pkg_reload_ime_info_db(void) int isf_pkg_select_all_ime_info_db(std::vector &ime_info) { int result = isf_db_select_all_ime_info(ime_info); - if (result == 0) { // Probably ime_info DB's already added by scim process. But isf_db_delete_ime_info() can delete it, so try to make one here. + if (result == 0) { isf_pkg_reload_ime_info_db(); return isf_db_select_all_ime_info(ime_info); diff --git a/ism/src/isf_query_utility.cpp b/ism/src/isf_query_utility.cpp index aca3eef..c1c37b7 100644 --- a/ism/src/isf_query_utility.cpp +++ b/ism/src/isf_query_utility.cpp @@ -79,16 +79,28 @@ static struct { const char* pPath; sqlite3* pHandle; bool need_reset; + bool in_transaction; } databaseInfo = { - DB_PATH, NULL, false + DB_PATH, NULL, false, false }; static inline int _db_disconnect(void); +static inline bool _is_in_transaction(void) +{ + return databaseInfo.in_transaction; +} + static inline int _begin_transaction(void) { sqlite3_stmt* pStmt = NULL; + if (databaseInfo.in_transaction != false) + { + LOGE("Transaction already started\n"); + return EXIT_FAILURE; + } + int ret = sqlite3_prepare_v2(databaseInfo.pHandle, "BEGIN TRANSACTION", -1, &pStmt, NULL); if (ret != SQLITE_OK) { @@ -103,6 +115,8 @@ static inline int _begin_transaction(void) return EXIT_FAILURE; } + databaseInfo.in_transaction = true; + sqlite3_finalize(pStmt); return EXIT_SUCCESS; } @@ -111,6 +125,12 @@ static inline int _rollback_transaction(void) { sqlite3_stmt* pStmt = NULL; + if (databaseInfo.in_transaction != true) + { + LOGE("Transaction not started\n"); + return EXIT_FAILURE; + } + int ret = sqlite3_prepare_v2(databaseInfo.pHandle, "ROLLBACK TRANSACTION", -1, &pStmt, NULL); if (ret != SQLITE_OK) { @@ -125,6 +145,8 @@ static inline int _rollback_transaction(void) return EXIT_FAILURE; } + databaseInfo.in_transaction = false; + sqlite3_finalize(pStmt); return EXIT_SUCCESS; } @@ -133,6 +155,12 @@ static inline int _commit_transaction(void) { sqlite3_stmt* pStmt = NULL; + if (databaseInfo.in_transaction != true) + { + LOGE("Transaction not started\n"); + return EXIT_FAILURE; + } + int ret = sqlite3_prepare_v2(databaseInfo.pHandle, "COMMIT TRANSACTION", -1, &pStmt, NULL); if (ret != SQLITE_OK) { @@ -147,6 +175,8 @@ static inline int _commit_transaction(void) return EXIT_FAILURE; } + databaseInfo.in_transaction = false; + sqlite3_finalize(pStmt); return EXIT_SUCCESS; } @@ -270,6 +300,15 @@ static inline int _db_connect(void) return 0; } +static inline int _db_is_connected(void) +{ + if (databaseInfo.pHandle) { + return 1; + } + + return 0; +} + static inline int _db_disconnect(void) { if (!databaseInfo.pHandle) @@ -1555,7 +1594,7 @@ EXAPI int isf_db_update_has_option_by_appid(const char *appid, bool has_option) * * @return the number of updated data. */ -EXAPI int isf_db_update_ime_info(ImeInfoDB *ime_db) +EXAPI int isf_db_update_ime_info(ImeInfoDB *ime_db, bool in_transaction) { int ret = 0; @@ -1564,9 +1603,9 @@ EXAPI int isf_db_update_ime_info(ImeInfoDB *ime_db) return ret; } - if (_db_connect() == 0) { + if (in_transaction || _db_connect() == 0) { ret = _db_update_ime_info(ime_db); - _db_disconnect(); + if (!in_transaction) _db_disconnect(); } else LOGW ("failed\n"); @@ -1581,7 +1620,7 @@ EXAPI int isf_db_update_ime_info(ImeInfoDB *ime_db) * * @return the number of inserted data. */ -EXAPI int isf_db_insert_ime_info(ImeInfoDB *ime_db) +EXAPI int isf_db_insert_ime_info(ImeInfoDB *ime_db, bool in_transaction) { int ret = 0; @@ -1589,9 +1628,9 @@ EXAPI int isf_db_insert_ime_info(ImeInfoDB *ime_db) return ret; } - if (_db_connect() == 0) { + if (in_transaction || _db_connect() == 0) { ret = _db_insert_ime_info(ime_db); - _db_disconnect(); + if (!in_transaction) _db_disconnect(); } else { LOGE ("_db_connect() failed\n"); @@ -1672,6 +1711,79 @@ EXAPI int isf_db_delete_ime_info(void) return ret; } +/** +* @brief Begin transaction +* +* @return 1 if there is an ongoing transaction, otherwise return 0. +*/ +EXAPI int isf_db_is_in_transaction(void) +{ + int ret = 0; + + if (_db_is_connected() == 1) { + if (_is_in_transaction()) { + ret = 1; + } + } + + return ret; +} + +/** + * @brief Begin transaction + * + * @return 1 if it is successful, otherwise return 0. + */ +EXAPI int isf_db_begin_transaction(void) +{ + int ret = EXIT_FAILURE; + + if (_db_is_connected() == 0) { + if (_db_connect() == 0) { + ret = _begin_transaction(); + } + } else + LOGW("failed\n"); + + return (ret == EXIT_SUCCESS); +} + +/** + * @brief Commit current transaction + * + * @return 1 if it is successful, otherwise return 0. + */ +EXAPI int isf_db_commit_transaction(void) +{ + int ret = EXIT_FAILURE; + + if (_db_is_connected() == 1) { + ret = _commit_transaction(); + _db_disconnect(); + } else + LOGW("failed\n"); + + return (ret == EXIT_SUCCESS); +} + +/** + * @brief Rollback current transaction + * + * @return 1 if it is successful, otherwise return 0. + */ +EXAPI int isf_db_rollback_transaction(void) +{ + int ret = EXIT_FAILURE; + + if (_db_is_connected() == 1) { + ret = _rollback_transaction(); + _db_disconnect(); + } else + LOGW("failed\n"); + + return (ret == EXIT_SUCCESS); +} + /* vi:ts=4:nowrap:ai:expandtab */ diff --git a/ism/src/isf_query_utility.h b/ism/src/isf_query_utility.h index f200bbf..04f1ffb 100644 --- a/ism/src/isf_query_utility.h +++ b/ism/src/isf_query_utility.h @@ -75,11 +75,15 @@ EXAPI int isf_db_update_label_by_appid(const char *appid, const char *label); EXAPI int isf_db_update_disp_lang(const char *disp_lang); EXAPI int isf_db_update_is_enabled_by_appid(const char *appid, bool is_enabled); EXAPI int isf_db_update_has_option_by_appid(const char *appid, bool has_option); -EXAPI int isf_db_update_ime_info(ImeInfoDB *ime_db); -EXAPI int isf_db_insert_ime_info(ImeInfoDB *ime_db); +EXAPI int isf_db_update_ime_info(ImeInfoDB *ime_db, bool in_transaction); +EXAPI int isf_db_insert_ime_info(ImeInfoDB *ime_db, bool in_transaction); EXAPI int isf_db_delete_ime_info_by_pkgid(const char *pkgid); EXAPI int isf_db_delete_ime_info_by_appid(const char *appid); EXAPI int isf_db_delete_ime_info(void); +EXAPI int isf_db_is_in_transaction(void); +EXAPI int isf_db_begin_transaction(void); +EXAPI int isf_db_commit_transaction(void); +EXAPI int isf_db_rollback_transaction(void); #endif /* __ISF_QUERY_UTILITY_H__ */ -- 2.7.4