| 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/compression.h" |
| 37 |
|
|
#include "file_chunk.h" |
| 38 |
|
|
#include "publish/repository.h" |
| 39 |
|
|
#include "statistics.h" |
| 40 |
|
|
#include "swissknife_sync.h" |
| 41 |
|
|
#include "sync_item.h" |
| 42 |
|
|
#include "util/platform.h" |
| 43 |
|
|
#include "util/pointer.h" |
| 44 |
|
|
#include "util/shared_ptr.h" |
| 45 |
|
|
#include "xattr.h" |
| 46 |
|
|
|
| 47 |
|
|
namespace manifest { |
| 48 |
|
|
class Manifest; |
| 49 |
|
|
} |
| 50 |
|
|
|
| 51 |
|
|
namespace publish { |
| 52 |
|
|
|
| 53 |
|
|
class SyncDiffReporter : public DiffListener { |
| 54 |
|
|
public: |
| 55 |
|
|
enum PrintAction { |
| 56 |
|
|
kPrintDots, |
| 57 |
|
|
kPrintChanges |
| 58 |
|
|
}; |
| 59 |
|
|
|
| 60 |
|
✗ |
explicit SyncDiffReporter(PrintAction print_action = kPrintChanges, |
| 61 |
|
|
unsigned int processing_dot_interval = 100) |
| 62 |
|
✗ |
: print_action_(print_action) |
| 63 |
|
✗ |
, processing_dot_interval_(processing_dot_interval) |
| 64 |
|
✗ |
, changed_items_(0) { } |
| 65 |
|
|
|
| 66 |
|
|
virtual void OnInit(const history::History::Tag &from_tag, |
| 67 |
|
|
const history::History::Tag &to_tag); |
| 68 |
|
|
virtual void OnStats(const catalog::DeltaCounters &delta); |
| 69 |
|
|
|
| 70 |
|
|
virtual void OnAdd(const std::string &path, |
| 71 |
|
|
const catalog::DirectoryEntry &entry); |
| 72 |
|
|
virtual void OnRemove(const std::string &path, |
| 73 |
|
|
const catalog::DirectoryEntry &entry); |
| 74 |
|
|
virtual void OnModify(const std::string &path, |
| 75 |
|
|
const catalog::DirectoryEntry &entry_from, |
| 76 |
|
|
const catalog::DirectoryEntry &entry_to); |
| 77 |
|
|
void CommitReport(); |
| 78 |
|
|
|
| 79 |
|
|
private: |
| 80 |
|
|
void PrintDots(); |
| 81 |
|
|
void AddImpl(const std::string &path); |
| 82 |
|
|
void RemoveImpl(const std::string &path); |
| 83 |
|
|
void ModifyImpl(const std::string &path); |
| 84 |
|
|
|
| 85 |
|
|
PrintAction print_action_; |
| 86 |
|
|
unsigned int processing_dot_interval_; |
| 87 |
|
|
unsigned int changed_items_; |
| 88 |
|
|
}; |
| 89 |
|
|
|
| 90 |
|
|
/** |
| 91 |
|
|
* If we encounter a file with linkcount > 1 it will be added to a HardlinkGroup |
| 92 |
|
|
* After processing all files, the HardlinkGroups are populated with |
| 93 |
|
|
* related hardlinks |
| 94 |
|
|
* Assertion: linkcount == HardlinkGroup::hardlinks.size() at the end |
| 95 |
|
|
*/ |
| 96 |
|
|
struct HardlinkGroup { |
| 97 |
|
✗ |
explicit HardlinkGroup(const SharedPtr<SyncItem> &item) : master(item) { |
| 98 |
|
✗ |
hardlinks[master->GetRelativePath()] = item; |
| 99 |
|
|
} |
| 100 |
|
|
|
| 101 |
|
✗ |
void AddHardlink(const SharedPtr<SyncItem> &entry) { |
| 102 |
|
✗ |
hardlinks[entry->GetRelativePath()] = entry; |
| 103 |
|
|
} |
| 104 |
|
|
|
| 105 |
|
|
SharedPtr<SyncItem> master; |
| 106 |
|
|
SyncItemList hardlinks; |
| 107 |
|
|
FileChunkList file_chunks; |
| 108 |
|
|
}; |
| 109 |
|
|
|
| 110 |
|
|
class AbstractSyncMediator { |
| 111 |
|
|
public: |
| 112 |
|
|
virtual ~AbstractSyncMediator() = 0; |
| 113 |
|
|
|
| 114 |
|
|
virtual void RegisterUnionEngine(SyncUnion *engine) = 0; |
| 115 |
|
|
|
| 116 |
|
|
virtual void Add(SharedPtr<SyncItem> entry) = 0; |
| 117 |
|
|
virtual void Touch(SharedPtr<SyncItem> entry) = 0; |
| 118 |
|
|
virtual void Remove(SharedPtr<SyncItem> entry) = 0; |
| 119 |
|
|
virtual void Replace(SharedPtr<SyncItem> entry) = 0; |
| 120 |
|
|
virtual void Clone(const std::string from, const std::string to) = 0; |
| 121 |
|
|
|
| 122 |
|
|
virtual void AddUnmaterializedDirectory(SharedPtr<SyncItem> entry) = 0; |
| 123 |
|
|
|
| 124 |
|
|
virtual void EnterDirectory(SharedPtr<SyncItem> entry) = 0; |
| 125 |
|
|
virtual void LeaveDirectory(SharedPtr<SyncItem> entry) = 0; |
| 126 |
|
|
|
| 127 |
|
|
virtual bool Commit(manifest::Manifest *manifest) = 0; |
| 128 |
|
|
|
| 129 |
|
|
virtual bool IsExternalData() const = 0; |
| 130 |
|
|
virtual bool IsDirectIo() const = 0; |
| 131 |
|
|
virtual zlib::Algorithms GetCompressionAlgorithm() const = 0; |
| 132 |
|
|
}; |
| 133 |
|
|
|
| 134 |
|
|
/** |
| 135 |
|
|
* Mapping of inode number to the related HardlinkGroup. |
| 136 |
|
|
*/ |
| 137 |
|
|
typedef std::map<uint64_t, HardlinkGroup> HardlinkGroupMap; |
| 138 |
|
|
|
| 139 |
|
|
/** |
| 140 |
|
|
* The SyncMediator refines the input received from a concrete UnionSync object. |
| 141 |
|
|
* For example, it resolves the insertion and deletion of complete directories |
| 142 |
|
|
* by recursing them. It works as a mediator between the union file system and |
| 143 |
|
|
* forwards the correct database commands to the catalog handler to sync the |
| 144 |
|
|
* changes into the repository. |
| 145 |
|
|
* Furthermore it sends new and modified files to the spooler for compression |
| 146 |
|
|
* and hashing. |
| 147 |
|
|
*/ |
| 148 |
|
|
class SyncMediator : public virtual AbstractSyncMediator { |
| 149 |
|
|
public: |
| 150 |
|
|
static const unsigned int processing_dot_interval = 100; |
| 151 |
|
|
|
| 152 |
|
|
SyncMediator(catalog::WritableCatalogManager *catalog_manager, |
| 153 |
|
|
const SyncParameters *params, |
| 154 |
|
|
perf::StatisticsTemplate statistics); |
| 155 |
|
|
void RegisterUnionEngine(SyncUnion *engine); |
| 156 |
|
|
// Final class, it is not meant to be derived any further |
| 157 |
|
|
~SyncMediator(); |
| 158 |
|
|
|
| 159 |
|
|
void Add(SharedPtr<SyncItem> entry); |
| 160 |
|
|
void Touch(SharedPtr<SyncItem> entry); |
| 161 |
|
|
void Remove(SharedPtr<SyncItem> entry); |
| 162 |
|
|
void Replace(SharedPtr<SyncItem> entry); |
| 163 |
|
|
void Clone(const std::string from, const std::string to); |
| 164 |
|
|
|
| 165 |
|
|
void AddUnmaterializedDirectory(SharedPtr<SyncItem> entry); |
| 166 |
|
|
|
| 167 |
|
|
void EnterDirectory(SharedPtr<SyncItem> entry); |
| 168 |
|
|
void LeaveDirectory(SharedPtr<SyncItem> entry); |
| 169 |
|
|
|
| 170 |
|
|
bool Commit(manifest::Manifest *manifest); |
| 171 |
|
|
|
| 172 |
|
|
// The sync union engine uses this information to create properly initialized |
| 173 |
|
|
// sync items |
| 174 |
|
✗ |
bool IsExternalData() const { return params_->external_data; } |
| 175 |
|
✗ |
bool IsDirectIo() const { return params_->direct_io; } |
| 176 |
|
✗ |
zlib::Algorithms GetCompressionAlgorithm() const { |
| 177 |
|
✗ |
return params_->compression_alg; |
| 178 |
|
|
} |
| 179 |
|
|
|
| 180 |
|
|
private: |
| 181 |
|
|
typedef std::stack<HardlinkGroupMap> HardlinkGroupMapStack; |
| 182 |
|
|
typedef std::vector<HardlinkGroup> HardlinkGroupList; |
| 183 |
|
|
|
| 184 |
|
|
void EnsureAllowed(SharedPtr<SyncItem> entry); |
| 185 |
|
|
|
| 186 |
|
|
// Called after figuring out the type of a path (file, symlink, dir) |
| 187 |
|
|
void AddFile(SharedPtr<SyncItem> entry); |
| 188 |
|
|
void RemoveFile(SharedPtr<SyncItem> entry); |
| 189 |
|
|
|
| 190 |
|
|
void AddDirectory(SharedPtr<SyncItem> entry); |
| 191 |
|
|
void RemoveDirectory(SharedPtr<SyncItem> entry); |
| 192 |
|
|
void TouchDirectory(SharedPtr<SyncItem> entry); |
| 193 |
|
|
|
| 194 |
|
|
void CreateNestedCatalog(SharedPtr<SyncItem> directory); |
| 195 |
|
|
void RemoveNestedCatalog(SharedPtr<SyncItem> directory); |
| 196 |
|
|
|
| 197 |
|
|
void TouchDirectoryRecursively(SharedPtr<SyncItem> entry); |
| 198 |
|
|
void TouchingFileCallback(const std::string &parent_dir, |
| 199 |
|
|
const std::string &file_name); |
| 200 |
|
|
void TouchingSymlinkCallback(const std::string &parent_dir, |
| 201 |
|
|
const std::string &link_name); |
| 202 |
|
|
void TouchDirectoryCallback(const std::string &parent_dir, |
| 203 |
|
|
const std::string &dir_name); |
| 204 |
|
|
void RemoveDirectoryRecursively(SharedPtr<SyncItem> entry); |
| 205 |
|
|
void RemoveFileCallback(const std::string &parent_dir, |
| 206 |
|
|
const std::string &file_name); |
| 207 |
|
|
void RemoveSymlinkCallback(const std::string &parent_dir, |
| 208 |
|
|
const std::string &link_name); |
| 209 |
|
|
void RemoveCharacterDeviceCallback(const std::string &parent_dir, |
| 210 |
|
|
const std::string &link_name); |
| 211 |
|
|
void RemoveBlockDeviceCallback(const std::string &parent_dir, |
| 212 |
|
|
const std::string &link_name); |
| 213 |
|
|
void RemoveFifoCallback(const std::string &parent_dir, |
| 214 |
|
|
const std::string &link_name); |
| 215 |
|
|
void RemoveSocketCallback(const std::string &parent_dir, |
| 216 |
|
|
const std::string &link_name); |
| 217 |
|
|
void RemoveDirectoryCallback(const std::string &parent_dir, |
| 218 |
|
|
const std::string &dir_name); |
| 219 |
|
|
bool IgnoreFileCallback(const std::string &parent_dir, |
| 220 |
|
|
const std::string &file_name); |
| 221 |
|
|
// Called by file system traversal |
| 222 |
|
|
void EnterAddedDirectoryCallback(const std::string &parent_dir, |
| 223 |
|
|
const std::string &dir_name); |
| 224 |
|
|
void LeaveAddedDirectoryCallback(const std::string &parent_dir, |
| 225 |
|
|
const std::string &dir_name); |
| 226 |
|
|
void AddDirectoryRecursively(SharedPtr<SyncItem> entry); |
| 227 |
|
|
bool AddDirectoryCallback(const std::string &parent_dir, |
| 228 |
|
|
const std::string &dir_name); |
| 229 |
|
|
void AddFileCallback(const std::string &parent_dir, |
| 230 |
|
|
const std::string &file_name); |
| 231 |
|
|
void AddCharacterDeviceCallback(const std::string &parent_dir, |
| 232 |
|
|
const std::string &file_name); |
| 233 |
|
|
void AddBlockDeviceCallback(const std::string &parent_dir, |
| 234 |
|
|
const std::string &file_name); |
| 235 |
|
|
void AddFifoCallback(const std::string &parent_dir, |
| 236 |
|
|
const std::string &file_name); |
| 237 |
|
|
void AddSocketCallback(const std::string &parent_dir, |
| 238 |
|
|
const std::string &file_name); |
| 239 |
|
|
void AddSymlinkCallback(const std::string &parent_dir, |
| 240 |
|
|
const std::string &link_name); |
| 241 |
|
|
SharedPtr<SyncItem> CreateSyncItem(const std::string &relative_parent_path, |
| 242 |
|
|
const std::string &filename, |
| 243 |
|
|
const SyncItemType entry_type) const; |
| 244 |
|
|
|
| 245 |
|
|
// Called by Upload Spooler |
| 246 |
|
|
void PublishFilesCallback(const upload::SpoolerResult &result); |
| 247 |
|
|
void PublishHardlinksCallback(const upload::SpoolerResult &result); |
| 248 |
|
|
|
| 249 |
|
|
// Hardlink handling |
| 250 |
|
|
void CompleteHardlinks(SharedPtr<SyncItem> entry); |
| 251 |
|
✗ |
HardlinkGroupMap &GetHardlinkMap() { return hardlink_stack_.top(); } |
| 252 |
|
|
void LegacyRegularHardlinkCallback(const std::string &parent_dir, |
| 253 |
|
|
const std::string &file_name); |
| 254 |
|
|
void LegacySymlinkHardlinkCallback(const std::string &parent_dir, |
| 255 |
|
|
const std::string &file_name); |
| 256 |
|
|
void LegacyCharacterDeviceHardlinkCallback(const std::string &parent_dir, |
| 257 |
|
|
const std::string &file_name); |
| 258 |
|
|
void LegacyBlockDeviceHardlinkCallback(const std::string &parent_dir, |
| 259 |
|
|
const std::string &file_name); |
| 260 |
|
|
void LegacyFifoHardlinkCallback(const std::string &parent_dir, |
| 261 |
|
|
const std::string &file_name); |
| 262 |
|
|
void LegacySocketHardlinkCallback(const std::string &parent_dir, |
| 263 |
|
|
const std::string &file_name); |
| 264 |
|
|
void InsertLegacyHardlink(SharedPtr<SyncItem> entry); |
| 265 |
|
|
uint64_t GetTemporaryHardlinkGroupNumber(SharedPtr<SyncItem> entry) const; |
| 266 |
|
|
void InsertHardlink(SharedPtr<SyncItem> entry); |
| 267 |
|
|
|
| 268 |
|
|
void AddLocalHardlinkGroups(const HardlinkGroupMap &hardlinks); |
| 269 |
|
|
void AddHardlinkGroup(const HardlinkGroup &group); |
| 270 |
|
|
|
| 271 |
|
|
catalog::WritableCatalogManager *catalog_manager_; |
| 272 |
|
|
SyncUnion *union_engine_; |
| 273 |
|
|
|
| 274 |
|
|
bool handle_hardlinks_; |
| 275 |
|
|
|
| 276 |
|
|
/** |
| 277 |
|
|
* Hardlinks are supported as long as they all reside in the same directory. |
| 278 |
|
|
* If a recursion enters a directory, we push an empty HardlinkGroupMap to |
| 279 |
|
|
* keep track of the hardlinks of this directory. |
| 280 |
|
|
* When leaving a directory (i.e. it is completely processed) the stack is |
| 281 |
|
|
* popped and the HardlinkGroupMap is processed. |
| 282 |
|
|
*/ |
| 283 |
|
|
HardlinkGroupMapStack hardlink_stack_; |
| 284 |
|
|
|
| 285 |
|
|
/** |
| 286 |
|
|
* New and modified files are sent to an external spooler for hashing and |
| 287 |
|
|
* compression. A spooler callback adds them to the catalogs, once processed. |
| 288 |
|
|
*/ |
| 289 |
|
|
pthread_mutex_t lock_file_queue_; |
| 290 |
|
|
SyncItemList file_queue_; |
| 291 |
|
|
|
| 292 |
|
|
HardlinkGroupList hardlink_queue_; |
| 293 |
|
|
|
| 294 |
|
|
const SyncParameters *params_; |
| 295 |
|
|
mutable unsigned int changed_items_; |
| 296 |
|
|
|
| 297 |
|
|
/** |
| 298 |
|
|
* By default, files have no extended attributes. |
| 299 |
|
|
*/ |
| 300 |
|
|
XattrList default_xattrs_; |
| 301 |
|
|
UniquePtr<perf::FsCounters> counters_; |
| 302 |
|
|
|
| 303 |
|
|
UniquePtr<SyncDiffReporter> reporter_; |
| 304 |
|
|
}; // class SyncMediator |
| 305 |
|
|
|
| 306 |
|
|
} // namespace publish |
| 307 |
|
|
|
| 308 |
|
|
#endif // CVMFS_SYNC_MEDIATOR_H_ |
| 309 |
|
|
|