1 /*
2  * Copyright (C) Tildeslash Ltd. All rights reserved.
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 3.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
14  *
15  * In addition, as a special exception, the copyright holders give
16  * permission to link the code of portions of this program with the
17  * OpenSSL library under certain conditions as described in each
18  * individual source file, and distribute linked combinations
19  * including the two.
20  *
21  * You must obey the GNU General Public License in all respects
22  * for all of the code used other than OpenSSL.
23  */
24 
25 #include "Config.h"
26 
27 #include <stdlib.h>
28 
29 #include "Thread.h"
30 #include "system/Time.h"
31 #include "SQLiteAdapter.h"
32 
33 
34 #if defined SQLITEUNLOCK && SQLITE_VERSION_NUMBER >= 3006012
35 
36 /*
37  * SQLite unlock notify API
38  * @see https://www.sqlite.org/unlock_notify.html
39  */
40 
41 typedef struct UnlockNotification {
42         int fired;
43         Sem_T cond;
44         Mutex_T mutex;
45 } UnlockNotification_T;
46 
47 
unlock_notify_cb(void ** apArg,int nArg)48 static inline void unlock_notify_cb(void **apArg, int nArg) {
49         for (int i = 0; i < nArg; i++) {
50                 UnlockNotification_T *p = (UnlockNotification_T *)apArg[i];
51                 Mutex_lock(p->mutex);
52                 p->fired = 1;
53                 Sem_signal(p->cond);
54                 Mutex_unlock(p->mutex);
55         }
56 }
57 
58 
wait_for_unlock_notify(sqlite3 * db)59 static inline int wait_for_unlock_notify(sqlite3 *db){
60         UnlockNotification_T un;
61         un.fired = 0;
62         Mutex_init(un.mutex);
63         Sem_init(un.cond);
64         int rc = sqlite3_unlock_notify(db, unlock_notify_cb, (void *)&un);
65         assert(rc == SQLITE_LOCKED || rc == SQLITE_OK);
66         if (rc == SQLITE_OK) {
67                 Mutex_lock(un.mutex);
68                 if (! un.fired)
69                         Sem_wait(un.cond, un.mutex);
70                 Mutex_unlock(un.mutex);
71         }
72         Sem_destroy(un.cond);
73         Mutex_destroy(un.mutex);
74         return rc;
75 }
76 
77 
sqlite3_blocking_exec(sqlite3 * db,const char * zSql,int (* callback)(void *,int,char **,char **),void * arg,char ** errmsg)78 static inline int sqlite3_blocking_exec(sqlite3 *db, const char *zSql, int (*callback)(void *, int, char **, char **), void *arg, char **errmsg) {
79         int rc;
80         while (SQLITE_LOCKED == (rc = sqlite3_exec(db, zSql, callback, arg, errmsg))) {
81                 rc = wait_for_unlock_notify(db);
82                 if (rc != SQLITE_OK)
83                         break;
84         }
85         return rc;
86 }
87 
88 
89 // MARK: - Blocking API
90 
zdb_sqlite3_step(sqlite3_stmt * pStmt)91 int zdb_sqlite3_step(sqlite3_stmt *pStmt) {
92         int rc;
93         while (SQLITE_LOCKED == (rc = sqlite3_step(pStmt))) {
94                 rc = wait_for_unlock_notify(sqlite3_db_handle(pStmt));
95                 if (rc != SQLITE_OK)
96                         break;
97 #if SQLITE_VERSION_NUMBER < 3070000 || defined SQLITE_OMIT_AUTORESET
98                 sqlite3_reset(pStmt);
99 #endif
100         }
101         return rc;
102 }
103 
104 
zdb_sqlite3_prepare_v2(sqlite3 * db,const char * zSql,int nSql,sqlite3_stmt ** ppStmt,const char ** pz)105 int zdb_sqlite3_prepare_v2(sqlite3 *db, const char *zSql, int nSql, sqlite3_stmt **ppStmt, const char **pz) {
106         int rc;
107         while (SQLITE_LOCKED == (rc = sqlite3_prepare_v2(db, zSql, nSql, ppStmt, pz))) {
108                 rc = wait_for_unlock_notify(db);
109                 if (rc != SQLITE_OK)
110                         break;
111         }
112         return rc;
113 }
114 
115 
zdb_sqlite3_exec(sqlite3 * db,const char * sql)116 int zdb_sqlite3_exec(sqlite3 *db, const char *sql) {
117         return sqlite3_blocking_exec(db, sql, NULL, NULL, NULL);
118 }
119 
120 
121 #else // NOT SQLITEUNLOCK
122 
123 // Exponential backoff https://en.wikipedia.org/wiki/Exponential_backoff
124 // Expected mean backoff time: (2^10 - 1)/2 × slot = 2.6 seconds
_backoff(int step)125 static inline void _backoff(int step) {
126         static int slot = 51 * 100; // µs
127         switch (step) {
128                 case 0:
129                         Time_usleep(slot * (random() % 2));
130                         break;
131                 case 1:
132                         Time_usleep(slot * (random() % 4));
133                         break;
134                 default:
135                         // slot µs * R[0...2^step - 1]
136                         Time_usleep(slot * (random() % (1 << step)));
137                         break;
138         }
139 }
140 
141 // MARK: - Backoff API
142 
143 #define _exec_or_backoff(S) do { \
144         for (int i = 0, steps = 10; i < steps; i++) { \
145         int status = S; \
146         if ((status != SQLITE_BUSY) && (status != SQLITE_LOCKED)) return status; \
147         _backoff(i); } return S; } while(0)
148 
149 
zdb_sqlite3_step(sqlite3_stmt * pStmt)150 int zdb_sqlite3_step(sqlite3_stmt *pStmt) {
151         _exec_or_backoff(sqlite3_step(pStmt));
152 }
153 
154 
zdb_sqlite3_prepare_v2(sqlite3 * db,const char * zSql,int nSql,sqlite3_stmt ** ppStmt,const char ** pz)155 int zdb_sqlite3_prepare_v2(sqlite3 *db, const char *zSql, int nSql, sqlite3_stmt **ppStmt, const char **pz) {
156         _exec_or_backoff(sqlite3_prepare_v2(db, zSql, nSql, ppStmt, pz));
157 }
158 
159 
zdb_sqlite3_exec(sqlite3 * db,const char * sql)160 int zdb_sqlite3_exec(sqlite3 *db, const char *sql) {
161         _exec_or_backoff(sqlite3_exec(db, sql, NULL, NULL, NULL));
162 }
163 
164 
165 #endif
166