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