GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/swissknife_rotate_statsdb.cc
Date: 2026-03-22 02:40:38
Exec Total Coverage
Lines: 0 40 0.0%
Branches: 0 26 0.0%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 *
4 * Rotates the statistics database for a CernVM-FS repository. This is
5 * intended to be called from logrotate instead of the system sqlite3 binary,
6 * so that the vendored SQLite (which supports VACUUM INTO) is used regardless
7 * of the system SQLite version.
8 */
9
10 #include "swissknife_rotate_statsdb.h"
11
12 #include <string>
13 #include <unistd.h>
14
15 #include "sql.h"
16 #include "statistics_database.h"
17 #include "util/logging.h"
18 #include "util/posix.h"
19
20 namespace swissknife {
21
22 ParameterList CommandRotateStatsDB::GetParams() const {
23 ParameterList r;
24 r.push_back(Parameter::Mandatory('p', "path to the stats.db file"));
25 return r;
26 }
27
28 int CommandRotateStatsDB::Main(const ArgumentList &args) {
29 const std::string db_path = *args.find('p')->second;
30 const std::string archive_path = db_path + ".archive";
31
32 if (!FileExists(db_path)) {
33 LogCvmfs(kLogCvmfs, kLogStderr, "stats.db not found: %s",
34 db_path.c_str());
35 return 1;
36 }
37
38 // Remove any existing archive so VACUUM INTO can write a fresh one
39 if (FileExists(archive_path)) {
40 if (unlink(archive_path.c_str()) != 0) {
41 LogCvmfs(kLogCvmfs, kLogStderr, "failed to remove existing archive: %s",
42 archive_path.c_str());
43 return 1;
44 }
45 }
46
47 StatisticsDatabase *db =
48 StatisticsDatabase::Open(db_path, StatisticsDatabase::kOpenReadWrite);
49 if (db == NULL) {
50 LogCvmfs(kLogCvmfs, kLogStderr, "failed to open statistics database: %s",
51 db_path.c_str());
52 return 1;
53 }
54
55 // VACUUM INTO creates a compacted copy of the current database
56 const std::string vacuum_into =
57 "VACUUM INTO '" + archive_path + "';";
58 if (!sqlite::Sql(db->sqlite_db(), vacuum_into).Execute()) {
59 LogCvmfs(kLogCvmfs, kLogStderr,
60 "VACUUM INTO failed for %s: %s",
61 db_path.c_str(), db->GetLastErrorMsg().c_str());
62 delete db;
63 return 1;
64 }
65
66 // Clear all rows from the live database
67 if (!sqlite::Sql(db->sqlite_db(),
68 "DELETE FROM publish_statistics;").Execute()) {
69 LogCvmfs(kLogCvmfs, kLogStderr,
70 "failed to clear publish_statistics in %s: %s",
71 db_path.c_str(), db->GetLastErrorMsg().c_str());
72 delete db;
73 return 1;
74 }
75 if (!sqlite::Sql(db->sqlite_db(),
76 "DELETE FROM gc_statistics;").Execute()) {
77 LogCvmfs(kLogCvmfs, kLogStderr,
78 "failed to clear gc_statistics in %s: %s",
79 db_path.c_str(), db->GetLastErrorMsg().c_str());
80 delete db;
81 return 1;
82 }
83
84 // Reclaim space freed by the DELETEs
85 if (!db->Vacuum()) {
86 LogCvmfs(kLogCvmfs, kLogStderr, "VACUUM failed for %s: %s",
87 db_path.c_str(), db->GetLastErrorMsg().c_str());
88 delete db;
89 return 1;
90 }
91
92 LogCvmfs(kLogCvmfs, kLogStdout,
93 "Rotated statistics database: %s -> %s",
94 db_path.c_str(), archive_path.c_str());
95 delete db;
96 return 0;
97 }
98
99 } // namespace swissknife
100