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