Simplify db_manager's sync query execution routine 52/49752/1
authorMu-Woong <muwoong.lee@samsung.com>
Tue, 20 Oct 2015 04:32:04 +0000 (13:32 +0900)
committerMu-Woong <muwoong.lee@samsung.com>
Tue, 20 Oct 2015 04:32:04 +0000 (13:32 +0900)
Naive locking mechanism is used instead of condition variables.

Change-Id: Icd6c3ca2ae61900169bebafda7716f4c4c19cef9
Signed-off-by: Mu-Woong <muwoong.lee@samsung.com>
src/db_mgr_impl.cpp
src/db_mgr_impl.h

index 8db319e..b229039 100644 (file)
 #define CONTEXT_DB_PATH tzplatform_mkpath(TZ_USER_DB, ".context-service.db")
 
 static bool initialized = false;
-static GThread *mainthread = NULL;
-static GMutex sync_insert_mutex;
-static GMutex sync_execute_mutex;
-static GCond sync_insert_cond;
-static GCond sync_execute_cond;
-static int64_t sync_insert_row_id = -1;
-static unsigned int sync_insert_qid = 0;
-static int sync_execute_error;
-static std::vector<ctx::json> sync_execute_result;
-static unsigned int sync_execute_qid = 0;
+static GMutex exec_mutex;
 
 ctx::db_manager_impl::db_manager_impl()
        : db_handle(NULL)
@@ -52,7 +43,6 @@ bool ctx::db_manager_impl::init()
 {
        IF_FAIL_RETURN_TAG(!initialized, true, _W, "Re-initialization");
        IF_FAIL_RETURN(open(), false);
-       mainthread = g_thread_self();
        IF_FAIL_RETURN(start(), false);
        initialized = true;
        return true;
@@ -85,25 +75,20 @@ void ctx::db_manager_impl::close()
        db_handle = NULL;
 }
 
-bool ctx::db_manager_impl::is_main_thread()
-{
-       return mainthread == g_thread_self();
-}
-
 void ctx::db_manager_impl::on_thread_event_popped(int type, void* data)
 {
        IF_FAIL_VOID(data);
        query_info_s *info = static_cast<query_info_s*>(data);
 
        switch (type) {
-               case QTYPE_CREATE_TABLE:
-               case QTYPE_INSERT:
-               case QTYPE_EXECUTE:
-                       _execute(type, info->id, info->query.c_str(), info->listener);
-                       break;
-               default:
-                       _W("Unknown type: %d", type);
-                       break;
+       case QTYPE_CREATE_TABLE:
+       case QTYPE_INSERT:
+       case QTYPE_EXECUTE:
+               _execute(type, info->id, info->query.c_str(), info->listener);
+               break;
+       default:
+               _W("Unknown type: %d", type);
+               break;
        }
 
        delete_thread_event(type, data);
@@ -116,6 +101,18 @@ void ctx::db_manager_impl::delete_thread_event(int type, void* data)
        delete info;
 }
 
+std::string ctx::db_manager_impl::compose_create_query(const char* table_name, const char* columns, const char* option)
+{
+       std::string query;
+       query = "CREATE TABLE IF NOT EXISTS ";
+       query = query + table_name + " (row_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT," + columns + ")";
+       if (option) {
+               query = query + " " + option;
+       }
+       query += ";";
+       return query;
+}
+
 bool ctx::db_manager_impl::create_table(unsigned int query_id, const char* table_name, const char* columns, const char* option, db_listener_iface* listener)
 {
        IF_FAIL_RETURN_TAG(initialized, false, _E, "Not initialized");
@@ -123,13 +120,7 @@ bool ctx::db_manager_impl::create_table(unsigned int query_id, const char* table
        query_info_s *info = new(std::nothrow) query_info_s;
        IF_FAIL_RETURN_TAG(info, false, _E, "Memory allocation failed");
 
-       info->query = "CREATE TABLE IF NOT EXISTS ";
-       info->query = info->query + table_name + " (row_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT," + columns + ")";
-       if (option) {
-               info->query = info->query + " " + option;
-       }
-       info->query += ";";
-
+       info->query = compose_create_query(table_name, columns, option);
        info->id = query_id;
        info->listener = listener;
 
@@ -142,12 +133,10 @@ bool ctx::db_manager_impl::create_table(unsigned int query_id, const char* table
        return true;
 }
 
-bool ctx::db_manager_impl::insert(unsigned int query_id, const char* table_name, json& record, db_listener_iface* listener)
+std::string ctx::db_manager_impl::compose_insert_query(const char* table_name, json& record)
 {
-       IF_FAIL_RETURN_TAG(initialized, false, _E, "Not initialized");
-
        std::list<std::string> keys;
-       IF_FAIL_RETURN_TAG(record.get_keys(&keys), false, _E, "Invalid record");
+       IF_FAIL_RETURN_TAG(record.get_keys(&keys), "", _E, "Invalid record");
 
        std::ostringstream colstream;
        std::ostringstream valstream;
@@ -159,7 +148,7 @@ bool ctx::db_manager_impl::insert(unsigned int query_id, const char* table_name,
                        colstream << *it << ",";
 
                        char* buf = sqlite3_mprintf("%Q", s.c_str());
-                       IF_FAIL_RETURN_TAG(buf, false, _E, "Memory allocation failed");
+                       IF_FAIL_RETURN_TAG(buf, "", _E, "Memory allocation failed");
                        valstream << buf << ",";
                        sqlite3_free(buf);
                } else if (record.get(NULL, (*it).c_str(), &i)) {
@@ -171,21 +160,32 @@ bool ctx::db_manager_impl::insert(unsigned int query_id, const char* table_name,
        std::string cols = colstream.str();
        std::string vals = valstream.str();
 
-       IF_FAIL_RETURN_TAG(!cols.empty(), false, _E, "Invalid record");
+       IF_FAIL_RETURN_TAG(!cols.empty(), "", _E, "Invalid record");
 
        cols.erase(cols.size() - 1);
        vals.erase(vals.size() - 1);
 
+       std::string query = "INSERT INTO ";
+       query = query + table_name + " (" + cols + ") VALUES (" + vals + ");";
+       query = query + "SELECT seq FROM sqlite_sequence WHERE name='" + table_name + "';";
+
+       return query;
+}
+
+bool ctx::db_manager_impl::insert(unsigned int query_id, const char* table_name, json& record, db_listener_iface* listener)
+{
+       IF_FAIL_RETURN_TAG(initialized, false, _E, "Not initialized");
+
+       std::string query = compose_insert_query(table_name, record);
+       IF_FAIL_RETURN(!query.empty(), false);
+
        query_info_s *info = new(std::nothrow) query_info_s;
        IF_FAIL_RETURN_TAG(info, false, _E, "Memory allocation failed");
 
+       info->query = query;
        info->id = query_id;
        info->listener = listener;
 
-       info->query = "INSERT INTO ";
-       info->query = info->query + table_name + " (" + cols + ") VALUES (" + vals + ");";
-       info->query = info->query + "SELECT seq FROM sqlite_sequence WHERE name='" + table_name + "';";
-
        if (!push_thread_event(QTYPE_INSERT, info)) {
                _E("Pushing thread event failed");
                delete info;
@@ -198,6 +198,7 @@ bool ctx::db_manager_impl::insert(unsigned int query_id, const char* table_name,
 bool ctx::db_manager_impl::execute(unsigned int query_id, const char* query, db_listener_iface* listener)
 {
        IF_FAIL_RETURN_TAG(initialized, false, _E, "Not initialized");
+       IF_FAIL_RETURN_TAG(query, false, _E, "Null query");
 
        query_info_s *info = new(std::nothrow) query_info_s;
        IF_FAIL_RETURN_TAG(info, false, _E, "Memory allocation failed");
@@ -217,16 +218,21 @@ bool ctx::db_manager_impl::execute(unsigned int query_id, const char* query, db_
 
 void ctx::db_manager_impl::_execute(int query_type, unsigned int query_id, const char* query, db_listener_iface* listener)
 {
-       _SD("SQL(%d): %s", query_id, query);
        IF_FAIL_VOID(query);
        IF_FAIL_VOID_TAG(db_handle, _E, "DB not opened");
+       _SD("SQL(%d): %s", query_id, query);
 
        std::vector<json> *query_result = new(std::nothrow) std::vector<json>;
        IF_FAIL_VOID_TAG(query_result, _E, "Memory allocation failed");
 
        char *err = NULL;
+       int ret;
+
+       {
+               scope_mutex sm(&exec_mutex);
+               ret = sqlite3_exec(db_handle, query, execution_result_cb, query_result, &err);
+       }
 
-       int ret = sqlite3_exec(db_handle, query, execution_result_cb, query_result, &err);
        if (ret != SQLITE_OK) {
                _E("DB Error: %s", err);
                sqlite3_free(err);
@@ -281,24 +287,24 @@ gboolean ctx::db_manager_impl::_send_result(gpointer data)
 
        if (qr->listener) {
                switch (qr->type) {
-                       case QTYPE_CREATE_TABLE:
-                               qr->listener->on_creation_result_received(qr->id, qr->error);
-                               break;
-                       case QTYPE_INSERT:
-                               {
-                                       int64_t row_id = -1;
-                                       if (qr->error == ERR_NONE && qr->result && !qr->result->empty()) {
-                                               qr->result->at(0).get(NULL, "seq", &row_id);
-                                               _D("RowId: %d", row_id);
-                                       }
-                                       qr->listener->on_insertion_result_received(qr->id, qr->error, row_id);
+               case QTYPE_CREATE_TABLE:
+                       qr->listener->on_creation_result_received(qr->id, qr->error);
+                       break;
+               case QTYPE_INSERT:
+                       {
+                               int64_t row_id = -1;
+                               if (qr->error == ERR_NONE && qr->result && !qr->result->empty()) {
+                                       qr->result->at(0).get(NULL, "seq", &row_id);
+                                       _D("RowId: %d", row_id);
                                }
-                               break;
-                       case QTYPE_EXECUTE:
-                               qr->listener->on_query_result_received(qr->id, qr->error, *(qr->result));
-                               break;
-                       default:
-                               _W("Unknown query type: %d", qr->type);
+                               qr->listener->on_insertion_result_received(qr->id, qr->error, row_id);
+                       }
+                       break;
+               case QTYPE_EXECUTE:
+                       qr->listener->on_query_result_received(qr->id, qr->error, *(qr->result));
+                       break;
+               default:
+                       _W("Unknown query type: %d", qr->type);
                }
        }
 
@@ -307,88 +313,81 @@ gboolean ctx::db_manager_impl::_send_result(gpointer data)
        return FALSE;
 }
 
-static unsigned int generate_qid()
+bool ctx::db_manager_impl::create_table_sync(const char* table_name, const char* columns, const char* option)
 {
-       static GMutex mutex;
-       static unsigned int qid = 0;
+       IF_FAIL_RETURN_TAG(db_handle, false, _E, "DB not opened");
 
-       ctx::scope_mutex sm(&mutex);
+       std::string query = compose_create_query(table_name, columns, option);
+       IF_FAIL_RETURN(!query.empty(), false);
+       _SD("SQL: %s", query.c_str());
 
-       ++qid;
+       char *err = NULL;
+       int ret;
+       {
+               scope_mutex sm(&exec_mutex);
+               ret = sqlite3_exec(db_handle, query.c_str(), NULL, NULL, &err);
+       }
 
-       if (qid == 0) { // Overflow handling
-               qid = 1;
+       if (ret != SQLITE_OK) {
+               _E("DB Error: %s", err);
+               sqlite3_free(err);
+               return false;
        }
 
-       return qid;
+       return true;
 }
 
 bool ctx::db_manager_impl::insert_sync(const char* table_name, json& record, int64_t* row_id)
 {
-       IF_FAIL_RETURN_TAG(initialized, false, _E, "Not initialized");
-       IF_FAIL_RETURN_TAG(!db_manager_impl::is_main_thread(), false, _E, "Cannot use this in the main thread");
+       IF_FAIL_RETURN_TAG(db_handle, false, _E, "DB not opened");
        IF_FAIL_RETURN_TAG(table_name && row_id, false, _E, "Invalid parameter");
 
-       ctx::scope_mutex sm(&sync_insert_mutex);
+       std::string query = compose_insert_query(table_name, record);
+       IF_FAIL_RETURN(!query.empty(), false);
+       _SD("SQL: %s", query.c_str());
 
-       unsigned int qid = generate_qid();
-       insert(qid, table_name, record, this);
-
-       while (sync_insert_qid != qid) {
-               g_cond_wait(&sync_insert_cond, &sync_insert_mutex);
+       std::vector<json> query_result;
+       char *err = NULL;
+       int ret;
+       {
+               scope_mutex sm(&exec_mutex);
+               ret = sqlite3_exec(db_handle, query.c_str(), execution_result_cb, &query_result, &err);
        }
 
-       *row_id = sync_insert_row_id;
+       if (ret != SQLITE_OK) {
+               _E("DB Error: %s", err);
+               sqlite3_free(err);
+               return false;
+       }
 
-       IF_FAIL_RETURN_TAG(*row_id > 0, false, _E, "Insertion failed");
-       return true;
-}
+       IF_FAIL_RETURN_TAG(!query_result.empty(), false, _E, "No row id");
 
-void ctx::db_manager_impl::on_insertion_result_received(unsigned int query_id, int error, int64_t row_id)
-{
-       ctx::scope_mutex sm(&sync_insert_mutex);
+       *row_id = -1;
+       query_result.at(0).get(NULL, "seq", row_id);
+       _D("RowId: %d", *row_id);
 
-       sync_insert_row_id = row_id;
-       sync_insert_qid = query_id;
-
-       g_cond_signal(&sync_insert_cond);
+       return true;
 }
 
 bool ctx::db_manager_impl::execute_sync(const char* query, std::vector<json>* records)
 {
-       IF_FAIL_RETURN_TAG(initialized, false, _E, "Not initialized");
-       IF_FAIL_RETURN_TAG(!db_manager_impl::is_main_thread(), false, _E, "Cannot use this in the main thread");
+       IF_FAIL_RETURN_TAG(db_handle, false, _E, "DB not opened");
        IF_FAIL_RETURN_TAG(query && records, false, _E, "Invalid parameter");
 
-       ctx::scope_mutex sm(&sync_execute_mutex);
+       _SD("SQL: %s", query);
 
-       unsigned int qid = generate_qid();
-       execute(qid, query, this);
-
-       while (sync_execute_qid != qid) {
-               g_cond_wait(&sync_execute_cond, &sync_execute_mutex);
+       char *err = NULL;
+       int ret;
+       {
+               scope_mutex sm(&exec_mutex);
+               ret = sqlite3_exec(db_handle, query, execution_result_cb, records, &err);
        }
 
-       IF_FAIL_RETURN_TAG(sync_execute_error == ERR_NONE, false, _E, "Query execution failed");
-
-       *records = sync_execute_result;
-       sync_execute_result.clear();
+       if (ret != SQLITE_OK) {
+               _E("DB Error: %s", err);
+               sqlite3_free(err);
+               return false;
+       }
 
        return true;
 }
-
-void ctx::db_manager_impl::on_query_result_received(unsigned int query_id, int error, std::vector<json>& records)
-{
-       ctx::scope_mutex sm(&sync_execute_mutex);
-
-       sync_execute_error = error;
-       sync_execute_result = records;
-       sync_execute_qid = query_id;
-
-       g_cond_signal(&sync_execute_cond);
-}
-
-void ctx::db_manager_impl::on_creation_result_received(unsigned int query_id, int error)
-{
-       _D("Table Created: QID: %d, Error: %#x", query_id, error);
-}
index d3f7a93..a00fd52 100644 (file)
 
 namespace ctx {
 
-       class db_manager_impl : public event_driven_thread, public db_listener_iface, public db_manager_iface {
-               private:
-                       enum query_type_e {
-                               QTYPE_CREATE_TABLE = 1,
-                               QTYPE_INSERT,
-                               QTYPE_EXECUTE,
-                       };
-
-                       struct query_info_s {
-                               unsigned int id;
-                               db_listener_iface* listener;
-                               std::string query;
-                       };
-
-                       struct query_result_s {
-                               int type;
-                               unsigned int id;
-                               int error;
-                               db_listener_iface* listener;
-                               std::vector<json>* result;
-                       };
-
-                       sqlite3 *db_handle;
-
-                       static bool is_main_thread();
-
-                       void on_thread_event_popped(int type, void* data);
-                       void delete_thread_event(int type, void* data);
-
-                       bool open();
-                       void close();
-
-                       void _execute(int query_type, unsigned int query_id, const char* query, db_listener_iface* listener);
-                       void send_result(int query_type, unsigned int query_id, db_listener_iface* listener, int error, std::vector<json>* result);
-
-                       static int execution_result_cb(void *user_data, int dim, char **value, char **column);
-                       static gboolean _send_result(gpointer data);
-
-                       void on_creation_result_received(unsigned int query_id, int error);
-                       void on_insertion_result_received(unsigned int query_id, int error, int64_t row_id);
-                       void on_query_result_received(unsigned int query_id, int error, std::vector<json>& records);
-
-               public:
-                       db_manager_impl();
-                       ~db_manager_impl();
-
-                       bool init();
-                       void release();
-
-                       bool create_table(unsigned int query_id, const char* table_name, const char* columns, const char* option = NULL, db_listener_iface* listener = NULL);
-                       bool insert(unsigned int query_id, const char* table_name, json& record, db_listener_iface* listener = NULL);
-                       bool execute(unsigned int query_id, const char* query, db_listener_iface* listener);
-                       bool insert_sync(const char* table_name, json& record, int64_t* row_id);
-                       bool execute_sync(const char* query, std::vector<json>* records);
+       class db_manager_impl : public event_driven_thread, public db_manager_iface {
+       private:
+               enum query_type_e {
+                       QTYPE_CREATE_TABLE = 1,
+                       QTYPE_INSERT,
+                       QTYPE_EXECUTE,
+               };
+
+               struct query_info_s {
+                       unsigned int id;
+                       db_listener_iface* listener;
+                       std::string query;
+               };
+
+               struct query_result_s {
+                       int type;
+                       unsigned int id;
+                       int error;
+                       db_listener_iface* listener;
+                       std::vector<json>* result;
+               };
+
+               sqlite3 *db_handle;
+
+               void on_thread_event_popped(int type, void* data);
+               void delete_thread_event(int type, void* data);
+
+               bool open();
+               void close();
+
+               std::string compose_create_query(const char* table_name, const char* columns, const char* option);
+               std::string compose_insert_query(const char* table_name, json& record);
+
+               void _execute(int query_type, unsigned int query_id, const char* query, db_listener_iface* listener);
+               void send_result(int query_type, unsigned int query_id, db_listener_iface* listener, int error, std::vector<json>* result);
+
+               static int execution_result_cb(void *user_data, int dim, char **value, char **column);
+               static gboolean _send_result(gpointer data);
+
+       public:
+               db_manager_impl();
+               ~db_manager_impl();
+
+               bool init();
+               void release();
+
+               bool create_table(unsigned int query_id, const char* table_name, const char* columns, const char* option = NULL, db_listener_iface* listener = NULL);
+               bool insert(unsigned int query_id, const char* table_name, json& record, db_listener_iface* listener = NULL);
+               bool execute(unsigned int query_id, const char* query, db_listener_iface* listener);
+
+               bool create_table_sync(const char* table_name, const char* columns, const char* option = NULL);
+               bool insert_sync(const char* table_name, json& record, int64_t* row_id);
+               bool execute_sync(const char* query, std::vector<json>* records);
 
        };      /* class db_manager */
 }