aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2015-07-10 14:13:39 +0100
committerVsevolod Stakhov <vsevolod@highsecure.ru>2015-07-10 14:13:39 +0100
commit39ebf65fa5605de25cb54460119c88ce0402db85 (patch)
tree2ccc13dc78d53baaa2a29788ae0cb9eb94d152a1
parente1b9099abb7681ac0fcd9b586790bbefe61ab2f9 (diff)
downloadrspamd-39ebf65fa5605de25cb54460119c88ce0402db85.tar.gz
rspamd-39ebf65fa5605de25cb54460119c88ce0402db85.zip
Unify sqlite open and create function.
-rw-r--r--src/libstat/backends/sqlite3_backend.c142
-rw-r--r--src/libutil/sqlite_utils.c152
-rw-r--r--src/libutil/sqlite_utils.h9
3 files changed, 168 insertions, 135 deletions
diff --git a/src/libstat/backends/sqlite3_backend.c b/src/libstat/backends/sqlite3_backend.c
index 94252ceb2..4ded6198d 100644
--- a/src/libstat/backends/sqlite3_backend.c
+++ b/src/libstat/backends/sqlite3_backend.c
@@ -181,150 +181,28 @@ rspamd_sqlite3_backend_quark (void)
return g_quark_from_static_string ("sqlite3-stat-backend");
}
-static gboolean
-rspamd_sqlite3_wait (const gchar *lock)
-{
- gint fd;
- struct timespec sleep_ts = {
- .tv_sec = 0,
- .tv_nsec = 1000000
- };
-
- fd = open (lock, O_RDONLY);
-
- if (fd == -1) {
- msg_err ("cannot open lock file %s: %s", lock, strerror (errno));
-
- return FALSE;
- }
-
- while (!rspamd_file_lock (fd, TRUE)) {
- if (nanosleep (&sleep_ts, NULL) == -1 && errno != EINTR) {
- close (fd);
- msg_err ("cannot sleep open lock file %s: %s", lock, strerror (errno));
-
- return FALSE;
- }
- }
-
- rspamd_file_unlock (fd, FALSE);
-
- close (fd);
-
- return TRUE;
-}
-
static struct rspamd_stat_sqlite3_db *
rspamd_sqlite3_opendb (const gchar *path, const ucl_object_t *opts,
gboolean create, GError **err)
{
struct rspamd_stat_sqlite3_db *bk;
- sqlite3 *sqlite;
- sqlite3_stmt *stmt;
- gint rc, flags, lock_fd;
- gchar lock_path[PATH_MAX];
- static const char sqlite_wal[] = "PRAGMA journal_mode=\"wal\";",
- fallback_journal[] = "PRAGMA journal_mode=\"off\";",
- user_version[] = "PRAGMA user_version;";
-
- flags = SQLITE_OPEN_READWRITE;
-#ifdef SQLITE_OPEN_SHAREDCACHE
- flags |= SQLITE_OPEN_SHAREDCACHE;
-#endif
-#ifdef SQLITE_OPEN_WAL
- flags |= SQLITE_OPEN_WAL;
-#endif
-
- if (create) {
- flags |= SQLITE_OPEN_CREATE;
-
- rspamd_snprintf (lock_path, sizeof (lock_path), "%s.lock", path);
- lock_fd = open (lock_path, O_WRONLY|O_CREAT|O_EXCL, 00600);
-
- if (lock_fd == -1 && (errno == EEXIST || errno == EBUSY)) {
- if (!rspamd_sqlite3_wait (lock_path)) {
- g_set_error (err, rspamd_sqlite3_backend_quark (),
- errno, "cannot create sqlite file %s: %s",
- path, strerror (errno));
-
- return NULL;
- }
- /* At this point we have database created */
- create = FALSE;
- }
- else {
- g_assert (rspamd_file_lock (lock_fd, FALSE));
- }
- }
- else if (access (path, R_OK) == -1) {
- g_set_error (err, rspamd_sqlite3_backend_quark (),
- errno, "cannot open sqlite file %s: %s",
- path, strerror (errno));
- return NULL;
- }
+ bk = g_slice_alloc0 (sizeof (*bk));
+ bk->sqlite = rspamd_sqlite3_open_or_create (path, create_tables_sql, err);
- if ((rc = sqlite3_open_v2 (path, &sqlite,
- flags, NULL)) != SQLITE_OK) {
-#if SQLITE_VERSION_NUMBER >= 3008000
- g_set_error (err, rspamd_sqlite3_backend_quark (),
- rc, "cannot open sqlite db %s: %s",
- path, sqlite3_errstr (rc));
-#else
- g_set_error (err, rspamd_sqlite3_backend_quark (),
- rc, "cannot open sqlite db %s: %d",
- path, rc);
-#endif
+ if (bk->sqlite == NULL) {
+ g_slice_free1 (sizeof (*bk), bk);
return NULL;
}
- if (sqlite3_exec (sqlite, sqlite_wal, NULL, NULL, NULL) != SQLITE_OK) {
- msg_warn ("WAL mode is not supported, locking issues might occur");
- sqlite3_exec (sqlite, fallback_journal, NULL, NULL, NULL);
- }
-
- /* Check user_version */
- if (!create) {
- g_assert (sqlite3_prepare_v2 (sqlite, user_version, -1, &stmt, NULL)
- == SQLITE_OK);
- g_assert (sqlite3_step (stmt) == SQLITE_ROW);
-
- if (sqlite3_column_int (stmt, 0) != atoi (SQLITE3_SCHEMA_VERSION)) {
- msg_warn ("bad sqlite database: %s, try to recreate it", path);
- create = TRUE;
- }
-
- sqlite3_finalize (stmt);
- }
-
- if (create) {
- if (sqlite3_exec (sqlite, create_tables_sql, NULL, NULL, NULL) != SQLITE_OK) {
- g_set_error (err, rspamd_sqlite3_backend_quark (),
- -1, "cannot execute create sql `%s`: %s",
- create_tables_sql, sqlite3_errmsg (sqlite));
- sqlite3_close (sqlite);
- rspamd_file_unlock (lock_fd, FALSE);
- unlink (lock_path);
- close (lock_fd);
-
- return NULL;
- }
-
- rspamd_file_unlock (lock_fd, FALSE);
- unlink (lock_path);
- close (lock_fd);
- }
-
- bk = g_slice_alloc0 (sizeof (*bk));
- bk->sqlite = sqlite;
- bk->prstmt = rspamd_sqlite3_init_prstmt (sqlite, prepared_stmts,
+ bk->prstmt = rspamd_sqlite3_init_prstmt (bk->sqlite, prepared_stmts,
RSPAMD_STAT_BACKEND_MAX, err);
if (bk->prstmt == NULL) {
+ sqlite3_close (bk->sqlite);
g_slice_free1 (sizeof (*bk), bk);
- sqlite3_close (sqlite);
return NULL;
}
@@ -374,21 +252,15 @@ rspamd_sqlite3_init (struct rspamd_stat_ctx *ctx,
filename = ucl_object_tostring (filenameo);
- if ((bk = rspamd_sqlite3_opendb (filename, stf->opts, FALSE,
+ if ((bk = rspamd_sqlite3_opendb (filename, stf->opts, TRUE,
&err)) == NULL) {
msg_err ("cannot open sqlite3 db: %e", err);
- g_error_free (err);
- err = NULL;
-
- bk = rspamd_sqlite3_opendb (filename, stf->opts, TRUE,
- &err);
}
if (bk != NULL) {
g_hash_table_insert (new->files, stf, bk);
}
else {
- msg_err ("cannot create sqlite3 db: %e", err);
g_error_free (err);
err = NULL;
}
diff --git a/src/libutil/sqlite_utils.c b/src/libutil/sqlite_utils.c
index ba91a874f..c07223c6e 100644
--- a/src/libutil/sqlite_utils.c
+++ b/src/libutil/sqlite_utils.c
@@ -172,3 +172,155 @@ rspamd_sqlite3_close_prstmt (sqlite3 *db, GArray *stmts)
return;
}
+
+static gboolean
+rspamd_sqlite3_wait (const gchar *lock)
+{
+ gint fd;
+ struct timespec sleep_ts = {
+ .tv_sec = 0,
+ .tv_nsec = 1000000
+ };
+
+ fd = open (lock, O_RDONLY);
+
+ if (fd == -1) {
+ msg_err ("cannot open lock file %s: %s", lock, strerror (errno));
+
+ return FALSE;
+ }
+
+ while (!rspamd_file_lock (fd, TRUE)) {
+ if (nanosleep (&sleep_ts, NULL) == -1 && errno != EINTR) {
+ close (fd);
+ msg_err ("cannot sleep open lock file %s: %s", lock, strerror (errno));
+
+ return FALSE;
+ }
+ }
+
+ rspamd_file_unlock (fd, FALSE);
+
+ close (fd);
+
+ return TRUE;
+}
+
+
+
+sqlite3 *
+rspamd_sqlite3_open_or_create (const gchar *path, const
+ gchar *create_sql, GError **err)
+{
+ sqlite3 *sqlite;
+ sqlite3_stmt *stmt;
+ gint rc, flags, lock_fd;
+ gchar lock_path[PATH_MAX], dbdir[PATH_MAX], *pdir;
+ static const char sqlite_wal[] = "PRAGMA journal_mode=\"wal\";",
+ exclusive_lock_sql[] = "PRAGMA locking_mode=\"exclusive\";";
+ gboolean create = FALSE;
+
+ flags = SQLITE_OPEN_READWRITE;
+#ifdef SQLITE_OPEN_SHAREDCACHE
+ flags |= SQLITE_OPEN_SHAREDCACHE;
+#endif
+#ifdef SQLITE_OPEN_WAL
+ flags |= SQLITE_OPEN_WAL;
+#endif
+
+ rspamd_strlcpy (dbdir, path, sizeof (dbdir));
+ pdir = dirname (dbdir);
+
+ if (access (pdir, W_OK) == -1) {
+ g_set_error (err, rspamd_sqlite3_quark (),
+ errno, "cannot open sqlite directory %s: %s",
+ pdir, strerror (errno));
+
+ return NULL;
+ }
+
+ if (access (path, R_OK) == -1) {
+ flags |= SQLITE_OPEN_CREATE;
+
+ rspamd_snprintf (lock_path, sizeof (lock_path), "%s.lock", path);
+ lock_fd = open (lock_path, O_WRONLY|O_CREAT|O_EXCL, 00600);
+
+ if (lock_fd == -1 && (errno == EEXIST || errno == EBUSY)) {
+ if (!rspamd_sqlite3_wait (lock_path)) {
+ g_set_error (err, rspamd_sqlite3_quark (),
+ errno, "cannot create sqlite file %s: %s",
+ path, strerror (errno));
+
+ return NULL;
+ }
+
+ /* At this point we have database created */
+ create = FALSE;
+ }
+ else {
+ g_assert (rspamd_file_lock (lock_fd, FALSE));
+ create = TRUE;
+ }
+ }
+
+ if ((rc = sqlite3_open_v2 (path, &sqlite,
+ flags, NULL)) != SQLITE_OK) {
+#if SQLITE_VERSION_NUMBER >= 3008000
+ g_set_error (err, rspamd_sqlite3_quark (),
+ rc, "cannot open sqlite db %s: %s",
+ path, sqlite3_errstr (rc));
+#else
+ g_set_error (err, rspamd_sqlite3_quark (),
+ rc, "cannot open sqlite db %s: %d",
+ path, rc);
+#endif
+
+ return NULL;
+ }
+
+ if (create) {
+ if (sqlite3_exec (sqlite, exclusive_lock_sql, NULL, NULL, NULL) != SQLITE_OK) {
+ msg_warn ("cannot exclusively lock database to create schema");
+ }
+
+ if (sqlite3_exec (sqlite, create_sql, NULL, NULL, NULL) != SQLITE_OK) {
+ g_set_error (err, rspamd_sqlite3_quark (),
+ -1, "cannot execute create sql `%s`: %s",
+ create_sql, sqlite3_errmsg (sqlite));
+ sqlite3_close (sqlite);
+ rspamd_file_unlock (lock_fd, FALSE);
+ unlink (lock_path);
+ close (lock_fd);
+
+ return NULL;
+ }
+
+ sqlite3_close (sqlite);
+ rspamd_file_unlock (lock_fd, FALSE);
+ unlink (lock_path);
+ close (lock_fd);
+
+ /* Reopen in normal mode */
+ flags &= ~SQLITE_OPEN_CREATE;
+ if ((rc = sqlite3_open_v2 (path, &sqlite,
+ flags, NULL)) != SQLITE_OK) {
+ #if SQLITE_VERSION_NUMBER >= 3008000
+ g_set_error (err, rspamd_sqlite3_quark (),
+ rc, "cannot open sqlite db after creation %s: %s",
+ path, sqlite3_errstr (rc));
+ #else
+ g_set_error (err, rspamd_sqlite3_quark (),
+ rc, "cannot open sqlite db after creation %s: %d",
+ path, rc);
+ #endif
+
+ return NULL;
+ }
+ }
+
+ if (sqlite3_exec (sqlite, sqlite_wal, NULL, NULL, NULL) != SQLITE_OK) {
+ msg_warn ("WAL mode is not supported, locking issues might occur");
+ }
+
+ return sqlite;
+}
diff --git a/src/libutil/sqlite_utils.h b/src/libutil/sqlite_utils.h
index 5cb71f3ad..18dd20a6f 100644
--- a/src/libutil/sqlite_utils.h
+++ b/src/libutil/sqlite_utils.h
@@ -68,4 +68,13 @@ gint rspamd_sqlite3_run_prstmt (sqlite3 *db, GArray *stmts,
*/
void rspamd_sqlite3_close_prstmt (sqlite3 *db, GArray *stmts);
+/**
+ * Creates or opens sqlite database trying to share it between processes
+ * @param path
+ * @param create_sql
+ * @return
+ */
+sqlite3 * rspamd_sqlite3_open_or_create (const gchar *path, const
+ gchar *create_sql, GError **err);
+
#endif /* SRC_LIBUTIL_SQLITE_UTILS_H_ */