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 |