GCC Code Coverage Report
Directory: cvmfs/ Exec Total Coverage
File: cvmfs/receiver/catalog_merge_tool_impl.h Lines: 69 102 67.6 %
Date: 2019-02-03 02:48:13 Branches: 35 108 32.4 %

Line Branch Exec Source
1
/**
2
 * This file is part of the CernVM File System.
3
 */
4
5
#ifndef CVMFS_RECEIVER_CATALOG_MERGE_TOOL_IMPL_H_
6
#define CVMFS_RECEIVER_CATALOG_MERGE_TOOL_IMPL_H_
7
8
#include <string>
9
10
#include "catalog.h"
11
#include "hash.h"
12
#include "lease_path_util.h"
13
#include "logging.h"
14
#include "manifest.h"
15
#include "options.h"
16
#include "upload.h"
17
#include "util/posix.h"
18
#include "util/raii_temp_dir.h"
19
20
5
inline PathString MakeRelative(const PathString& path) {
21
5
  std::string rel_path;
22
5
  std::string abs_path = path.ToString();
23
5
  if (abs_path[0] == '/') {
24
5
    rel_path = abs_path.substr(1);
25
  } else {
26
    rel_path = abs_path;
27
  }
28
5
  return PathString(rel_path);
29
}
30
31
2
inline void SplitHardlink(catalog::DirectoryEntry* entry) {
32
2
  if (entry->linkcount() > 1) {
33
    LogCvmfs(kLogReceiver, kLogSyslogErr,
34
              "CatalogMergeTool - Hardlink found: %s. Hardlinks are not "
35
              "supported when publishing through repository gateway and "
36
              "will be split.", entry->name().c_str());
37
    entry->set_linkcount(1);
38
  }
39
2
}
40
41
2
inline void AbortIfHardlinked(const catalog::DirectoryEntry& entry) {
42
2
  if (entry.linkcount() > 1) {
43
    LogCvmfs(kLogReceiver, kLogSyslogErr,
44
              "CatalogMergeTool - Removal of file %s with linkcount > 1 is "
45
              "not supported. Aborting", entry.name().c_str());
46
    abort();
47
  }
48
2
}
49
50
namespace receiver {
51
52
template <typename RwCatalogMgr, typename RoCatalogMgr>
53
1
bool CatalogMergeTool<RwCatalogMgr, RoCatalogMgr>::Run(
54
    const Params& params, std::string* new_manifest_path) {
55
1
  UniquePtr<upload::Spooler> spooler;
56
1
  perf::Statistics stats;
57
1
  UniquePtr<RaiiTempDir> raii_temp_dir(RaiiTempDir::Create(temp_dir_prefix_));
58
1
  if (needs_setup_) {
59
    upload::SpoolerDefinition definition(
60
        params.spooler_configuration, params.hash_alg, params.compression_alg,
61
        params.generate_legacy_bulk_chunks, params.use_file_chunking,
62
        params.min_chunk_size, params.avg_chunk_size, params.max_chunk_size,
63
1
        "dummy_token", "dummy_key");
64
1
    spooler = upload::Spooler::Construct(definition);
65
1
    const std::string temp_dir = raii_temp_dir->dir();
66
1
    output_catalog_mgr_ = new RwCatalogMgr(
67
        manifest_->catalog_hash(), repo_path_, temp_dir, spooler,
68
        download_manager_, params.enforce_limits, params.nested_kcatalog_limit,
69
        params.root_kcatalog_limit, params.file_mbyte_limit, &stats,
70
        params.use_autocatalogs, params.max_weight, params.min_weight);
71
1
    output_catalog_mgr_->Init();
72
  }
73
74
1
  bool ret = CatalogDiffTool<RoCatalogMgr>::Run(PathString(""));
75
76
1
  ret &= CreateNewManifest(new_manifest_path);
77
78
1
  output_catalog_mgr_.Destroy();
79
80
1
  return ret;
81
}
82
83
template <typename RwCatalogMgr, typename RoCatalogMgr>
84
2
void CatalogMergeTool<RwCatalogMgr, RoCatalogMgr>::ReportAddition(
85
    const PathString& path, const catalog::DirectoryEntry& entry,
86
    const XattrList& xattrs, const FileChunkList& chunks) {
87
2
  const PathString rel_path = MakeRelative(path);
88
89
  /*
90
   * Note: If the addition of a file or directory outside of the lease
91
   *       path is encountered here, this means that the item was deleted
92
   *       by another writer running concurrently.
93
   *       The correct course of action is to ignore this change here.
94
   * */
95
2
  if (!IsPathInLease(lease_path_, rel_path)) {
96
    return;
97
  }
98
99
  const std::string parent_path =
100

2
      std::strchr(rel_path.c_str(), '/') ? GetParentPath(rel_path).c_str() : "";
101
102
2
  if (entry.IsDirectory()) {
103
1
    output_catalog_mgr_->AddDirectory(entry, parent_path);
104
1
    if (entry.IsNestedCatalogMountpoint()) {
105
      output_catalog_mgr_->CreateNestedCatalog(std::string(rel_path.c_str()));
106
    }
107

1
  } else if (entry.IsRegular() || entry.IsLink()) {
108
1
    catalog::DirectoryEntry modified_entry = entry;
109
1
    SplitHardlink(&modified_entry);
110
    const catalog::DirectoryEntryBase* base_entry =
111
1
        static_cast<const catalog::DirectoryEntryBase*>(&modified_entry);
112
1
    if (entry.IsChunkedFile()) {
113
      assert(!chunks.IsEmpty());
114
      output_catalog_mgr_->AddChunkedFile(*base_entry, xattrs, parent_path,
115
                                          chunks);
116
    } else {
117
1
      output_catalog_mgr_->AddFile(*base_entry, xattrs, parent_path);
118
    }
119
  }
120
}
121
122
template <typename RwCatalogMgr, typename RoCatalogMgr>
123
2
void CatalogMergeTool<RwCatalogMgr, RoCatalogMgr>::ReportRemoval(
124
    const PathString& path, const catalog::DirectoryEntry& entry) {
125
2
  const PathString rel_path = MakeRelative(path);
126
127
  /*
128
   * Note: If the removal of a file or directory outside of the lease
129
   *       path is encountered here, this means that the item was created
130
   *       by another writer running concurrently.
131
   *       The correct course of action is to ignore this change here.
132
   * */
133
2
  if (!IsPathInLease(lease_path_, rel_path)) {
134
    return;
135
  }
136
137
2
  if (entry.IsDirectory()) {
138
1
    if (entry.IsNestedCatalogMountpoint()) {
139
      output_catalog_mgr_->RemoveNestedCatalog(std::string(rel_path.c_str()),
140
                                               false);
141
    }
142
1
    output_catalog_mgr_->RemoveDirectory(rel_path.c_str());
143

1
  } else if (entry.IsRegular() || entry.IsLink()) {
144
1
    AbortIfHardlinked(entry);
145
1
    output_catalog_mgr_->RemoveFile(rel_path.c_str());
146
  }
147
}
148
149
template <typename RwCatalogMgr, typename RoCatalogMgr>
150
1
void CatalogMergeTool<RwCatalogMgr, RoCatalogMgr>::ReportModification(
151
    const PathString& path, const catalog::DirectoryEntry& entry1,
152
    const catalog::DirectoryEntry& entry2, const XattrList& xattrs,
153
    const FileChunkList& chunks) {
154
1
  const PathString rel_path = MakeRelative(path);
155
156
  /*
157
   * Note: If the modification of a file or directory outside of the lease
158
   *       path is encountered here, this means that the item was modified
159
   *       by another writer running concurrently.
160
   *       The correct course of action is to ignore this change here.
161
   * */
162
1
  if (!IsPathInLease(lease_path_, rel_path)) {
163
    return;
164
  }
165
166
  const std::string parent_path =
167

1
      std::strchr(rel_path.c_str(), '/') ? GetParentPath(rel_path).c_str() : "";
168
169

1
  if (entry1.IsDirectory() && entry2.IsDirectory()) {
170
    // From directory to directory
171
    const catalog::DirectoryEntryBase* base_entry =
172
        static_cast<const catalog::DirectoryEntryBase*>(&entry2);
173
    output_catalog_mgr_->TouchDirectory(*base_entry, rel_path.c_str());
174
    if (!entry1.IsNestedCatalogMountpoint() &&
175
        entry2.IsNestedCatalogMountpoint()) {
176
      output_catalog_mgr_->CreateNestedCatalog(std::string(rel_path.c_str()));
177
    } else if (entry1.IsNestedCatalogMountpoint() &&
178
               !entry2.IsNestedCatalogMountpoint()) {
179
      output_catalog_mgr_->RemoveNestedCatalog(std::string(rel_path.c_str()));
180
    }
181


1
  } else if ((entry1.IsRegular() || entry1.IsLink()) && entry2.IsDirectory()) {
182
    // From file to directory
183
    AbortIfHardlinked(entry1);
184
    output_catalog_mgr_->RemoveFile(rel_path.c_str());
185
    output_catalog_mgr_->AddDirectory(entry2, parent_path);
186
    if (entry2.IsNestedCatalogMountpoint()) {
187
      output_catalog_mgr_->CreateNestedCatalog(std::string(rel_path.c_str()));
188
    }
189
190


1
  } else if (entry1.IsDirectory() && (entry2.IsRegular() || entry2.IsLink())) {
191
    // From directory to file
192
    catalog::DirectoryEntry modified_entry = entry2;
193
    SplitHardlink(&modified_entry);
194
    const catalog::DirectoryEntryBase* base_entry =
195
        static_cast<const catalog::DirectoryEntryBase*>(&modified_entry);
196
    output_catalog_mgr_->RemoveDirectory(rel_path.c_str());
197
    if (entry2.IsChunkedFile()) {
198
      assert(!chunks.IsEmpty());
199
      output_catalog_mgr_->AddChunkedFile(*base_entry, xattrs, parent_path,
200
                                          chunks);
201
    } else {
202
      output_catalog_mgr_->AddFile(*base_entry, xattrs, parent_path);
203
    }
204
205


1
  } else if ((entry1.IsRegular() || entry1.IsLink()) &&
206
             (entry2.IsRegular() || entry2.IsLink())) {
207
    // From file to file
208
1
    AbortIfHardlinked(entry1);
209
1
    catalog::DirectoryEntry modified_entry = entry2;
210
1
    SplitHardlink(&modified_entry);
211
    const catalog::DirectoryEntryBase* base_entry =
212
1
        static_cast<const catalog::DirectoryEntryBase*>(&modified_entry);
213
1
    output_catalog_mgr_->RemoveFile(rel_path.c_str());
214
1
    if (entry2.IsChunkedFile()) {
215
      assert(!chunks.IsEmpty());
216
      output_catalog_mgr_->AddChunkedFile(*base_entry, xattrs, parent_path,
217
                                          chunks);
218
    } else {
219
1
      output_catalog_mgr_->AddFile(*base_entry, xattrs, parent_path);
220
    }
221
  }
222
}
223
224
template <typename RwCatalogMgr, typename RoCatalogMgr>
225
1
bool CatalogMergeTool<RwCatalogMgr, RoCatalogMgr>::CreateNewManifest(
226
    std::string* new_manifest_path) {
227
1
  if (!output_catalog_mgr_->Commit(false, 0, manifest_)) {
228
    LogCvmfs(kLogReceiver, kLogSyslogErr,
229
             "CatalogMergeTool - Could not commit output catalog");
230
    return false;
231
  }
232
233
1
  const std::string new_path = CreateTempPath(temp_dir_prefix_, 0600);
234
235
1
  if (!manifest_->Export(new_path)) {
236
    LogCvmfs(kLogReceiver, kLogSyslogErr,
237
             "CatalogMergeTool - Could not export new manifest");
238
  }
239
240
1
  *new_manifest_path = new_path;
241
242
1
  return true;
243
}
244
245
}  // namespace receiver
246
247
#endif  // CVMFS_RECEIVER_CATALOG_MERGE_TOOL_IMPL_H_