CernVM-FS  2.13.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
swissknife_migrate.h
Go to the documentation of this file.
1 
5 #ifndef CVMFS_SWISSKNIFE_MIGRATE_H_
6 #define CVMFS_SWISSKNIFE_MIGRATE_H_
7 
8 #include <map>
9 #include <string>
10 #include <vector>
11 
12 #include "catalog.h"
13 #include "catalog_traversal.h"
14 #include "crypto/hash.h"
15 #include "history_sqlite.h"
16 #include "manifest.h"
17 #include "swissknife.h"
18 #include "uid_map.h"
19 #include "upload.h"
20 #include "util/algorithm.h"
21 #include "util/atomic.h"
22 #include "util/concurrency.h"
23 #include "util/future.h"
24 #include "util/logging.h"
25 #include "util/pointer.h"
26 
27 namespace catalog {
28 class WritableCatalog;
29 }
30 
31 namespace swissknife {
32 
33 class CommandMigrate : public Command {
34  protected:
37  : max_row_id(0)
38  , entry_count(0)
41  , migration_time(0.0) { }
42  unsigned int max_row_id;
43  unsigned int entry_count;
44 
45  unsigned int hardlink_group_count;
46  unsigned int aggregated_linkcounts;
47 
49 
50  std::string root_path;
51  };
52 
53  class CatalogStatisticsList : protected std::vector<CatalogStatistics>,
54  public Lockable {
55  friend class CommandMigrate;
56 
57  public:
58  inline void Insert(const CatalogStatistics &statistics) {
60  this->push_back(statistics);
61  }
62  };
63 
64  public:
66  typedef std::vector<PendingCatalog *> PendingCatalogList;
67  struct PendingCatalog {
69  : success(false)
71  , new_catalog(NULL)
72  , new_catalog_size(0) { }
73  virtual ~PendingCatalog();
74 
75  inline const std::string root_path() const {
76  return old_catalog->mountpoint().ToString();
77  }
78  inline bool IsRoot() const { return old_catalog->IsRoot(); }
79  inline bool HasNew() const { return new_catalog != NULL; }
80 
81  inline bool HasChanges() const {
82  return (new_catalog != NULL
84  }
85 
86  inline shash::Any GetOldContentHash() const { return old_catalog->hash(); }
87 
88  bool success;
89 
92 
96 
98 
99  // Note: As soon as the `was_updated` future is set to 'true', both
100  // `new_catalog_hash` and `new_catalog_size` are assumed to be set
101  // accordingly. If it is set to 'false' they will be ignored.
105  };
106 
108  : public std::map<std::string, const PendingCatalog *>,
109  public Lockable { };
110 
111  template<class DerivedT>
112  class AbstractMigrationWorker : public ConcurrentWorker<DerivedT> {
113  public:
116 
117  struct worker_context {
119  const bool collect_catalog_statistics)
120  : temporary_directory(temporary_directory)
121  , collect_catalog_statistics(collect_catalog_statistics) { }
122  const std::string temporary_directory;
124  };
125 
126  public:
127  explicit AbstractMigrationWorker(const worker_context *context);
128  virtual ~AbstractMigrationWorker();
129 
130  void operator()(const expected_data &data);
131 
132  protected:
133  bool RunMigration(PendingCatalog *data) const { return false; }
134 
136  bool UpdateCatalogMetadata(PendingCatalog *data) const;
137  bool CleanupNestedCatalogs(PendingCatalog *data) const;
139 
141  const catalog::Catalog *catalog) const;
142 
143  protected:
144  const std::string temporary_directory_;
146 
148  };
149 
151  : public AbstractMigrationWorker<MigrationWorker_20x> {
153 
154  protected:
155  static const float kSchema;
156  static const unsigned kSchemaRevision;
157 
158  public:
160  : AbstractMigrationWorker<MigrationWorker_20x>::worker_context {
162  const bool collect_catalog_statistics,
164  const bool analyze_file_linkcounts,
165  const uid_t uid,
166  const gid_t gid)
168  temporary_directory, collect_catalog_statistics)
169  , fix_nested_catalog_transitions(fix_nested_catalog_transitions)
170  , analyze_file_linkcounts(analyze_file_linkcounts)
171  , uid(uid)
172  , gid(gid) { }
175  const uid_t uid;
176  const gid_t gid;
177  };
178 
179  public:
180  explicit MigrationWorker_20x(const worker_context *context);
181 
182  protected:
183  bool RunMigration(PendingCatalog *data) const;
184 
185  bool CreateNewEmptyCatalog(PendingCatalog *data) const;
187  bool AttachOldCatalogDatabase(PendingCatalog *data) const;
188  bool StartDatabaseTransaction(PendingCatalog *data) const;
189  bool MigrateFileMetadata(PendingCatalog *data) const;
190  bool AnalyzeFileLinkcounts(PendingCatalog *data) const;
194  bool GenerateCatalogStatistics(PendingCatalog *data) const;
195  bool FindRootEntryInformation(PendingCatalog *data) const;
196  bool CommitDatabaseTransaction(PendingCatalog *data) const;
197  bool DetachOldCatalogDatabase(PendingCatalog *data) const;
198 
199  private:
202  const uid_t uid_;
203  const gid_t gid_;
204  };
205 
207  : public AbstractMigrationWorker<MigrationWorker_217> {
209 
210  public:
211  explicit MigrationWorker_217(const worker_context *context);
212 
213  protected:
214  bool RunMigration(PendingCatalog *data) const;
215 
217  bool StartDatabaseTransaction(PendingCatalog *data) const;
219  bool UpdateCatalogSchema(PendingCatalog *data) const;
220  bool CommitDatabaseTransaction(PendingCatalog *data) const;
221  };
222 
224  : public AbstractMigrationWorker<ChownMigrationWorker> {
226 
227  public:
229  : AbstractMigrationWorker<ChownMigrationWorker>::worker_context {
231  const bool collect_catalog_statistics,
232  const UidMap &uid_map,
233  const GidMap &gid_map)
235  temporary_directory, collect_catalog_statistics)
236  , uid_map(uid_map)
237  , gid_map(gid_map) { }
238  const UidMap &uid_map;
239  const GidMap &gid_map;
240  };
241 
242  public:
243  explicit ChownMigrationWorker(const worker_context *context);
244 
245  protected:
246  bool RunMigration(PendingCatalog *data) const;
247  bool ApplyPersonaMappings(PendingCatalog *data) const;
248 
249  private:
250  template<class MapT>
251  std::string GenerateMappingStatement(const MapT &map,
252  const std::string &column) const;
253 
254  private:
255  const std::string uid_map_statement_;
256  const std::string gid_map_statement_;
257  };
258 
260  : public AbstractMigrationWorker<HardlinkRemovalMigrationWorker> {
262 
263  public:
264  explicit HardlinkRemovalMigrationWorker(const worker_context *context)
266 
267  protected:
268  bool RunMigration(PendingCatalog *data) const;
269 
271  bool BreakUpHardlinks(PendingCatalog *data) const;
272  };
273 
275  : public AbstractMigrationWorker<BulkhashRemovalMigrationWorker> {
277 
278  public:
279  explicit BulkhashRemovalMigrationWorker(const worker_context *context)
281 
282  protected:
283  bool RunMigration(PendingCatalog *data) const;
284 
286  bool RemoveRedundantBulkHashes(PendingCatalog *data) const;
287  };
288 
289  // Regenerate / repair statistics counters
291  : public AbstractMigrationWorker<StatsMigrationWorker> {
293 
294  public:
295  explicit StatsMigrationWorker(const worker_context *context);
296 
297  protected:
298  bool RunMigration(PendingCatalog *data) const;
299 
301  bool StartDatabaseTransaction(PendingCatalog *data) const;
302  bool RepairStatisticsCounters(PendingCatalog *data) const;
303  bool CommitDatabaseTransaction(PendingCatalog *data) const;
304  };
305 
306  public:
307  CommandMigrate();
309  virtual std::string GetName() const { return "migrate"; }
310  virtual std::string GetDescription() const {
311  return "CernVM-FS catalog repository migration \n"
312  "This command migrates the whole catalog structure of a given "
313  "repository";
314  }
315  virtual ParameterList GetParams() const;
316 
317  int Main(const ArgumentList &args);
318 
320  const catalog::DirectoryEntry &nested_root,
321  catalog::DirectoryEntry *mountpoint);
323 
324  protected:
325  template<class ObjectFetcherT>
326  bool LoadCatalogs(const shash::Any &manual_root_hash,
327  ObjectFetcherT *object_fetcher) {
329  retval = object_fetcher->FetchManifest(&manifest_upstream_);
330  if (retval != ObjectFetcherFailures::kFailOk) {
331  LogCvmfs(kLogCvmfs, kLogStdout, "could not get manifest (%d)", retval);
332  return false;
333  }
334 
335  if (!manifest_upstream_->history().IsNull()) {
336  retval = object_fetcher->FetchHistory(&history_upstream_,
337  manifest_upstream_->history());
338  if (retval != ObjectFetcherFailures::kFailOk) {
339  LogCvmfs(kLogCvmfs, kLogStdout, "could not get history (%d)", retval);
340  return false;
341  }
342  }
343 
345  const bool generate_full_catalog_tree = true;
346  params.no_close = generate_full_catalog_tree;
347  params.object_fetcher = object_fetcher;
348  CatalogTraversal<ObjectFetcherT> traversal(params);
350 
351  if (manual_root_hash.IsNull())
352  return traversal.Traverse();
353  return traversal.Traverse(manual_root_hash);
354  }
355 
356  void CatalogCallback(
358  void MigrationCallback(PendingCatalog * const &data);
359  void UploadCallback(const upload::SpoolerResult &result);
360 
361  void PrintStatusMessage(const PendingCatalog *catalog,
362  const shash::Any &content_hash,
363  const std::string &message);
364 
365  template<class MigratorT>
366  bool DoMigrationAndCommit(const std::string &manifest_path,
367  typename MigratorT::worker_context *context);
368 
369  template<class MigratorT>
370  void ConvertCatalogsRecursively(PendingCatalog *catalog, MigratorT *migrator);
371  bool RaiseFileDescriptorLimit() const;
372  bool ConfigureSQLite() const;
373  void AnalyzeCatalogStatistics() const;
374  bool ReadPersona(const std::string &uid, const std::string &gid);
375  bool ReadPersonaMaps(const std::string &uid_map_path,
376  const std::string &gid_map_path,
377  UidMap *uid_map,
378  GidMap *gid_map) const;
379 
381  void CreateNestedCatalogMarkerDirent(const shash::Any &content_hash);
382 
383  void UploadHistoryClosure(const upload::SpoolerResult &result,
384  Future<shash::Any> *hash);
385  bool UpdateUndoTags(PendingCatalog *root_catalog,
386  uint64_t revision,
387  time_t timestamp,
388  shash::Any *history_hash);
389 
390  private:
393  unsigned int catalog_count_;
396 
397  uid_t uid_;
398  gid_t gid_;
399 
400  std::string temporary_directory_;
403 
409 
412 };
413 
414 } // namespace swissknife
415 
416 #endif // CVMFS_SWISSKNIFE_MIGRATE_H_
catalog::Catalog const * root_catalog_
void ConvertCatalogsRecursively(PendingCatalog *catalog, MigratorT *migrator)
bool UpdateCatalogMetadata(PendingCatalog *data) const
PendingCatalog(const catalog::Catalog *old_catalog=NULL)
bool AnalyzeFileLinkcounts(PendingCatalog *data) const
UniquePtr< upload::Spooler > spooler_
CallbackPtr RegisterListener(typename BoundClosure< CatalogTraversalData< ObjectFetcherT::CatalogTN >, DelegateT, ClosureDataT >::CallbackMethod method, DelegateT *delegate, ClosureDataT data)
PendingCatalogMap pending_catalogs_
bool IsNull() const
Definition: hash.h:371
bool ReadPersonaMaps(const std::string &uid_map_path, const std::string &gid_map_path, UidMap *uid_map, GidMap *gid_map) const
bool IsRoot() const
Definition: catalog.h:189
bool MigrateFileMetadata(PendingCatalog *data) const
bool UpdateCatalogSchema(PendingCatalog *data) const
void Insert(const CatalogStatistics &statistics)
bool FindRootEntryInformation(PendingCatalog *data) const
bool StartDatabaseTransaction(PendingCatalog *data) const
bool LoadCatalogs(const shash::Any &manual_root_hash, ObjectFetcherT *object_fetcher)
bool FixNestedCatalogTransitionPoints(PendingCatalog *data) const
virtual std::string GetName() const
std::vector< Parameter > ParameterList
Definition: swissknife.h:71
void CreateNestedCatalogMarkerDirent(const shash::Any &content_hash)
void UploadCallback(const upload::SpoolerResult &result)
bool UpdateUndoTags(PendingCatalog *root_catalog, uint64_t revision, time_t timestamp, shash::Any *history_hash)
static void FixNestedCatalogTransitionPoint(const catalog::DirectoryEntry &nested_root, catalog::DirectoryEntry *mountpoint)
virtual ParameterList GetParams() const
void PrintStatusMessage(const PendingCatalog *catalog, const shash::Any &content_hash, const std::string &message)
worker_context(const std::string &temporary_directory, const bool collect_catalog_statistics, const bool fix_nested_catalog_transitions, const bool analyze_file_linkcounts, const uid_t uid, const gid_t gid)
bool RemoveDanglingNestedMountpoints(PendingCatalog *data) const
static catalog::DirectoryEntry nested_catalog_marker_
bool AttachOldCatalogDatabase(PendingCatalog *data) const
bool ReadPersona(const std::string &uid, const std::string &gid)
bool MigrateNestedCatalogMountPoints(PendingCatalog *data) const
void CatalogCallback(const CatalogTraversalData< catalog::WritableCatalog > &data)
UniquePtr< history::SqliteHistory > history_upstream_
bool CommitDatabaseTransaction(PendingCatalog *data) const
int32_t atomic_int32
Definition: atomic.h:17
worker_context(const std::string &temporary_directory, const bool collect_catalog_statistics, const UidMap &uid_map, const GidMap &gid_map)
bool GenerateCatalogStatistics(PendingCatalog *data) const
void UploadHistoryClosure(const upload::SpoolerResult &result, Future< shash::Any > *hash)
Future< catalog::DirectoryEntry > root_entry
unsigned GetModifiedRowCount() const
Definition: sql_impl.h:350
std::string GenerateMappingStatement(const MapT &map, const std::string &column) const
bool RepairStatisticsCounters(PendingCatalog *data) const
bool CheckDatabaseSchemaCompatibility(PendingCatalog *data) const
std::vector< PendingCatalog * > PendingCatalogList
bool StartDatabaseTransaction(PendingCatalog *data) const
bool DetachOldCatalogDatabase(PendingCatalog *data) const
bool ApplyPersonaMappings(PendingCatalog *data) const
perf::Statistics * statistics()
Definition: server_tool.h:47
bool CommitDatabaseTransaction(PendingCatalog *data) const
static const catalog::DirectoryEntry & GetNestedCatalogMarkerDirent()
bool RunMigration(PendingCatalog *data) const
PathString mountpoint() const
Definition: catalog.h:175
virtual std::string GetDescription() const
Future< catalog::DeltaCounters > nested_statistics
bool CollectAndAggregateStatistics(PendingCatalog *data) const
bool Traverse(const TraversalType type=Base::kBreadthFirst)
worker_context(const std::string &temporary_directory, const bool collect_catalog_statistics)
bool GenerateNewStatisticsCounters(PendingCatalog *data) const
bool CommitDatabaseTransaction(PendingCatalog *data) const
bool RunMigration(PendingCatalog *data) const
std::string ToString() const
Definition: shortstring.h:139
int Main(const ArgumentList &args)
std::map< char, SharedPtr< std::string > > ArgumentList
Definition: swissknife.h:72
MigrationWorker_20x(const worker_context *context)
UniquePtr< manifest::Manifest > manifest_upstream_
bool CleanupNestedCatalogs(PendingCatalog *data) const
bool UpdateNestedCatalogReferences(PendingCatalog *data) const
bool CreateNewEmptyCatalog(PendingCatalog *data) const
CatalogStatisticsList catalog_statistics_list_
const CatalogDatabase & database() const
Definition: catalog.h:249
bool CheckDatabaseSchemaCompatibility(PendingCatalog *data) const
bool StartDatabaseTransaction(PendingCatalog *data) const
shash::Any hash() const
Definition: catalog.h:182
bool CheckDatabaseSchemaCompatibility(PendingCatalog *data) const
void MigrationCallback(PendingCatalog *const &data)
catalog::WritableCatalog * GetWritable(const catalog::Catalog *catalog) const
bool DoMigrationAndCommit(const std::string &manifest_path, typename MigratorT::worker_context *context)
CVMFS_EXPORT void LogCvmfs(const LogSource source, const int mask, const char *format,...)
Definition: logging.cc:545