]> git.proxmox.com Git - pve-cluster.git/blobdiff - data/src/database.c
pmxcfs: db: tell query planner that prepared statement are long living
[pve-cluster.git] / data / src / database.c
index cff15cfdf74632fc9a92cdda9a0ba05a3b690828..80e0b60bbf6c1cc1a338f2bf2082a307a5126141 100644 (file)
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2010 Proxmox Server Solutions GmbH
+  Copyright (C) 2010 - 2020 Proxmox Server Solutions GmbH
 
   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published by
@@ -25,6 +25,7 @@
 #endif /* HAVE_CONFIG_H */
 
 #include <stdlib.h>
+#include <inttypes.h>
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
@@ -153,7 +154,12 @@ static int backend_write_inode(
 {
        int rc;
 
-       cfs_debug("enter backend_write_inode %016zX", inode);
+       cfs_debug(
+           "enter backend_write_inode %016" PRIX64 " '%s', size %"PRIu32"",
+           inode,
+           name,
+           size
+       );
 
        if ((rc = sqlite3_bind_int64(stmt, 1, inode)) !=  SQLITE_OK) {
                cfs_critical("sqlite3_bind failed: %s\n", sqlite3_errmsg(db));
@@ -179,12 +185,11 @@ static int backend_write_inode(
                cfs_critical("sqlite3_bind failed: %s\n", sqlite3_errmsg(db));
                return rc;
        }
-       /* question: can we use SQLITE_STATIC instead? */
-       if ((rc = sqlite3_bind_text(stmt, 7, name, -1, SQLITE_TRANSIENT)) !=  SQLITE_OK) {
+       if ((rc = sqlite3_bind_text(stmt, 7, name, -1, SQLITE_STATIC)) !=  SQLITE_OK) {
                cfs_critical("sqlite3_bind failed: %s\n", sqlite3_errmsg(db));
                return rc;
        }
-       if ((rc = sqlite3_bind_blob(stmt, 8, value, size, SQLITE_TRANSIENT)) !=  SQLITE_OK) {
+       if ((rc = sqlite3_bind_blob(stmt, 8, value, size, SQLITE_STATIC)) !=  SQLITE_OK) {
                cfs_critical("sqlite3_bind failed: %s\n", sqlite3_errmsg(db));
                return rc;
        }
@@ -271,7 +276,7 @@ int bdb_backend_write(
                        goto rollback;
 
                if (sqlite3_changes(bdb->db) != 1) {
-                       cfs_critical("no such inode %016zX", inode);
+                       cfs_critical("no such inode %016" PRIX64, inode);
                        goto rollback;
                }
        }
@@ -320,10 +325,9 @@ static gboolean bdb_backend_load_index(
        g_return_val_if_fail(root->version == 0, FALSE);
        g_return_val_if_fail(g_hash_table_size(index) == 1, FALSE);
 
-       int rc;
-
        sqlite3_stmt *stmt = bdb->stmt_load_all;
 
+       int rc;
        while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
 
                memdb_tree_entry_t *te;
@@ -332,7 +336,7 @@ static gboolean bdb_backend_load_index(
                const char *name = (const char *)sqlite3_column_text(stmt, 6);
                int namelen = sqlite3_column_bytes(stmt, 6);
                if (name == NULL || namelen == 0) {
-                       cfs_critical("inode has no name (inode = %016zX)", inode);
+                       cfs_critical("inode has no name (inode = %016" PRIX64 ")", inode);
                        goto fail;
                } 
                te = g_malloc0(sizeof(memdb_tree_entry_t) + namelen + 1);
@@ -355,24 +359,24 @@ static gboolean bdb_backend_load_index(
                                te->data.value = g_memdup(value, size);
                } else if (te->type == DT_DIR) {
                        if (size) {
-                               cfs_critical("directory inode contains data (inode = %016zX)",
+                               cfs_critical("directory inode contains data (inode = %016" PRIX64 ")",
                                           te->inode);
                                g_free(te);
                                goto fail;
                        }
                        te->data.entries = NULL;
                } else {
-                       cfs_critical("inode has unknown type (inode = %016zX, type = %d)",
+                       cfs_critical("inode has unknown type (inode = %016" PRIX64 ", type = %d)",
                                   te->inode, te->type);
                        g_free(te);
                        goto fail;
                }
 
-               cfs_debug("name %s (inode = %016zX, parent = %016zX)", 
+               cfs_debug("name %s (inode = %016" PRIX64 ", parent = %016" PRIX64 ")",
                        te->name, te->inode, te->parent);
 
                if (te->inode == 0) {
-                       if (te->name && !strcmp(te->name, VERSIONFILENAME)) {
+                       if (!strcmp(te->name, VERSIONFILENAME)) {
                                root->version = te->version;
                                root->writer = te->writer;
                                root->mtime = te->mtime;
@@ -396,7 +400,7 @@ static gboolean bdb_backend_load_index(
 
                        } else if (!(pte->type == DT_DIR || pte->type == 0)) {
                                cfs_critical("parent is not a directory "
-                                            "(inode = %016zX, parent = %016zX, name = '%s')", 
+                                            "(inode = %016" PRIX64 ", parent = %016" PRIX64 ", name = '%s')",
                                             te->inode, te->parent, te->name);
                                memdb_tree_entry_free(te);
                                goto fail;
@@ -408,7 +412,7 @@ static gboolean bdb_backend_load_index(
                                if ((tmpte = g_hash_table_lookup(index, &te->inode))) {
                                        if (tmpte->type != 0) {
                                                cfs_critical("found strange placeholder for "
-                                                            "(inode = %016zX, parent = %016zX, name = '%s', type = '%d')", 
+                                                            "(inode = %016" PRIX64 ", parent = %016" PRIX64 ", name = '%s', type = '%d')",
                                                             te->inode, te->parent, te->name, tmpte->type);
                                                memdb_tree_entry_free(te);
                                                goto fail;
@@ -420,11 +424,18 @@ static gboolean bdb_backend_load_index(
                                        te->data.entries = g_hash_table_new(g_str_hash, g_str_equal);
                                }
                        }
-                               
-                       if (g_hash_table_lookup(pte->data.entries, te->name)) {
-                               cfs_critical("found entry with duplicate name "
-                                            "(inode = %016zX, parent = %016zX, name = '%s')", 
-                                            te->inode, te->parent, te->name);
+
+                       memdb_tree_entry_t *existing;
+                       if ((existing = g_hash_table_lookup(pte->data.entries, te->name))) {
+                               cfs_critical(
+                                   "found entry with duplicate name '%s' - "
+                                   "A:(inode = 0x%016"PRIX64", parent = 0x%016"PRIX64", v./mtime = 0x%"PRIX64"/0x%"PRIi32")"
+                                   " vs. "
+                                   "B:(inode = 0x%016"PRIX64", parent = 0x%016"PRIX64", v./mtime = 0x%"PRIX64"/0x%"PRIi32")",
+                                    te->name,
+                                    existing->inode, existing->parent, existing->version, existing->mtime,
+                                    te->inode, te->parent, te->version, te->mtime
+                               );
                                goto fail;
                        }
 
@@ -444,7 +455,7 @@ static gboolean bdb_backend_load_index(
        while (g_hash_table_iter_next (&iter, &key, &value)) {
                memdb_tree_entry_t *te = (memdb_tree_entry_t *)value;
                if (te->type == 0) {
-                       cfs_critical("missing directory inode (inode = %016zX)", te->inode);
+                       cfs_critical("missing directory inode (inode = %016" PRIX64 ")", te->inode);
                        goto fail;
                }
        }
@@ -489,7 +500,7 @@ gboolean bdb_backend_commit_update(
                return rc;
        }
 
-       g_mutex_lock (memdb->mutex);
+       g_mutex_lock (&memdb->mutex);
 
        /* first, delete anything not found in master index) */
 
@@ -505,7 +516,7 @@ gboolean bdb_backend_commit_update(
                                if (bdb_backend_delete_inode(bdb, slave_inode) != SQLITE_OK)
                                        goto abort;
 
-                               cfs_debug("deleted inode %016zX", slave_inode);
+                               cfs_debug("deleted inode %016" PRIX64, slave_inode);
                        }
                        j++;
                }
@@ -518,8 +529,8 @@ gboolean bdb_backend_commit_update(
 
                if (bdb_backend_delete_inode(bdb, slave_inode) != SQLITE_OK)
                        goto abort;
-              
-               cfs_debug("deleted inode %016zX", slave_inode);
+
+               cfs_debug("deleted inode %016" PRIX64, slave_inode);
 
                j++;
        }
@@ -603,7 +614,7 @@ gboolean bdb_backend_commit_update(
        result = TRUE;
 
 ret:
-       g_mutex_unlock (memdb->mutex);
+       g_mutex_unlock (&memdb->mutex);
 
        if (index)
                g_hash_table_destroy(index);
@@ -668,49 +679,53 @@ db_backend_t *bdb_backend_open(
        if (!(bdb->db = bdb_create(filename)))
                goto fail;
 
-       rc = sqlite3_prepare_v2(bdb->db, sql_insert_entry, -1, &bdb->stmt_insert_entry, NULL);
+       // tell the query planner that the prepared statement will be retained for a long time and
+       // probably reused many times
+       const unsigned int flags = SQLITE_PREPARE_PERSISTENT;
+
+       rc = sqlite3_prepare_v3(bdb->db, sql_insert_entry, -1, flags, &bdb->stmt_insert_entry, NULL);
        if (rc != SQLITE_OK) {
                cfs_critical("sqlite3_prepare 'sql_insert_entry' failed: %s\n", 
                             sqlite3_errmsg(bdb->db));
                goto fail;
        }
-       rc = sqlite3_prepare_v2(bdb->db, sql_update_entry, -1, &bdb->stmt_update_entry, NULL);
+       rc = sqlite3_prepare_v3(bdb->db, sql_update_entry, -1, flags, &bdb->stmt_update_entry, NULL);
        if (rc != SQLITE_OK) {
                cfs_critical("sqlite3_prepare 'sql_update_entry' failed: %s\n", 
                             sqlite3_errmsg(bdb->db));
                goto fail;
        }
-       rc = sqlite3_prepare_v2(bdb->db, sql_replace_entry, -1, &bdb->stmt_replace_entry, NULL);
+       rc = sqlite3_prepare_v3(bdb->db, sql_replace_entry, -1, flags, &bdb->stmt_replace_entry, NULL);
        if (rc != SQLITE_OK) {
                cfs_critical("sqlite3_prepare 'sql_replace_entry' failed: %s\n", 
                             sqlite3_errmsg(bdb->db));
                goto fail;
        }
-       rc = sqlite3_prepare_v2(bdb->db, sql_delete_entry, -1, &bdb->stmt_delete_entry, NULL);
+       rc = sqlite3_prepare_v3(bdb->db, sql_delete_entry, -1, flags, &bdb->stmt_delete_entry, NULL);
        if (rc != SQLITE_OK) {
                cfs_critical("sqlite3_prepare 'sql_delete_entry' failed: %s\n", 
                             sqlite3_errmsg(bdb->db));
                goto fail;
        }
-       rc = sqlite3_prepare_v2(bdb->db, sql_begin, -1, &bdb->stmt_begin, NULL);
+       rc = sqlite3_prepare_v3(bdb->db, sql_begin, -1, flags, &bdb->stmt_begin, NULL);
        if (rc != SQLITE_OK) {
                cfs_critical("sqlite3_prepare 'sql_begin' failed: %s\n", 
                             sqlite3_errmsg(bdb->db));
                goto fail;
        }
-       rc = sqlite3_prepare_v2(bdb->db, sql_commit, -1, &bdb->stmt_commit, NULL);
+       rc = sqlite3_prepare_v3(bdb->db, sql_commit, -1, flags, &bdb->stmt_commit, NULL);
        if (rc != SQLITE_OK) {
                cfs_critical("sqlite3_prepare 'sql_commit' failed: %s\n", 
                             sqlite3_errmsg(bdb->db));
                goto fail;
        }
-       rc = sqlite3_prepare_v2(bdb->db, sql_rollback, -1, &bdb->stmt_rollback, NULL);
+       rc = sqlite3_prepare_v3(bdb->db, sql_rollback, -1, flags, &bdb->stmt_rollback, NULL);
        if (rc != SQLITE_OK) {
                cfs_critical("sqlite3_prepare 'sql_rollback' failed: %s\n", 
                             sqlite3_errmsg(bdb->db));
                goto fail;
        }
-       rc = sqlite3_prepare_v2(bdb->db, sql_load_all, -1, &bdb->stmt_load_all, NULL);
+       rc = sqlite3_prepare_v3(bdb->db, sql_load_all, -1, flags, &bdb->stmt_load_all, NULL);
        if (rc != SQLITE_OK) {
                cfs_critical("sqlite3_prepare 'sql_load_all' failed: %s\n", 
                             sqlite3_errmsg(bdb->db));
@@ -733,9 +748,7 @@ db_backend_t *bdb_backend_open(
        return bdb;
 
 fail:
-
        bdb_backend_close(bdb);
-               
+
        return NULL;
 }
-