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  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  LogCvmfs(kLogReceiver, kLogDebug, "DiffRec: recursing into %s",
107  path.ToString().c_str());
108 
109  catalog::DirectoryEntryList old_listing;
110  AppendFirstEntry(&old_listing);
111  old_catalog_mgr_->Listing(path, &old_listing);
112  sort(old_listing.begin(), old_listing.end(), IsSmaller);
113  AppendLastEntry(&old_listing);
114 
115  // create these paths here so it can be "reused" in the loop without
116  // re-initializing every time, this should save time in doing memcpy
117  // especially when the path gets longer
118  PathString old_path(path);
119  old_path.Append("/", 1);
120  PathString new_path(path);
121  new_path.Append("/", 1);
122  unsigned length_after_truncate = old_path.GetLength();
123 
124  catalog::DirectoryEntryList new_listing;
125  AppendFirstEntry(&new_listing);
126  new_catalog_mgr_->Listing(path, &new_listing);
127  sort(new_listing.begin(), new_listing.end(), IsSmaller);
128  AppendLastEntry(&new_listing);
129 
130  unsigned i_from = 0, size_from = old_listing.size();
131  unsigned i_to = 0, size_to = new_listing.size();
132  while ((i_from < size_from) || (i_to < size_to)) {
133  catalog::DirectoryEntry old_entry = old_listing[i_from];
134  catalog::DirectoryEntry new_entry = new_listing[i_to];
135 
136  if (old_entry.linkcount() == 0) {
138  "CatalogDiffTool - Entry %s in old catalog has linkcount 0. "
139  "Aborting.",
140  old_entry.name().c_str());
141  }
142  if (new_entry.linkcount() == 0) {
144  "CatalogDiffTool - Entry %s in new catalog has linkcount 0. "
145  "Aborting.",
146  new_entry.name().c_str());
147  }
148 
149  // Skip .cvmfs hidden directory
150  while (old_entry.IsHidden()) old_entry = old_listing[++i_from];
151  while (new_entry.IsHidden()) new_entry = new_listing[++i_to];
152 
153  old_path.Truncate(length_after_truncate);
154  old_path.Append(old_entry.name().GetChars(), old_entry.name().GetLength());
155  new_path.Truncate(length_after_truncate);
156  new_path.Append(new_entry.name().GetChars(), new_entry.name().GetLength());
157 
158  XattrList xattrs;
159  if (new_entry.HasXattrs()) {
160  new_catalog_mgr_->LookupXattrs(new_path, &xattrs);
161  }
162 
163  if (IsSmaller(new_entry, old_entry)) {
164  i_to++;
165  bool recurse = new_entry.IsDirectory();
166  if (IsReportablePath(new_path)) {
167  FileChunkList chunks;
168  if (new_entry.IsChunkedFile()) {
169  new_catalog_mgr_->ListFileChunks(new_path, new_entry.hash_algorithm(),
170  &chunks);
171  }
172  recurse &= ReportAddition(new_path, new_entry, xattrs, chunks);
173  }
174  if (recurse) {
175  DiffRec(new_path);
176  }
177  continue;
178  } else if (IsSmaller(old_entry, new_entry)) {
179  i_from++;
180  if (old_entry.IsDirectory() && !old_entry.IsNestedCatalogMountpoint()) {
181  DiffRec(old_path);
182  }
183  if (IsReportablePath(old_path)) {
184  ReportRemoval(old_path, old_entry);
185  }
186  continue;
187  }
188 
189  assert(old_path == new_path);
190  i_from++;
191  i_to++;
192 
194  old_entry.CompareTo(new_entry);
196  old_entry.IsNestedCatalogMountpoint()) {
197  // Early recursion stop if nested catalogs are identical
198  shash::Any id_nested_from, id_nested_to;
199  id_nested_from = old_catalog_mgr_->GetNestedCatalogHash(old_path);
200  id_nested_to = new_catalog_mgr_->GetNestedCatalogHash(new_path);
201  assert(!id_nested_from.IsNull() && !id_nested_to.IsNull());
202  if (id_nested_from == id_nested_to) continue;
203  }
204 
205  if (IsReportablePath(old_path) &&
207  old_entry.IsNestedCatalogMountpoint())) {
208  // Modified directory entry, or nested catalog with modified hash
209  FileChunkList chunks;
210  if (new_entry.IsChunkedFile()) {
211  new_catalog_mgr_->ListFileChunks(new_path, new_entry.hash_algorithm(),
212  &chunks);
213  }
214  bool recurse =
215  ReportModification(old_path, old_entry, new_entry, xattrs, chunks);
216  if (!recurse) continue;
217  }
218 
219  if (old_entry.IsDirectory() || new_entry.IsDirectory()) {
220  DiffRec(old_path);
221  }
222  }
223 }
224 
225 #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
std::string ToString() const
Definition: shortstring.h:141
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