CernVM-FS  2.12.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  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  bool a_is_first = (a.inode() == catalog::DirectoryEntryBase::kInvalidInode);
35  bool a_is_last = (a.inode() == kLastInode);
36  bool b_is_first = (b.inode() == catalog::DirectoryEntryBase::kInvalidInode);
37  bool b_is_last = (b.inode() == kLastInode);
38 
39  if (a_is_last || b_is_first) return false;
40  if (a_is_first) return !b_is_first;
41  if (b_is_last) return !a_is_last;
42  return a.name() < b.name();
43 }
44 
45 template <typename RoCatalogMgr>
47  if (needs_setup_) {
48  // Create a temp directory
49  old_raii_temp_dir_ = RaiiTempDir::Create(temp_dir_prefix_);
50  new_raii_temp_dir_ = RaiiTempDir::Create(temp_dir_prefix_);
51 
52  // Old catalog from release manager machine (before lease)
53  old_catalog_mgr_ =
54  OpenCatalogManager(repo_path_, old_raii_temp_dir_->dir(),
55  old_root_hash_, download_manager_, &stats_old_,
56  cache_dir_);
57 
58  // New catalog from release manager machine (before lease)
59  new_catalog_mgr_ =
60  OpenCatalogManager(repo_path_, new_raii_temp_dir_->dir(),
61  new_root_hash_, download_manager_, &stats_new_,
62  cache_dir_);
63 
64  if (!old_catalog_mgr_.IsValid()) {
65  LogCvmfs(kLogCvmfs, kLogStderr, "Could not open old catalog");
66  return false;
67  }
68 
69  if (!new_catalog_mgr_.IsValid()) {
70  LogCvmfs(kLogCvmfs, kLogStderr, "Could not open new catalog");
71  return false;
72  }
73  }
74 
75  return true;
76 }
77 
78 template <typename RoCatalogMgr>
80  DiffRec(path);
81 
82  return true;
83 }
84 
85 template <typename RoCatalogMgr>
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  RoCatalogMgr* mgr = new RoCatalogMgr(root_hash, repo_path, temp_dir,
91  download_manager, stats, true,
92  cache_dir);
93  mgr->Init();
94 
95  return mgr;
96 }
97 
98 template <typename RoCatalogMgr>
100  // Terminate recursion upon reaching an ignored path
101  if (IsIgnoredPath(path)) {
102  assert(!IsReportablePath(path));
103  return;
104  }
105 
106  catalog::DirectoryEntryList old_listing;
107  AppendFirstEntry(&old_listing);
108  old_catalog_mgr_->Listing(path, &old_listing);
109  sort(old_listing.begin(), old_listing.end(), IsSmaller);
110  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  PathString old_path(path);
116  old_path.Append("/", 1);
117  PathString new_path(path);
118  new_path.Append("/", 1);
119  unsigned length_after_truncate = old_path.GetLength();
120 
121  catalog::DirectoryEntryList new_listing;
122  AppendFirstEntry(&new_listing);
123  new_catalog_mgr_->Listing(path, &new_listing);
124  sort(new_listing.begin(), new_listing.end(), IsSmaller);
125  AppendLastEntry(&new_listing);
126 
127  unsigned i_from = 0, size_from = old_listing.size();
128  unsigned i_to = 0, size_to = new_listing.size();
129  while ((i_from < size_from) || (i_to < size_to)) {
130  catalog::DirectoryEntry old_entry = old_listing[i_from];
131  catalog::DirectoryEntry new_entry = new_listing[i_to];
132 
133  if (old_entry.linkcount() == 0) {
135  "CatalogDiffTool - Entry %s in old catalog has linkcount 0. "
136  "Aborting.",
137  old_entry.name().c_str());
138  }
139  if (new_entry.linkcount() == 0) {
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  while (old_entry.IsHidden()) old_entry = old_listing[++i_from];
148  while (new_entry.IsHidden()) new_entry = new_listing[++i_to];
149 
150  old_path.Truncate(length_after_truncate);
151  old_path.Append(old_entry.name().GetChars(), old_entry.name().GetLength());
152  new_path.Truncate(length_after_truncate);
153  new_path.Append(new_entry.name().GetChars(), new_entry.name().GetLength());
154 
155  XattrList xattrs;
156  if (new_entry.HasXattrs()) {
157  new_catalog_mgr_->LookupXattrs(new_path, &xattrs);
158  }
159 
160  if (IsSmaller(new_entry, old_entry)) {
161  i_to++;
162  if (IsReportablePath(new_path)) {
163  FileChunkList chunks;
164  if (new_entry.IsChunkedFile()) {
165  new_catalog_mgr_->ListFileChunks(new_path, new_entry.hash_algorithm(),
166  &chunks);
167  }
168  ReportAddition(new_path, new_entry, xattrs, chunks);
169  }
170  if (new_entry.IsDirectory()) {
171  DiffRec(new_path);
172  }
173  continue;
174  } else if (IsSmaller(old_entry, new_entry)) {
175  i_from++;
176  if (old_entry.IsDirectory() && !old_entry.IsNestedCatalogMountpoint()) {
177  DiffRec(old_path);
178  }
179  if (IsReportablePath(old_path)) {
180  ReportRemoval(old_path, old_entry);
181  }
182  continue;
183  }
184 
185  assert(old_path == new_path);
186  i_from++;
187  i_to++;
188 
190  old_entry.CompareTo(new_entry);
192  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  if (IsReportablePath(old_path) &&
203  old_entry.IsNestedCatalogMountpoint())) {
204  // Modified directory entry, or nested catalog with modified hash
205  FileChunkList chunks;
206  if (new_entry.IsChunkedFile()) {
207  new_catalog_mgr_->ListFileChunks(new_path, new_entry.hash_algorithm(),
208  &chunks);
209  }
210  bool recurse =
211  ReportModification(old_path, old_entry, new_entry, xattrs, chunks);
212  if (!recurse) continue;
213  }
214 
215  if (!old_entry.IsDirectory() || !new_entry.IsDirectory()) {
216  if (old_entry.IsDirectory()) {
217  DiffRec(old_path);
218  } else if (new_entry.IsDirectory()) {
219  DiffRec(new_path);
220  }
221  continue;
222  }
223 
224  // Recursion
225  DiffRec(old_path);
226  }
227 }
228 
229 #endif // CVMFS_CATALOG_DIFF_TOOL_IMPL_H_
uint32_t linkcount() const
void AppendLastEntry(catalog::DirectoryEntryList *entry_list)
bool IsNull() const
Definition: hash.h:383
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
bool Run(const PathString &path)
unsigned GetLength() const
Definition: shortstring.h:131
const char * c_str() const
Definition: shortstring.h:145
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:528