blob: 4438ad7f146ca3f83d3230637c3f59a4e33e2765 [file]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#include <regex>
#include "exec/acid-metadata-utils.h"
#include "common/logging.h"
#include "gen-cpp/CatalogObjects_types.h"
#include "common/names.h"
namespace impala {
/// Unnamed namespace for auxiliary functions.
namespace {
const string BASE_PREFIX = "base_";
const string DELTA_PREFIX = "delta_";
const string DELETE_DELTA_PREFIX = "delete_delta_";
string GetParentDirName(const string& filepath) {
int slash_before_file = filepath.rfind('/');
if (slash_before_file == string::npos) return "";
int slash_before_dirname = filepath.rfind('/', slash_before_file - 1);
if (slash_before_dirname == string::npos) return "";
return filepath.substr(
slash_before_dirname + 1, slash_before_file - slash_before_dirname - 1);
}
inline string GetFileName(const string& filepath) {
std::size_t slash_before_file = filepath.rfind('/');
if (slash_before_file == string::npos) return filepath;
return filepath.substr(slash_before_file + 1);
}
inline bool StrStartsWith(const string& str, const string& prefix) {
return str.rfind(prefix, 0) == 0;
}
} // unnamed namespace
ValidWriteIdList::ValidWriteIdList(const TValidWriteIdList& valid_write_ids) {
InitFrom(valid_write_ids);
}
std::pair<int64_t, int64_t> ValidWriteIdList::GetWriteIdRange(const string& file_path) {
string dir_name = GetParentDirName(file_path);
if (!(StrStartsWith(dir_name, DELTA_PREFIX) ||
StrStartsWith(dir_name, DELETE_DELTA_PREFIX) ||
StrStartsWith(dir_name, BASE_PREFIX))) {
// Write ids of original files are 0.
return {0, 0};
}
int min_write_id_pos = 0;
if (StrStartsWith(dir_name, DELTA_PREFIX)) {
min_write_id_pos = DELTA_PREFIX.size();
}
else if (StrStartsWith(dir_name, DELETE_DELTA_PREFIX)) {
min_write_id_pos = DELETE_DELTA_PREFIX.size();
} else {
StrStartsWith(dir_name, BASE_PREFIX);
int write_id_pos = BASE_PREFIX.size();
int64_t write_id = std::atoll(dir_name.c_str() + write_id_pos);
return {write_id, write_id};
}
int max_write_id_pos = dir_name.find('_', min_write_id_pos) + 1;
return {std::atoll(dir_name.c_str() + min_write_id_pos),
std::atoll(dir_name.c_str() + max_write_id_pos)};
}
int ValidWriteIdList::GetStatementId(const std::string& file_path) {
string dir_name = GetParentDirName(file_path);
// Only delta directories can have a statement id.
if (StrStartsWith(dir_name, BASE_PREFIX)) return 0;
// Expected number of '_' if statement id is present.
int expected_underscores = 0;
if (StrStartsWith(dir_name, DELTA_PREFIX)) {
expected_underscores = 3;
} else if (StrStartsWith(dir_name, DELETE_DELTA_PREFIX)) {
expected_underscores = 4;
} else {
return 0;
}
int count_underscores = std::count(dir_name.begin(), dir_name.end(), '_');
if (count_underscores != expected_underscores || dir_name.find("_v") != string::npos) {
return 0;
}
int last_underscore_pos = dir_name.rfind('_');
return std::atoi(dir_name.c_str() + last_underscore_pos + 1);
}
int ValidWriteIdList::GetBucketProperty(const std::string& file_path) {
static const std::regex ORIGINAL_PATTERN("[0-9]+_[0-9]+(_copy_[0-9]+)?");
static const std::regex BUCKET_PATTERN("bucket_([0-9]+)(_[0-9]+)?");
string filename = GetFileName(file_path);
int bucket_id = 0;
if (std::regex_match(filename, ORIGINAL_PATTERN)) {
bucket_id = std::atoi(filename.c_str());
} else if (std::regex_match(filename, BUCKET_PATTERN)) {
bucket_id = std::atoi(filename.c_str() + sizeof("bucket_"));
} else {
return -1;
}
int statement_id = GetStatementId(file_path);
constexpr int BUCKET_CODEC_VERSION = 1;
constexpr int NUM_BUCKET_ID_BITS = 12;
constexpr int NUM_STATEMENT_ID_BITS = 12;
return BUCKET_CODEC_VERSION << (1 + NUM_BUCKET_ID_BITS + 4 + NUM_STATEMENT_ID_BITS) |
bucket_id << (4 + NUM_STATEMENT_ID_BITS) |
statement_id;
}
void ValidWriteIdList::InitFrom(const TValidWriteIdList& valid_write_ids) {
if (valid_write_ids.__isset.high_watermark) {
high_water_mark_ = valid_write_ids.high_watermark;
} else {
high_water_mark_ = std::numeric_limits<int64_t>::max();
}
invalid_write_ids_.clear();
for (int64_t invalid_write_id : valid_write_ids.invalid_write_ids) {
invalid_write_ids_.insert(invalid_write_id);
}
}
bool ValidWriteIdList::IsWriteIdValid(int64_t write_id) const {
if (write_id > high_water_mark_) {
return false;
}
return invalid_write_ids_.find(write_id) == invalid_write_ids_.end();
}
ValidWriteIdList::RangeResponse ValidWriteIdList::IsWriteIdRangeValid(
int64_t min_write_id, int64_t max_write_id) const {
if (max_write_id <= high_water_mark_ && invalid_write_ids_.empty()) return ALL;
bool found_valid = false;
bool found_invalid = false;
for (int64_t i = min_write_id; i <= max_write_id; ++i) {
if (IsWriteIdValid(i)) {
found_valid = true;
} else {
found_invalid = true;
}
if (found_valid && found_invalid) return SOME;
}
if (found_invalid) return NONE;
return ALL;
}
ValidWriteIdList::RangeResponse ValidWriteIdList::IsFileRangeValid(
const std::string& file_path) const {
std::pair<int64_t, int64_t> write_id_range = GetWriteIdRange(file_path);
// In base and original directories everything is valid.
if (write_id_range == std::make_pair<int64_t, int64_t>(0, 0)) return ALL;
return IsWriteIdRangeValid(write_id_range.first, write_id_range.second);
}
bool ValidWriteIdList::IsCompacted(const std::string& file_path) {
string dir_name = GetParentDirName(file_path);
if (!StrStartsWith(dir_name, BASE_PREFIX) &&
!StrStartsWith(dir_name, DELTA_PREFIX) &&
!StrStartsWith(dir_name, DELETE_DELTA_PREFIX)) return false;
return dir_name.find("_v") != string::npos;
}
} // namespace impala