24 #include <unordered_map>
33 #include "MapDRelease.h"
37 namespace migrations {
56 "migration.lockfile");
62 throw std::runtime_error(
63 "another HeavyDB server instance is already using data directory: " + base_path);
68 if (!migration_enabled_) {
72 migration_enabled_ =
true;
93 const int database_id,
96 std::vector<int> tables_migrated = {};
97 std::unordered_map<int, std::vector<std::string>> tables_to_migrate;
98 sqlite.
query(
"BEGIN TRANSACTION");
101 "select name from sqlite_master WHERE type='table' AND "
102 "name='mapd_version_history'");
105 "CREATE TABLE mapd_version_history(version integer, migration_history text "
108 "CREATE TABLE mapd_date_in_days_column_migration_tmp(table_id integer primary "
112 "select * from mapd_version_history where migration_history = "
113 "'date_in_days_column'");
116 sqlite.
query(
"END TRANSACTION");
119 LOG(
INFO) <<
"Checking for date columns requiring metadata migration.";
121 "select name from sqlite_master where type='table' AND "
122 "name='mapd_date_in_days_column_migration_tmp'");
124 sqlite.
query(
"select table_id from mapd_date_in_days_column_migration_tmp");
126 for (
size_t i = 0; i < sqlite.
getNumRows(); i++) {
127 tables_migrated.push_back(sqlite.
getData<
int>(i, 0));
132 "CREATE TABLE mapd_date_in_days_column_migration_tmp(table_id integer "
137 "SELECT tables.tableid, tables.name, columns.name FROM mapd_tables tables, "
138 "mapd_columns columns where tables.tableid = columns.tableid AND "
139 "columns.coltype = ?1 AND columns.compression = ?2",
140 std::vector<std::string>{
144 for (
size_t i = 0; i < sqlite.
getNumRows(); i++) {
145 tables_to_migrate[sqlite.
getData<
int>(i, 0)] = {
146 sqlite.
getData<std::string>(i, 1), sqlite.
getData<std::string>(i, 2)};
149 }
catch (
const std::exception& e) {
150 LOG(
ERROR) <<
"Failed to complete migration on date in days column metadata: "
152 sqlite.
query(
"ROLLBACK");
155 sqlite.
query(
"END TRANSACTION");
157 for (
auto& id_names : tables_to_migrate) {
158 if (std::find(tables_migrated.begin(), tables_migrated.end(), id_names.first) ==
159 tables_migrated.end()) {
160 sqlite.
query(
"BEGIN TRANSACTION");
162 LOG(
INFO) <<
"Table: " << id_names.second[0]
163 <<
" may suffer from issues with DATE column: " << id_names.second[1]
164 <<
". Running an OPTIMIZE command to solve any issues with metadata.";
169 auto table_desc_itr = table_descriptors_by_id.find(id_names.first);
170 if (table_desc_itr == table_descriptors_by_id.end()) {
171 throw std::runtime_error(
"Table descriptor does not exist for table " +
172 id_names.second[0] +
" does not exist.");
174 auto td = table_desc_itr->second;
179 "INSERT INTO mapd_date_in_days_column_migration_tmp VALUES(?)",
181 }
catch (
const std::exception& e) {
182 LOG(
ERROR) <<
"Failed to complete metadata migration on date in days column: "
184 sqlite.
query(
"ROLLBACK");
187 sqlite.
query(
"COMMIT");
191 sqlite.
query(
"BEGIN TRANSACTION");
193 sqlite.
query(
"DROP TABLE mapd_date_in_days_column_migration_tmp");
195 "INSERT INTO mapd_version_history(version, migration_history) values(?,?)",
197 }
catch (
const std::exception& e) {
198 LOG(
ERROR) <<
"Failed to complete migraion on date in days column: " << e.what();
199 sqlite.
query(
"ROLLBACK");
202 sqlite.
query(
"END TRANSACTION");
203 LOG(
INFO) <<
"Successfully migrated all date in days column metadata.";
211 auto& catalog = *
cat;
214 if (catalog.isInfoSchemaDb()) {
219 LOG(
INFO) <<
"MigrationMgr: dropRenderGroupColumns: Processing catalog '"
220 << catalog.name() <<
"'";
223 auto* heavyconnect_cache =
224 catalog.getDataMgr().getPersistentStorageMgr()->getDiskCache();
226 bool all_tables_migrated =
true;
229 for (
auto td_itr = table_descriptors_by_id.begin();
230 td_itr != table_descriptors_by_id.end();
233 auto const* td = td_itr->second;
238 LOG(
INFO) <<
"MigrationMgr: dropRenderGroupColumns: Skipping view '"
239 << td->tableName <<
"'";
243 LOG(
INFO) <<
"MigrationMgr: dropRenderGroupColumns: Skipping temporary table '"
244 << td->tableName <<
"'";
248 LOG(
INFO) <<
"MigrationMgr: dropRenderGroupColumns: Examining table '"
249 << td->tableName <<
"'";
253 catalog.getAllColumnMetadataForTable(td->tableId,
false,
false,
false);
255 std::vector<std::string> columns_to_drop;
257 for (
auto cd_itr = logical_cds.begin(); cd_itr != logical_cds.end(); cd_itr++) {
258 auto const* cd = *cd_itr;
261 auto const cd_type = cd->columnType.get_type();
264 auto const next_itr = std::next(cd_itr);
265 if (next_itr == logical_cds.end()) {
270 auto const* next_cd = *next_itr;
273 auto const next_name = next_cd->columnName;
274 auto const expected_name = cd->columnName +
"_render_group";
275 if (next_name == expected_name) {
277 auto const next_type = next_cd->columnType.get_type();
278 if (next_type ==
kINT) {
280 auto const next_id = next_cd->columnId;
281 auto const expected_next_id =
282 cd->columnId + cd->columnType.get_physical_cols() + 1;
283 if (next_id == expected_next_id) {
285 LOG(
INFO) <<
"MigrationMgr: dropRenderGroupColumns: Found render "
289 columns_to_drop.emplace_back(next_name);
293 LOG(
ERROR) <<
"MigrationMgr: dropRenderGroupColumns: Expected render "
295 << next_name <<
"' has wrong ID (" << next_id <<
"/"
296 << expected_next_id <<
"), skipping...";
299 LOG(
ERROR) <<
"MigrationMgr: dropRenderGroupColumns: Expected render "
301 << next_name <<
"' has wrong type (" <<
to_string(next_type)
309 if (columns_to_drop.size() == 0) {
311 <<
"MigrationMgr: dropRenderGroupColumns: No render group columns found";
316 catalog.getSqliteConnector().query(
"BEGIN TRANSACTION");
318 std::vector<int> column_ids;
319 for (
auto const& column : columns_to_drop) {
320 auto const* cd = catalog.getMetadataForColumn(td->tableId, column);
322 LOG(
INFO) <<
"MigrationMgr: dropRenderGroupColumns: Removing render "
324 << cd->columnName <<
"'";
325 catalog.dropColumn(*td, *cd);
326 column_ids.push_back(cd->columnId);
328 if (!td->isForeignTable()) {
329 for (
auto const* physical_td : catalog.getPhysicalTablesDescriptors(td)) {
335 if (physical_td->fragmenter ==
nullptr) {
336 catalog.getMetadataForTable(physical_td->tableId,
true);
337 CHECK(physical_td->fragmenter);
339 physical_td->fragmenter->dropColumns(column_ids);
342 catalog.rollLegacy(
true);
343 if (!td->isForeignTable()) {
345 catalog.resetTableEpochFloor(td->tableId);
346 catalog.checkpoint(td->tableId);
349 catalog.getSqliteConnector().query(
"END TRANSACTION");
350 }
catch (std::exception& e) {
351 if (!td->isForeignTable()) {
352 catalog.setForReload(td->tableId);
354 catalog.rollLegacy(
false);
355 catalog.getSqliteConnector().query(
"ROLLBACK TRANSACTION");
356 LOG(
ERROR) <<
"MigrationMgr: dropRenderGroupColumns: Failed to drop render group "
357 "columns for Table '"
358 << td->tableName <<
"' in Database '" << catalog.name() <<
"' ("
362 all_tables_migrated =
false;
369 if (heavyconnect_cache && td->isForeignTable()) {
370 for (
auto const* physical_td : catalog.getPhysicalTablesDescriptors(td)) {
372 LOG(
INFO) <<
"MigrationMgr: dropRenderGroupColumns: Flushing HeavyConnect "
374 << physical_td->tableName <<
"'";
375 heavyconnect_cache->clearForTablePrefix(
376 {catalog.getCurrentDB().dbId, physical_td->tableId});
381 return all_tables_migrated;
386 const std::filesystem::path& new_path) {
387 bool file_updated{
false};
388 if (std::filesystem::exists(old_path)) {
390 if (std::filesystem::is_symlink(old_path)) {
391 if (std::filesystem::read_symlink(old_path) != new_path.filename()) {
392 std::stringstream ss;
393 ss <<
"Rebrand migration: Encountered an unexpected symlink at path: " << old_path
394 <<
". Symlink does not reference file: " << new_path.filename();
395 throw std::runtime_error(ss.str());
397 if (!std::filesystem::exists(new_path)) {
398 std::stringstream ss;
399 ss <<
"Rebrand migration: Encountered symlink at legacy path: " << old_path
400 <<
" but no corresponding file at new path: " << new_path;
401 throw std::runtime_error(ss.str());
404 if (std::filesystem::exists(new_path)) {
405 std::stringstream ss;
406 ss <<
"Rebrand migration: Encountered existing non-symlink files at the legacy "
408 << old_path <<
" and new path: " << new_path;
409 throw std::runtime_error(ss.str());
411 std::filesystem::rename(old_path, new_path);
412 std::cout <<
"Rebrand migration: Renamed " << old_path <<
" to " << new_path
418 if (std::filesystem::exists(old_path)) {
419 if (!std::filesystem::is_symlink(old_path)) {
420 std::stringstream ss;
421 ss <<
"Rebrand migration: An unexpected error occurred. A symlink should have been "
424 throw std::runtime_error(ss.str());
426 if (std::filesystem::read_symlink(old_path) != new_path.filename()) {
427 std::stringstream ss;
428 ss <<
"Rebrand migration: Encountered an unexpected symlink at path: " << old_path
429 <<
". Symlink does not reference file: " << new_path.filename();
430 throw std::runtime_error(ss.str());
432 }
else if (std::filesystem::exists(new_path)) {
433 std::filesystem::create_symlink(new_path.filename(), old_path);
434 std::cout <<
"Rebrand migration: Added symlink from " << old_path <<
" to "
435 << new_path.filename() << std::endl;
442 const std::string& dir_name,
443 const std::string& old_file_name,
444 const std::string& new_file_name) {
445 auto old_path = std::filesystem::canonical(base_path);
446 auto new_path = std::filesystem::canonical(base_path);
447 if (!dir_name.empty()) {
448 old_path /= dir_name;
449 new_path /= dir_name;
451 if (old_file_name.empty()) {
452 throw std::runtime_error(
453 "Unexpected error in rename_and_symlink_file: old_file_name is empty");
455 old_path /= old_file_name;
457 if (new_file_name.empty()) {
458 throw std::runtime_error(
459 "Unexpected error in rename_and_symlink_file: new_file_name is empty");
461 new_path /= new_file_name;
468 bool migration_occurred{
false};
471 const std::map<std::string, std::string> old_to_new_dir_names {
481 const auto storage_base_path = std::filesystem::canonical(base_path);
484 for (
const auto& [old_dir_name, new_dir_name] : old_to_new_dir_names) {
485 auto old_path = storage_base_path / old_dir_name;
486 auto new_path = storage_base_path / new_dir_name;
488 migration_occurred =
true;
501 "omnisci_system_catalog",
503 if (license_updated || key_updated || sys_catalog_updated) {
504 migration_occurred =
true;
508 const std::array<std::filesystem::path, 9> files_to_delete{
509 storage_base_path /
"omnisci_disk_cache",
510 storage_base_path /
"omnisci_server_pid.lck",
511 storage_base_path /
"mapd_server_pid.lck",
519 for (
const auto& file_path : files_to_delete) {
520 if (std::filesystem::exists(file_path)) {
521 std::filesystem::remove_all(file_path);
522 std::cout <<
"Rebrand migration: Deleted file " << file_path << std::endl;
523 migration_occurred =
true;
526 if (migration_occurred) {
527 std::cout <<
"Rebrand migration completed" << std::endl;
const std::string kDataDirectoryName
T getData(const int row, const int col)
class for a per-database catalog. also includes metadata for the current database and the current use...
static bool dropRenderGroupColumns(const Catalog_Namespace::TableDescriptorMapById &table_descriptors_by_id, Catalog_Namespace::Catalog *cat)
virtual void query_with_text_params(std::string const &query_only)
static void relaxMigrationLock()
const std::string kDefaultLogDirName
const std::string kSystemCatalogName
virtual void query(const std::string &queryString)
Driver for running cleanup processes on a table. TableOptimizer provides functions for various cleanu...
Constants for Builtin SQL Types supported by HEAVY.AI.
const std::string kDefaultExportDirName
static std::shared_ptr< Executor > getExecutor(const ExecutorId id, const std::string &debug_dir="", const std::string &debug_file="", const SystemParameters &system_parameters=SystemParameters())
bool rename_and_symlink_path(const std::filesystem::path &old_path, const std::filesystem::path &new_path)
const std::string kDefaultImportDirName
std::map< int, TableDescriptor * > TableDescriptorMapById
static bool migration_enabled_
static const int32_t MAPD_VERSION
const std::string kDefaultKeyFileName
const std::string kDefaultKeyStoreDirName
static void executeRebrandMigration(const std::string &base_path)
static void takeMigrationLock(const std::string &base_path)
bool table_is_temporary(const TableDescriptor *const td)
bool rename_and_symlink_file(const std::filesystem::path &base_path, const std::string &dir_name, const std::string &old_file_name, const std::string &new_file_name)
const std::string kCatalogDirectoryName
const std::string kDefaultLicenseFileName
static void migrateDateInDaysMetadata(const Catalog_Namespace::TableDescriptorMapById &table_descriptors_by_id, const int database_id, Catalog_Namespace::Catalog *cat, SqliteConnector &sqlite)
static std::unique_ptr< heavyai::DistributedSharedMutex > migration_mutex_
const std::string kLockfilesDirectoryName
static constexpr ExecutorId UNITARY_EXECUTOR_ID
virtual size_t getNumRows() const
void recomputeMetadata() const
Recomputes per-chunk metadata for each fragment in the table. Updates and deletes can cause chunk met...