OmniSciDB  17c254d2f8
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
TableArchiver.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2020 OmniSci, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
18 
19 #include <algorithm>
20 #include <boost/filesystem.hpp>
21 #include <boost/process.hpp>
22 #include <boost/range/combine.hpp>
23 #include <cerrno>
24 #include <cstdio>
25 #include <cstring>
26 #include <exception>
27 #include <list>
28 #include <memory>
29 #include <regex>
30 #include <set>
31 #include <sstream>
32 #include <system_error>
33 
35 #include "LockMgr/LockMgr.h"
36 #include "Parser/ParseDDL.h"
37 #include "Shared/File.h"
38 #include "Shared/Logger.h"
40 #include "Shared/measure.h"
41 #include "Shared/thread_count.h"
42 
43 extern bool g_cluster;
45 
46 constexpr static char const* table_schema_filename = "_table.sql";
47 constexpr static char const* table_oldinfo_filename = "_table.oldinfo";
48 constexpr static char const* table_epoch_filename = "_table.epoch";
49 
50 namespace std {
51 
52 template <typename T, typename U>
53 struct tuple_size<boost::tuples::cons<T, U>>
54  : boost::tuples::length<boost::tuples::cons<T, U>> {};
55 template <size_t I, typename T, typename U>
56 struct tuple_element<I, boost::tuples::cons<T, U>>
57  : boost::tuples::element<I, boost::tuples::cons<T, U>> {};
58 
59 } // namespace std
60 
61 namespace {
62 
63 inline auto simple_file_closer = [](FILE* f) { std::fclose(f); };
64 
65 inline std::string abs_path(const File_Namespace::GlobalFileMgr* global_file_mgr) {
66  return boost::filesystem::canonical(global_file_mgr->getBasePath()).string();
67 }
68 
69 inline std::string run(const std::string& cmd, const std::string& chdir = "") {
70  VLOG(3) << "running cmd: " << cmd;
71  int rcode;
72  std::error_code ec;
73  std::string output, errors;
74  const auto time_ms = measure<>::execution([&]() {
75  using namespace boost::process;
76  ipstream stdout, stderr;
77  if (!chdir.empty()) {
78  rcode = system(cmd, std_out > stdout, std_err > stderr, ec, start_dir = chdir);
79  } else {
80  rcode = system(cmd, std_out > stdout, std_err > stderr, ec);
81  }
82  std::ostringstream ss_output, ss_errors;
83  stdout >> ss_output.rdbuf();
84  stderr >> ss_errors.rdbuf();
85  output = ss_output.str();
86  errors = ss_errors.str();
87  });
88  if (rcode || ec) {
89  LOG(ERROR) << "failed cmd: " << cmd;
90  LOG(ERROR) << "exit code: " << rcode;
91  LOG(ERROR) << "error code: " << ec.value() << " - " << ec.message();
92  LOG(ERROR) << "stdout: " << output;
93  LOG(ERROR) << "stderr: " << errors;
94 #if defined(__APPLE__)
95  // osx bsdtar options "--use-compress-program" and "--fast-read" together
96  // run into pipe write error after tar extracts the first occurrence of a
97  // file and closes the read end while the decompression program still writes
98  // to the pipe. bsdtar doesn't handle this situation well like gnu tar does.
99  if (1 == rcode && cmd.find("--fast-read") &&
100  (errors.find("cannot write decoded block") != std::string::npos ||
101  errors.find("Broken pipe") != std::string::npos)) {
102  // ignore this error, or lose speed advantage of "--fast-read" on osx.
103  LOG(ERROR) << "tar error ignored on osx for --fast-read";
104  } else
105 #endif
106  // circumvent tar warning on reading file that is "changed as we read it".
107  // this warning results from reading a table file under concurrent inserts
108  if (1 == rcode && errors.find("changed as we read") != std::string::npos) {
109  LOG(ERROR) << "tar error ignored under concurrent inserts";
110  } else {
111  throw std::runtime_error("Failed to run command: " + cmd +
112  "\nexit code: " + std::to_string(rcode) + "\nerrors:\n" +
113  (rcode ? errors : ec.message()));
114  }
115  } else {
116  VLOG(3) << "finished cmd: " << cmd;
117  VLOG(3) << "time: " << time_ms << " ms";
118  VLOG(3) << "stdout: " << output;
119  }
120  return output;
121 }
122 
123 inline std::string simple_file_cat(const std::string& archive_path,
124  const std::string& file_name,
125  const std::string& compression) {
126 #if defined(__APPLE__)
127  constexpr static auto opt_occurrence = " --fast-read ";
128 #else
129  constexpr static auto opt_occurrence = " --occurrence=1 ";
130 #endif
131  boost::filesystem::path temp_dir =
132  boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
133  boost::filesystem::create_directories(temp_dir);
134  run("tar " + compression + " -xvf \"" + archive_path + "\" " + opt_occurrence +
135  file_name,
136  temp_dir.string());
137  const auto output = run("cat " + (temp_dir / file_name).string());
138  boost::filesystem::remove_all(temp_dir);
139  return output;
140 }
141 
142 inline std::string get_table_schema(const std::string& archive_path,
143  const std::string& table,
144  const std::string& compression) {
145  const auto schema_str =
146  simple_file_cat(archive_path, table_schema_filename, compression);
147  std::regex regex("@T");
148  return std::regex_replace(schema_str, regex, table);
149 }
150 
151 // Adjust column ids in chunk keys in a table's data files under a temp_data_dir,
152 // including files of all shards of the table. Can be slow for big files but should
153 // be scale faster than refragmentizing. Table altering should be rare for olap.
154 void adjust_altered_table_files(const std::string& temp_data_dir,
155  const std::unordered_map<int, int>& column_ids_map) {
156  boost::filesystem::path base_path(temp_data_dir);
157  boost::filesystem::recursive_directory_iterator end_it;
159  for (boost::filesystem::recursive_directory_iterator fit(base_path); fit != end_it;
160  ++fit) {
161  if (boost::filesystem::is_regular_file(fit->status())) {
162  const std::string file_path = fit->path().string();
163  const std::string file_name = fit->path().filename().string();
164  std::vector<std::string> tokens;
165  boost::split(tokens, file_name, boost::is_any_of("."));
166  // ref. FileMgr::init for hint of data file name layout
167  if (tokens.size() > 2 && MAPD_FILE_EXT == "." + tokens[2]) {
168  thread_controller.startThread([file_name, file_path, tokens, &column_ids_map] {
169  const auto page_size = boost::lexical_cast<int64_t>(tokens[1]);
170  const auto file_size = boost::filesystem::file_size(file_path);
171  std::unique_ptr<FILE, decltype(simple_file_closer)> fp(
172  std::fopen(file_path.c_str(), "r+"), simple_file_closer);
173  if (!fp) {
174  throw std::runtime_error("Failed to open " + file_path +
175  " for update: " + std::strerror(errno));
176  }
177  // ref. FileInfo::openExistingFile for hint of chunk header layout
178  for (size_t page = 0; page < file_size / page_size; ++page) {
179  int ints[8];
180  if (0 != std::fseek(fp.get(), page * page_size, SEEK_SET)) {
181  throw std::runtime_error("Failed to seek to page# " + std::to_string(page) +
182  file_path + " for read: " + std::strerror(errno));
183  }
184  if (1 != fread(ints, sizeof ints, 1, fp.get())) {
185  throw std::runtime_error("Failed to read " + file_path + ": " +
186  std::strerror(errno));
187  }
188  if (ints[0] > 0) { // header size
189  auto cit = column_ids_map.find(ints[3]);
190  CHECK(cit != column_ids_map.end());
191  if (ints[3] != cit->second) {
192  ints[3] = cit->second;
193  if (0 != std::fseek(fp.get(), page * page_size, SEEK_SET)) {
194  throw std::runtime_error("Failed to seek to page# " +
195  std::to_string(page) + file_path +
196  " for write: " + std::strerror(errno));
197  }
198  if (1 != fwrite(ints, sizeof ints, 1, fp.get())) {
199  throw std::runtime_error("Failed to write " + file_path + ": " +
200  std::strerror(errno));
201  }
202  }
203  }
204  }
205  });
206  thread_controller.checkThreadsStatus();
207  }
208  }
209  }
210  thread_controller.finish();
211 }
212 
214  const std::string& temp_data_dir,
215  const std::vector<std::string>& target_paths,
216  const std::string& name_prefix) {
217  boost::filesystem::path base_path(temp_data_dir);
218  boost::filesystem::directory_iterator end_it;
219  int target_path_index = 0;
220  for (boost::filesystem::directory_iterator fit(base_path); fit != end_it; ++fit) {
221  if (!boost::filesystem::is_regular_file(fit->status())) {
222  const std::string file_path = fit->path().string();
223  const std::string file_name = fit->path().filename().string();
224  if (boost::istarts_with(file_name, name_prefix)) {
225  const std::string target_path =
226  abs_path(global_file_mgr) + "/" + target_paths[target_path_index++];
227  if (std::rename(file_path.c_str(), target_path.c_str())) {
228  throw std::runtime_error("Failed to rename file " + file_path + " to " +
229  target_path + ": " + std::strerror(errno));
230  }
231  }
232  }
233  }
234 }
235 
236 } // namespace
237 
239  const std::string& archive_path,
240  const std::string& compression) {
241  if (g_cluster) {
242  throw std::runtime_error("DUMP/RESTORE is not supported yet on distributed setup.");
243  }
244  if (boost::filesystem::exists(archive_path)) {
245  throw std::runtime_error("Archive " + archive_path + " already exists.");
246  }
248  throw std::runtime_error("Dumping view or temporary table is not supported.");
249  }
250  // collect paths of files to archive
251  const auto global_file_mgr = cat_->getDataMgr().getGlobalFileMgr();
252  std::vector<std::string> file_paths;
253  auto file_writer = [&file_paths, global_file_mgr](const std::string& file_name,
254  const std::string& file_type,
255  const std::string& file_data) {
256  const auto file_path = abs_path(global_file_mgr) + "/" + file_name;
257  std::unique_ptr<FILE, decltype(simple_file_closer)> fp(
258  std::fopen(file_path.c_str(), "w"), simple_file_closer);
259  if (!fp) {
260  throw std::runtime_error("Failed to create " + file_type + " file '" + file_path +
261  "': " + std::strerror(errno));
262  }
263  if (std::fwrite(file_data.data(), 1, file_data.size(), fp.get()) < file_data.size()) {
264  throw std::runtime_error("Failed to write " + file_type + " file '" + file_path +
265  "': " + std::strerror(errno));
266  }
267  file_paths.push_back(file_name);
268  };
269  // Prevent modification of the table schema during a dump operation, while allowing
270  // concurrent inserts.
271  auto table_read_lock =
273  const auto table_name = td->tableName;
274  {
275  // - gen schema file
276  const auto schema_str = cat_->dumpSchema(td);
277  file_writer(table_schema_filename, "table schema", schema_str);
278  // - gen column-old-info file
279  const auto cds = cat_->getAllColumnMetadataForTable(td->tableId, true, true, true);
280  std::vector<std::string> column_oldinfo;
281  std::transform(cds.begin(),
282  cds.end(),
283  std::back_inserter(column_oldinfo),
284  [&](const auto cd) -> std::string {
285  return cd->columnName + ":" + std::to_string(cd->columnId) + ":" +
287  });
288  const auto column_oldinfo_str = boost::algorithm::join(column_oldinfo, " ");
289  file_writer(table_oldinfo_filename, "table old info", column_oldinfo_str);
290  // - gen table epoch
291  const auto epoch = cat_->getTableEpoch(cat_->getCurrentDB().dbId, td->tableId);
292  file_writer(table_epoch_filename, "table epoch", std::to_string(epoch));
293  // - collect table data file paths ...
294  const auto data_file_dirs = cat_->getTableDataDirectories(td);
295  file_paths.insert(file_paths.end(), data_file_dirs.begin(), data_file_dirs.end());
296  // - collect table dict file paths ...
297  const auto dict_file_dirs = cat_->getTableDictDirectories(td);
298  file_paths.insert(file_paths.end(), dict_file_dirs.begin(), dict_file_dirs.end());
299  // tar takes time. release cat lock to yield the cat to concurrent CREATE statements.
300  }
301  // run tar to archive the files ... this may take a while !!
302  run("tar " + compression + " -cvf \"" + archive_path + "\" " +
303  boost::algorithm::join(file_paths, " "),
304  abs_path(global_file_mgr));
305 }
306 
307 // Restore data and dict files of a table from a tgz archive.
309  const TableDescriptor* td,
310  const std::string& archive_path,
311  const std::string& compression) {
312  if (g_cluster) {
313  throw std::runtime_error("DUMP/RESTORE is not supported yet on distributed setup.");
314  }
315  if (!boost::filesystem::exists(archive_path)) {
316  throw std::runtime_error("Archive " + archive_path + " does not exist.");
317  }
319  throw std::runtime_error("Restoring view or temporary table is not supported.");
320  }
321  // Obtain table schema read lock to prevent modification of the schema during
322  // restoration
323  const auto table_read_lock =
325  // prevent concurrent inserts into table during restoration
326  const auto insert_data_lock =
328 
329  // untar takes time. no grab of cat lock to yield to concurrent CREATE stmts.
330  const auto global_file_mgr = cat_->getDataMgr().getGlobalFileMgr();
331  // dirs where src files are untarred and dst files are backed up
332  constexpr static const auto temp_data_basename = "_data";
333  constexpr static const auto temp_back_basename = "_back";
334  const auto temp_data_dir = abs_path(global_file_mgr) + "/" + temp_data_basename;
335  const auto temp_back_dir = abs_path(global_file_mgr) + "/" + temp_back_basename;
336  // clean up tmp dirs and files in any case
337  auto tmp_files_cleaner = [&](void*) {
338  run("rm -rf " + temp_data_dir + " " + temp_back_dir);
339  run("rm -f " + abs_path(global_file_mgr) + "/" + table_schema_filename);
340  run("rm -f " + abs_path(global_file_mgr) + "/" + table_oldinfo_filename);
341  run("rm -f " + abs_path(global_file_mgr) + "/" + table_epoch_filename);
342  };
343  std::unique_ptr<decltype(tmp_files_cleaner), decltype(tmp_files_cleaner)> tfc(
344  &tmp_files_cleaner, tmp_files_cleaner);
345  // extract & parse schema
346  const auto schema_str = get_table_schema(archive_path, td->tableName, compression);
347  const auto create_table_stmt =
348  Parser::parseDDL<Parser::CreateTableStmt>("table schema", schema_str);
349  // verify compatibility between source and destination schemas
350  TableDescriptor src_td;
351  std::list<ColumnDescriptor> src_columns;
352  std::vector<Parser::SharedDictionaryDef> shared_dict_defs;
353  create_table_stmt->executeDryRun(session, src_td, src_columns, shared_dict_defs);
354  // - sanity check table-level compatibility
355  if (src_td.hasDeletedCol != td->hasDeletedCol) {
356  // TODO: allow the case, in which src data enables vacuum while
357  // dst doesn't, by simply discarding src $deleted column data.
358  throw std::runtime_error("Incompatible table VACCUM option");
359  }
360  if (src_td.nShards != td->nShards) {
361  // TODO: allow different shard numbers if they have a "GCD",
362  // by splitting/merging src data files before drop into dst.
363  throw std::runtime_error("Unmatched number of table shards");
364  }
365  // - sanity check column-level compatibility (based on column names)
366  const auto dst_columns =
367  cat_->getAllColumnMetadataForTable(td->tableId, false, false, false);
368  if (dst_columns.size() != src_columns.size()) {
369  throw std::runtime_error("Unmatched number of table columns");
370  }
371  for (const auto& [src_cd, dst_cd] : boost::combine(src_columns, dst_columns)) {
372  if (src_cd.columnType.get_type_name() != dst_cd->columnType.get_type_name() ||
373  src_cd.columnType.get_compression_name() !=
374  dst_cd->columnType.get_compression_name()) {
375  throw std::runtime_error("Incompatible types on column " + src_cd.columnName);
376  }
377  }
378  // extract src table column ids (ALL columns incl. system/virtual/phy geo cols)
379  const auto all_src_oldinfo_str =
380  simple_file_cat(archive_path, table_oldinfo_filename, compression);
381  std::vector<std::string> src_oldinfo_strs;
382  boost::algorithm::split(src_oldinfo_strs,
383  all_src_oldinfo_str,
384  boost::is_any_of(" "),
385  boost::token_compress_on);
386  auto all_dst_columns =
387  cat_->getAllColumnMetadataForTable(td->tableId, true, true, true);
388  if (src_oldinfo_strs.size() != all_dst_columns.size()) {
389  throw std::runtime_error("Source table has a unmatched number of columns: " +
390  std::to_string(src_oldinfo_strs.size()) + " vs " +
391  std::to_string(all_dst_columns.size()));
392  }
393  // build a map of src column ids and dst column ids, just in case src table has been
394  // ALTERed before and chunk keys of src table needs to be adjusted accordingly.
395  // note: this map is used only for the case of migrating a table and not for restoring
396  // a table. When restoring a table, the two tables must have the same column ids.
397  //
398  // also build a map of src dict paths and dst dict paths for relocating src dicts
399  std::unordered_map<int, int> column_ids_map;
400  std::unordered_map<std::string, std::string> dict_paths_map;
401  // sort inputs of transform in lexical order of column names for correct mappings
402  std::list<std::vector<std::string>> src_oldinfo_tokens;
403  std::transform(
404  src_oldinfo_strs.begin(),
405  src_oldinfo_strs.end(),
406  std::back_inserter(src_oldinfo_tokens),
407  [](const auto& src_oldinfo_str) -> auto {
408  std::vector<std::string> tokens;
410  tokens, src_oldinfo_str, boost::is_any_of(":"), boost::token_compress_on);
411  return tokens;
412  });
413  src_oldinfo_tokens.sort(
414  [](const auto& lhs, const auto& rhs) { return lhs[0].compare(rhs[0]) < 0; });
415  all_dst_columns.sort(
416  [](auto a, auto b) { return a->columnName.compare(b->columnName) < 0; });
417  // transform inputs into the maps
418  std::transform(src_oldinfo_tokens.begin(),
419  src_oldinfo_tokens.end(),
420  all_dst_columns.begin(),
421  std::inserter(column_ids_map, column_ids_map.end()),
422  [&](const auto& tokens, const auto& cd) -> std::pair<int, int> {
423  VLOG(3) << boost::algorithm::join(tokens, ":") << " ==> "
424  << cd->columnName << ":" << cd->columnId;
425  dict_paths_map[tokens[2]] = cat_->getColumnDictDirectory(cd);
426  return {boost::lexical_cast<int>(tokens[1]), cd->columnId};
427  });
428  bool was_table_altered = false;
429  std::for_each(column_ids_map.begin(), column_ids_map.end(), [&](auto& it) {
430  was_table_altered = was_table_altered || it.first != it.second;
431  });
432  VLOG(3) << "was_table_altered = " << was_table_altered;
433  // extract all data files to a temp dir. will swap with dst table dir after all set,
434  // otherwise will corrupt table in case any bad thing happens in the middle.
435  run("rm -rf " + temp_data_dir);
436  run("mkdir -p " + temp_data_dir);
437  run("tar " + compression + " -xvf \"" + archive_path + "\"", temp_data_dir);
438  // if table was ever altered after it was created, update column ids in chunk headers.
439  if (was_table_altered) {
440  const auto time_ms = measure<>::execution(
441  [&]() { adjust_altered_table_files(temp_data_dir, column_ids_map); });
442  VLOG(3) << "adjust_altered_table_files: " << time_ms << " ms";
443  }
444  // finally,,, swap table data/dict dirs!
445  const auto data_file_dirs = cat_->getTableDataDirectories(td);
446  const auto dict_file_dirs = cat_->getTableDictDirectories(td);
447  // move current target dirs, if exists, to backup dir
448  std::vector<std::string> both_file_dirs;
449  std::merge(data_file_dirs.begin(),
450  data_file_dirs.end(),
451  dict_file_dirs.begin(),
452  dict_file_dirs.end(),
453  std::back_inserter(both_file_dirs));
454  bool backup_completed = false;
455  try {
456  run("rm -rf " + temp_back_dir);
457  run("mkdir -p " + temp_back_dir);
458  for (const auto& dir : both_file_dirs) {
459  const auto dir_full_path = abs_path(global_file_mgr) + "/" + dir;
460  if (boost::filesystem::is_directory(dir_full_path)) {
461  run("mv " + dir_full_path + " " + temp_back_dir);
462  }
463  }
464  backup_completed = true;
465  // accord src data dirs to dst
467  cat_->getDataMgr().getGlobalFileMgr(), temp_data_dir, data_file_dirs, "table_");
468  // accord src dict dirs to dst
469  for (const auto& dit : dict_paths_map) {
470  if (!dit.first.empty() && !dit.second.empty()) {
471  const auto src_dict_path = temp_data_dir + "/" + dit.first;
472  const auto dst_dict_path = abs_path(global_file_mgr) + "/" + dit.second;
473  run("mv " + src_dict_path + " " + dst_dict_path);
474  }
475  }
476  // throw if sanity test forces a rollback
478  throw std::runtime_error("lol!");
479  }
480  } catch (...) {
481  // once backup is completed, whatever in abs_path(global_file_mgr) is the "src"
482  // dirs that are to be rolled back and discarded
483  if (backup_completed) {
484  run("rm -rf " + boost::algorithm::join(both_file_dirs, " "),
485  abs_path(global_file_mgr));
486  }
487  // complete rollback by recovering original "dst" table dirs from backup dir
488  boost::filesystem::path base_path(temp_back_dir);
489  boost::filesystem::directory_iterator end_it;
490  for (boost::filesystem::directory_iterator fit(base_path); fit != end_it; ++fit) {
491  run("mv " + fit->path().string() + " .", abs_path(global_file_mgr));
492  }
493  throw;
494  }
495  // set for reloading table from the restored/migrated files
496  const auto epoch = simple_file_cat(archive_path, table_epoch_filename, compression);
498  cat_->getCurrentDB().dbId, td->tableId, boost::lexical_cast<int>(epoch));
499 }
500 
501 // Migrate a table, which doesn't exist in current db, from a tar ball to the db.
502 // This actually creates the table and restores data/dict files from the tar ball.
504  const std::string& table_name,
505  const std::string& archive_path,
506  const std::string& compression) {
507  // replace table name and drop foreign dict references
508  const auto schema_str = get_table_schema(archive_path, table_name, compression);
509  Parser::parseDDL<Parser::CreateTableStmt>("table schema", schema_str)->execute(session);
510  try {
511  restoreTable(
512  session, cat_->getMetadataForTable(table_name), archive_path, compression);
513  } catch (...) {
514  Parser::parseDDL<Parser::DropTableStmt>("statement",
515  "DROP TABLE IF EXISTS " + table_name + ";")
516  ->execute(session);
517  throw;
518  }
519 }
std::string get_table_schema(const std::string &archive_path, const std::string &table, const std::string &compression)
static ReadLock getReadLockForTable(const Catalog_Namespace::Catalog &cat, const std::string &table_name)
Definition: LockMgrImpl.h:164
std::string getBasePath() const
static constexpr char const * table_schema_filename
std::string tableName
static TimeT::rep execution(F func, Args &&...args)
Definition: sample.cpp:29
std::string abs_path(const File_Namespace::GlobalFileMgr *global_file_mgr)
Data_Namespace::DataMgr & getDataMgr() const
Definition: Catalog.h:183
#define LOG(tag)
Definition: Logger.h:188
static WriteLock getWriteLockForTable(const Catalog_Namespace::Catalog &cat, const std::string &table_name)
Definition: LockMgrImpl.h:155
void startThread(FuncType &&func, Args &&...args)
void adjust_altered_table_files(const std::string &temp_data_dir, const std::unordered_map< int, int > &column_ids_map)
std::string join(T const &container, std::string const &delim)
#define MAPD_FILE_EXT
Definition: File.h:26
static constexpr char const * table_oldinfo_filename
int32_t getTableEpoch(const int32_t db_id, const int32_t table_id) const
Definition: Catalog.cpp:2585
std::vector< std::string > getTableDataDirectories(const TableDescriptor *td) const
Definition: Catalog.cpp:3680
void restoreTable(const Catalog_Namespace::SessionInfo &session, const TableDescriptor *td, const std::string &archive_path, const std::string &compression)
std::string to_string(char const *&&v)
std::vector< std::string > split(std::string_view str, std::string_view delim, std::optional< size_t > maxsplit)
split apart a string into a vector of substrings
std::string getColumnDictDirectory(const ColumnDescriptor *cd) const
Definition: Catalog.cpp:3694
CHECK(cgen_state)
const DBMetadata & getCurrentDB() const
Definition: Catalog.h:182
const int8_t const int64_t const uint64_t const int32_t const int64_t int64_t uint32_t const int64_t int32_t * error_code
void rename_table_directories(const File_Namespace::GlobalFileMgr *global_file_mgr, const std::string &temp_data_dir, const std::vector< std::string > &target_paths, const std::string &name_prefix)
std::list< const ColumnDescriptor * > getAllColumnMetadataForTable(const int tableId, const bool fetchSystemColumns, const bool fetchVirtualColumns, const bool fetchPhysicalColumns) const
Returns a list of pointers to constant ColumnDescriptor structs for all the columns from a particular...
Definition: Catalog.cpp:1677
void setTableEpoch(const int db_id, const int table_id, const int new_epoch)
Definition: Catalog.cpp:2615
std::vector< std::string > getTableDictDirectories(const TableDescriptor *td) const
Definition: Catalog.cpp:3710
Data_Namespace::MemoryLevel persistenceLevel
static constexpr char const * table_epoch_filename
bool g_cluster
const TableDescriptor * getMetadataForTable(const std::string &tableName, const bool populateFragmenter=true) const
Returns a pointer to a const TableDescriptor struct matching the provided tableName.
static bool run
specifies the content in-memory of a row in the table metadata table
std::string simple_file_cat(const std::string &archive_path, const std::string &file_name, const std::string &compression)
std::string dumpSchema(const TableDescriptor *td) const
Definition: Catalog.cpp:3726
int cpu_threads()
Definition: thread_count.h:25
void dumpTable(const TableDescriptor *td, const std::string &archive_path, const std::string &compression)
A selection of helper methods for File I/O.
#define VLOG(n)
Definition: Logger.h:291
bool g_test_rollback_dump_restore
File_Namespace::GlobalFileMgr * getGlobalFileMgr() const
Definition: DataMgr.cpp:528
Catalog_Namespace::Catalog * cat_
Definition: TableArchiver.h:43