본문 바로가기

IT/Tizen

[Tizen] 타이젠 앱 DB는 언제 어디서 초기화하는게 좋을까요?

일요일 석양무렵,

관리비 용지 위에다가 앱을 위한 디비 스키마를 그렸습니다.


공동항목과 세대항목으로 나뉘어진 관리비 용지 가운데,

가장 큰 부분을 차지하는 주차비충당금을 보며 한숨을 쉬다가도,

디비에 새겨놓아야하는 필드가 떠오를때마다 다시 펜을 부여잡고 관리비 용지 귀퉁이에 스키마를 그렸죠.


테이블 여덟개를 끄적이고 나니

코드로 옮겨 확인을 해봐야겠다는 생각이 들었습니다.


안녕하세요, Tizen 개발자 윤진입니다.


앱을 위한 DB는 어느 시점에 초기화되어야할까요?

DB 초기화 시점은 아래 중에 하나일 것입니다.

- 앱이 설치되는 시점

- 앱이 처음 런칭되는 시점

- 앱에서 실질적으로 DB에 접근하는 시점


1. 앱이 설치되는 시점

앱이 설치되는 시점에 DB를 만들면,

앱을 런칭한 이후에 DB를 만들 필요가 없으므로,

런칭 혹은 런타임 중에 DB 초기화로 시간을 보내지 않아도 됩니다.


다만 멀티유저 시스템에서 하나의 앱을 다수의 사용자가 공유할 때,

각 사용자마다 DB 파일을 따로 관리하는 경우,

DB 파일을 런타임 중에 추가로 초기화해야합니다.


앱을 최초로 설치한 사용자는 앱을 설치하며 DB를 초기화하고,

앱을 최초로 설치하지 않은 사용자는 설치하며 DB를 초기화하지 못했기 때문에, 런타임 중에 초기화를 해야합니다.

이러한 루틴이 적합한 곳도 있을 수도 있지만,

일관성 있는 룰을 원하는 개발자는 다른 방식으로 DB를 초기화하고 싶겠죠?


2. 앱이 처음 런칭되는 시점

앱이 처음 런칭되는 시점에,

DB파일에 접근하여 DB파일이 준비되어 있지 않다면,

DB를 초기화하는 루틴을 추가할 수도 있습니다.


이 경우는 첫 런칭에서 DB를 초기화해야하기 때문에

첫 런칭 속도에 영향을 줄 수 있습니다.

사용자가 홈/메뉴에서 앱을 선택하였지만,

DB 초기화로 시간을 허비하다보면 최적화가 되어 있지 않은 앱으로 의심 받을 수 있죠. :)


하지만, 멀티유저 환경에서 유연하게 대응할 수 있습니다.

앱을 설치한 유저 외에 다른 유저가 앱을 런칭할 때,

홈 디렉토리에서 DB 파일을 찾아보고 DB 파일이 없으면 바로 생성하면 됩니다.

앱을 설치한 유저나 사용하는 유저나 모두 일관되게 앱을 런칭하며 DB를 만들게 되죠.


3. 앱에서 실질적으로 DB에 접근하는 시점

DB 초기화 루틴을 최대한 뒤로 미룬다.

DB에서 관리하는 데이터가 런칭과 무관하다면,

어렵지 않게 런칭 루틴에서 떼어내어 실제 DB가 사용되는 시점으로 초기화를 늦출 수 있습니다.

이 경우 런칭 성능에는 DB가 전혀 영향을 미치지 않는다는 장점이 있습니다.


다만 DB에 접근하는 루틴과 사용자 동작과 겹치게 된다면,

사용자는 앱이 순간적으로 멈춘다는 인상을 받을 수도 있겠죠.


위의 세 가지 모두 장단점이 있습니다.

모두의 장점을 취할 수는 없기 때문에,

여기서는 2번, 앱이 런칭되며 DB를 초기화하는 루틴을 선택하기로 하죠.

첫 런칭에서 DB 초기화로 약간의 시간을 소요하고 난 뒤,

앱에 진입하고 나서부터는 적어도 DB 때문에 사용자가 기다리지 않도록 하고 싶습니다.


그렇다면, DB 파일은 어디에 생성해야하는 것일까요?


Tizen 2.4에서 제공하는 API는,

앱의 데이터 영역을 확정하여 알려줍니다.



위의 함수에서 데이터를 저장할 디렉토리를 얻어온 후,

런칭 직후 위의 디렉토리에 DB가 없으면 바로 초기화 루틴으로 진입하면 됩니다.


그렇다면, 위의 함수는 멀티유저에 대비가 되어 있을까요?

현재 소스를 따라가 보면,

앱의 pkgid로 data 디렉토리를 한정짓고 있네요.


static int __get_root_path(char *root_path, int root_path_len, bool external)
{
    static char pkgid[_MAX_PACKAGE_ID_LEN] = {0,};
    const char *specific_path = external ? _EXTERNAL_APP_SPECIFIC_PATH : _APP_SPECIFIC_PATH;

    if (pkgid[0] == '\0')
    {  
        int err = __get_pkgid(pkgid, _MAX_PACKAGE_ID_LEN - 1);
        if (err != AUL_R_OK)
        {
            return err;
        }
    }  
    {  
        int specific_path_len = strlen(specific_path);
        int pkgid_len = strlen(pkgid);
        int total_len = specific_path_len + pkgid_len + 1;

        if (total_len > root_path_len)
        {
            _E("Assert: path length %d is too long", total_len);
            assert(false);
        }

        strncat(root_path, specific_path, specific_path_len);
        strncat(root_path + specific_path_len, pkgid, pkgid_len);
        root_path[specific_path_len + pkgid_len] = '/';
    }  

    return AUL_R_OK;
}


위의 함수를 사용하여,

아래와 같이 db_open()을 구현할 수 있습니다.


HAPI appl_error_e db_open(void)
{
    char *path = NULL;
    char db_file[FILE_LEN] = {0, };
    int ret = SQLITE_OK;

    path = app_get_data_path();
    retv_if(!path, APPL_ERROR_FAIL);
   
    snprintf(db_file, sizeof(db_file), "%s/%s", path, APP_DB_FILE);

    ret = sqlite3_open(db_file, &db_info.db);
    if (SQLITE_OK != ret) {
        _E("%s", sqlite3_errmsg(db_info.db));
        free(path);
        return APPL_ERROR_FAIL;
    }  

    free(path);
    return APPL_ERROR_NONE;
}


위처럼 app_get_data_path()로 data를 저장할 디렉토리를 얻어온 후,

DB 명을 대입하여 sqlite3_open()을 수행하면 되죠.


이제 막 DB 초기화와 관련된 걸음마를 떼었습니다.

앞으로 갈 길이 삼천리인데 또 눈꺼풀이 잠겨오네요.


끝_