본문 바로가기

IT/Tizen

[Tizen] 타이젠 플랫폼이 선택한 DB는 SQLite

간단한 앱을 하나 짜더라도

사용자로그를 관리하기 위해서는 DB가 필요하죠.


하지만, 플랫폼마다 지원하는 DBMS가 달라서,

낯선 DBMS 환경에 적응해야하는 경우도 있습니다.


다행스럽게도 타이젠에서는 모바일이나 웨어러블 같은 임베디드 환경에서,

가장 널리 사용되고 있는 SQLite를 지원하고 있습니다.


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


타이젠 2.3에서 지원하고 있는 API 레퍼런스를 살펴보면,

API Reference > Native Application > Native API Reference > Base > sqlite

위와 같이 SQLite 항목을 찾을 수 있습니다.



SQLite 항목을 살펴보면,

SQLite는 가벼운 sql 데이터베이스로 라이브러리 형태로 제공된다고 언급되어 있습니다.

플랫폼에 탑재된 버전은 3.7.13(2015. 5. 28 현재 3. 8. 10. 2가 최신버전)이고,

Documentation은 SQLite 공식사이트(http://www.sqlite.org/docs.html)에 방문하여 보아야 합니다.

SQLite는 시중에 좋은 책도 많이 나와있고,

구글링으로도 깊이 있는 정보를 찾을 수 있기 때문에 API 사용법에 대한 언급은 하지 않겠습니다.


타이젠 플랫폼 소스를 살펴보면 몇가지 흥미로운 사실을 발견할 수 있습니다.


- sqlite3_open()을 직접 호출해주는 라이브러리가 몇개 있습니다.

  libslp-memo, libslp-alaram는 라이브러리 이름으로 파악해보건대,

  위의 라이브러리를 사용하는 앱에서만 DB 정보를 독점하는 것으로 보입니다.

  다른 프로세스에 앱 DB에 대한 정보를 건네줄 필요가 없기 때문에,

  앱에서 사용하는 라이브러리내에 직접 sqlite3를 사용했겠지요.


- 앱단에서는 sqlite3_open() 대신 db_util_open()이라는 유틸리티 함수를 사용하고 있네요.

  db_util_open() 함수 내부에서 sqlite3_open()을 하고, busy handler와 journal mode를 설정하고 있습니다.


/**
 * @brief invoke sqlite3_open with platform common configuration
 * @details register busy handler, create localized collation
 * @param [in] database file name (UTF-8)
 * @param [out] SQLite database handle
 * @param [in] option value
 * @return sqlite3 function return value will be returned
 * @see db_util_open_with_options()
 * @see db_util_close()
 *
 */
EXPORT_API int db_util_open(const char *pszFilePath, sqlite3 **ppDB,
                        int nOption);

위의 함수는 "git://review.tizen.org/framework/appfw/libslp-db-util"의 "include/util-func.h"에서 볼 수 있습니다.

첫번째 인자로 DB 파일이름을 넣어주면,

두번째 인자로 sqlite handle을 넘겨줍니다.


static int __db_util_open(sqlite3 *ppDB)
{
   /* ...생략... */
    /* Register Busy handler */
    rc = sqlite3_busy_handler(ppDB, __db_util_busyhandler, NULL);
    if (SQLITE_OK != rc) {
        DB_UTIL_TRACE_WARNING("Fail to register busy handler\n");
        sqlite3_close(ppDB);
        return rc;
    }

    /* Code to change default journal mode of sqlite3 is enabled so this option is disabled */
    /* Enable persist journal mode */
    rc = sqlite3_exec(ppDB, "PRAGMA journal_mode = PERSIST",
            NULL, NULL, &pszErrorMsg);
    if (SQLITE_OK != rc) {
        DB_UTIL_TRACE_WARNING("Fail to change journal mode: %d, %d, %s, %s\n",
                                sqlite3_errcode(ppDB),
                                sqlite3_extended_errcode(ppDB),
                                pszErrorMsg,
                                sqlite3_errmsg(ppDB));
        sqlite3_free(pszErrorMsg);
        sqlite3_close(ppDB);
   /* ...생략... */ }


위의 코드에서 busy handler를 등록하여,

DB가 EXCLUSIVE 등의 이유로 busy인 경우 retry하도록 설정합니다.


그리고 저널모드로 Persist를 지정해줍니다.

Persist는 롤백 루틴에 사용하는 파일을 일정한 크기로 유지하여,

파일 create & destroy에 따른 비용을 줄이고,

read & write를 최소한의 비용으로 할 수 있게,

디스크 공간은 버리고 성능을 택하는 저널방법입니다.

적어도 이 API만 보면, 타이젠은 성능 최우선의 정책을 취하는 것으로 보입니다.


busy handler에서는 usleep()을 직접 썼습니다.

usleep()은 프로세스 자체를 멈춰버리므로,

busy 상황에서 db_util_open()을 사용하여 강제로 앱프로세스를 멈추게 합니다.


static int __db_util_busyhandler(void *pData, int count)
{
    if(5 - count > 0) {
        DB_UTIL_TRACE_DEBUG("Busy Handler Called! : PID(%d) / CNT(%d)\n", getpid(), count+1);
        usleep((count+1)*100000);
        return 1;
    } else {
        DB_UTIL_TRACE_DEBUG("Busy Handler will be returned SQLITE_BUSY error : PID(%d) \n", getpid());
        return 0;
    }
}


db_util_open()은 framework이나 app단 모두에서 고루 사용하고 있습니다.

framework/api/favorites

framework/pim/calendar-service

framework/pim/contact-service

framework/messaging/email-service

framework/appfw/ail

framework/appfw/slp-pkgmgr

framework/appfw/alarm-manager

apps/home/menu-screen

apps/home/notification

apps/web/browser

등 상당수의 framework와 app에서 사용하고 있습니다.


DB를 open하는 방식으로도 타이젠 플랫폼의 정책을 엿볼 수 있습니다.

플랫폼 버전이 업그레이드될 때마다,

세부구현방식은 바뀔 수 있지만,

플랫폼 정책은 바꾸기 힘들겠죠.

경량화와 빠른 속도를 특장점으로 내세우는 타이젠은,

어쩌면, ivi나 IoT에 적합한 플랫폼일지도 모른다는 생각이 듭니다.


이제 너무 졸려 더 이상 단어를 쓸 여력이 없는 새벽 1시 54분에 마칩니다.


끝_