From b39929ac7c201b8b9c146172acf52904214fe6c4 Mon Sep 17 00:00:00 2001
From: Dmitrii <naidv88@gmail.com>
Date: Mon, 3 Jan 2022 13:36:03 +0500
Subject: [PATCH] [+] add pool sqlite

---
 .../dap_chain_global_db_driver_sqlite.c       | 127 +++++++++++++++---
 .../dap_chain_global_db_driver_sqlite.h       |   2 +
 2 files changed, 108 insertions(+), 21 deletions(-)

diff --git a/modules/global-db/dap_chain_global_db_driver_sqlite.c b/modules/global-db/dap_chain_global_db_driver_sqlite.c
index a853e58f93..50514ccf94 100644
--- a/modules/global-db/dap_chain_global_db_driver_sqlite.c
+++ b/modules/global-db/dap_chain_global_db_driver_sqlite.c
@@ -41,8 +41,15 @@
 
 #define LOG_TAG "db_sqlite"
 
-static sqlite3 *s_db = NULL;
+struct dap_sqlite_conn_pool_item {
+	sqlite3 *conn;
+	int busy;
+};
+
+//static sqlite3 *s_db = NULL;
+static sqlite3 *s_trans = NULL;
 static char *s_filename_db = NULL;
+static struct dap_sqlite_conn_pool_item s_conn_pool[DAP_SQLITE_POOL_COUNT];
 static pthread_rwlock_t s_db_rwlock = PTHREAD_RWLOCK_INITIALIZER;
 // Value of one field in the table
 typedef struct _SQLITE_VALUE_
@@ -77,6 +84,41 @@ typedef struct _SQLITE_ROW_VALUE_
 
 static int dap_db_driver_sqlite_exec(sqlite3 *l_db, const char *l_query, char **l_error_message);
 
+static sqlite3 *s_sqlite_get_connection(void)
+{
+	if (pthread_rwlock_wrlock(&s_db_rwlock) == EDEADLK) {
+		return NULL;
+	}
+
+	sqlite3 *l_ret = NULL;
+	for (int i = 0; i < DAP_SQLITE_POOL_COUNT; i++) {
+		if (!s_conn_pool[i].busy) {
+			l_ret = s_conn_pool[i].conn;
+			s_conn_pool[i].busy = 1;
+			break;
+		}
+	}
+
+	pthread_rwlock_unlock(&s_db_rwlock);
+	return l_ret;
+}
+
+static void s_sqlite_free_connection(sqlite3 *a_conn)
+{
+	if (pthread_rwlock_wrlock(&s_db_rwlock) == EDEADLK) {
+		return;
+	}
+
+	for (int i = 0; i < DAP_SQLITE_POOL_COUNT; i++) {
+		if (s_conn_pool[i].conn == a_conn) {
+			s_conn_pool[i].busy = 0;
+			break;
+		}
+	}
+
+	pthread_rwlock_unlock(&s_db_rwlock);
+}
+
 /**
  * @brief Initializes a SQLite database.
  * @note no thread safe
@@ -112,13 +154,18 @@ int dap_db_driver_sqlite_init(const char *a_filename_db, dap_db_driver_callbacks
     DAP_DEL_Z(l_filename_dir);
     // Open Sqlite file, create if nessesary
     char *l_error_message = NULL;
-    s_db = dap_db_driver_sqlite_open(a_filename_db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, &l_error_message);
-    if(!s_db) {
-        log_it(L_ERROR, "Can't init sqlite err: \"%s\"", l_error_message);
-        dap_db_driver_sqlite_free(l_error_message);
-        l_ret = -3;
-    }
-    else {
+	for (int i = 0; i < DAP_SQLITE_POOL_COUNT; i++) {
+		s_conn_pool[i].conn = dap_db_driver_sqlite_open(a_filename_db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, &l_error_message);
+		if (!s_conn_pool[i].conn) {
+        	log_it(L_ERROR, "Can't init sqlite err: \"%s\"", l_error_message);
+        	dap_db_driver_sqlite_free(l_error_message);
+        	l_ret = -3;
+			for(int ii = i - 1; ii >= 0; ii--) {
+        		dap_db_driver_sqlite_close(s_conn_pool[ii].conn);
+			}
+			goto end;
+		}
+		sqlite3 *s_db = s_conn_pool[i].conn;
         if(!dap_db_driver_sqlite_set_pragma(s_db, "synchronous", "NORMAL")) // 0 | OFF | 1 | NORMAL | 2 | FULL
             printf("can't set new synchronous mode\n");
         if(!dap_db_driver_sqlite_set_pragma(s_db, "journal_mode", "OFF")) // DELETE | TRUNCATE | PERSIST | MEMORY | WAL | OFF
@@ -126,6 +173,9 @@ int dap_db_driver_sqlite_init(const char *a_filename_db, dap_db_driver_callbacks
 
         if(!dap_db_driver_sqlite_set_pragma(s_db, "page_size", "1024")) // DELETE | TRUNCATE | PERSIST | MEMORY | WAL | OFF
             printf("can't set page_size\n");
+		s_conn_pool[i].busy = 0;
+	}
+
         //      *PRAGMA page_size = bytes; // page size DB; it is reasonable to make it equal to the size of the disk cluster 4096
         //     *PRAGMA cache_size = -kibibytes; // by default it is equal to 2000 pages of database
 //
@@ -141,7 +191,7 @@ int dap_db_driver_sqlite_init(const char *a_filename_db, dap_db_driver_callbacks
         a_drv_callback->deinit = dap_db_driver_sqlite_deinit;
         a_drv_callback->flush = dap_db_driver_sqlite_flush;
         s_filename_db = strdup(a_filename_db);
-    }
+end:
         return l_ret;
 }
 
@@ -153,13 +203,14 @@ int dap_db_driver_sqlite_init(const char *a_filename_db, dap_db_driver_callbacks
 int dap_db_driver_sqlite_deinit(void)
 {
         pthread_rwlock_wrlock(&s_db_rwlock);
-        if(!s_db){
-            pthread_rwlock_unlock(&s_db_rwlock);
-            return -666;
-        }
-        dap_db_driver_sqlite_close(s_db);
+		for (int i = 0; i < DAP_SQLITE_POOL_COUNT; i++) {
+			if (s_conn_pool[i].conn) {
+        		dap_db_driver_sqlite_close(s_conn_pool[i].conn);
+				s_conn_pool[i].busy = 0;
+			}
+		}
         pthread_rwlock_unlock(&s_db_rwlock);
-        s_db = NULL;
+        //s_db = NULL;
         return sqlite3_shutdown();
 }
 
@@ -191,14 +242,14 @@ sqlite3* dap_db_driver_sqlite_open(const char *a_filename_utf8, int a_flags, cha
 {
     sqlite3 *l_db = NULL;
 
-    int l_rc = sqlite3_open_v2(a_filename_utf8, &l_db, a_flags | SQLITE_OPEN_FULLMUTEX, NULL);
+    int l_rc = sqlite3_open_v2(a_filename_utf8, &l_db, a_flags | SQLITE_OPEN_NOMUTEX, NULL);
     // if unable to open the database file
     if(l_rc == SQLITE_CANTOPEN) {
         log_it(L_WARNING,"No database on path %s, creating one from scratch", a_filename_utf8);
         if(l_db)
             sqlite3_close(l_db);
         // try to create database
-        l_rc = sqlite3_open_v2(a_filename_utf8, &l_db, a_flags | SQLITE_OPEN_FULLMUTEX| SQLITE_OPEN_CREATE, NULL);
+        l_rc = sqlite3_open_v2(a_filename_utf8, &l_db, a_flags | SQLITE_OPEN_NOMUTEX| SQLITE_OPEN_CREATE, NULL);
     }
 
     if(l_rc != SQLITE_OK) {
@@ -269,6 +320,7 @@ bool dap_db_driver_sqlite_set_pragma(sqlite3 *a_db, char *a_param, char *a_mode)
 int dap_db_driver_sqlite_flush()
 {
     log_it(L_DEBUG, "Start flush sqlite data base.");
+	sqlite3 *s_db = s_sqlite_get_connection();
     pthread_rwlock_wrlock(&s_db_rwlock);
     if(!s_db){
         pthread_rwlock_unlock(&s_db_rwlock);
@@ -331,6 +383,7 @@ static int dap_db_driver_sqlite_exec(sqlite3 *l_db, const char *l_query, char **
  */
 static int dap_db_driver_sqlite_create_group_table(const char *a_table_name)
 {
+	sqlite3 *s_db = s_sqlite_get_connection();
     char *l_error_message = NULL;
     if(!s_db || !a_table_name)
         return -1;
@@ -343,6 +396,7 @@ static int dap_db_driver_sqlite_create_group_table(const char *a_table_name)
         log_it(L_ERROR, "Creatу_table : %s\n", l_error_message);
         dap_db_driver_sqlite_free(l_error_message);
         DAP_DELETE(l_query);
+		s_sqlite_free_connection(s_db);
         return -1;
     }
     DAP_DELETE(l_query);
@@ -353,9 +407,11 @@ static int dap_db_driver_sqlite_create_group_table(const char *a_table_name)
         log_it(L_ERROR, "Create unique index : %s\n", l_error_message);
         dap_db_driver_sqlite_free(l_error_message);
         DAP_DELETE(l_query);
+		s_sqlite_free_connection(s_db);
         return -1;
     }
     DAP_DELETE(l_query);
+	s_sqlite_free_connection(s_db);
     return 0;
 }
 
@@ -512,13 +568,14 @@ int dap_db_driver_sqlite_vacuum(sqlite3 *l_db)
  */
 int dap_db_driver_sqlite_start_transaction(void)
 {
+	s_trans = s_sqlite_get_connection();
     pthread_rwlock_wrlock(&s_db_rwlock);
-    if(!s_db){
+    if(!s_trans){
         pthread_rwlock_unlock(&s_db_rwlock);
         return -666;
     }
 
-    if(SQLITE_OK == dap_db_driver_sqlite_exec(s_db, "BEGIN", NULL)){
+    if(SQLITE_OK == dap_db_driver_sqlite_exec(s_trans, "BEGIN", NULL)){
         pthread_rwlock_unlock(&s_db_rwlock);
         return 0;
     }else{
@@ -535,11 +592,11 @@ int dap_db_driver_sqlite_start_transaction(void)
 int dap_db_driver_sqlite_end_transaction(void)
 {
     pthread_rwlock_wrlock(&s_db_rwlock);
-    if(!s_db){
+    if(!s_trans){
         pthread_rwlock_unlock(&s_db_rwlock);
         return -666;
     }
-    if(SQLITE_OK == dap_db_driver_sqlite_exec(s_db, "COMMIT", NULL)){
+    if(SQLITE_OK == dap_db_driver_sqlite_exec(s_trans, "COMMIT", NULL)){
         pthread_rwlock_unlock(&s_db_rwlock);
         return 0;
     }else{
@@ -630,6 +687,7 @@ int dap_db_driver_sqlite_apply_store_obj(dap_store_obj_t *a_store_obj)
         return -1;
     }
     // execute request
+	sqlite3 *s_db = s_sqlite_get_connection();
     pthread_rwlock_wrlock(&s_db_rwlock);
     if(!s_db){
         pthread_rwlock_unlock(&s_db_rwlock);
@@ -669,6 +727,7 @@ int dap_db_driver_sqlite_apply_store_obj(dap_store_obj_t *a_store_obj)
         dap_db_driver_sqlite_free(l_error_message);
         l_ret = -1;
     }
+	s_sqlite_free_connection(s_db);
     if (a_store_obj->key)
         DAP_DELETE(a_store_obj->key);
     dap_db_driver_sqlite_free(l_query);
@@ -731,6 +790,7 @@ dap_store_obj_t* dap_db_driver_sqlite_read_last_store_obj(const char *a_group)
         return NULL;
     char * l_table_name = dap_db_driver_sqlite_make_table_name(a_group);
     char *l_str_query = sqlite3_mprintf("SELECT id,ts,key,value FROM '%s' ORDER BY id DESC LIMIT 1", l_table_name);
+	sqlite3 *s_db = s_sqlite_get_connection();
     pthread_rwlock_wrlock(&s_db_rwlock);
     if(!s_db){
         pthread_rwlock_unlock(&s_db_rwlock);
@@ -744,6 +804,7 @@ dap_store_obj_t* dap_db_driver_sqlite_read_last_store_obj(const char *a_group)
     if(l_ret != SQLITE_OK) {
         //log_it(L_ERROR, "read last l_ret=%d, %s\n", sqlite3_errcode(s_db), sqlite3_errmsg(s_db));
         dap_db_driver_sqlite_free(l_error_message);
+		s_sqlite_free_connection(s_db);
         return NULL;
     }
 
@@ -760,6 +821,8 @@ dap_store_obj_t* dap_db_driver_sqlite_read_last_store_obj(const char *a_group)
     dap_db_driver_sqlite_row_free(l_row);
     dap_db_driver_sqlite_query_free(l_res);
 
+	s_sqlite_free_connection(s_db);
+
     return l_obj;
 }
 
@@ -792,6 +855,7 @@ dap_store_obj_t* dap_db_driver_sqlite_read_cond_store_obj(const char *a_group, u
     else
         l_str_query = sqlite3_mprintf("SELECT id,ts,key,value FROM '%s' WHERE id>='%lld' ORDER BY id ASC",
                 l_table_name, a_id);
+	sqlite3 *s_db = s_sqlite_get_connection();
     pthread_rwlock_wrlock(&s_db_rwlock);
     if(!s_db){
         pthread_rwlock_unlock(&s_db_rwlock);
@@ -806,6 +870,7 @@ dap_store_obj_t* dap_db_driver_sqlite_read_cond_store_obj(const char *a_group, u
     if(l_ret != SQLITE_OK) {
         //log_it(L_ERROR, "read l_ret=%d, %s\n", sqlite3_errcode(s_db), sqlite3_errmsg(s_db));
         dap_db_driver_sqlite_free(l_error_message);
+		s_sqlite_free_connection(s_db);
         return NULL;
     }
 
@@ -835,9 +900,11 @@ dap_store_obj_t* dap_db_driver_sqlite_read_cond_store_obj(const char *a_group, u
     } while(l_row);
 
     dap_db_driver_sqlite_query_free(l_res);
+	s_sqlite_free_connection(s_db);
 
     if(a_count_out)
         *a_count_out = (size_t)l_count_out;
+
     return l_obj;
 }
 
@@ -851,6 +918,7 @@ dap_store_obj_t* dap_db_driver_sqlite_read_cond_store_obj(const char *a_group, u
  */
 dap_store_obj_t* dap_db_driver_sqlite_read_store_obj(const char *a_group, const char *a_key, size_t *a_count_out)
 {
+	sqlite3 *s_db = s_sqlite_get_connection();
     if(!a_group || !s_db)
         return NULL;
     dap_store_obj_t *l_obj = NULL;
@@ -884,6 +952,7 @@ dap_store_obj_t* dap_db_driver_sqlite_read_store_obj(const char *a_group, const
     DAP_DEL_Z(l_table_name);
     if(l_ret != SQLITE_OK) {
         //log_it(L_ERROR, "read l_ret=%d, %s\n", sqlite3_errcode(s_db), sqlite3_errmsg(s_db));
+		s_sqlite_free_connection(s_db);
         return NULL;
     }
 
@@ -913,6 +982,7 @@ dap_store_obj_t* dap_db_driver_sqlite_read_store_obj(const char *a_group, const
     } while(l_row);
 
     dap_db_driver_sqlite_query_free(l_res);
+	s_sqlite_free_connection(s_db);
 
     if(a_count_out)
         *a_count_out = l_count_out;
@@ -927,6 +997,7 @@ dap_store_obj_t* dap_db_driver_sqlite_read_store_obj(const char *a_group, const
  */
 dap_list_t* dap_db_driver_sqlite_get_groups_by_mask(const char *a_group_mask)
 {
+	sqlite3 *s_db = s_sqlite_get_connection();
     if(!a_group_mask || !s_db)
         return NULL;
     sqlite3_stmt *l_res;
@@ -937,6 +1008,7 @@ dap_list_t* dap_db_driver_sqlite_get_groups_by_mask(const char *a_group_mask)
     pthread_rwlock_unlock(&s_db_rwlock);
     if(l_ret != SQLITE_OK) {
         //log_it(L_ERROR, "Get tables l_ret=%d, %s\n", sqlite3_errcode(s_db), sqlite3_errmsg(s_db));
+		s_sqlite_free_connection(s_db);
         return NULL;
     }
     char * l_mask = dap_db_driver_sqlite_make_table_name(a_group_mask);
@@ -948,6 +1020,9 @@ dap_list_t* dap_db_driver_sqlite_get_groups_by_mask(const char *a_group_mask)
         dap_db_driver_sqlite_row_free(l_row);
     }
     dap_db_driver_sqlite_query_free(l_res);
+
+	s_sqlite_free_connection(s_db);
+
     return l_ret_list;
 }
 
@@ -960,6 +1035,7 @@ dap_list_t* dap_db_driver_sqlite_get_groups_by_mask(const char *a_group_mask)
  */
 size_t dap_db_driver_sqlite_read_count_store(const char *a_group, uint64_t a_id)
 {
+	sqlite3 *s_db = s_sqlite_get_connection();
     sqlite3_stmt *l_res;
     if(!a_group || ! s_db)
         return 0;
@@ -974,6 +1050,7 @@ size_t dap_db_driver_sqlite_read_count_store(const char *a_group, uint64_t a_id)
 
     if(l_ret != SQLITE_OK) {
         //log_it(L_ERROR, "Count l_ret=%d, %s\n", sqlite3_errcode(s_db), sqlite3_errmsg(s_db));
+		s_sqlite_free_connection(s_db);
         return 0;
     }
     size_t l_ret_val = 0;
@@ -983,6 +1060,9 @@ size_t dap_db_driver_sqlite_read_count_store(const char *a_group, uint64_t a_id)
         dap_db_driver_sqlite_row_free(l_row);
     }
     dap_db_driver_sqlite_query_free(l_res);
+
+	s_sqlite_free_connection(s_db);
+
     return l_ret_val;
 }
 
@@ -995,6 +1075,7 @@ size_t dap_db_driver_sqlite_read_count_store(const char *a_group, uint64_t a_id)
  */
 bool dap_db_driver_sqlite_is_obj(const char *a_group, const char *a_key)
 {
+	sqlite3 *s_db = s_sqlite_get_connection();
     sqlite3_stmt *l_res;
     if(!a_group || ! s_db)
         return false;
@@ -1009,6 +1090,7 @@ bool dap_db_driver_sqlite_is_obj(const char *a_group, const char *a_key)
 
     if(l_ret != SQLITE_OK) {
         //log_it(L_ERROR, "Exists l_ret=%d, %s\n", sqlite3_errcode(s_db), sqlite3_errmsg(s_db));
+		s_sqlite_free_connection(s_db);
         return false;
     }
     bool l_ret_val = false;
@@ -1018,5 +1100,8 @@ bool dap_db_driver_sqlite_is_obj(const char *a_group, const char *a_key)
         dap_db_driver_sqlite_row_free(l_row);
     }
     dap_db_driver_sqlite_query_free(l_res);
+
+	s_sqlite_free_connection(s_db);
+
     return l_ret_val;
 }
diff --git a/modules/global-db/include/dap_chain_global_db_driver_sqlite.h b/modules/global-db/include/dap_chain_global_db_driver_sqlite.h
index 7c05f5fd33..aa5e50219b 100644
--- a/modules/global-db/include/dap_chain_global_db_driver_sqlite.h
+++ b/modules/global-db/include/dap_chain_global_db_driver_sqlite.h
@@ -27,6 +27,8 @@
 #include <sqlite3.h>
 #include "dap_chain_global_db_driver.h"
 
+#define DAP_SQLITE_POOL_COUNT                   16
+
 int dap_db_driver_sqlite_init(const char *a_filename_db, dap_db_driver_callbacks_t *a_drv_callback);
 int dap_db_driver_sqlite_deinit(void);
 
-- 
GitLab