Integrate files into N files to reduce total file size 22/236622/5 submit/tizen/20200619.070358
authorKichan Kwon <k_c.kwon@samsung.com>
Thu, 18 Jun 2020 06:47:20 +0000 (15:47 +0900)
committerKichan Kwon <k_c.kwon@samsung.com>
Fri, 19 Jun 2020 06:51:31 +0000 (15:51 +0900)
- Although the size of value is small, each key file takes a file block
  - Block size is 4kB
  - 270 model-config keys takes 1.5MB
- To reduce file size, store many keys into the same file
  - To find file name, use hash function
  - In current, store 10 files

Change-Id: I7140e732d7dde1e6c6ad65b28f5f7a064502d9f5
Signed-off-by: Kichan Kwon <k_c.kwon@samsung.com>
include/system_info_private.h
src/init_db/system_info_db_init.c
src/system_info.c

index 53ea717..2454c76 100644 (file)
@@ -75,6 +75,18 @@ static const struct runtime runtime[LANG_MAX] = {
        { LANG_MAX,  NULL,     NULL    }
 };
 
+#define NUM_HASH_FILE 10
+static inline unsigned long simple_hash(char *str)
+{
+       unsigned long ret = 0;
+       int c;
+
+       while ((c = *str++) != 0)
+               ret += c;
+
+       return ret % NUM_HASH_FILE;
+}
+
 int system_info_get_file(const char *key, char *value, size_t len);
 int system_info_get_type_file(const char *key, system_info_type_e *type);
 
index 6c8eb7e..0de7132 100644 (file)
@@ -55,75 +55,155 @@ extern const struct runtime runtime[LANG_MAX];
 static int db_set_value(const char *db_path, char *tag, char *name, char *type, char *value, int val_len)
 {
        int ret;
+       char key_internal[KEY_MAX];
+       size_t key_internal_len;
        char file_path[PATH_MAX];
+       char file_path_new[PATH_MAX * 2];
+       char buf[PATH_MAX];
        char *ptr;
        FILE *fp = NULL;
+       FILE *fp_new = NULL;
+       int key_idx;
 
        if (!db_path || !tag || !name || !type || !value)
                return -EINVAL;
 
        if (name == strstr(name, KEY_PREFIX))
-               snprintf(file_path, sizeof(file_path), "%s/%s/%s:%s", db_path, tag, name + strlen(KEY_PREFIX), type);
+               snprintf(key_internal, sizeof(key_internal), "%s:%s:%s", tag, name + strlen(KEY_PREFIX), type);
        else
-               snprintf(file_path, sizeof(file_path), "%s/%s/%s:%s", db_path, tag, name, type);
-
-       // Make directory recursively
-       for (ptr = file_path + 1; *ptr != '\0'; ptr++) {
-               if (*ptr == '/') {
-                       *ptr = '\0';
-                       ret = mkdir(file_path, 0555);
-                       if (ret != 0 && errno != EEXIST) {
-                               _E("mkdir for %s failed (%d)", file_path, errno);
-                               return -errno;
-                       }
-                       *ptr = '/';
-               }
-       }
+               snprintf(key_internal, sizeof(key_internal), "%s:%s:%s", tag, name, type);
+       snprintf(file_path, sizeof(file_path), "%s/%lu", db_path, simple_hash(key_internal));
 
-       fp = fopen(file_path, "w");
+       fp = fopen(file_path, "r+");
        if (!fp) {
                _E("fopen for %s failed (%d)", file_path, errno);
                return -errno;
        }
 
-       ret = fwrite(value, val_len, 1, fp);
-       fclose(fp);
+       key_internal_len = strlen(key_internal);
+       key_idx = 0;
+       while ((ptr = fgets(buf, sizeof(buf), fp))) {
+               if (!strncmp(buf, key_internal, key_internal_len) && buf[key_internal_len] == ' ')
+                       break;
+               key_idx++;
+       }
 
-       if (ret < 1) {
-               _E("fwrite for %s failed", file_path);
-               return -errno;
+       // 1. Insert new value
+       if (!ptr) {
+               ret = fprintf(fp, "%s %s\n", key_internal, value);
+               fclose(fp);
+
+               if (ret < 2) {
+                       _E("fprintf for %s failed (%d)", file_path, errno);
+                       return -errno;
+               }
+
+               _I("DB: value (key:%s,value:%s) is stored", name, value);
+               return 0;
+       }
+
+       // 2. Make new file to update value
+       snprintf(file_path_new, sizeof(file_path_new), "%s_tmp", file_path);
+       fp_new = fopen(file_path_new, "w");
+       if (!fp_new) {
+               _E("fopen for %s failed (%d)", file_path_new, errno);
+               ret = -errno;
+               goto clean;
        }
 
-       _I("DB: value (key:%s,value:%s) is stored", name, value);
+       // 2-1. Copy prefix
+       rewind(fp);
+       for (int i = 0; i < key_idx; i++) {
+               if (!fgets(buf, sizeof(buf), fp)) {
+                       _E("fgets for %s failed", file_path);
+                       ret = -EIO;
+                       goto clean;
+               }
+               if (fputs(buf, fp_new) == EOF) {
+                       _E("fputs for %s failed", file_path_new);
+                       ret = -EIO;
+                       goto clean;
+               }
+       }
 
-       return 0;
+       // 2-2. Insert new value
+       ret = fprintf(fp_new, "%s %s\n", key_internal, value);
+       if (ret < 2) {
+               _E("fprintf for %s failed (%d)", file_path_new, errno);
+               ret = -errno;
+               goto clean;
+       }
+
+       // To move position indicator
+       if (!fgets(buf, sizeof(buf), fp)) {
+               _E("fgets for %s failed", file_path);
+               ret = -EIO;
+               goto clean;
+       }
+
+       // 2-3. Copy suffix
+       while (fgets(buf, sizeof(buf), fp)) {
+               if (fputs(buf, fp_new) == EOF) {
+                       _E("fputs for %s failed", file_path_new);
+                       ret = -EIO;
+                       goto clean;
+               }
+       }
+
+       // 2-4. Overwrite file
+       ret = rename(file_path_new, file_path);
+       if (ret != 0) {
+               _E("rename for %s failed (%d)", file_path_new, errno);
+               ret = -errno;
+               goto clean;
+       }
+
+       _I("DB: value (key:%s,value:%s) is updated", name, value);
+       ret = 0;
+
+clean:
+       if (fp_new)
+               fclose(fp_new);
+       if (fp)
+               fclose(fp);
+
+       return ret;
 }
 
 static int db_get_value(const char *db_path, char *tag, char *name, char *type, char *value, int val_len)
 {
-       int ret;
-       char file_path[PATH_MAX];
+       char key_internal[KEY_MAX];
+       size_t key_internal_len;
+       char buf[PATH_MAX];
+       char *ptr;
        FILE *fp = NULL;
 
        if (!db_path || !tag || !name || !type || !value)
                return -EINVAL;
 
        if (name == strstr(name, KEY_PREFIX))
-               snprintf(file_path, sizeof(file_path), "%s/%s/%s:%s", db_path, tag, name + strlen(KEY_PREFIX), type);
+               snprintf(key_internal, sizeof(key_internal), "%s:%s:%s", tag, name + strlen(KEY_PREFIX), type);
        else
-               snprintf(file_path, sizeof(file_path), "%s/%s/%s:%s", db_path, tag, name, type);
+               snprintf(key_internal, sizeof(key_internal), "%s:%s:%s", tag, name, type);
+       snprintf(buf, sizeof(buf), "%s/%lu", db_path, simple_hash(key_internal));
 
-       fp = fopen(file_path, "r");
+       fp = fopen(buf, "r");
        if (!fp) {
-               _E("fopen for %s failed (%d)", file_path, errno);
+               _E("fopen for %s failed (%d)", buf, errno);
                return -errno;
        }
 
-       ret = fread(value, val_len, 1, fp);
+       key_internal_len = strlen(key_internal);
+       while ((ptr = fgets(buf, sizeof(buf), fp))) {
+               if (!strncmp(buf, key_internal, key_internal_len) && buf[key_internal_len] == ' ') {
+                       sscanf(buf, "%*s %[^\n]s", value);
+                       break;
+               }
+       }
        fclose(fp);
 
-       if (ret < 1) {
-               _E("fread for %s failed", file_path);
+       if (!ptr) {
+               _E("fgets for %s failed", key_internal);
                return -EIO;
        }
 
@@ -311,6 +391,8 @@ static int system_info_get_values_ini(const char *db_path)
 static int system_info_create_db(const char *conf_path, char *db_path)
 {
        int ret;
+       char file_path[PATH_MAX];
+       FILE *fp = NULL;
 
        if (conf_path == NULL)
                conf_path = MODEL_CONFIG_RO_PATH;
@@ -318,6 +400,22 @@ static int system_info_create_db(const char *conf_path, char *db_path)
        if (db_path == NULL)
                db_path = SYSTEM_INFO_DB_RO_PATH;
 
+       ret = mkdir(db_path, 0555);
+       if (ret != 0 && errno != EEXIST) {
+               _E("mkdir for %s failed (%d)", db_path, errno);
+               return -errno;
+       }
+
+       for (int i = 0; i < NUM_HASH_FILE; i++) {
+               snprintf(file_path, sizeof(file_path), "%s/%d", db_path, i);
+               fp = fopen(file_path, "w");
+               if (!fp) {
+                       _E("fopen for %s failed (%d)", file_path, errno);
+                       return -errno;
+               }
+               fclose(fp);
+       }
+
        ret = system_info_get_values_config_xml(db_path, conf_path);
        if (ret < 0)
                _E("Failed to get keys and values from xml(%d)", ret);
index ad28fd6..5181ec6 100644 (file)
@@ -77,9 +77,9 @@ static void destroy_key_value(gpointer data)
 static int db_get_value(enum tag_type tag, const char *key,
                const char *type, char *value, size_t len)
 {
-       char *db_path;
        char key_internal[KEY_MAX];
-       char file_path[PATH_MAX];
+       size_t key_internal_len;
+       char buf[PATH_MAX];     // buffer size should be larger than KEY_MAX
        FILE *fp = NULL;
        int ret;
        char *tag_s;
@@ -100,9 +100,9 @@ static int db_get_value(enum tag_type tag, const char *key,
        }
 
        if (strstr(key, KEY_PREFIX) == key)
-               snprintf(key_internal, sizeof(key_internal), "%s/%s:%s", tag_s, key + strlen(KEY_PREFIX), type);
+               snprintf(key_internal, sizeof(key_internal), "%s:%s:%s", tag_s, key + strlen(KEY_PREFIX), type);
        else
-               snprintf(key_internal, sizeof(key_internal), "%s/%s:%s", tag_s, key, type);
+               snprintf(key_internal, sizeof(key_internal), "%s:%s:%s", tag_s, key, type);
 
        pthread_mutex_lock(&fmutex);
        if (!hashtable) {
@@ -117,24 +117,30 @@ static int db_get_value(enum tag_type tag, const char *key,
        }
 
        if (access(SYSTEM_INFO_DB_RW_PATH, R_OK) == 0)
-               db_path = SYSTEM_INFO_DB_RW_PATH;
+               snprintf(buf, sizeof(buf), SYSTEM_INFO_DB_RW_PATH"/%lu", simple_hash(key_internal));
        else
-               db_path = SYSTEM_INFO_DB_RO_PATH;
+               snprintf(buf, sizeof(buf), SYSTEM_INFO_DB_RO_PATH"/%lu", simple_hash(key_internal));
 
-       snprintf(file_path, sizeof(file_path), "%s/%s", db_path, key_internal);
-       fp = fopen(file_path, "r");
+       fp = fopen(buf, "r");
        if (!fp) {
                if (errno == ENOENT)
                        _D("Failed to find key in DB (%s, %s)", key, type);
                else
-                       _E("fopen for %s failed (%d)", file_path, errno); //LCOV_EXCL_LINE
+                       _E("fopen for %s failed (%d)", buf, errno); //LCOV_EXCL_LINE
                ret = SYSTEM_INFO_ERROR_IO_ERROR; //LCOV_EXCL_LINE
                goto out;
        }
 
-       temp = fgets(value, len, fp);
+       key_internal_len = strlen(key_internal);
+       while ((temp = fgets(buf, sizeof(buf), fp))) {
+               if (!strncmp(buf, key_internal, key_internal_len) && buf[key_internal_len] == ' ') {
+                       sscanf(buf, "%*s %[^\n]s", value);
+                       break;
+               }
+       }
+
        if (!temp) {
-               _E("fgets for %s failed", file_path);
+               _D("Failed to find key in DB (%s)", key_internal);
                ret = SYSTEM_INFO_ERROR_IO_ERROR;
                goto out;
        }