Clean sqlite prepared statements on thread shutdown (#13193)
* Clean sqlite prepared statements on thread shutdown * Add note for pending statements to finalize
Stelios Fragkakis committed
Jun 22, 2022 at 23:38 UTC
5ecd4b4a311e0a83dcd900f8e11f6f355a562b1e
1 file changed
+41
-4
database/sqlite/sqlite_functions.c
+41
-4
@@ -68,6 +68,9 @@ const char *database_cleanup[] = {
68
69
sqlite3 *db_meta = NULL;
70
71
+#define MAX_PREPARED_STATEMENTS (32)
72
+pthread_key_t key_pool[MAX_PREPARED_STATEMENTS];
73
+
74
static uv_mutex_t sqlite_transaction_lock;
75
76
int execute_insert(sqlite3_stmt *res)
@@ -96,6 +99,10 @@ static void add_stmt_to_list(sqlite3_stmt *res)
99
static sqlite3_stmt *statements[MAX_OPEN_STATEMENTS];
100
101
if (unlikely(!res)) {
102
+ if (idx)
103
+ info("Finilizing %d statements", idx);
104
+ else
105
+ info("No statements pending to finalize");
106
while (idx > 0) {
107
int rc;
108
rc = sqlite3_finalize(statements[--idx]);
@@ -107,13 +114,39 @@ static void add_stmt_to_list(sqlite3_stmt *res)
114
115
if (unlikely(idx == MAX_OPEN_STATEMENTS))
116
return;
110
- statements[idx++] = res;
117
}
118
113
-int prepare_statement(sqlite3 *database, char *query, sqlite3_stmt **statement) {
119
+static void release_statement(void *statement)
120
+{
121
+ int rc;
122
+#ifdef NETDATA_INTERNAL_CHECKS
123
+ info("Thread %d: Cleaning prepared statement on %p", gettid(), statement);
124
+#endif
125
+ if (unlikely(rc = sqlite3_finalize((sqlite3_stmt *) statement) != SQLITE_OK))
126
+ error_report("Failed to finalize statement, rc = %d", rc);
127
+}
128
+
129
+int prepare_statement(sqlite3 *database, char *query, sqlite3_stmt **statement)
130
+{
131
+ static __thread uint32_t keys_used = 0;
132
+
133
+ pthread_key_t *key = NULL;
134
+ int ret = 1;
135
+
136
+ if (likely(keys_used < MAX_PREPARED_STATEMENTS))
137
+ key = &key_pool[keys_used++];
138
+
139
int rc = sqlite3_prepare_v2(database, query, -1, statement, 0);
115
- if (likely(rc == SQLITE_OK))
116
- add_stmt_to_list(*statement);
140
+ if (likely(rc == SQLITE_OK)) {
141
+ if (likely(key)) {
142
+ ret = pthread_setspecific(*key, *statement);
143
+#ifdef NETDATA_INTERNAL_CHECKS
144
+ info("Thread %d: Using key %u on statement %p", gettid(), keys_used, *statement);
145
+#endif
146
+ }
147
+ if (ret)
148
+ add_stmt_to_list(*statement);
149
+ }
150
return rc;
151
}
152
@@ -448,6 +481,10 @@ int sql_init_database(db_check_action_type_t rebuild, int memory)
481
482
fatal_assert(0 == uv_mutex_init(&sqlite_transaction_lock));
483
info("SQLite database initialization completed");
484
+
485
+ for (int i = 0; i < MAX_PREPARED_STATEMENTS; i++)
486
+ (void)pthread_key_create(&key_pool[i], release_statement);
487
+
488
return 0;
489
}
490