GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/catalog_diff_tool_impl.h
Date: 2025-02-02 02:34:22
Exec Total Coverage
Lines: 111 128 86.7%
Branches: 111 218 50.9%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5 #ifndef CVMFS_CATALOG_DIFF_TOOL_IMPL_H_
6 #define CVMFS_CATALOG_DIFF_TOOL_IMPL_H_
7
8 #include <algorithm>
9 #include <string>
10
11 #include "catalog.h"
12 #include "crypto/hash.h"
13 #include "network/download.h"
14 #include "util/exception.h"
15 #include "util/logging.h"
16 #include "util/posix.h"
17
18 const uint64_t kLastInode = uint64_t(-1);
19
20 16 inline void AppendFirstEntry(catalog::DirectoryEntryList* entry_list) {
21
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 catalog::DirectoryEntry empty_entry;
22
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 entry_list->push_back(empty_entry);
23 16 }
24
25 16 inline void AppendLastEntry(catalog::DirectoryEntryList* entry_list) {
26
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
16 assert(!entry_list->empty());
27
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 catalog::DirectoryEntry last_entry;
28 16 last_entry.set_inode(kLastInode);
29
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 entry_list->push_back(last_entry);
30 16 }
31
32 86 inline bool IsSmaller(const catalog::DirectoryEntry& a,
33 const catalog::DirectoryEntry& b) {
34 86 bool a_is_first = (a.inode() == catalog::DirectoryEntryBase::kInvalidInode);
35 86 bool a_is_last = (a.inode() == kLastInode);
36 86 bool b_is_first = (b.inode() == catalog::DirectoryEntryBase::kInvalidInode);
37 86 bool b_is_last = (b.inode() == kLastInode);
38
39
4/4
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 44 times.
✓ Branch 3 taken 24 times.
86 if (a_is_last || b_is_first) return false;
40
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (a_is_first) return !b_is_first;
41
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 20 times.
24 if (b_is_last) return !a_is_last;
42
1/2
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
20 return a.name() < b.name();
43 }
44
45 template <typename RoCatalogMgr>
46 2 bool CatalogDiffTool<RoCatalogMgr>::Init() {
47
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (needs_setup_) {
48 // Create a temp directory
49 2 old_raii_temp_dir_ = RaiiTempDir::Create(temp_dir_prefix_);
50 2 new_raii_temp_dir_ = RaiiTempDir::Create(temp_dir_prefix_);
51
52 // Old catalog from release manager machine (before lease)
53
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
4 old_catalog_mgr_ =
54
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 OpenCatalogManager(repo_path_, old_raii_temp_dir_->dir(),
55 2 old_root_hash_, download_manager_, &stats_old_,
56 2 cache_dir_);
57
58 // New catalog from release manager machine (before lease)
59
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
4 new_catalog_mgr_ =
60
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 OpenCatalogManager(repo_path_, new_raii_temp_dir_->dir(),
61 2 new_root_hash_, download_manager_, &stats_new_,
62 2 cache_dir_);
63
64
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (!old_catalog_mgr_.IsValid()) {
65 LogCvmfs(kLogCvmfs, kLogStderr, "Could not open old catalog");
66 return false;
67 }
68
69
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (!new_catalog_mgr_.IsValid()) {
70 LogCvmfs(kLogCvmfs, kLogStderr, "Could not open new catalog");
71 return false;
72 }
73 }
74
75 2 return true;
76 }
77
78 template <typename RoCatalogMgr>
79 2 bool CatalogDiffTool<RoCatalogMgr>::Run(const PathString& path) {
80 2 DiffRec(path);
81
82 2 return true;
83 }
84
85 template <typename RoCatalogMgr>
86 4 RoCatalogMgr* CatalogDiffTool<RoCatalogMgr>::OpenCatalogManager(
87 const std::string& repo_path, const std::string& temp_dir,
88 const shash::Any& root_hash, download::DownloadManager* download_manager,
89 perf::Statistics* stats, const std::string& cache_dir) {
90
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 RoCatalogMgr* mgr = new RoCatalogMgr(root_hash, repo_path, temp_dir,
91 download_manager, stats, true,
92 cache_dir);
93 4 mgr->Init();
94
95 4 return mgr;
96 }
97
98 template <typename RoCatalogMgr>
99 8 void CatalogDiffTool<RoCatalogMgr>::DiffRec(const PathString& path) {
100 // Terminate recursion upon reaching an ignored path
101
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
8 if (IsIgnoredPath(path)) {
102 assert(!IsReportablePath(path));
103 return;
104 }
105
106 8 catalog::DirectoryEntryList old_listing;
107
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 AppendFirstEntry(&old_listing);
108
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 old_catalog_mgr_->Listing(path, &old_listing);
109
1/2
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
8 sort(old_listing.begin(), old_listing.end(), IsSmaller);
110
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 AppendLastEntry(&old_listing);
111
112 // create these paths here so it can be "reused" in the loop without
113 // re-initializing every time, this should save time in doing memcpy
114 // especially when the path gets longer
115
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 PathString old_path(path);
116
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 old_path.Append("/", 1);
117
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 PathString new_path(path);
118
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 new_path.Append("/", 1);
119 8 unsigned length_after_truncate = old_path.GetLength();
120
121 8 catalog::DirectoryEntryList new_listing;
122
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 AppendFirstEntry(&new_listing);
123
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 new_catalog_mgr_->Listing(path, &new_listing);
124
1/2
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
8 sort(new_listing.begin(), new_listing.end(), IsSmaller);
125
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 AppendLastEntry(&new_listing);
126
127 8 unsigned i_from = 0, size_from = old_listing.size();
128 8 unsigned i_to = 0, size_to = new_listing.size();
129
9/10
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 24 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 24 times.
✓ Branch 7 taken 3 times.
✓ Branch 8 taken 24 times.
✓ Branch 9 taken 27 times.
✓ Branch 10 taken 8 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 8 times.
110 while ((i_from < size_from) || (i_to < size_to)) {
130
1/2
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
27 catalog::DirectoryEntry old_entry = old_listing[i_from];
131
1/2
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
27 catalog::DirectoryEntry new_entry = new_listing[i_to];
132
133
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
27 if (old_entry.linkcount() == 0) {
134 PANIC(kLogStderr,
135 "CatalogDiffTool - Entry %s in old catalog has linkcount 0. "
136 "Aborting.",
137 old_entry.name().c_str());
138 }
139
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
27 if (new_entry.linkcount() == 0) {
140 PANIC(kLogStderr,
141 "CatalogDiffTool - Entry %s in new catalog has linkcount 0. "
142 "Aborting.",
143 new_entry.name().c_str());
144 }
145
146 // Skip .cvmfs hidden directory
147
1/4
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 27 times.
27 while (old_entry.IsHidden()) old_entry = old_listing[++i_from];
148
1/4
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 27 times.
27 while (new_entry.IsHidden()) new_entry = new_listing[++i_to];
149
150
1/2
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
27 old_path.Truncate(length_after_truncate);
151
3/6
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 27 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 27 times.
✗ Branch 10 not taken.
27 old_path.Append(old_entry.name().GetChars(), old_entry.name().GetLength());
152
1/2
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
27 new_path.Truncate(length_after_truncate);
153
3/6
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 27 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 27 times.
✗ Branch 10 not taken.
27 new_path.Append(new_entry.name().GetChars(), new_entry.name().GetLength());
154
155 27 XattrList xattrs;
156
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
27 if (new_entry.HasXattrs()) {
157 new_catalog_mgr_->LookupXattrs(new_path, &xattrs);
158 }
159
160
3/4
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 25 times.
27 if (IsSmaller(new_entry, old_entry)) {
161 2 i_to++;
162
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
2 if (IsReportablePath(new_path)) {
163
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 FileChunkList chunks;
164
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (new_entry.IsChunkedFile()) {
165 new_catalog_mgr_->ListFileChunks(new_path, new_entry.hash_algorithm(),
166 &chunks);
167 }
168
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 ReportAddition(new_path, new_entry, xattrs, chunks);
169 2 }
170
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
2 if (new_entry.IsDirectory()) {
171
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 DiffRec(new_path);
172 }
173 2 continue;
174
3/4
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 22 times.
27 } else if (IsSmaller(old_entry, new_entry)) {
175 3 i_from++;
176
5/6
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 2 times.
3 if (old_entry.IsDirectory() && !old_entry.IsNestedCatalogMountpoint()) {
177
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 DiffRec(old_path);
178 }
179
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
3 if (IsReportablePath(old_path)) {
180
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 ReportRemoval(old_path, old_entry);
181 }
182 3 continue;
183 }
184
185
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
22 assert(old_path == new_path);
186 22 i_from++;
187 22 i_to++;
188
189 catalog::DirectoryEntryBase::Differences diff =
190
1/2
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
22 old_entry.CompareTo(new_entry);
191
4/6
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 19 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 22 times.
41 if ((diff == catalog::DirectoryEntryBase::Difference::kIdentical) &&
192 19 old_entry.IsNestedCatalogMountpoint()) {
193 // Early recursion stop if nested catalogs are identical
194 shash::Any id_nested_from, id_nested_to;
195 id_nested_from = old_catalog_mgr_->GetNestedCatalogHash(old_path);
196 id_nested_to = new_catalog_mgr_->GetNestedCatalogHash(new_path);
197 assert(!id_nested_from.IsNull() && !id_nested_to.IsNull());
198 if (id_nested_from == id_nested_to) continue;
199 }
200
201
6/8
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 19 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 3 times.
✓ Branch 8 taken 19 times.
41 if (IsReportablePath(old_path) &&
202
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
19 ((diff != catalog::DirectoryEntryBase::Difference::kIdentical) ||
203 19 old_entry.IsNestedCatalogMountpoint())) {
204 // Modified directory entry, or nested catalog with modified hash
205
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 FileChunkList chunks;
206
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if (new_entry.IsChunkedFile()) {
207 new_catalog_mgr_->ListFileChunks(new_path, new_entry.hash_algorithm(),
208 &chunks);
209 }
210 bool recurse =
211
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 ReportModification(old_path, old_entry, new_entry, xattrs, chunks);
212
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!recurse) continue;
213
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 }
214
215
6/6
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 18 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 19 times.
✓ Branch 7 taken 3 times.
22 if (!old_entry.IsDirectory() || !new_entry.IsDirectory()) {
216
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 18 times.
19 if (old_entry.IsDirectory()) {
217
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 DiffRec(old_path);
218
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
18 } else if (new_entry.IsDirectory()) {
219 DiffRec(new_path);
220 }
221 19 continue;
222 }
223
224 // Recursion
225
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 DiffRec(old_path);
226 }
227 8 }
228
229 #endif // CVMFS_CATALOG_DIFF_TOOL_IMPL_H_
230