]> 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 e6f4ee8f982456b191dc09e7e842bc936547df05..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
@@ -154,7 +154,12 @@ static int backend_write_inode(
 {
        int rc;
 
-       cfs_debug("enter backend_write_inode %016" PRIX64, 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));
@@ -180,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;
        }
@@ -321,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;
@@ -373,7 +376,7 @@ static gboolean bdb_backend_load_index(
                        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;
@@ -421,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 = %016" PRIX64 ", parent = %016" PRIX64 ", 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;
                        }
 
@@ -519,7 +529,7 @@ gboolean bdb_backend_commit_update(
 
                if (bdb_backend_delete_inode(bdb, slave_inode) != SQLITE_OK)
                        goto abort;
-              
+
                cfs_debug("deleted inode %016" PRIX64, slave_inode);
 
                j++;
@@ -669,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));
@@ -734,9 +748,7 @@ db_backend_t *bdb_backend_open(
        return bdb;
 
 fail:
-
        bdb_backend_close(bdb);
-               
+
        return NULL;
 }
-