10 #include <sys/resource.h>
24 namespace swissknife {
28 CommandMigrate::CommandMigrate()
29 : file_descriptor_limit_(8192)
31 , has_committed_new_revision_(false)
34 , root_catalog_(NULL) {
43 "migration base version ( 2.0.x | 2.1.7 | chown | hardlink | bulkhash | "
46 'r',
"repository URL (absolute local path or remote URL)"));
69 static void Error(
const std::string &message) {
74 static void Error(
const std::string &message,
76 const std::string err_msg = message
84 static void Error(
const std::string &message,
87 const std::string err_msg = message
92 Error(err_msg, catalog);
98 const std::string &migration_base = *args.find(
'v')->second;
99 const std::string &repo_url = *args.find(
'r')->second;
100 const std::string &
spooler = *args.find(
'u')->second;
101 const std::string &manifest_path = *args.find(
'o')->second;
102 const std::string &tmp_dir = *args.find(
't')->second;
103 const std::string &uid = (args.count(
'p') > 0) ? *args.find(
'p')->second :
"";
104 const std::string &gid = (args.count(
'g') > 0) ? *args.find(
'g')->second :
"";
105 const std::string &repo_name = (args.count(
'n') > 0) ? *args.find(
'n')->second
107 const std::string &repo_keys = (args.count(
'k') > 0) ? *args.find(
'k')->second
109 const std::string &uid_map_path = (args.count(
'i') > 0)
110 ? *args.find(
'i')->second
112 const std::string &gid_map_path = (args.count(
'j') > 0)
113 ? *args.find(
'j')->second
115 const bool fix_transition_points = (args.count(
'f') > 0);
116 const bool analyze_file_linkcounts = (args.count(
'l') == 0);
117 const bool collect_catalog_statistics = (args.count(
's') > 0);
118 if (args.count(
'h') > 0) {
125 Error(
"Failed to raise file descriptor limits");
131 Error(
"Failed to preconfigure SQLite library");
138 spooler_ = upload::Spooler::Construct(spooler_definition);
140 Error(
"Failed to create upstream Spooler.");
149 bool loading_successful =
false;
153 const bool follow_redirects =
false;
154 const string proxy = (args.count(
'@') > 0) ? *args.find(
'@')->second :
"";
161 ObjectFetcher fetcher(
164 loading_successful =
LoadCatalogs(manual_root_hash, &fetcher);
167 ObjectFetcher fetcher(repo_url, tmp_dir);
168 loading_successful =
LoadCatalogs(manual_root_hash, &fetcher);
172 if (!loading_successful) {
173 Error(
"Failed to load catalog tree");
181 bool migration_succeeded =
false;
182 if (migration_base ==
"2.0.x") {
189 Error(
"Failed to create a nested catalog marker.");
196 collect_catalog_statistics,
197 fix_transition_points,
198 analyze_file_linkcounts,
201 migration_succeeded = DoMigrationAndCommit<MigrationWorker_20x>(
202 manifest_path, &context);
203 }
else if (migration_base ==
"2.1.7") {
205 collect_catalog_statistics);
206 migration_succeeded = DoMigrationAndCommit<MigrationWorker_217>(
207 manifest_path, &context);
208 }
else if (migration_base ==
"chown") {
211 if (!
ReadPersonaMaps(uid_map_path, gid_map_path, &uid_map, &gid_map)) {
212 Error(
"Failed to read UID and/or GID map");
217 migration_succeeded = DoMigrationAndCommit<ChownMigrationWorker>(
218 manifest_path, &context);
219 }
else if (migration_base ==
"hardlink") {
220 HardlinkRemovalMigrationWorker::worker_context context(
222 migration_succeeded = DoMigrationAndCommit<HardlinkRemovalMigrationWorker>(
223 manifest_path, &context);
224 }
else if (migration_base ==
"bulkhash") {
225 BulkhashRemovalMigrationWorker::worker_context context(
227 migration_succeeded = DoMigrationAndCommit<BulkhashRemovalMigrationWorker>(
228 manifest_path, &context);
229 }
else if (migration_base ==
"stats") {
231 collect_catalog_statistics);
232 migration_succeeded = DoMigrationAndCommit<StatsMigrationWorker>(
233 manifest_path, &context);
235 const std::string err_msg =
"Unknown migration base: " + migration_base;
241 if (!migration_succeeded) {
242 Error(
"Migration failed!");
258 const std::string &gid) {
260 Error(
"Please provide a user ID");
264 Error(
"Please provide a group ID");
275 const std::string &gid_map_path,
277 GidMap *gid_map)
const {
278 if (!uid_map->Read(uid_map_path) || !uid_map->IsValid()) {
279 Error(
"Failed to read UID map");
283 if (!gid_map->Read(gid_map_path) || !gid_map->IsValid()) {
284 Error(
"Failed to read GID map");
288 if (uid_map->RuleCount() == 0 && !uid_map->HasDefault()) {
289 Error(
"UID map appears to be empty");
293 if (gid_map->RuleCount() == 0 && !gid_map->HasDefault()) {
294 Error(
"GID map appears to be empty");
320 const string filename_new = filename_old +
".new";
326 history->TakeDatabaseFileOwnership();
345 retval = history->Insert(tag_trunk_previous);
348 retval = history->Insert(tag_trunk);
354 history->DropDatabaseFileOwnership();
358 upload::Spooler::CallbackPtr callback =
spooler_->RegisterListener(
360 spooler_->ProcessHistory(filename_new);
362 spooler_->UnregisterListener(callback);
363 unlink(filename_new.c_str());
364 *history_hash = history_hash_new.
Get();
365 if (history_hash->IsNull()) {
366 Error(
"failed to upload tag database");
374 template<
class MigratorT>
376 const std::string &manifest_path,
377 typename MigratorT::worker_context *context) {
383 Error(
"Failed to initialize worker migration system.");
403 "Catalog Migration finished with %d errors.", errors);
406 "\nCatalog Migration produced errors\nAborting...");
412 "\nCommitting migrated repository revision...");
427 "Updating repository tag database... ");
432 Error(
"Updating tag database failed.\nAborting...");
439 if (!manifest.
Export(manifest_path)) {
440 Error(
"Manifest export failed.\nAborting...");
446 "\nNo catalogs migrated, skipping the commit...");
458 std::string tree_indent;
459 std::string hash_string;
462 for (
unsigned int i = 1; i < data.
tree_level; ++i) {
463 tree_indent +=
"\u2502 ";
467 tree_indent +=
"\u251C\u2500 ";
479 hash_string.c_str(), path.c_str());
488 Error(
"Catalog migration failed! Aborting...");
512 if (new_catalog_size <= 0) {
513 Error(
"Failed to get uncompressed file size of catalog!", data);
529 Error(
"Failed to upload file " + path +
"\nAborting...");
536 unlink(path.c_str());
567 const std::string &message) {
572 message.c_str(), content_hash.
ToString().c_str(),
577 template<
class MigratorT>
579 MigratorT *migrator) {
583 catalog::CatalogList::const_iterator i = nested_catalogs.begin();
584 const catalog::CatalogList::const_iterator iend = nested_catalogs.end();
586 for (; i != iend; ++i) {
593 migrator->Schedule(catalog);
599 memset(&rpl, 0,
sizeof(rpl));
600 getrlimit(RLIMIT_NOFILE, &rpl);
605 const bool retval = setrlimit(RLIMIT_NOFILE, &rpl);
615 const int retval = sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
616 return (retval == SQLITE_OK);
622 unsigned int aggregated_entry_count = 0;
623 unsigned int aggregated_max_row_id = 0;
624 unsigned int aggregated_hardlink_count = 0;
625 unsigned int aggregated_linkcounts = 0;
626 double aggregated_migration_time = 0.0;
629 const CatalogStatisticsList::const_iterator iend =
631 for (; i != iend; ++i) {
632 aggregated_entry_count += i->entry_count;
633 aggregated_max_row_id += i->max_row_id;
634 aggregated_hardlink_count += i->hardlink_group_count;
635 aggregated_linkcounts += i->aggregated_linkcounts;
636 aggregated_migration_time += i->migration_time;
640 assert(aggregated_max_row_id > 0);
641 const unsigned int unused_inodes = aggregated_max_row_id
642 - aggregated_entry_count;
643 const float ratio = (
static_cast<float>(unused_inodes)
644 / static_cast<float>(aggregated_max_row_id))
647 "Actual Entries: %d\n"
648 "Allocated Inodes: %d\n"
649 " Unused Inodes: %d\n"
650 " Percentage of wasted Inodes: %.1f%%\n",
651 aggregated_entry_count, aggregated_max_row_id, unused_inodes, ratio);
654 const float average_linkcount = (aggregated_hardlink_count > 0)
655 ? aggregated_linkcounts
656 / aggregated_hardlink_count
659 "Generated Hardlink Groups: %d\n"
660 "Average Linkcount per Group: %.1f\n",
661 aggregated_hardlink_count, average_linkcount);
664 const double average_migration_time = aggregated_migration_time
665 /
static_cast<double>(
668 "Catalog Loading Time: %.2fs\n"
669 "Average Migration Time: %.2fs\n"
670 "Overall Migration Time: %.2fs\n"
671 "Aggregated Migration Time: %.2fs\n",
688 template<
class DerivedT>
692 , collect_catalog_statistics_(context->collect_catalog_statistics) { }
695 template<
class DerivedT>
700 template<
class DerivedT>
704 const bool success =
static_cast<DerivedT *
>(
this)->RunMigration(data)
705 && UpdateNestedCatalogReferences(data)
706 && UpdateCatalogMetadata(data)
707 && CollectAndAggregateStatistics(data)
708 && CleanupNestedCatalogs(data);
724 template<
class DerivedT>
733 "INSERT OR REPLACE INTO nested_catalogs (path, sha1, size) "
734 " VALUES (:path, :sha1, :size);");
740 const PendingCatalogList::const_iterator iend = data->
nested_catalogs.end();
741 for (; i != iend; ++i) {
748 const std::string &root_path = nested_catalog->
root_path();
753 const bool retval = add_nested_catalog.
BindText(1, root_path)
756 && add_nested_catalog.
BindInt64(3, catalog_size)
757 && add_nested_catalog.
Execute();
759 Error(
"Failed to add nested catalog link", add_nested_catalog, data);
762 add_nested_catalog.
Reset();
769 template<
class DerivedT>
791 template<
class DerivedT>
794 if (!collect_catalog_statistics_) {
805 writable,
"SELECT COUNT(*), MAX(rowid) FROM catalog;");
808 Error(
"Failed to count entries in catalog", wasted_inodes, data);
811 const unsigned int entry_count = wasted_inodes.
RetrieveInt64(0);
812 const unsigned int max_row_id = wasted_inodes.
RetrieveInt64(1);
823 template<
class DerivedT>
829 const PendingCatalogList::const_iterator iend = data->
nested_catalogs.end();
830 for (; i != iend; ++i) {
849 template<
class DerivedT>
864 , fix_nested_catalog_transitions_(context->fix_nested_catalog_transitions)
865 , analyze_file_linkcounts_(context->analyze_file_linkcounts)
867 ,
gid_(context->gid) { }
877 return CreateNewEmptyCatalog(data) && CheckDatabaseSchemaCompatibility(data)
878 && AttachOldCatalogDatabase(data) && StartDatabaseTransaction(data)
879 && MigrateFileMetadata(data) && MigrateNestedCatalogMountPoints(data)
880 && FixNestedCatalogTransitionPoints(data)
881 && RemoveDanglingNestedMountpoints(data)
882 && GenerateCatalogStatistics(data) && FindRootEntryInformation(data)
883 && CommitDatabaseTransaction(data) && DetachOldCatalogDatabase(data);
888 const string root_path = data->
root_path();
893 if (clg_db_path.empty()) {
894 Error(
"Failed to create temporary file for the new catalog database.");
897 const bool volatile_content =
false;
906 Error(
"Failed to create database for new catalog");
907 unlink(clg_db_path.c_str());
916 if (writable_catalog == NULL) {
917 Error(
"Failed to open database for new catalog");
918 unlink(clg_db_path.c_str());
940 Error(
"Failed to meet database requirements for migration.", data);
953 new_catalog,
"ATTACH '" + old_catalog.
filename() +
"' AS old;");
954 const bool retval = sql_attach_new.
Execute();
961 Error(
"Failed to attach database of old catalog", sql_attach_new, data);
995 "CREATE TEMPORARY TABLE hardlinks "
996 " ( hardlink_group_id INTEGER PRIMARY KEY AUTOINCREMENT, "
998 " linkcount INTEGER, "
999 " CONSTRAINT unique_inode UNIQUE (inode) );");
1000 retval = sql_create_hardlinks_table.
Execute();
1002 Error(
"Failed to create temporary hardlink analysis table",
1003 sql_create_hardlinks_table, data);
1014 "CREATE TEMPORARY TABLE dir_linkcounts "
1015 " ( inode INTEGER PRIMARY KEY, "
1016 " linkcount INTEGER );");
1017 retval = sql_create_linkcounts_table.
Execute();
1019 Error(
"Failed to create tmeporary directory linkcount analysis table",
1020 sql_create_linkcounts_table, data);
1026 if (analyze_file_linkcounts_) {
1027 retval = AnalyzeFileLinkcounts(data);
1045 "INSERT INTO dir_linkcounts "
1046 " SELECT c1.inode as inode, "
1047 " SUM(IFNULL(MIN(c2.inode,1),0)) + 2 as linkcount "
1048 " FROM old.catalog as c1 "
1049 " LEFT JOIN old.catalog as c2 "
1050 " ON c2.parent_1 = c1.md5path_1 AND "
1051 " c2.parent_2 = c1.md5path_2 AND "
1052 " c2.flags & :flag_dir_1 "
1053 " WHERE c1.flags & :flag_dir_2 "
1054 " GROUP BY c1.inode;");
1057 && sql_dir_linkcounts.
Execute();
1059 Error(
"Failed to analyze directory specific linkcounts", sql_dir_linkcounts,
1061 if (sql_dir_linkcounts.
GetLastError() == SQLITE_CONSTRAINT) {
1062 Error(
"Obviously your catalogs are corrupted, since we found a directory"
1063 "inode that is a file inode at the same time!");
1076 "INSERT INTO catalog "
1077 " SELECT md5path_1, md5path_2, "
1078 " parent_1, parent_2, "
1079 " IFNULL(hardlink_group_id, 0) << 32 | "
1080 " COALESCE(hardlinks.linkcount, dir_linkcounts.linkcount, 1) "
1082 " hash, size, mode, mtime, NULL, "
1083 " flags, name, symlink, "
1087 " FROM old.catalog "
1088 " LEFT JOIN hardlinks "
1089 " ON catalog.inode = hardlinks.inode "
1090 " LEFT JOIN dir_linkcounts "
1091 " ON catalog.inode = dir_linkcounts.inode;");
1094 && migrate_file_meta_data.
Execute();
1096 Error(
"Failed to migrate the file system meta data", migrate_file_meta_data,
1108 const std::string root_path = data->
root_path();
1109 const std::string file_path = root_path +
"/"
1117 && insert_nested_marker.
BindDirent(nested_marker)
1119 && insert_nested_marker.
Execute();
1121 Error(
"Failed to insert nested catalog marker into new nested catalog.",
1122 insert_nested_marker, data);
1133 "INSERT OR REPLACE INTO properties "
1134 " SELECT key, value "
1135 " FROM old.properties "
1136 " WHERE key != 'schema';");
1137 retval = copy_properties.
Execute();
1139 Error(
"Failed to migrate the properties table.", copy_properties, data);
1168 "CREATE TEMPORARY TABLE hl_scratch AS "
1169 " SELECT c1.inode AS inode, c1.md5path_1, c1.md5path_2, "
1170 " c1.parent_1 as c1p1, c1.parent_2 as c1p2, "
1171 " c2.parent_1 as c2p1, c2.parent_2 as c2p2 "
1172 " FROM old.catalog AS c1 "
1173 " INNER JOIN old.catalog AS c2 "
1174 " ON c1.inode == c2.inode AND "
1175 " (c1.md5path_1 != c2.md5path_1 OR "
1176 " c1.md5path_2 != c2.md5path_2);");
1177 retval = sql_create_hardlinks_scratch_table.
Execute();
1179 Error(
"Failed to create temporary scratch table for hardlink analysis",
1180 sql_create_hardlinks_scratch_table, data);
1190 "INSERT INTO hardlinks (inode, linkcount)"
1191 " SELECT inode, count(*) as linkcount "
1197 " SELECT DISTINCT hl.inode, hl.md5path_1, hl.md5path_2 "
1204 " SELECT inode, count(*) AS cnt "
1212 " SELECT DISTINCT inode,c1p1,c1p1,c2p1,c2p2 "
1213 " FROM hl_scratch AS hl "
1218 " ) AS supported_hardlinks "
1219 " LEFT JOIN hl_scratch AS hl "
1220 " ON supported_hardlinks.inode = hl.inode "
1222 " GROUP BY inode;");
1223 retval = fill_linkcount_table_for_files.
Execute();
1225 Error(
"Failed to analyze hardlink relationships for files.",
1226 fill_linkcount_table_for_files, data);
1233 "DROP TABLE hl_scratch;");
1234 retval = drop_hardlink_scratch_space.
Execute();
1236 Error(
"Failed to remove file linkcount analysis scratch table",
1237 drop_hardlink_scratch_space, data);
1242 if (collect_catalog_statistics_) {
1244 writable,
"SELECT count(*), sum(linkcount) FROM hardlinks;");
1245 retval = count_hardlinks.
FetchRow();
1247 Error(
"Failed to count the generated file hardlinks for statistics",
1248 count_hardlinks, data);
1270 "SET hardlinks = :linkcount "
1271 "WHERE md5path_1 = :md5_1 AND md5path_2 = :md5_2;");
1276 const PendingCatalogList::const_iterator iend = data->
nested_catalogs.end();
1277 for (; i != iend; ++i) {
1281 const string &root_path = nested_catalog->
root_path();
1288 && update_mntpnt_linkcount.
BindMd5(2, 3, mountpoint_hash)
1289 && update_mntpnt_linkcount.
Execute();
1291 Error(
"Failed to update linkcount of nested catalog mountpoint",
1292 update_mntpnt_linkcount, data);
1295 update_mntpnt_linkcount.
Reset();
1305 if (!fix_nested_catalog_transitions_) {
1320 const PendingCatalogList::const_iterator iend = data->
nested_catalogs.end();
1321 for (; i != iend; ++i) {
1326 const string &nested_root_path = nested_catalog->
root_path();
1328 nested_root_path.size());
1331 retval = lookup_mountpoint.
BindPathHash(mountpoint_path_hash)
1334 Error(
"Failed to fetch nested catalog mountpoint to check for compatible"
1335 "transition points",
1336 lookup_mountpoint, data);
1342 lookup_mountpoint.
Reset();
1346 mountpoint_entry.
CompareTo(nested_root_entry);
1351 assert(diffs & Difference::kNestedCatalogTransitionFlags);
1352 assert((diffs & Difference::kName) == 0);
1356 if ((diffs ^ Difference::kNestedCatalogTransitionFlags) != 0) {
1359 if ((diffs & Difference::kChecksum) || (diffs & Difference::kLinkcount)
1360 || (diffs & Difference::kSymlink)
1361 || (diffs & Difference::kChunkedFileFlag)) {
1362 Error(
"Found an irreparable mismatch in a nested catalog transition "
1364 + nested_root_path +
"'\nAborting...\n");
1373 retval = update_directory_entry.
BindPathHash(mountpoint_path_hash)
1374 && update_directory_entry.
BindDirent(mountpoint_entry)
1375 && update_directory_entry.
Execute();
1377 Error(
"Failed to save resynchronized nested catalog mountpoint into "
1379 update_directory_entry, data);
1382 update_directory_entry.
Reset();
1387 "NOTE: fixed incompatible nested catalog transition point at: "
1389 nested_root_path.c_str());
1405 mountpoint->
uid_ = nested_root.
uid_;
1406 mountpoint->
gid_ = nested_root.
gid_;
1416 bool retval =
false;
1420 typedef std::map<shash::Md5, catalog::Catalog::NestedCatalog>
1422 const NestedCatalogList &nested_clgs = data->
old_catalog
1424 NestedCatalogList::const_iterator i = nested_clgs.begin();
1425 const NestedCatalogList::const_iterator iend = nested_clgs.end();
1426 NestedCatalogMap nested_catalog_path_hashes;
1427 for (; i != iend; ++i) {
1430 nested_catalog_path_hashes[hash] = *i;
1438 std::vector<catalog::DirectoryEntry> todo_dirent;
1439 std::vector<shash::Md5> todo_hash;
1443 while (sql_dangling_mountpoints.
FetchRow()) {
1452 const NestedCatalogMap::const_iterator
1453 nested_catalog = nested_catalog_path_hashes.find(path_hash);
1454 if (nested_catalog != nested_catalog_path_hashes.end()) {
1456 "WARNING: found a non-empty nested catalog mountpoint under "
1458 nested_catalog->second.mountpoint.c_str());
1464 todo_dirent.push_back(dangling_mountpoint);
1465 todo_hash.push_back(path_hash);
1468 for (
unsigned i = 0; i < todo_dirent.size(); ++i) {
1469 retval = save_updated_mountpoint.
BindPathHash(todo_hash[i])
1470 && save_updated_mountpoint.
BindDirent(todo_dirent[i])
1471 && save_updated_mountpoint.
Execute()
1472 && save_updated_mountpoint.
Reset();
1474 Error(
"Failed to remove dangling nested catalog mountpoint entry in "
1476 save_updated_mountpoint, data);
1482 "NOTE: fixed dangling nested catalog "
1483 "mountpoint entry called: '%s' ",
1484 todo_dirent[i].name().c_str());
1502 Error(
"Failed to create temp file for nested catalog marker dummy.");
1533 bool retval =
false;
1541 const PendingCatalogList::const_iterator iend = data->
nested_catalogs.end();
1542 for (; i != iend; ++i) {
1552 "SELECT count(*) FROM catalog "
1553 " WHERE flags & :flag_file "
1554 " AND NOT flags & :flag_link;");
1556 writable,
"SELECT count(*) FROM catalog WHERE flags & :flag_link;");
1558 writable,
"SELECT count(*) FROM catalog WHERE flags & :flag_dir;");
1561 "SELECT sum(size) FROM catalog WHERE flags & :flag_file "
1562 " AND NOT flags & :flag_link");
1569 Error(
"Failed to count regular files.", count_regular_files, data);
1575 Error(
"Failed to count symlinks.", count_symlinks, data);
1581 Error(
"Failed to count directories.", count_directories, data);
1588 Error(
"Failed to aggregate the file sizes.", aggregate_file_size, data);
1614 std::string root_path = data->
root_path();
1616 shash::Md5(root_path.data(), root_path.size());
1619 retval = lookup_root_entry.BindPathHash(root_path_hash)
1620 && lookup_root_entry.FetchRow();
1622 Error(
"Failed to retrieve root directory entry of migrated catalog",
1623 lookup_root_entry, data);
1630 Error(
"Retrieved linkcount of catalog root entry is not sane.", data);
1652 const bool retval = detach_old_catalog.
Execute();
1654 Error(
"Failed to detach old catalog database.", detach_old_catalog, data);
1665 const worker_context *context)
1671 return CheckDatabaseSchemaCompatibility(data)
1672 && StartDatabaseTransaction(data)
1673 && GenerateNewStatisticsCounters(data) && UpdateCatalogSchema(data)
1674 && CommitDatabaseTransaction(data);
1683 if ((old_catalog.schema_version()
1685 || (old_catalog.schema_version()
1687 Error(
"Given Catalog is not Schema 2.4.", data);
1706 bool retval =
false;
1715 const PendingCatalogList::const_iterator iend = data->
nested_catalogs.end();
1716 for (; i != iend; ++i) {
1726 "SELECT count(*), sum(size) FROM catalog "
1727 " WHERE flags & :flag_chunked_file;");
1729 "SELECT count(*) FROM chunks;");
1732 "SELECT sum(size) FROM catalog WHERE flags & :flag_file "
1733 " AND NOT flags & :flag_link;");
1739 Error(
"Failed to count chunked files.", count_chunked_files, data);
1742 retval = count_file_chunks.
FetchRow();
1744 Error(
"Failed to count file chunks", count_file_chunks, data);
1751 Error(
"Failed to aggregate the file sizes.", aggregate_file_size, data);
1765 Error(
"Failed to read old catalog statistics counters", data);
1771 Error(
"Failed to write new statistics counters to database", data);
1789 "UPDATE properties SET value = :schema_version WHERE key = 'schema';");
1791 const bool retval = update_schema_version.
BindDouble(1, 2.5)
1792 && update_schema_version.
Execute();
1795 "Failed to update catalog schema version", update_schema_version, data);
1817 , uid_map_statement_(GenerateMappingStatement(context->uid_map,
"uid"))
1818 , gid_map_statement_(GenerateMappingStatement(context->gid_map,
"gid")) { }
1822 return ApplyPersonaMappings(data);
1846 Error(
"Failed to update UIDs", uid_sql, data);
1852 Error(
"Failed to update GIDs", gid_sql, data);
1860 template<
class MapT>
1862 const MapT &map,
const std::string &column)
const {
1863 assert(map.RuleCount() > 0 || map.HasDefault());
1865 std::string stmt =
"UPDATE OR ABORT catalog SET " + column +
" = ";
1867 if (map.RuleCount() == 0) {
1872 stmt +=
"CASE " + column +
" ";
1873 typedef typename MapT::map_type::const_iterator map_iterator;
1874 map_iterator i = map.GetRuleMap().begin();
1875 const map_iterator iend = map.GetRuleMap().end();
1876 for (; i != iend; ++i) {
1882 stmt += (map.HasDefault()) ?
"ELSE " +
StringifyInt(map.GetDefault()) +
" "
1883 :
"ELSE " + column +
" ";
1897 return CheckDatabaseSchemaCompatibility(data) && BreakUpHardlinks(data);
1945 const std::string stmt =
"UPDATE OR ABORT catalog "
1946 "SET hardlinks = 1 "
1947 "WHERE flags & :file_flag "
1948 " AND hardlinks > 1;";
1951 hardlink_removal_sql.
Execute();
1961 return CheckDatabaseSchemaCompatibility(data)
1962 && RemoveRedundantBulkHashes(data);
1990 const std::string stmt =
"UPDATE OR ABORT catalog "
1992 "WHERE flags & :file_chunked_flag;";
1995 bulkhash_removal_sql.
Execute();
2005 const worker_context *context)
2011 return CheckDatabaseSchemaCompatibility(data)
2012 && StartDatabaseTransaction(data) && RepairStatisticsCounters(data)
2013 && CommitDatabaseTransaction(data);
2024 Error(
"Given catalog schema is < 2.5.", data);
2029 Error(
"Given catalog revision is < 5", data);
2048 bool retval =
false;
2057 const PendingCatalogList::const_iterator iend = data->
nested_catalogs.end();
2058 for (; i != iend; ++i) {
2068 std::string(
"SELECT count(*), sum(size) FROM catalog ") +
"WHERE flags & "
2074 std::string(
"SELECT count(*), sum(size) FROM catalog ") +
"WHERE flags & "
2078 std::string(
"SELECT count(*) FROM catalog ") +
"WHERE flags & "
2082 std::string(
"SELECT count(*) FROM catalog ") +
"WHERE flags & "
2085 std::string(
"SELECT count(*) FROM catalog ")
2086 +
"WHERE xattr IS NOT NULL;");
2089 std::string(
"SELECT count(*), sum(size) FROM catalog ") +
"WHERE flags & "
2093 std::string(
"SELECT count(*) FROM catalog ") +
"WHERE flags & "
2096 "SELECT count(*) FROM chunks;");
2103 Error(
"Failed to collect catalog statistics", data);
2125 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
CVMFS_EXPORT const LogSource source
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
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 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,...)