]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
Unify sqlite open and create function.
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Fri, 10 Jul 2015 13:13:39 +0000 (14:13 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Fri, 10 Jul 2015 13:13:39 +0000 (14:13 +0100)
src/libstat/backends/sqlite3_backend.c
src/libutil/sqlite_utils.c
src/libutil/sqlite_utils.h

index 94252ceb285040f5e9a543dc1610d1d0be51bbfd..4ded6198db2dfde5215ac77ea82a2ed64366df86 100644 (file)
@@ -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;
                                }
index ba91a874f45ce21944d6e8890a48631213522c0c..c07223c6ed91c8cc0d14d0571199c5458323d8fd 100644 (file)
@@ -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;
+}
index 5cb71f3ad4c1200c3218064dd23a70d68fbbad66..18dd20a6fab88bfa00fb414c2f78f0bd9267653b 100644 (file)
@@ -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_ */