modify DB checking logic 14/227114/4 accepted/tizen/unified/20200312.131127 submit/tizen/20200311.122144
authorjk.koo <jk.koo@samsung.com>
Tue, 10 Mar 2020 02:01:09 +0000 (11:01 +0900)
committerYoungjae Shin <yj99.shin@samsung.com>
Tue, 10 Mar 2020 09:08:18 +0000 (18:08 +0900)
Change-Id: Icb2a6de1eb004bfeb98917251f0bc21b0f3ed203
Signed-off-by: jk.koo <jk.koo@samsung.com>
server/ctsvc_schema_recovery.c
server/db/ctsvc_db_schema.h

index adeb6ac..40faf6f 100644 (file)
 #include "ctsvc_schema_recovery.h"
 #include "ctsvc_db_schema.h"
 
-/* Additional Error */
-enum {
-       CTSVC_ERR_NO_DB_FILE = -10000,
-       CTSVC_ERR_NO_TABLE,
-};
-
-static inline int __ctsvc_server_check_db_file(void)
+static inline bool __ctsvc_server_db_file_exist(void)
 {
        int fd = open(CTSVC_DB_PATH, O_RDONLY);
-       RETVM_IF(-1 == fd, CTSVC_ERR_NO_DB_FILE, "DB file is not exist");
+       RETVM_IF(-1 == fd, false, "DB file does not exist");
 
        close(fd);
-       return CONTACTS_ERROR_NONE;
+       return true;
 }
 
 static inline int __ctsvc_server_remake_db_file()
@@ -67,112 +61,165 @@ static inline int __ctsvc_server_remake_db_file()
        return CONTACTS_ERROR_NONE;
 }
 
-static bool need_to_remove = false;
-static int __integrity_callback(void *pid, int argc, char **argv, char **notUsed2)
+static int __integrity_callback(void *user_data, int ncol, char **cols, char **name)
 {
        CTS_FN_CALL;
 
-       if (NULL == argv || NULL == argv[0]) {
-               ERR("Invalid parameter");
-               need_to_remove = true;
-               return -1;
-       }
+       RETV_IF(0 == ncol, CONTACTS_ERROR_DB);
+       RETV_IF(NULL == cols, CONTACTS_ERROR_DB);
 
-       if (0 != strcmp(argv[0], "ok")) {
-               ERR("integrity_check() Fail(argv[%s])", argv[0]);
-               need_to_remove = true;
-               return -1;
+       if (0 != strcmp(cols[0], "ok")) {
+               ERR("integrity_check Fail(%s)", cols[0]);
+               return CONTACTS_ERROR_DB;
        }
 
-       DBG("integrity_check done");
        return 0;
 }
 
-static int __ctsvc_server_check_db_integrity(void)
+static bool __ctsvc_server_check_db_table(sqlite3 *db)
 {
        CTS_FN_CALL;
-       int ret = 0;
-       sqlite3 *db = NULL;
+       int ret;
        cts_stmt stmt = NULL;
-       int sqlite_error = SQLITE_OK;
 
-       ret = ctsvc_server_db_open(&db, &sqlite_error);
-       if (CONTACTS_ERROR_NONE != ret) {
+       do {
+               /* check if table is missing */
+               const char *query = "SELECT count(*) FROM sqlite_master WHERE type='table'"
+                       " AND name IN ('"CTS_TABLE_PERSONS"','"CTS_TABLE_ADDRESSBOOKS"','"CTS_TABLE_CONTACTS"',"
+                       "'"CTS_TABLE_DELETEDS"','"CTS_TABLE_VERSION"','"CTS_TABLE_SDN"','"CTS_TABLE_DATA"',"
+                       "'"CTS_TABLE_GROUPS"','"CTS_TABLE_GROUP_DELETEDS"','"CTS_TABLE_GROUP_RELATIONS"',"
+                       "'"CTS_TABLE_SPEEDDIALS"','"CTS_TABLE_FAVORITES"','"CTS_TABLE_SIM_INFO"',"
+                       "'"CTS_TABLE_PHONELOGS"','"CTS_TABLE_PHONELOG_STAT"','"CTS_TABLE_CONTACT_STAT"',"
+                       "'"CTS_TABLE_ACTIVITIES"','"CTS_TABLE_ACTIVITY_PHOTOS"','"CTS_TABLE_SEARCH_INDEX"',"
+                       "'"CTS_TABLE_NAME_LOOKUP"','"CTS_TABLE_PHONE_LOOKUP"','"CTS_TABLE_MY_PROFILES"')";
+               ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, NULL);
+               if (SQLITE_OK != ret) {
+                       /* LCOV_EXCL_START */
+                       ERR("sqlite3_prepare_v2() Fail(%s)", sqlite3_errstr(ret));
+                       break;
+                       /* LCOV_EXCL_STOP */
+               }
+
+               ret = sqlite3_step(stmt);
+               if (SQLITE_ROW != ret) {
+                       /* LCOV_EXCL_START */
+                       ERR("sqlite3_step() Fail(%s)", sqlite3_errstr(ret));
+                       sqlite3_finalize(stmt);
+                       break;
+                       /* LCOV_EXCL_STOP */
+               }
+       }while (0);
+
+       switch (ret) {
+       case SQLITE_ROW:
+               break;
+       case SQLITE_DONE:
+       case SQLITE_BUSY:
+       case SQLITE_LOCKED:
+       case SQLITE_FULL:
+       case SQLITE_CONSTRAINT:
+       case SQLITE_NOMEM:
                /* LCOV_EXCL_START */
-               ERR("ctsvc_server_db_open() Fail(%d), sqlite_error(%d)", ret, sqlite_error);
-               if (SQLITE_ERROR == sqlite_error ||SQLITE_CORRUPT == sqlite_error ||SQLITE_NOTADB == sqlite_error)
-                       return -1;
-               else
-                       return 0;
+               // It's not critical. It can be ignored
+               INFO("False Positive(err = [%d]%s)", ret, sqlite3_errstr(ret));
+               return true;
                /* LCOV_EXCL_STOP */
-       }
-
-       ret = sqlite3_exec(db, "pragma integrity_check", __integrity_callback, NULL, NULL);
-       if (true == need_to_remove || SQLITE_ERROR == ret || SQLITE_CORRUPT == ret || SQLITE_NOTADB == ret) {
+       case SQLITE_IOERR:
+       case SQLITE_CORRUPT:
+       default:
                /* LCOV_EXCL_START */
-               ERR("need_to_remove [%s], ret [%d]", need_to_remove ? "true" : "false", ret);
-               need_to_remove = false;
-               return -1;
+               ERR("Critical Error(%d:%s)", ret, sqlite3_errstr(ret));
+               ctsvc_server_db_close();
+               return false;
                /* LCOV_EXCL_STOP */
        }
 
-       /* check if table is missing */
-       const char *query = "SELECT count(*) FROM sqlite_master WHERE type='table'"
-               " AND name IN ('persons','addressbooks','contacts','contact_deleteds','cts_version' ,"
-               "'sdn','data','groups','group_deleteds','group_relations','speeddials','favorites','sim_info',"
-               "'phonelogs','phonelog_stat','contact_stat','activities','activity_photos','search_index','name_lookup','phone_lookup','my_profiles')";
-       ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, NULL);
-       if (SQLITE_OK != ret) {
+       int get_count = sqlite3_column_int(stmt, 0);
+       sqlite3_finalize(stmt);
+
+       if (get_count != CTS_SCHEMA_TABLE_TOTAL) {
                /* LCOV_EXCL_START */
-               ERR("sqlite3_qlite3_prepare_v2() Fail(%d)", ret);
-               if (SQLITE_ERROR == ret ||SQLITE_CORRUPT == ret ||SQLITE_NOTADB == ret)
-                       return -1;
-               else
-                       return 0;
+               ERR("Table is missing(expected(%d) but result(%d)", CTS_SCHEMA_TABLE_TOTAL, get_count);
+               ctsvc_server_db_close();
+               return false;
                /* LCOV_EXCL_STOP */
        }
 
-       ret = sqlite3_step(stmt);
-       if (SQLITE_ROW != ret) {
+       return true;
+}
+
+static bool __ctsvc_server_check_db()
+{
+       CTS_FN_CALL;
+       int ret;
+       sqlite3 *db = NULL;
+       int sqlite_error = SQLITE_OK;
+
+       ret = ctsvc_server_db_open(&db, &sqlite_error);
+       if (CONTACTS_ERROR_NONE != ret) {
                /* LCOV_EXCL_START */
-               ERR("sqlite3_step() Fail(%d)", ret);
-               sqlite3_finalize(stmt);
-               if (SQLITE_ERROR == ret ||SQLITE_CORRUPT == ret ||SQLITE_NOTADB == ret)
-                       return -1;
-               else
-                       return 0;
+               INFO("ctsvc_server_db_open() Fail(%d), sqlite_error(%s)", ret, sqlite3_errstr(sqlite_error));
+
+               if (SQLITE_BUSY == sqlite_error || SQLITE_NOMEM == sqlite_error) {
+                       INFO("it's not critical enough to clear the db.");
+                       return true;
+               }
+               ctsvc_server_db_close();
+               return false;
                /* LCOV_EXCL_STOP */
        }
 
-       int get_count = sqlite3_column_int(stmt, 0);
-       sqlite3_finalize(stmt);
-
-       if (get_count != CTS_SCHEMA_TABLE_TOTAL) {
+       ret = sqlite3_exec(db, "pragma integrity_check", __integrity_callback, NULL, NULL);
+       if (SQLITE_ABORT == ret) {
                /* LCOV_EXCL_START */
-               ERR("Table is missing(expected(%d) but result(%d)", CTS_SCHEMA_TABLE_TOTAL, get_count);
-               return -1;
+               ERR("integrity_check Fail()");
+               ctsvc_server_db_close();
+               return false;
                /* LCOV_EXCL_STOP */
        }
 
-       return 0;
+       return __ctsvc_server_check_db_table(db);
 }
 
-int ctsvc_server_check_schema(void)
+static void __ctsvc_server_backup_file()
 {
-       if (CONTACTS_ERROR_NONE != __ctsvc_server_check_db_file()
-               || 0 != __ctsvc_server_check_db_integrity())
-       {
-               ERR("Need to remove and remake db files");
-
-               ctsvc_server_db_close();
+       int i;
+       const int MAX_BACKUP = 4;
+       char new_path[CTSVC_PATH_MAX_LEN];
+       for (i = 0; i < MAX_BACKUP; i++) {
+               snprintf(new_path, sizeof(new_path), "%s%d", CTSVC_DB_PATH, i);
+               if (-1 == access(new_path, F_OK))
+                       break;
+       }
 
-               if (remove(CTSVC_DB_SHM_FILE) != 0)
-                       ERR("Failed to remove CTSVC_DB_SHM_FILE");
-               if (remove(CTSVC_DB_WAL_FILE) != 0)
-                       ERR("Failed to remove CTSVC_DB_WAL_FILE");
-               if (remove(CTSVC_DB_PATH) !=0)
-                       ERR("Failed to remove CTSVC_DB_PATH");
+       if (rename(CTSVC_DB_PATH, new_path))
+               ERR("rename(%s) Fail(%d)", new_path, errno);
+       snprintf(new_path, sizeof(new_path), "%s%d", CTSVC_DB_SHM_PATH, i);
+       if (rename(CTSVC_DB_SHM_PATH, new_path))
+               ERR("rename(%s) Fail(%d)", new_path, errno);
+       snprintf(new_path, sizeof(new_path), "%s%d", CTSVC_DB_WAL_PATH, i);
+       if (rename(CTSVC_DB_WAL_PATH, new_path))
+               ERR("rename(%s) Fail(%d)", new_path, errno);
+
+       i = (i + 1) % MAX_BACKUP;
+       snprintf(new_path, sizeof(new_path), "%s%d", CTSVC_DB_PATH, i);
+       if (0 == access(new_path, F_OK)) {
+               remove(new_path);
+               snprintf(new_path, sizeof(new_path), "%s%d", CTSVC_DB_SHM_PATH, i);
+               remove(new_path);
+               snprintf(new_path, sizeof(new_path), "%s%d", CTSVC_DB_WAL_PATH, i);
+               remove(new_path);
+       }
+}
 
+int ctsvc_server_check_schema(void)
+{
+       if (false == __ctsvc_server_db_file_exist()) {
+               ERR("Need to remake db files");
+               __ctsvc_server_remake_db_file();
+       } else if (false == __ctsvc_server_check_db()) {
+               ERR("Need to backup and remake db files");
+               __ctsvc_server_backup_file();
                __ctsvc_server_remake_db_file();
        }
 
index 8439a2c..6af8b6a 100644 (file)
@@ -22,8 +22,8 @@
 #include <tzplatform_config.h>
 
 #define CTSVC_DB_PATH tzplatform_mkpath(TZ_USER_DB, "privacy/.contacts-svc.db")
-#define CTSVC_DB_SHM_FILE tzplatform_mkpath(TZ_USER_DB, "privacy/.contacts-svc.db-shm")
-#define CTSVC_DB_WAL_FILE tzplatform_mkpath(TZ_USER_DB, "privacy/.contacts-svc.db-wal")
+#define CTSVC_DB_SHM_PATH tzplatform_mkpath(TZ_USER_DB, "privacy/.contacts-svc.db-shm")
+#define CTSVC_DB_WAL_PATH tzplatform_mkpath(TZ_USER_DB, "privacy/.contacts-svc.db-wal")
 
 /* For Security */
 #define CTS_SECURITY_FILE_GROUP 5000