]> git.proxmox.com Git - pve-cluster.git/blame - data/src/database.c
buildsys: add sbuild convenience target
[pve-cluster.git] / data / src / database.c
CommitLineData
fe000966 1/*
84c98315 2 Copyright (C) 2010 - 2020 Proxmox Server Solutions GmbH
fe000966
DM
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Affero General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Affero General Public License for more details.
13
14 You should have received a copy of the GNU Affero General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17 Author: Dietmar Maurer <dietmar@proxmox.com>
18
19*/
20
21#define G_LOG_DOMAIN "database"
22
23#ifdef HAVE_CONFIG_H
24#include <config.h>
25#endif /* HAVE_CONFIG_H */
26
27#include <stdlib.h>
e5a5a3ea 28#include <inttypes.h>
fe000966
DM
29#include <stdio.h>
30#include <string.h>
31#include <unistd.h>
32#include <glib.h>
33#include <dirent.h>
34#include <sys/stat.h>
35#include <errno.h>
36
37#include <sqlite3.h>
38
39#include "cfs-utils.h"
40#include "status.h"
41#include "memdb.h"
42
43struct db_backend {
44 sqlite3 *db;
45 sqlite3_stmt *stmt_insert_entry;
46 sqlite3_stmt *stmt_update_entry;
47 sqlite3_stmt *stmt_replace_entry;
48 sqlite3_stmt *stmt_delete_entry;
49 sqlite3_stmt *stmt_begin;
50 sqlite3_stmt *stmt_commit;
48009cd2
TL
51 sqlite3_stmt *stmt_rollback;
52 sqlite3_stmt *stmt_load_all;
fe000966
DM
53};
54
55#define VERSIONFILENAME "__version__"
56
57/* colume type "INTEGER PRIMARY KEY" is a special case, because sqlite
48009cd2 58 * uses the internal ROWID. So only real interger are allowed, and
fe000966
DM
59 * there is no need to add an additionl check
60 */
48009cd2 61static const char *sql_create_db =
fe000966 62 "CREATE TABLE IF NOT EXISTS tree ("
48009cd2 63 " inode INTEGER PRIMARY KEY NOT NULL,"
fe000966
DM
64 " parent INTEGER NOT NULL CHECK(typeof(parent)=='integer'),"
65 " version INTEGER NOT NULL CHECK(typeof(version)=='integer'),"
66 " writer INTEGER NOT NULL CHECK(typeof(writer)=='integer'),"
67 " mtime INTEGER NOT NULL CHECK(typeof(mtime)=='integer'),"
68 " type INTEGER NOT NULL CHECK(typeof(type)=='integer'),"
69 " name TEXT NOT NULL,"
70 " data BLOB);";
71
72static const char *sql_load_all =
73 "SELECT inode, parent, version, writer, mtime, type, name, data FROM tree;";
74
75static char *sql_insert_entry =
76 "INSERT INTO tree ("
77 "inode, parent, version, writer, mtime, type, name, data) "
78 "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8);";
79
80static char *sql_update_entry =
81 "UPDATE tree SET parent = ?2, version = ?3, writer = ?4, mtime = ?5, "
82 "type = ?6, name = ?7, data = ?8 WHERE inode = ?1;";
83
84static char *sql_replace_entry =
85 "REPLACE INTO tree (inode, parent, version, writer, mtime, type, "
86 "name, data) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8);";
87
88static char *sql_delete_entry =
89 "DELETE FROM tree WHERE inode = ?1;";
90
91static char *sql_begin = "BEGIN TRANSACTION;";
92static char *sql_commit = "COMMIT TRANSACTION;";
93static char *sql_rollback = "ROLLBACK TRANSACTION;";
94
95static sqlite3 *bdb_create(
96 const char *filename)
97{
98 int rc;
99 sqlite3 *db = NULL;
100
101 int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
102 rc = sqlite3_open_v2(filename, &db, flags, NULL);
103 if (rc != SQLITE_OK) {
104 cfs_critical("splite3_open_v2 failed: %d\n", rc);
105 sqlite3_close(db);
106 return NULL;
107 }
108
109 if (chmod(filename, 0600) == -1) {
110 cfs_critical("chmod failed: %s", strerror(errno));
48009cd2 111 return NULL;
fe000966
DM
112 }
113
114 /* use WAL mode - to allow concurrent reads */
115 rc = sqlite3_exec(db, "PRAGMA journal_mode=WAL;", NULL, NULL, NULL);
116 if (rc != SQLITE_OK) {
117 cfs_critical("unable to set WAL mode: %s\n", sqlite3_errmsg(db));
118 sqlite3_close(db);
119 return NULL;
120 }
121
122 /* NORMAL is good enough when using WAL */
123 rc = sqlite3_exec(db, "PRAGMA synchronous=NORMAL", NULL, NULL, NULL);
124 if (rc != SQLITE_OK) {
125 cfs_critical("unable to set synchronous mode: %s\n", sqlite3_errmsg(db));
126 sqlite3_close(db);
127 return NULL;
128 }
129
130 sqlite3_busy_timeout(db, 10000); /* 10 seconds */
131
132 rc = sqlite3_exec(db, sql_create_db, NULL, NULL, NULL);
133 if (rc != SQLITE_OK) {
134 cfs_critical("init database failed: %s\n", sqlite3_errmsg(db));
135 sqlite3_close(db);
136 return NULL;
137 }
138
139 return db;
140}
141
142static int backend_write_inode(
143 sqlite3 *db,
144 sqlite3_stmt *stmt,
48009cd2
TL
145 guint64 inode,
146 guint64 parent,
147 guint64 version,
fe000966
DM
148 guint32 writer,
149 guint32 mtime,
48009cd2
TL
150 guint32 size,
151 char type,
fe000966
DM
152 char *name,
153 gpointer value)
154{
155 int rc;
156
48009cd2 157 cfs_debug("enter backend_write_inode %016" PRIX64 " '%s', size %"PRIu32"", inode, name, size);
fe000966
DM
158
159 if ((rc = sqlite3_bind_int64(stmt, 1, inode)) != SQLITE_OK) {
160 cfs_critical("sqlite3_bind failed: %s\n", sqlite3_errmsg(db));
161 return rc;
162 }
163 if ((rc = sqlite3_bind_int64(stmt, 2, parent)) != SQLITE_OK) {
164 cfs_critical("sqlite3_bind failed: %s\n", sqlite3_errmsg(db));
165 return rc;
166 }
167 if ((rc = sqlite3_bind_int64(stmt, 3, version)) != SQLITE_OK) {
168 cfs_critical("sqlite3_bind failed: %s\n", sqlite3_errmsg(db));
169 return rc;
170 }
171 if ((rc = sqlite3_bind_int64(stmt, 4, writer)) != SQLITE_OK) {
172 cfs_critical("sqlite3_bind failed: %s\n", sqlite3_errmsg(db));
173 return rc;
174 }
175 if ((rc = sqlite3_bind_int64(stmt, 5, mtime)) != SQLITE_OK) {
176 cfs_critical("sqlite3_bind failed: %s\n", sqlite3_errmsg(db));
177 return rc;
178 }
179 if ((rc = sqlite3_bind_int64(stmt, 6, type)) != SQLITE_OK) {
180 cfs_critical("sqlite3_bind failed: %s\n", sqlite3_errmsg(db));
181 return rc;
182 }
c44bb3d6 183 if ((rc = sqlite3_bind_text(stmt, 7, name, -1, SQLITE_STATIC)) != SQLITE_OK) {
fe000966
DM
184 cfs_critical("sqlite3_bind failed: %s\n", sqlite3_errmsg(db));
185 return rc;
186 }
c44bb3d6 187 if ((rc = sqlite3_bind_blob(stmt, 8, value, size, SQLITE_STATIC)) != SQLITE_OK) {
fe000966
DM
188 cfs_critical("sqlite3_bind failed: %s\n", sqlite3_errmsg(db));
189 return rc;
190 }
191
192 if ((rc = sqlite3_step(stmt)) != SQLITE_DONE) {
193 cfs_critical("sqlite3_step failed: %s\n", sqlite3_errmsg(db));
194 sqlite3_reset(stmt);
195 return rc;
196 }
197
198 sqlite3_reset(stmt);
199
200 return SQLITE_OK;
201}
202
203static int bdb_backend_delete_inode(
204 db_backend_t *bdb,
205 guint64 inode)
206{
207 int rc;
208
209 cfs_debug("enter dbd_backend_delete_inode");
210
211 sqlite3_stmt *stmt = bdb->stmt_delete_entry;
212
213 if ((rc = sqlite3_bind_int64(stmt, 1, inode)) != SQLITE_OK) {
214 cfs_critical("delete_inode/sqlite3_bind failed: %s\n", sqlite3_errmsg(bdb->db));
215 return rc;
216 }
217
218 if ((rc = sqlite3_step(stmt)) != SQLITE_DONE) {
219 cfs_critical("delete_inode failed: %s\n", sqlite3_errmsg(bdb->db));
220 sqlite3_reset(stmt);
221 return rc;
222 }
223
224 sqlite3_reset(stmt);
225
226 return SQLITE_OK;
227}
228
229int bdb_backend_write(
230 db_backend_t *bdb,
48009cd2
TL
231 guint64 inode,
232 guint64 parent,
233 guint64 version,
fe000966
DM
234 guint32 writer,
235 guint32 mtime,
48009cd2
TL
236 guint32 size,
237 char type,
fe000966
DM
238 char *name,
239 gpointer value,
240 guint64 delete_inode)
241{
48009cd2
TL
242 g_return_val_if_fail(bdb != NULL, SQLITE_PERM);
243 g_return_val_if_fail(inode == 0 || (name != NULL && name[0]), SQLITE_PERM);
fe000966
DM
244 g_return_val_if_fail(type == DT_REG || type == DT_DIR, SQLITE_PERM);
245 int rc;
246
247 gboolean need_txn = (inode != 0 || delete_inode != 0);
248
249 if (need_txn) {
250 rc = sqlite3_step(bdb->stmt_begin);
251 sqlite3_reset(bdb->stmt_begin);
252 if (rc != SQLITE_DONE) {
253 cfs_critical("begin transaction failed: %s\n", sqlite3_errmsg(bdb->db));
254 return rc;
255 }
256 }
257
258 if (delete_inode != 0) {
259 if ((rc = bdb_backend_delete_inode(bdb, delete_inode)) != SQLITE_OK)
260 goto rollback;
261 }
262
263 if (inode != 0) {
264
48009cd2 265 sqlite3_stmt *stmt = (inode > version) ?
fe000966
DM
266 bdb->stmt_insert_entry : bdb->stmt_replace_entry;
267
48009cd2
TL
268 rc = backend_write_inode(bdb->db, stmt, inode, parent, version,
269 writer, mtime, size, type, name, value);
fe000966
DM
270 if (rc != SQLITE_OK)
271 goto rollback;
272
273 if (sqlite3_changes(bdb->db) != 1) {
e5a5a3ea 274 cfs_critical("no such inode %016" PRIX64, inode);
fe000966
DM
275 goto rollback;
276 }
277 }
278
48009cd2
TL
279 rc = backend_write_inode(bdb->db, bdb->stmt_replace_entry, 0, 0, version,
280 writer, mtime, 0, DT_REG, VERSIONFILENAME, NULL);
fe000966
DM
281
282 if (rc != SQLITE_OK)
283 goto rollback;
284
48009cd2 285
fe000966
DM
286 if (need_txn) {
287 rc = sqlite3_step(bdb->stmt_commit);
288 sqlite3_reset(bdb->stmt_commit);
289 if (rc != SQLITE_DONE) {
290 cfs_critical("commit transaction failed: %s\n", sqlite3_errmsg(bdb->db));
48009cd2 291 goto rollback;
fe000966
DM
292 }
293 }
294
295 return SQLITE_OK;
296
297rollback:
48009cd2 298
fe000966
DM
299 if (!need_txn)
300 return rc;
301
302 int rbrc = sqlite3_step(bdb->stmt_rollback);
303 sqlite3_reset(bdb->stmt_rollback);
304 if (rbrc != SQLITE_DONE) {
305 cfs_critical("rollback transaction failed: %s\n", sqlite3_errmsg(bdb->db));
306 return rc;
307 }
48009cd2 308
fe000966
DM
309 return rc;
310}
311
312static gboolean bdb_backend_load_index(
48009cd2 313 db_backend_t *bdb,
fe000966
DM
314 memdb_tree_entry_t *root,
315 GHashTable *index)
316{
317 g_return_val_if_fail(bdb != NULL, FALSE);
318 g_return_val_if_fail(root != NULL, FALSE);
319 g_return_val_if_fail(index != NULL, FALSE);
320 g_return_val_if_fail(root->version == 0, FALSE);
321 g_return_val_if_fail(g_hash_table_size(index) == 1, FALSE);
322
fe000966
DM
323 sqlite3_stmt *stmt = bdb->stmt_load_all;
324
42f0a0a5 325 int rc;
fe000966
DM
326 while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
327
328 memdb_tree_entry_t *te;
329
330 guint64 inode = sqlite3_column_int64(stmt, 0);
331 const char *name = (const char *)sqlite3_column_text(stmt, 6);
332 int namelen = sqlite3_column_bytes(stmt, 6);
333 if (name == NULL || namelen == 0) {
e5a5a3ea 334 cfs_critical("inode has no name (inode = %016" PRIX64 ")", inode);
fe000966 335 goto fail;
48009cd2 336 }
fe000966
DM
337 te = g_malloc0(sizeof(memdb_tree_entry_t) + namelen + 1);
338 strcpy(te->name, name);
339
48009cd2 340 te->inode = inode;
fe000966
DM
341 te->parent = sqlite3_column_int64(stmt, 1);
342 te->version = sqlite3_column_int64(stmt, 2);
343 te->writer = sqlite3_column_int64(stmt, 3) & 0x0ffffffff;
344 te->mtime = sqlite3_column_int64(stmt, 4) & 0x0ffffffff;
345 te->type = sqlite3_column_int64(stmt, 5) & 255;
48009cd2 346
fe000966 347 gconstpointer value = sqlite3_column_blob(stmt, 7);
48009cd2 348
fe000966 349 int size = sqlite3_column_bytes(stmt, 7);
48009cd2
TL
350 te->size = size;
351
fe000966
DM
352 if (te->type == DT_REG) {
353 if (size > 0)
2c372aee 354 te->data.value = g_memdup2(value, size);
fe000966
DM
355 } else if (te->type == DT_DIR) {
356 if (size) {
e5a5a3ea 357 cfs_critical("directory inode contains data (inode = %016" PRIX64 ")",
fe000966
DM
358 te->inode);
359 g_free(te);
360 goto fail;
361 }
362 te->data.entries = NULL;
363 } else {
e5a5a3ea 364 cfs_critical("inode has unknown type (inode = %016" PRIX64 ", type = %d)",
fe000966
DM
365 te->inode, te->type);
366 g_free(te);
367 goto fail;
368 }
369
e5a5a3ea 370 cfs_debug("name %s (inode = %016" PRIX64 ", parent = %016" PRIX64 ")",
fe000966
DM
371 te->name, te->inode, te->parent);
372
373 if (te->inode == 0) {
73f041fd 374 if (!strcmp(te->name, VERSIONFILENAME)) {
fe000966
DM
375 root->version = te->version;
376 root->writer = te->writer;
377 root->mtime = te->mtime;
378 memdb_tree_entry_free(te);
379 } else {
380 cfs_critical("root inode has unexpected name '%s'", te->name);
381 memdb_tree_entry_free(te);
382 goto fail;
383 }
384 } else {
385 memdb_tree_entry_t *pte;
386
48009cd2
TL
387 if (!(pte = g_hash_table_lookup(index, &te->parent))) {
388 /* allocate placeholder (type == 0)
fe000966
DM
389 * this is simply replaced if we find a real inode later
390 */
391 pte = g_malloc0(sizeof(memdb_tree_entry_t));
392 pte->inode = te->parent;
393 pte->data.entries = g_hash_table_new(g_str_hash, g_str_equal);
394 g_hash_table_replace(index, &pte->inode, pte);
395
4c34134e 396 } else if (!(pte->type == DT_DIR || pte->type == 0)) {
fe000966 397 cfs_critical("parent is not a directory "
e5a5a3ea 398 "(inode = %016" PRIX64 ", parent = %016" PRIX64 ", name = '%s')",
fe000966
DM
399 te->inode, te->parent, te->name);
400 memdb_tree_entry_free(te);
401 goto fail;
402 }
403
404 if (te->type == DT_DIR) {
4c34134e
DM
405 memdb_tree_entry_t *tmpte;
406 /* test if there is a placeholder entry */
407 if ((tmpte = g_hash_table_lookup(index, &te->inode))) {
408 if (tmpte->type != 0) {
409 cfs_critical("found strange placeholder for "
e5a5a3ea 410 "(inode = %016" PRIX64 ", parent = %016" PRIX64 ", name = '%s', type = '%d')",
4c34134e
DM
411 te->inode, te->parent, te->name, tmpte->type);
412 memdb_tree_entry_free(te);
413 goto fail;
414 }
415 /* copy entries from placeholder */
416 te->data.entries = tmpte->data.entries;
417 tmpte->data.entries = NULL;
418 } else {
419 te->data.entries = g_hash_table_new(g_str_hash, g_str_equal);
420 }
fe000966 421 }
42f0a0a5
TL
422
423 memdb_tree_entry_t *existing;
424 if ((existing = g_hash_table_lookup(pte->data.entries, te->name))) {
425 cfs_critical(
426 "found entry with duplicate name '%s' - "
427 "A:(inode = 0x%016"PRIX64", parent = 0x%016"PRIX64", v./mtime = 0x%"PRIX64"/0x%"PRIi32")"
428 " vs. "
429 "B:(inode = 0x%016"PRIX64", parent = 0x%016"PRIX64", v./mtime = 0x%"PRIX64"/0x%"PRIi32")",
430 te->name,
431 existing->inode, existing->parent, existing->version, existing->mtime,
432 te->inode, te->parent, te->version, te->mtime
433 );
fe000966
DM
434 goto fail;
435 }
436
437 g_hash_table_replace(pte->data.entries, te->name, te);
438 g_hash_table_replace(index, &te->inode, te);
439 }
440 }
441 if (rc != SQLITE_DONE) {
442 cfs_critical("select returned error: %s", sqlite3_errmsg(bdb->db));
443 goto fail;
444 }
445
4c34134e 446 /* check if all inodes have parents (there must be no placeholders) */
fe000966
DM
447 GHashTableIter iter;
448 gpointer key, value;
449 g_hash_table_iter_init (&iter, index);
450 while (g_hash_table_iter_next (&iter, &key, &value)) {
451 memdb_tree_entry_t *te = (memdb_tree_entry_t *)value;
452 if (te->type == 0) {
e5a5a3ea 453 cfs_critical("missing directory inode (inode = %016" PRIX64 ")", te->inode);
fe000966
DM
454 goto fail;
455 }
456 }
457
458 sqlite3_reset(stmt);
459
460 return TRUE;
461
462fail:
48009cd2 463 sqlite3_reset(stmt);
fe000966
DM
464
465 cfs_critical("DB load failed");
466
467 return FALSE;
468}
469
470gboolean bdb_backend_commit_update(
48009cd2
TL
471 memdb_t *memdb,
472 memdb_index_t *master,
473 memdb_index_t *slave,
fe000966
DM
474 GList *inodes)
475{
476 g_return_val_if_fail(memdb != NULL, FALSE);
477 g_return_val_if_fail(memdb->bdb != NULL, FALSE);
478 g_return_val_if_fail(master != NULL, FALSE);
479 g_return_val_if_fail(slave != NULL, FALSE);
480
481 cfs_debug("enter bdb_backend_commit_update");
482
483 memdb_tree_entry_t *root = NULL;
484 GHashTable *index = NULL;
485
486 db_backend_t *bdb = (db_backend_t *)memdb->bdb;
487 gboolean result = FALSE;
488
489 int rc;
490
491 rc = sqlite3_step(bdb->stmt_begin);
492 sqlite3_reset(bdb->stmt_begin);
493 if (rc != SQLITE_DONE) {
494 cfs_critical("begin transaction failed: %s\n", sqlite3_errmsg(bdb->db));
495 return rc;
496 }
497
89fde9ac 498 g_mutex_lock (&memdb->mutex);
fe000966
DM
499
500 /* first, delete anything not found in master index) */
501
502 int i = 0;
503 int j = 0;
504
505 for (i = 0; i < master->size; i++) {
506 guint64 inode = master->entries[i].inode;
507 guint64 slave_inode;
508 while (j < slave->size && (slave_inode = slave->entries[j].inode) <= inode) {
509
510 if (slave_inode < inode) {
511 if (bdb_backend_delete_inode(bdb, slave_inode) != SQLITE_OK)
512 goto abort;
513
e5a5a3ea 514 cfs_debug("deleted inode %016" PRIX64, slave_inode);
fe000966
DM
515 }
516 j++;
517 }
518 if (j >= slave->size)
519 break;
520 }
521
522 while (j < slave->size) {
523 guint64 slave_inode = slave->entries[j].inode;
524
525 if (bdb_backend_delete_inode(bdb, slave_inode) != SQLITE_OK)
526 goto abort;
42f0a0a5 527
e5a5a3ea 528 cfs_debug("deleted inode %016" PRIX64, slave_inode);
fe000966
DM
529
530 j++;
531 }
532
533 /* now add all updates */
534
535 GList *l = inodes;
536 while (l) {
537 memdb_tree_entry_t *te = (memdb_tree_entry_t *)l->data;
538
539 tree_entry_debug(te);
540
541 if (backend_write_inode(
48009cd2
TL
542 bdb->db, bdb->stmt_replace_entry, te->inode, te->parent, te->version,
543 te->writer, te->mtime, te->size, te->type,
fe000966
DM
544 te->inode ? te->name : VERSIONFILENAME, te->data.value) != SQLITE_OK) {
545 goto abort;
546 }
547
548 l = g_list_next(l);
549 }
550
551 /* now try to reload */
552 root = memdb_tree_entry_new("");
553 root->data.entries = g_hash_table_new(g_str_hash, g_str_equal);
554 root->type = DT_DIR;
555
48009cd2 556 index = g_hash_table_new_full(g_int64_hash, g_int64_equal, NULL,
fe000966
DM
557 (GDestroyNotify)memdb_tree_entry_free);
558
559 g_hash_table_replace(index, &root->inode, root);
560
561 if (!bdb_backend_load_index(bdb, root, index))
562 goto abort;
563
564 if (!memdb->root->version) {
565 cfs_critical("new index has version 0 - internal error");
566 goto abort;
567 }
568
569 memdb_index_t *new_idx = memdb_encode_index(index, root);
570 if (!new_idx) {
571 cfs_critical("cant encode new index - internal error");
572 goto abort;
573 }
48009cd2 574
fe000966
DM
575 int idx_equal = (new_idx->bytes == master->bytes &&
576 (memcmp(master, new_idx, new_idx->bytes) == 0));
577
578 g_free (new_idx);
579
580 if (!idx_equal) {
581 cfs_critical("new index does not match master index - internal error");
582 goto abort;
583 }
584
585 rc = sqlite3_step(bdb->stmt_commit);
586 sqlite3_reset(bdb->stmt_commit);
587 if (rc != SQLITE_DONE) {
588 cfs_critical("commit transaction failed: %s\n", sqlite3_errmsg(bdb->db));
48009cd2 589 goto abort;
fe000966
DM
590 }
591
592 g_hash_table_destroy(memdb->index);
593 memdb->index = index;
594 memdb->root = root;
595 index = NULL;
596 root = NULL;
597
598 record_memdb_reload();
599
600 if (!memdb_recreate_vmlist(memdb)) {
601 cfs_critical("memdb_recreate_vmlist failed");
602 memdb->errors = 1;
603 result = FALSE;
604 goto ret;
605 }
606
607 memdb_update_locks(memdb);
608
609 result = TRUE;
610
611ret:
89fde9ac 612 g_mutex_unlock (&memdb->mutex);
fe000966
DM
613
614 if (index)
615 g_hash_table_destroy(index);
616
617 cfs_debug("leave bdb_backend_commit_update (%d)", result);
618
619 return result;
620
621abort:
622
623 memdb->errors = 1;
624
625 rc = sqlite3_step(bdb->stmt_rollback);
626 sqlite3_reset(bdb->stmt_rollback);
627 if (rc != SQLITE_DONE)
628 cfs_critical("rollback transaction failed: %s\n", sqlite3_errmsg(bdb->db));
629
630 result = FALSE;
631
632 goto ret;
633}
634
635void bdb_backend_close(db_backend_t *bdb)
48009cd2 636{
fe000966
DM
637 g_return_if_fail(bdb != NULL);
638
639 sqlite3_finalize(bdb->stmt_insert_entry);
640 sqlite3_finalize(bdb->stmt_replace_entry);
641 sqlite3_finalize(bdb->stmt_update_entry);
642 sqlite3_finalize(bdb->stmt_delete_entry);
643 sqlite3_finalize(bdb->stmt_begin);
644 sqlite3_finalize(bdb->stmt_commit);
645 sqlite3_finalize(bdb->stmt_rollback);
646 sqlite3_finalize(bdb->stmt_load_all);
647
648 int rc;
649 if ((rc = sqlite3_close(bdb->db)) != SQLITE_OK) {
650 cfs_critical("sqlite3_close failed: %d\n", rc);
651 }
652
653 sqlite3_shutdown();
654
655 g_free(bdb);
656}
657
658db_backend_t *bdb_backend_open(
659 const char *filename,
660 memdb_tree_entry_t *root,
661 GHashTable *index)
662{
663 g_return_val_if_fail(filename != NULL, NULL);
664 g_return_val_if_fail(root != NULL, NULL);
665 g_return_val_if_fail(index != NULL, NULL);
666
667 db_backend_t *bdb = g_new0(db_backend_t, 1);
668 g_return_val_if_fail(bdb != NULL, NULL);
669
670 int rc;
671
672 sqlite3_initialize();
673
674 if (!(bdb->db = bdb_create(filename)))
675 goto fail;
676
49426115
TL
677 // tell the query planner that the prepared statement will be retained for a long time and
678 // probably reused many times
679 const unsigned int flags = SQLITE_PREPARE_PERSISTENT;
680
681 rc = sqlite3_prepare_v3(bdb->db, sql_insert_entry, -1, flags, &bdb->stmt_insert_entry, NULL);
fe000966 682 if (rc != SQLITE_OK) {
48009cd2 683 cfs_critical("sqlite3_prepare 'sql_insert_entry' failed: %s\n",
fe000966
DM
684 sqlite3_errmsg(bdb->db));
685 goto fail;
686 }
49426115 687 rc = sqlite3_prepare_v3(bdb->db, sql_update_entry, -1, flags, &bdb->stmt_update_entry, NULL);
fe000966 688 if (rc != SQLITE_OK) {
48009cd2 689 cfs_critical("sqlite3_prepare 'sql_update_entry' failed: %s\n",
fe000966
DM
690 sqlite3_errmsg(bdb->db));
691 goto fail;
692 }
49426115 693 rc = sqlite3_prepare_v3(bdb->db, sql_replace_entry, -1, flags, &bdb->stmt_replace_entry, NULL);
fe000966 694 if (rc != SQLITE_OK) {
48009cd2 695 cfs_critical("sqlite3_prepare 'sql_replace_entry' failed: %s\n",
fe000966
DM
696 sqlite3_errmsg(bdb->db));
697 goto fail;
698 }
49426115 699 rc = sqlite3_prepare_v3(bdb->db, sql_delete_entry, -1, flags, &bdb->stmt_delete_entry, NULL);
fe000966 700 if (rc != SQLITE_OK) {
48009cd2 701 cfs_critical("sqlite3_prepare 'sql_delete_entry' failed: %s\n",
fe000966
DM
702 sqlite3_errmsg(bdb->db));
703 goto fail;
704 }
49426115 705 rc = sqlite3_prepare_v3(bdb->db, sql_begin, -1, flags, &bdb->stmt_begin, NULL);
fe000966 706 if (rc != SQLITE_OK) {
48009cd2 707 cfs_critical("sqlite3_prepare 'sql_begin' failed: %s\n",
fe000966
DM
708 sqlite3_errmsg(bdb->db));
709 goto fail;
710 }
49426115 711 rc = sqlite3_prepare_v3(bdb->db, sql_commit, -1, flags, &bdb->stmt_commit, NULL);
fe000966 712 if (rc != SQLITE_OK) {
48009cd2 713 cfs_critical("sqlite3_prepare 'sql_commit' failed: %s\n",
fe000966
DM
714 sqlite3_errmsg(bdb->db));
715 goto fail;
716 }
49426115 717 rc = sqlite3_prepare_v3(bdb->db, sql_rollback, -1, flags, &bdb->stmt_rollback, NULL);
fe000966 718 if (rc != SQLITE_OK) {
48009cd2 719 cfs_critical("sqlite3_prepare 'sql_rollback' failed: %s\n",
fe000966
DM
720 sqlite3_errmsg(bdb->db));
721 goto fail;
722 }
49426115 723 rc = sqlite3_prepare_v3(bdb->db, sql_load_all, -1, flags, &bdb->stmt_load_all, NULL);
fe000966 724 if (rc != SQLITE_OK) {
48009cd2 725 cfs_critical("sqlite3_prepare 'sql_load_all' failed: %s\n",
fe000966
DM
726 sqlite3_errmsg(bdb->db));
727 goto fail;
728 }
729
730 if (!bdb_backend_load_index(bdb, root, index))
731 goto fail;
732
733 if (!root->version) {
734 root->version++;
48009cd2 735
fe000966
DM
736 guint32 mtime = time(NULL);
737
48009cd2 738 if (bdb_backend_write(bdb, 0, 0, root->version, 0, mtime,
fe000966
DM
739 0, DT_REG, NULL, NULL, 0) != SQLITE_OK)
740 goto fail;
741 }
742
743 return bdb;
744
745fail:
fe000966 746 bdb_backend_close(bdb);
42f0a0a5 747
fe000966
DM
748 return NULL;
749}