GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/swissknife_ingest_gc.h
Date: 2026-05-17 02:35:27
Exec Total Coverage
Lines: 37 72 51.4%
Branches: 34 133 25.6%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 *
4 * GC database helper functions for cvmfs_swissknife ingest.
5 * These read/update the SQLite database produced by cvmfs_ducc gc.
6 */
7
8 #ifndef CVMFS_SWISSKNIFE_INGEST_GC_H_
9 #define CVMFS_SWISSKNIFE_INGEST_GC_H_
10
11 #include <stdint.h>
12
13 #include <string>
14 #include <vector>
15
16 #include "duplex_sqlite3.h"
17 #include "util/logging.h"
18 #include "util/string.h"
19
20 /**
21 * Read pending (not yet deleted) paths from a GC SQLite database.
22 *
23 * If batch_size > 0, at most batch_size rows are returned (in id order).
24 * If ids is non-NULL, the ids of the returned rows are written to it in the
25 * same order as paths.
26 * Returns true on success.
27 */
28 126 inline bool ReadGCDatabase(const std::string &db_path,
29 std::vector<std::string> *paths,
30 std::vector<int64_t> *ids = NULL,
31 int batch_size = 0) {
32 126 sqlite3 *db = NULL;
33
1/2
✓ Branch 2 taken 126 times.
✗ Branch 3 not taken.
126 int rc = sqlite3_open_v2(db_path.c_str(), &db, SQLITE_OPEN_READONLY, NULL);
34
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 105 times.
126 if (rc != SQLITE_OK) {
35
2/4
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 21 times.
✗ Branch 6 not taken.
21 LogCvmfs(kLogCvmfs, kLogStderr, "Cannot open GC database %s: %s",
36 db_path.c_str(), sqlite3_errmsg(db));
37
2/4
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
21 if (db) sqlite3_close(db);
38 21 return false;
39 }
40
41 std::string sql = "SELECT id, path FROM gc_paths WHERE deleted = 0 "
42
1/2
✓ Branch 2 taken 105 times.
✗ Branch 3 not taken.
105 "ORDER BY id";
43
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 105 times.
105 if (batch_size > 0) {
44 sql += " LIMIT " + StringifyInt(batch_size);
45 }
46 105 sqlite3_stmt *stmt = NULL;
47
1/2
✓ Branch 2 taken 105 times.
✗ Branch 3 not taken.
105 rc = sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, NULL);
48
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 105 times.
105 if (rc != SQLITE_OK) {
49 LogCvmfs(kLogCvmfs, kLogStderr,
50 "Cannot prepare GC query on %s: %s",
51 db_path.c_str(), sqlite3_errmsg(db));
52 sqlite3_close(db);
53 return false;
54 }
55
56
3/4
✓ Branch 1 taken 105252 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 105147 times.
✓ Branch 4 taken 105 times.
105252 while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
57
1/2
✓ Branch 1 taken 105147 times.
✗ Branch 2 not taken.
105147 const int64_t id = sqlite3_column_int64(stmt, 0);
58 const char *path =
59
1/2
✓ Branch 1 taken 105147 times.
✗ Branch 2 not taken.
105147 reinterpret_cast<const char *>(sqlite3_column_text(stmt, 1));
60
1/2
✓ Branch 0 taken 105147 times.
✗ Branch 1 not taken.
105147 if (path) {
61
2/4
✓ Branch 2 taken 105147 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 105147 times.
✗ Branch 6 not taken.
105147 paths->push_back(std::string(path));
62
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 105147 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
105147 if (ids != NULL) ids->push_back(id);
63 }
64 }
65
66
1/2
✓ Branch 1 taken 105 times.
✗ Branch 2 not taken.
105 sqlite3_finalize(stmt);
67
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 105 times.
105 if (rc != SQLITE_DONE) {
68 LogCvmfs(kLogCvmfs, kLogStderr,
69 "Error reading GC database %s: %s",
70 db_path.c_str(), sqlite3_errmsg(db));
71 sqlite3_close(db);
72 return false;
73 }
74
75
1/2
✓ Branch 1 taken 105 times.
✗ Branch 2 not taken.
105 sqlite3_close(db);
76 105 return true;
77 105 }
78
79
80 /**
81 * Mark paths as deleted in the GC SQLite database.
82 *
83 * If ids is non-empty, only the rows with the given ids are marked.
84 * If ids is empty, all currently-pending rows are marked (legacy behaviour).
85 * Returns true on success.
86 */
87 105 inline bool MarkGCPathsDeleted(
88 const std::string &db_path,
89 const std::vector<int64_t> &ids = std::vector<int64_t>()) {
90 105 sqlite3 *db = NULL;
91
1/2
✓ Branch 2 taken 105 times.
✗ Branch 3 not taken.
105 int rc = sqlite3_open_v2(db_path.c_str(), &db, SQLITE_OPEN_READWRITE, NULL);
92
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 84 times.
105 if (rc != SQLITE_OK) {
93
2/4
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 21 times.
✗ Branch 6 not taken.
21 LogCvmfs(kLogCvmfs, kLogStderr,
94 "Cannot open GC database for update %s: %s",
95 db_path.c_str(), sqlite3_errmsg(db));
96
2/4
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
21 if (db) sqlite3_close(db);
97 21 return false;
98 }
99
100
1/2
✓ Branch 1 taken 84 times.
✗ Branch 2 not taken.
84 if (ids.empty()) {
101 84 const char *sql = "UPDATE gc_paths SET deleted = 1 WHERE deleted = 0";
102 84 char *err_msg = NULL;
103
1/2
✓ Branch 1 taken 84 times.
✗ Branch 2 not taken.
84 rc = sqlite3_exec(db, sql, NULL, NULL, &err_msg);
104
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
84 if (rc != SQLITE_OK) {
105 LogCvmfs(kLogCvmfs, kLogStderr,
106 "Cannot mark GC paths as deleted in %s: %s",
107 db_path.c_str(), err_msg ? err_msg : "unknown error");
108 sqlite3_free(err_msg);
109 sqlite3_close(db);
110 return false;
111 }
112
1/2
✓ Branch 1 taken 84 times.
✗ Branch 2 not taken.
84 sqlite3_close(db);
113 84 return true;
114 }
115
116 const char *sql = "UPDATE gc_paths SET deleted = 1 WHERE id = ?";
117 sqlite3_stmt *stmt = NULL;
118 rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
119 if (rc != SQLITE_OK) {
120 LogCvmfs(kLogCvmfs, kLogStderr,
121 "Cannot prepare GC update on %s: %s",
122 db_path.c_str(), sqlite3_errmsg(db));
123 sqlite3_close(db);
124 return false;
125 }
126
127 sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL, NULL);
128 for (size_t i = 0; i < ids.size(); ++i) {
129 sqlite3_bind_int64(stmt, 1, ids[i]);
130 rc = sqlite3_step(stmt);
131 if (rc != SQLITE_DONE) {
132 LogCvmfs(kLogCvmfs, kLogStderr,
133 "Cannot mark GC path id %ld as deleted in %s: %s",
134 static_cast<long>(ids[i]), db_path.c_str(), // NOLINT
135 sqlite3_errmsg(db));
136 sqlite3_finalize(stmt);
137 sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL);
138 sqlite3_close(db);
139 return false;
140 }
141 sqlite3_reset(stmt);
142 }
143 sqlite3_exec(db, "COMMIT", NULL, NULL, NULL);
144 sqlite3_finalize(stmt);
145 sqlite3_close(db);
146 return true;
147 }
148
149 #endif // CVMFS_SWISSKNIFE_INGEST_GC_H_
150