GCC Code Coverage Report
Directory: cvmfs/ Exec Total Coverage
File: cvmfs/sync_mediator.h Lines: 1 10 10.0 %
Date: 2019-02-03 02:48:13 Branches: 0 0 - %

Line Branch Exec Source
1
/**
2
 * This file is part of the CernVM File System.
3
 *
4
 * The SyncMediator is an intermediate layer between the UnionSync
5
 * implementation and the CatalogManager.
6
 * It's main responsibility is to unwind file system intrinsics as
7
 * deleting all files in a deleted directory. Furthermore newly
8
 * created directories are recursed and all included files are
9
 * added as a whole (performance improvement).
10
 *
11
 * Furthermore it keeps track of hard link relations.  As we cannot store the
12
 * transient inode of the union file system in cvmfs, we just keep track of
13
 * hard link relations itself.  Inodes will be assigned at run time of the CVMFS
14
 * client taking these relations into account.
15
 *
16
 * Another responsibility of this class is the creation and destruction
17
 * of nested catalogs.  If a .cvmfscatalog magic file is encountered,
18
 * either on delete or add, it will be treated as nested catalog change.
19
 *
20
 * New and modified files are piped to external processes for hashing and
21
 * compression.  Results come back in a pipe.
22
 */
23
24
#ifndef CVMFS_SYNC_MEDIATOR_H_
25
#define CVMFS_SYNC_MEDIATOR_H_
26
27
#include <pthread.h>
28
29
#include <map>
30
#include <set>
31
#include <stack>
32
#include <string>
33
#include <vector>
34
35
#include "catalog_mgr_rw.h"
36
#include "compression.h"
37
#include "file_chunk.h"
38
#include "platform.h"
39
#include "swissknife_sync.h"
40
#include "sync_item.h"
41
#include "util/shared_ptr.h"
42
#include "xattr.h"
43
44
namespace manifest {
45
class Manifest;
46
}
47
48
struct Counters;
49
50
namespace publish {
51
52
/**
53
 * If we encounter a file with linkcount > 1 it will be added to a HardlinkGroup
54
 * After processing all files, the HardlinkGroups are populated with
55
 * related hardlinks
56
 * Assertion: linkcount == HardlinkGroup::hardlinks.size() at the end
57
 */
58
struct HardlinkGroup {
59
  explicit HardlinkGroup(SharedPtr<SyncItem> item) : master(item) {
60
    hardlinks[master->GetRelativePath()] = item;
61
  }
62
63
  void AddHardlink(SharedPtr<SyncItem> entry) {
64
    hardlinks[entry->GetRelativePath()] = entry;
65
  }
66
67
  SharedPtr<SyncItem> master;
68
  SyncItemList hardlinks;
69
  FileChunkList file_chunks;
70
};
71
72
1
class AbstractSyncMediator {
73
 public:
74
  virtual ~AbstractSyncMediator() = 0;
75
76
  virtual void RegisterUnionEngine(SyncUnion *engine) = 0;
77
78
  virtual void Add(SharedPtr<SyncItem> entry) = 0;
79
  virtual void Touch(SharedPtr<SyncItem> entry) = 0;
80
  virtual void Remove(SharedPtr<SyncItem> entry) = 0;
81
  virtual void Replace(SharedPtr<SyncItem> entry) = 0;
82
  virtual void Clone(const std::string from, const std::string to) = 0;
83
84
  virtual void AddUnmaterializedDirectory(SharedPtr<SyncItem> entry) = 0;
85
86
  virtual void EnterDirectory(SharedPtr<SyncItem> entry) = 0;
87
  virtual void LeaveDirectory(SharedPtr<SyncItem> entry) = 0;
88
89
  virtual bool Commit(manifest::Manifest *manifest) = 0;
90
91
  virtual bool IsExternalData() const = 0;
92
  virtual zlib::Algorithms GetCompressionAlgorithm() const = 0;
93
};
94
95
/**
96
 * Mapping of inode number to the related HardlinkGroup.
97
 */
98
typedef std::map<uint64_t, HardlinkGroup> HardlinkGroupMap;
99
100
/**
101
 * The SyncMediator refines the input received from a concrete UnionSync object.
102
 * For example, it resolves the insertion and deletion of complete directories
103
 * by recursing them.  It works as a mediator between the union file system and
104
 * forwards the correct database commands to the catalog handler to sync the
105
 * changes into the repository.
106
 * Furthermore it sends new and modified files to the spooler for compression
107
 * and hashing.
108
 */
109
class SyncMediator : public virtual AbstractSyncMediator {
110
 public:
111
  static const unsigned int processing_dot_interval = 100;
112
113
  SyncMediator(catalog::WritableCatalogManager *catalog_manager,
114
               const SyncParameters *params,
115
               perf::StatisticsTemplate statistics);
116
  void RegisterUnionEngine(SyncUnion *engine);
117
  // Final class, it is not meant to be derived any further
118
  ~SyncMediator();
119
120
  void Add(SharedPtr<SyncItem> entry);
121
  void Touch(SharedPtr<SyncItem> entry);
122
  void Remove(SharedPtr<SyncItem> entry);
123
  void Replace(SharedPtr<SyncItem> entry);
124
  void Clone(const std::string from, const std::string to);
125
126
  void AddUnmaterializedDirectory(SharedPtr<SyncItem> entry);
127
128
  void EnterDirectory(SharedPtr<SyncItem> entry);
129
  void LeaveDirectory(SharedPtr<SyncItem> entry);
130
131
  bool Commit(manifest::Manifest *manifest);
132
133
  // The sync union engine uses this information to create properly initialized
134
  // sync items
135
  bool IsExternalData() const { return params_->external_data; }
136
  zlib::Algorithms GetCompressionAlgorithm() const {
137
    return params_->compression_alg;
138
  }
139
140
 private:
141
  enum ChangesetAction {
142
    kAdd,
143
    kAddCatalog,
144
    kAddHardlinks,
145
    kTouch,
146
    kRemove,
147
    kRemoveCatalog
148
  };
149
150
  typedef std::stack<HardlinkGroupMap> HardlinkGroupMapStack;
151
  typedef std::vector<HardlinkGroup> HardlinkGroupList;
152
153
  void PrintChangesetNotice(const ChangesetAction action,
154
                            const std::string &extra_info) const;
155
156
  void EnsureAllowed(SharedPtr<SyncItem> entry);
157
158
  // Called after figuring out the type of a path (file, symlink, dir)
159
  void AddFile(SharedPtr<SyncItem> entry);
160
  void RemoveFile(SharedPtr<SyncItem> entry);
161
162
  void AddDirectory(SharedPtr<SyncItem> entry);
163
  void RemoveDirectory(SharedPtr<SyncItem> entry);
164
  void TouchDirectory(SharedPtr<SyncItem> entry);
165
166
  void CreateNestedCatalog(SharedPtr<SyncItem> directory);
167
  void RemoveNestedCatalog(SharedPtr<SyncItem> directory);
168
169
  void TouchDirectoryRecursively(SharedPtr<SyncItem> entry);
170
  void TouchingFileCallback(const std::string &parent_dir,
171
                          const std::string &file_name);
172
  void TouchingSymlinkCallback(const std::string &parent_dir,
173
                             const std::string &link_name);
174
  void TouchDirectoryCallback(const std::string &parent_dir,
175
                               const std::string &dir_name);
176
  void RemoveDirectoryRecursively(SharedPtr<SyncItem> entry);
177
  void RemoveFileCallback(const std::string &parent_dir,
178
                          const std::string &file_name);
179
  void RemoveSymlinkCallback(const std::string &parent_dir,
180
                             const std::string &link_name);
181
  void RemoveCharacterDeviceCallback(const std::string &parent_dir,
182
                                     const std::string &link_name);
183
  void RemoveBlockDeviceCallback(const std::string &parent_dir,
184
                                 const std::string &link_name);
185
  void RemoveFifoCallback(const std::string &parent_dir,
186
                          const std::string &link_name);
187
  void RemoveSocketCallback(const std::string &parent_dir,
188
                            const std::string &link_name);
189
  void RemoveDirectoryCallback(const std::string &parent_dir,
190
                               const std::string &dir_name);
191
  bool IgnoreFileCallback(const std::string &parent_dir,
192
                          const std::string &file_name);
193
  // Called by file system traversal
194
  void EnterAddedDirectoryCallback(const std::string &parent_dir,
195
                                   const std::string &dir_name);
196
  void LeaveAddedDirectoryCallback(const std::string &parent_dir,
197
                                   const std::string &dir_name);
198
  void AddDirectoryRecursively(SharedPtr<SyncItem> entry);
199
  bool AddDirectoryCallback(const std::string &parent_dir,
200
                            const std::string &dir_name);
201
  void AddFileCallback(const std::string &parent_dir,
202
                       const std::string &file_name);
203
  void AddCharacterDeviceCallback(const std::string &parent_dir,
204
                                  const std::string &file_name);
205
  void AddBlockDeviceCallback(const std::string &parent_dir,
206
                              const std::string &file_name);
207
  void AddFifoCallback(const std::string &parent_dir,
208
                       const std::string &file_name);
209
  void AddSocketCallback(const std::string &parent_dir,
210
                         const std::string &file_name);
211
  void AddSymlinkCallback(const std::string &parent_dir,
212
                          const std::string &link_name);
213
  SharedPtr<SyncItem> CreateSyncItem(const std::string &relative_parent_path,
214
                                     const std::string &filename,
215
                                     const SyncItemType entry_type) const;
216
217
  // Called by Upload Spooler
218
  void PublishFilesCallback(const upload::SpoolerResult &result);
219
  void PublishHardlinksCallback(const upload::SpoolerResult &result);
220
221
  // Hardlink handling
222
  void CompleteHardlinks(SharedPtr<SyncItem> entry);
223
  HardlinkGroupMap &GetHardlinkMap() { return hardlink_stack_.top(); }
224
  void LegacyRegularHardlinkCallback(const std::string &parent_dir,
225
                                     const std::string &file_name);
226
  void LegacySymlinkHardlinkCallback(const std::string &parent_dir,
227
                                     const std::string &file_name);
228
  void LegacyCharacterDeviceHardlinkCallback(const std::string &parent_dir,
229
                                             const std::string &file_name);
230
  void LegacyBlockDeviceHardlinkCallback(const std::string &parent_dir,
231
                                         const std::string &file_name);
232
  void LegacyFifoHardlinkCallback(const std::string &parent_dir,
233
                                  const std::string &file_name);
234
  void LegacySocketHardlinkCallback(const std::string &parent_dir,
235
                                    const std::string &file_name);
236
  void InsertLegacyHardlink(SharedPtr<SyncItem> entry);
237
  uint64_t GetTemporaryHardlinkGroupNumber(SharedPtr<SyncItem> entry) const;
238
  void InsertHardlink(SharedPtr<SyncItem> entry);
239
240
  void AddLocalHardlinkGroups(const HardlinkGroupMap &hardlinks);
241
  void AddHardlinkGroup(const HardlinkGroup &group);
242
243
  catalog::WritableCatalogManager *catalog_manager_;
244
  SyncUnion *union_engine_;
245
246
  bool handle_hardlinks_;
247
248
  /**
249
   * Hardlinks are supported as long as they all reside in the same directory.
250
   * If a recursion enters a directory, we push an empty HardlinkGroupMap to
251
   * keep track of the hardlinks of this directory.
252
   * When leaving a directory (i.e. it is completely processed) the stack is
253
   * popped and the HardlinkGroupMap is processed.
254
   */
255
  HardlinkGroupMapStack hardlink_stack_;
256
257
  /**
258
   * New and modified files are sent to an external spooler for hashing and
259
   * compression.  A spooler callback adds them to the catalogs, once processed.
260
   */
261
  pthread_mutex_t lock_file_queue_;
262
  SyncItemList file_queue_;
263
264
  HardlinkGroupList hardlink_queue_;
265
266
  const SyncParameters *params_;
267
  mutable unsigned int changed_items_;
268
269
  /**
270
   * By default, files have no extended attributes.
271
   */
272
  XattrList default_xattrs;
273
  UniquePtr<Counters> counters_;
274
};  // class SyncMediator
275
276
}  // namespace publish
277
278
#endif  // CVMFS_SYNC_MEDIATOR_H_