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 
57  // New catalog from release manager machine (before lease)
58  new_catalog_mgr_ =
59  OpenCatalogManager(repo_path_, new_raii_temp_dir_->dir(),
60  new_root_hash_, download_manager_, &stats_new_);
61 
62  if (!old_catalog_mgr_.IsValid()) {
63  LogCvmfs(kLogCvmfs, kLogStderr, "Could not open old catalog");
64  return false;
65  }
66 
67  if (!new_catalog_mgr_.IsValid()) {
68  LogCvmfs(kLogCvmfs, kLogStderr, "Could not open new catalog");
69  return false;
70  }
71  }
72 
73  return true;
74 }
75 
76 template <typename RoCatalogMgr>
78  DiffRec(path);
79 
80  return true;
81 }
82 
83 template <typename RoCatalogMgr>
85  const std::string& repo_path, const std::string& temp_dir,
86  const shash::Any& root_hash, download::DownloadManager* download_manager,
87  perf::Statistics* stats) {
88  RoCatalogMgr* mgr = new RoCatalogMgr(root_hash, repo_path, temp_dir,
89  download_manager, stats, true);
90  mgr->Init();
91 
92  return mgr;
93 }
94 
95 template <typename RoCatalogMgr>
97  // Terminate recursion upon reaching an ignored path
98  if (IsIgnoredPath(path)) {
99  assert(!IsReportablePath(path));
100  return;
101  }
102 
103  catalog::DirectoryEntryList old_listing;
104  AppendFirstEntry(&old_listing);
105  old_catalog_mgr_->Listing(path, &old_listing);
106  sort(old_listing.begin(), old_listing.end(), IsSmaller);
107  AppendLastEntry(&old_listing);
108 
109  // create these paths here so it can be "reused" in the loop without
110  // re-initializing every time, this should save time in doing memcpy
111  // especially when the path gets longer
112  PathString old_path(path);
113  old_path.Append("/", 1);
114  PathString new_path(path);
115  new_path.Append("/", 1);
116  unsigned length_after_truncate = old_path.GetLength();
117 
118  catalog::DirectoryEntryList new_listing;
119  AppendFirstEntry(&new_listing);
120  new_catalog_mgr_->Listing(path, &new_listing);
121  sort(new_listing.begin(), new_listing.end(), IsSmaller);
122  AppendLastEntry(&new_listing);
123 
124  unsigned i_from = 0, size_from = old_listing.size();
125  unsigned i_to = 0, size_to = new_listing.size();
126  while ((i_from < size_from) || (i_to < size_to)) {
127  catalog::DirectoryEntry old_entry = old_listing[i_from];
128  catalog::DirectoryEntry new_entry = new_listing[i_to];
129 
130  if (old_entry.linkcount() == 0) {
132  "CatalogDiffTool - Entry %s in old catalog has linkcount 0. "
133  "Aborting.",
134  old_entry.name().c_str());
135  }
136  if (new_entry.linkcount() == 0) {
138  "CatalogDiffTool - Entry %s in new catalog has linkcount 0. "
139  "Aborting.",
140  new_entry.name().c_str());
141  }
142 
143  // Skip .cvmfs hidden directory
144  while (old_entry.IsHidden()) old_entry = old_listing[++i_from];
145  while (new_entry.IsHidden()) new_entry = new_listing[++i_to];
146 
147  old_path.Truncate(length_after_truncate);
148  old_path.Append(old_entry.name().GetChars(), old_entry.name().GetLength());
149  new_path.Truncate(length_after_truncate);
150  new_path.Append(new_entry.name().GetChars(), new_entry.name().GetLength());
151 
152  XattrList xattrs;
153  if (new_entry.HasXattrs()) {
154  new_catalog_mgr_->LookupXattrs(new_path, &xattrs);
155  }
156 
157  if (IsSmaller(new_entry, old_entry)) {
158  i_to++;
159  if (IsReportablePath(new_path)) {
160  FileChunkList chunks;
161  if (new_entry.IsChunkedFile()) {
162  new_catalog_mgr_->ListFileChunks(new_path, new_entry.hash_algorithm(),
163  &chunks);
164  }
165  ReportAddition(new_path, new_entry, xattrs, chunks);
166  }
167  if (new_entry.IsDirectory()) {
168  DiffRec(new_path);
169  }
170  continue;
171  } else if (IsSmaller(old_entry, new_entry)) {
172  i_from++;
173  if (old_entry.IsDirectory() && !old_entry.IsNestedCatalogMountpoint()) {
174  DiffRec(old_path);
175  }
176  if (IsReportablePath(old_path)) {
177  ReportRemoval(old_path, old_entry);
178  }
179  continue;
180  }
181 
182  assert(old_path == new_path);
183  i_from++;
184  i_to++;
185 
187  old_entry.CompareTo(new_entry);
189  old_entry.IsNestedCatalogMountpoint()) {
190  // Early recursion stop if nested catalogs are identical
191  shash::Any id_nested_from, id_nested_to;
192  id_nested_from = old_catalog_mgr_->GetNestedCatalogHash(old_path);
193  id_nested_to = new_catalog_mgr_->GetNestedCatalogHash(new_path);
194  assert(!id_nested_from.IsNull() && !id_nested_to.IsNull());
195  if (id_nested_from == id_nested_to) continue;
196  }
197 
198  if (IsReportablePath(old_path) &&
200  old_entry.IsNestedCatalogMountpoint())) {
201  // Modified directory entry, or nested catalog with modified hash
202  FileChunkList chunks;
203  if (new_entry.IsChunkedFile()) {
204  new_catalog_mgr_->ListFileChunks(new_path, new_entry.hash_algorithm(),
205  &chunks);
206  }
207  bool recurse =
208  ReportModification(old_path, old_entry, new_entry, xattrs, chunks);
209  if (!recurse) continue;
210  }
211 
212  if (!old_entry.IsDirectory() || !new_entry.IsDirectory()) {
213  if (old_entry.IsDirectory()) {
214  DiffRec(old_path);
215  } else if (new_entry.IsDirectory()) {
216  DiffRec(new_path);
217  }
218  continue;
219  }
220 
221  // Recursion
222  DiffRec(old_path);
223  }
224 }
225 
226 #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
RoCatalogMgr * OpenCatalogManager(const std::string &repo_path, const std::string &temp_dir, const shash::Any &root_hash, download::DownloadManager *download_manager, perf::Statistics *stats)
std::vector< DirectoryEntry > DirectoryEntryList
NameString name() const
bool HasXattrs() const
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