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_ |