10 #include <sys/resource.h>
24 namespace swissknife {
28 CommandMigrate::CommandMigrate() :
29 file_descriptor_limit_(8192),
31 has_committed_new_revision_(false),
43 "migration base version ( 2.0.x | 2.1.7 | chown | hardlink | bulkhash | "
46 "repository URL (absolute local path or remote URL)"));
50 "temporary directory for catalog decompress"));
52 "user id to be used for this repository"));
54 "group id to be used for this repository"));
64 "enable collection of catalog statistics"));
69 static void Error(
const std::string &message) {
74 static void Error(
const std::string &message,
76 const std::string err_msg = message +
"\n"
82 static void Error(
const std::string &message,
85 const std::string err_msg =
89 Error(err_msg, catalog);
95 const std::string &migration_base = *args.find(
'v')->second;
96 const std::string &repo_url = *args.find(
'r')->second;
97 const std::string &
spooler = *args.find(
'u')->second;
98 const std::string &manifest_path = *args.find(
'o')->second;
99 const std::string &tmp_dir = *args.find(
't')->second;
100 const std::string &uid = (args.count(
'p') > 0) ?
101 *args.find(
'p')->second :
103 const std::string &gid = (args.count(
'g') > 0) ?
104 *args.find(
'g')->second :
106 const std::string &repo_name = (args.count(
'n') > 0) ?
107 *args.find(
'n')->second :
109 const std::string &repo_keys = (args.count(
'k') > 0) ?
110 *args.find(
'k')->second :
112 const std::string &uid_map_path = (args.count(
'i') > 0) ?
113 *args.find(
'i')->second :
115 const std::string &gid_map_path = (args.count(
'j') > 0) ?
116 *args.find(
'j')->second :
118 const bool fix_transition_points = (args.count(
'f') > 0);
119 const bool analyze_file_linkcounts = (args.count(
'l') == 0);
120 const bool collect_catalog_statistics = (args.count(
's') > 0);
121 if (args.count(
'h') > 0) {
128 Error(
"Failed to raise file descriptor limits");
134 Error(
"Failed to preconfigure SQLite library");
141 spooler_ = upload::Spooler::Construct(spooler_definition);
143 Error(
"Failed to create upstream Spooler.");
152 bool loading_successful =
false;
156 const bool follow_redirects =
false;
157 const string proxy = (args.count(
'@') > 0) ? *args.find(
'@')->second :
"";
164 ObjectFetcher fetcher(repo_name,
170 loading_successful =
LoadCatalogs(manual_root_hash, &fetcher);
173 ObjectFetcher fetcher(repo_url, tmp_dir);
174 loading_successful =
LoadCatalogs(manual_root_hash, &fetcher);
178 if (!loading_successful) {
179 Error(
"Failed to load catalog tree");
187 bool migration_succeeded =
false;
188 if (migration_base ==
"2.0.x") {
195 Error(
"Failed to create a nested catalog marker.");
202 collect_catalog_statistics,
203 fix_transition_points,
204 analyze_file_linkcounts,
207 migration_succeeded =
208 DoMigrationAndCommit<MigrationWorker_20x>(manifest_path, &context);
209 }
else if (migration_base ==
"2.1.7") {
211 collect_catalog_statistics);
212 migration_succeeded =
213 DoMigrationAndCommit<MigrationWorker_217>(manifest_path, &context);
214 }
else if (migration_base ==
"chown") {
217 if (!
ReadPersonaMaps(uid_map_path, gid_map_path, &uid_map, &gid_map)) {
218 Error(
"Failed to read UID and/or GID map");
222 collect_catalog_statistics,
225 migration_succeeded =
226 DoMigrationAndCommit<ChownMigrationWorker>(manifest_path, &context);
227 }
else if (migration_base ==
"hardlink") {
228 HardlinkRemovalMigrationWorker::worker_context
230 migration_succeeded =
231 DoMigrationAndCommit<HardlinkRemovalMigrationWorker>(manifest_path,
233 }
else if (migration_base ==
"bulkhash") {
234 BulkhashRemovalMigrationWorker::worker_context
236 migration_succeeded =
237 DoMigrationAndCommit<BulkhashRemovalMigrationWorker>(manifest_path,
239 }
else if (migration_base ==
"stats") {
240 StatsMigrationWorker::worker_context context(
242 migration_succeeded =
243 DoMigrationAndCommit<StatsMigrationWorker>(manifest_path, &context);
245 const std::string err_msg =
"Unknown migration base: " + migration_base;
251 if (!migration_succeeded) {
252 Error(
"Migration failed!");
268 const std::string &gid) {
270 Error(
"Please provide a user ID");
274 Error(
"Please provide a group ID");
286 const std::string &gid_map_path,
288 GidMap *gid_map)
const {
289 if (!uid_map->Read(uid_map_path) || !uid_map->IsValid()) {
290 Error(
"Failed to read UID map");
294 if (!gid_map->Read(gid_map_path) || !gid_map->IsValid()) {
295 Error(
"Failed to read GID map");
299 if (uid_map->RuleCount() == 0 && !uid_map->HasDefault()) {
300 Error(
"UID map appears to be empty");
304 if (gid_map->RuleCount() == 0 && !gid_map->HasDefault()) {
305 Error(
"GID map appears to be empty");
335 string filename_new = filename_old +
".new";
337 if (!retval)
return false;
340 history->TakeDatabaseFileOwnership();
346 if (!retval)
return false;
358 retval = history->Insert(tag_trunk_previous);
359 if (!retval)
return false;
360 retval = history->Insert(tag_trunk);
361 if (!retval)
return false;
365 history->DropDatabaseFileOwnership();
369 upload::Spooler::CallbackPtr callback =
spooler_->RegisterListener(
371 spooler_->ProcessHistory(filename_new);
373 spooler_->UnregisterListener(callback);
374 unlink(filename_new.c_str());
375 *history_hash = history_hash_new.
Get();
376 if (history_hash->IsNull()) {
377 Error(
"failed to upload tag database");
385 template <
class MigratorT>
387 const std::string &manifest_path,
388 typename MigratorT::worker_context *context
395 Error(
"Failed to initialize worker migration system.");
415 "Catalog Migration finished with %d errors.", errors);
418 "\nCatalog Migration produced errors\nAborting...");
424 "\nCommitting migrated repository revision...");
439 "Updating repository tag database... ");
445 Error(
"Updating tag database failed.\nAborting...");
452 if (!manifest.
Export(manifest_path)) {
453 Error(
"Manifest export failed.\nAborting...");
459 "\nNo catalogs migrated, skipping the commit...");
471 std::string tree_indent;
472 std::string hash_string;
475 for (
unsigned int i = 1; i < data.
tree_level; ++i) {
476 tree_indent +=
"\u2502 ";
480 tree_indent +=
"\u251C\u2500 ";
503 Error(
"Catalog migration failed! Aborting...");
527 if (new_catalog_size <= 0) {
528 Error(
"Failed to get uncompressed file size of catalog!", data);
544 Error(
"Failed to upload file " + path +
"\nAborting...");
551 unlink(path.c_str());
582 const std::string &message) {
594 template <
class MigratorT>
596 MigratorT *migrator) {
600 catalog::CatalogList::const_iterator i = nested_catalogs.begin();
601 catalog::CatalogList::const_iterator iend = nested_catalogs.end();
603 for (; i != iend; ++i) {
610 migrator->Schedule(catalog);
616 memset(&rpl, 0,
sizeof(rpl));
617 getrlimit(RLIMIT_NOFILE, &rpl);
622 const bool retval = setrlimit(RLIMIT_NOFILE, &rpl);
632 int retval = sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
633 return (retval == SQLITE_OK);
639 unsigned int aggregated_entry_count = 0;
640 unsigned int aggregated_max_row_id = 0;
641 unsigned int aggregated_hardlink_count = 0;
642 unsigned int aggregated_linkcounts = 0;
643 double aggregated_migration_time = 0.0;
647 for (; i != iend; ++i) {
648 aggregated_entry_count += i->entry_count;
649 aggregated_max_row_id += i->max_row_id;
650 aggregated_hardlink_count += i->hardlink_group_count;
651 aggregated_linkcounts += i->aggregated_linkcounts;
652 aggregated_migration_time += i->migration_time;
656 assert(aggregated_max_row_id > 0);
657 const unsigned int unused_inodes =
658 aggregated_max_row_id - aggregated_entry_count;
660 (
static_cast<float>(unused_inodes) /
661 static_cast<float>(aggregated_max_row_id)) * 100.0f;
663 "Allocated Inodes: %d\n"
664 " Unused Inodes: %d\n"
665 " Percentage of wasted Inodes: %.1f%%\n",
666 aggregated_entry_count, aggregated_max_row_id, unused_inodes, ratio);
669 const float average_linkcount = (aggregated_hardlink_count > 0)
670 ? aggregated_linkcounts /
671 aggregated_hardlink_count
674 "Average Linkcount per Group: %.1f\n",
675 aggregated_hardlink_count, average_linkcount);
678 const double average_migration_time =
679 aggregated_migration_time /
static_cast<double>(number_of_catalogs);
681 "Average Migration Time: %.2fs\n"
682 "Overall Migration Time: %.2fs\n"
683 "Aggregated Migration Time: %.2fs\n",
685 average_migration_time,
687 aggregated_migration_time);
702 template<
class DerivedT>
706 , collect_catalog_statistics_(context->collect_catalog_statistics)
710 template<
class DerivedT>
714 template<
class DerivedT>
718 const bool success =
static_cast<DerivedT*
>(
this)->RunMigration(data) &&
719 UpdateNestedCatalogReferences(data) &&
720 UpdateCatalogMetadata(data) &&
721 CollectAndAggregateStatistics(data) &&
722 CleanupNestedCatalogs(data);
738 template<
class DerivedT>
747 "INSERT OR REPLACE INTO nested_catalogs (path, sha1, size) "
748 " VALUES (:path, :sha1, :size);");
755 for (; i != iend; ++i) {
762 const std::string &root_path = nested_catalog->
root_path();
768 add_nested_catalog.
BindText(1, root_path) &&
770 add_nested_catalog.
BindInt64(3, catalog_size) &&
773 Error(
"Failed to add nested catalog link", add_nested_catalog, data);
776 add_nested_catalog.
Reset();
783 template<
class DerivedT>
805 template<
class DerivedT>
809 if (!collect_catalog_statistics_) {
820 "SELECT COUNT(*), MAX(rowid) FROM catalog;");
823 Error(
"Failed to count entries in catalog", wasted_inodes, data);
826 const unsigned int entry_count = wasted_inodes.
RetrieveInt64(0);
827 const unsigned int max_row_id = wasted_inodes.
RetrieveInt64(1);
838 template<
class DerivedT>
846 for (; i != iend; ++i) {
865 template<
class DerivedT>
880 , fix_nested_catalog_transitions_(context->fix_nested_catalog_transitions)
881 , analyze_file_linkcounts_(context->analyze_file_linkcounts)
883 ,
gid_(context->gid) { }
894 return CreateNewEmptyCatalog(data) &&
895 CheckDatabaseSchemaCompatibility(data) &&
896 AttachOldCatalogDatabase(data) &&
897 StartDatabaseTransaction(data) &&
898 MigrateFileMetadata(data) &&
899 MigrateNestedCatalogMountPoints(data) &&
900 FixNestedCatalogTransitionPoints(data) &&
901 RemoveDanglingNestedMountpoints(data) &&
902 GenerateCatalogStatistics(data) &&
903 FindRootEntryInformation(data) &&
904 CommitDatabaseTransaction(data) &&
905 DetachOldCatalogDatabase(data);
911 const string root_path = data->
root_path();
914 const string clg_db_path =
916 if (clg_db_path.empty()) {
917 Error(
"Failed to create temporary file for the new catalog database.");
920 const bool volatile_content =
false;
929 Error(
"Failed to create database for new catalog");
930 unlink(clg_db_path.c_str());
939 if (writable_catalog == NULL) {
940 Error(
"Failed to open database for new catalog");
941 unlink(clg_db_path.c_str());
967 Error(
"Failed to meet database requirements for migration.", data);
981 "ATTACH '" + old_catalog.
filename() +
"' AS old;");
982 bool retval = sql_attach_new.
Execute();
989 Error(
"Failed to attach database of old catalog", sql_attach_new, data);
1024 "CREATE TEMPORARY TABLE hardlinks "
1025 " ( hardlink_group_id INTEGER PRIMARY KEY AUTOINCREMENT, "
1027 " linkcount INTEGER, "
1028 " CONSTRAINT unique_inode UNIQUE (inode) );");
1029 retval = sql_create_hardlinks_table.
Execute();
1031 Error(
"Failed to create temporary hardlink analysis table",
1032 sql_create_hardlinks_table, data);
1042 "CREATE TEMPORARY TABLE dir_linkcounts "
1043 " ( inode INTEGER PRIMARY KEY, "
1044 " linkcount INTEGER );");
1045 retval = sql_create_linkcounts_table.
Execute();
1047 Error(
"Failed to create tmeporary directory linkcount analysis table",
1048 sql_create_linkcounts_table, data);
1054 if (analyze_file_linkcounts_) {
1055 retval = AnalyzeFileLinkcounts(data);
1072 "INSERT INTO dir_linkcounts "
1073 " SELECT c1.inode as inode, "
1074 " SUM(IFNULL(MIN(c2.inode,1),0)) + 2 as linkcount "
1075 " FROM old.catalog as c1 "
1076 " LEFT JOIN old.catalog as c2 "
1077 " ON c2.parent_1 = c1.md5path_1 AND "
1078 " c2.parent_2 = c1.md5path_2 AND "
1079 " c2.flags & :flag_dir_1 "
1080 " WHERE c1.flags & :flag_dir_2 "
1081 " GROUP BY c1.inode;");
1087 Error(
"Failed to analyze directory specific linkcounts",
1088 sql_dir_linkcounts, data);
1089 if (sql_dir_linkcounts.
GetLastError() == SQLITE_CONSTRAINT) {
1090 Error(
"Obviously your catalogs are corrupted, since we found a directory"
1091 "inode that is a file inode at the same time!");
1103 "INSERT INTO catalog "
1104 " SELECT md5path_1, md5path_2, "
1105 " parent_1, parent_2, "
1106 " IFNULL(hardlink_group_id, 0) << 32 | "
1107 " COALESCE(hardlinks.linkcount, dir_linkcounts.linkcount, 1) "
1109 " hash, size, mode, mtime, "
1110 " flags, name, symlink, "
1114 " FROM old.catalog "
1115 " LEFT JOIN hardlinks "
1116 " ON catalog.inode = hardlinks.inode "
1117 " LEFT JOIN dir_linkcounts "
1118 " ON catalog.inode = dir_linkcounts.inode;");
1121 migrate_file_meta_data.
Execute();
1123 Error(
"Failed to migrate the file system meta data",
1124 migrate_file_meta_data, data);
1135 const std::string root_path = data->
root_path();
1136 const std::string file_path = root_path +
1142 retval = insert_nested_marker.
BindPathHash(path_hash) &&
1144 insert_nested_marker.
BindDirent(nested_marker) &&
1146 insert_nested_marker.
Execute();
1148 Error(
"Failed to insert nested catalog marker into new nested catalog.",
1149 insert_nested_marker, data);
1160 "INSERT OR REPLACE INTO properties "
1161 " SELECT key, value "
1162 " FROM old.properties "
1163 " WHERE key != 'schema';");
1164 retval = copy_properties.
Execute();
1166 Error(
"Failed to migrate the properties table.", copy_properties, data);
1195 "CREATE TEMPORARY TABLE hl_scratch AS "
1196 " SELECT c1.inode AS inode, c1.md5path_1, c1.md5path_2, "
1197 " c1.parent_1 as c1p1, c1.parent_2 as c1p2, "
1198 " c2.parent_1 as c2p1, c2.parent_2 as c2p2 "
1199 " FROM old.catalog AS c1 "
1200 " INNER JOIN old.catalog AS c2 "
1201 " ON c1.inode == c2.inode AND "
1202 " (c1.md5path_1 != c2.md5path_1 OR "
1203 " c1.md5path_2 != c2.md5path_2);");
1204 retval = sql_create_hardlinks_scratch_table.
Execute();
1206 Error(
"Failed to create temporary scratch table for hardlink analysis",
1207 sql_create_hardlinks_scratch_table, data);
1216 "INSERT INTO hardlinks (inode, linkcount)"
1217 " SELECT inode, count(*) as linkcount "
1223 " SELECT DISTINCT hl.inode, hl.md5path_1, hl.md5path_2 "
1230 " SELECT inode, count(*) AS cnt "
1238 " SELECT DISTINCT inode,c1p1,c1p1,c2p1,c2p2 "
1239 " FROM hl_scratch AS hl "
1244 " ) AS supported_hardlinks "
1245 " LEFT JOIN hl_scratch AS hl "
1246 " ON supported_hardlinks.inode = hl.inode "
1248 " GROUP BY inode;");
1249 retval = fill_linkcount_table_for_files.
Execute();
1251 Error(
"Failed to analyze hardlink relationships for files.",
1252 fill_linkcount_table_for_files, data);
1259 "DROP TABLE hl_scratch;");
1260 retval = drop_hardlink_scratch_space.
Execute();
1262 Error(
"Failed to remove file linkcount analysis scratch table",
1263 drop_hardlink_scratch_space, data);
1268 if (collect_catalog_statistics_) {
1270 "SELECT count(*), sum(linkcount) FROM hardlinks;");
1271 retval = count_hardlinks.
FetchRow();
1273 Error(
"Failed to count the generated file hardlinks for statistics",
1274 count_hardlinks, data);
1296 "SET hardlinks = :linkcount "
1297 "WHERE md5path_1 = :md5_1 AND md5path_2 = :md5_2;");
1302 PendingCatalogList::const_iterator iend = data->
nested_catalogs.end();
1303 for (; i != iend; ++i) {
1307 const string &root_path = nested_catalog->
root_path();
1315 update_mntpnt_linkcount.
BindMd5(2, 3, mountpoint_hash) &&
1316 update_mntpnt_linkcount.
Execute();
1318 Error(
"Failed to update linkcount of nested catalog mountpoint",
1319 update_mntpnt_linkcount, data);
1322 update_mntpnt_linkcount.
Reset();
1333 if (!fix_nested_catalog_transitions_) {
1348 PendingCatalogList::const_iterator iend = data->
nested_catalogs.end();
1349 for (; i != iend; ++i) {
1354 const string &nested_root_path = nested_catalog->
root_path();
1356 shash::Md5(nested_root_path.data(), nested_root_path.size());
1359 retval = lookup_mountpoint.
BindPathHash(mountpoint_path_hash) &&
1362 Error(
"Failed to fetch nested catalog mountpoint to check for compatible"
1363 "transition points", lookup_mountpoint, data);
1369 lookup_mountpoint.
Reset();
1373 mountpoint_entry.
CompareTo(nested_root_entry);
1378 assert(diffs & Difference::kNestedCatalogTransitionFlags);
1379 assert((diffs & Difference::kName) == 0);
1383 if ((diffs ^ Difference::kNestedCatalogTransitionFlags) != 0) {
1386 if ((diffs & Difference::kChecksum) ||
1387 (diffs & Difference::kLinkcount) ||
1388 (diffs & Difference::kSymlink) ||
1389 (diffs & Difference::kChunkedFileFlag) )
1391 Error(
"Found an irreparable mismatch in a nested catalog transition "
1392 "point at '" + nested_root_path +
"'\nAborting...\n");
1398 nested_root_entry, &mountpoint_entry);
1401 retval = update_directory_entry.
BindPathHash(mountpoint_path_hash) &&
1402 update_directory_entry.
BindDirent(mountpoint_entry) &&
1403 update_directory_entry.
Execute();
1405 Error(
"Failed to save resynchronized nested catalog mountpoint into "
1406 "catalog database", update_directory_entry, data);
1409 update_directory_entry.
Reset();
1414 "NOTE: fixed incompatible nested catalog transition point at: "
1415 "'%s' ", nested_root_path.c_str());
1432 mountpoint->
uid_ = nested_root.
uid_;
1433 mountpoint->
gid_ = nested_root.
gid_;
1444 bool retval =
false;
1448 typedef std::map<shash::Md5, catalog::Catalog::NestedCatalog>
1450 const NestedCatalogList& nested_clgs =
1452 NestedCatalogList::const_iterator i = nested_clgs.begin();
1453 const NestedCatalogList::const_iterator iend = nested_clgs.end();
1454 NestedCatalogMap nested_catalog_path_hashes;
1455 for (; i != iend; ++i) {
1458 nested_catalog_path_hashes[hash] = *i;
1466 std::vector<catalog::DirectoryEntry> todo_dirent;
1467 std::vector<shash::Md5> todo_hash;
1471 while (sql_dangling_mountpoints.
FetchRow()) {
1479 const NestedCatalogMap::const_iterator nested_catalog =
1480 nested_catalog_path_hashes.find(path_hash);
1481 if (nested_catalog != nested_catalog_path_hashes.end()) {
1483 "WARNING: found a non-empty nested catalog mountpoint under "
1484 "'%s'", nested_catalog->second.mountpoint.c_str());
1490 todo_dirent.push_back(dangling_mountpoint);
1491 todo_hash.push_back(path_hash);
1494 for (
unsigned i = 0; i < todo_dirent.size(); ++i) {
1495 retval = save_updated_mountpoint.
BindPathHash(todo_hash[i]) &&
1496 save_updated_mountpoint.
BindDirent(todo_dirent[i]) &&
1497 save_updated_mountpoint.
Execute() &&
1498 save_updated_mountpoint.
Reset();
1500 Error(
"Failed to remove dangling nested catalog mountpoint entry in "
1501 "catalog", save_updated_mountpoint, data);
1507 "mountpoint entry called: '%s' ",
1508 todo_dirent[i].name().c_str());
1526 Error(
"Failed to create temp file for nested catalog marker dummy.");
1559 bool retval =
false;
1567 PendingCatalogList::const_iterator iend = data->
nested_catalogs.end();
1568 for (; i != iend; ++i) {
1577 "SELECT count(*) FROM catalog "
1578 " WHERE flags & :flag_file "
1579 " AND NOT flags & :flag_link;");
1581 "SELECT count(*) FROM catalog WHERE flags & :flag_link;");
1583 "SELECT count(*) FROM catalog WHERE flags & :flag_dir;");
1585 "SELECT sum(size) FROM catalog WHERE flags & :flag_file "
1586 " AND NOT flags & :flag_link");
1594 Error(
"Failed to count regular files.", count_regular_files, data);
1601 Error(
"Failed to count symlinks.", count_symlinks, data);
1608 Error(
"Failed to count directories.", count_directories, data);
1616 Error(
"Failed to aggregate the file sizes.", aggregate_file_size, data);
1643 std::string root_path = data->
root_path();
1647 retval = lookup_root_entry.BindPathHash(root_path_hash) &&
1648 lookup_root_entry.FetchRow();
1650 Error(
"Failed to retrieve root directory entry of migrated catalog",
1651 lookup_root_entry, data);
1658 Error(
"Retrieved linkcount of catalog root entry is not sane.", data);
1682 const bool retval = detach_old_catalog.
Execute();
1684 Error(
"Failed to detach old catalog database.", detach_old_catalog, data);
1695 const worker_context *context)
1703 return CheckDatabaseSchemaCompatibility(data) &&
1704 StartDatabaseTransaction(data) &&
1705 GenerateNewStatisticsCounters(data) &&
1706 UpdateCatalogSchema(data) &&
1707 CommitDatabaseTransaction(data);
1717 if ((old_catalog.schema_version() < 2.4 -
1720 (old_catalog.schema_version() > 2.4 +
1723 Error(
"Given Catalog is not Schema 2.4.", data);
1743 bool retval =
false;
1752 PendingCatalogList::const_iterator iend = data->
nested_catalogs.end();
1753 for (; i != iend; ++i) {
1762 "SELECT count(*), sum(size) FROM catalog "
1763 " WHERE flags & :flag_chunked_file;");
1765 "SELECT count(*) FROM chunks;");
1767 "SELECT sum(size) FROM catalog WHERE flags & :flag_file "
1768 " AND NOT flags & :flag_link;");
1775 Error(
"Failed to count chunked files.", count_chunked_files, data);
1778 retval = count_file_chunks.
FetchRow();
1780 Error(
"Failed to count file chunks", count_file_chunks, data);
1788 Error(
"Failed to aggregate the file sizes.", aggregate_file_size, data);
1802 Error(
"Failed to read old catalog statistics counters", data);
1808 Error(
"Failed to write new statistics counters to database", data);
1825 "UPDATE properties SET value = :schema_version WHERE key = 'schema';");
1829 update_schema_version.
Execute();
1831 Error(
"Failed to update catalog schema version",
1832 update_schema_version,
1855 , uid_map_statement_(GenerateMappingStatement(context->uid_map,
"uid"))
1856 , gid_map_statement_(GenerateMappingStatement(context->gid_map,
"gid"))
1861 return ApplyPersonaMappings(data);
1886 Error(
"Failed to update UIDs", uid_sql, data);
1892 Error(
"Failed to update GIDs", gid_sql, data);
1900 template <
class MapT>
1903 const std::string &column)
const {
1904 assert(map.RuleCount() > 0 || map.HasDefault());
1906 std::string stmt =
"UPDATE OR ABORT catalog SET " + column +
" = ";
1908 if (map.RuleCount() == 0) {
1913 stmt +=
"CASE " + column +
" ";
1914 typedef typename MapT::map_type::const_iterator map_iterator;
1915 map_iterator i = map.GetRuleMap().begin();
1916 const map_iterator iend = map.GetRuleMap().end();
1917 for (; i != iend; ++i) {
1923 stmt += (map.HasDefault())
1925 :
"ELSE " + column +
" ";
1939 return CheckDatabaseSchemaCompatibility(data) &&
1940 BreakUpHardlinks(data);
1989 const std::string stmt =
"UPDATE OR ABORT catalog "
1990 "SET hardlinks = 1 "
1991 "WHERE flags & :file_flag "
1992 " AND hardlinks > 1;";
1995 hardlink_removal_sql.
Execute();
2005 return CheckDatabaseSchemaCompatibility(data) &&
2006 RemoveRedundantBulkHashes(data);
2035 const std::string stmt =
"UPDATE OR ABORT catalog "
2037 "WHERE flags & :file_chunked_flag;";
2040 bulkhash_removal_sql.
Execute();
2050 const worker_context *context)
2058 return CheckDatabaseSchemaCompatibility(data) &&
2059 StartDatabaseTransaction(data) &&
2060 RepairStatisticsCounters(data) &&
2061 CommitDatabaseTransaction(data);
2073 Error(
"Given catalog schema is < 2.5.", data);
2078 Error(
"Given catalog revision is < 5", data);
2099 bool retval =
false;
2108 PendingCatalogList::const_iterator iend = data->
nested_catalogs.end();
2109 for (; i != iend; ++i) {
2118 std::string(
"SELECT count(*), sum(size) FROM catalog ") +
2124 std::string(
"SELECT count(*), sum(size) FROM catalog ") +
2128 std::string(
"SELECT count(*) FROM catalog ") +
2131 std::string(
"SELECT count(*) FROM catalog ") +
2135 std::string(
"SELECT count(*) FROM catalog ") +
2136 "WHERE xattr IS NOT NULL;");
2138 std::string(
"SELECT count(*), sum(size) FROM catalog ") +
2141 std::string(
"SELECT count(*) FROM catalog ") +
2144 "SELECT count(*) FROM chunks;");
2146 retval = count_regular.
FetchRow() &&
2155 Error(
"Failed to collect catalog statistics", data);
2177 Error(
"Failed to write new statistics counters to database", data);
bool InsertIntoDatabase(const CatalogDatabase &database) const
uint32_t linkcount() const
catalog::Catalog const * root_catalog_
StopWatch migration_stopwatch_
int return_code
the return value of the spooler operation
void ConvertCatalogsRecursively(PendingCatalog *catalog, MigratorT *migrator)
void operator()(const expected_data &data)
static Parameter Optional(const char key, const std::string &desc)
bool UpdateCatalogMetadata(PendingCatalog *data) const
std::string GetLastErrorMsg() const
bool AnalyzeFileLinkcounts(PendingCatalog *data) const
UniquePtr< upload::Spooler > spooler_
CallbackPtr RegisterListener(typename BoundClosure< WorkerT::returned_data, DelegateT, ClosureDataT >::CallbackMethod method, DelegateT *delegate, ClosureDataT data)
PendingCatalogMap pending_catalogs_
static const unsigned kSchemaRevision
Differences CompareTo(const DirectoryEntry &other) const
bool ReadPersonaMaps(const std::string &uid_map_path, const std::string &gid_map_path, UidMap *uid_map, GidMap *gid_map) const
const manifest::Manifest * manifest() const
bool Export(const std::string &path) const
std::string nested_catalog_marker_tmp_path_
shash::Md5 GetPathHash() const
static Parameter Switch(const char key, const std::string &desc)
catalog::WritableCatalog * new_catalog
bool MigrateFileMetadata(PendingCatalog *data) const
bool UpdateCatalogSchema(PendingCatalog *data) const
FileChunkList file_chunks
the file chunks generated during processing
bool BindText(const int index, const std::string &value)
void Insert(const CatalogStatistics &statistics)
std::string database_path() const
void set_catalog_hash(const shash::Any &catalog_hash)
bool FindRootEntryInformation(PendingCatalog *data) const
const std::string & filename() const
const catalog::Catalog * old_catalog
ConcurrentWorkers< DerivedWorkerT > * master() const
void WaitForEmptyQueue() const
bool StartDatabaseTransaction(PendingCatalog *data) const
bool LoadCatalogs(const shash::Any &manual_root_hash, ObjectFetcherT *object_fetcher)
bool BindDirent(const DirectoryEntry &entry)
void AnalyzeCatalogStatistics() const
ChownMigrationWorker(const worker_context *context)
bool FixNestedCatalogTransitionPoints(PendingCatalog *data) const
static const std::string kPreviousHeadTag
MigrationWorker_217(const worker_context *context)
std::vector< Parameter > ParameterList
void CreateNestedCatalogMarkerDirent(const shash::Any &content_hash)
atomic_int32 catalogs_processed_
std::string ToString(const bool with_suffix=false) const
void Assign(const char *chars, const unsigned length)
void UploadCallback(const upload::SpoolerResult &result)
const history::History * history() const
void UpdateLastModified()
void ApplyDelta(const DeltaCounters &delta)
bool IsHttpUrl(const std::string &path)
DirectoryEntry GetDirent(const Catalog *catalog, const bool expand_symlink=true) const
bool BeginTransaction() const
std::string CreateTempPath(const std::string &path_prefix, const int mode)
unsigned int GetNumberOfCpuCores()
void set_revision(const uint64_t revision)
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
bool RunMigration(PendingCatalog *data) const
shash::Any new_catalog_hash
assert((mem||(size==0))&&"Out Of Memory")
static const int kFlagFileChunk
PendingCatalogList nested_catalogs
float schema_version() const
CatalogList GetChildren() const
void PrintStatusMessage(const PendingCatalog *catalog, const shash::Any &content_hash, const std::string &message)
upload::Spooler * spooler
void SetPreviousRevision(const shash::Any &hash)
bool RemoveDanglingNestedMountpoints(PendingCatalog *data) const
static const int kFlagFile
static catalog::DirectoryEntry nested_catalog_marker_
bool AttachOldCatalogDatabase(PendingCatalog *data) const
bool CopyPath2Path(const string &src, const string &dest)
bool ReadPersona(const std::string &uid, const std::string &gid)
const NestedCatalogList & ListNestedCatalogs() const
void Set(const T &object)
const std::string root_path() const
void JobSuccessful(const returned_data_t &data)
bool MigrateNestedCatalogMountPoints(PendingCatalog *data) const
shash::Any GetOldContentHash() const
unsigned schema_revision() const
void CatalogCallback(const CatalogTraversalData< catalog::WritableCatalog > &data)
UniquePtr< history::SqliteHistory > history_upstream_
bool ConfigureSQLite() const
static const int kFlagLink
static void Error(const std::string &message)
bool WriteToDatabase(const CatalogDatabase &database) const
unsigned int hardlink_group_count
bool IsNestedCatalogMountpoint() const
bool BindPathHash(const shash::Md5 &hash)
virtual ~AbstractMigrationWorker()
bool CommitDatabaseTransaction(PendingCatalog *data) const
static SqliteHistory * OpenWritable(const std::string &file_name)
static WritableCatalog * AttachFreely(const std::string &root_path, const std::string &file, const shash::Any &catalog_hash, Catalog *parent=NULL, const bool is_not_root=false)
uint64_t GetRevision() const
bool GenerateCatalogStatistics(PendingCatalog *data) const
StopWatch catalog_loading_stopwatch_
unsigned int file_descriptor_limit_
uint64_t GetLastModified() const
int64_t String2Int64(const string &value)
bool BindDouble(const int index, const double value)
bool CheckDatabaseSchemaCompatibility(PendingCatalog *data) const
void UploadHistoryClosure(const upload::SpoolerResult &result, Future< shash::Any > *hash)
std::string local_path
the local_path previously given as input
Future< catalog::DirectoryEntry > root_entry
std::string GenerateMappingStatement(const MapT &map, const std::string &column) const
static const std::string kPreviousHeadTagDescription
static const float kSchemaEpsilon
bool RepairStatisticsCounters(PendingCatalog *data) const
bool CheckDatabaseSchemaCompatibility(PendingCatalog *data) const
bool RunMigration(PendingCatalog *data) const
unsigned int catalog_count_
std::string temporary_directory_
static Parameter Mandatory(const char key, const std::string &desc)
bool StartDatabaseTransaction(PendingCatalog *data) const
bool DetachOldCatalogDatabase(PendingCatalog *data) const
const char kSuffixCatalog
bool ApplyPersonaMappings(PendingCatalog *data) const
static const int kFlagFileSpecial
AbstractMigrationWorker(const worker_context *context)
static const int kFlagFileExternal
bool CommitDatabaseTransaction(PendingCatalog *data) const
static const std::string kHeadTag
static const catalog::DirectoryEntry & GetNestedCatalogMarkerDirent()
void PopulateToParent(DeltaCounters *parent) const
const shash::Any catalog_hash
bool InsertInitialValues(const std::string &root_path, const bool volatile_content, const std::string &voms_authz, const DirectoryEntry &root_entry=DirectoryEntry(kDirentNegative))
sqlite3_int64 RetrieveInt64(const int idx_column) const
StatsMigrationWorker(const worker_context *context)
bool RunMigration(PendingCatalog *data) const
PathString mountpoint() const
bool CheckDatabaseSchemaCompatibility(PendingCatalog *data) const
bool BindPathHash(const struct shash::Md5 &hash)
string StringifyInt(const int64_t value)
bool GenerateNestedCatalogMarkerChunk()
bool CommitTransaction() const
bool ReadFromDatabase(const CatalogDatabase &database, const LegacyMode::Type legacy=LegacyMode::kNoLegacy)
bool BreakUpHardlinks(PendingCatalog *data) const
bool BindInt64(const int index, const sqlite3_int64 value)
Future< bool > was_updated
void set_history(const shash::Any &history_db)
Future< catalog::DeltaCounters > nested_statistics
bool CollectAndAggregateStatistics(PendingCatalog *data) const
std::vector< Catalog * > CatalogList
bool GenerateNewStatisticsCounters(PendingCatalog *data) const
void set_ttl(const uint32_t ttl)
bool CommitDatabaseTransaction(PendingCatalog *data) const
bool RunMigration(PendingCatalog *data) const
bool has_committed_new_revision_
std::string ToString() const
std::vector< NestedCatalog > NestedCatalogList
bool RemoveRedundantBulkHashes(PendingCatalog *data) const
int Main(const ArgumentList &args)
std::map< char, SharedPtr< std::string > > ArgumentList
ShortString< kDefaultMaxPath, 0 > PathString
virtual ~PendingCatalog()
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
void set_catalog_size(const uint64_t catalog_size)
CatalogStatisticsList catalog_statistics_list_
const CatalogDatabase & database() const
unsigned int GetNumberOfFailedJobs() const
Any MkFromHexPtr(const HexPtr hex, const char suffix)
int64_t GetFileSize(const std::string &path)
HttpObjectFetcher ObjectFetcher
unsigned int aggregated_linkcounts
bool CheckDatabaseSchemaCompatibility(PendingCatalog *data) const
CatalogStatistics statistics
static const float kLatestSupportedSchema
bool StartDatabaseTransaction(PendingCatalog *data) const
void JobFailed(const returned_data_t &data)
unsigned GetLength() const
static const char * kVirtualPath
bool CheckDatabaseSchemaCompatibility(PendingCatalog *data) const
bool BindMd5(const int idx_high, const int idx_low, const shash::Md5 &hash)
const char * GetChars() const
uint32_t hardlink_group() const
bool BindParentPathHash(const shash::Md5 &hash)
static const unsigned kLatestSchemaRevision
static const int kFlagDir
void MigrationCallback(PendingCatalog *const &data)
bool RunMigration(PendingCatalog *data) const
bool RaiseFileDescriptorLimit() const
void set_is_nested_catalog_mountpoint(const bool val)
bool BindPathHash(const shash::Md5 &hash)
catalog::WritableCatalog * GetWritable(const catalog::Catalog *catalog) const
const unsigned int tree_level
static DerivedT * Create(const std::string &filename)
bool DoMigrationAndCommit(const std::string &manifest_path, typename MigratorT::worker_context *context)
bool RunMigration(PendingCatalog *data) const
bool BindDirent(const DirectoryEntry &entry)
void set_root_path(const std::string &root_path)
static const float kSchema
CVMFS_EXPORT void LogCvmfs(const LogSource source, const int mask, const char *format,...)