Utils.cpp 9.5 KB
Newer Older
1
// Copyright (C) 2019-2020 Zilliz. All rights reserved.
J
jinhai 已提交
2
//
3 4
// Licensed 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
J
jinhai 已提交
5
//
6 7 8 9 10
// 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.
J
jinhai 已提交
11

S
starlord 已提交
12
#include "db/Utils.h"
X
Xu Peng 已提交
13

S
shengjh 已提交
14
#include <fiu-local.h>
S
starlord 已提交
15
#include <boost/filesystem.hpp>
X
Xu Peng 已提交
16
#include <chrono>
S
starlord 已提交
17
#include <mutex>
18
#include <regex>
S
starlord 已提交
19
#include <vector>
X
Xu Peng 已提交
20

21 22 23 24 25
#include "server/Config.h"
#include "storage/s3/S3ClientWrapper.h"
#include "utils/CommonUtil.h"
#include "utils/Log.h"

J
jinhai 已提交
26
namespace milvus {
X
Xu Peng 已提交
27 28 29
namespace engine {
namespace utils {

S
starlord 已提交
30 31
namespace {

S
starlord 已提交
32
const char* TABLES_FOLDER = "/tables/";
S
starlord 已提交
33

J
jinhai 已提交
34 35
uint64_t index_file_counter = 0;
std::mutex index_file_counter_mutex;
36

C
Cai Yudong 已提交
37
static std::string
S
starlord 已提交
38
ConstructParentFolder(const std::string& db_path, const meta::TableFileSchema& table_file) {
S
starlord 已提交
39
    std::string table_path = db_path + TABLES_FOLDER + table_file.table_id_;
40
    std::string partition_path = table_path + "/" + table_file.segment_id_;
S
starlord 已提交
41 42 43
    return partition_path;
}

C
Cai Yudong 已提交
44
static std::string
S
starlord 已提交
45
GetTableFileParentFolder(const DBMetaOptions& options, const meta::TableFileSchema& table_file) {
S
starlord 已提交
46 47
    uint64_t path_count = options.slave_paths_.size() + 1;
    std::string target_path = options.path_;
48 49
    uint64_t index = 0;

S
starlord 已提交
50
    if (meta::TableFileSchema::NEW_INDEX == table_file.file_type_) {
51 52 53 54 55
        // index file is large file and to be persisted permanently
        // we need to distribute index files to each db_path averagely
        // round robin according to a file counter
        std::lock_guard<std::mutex> lock(index_file_counter_mutex);
        index = index_file_counter % path_count;
56
        ++index_file_counter;
57 58 59 60 61 62 63
    } else {
        // for other type files, they could be merged or deleted
        // so we round robin according to their file id
        index = table_file.id_ % path_count;
    }

    if (index > 0) {
S
starlord 已提交
64
        target_path = options.slave_paths_[index - 1];
S
starlord 已提交
65 66 67 68 69
    }

    return ConstructParentFolder(target_path, table_file);
}

S
starlord 已提交
70
}  // namespace
S
starlord 已提交
71

S
starlord 已提交
72 73
int64_t
GetMicroSecTimeStamp() {
X
Xu Peng 已提交
74
    auto now = std::chrono::system_clock::now();
S
starlord 已提交
75
    auto micros = std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch()).count();
X
Xu Peng 已提交
76 77 78 79

    return micros;
}

S
starlord 已提交
80
Status
S
starlord 已提交
81
CreateTablePath(const DBMetaOptions& options, const std::string& table_id) {
S
starlord 已提交
82
    std::string db_path = options.path_;
S
starlord 已提交
83 84
    std::string table_path = db_path + TABLES_FOLDER + table_id;
    auto status = server::CommonUtil::CreateDirectory(table_path);
S
starlord 已提交
85 86 87
    if (!status.ok()) {
        ENGINE_LOG_ERROR << status.message();
        return status;
S
starlord 已提交
88 89
    }

S
starlord 已提交
90
    for (auto& path : options.slave_paths_) {
S
starlord 已提交
91 92
        table_path = path + TABLES_FOLDER + table_id;
        status = server::CommonUtil::CreateDirectory(table_path);
S
shengjh 已提交
93
        fiu_do_on("CreateTablePath.creat_slave_path", status = Status(DB_INVALID_PATH, ""));
S
starlord 已提交
94 95 96
        if (!status.ok()) {
            ENGINE_LOG_ERROR << status.message();
            return status;
S
starlord 已提交
97 98 99 100 101 102
        }
    }

    return Status::OK();
}

S
starlord 已提交
103
Status
S
starlord 已提交
104
DeleteTablePath(const DBMetaOptions& options, const std::string& table_id, bool force) {
S
starlord 已提交
105 106
    std::vector<std::string> paths = options.slave_paths_;
    paths.push_back(options.path_);
S
starlord 已提交
107

S
starlord 已提交
108
    for (auto& path : paths) {
S
starlord 已提交
109
        std::string table_path = path + TABLES_FOLDER + table_id;
S
starlord 已提交
110
        if (force) {
S
starlord 已提交
111 112
            boost::filesystem::remove_all(table_path);
            ENGINE_LOG_DEBUG << "Remove table folder: " << table_path;
S
starlord 已提交
113
        } else if (boost::filesystem::exists(table_path) && boost::filesystem::is_empty(table_path)) {
S
starlord 已提交
114 115 116
            boost::filesystem::remove_all(table_path);
            ENGINE_LOG_DEBUG << "Remove table folder: " << table_path;
        }
S
starlord 已提交
117 118
    }

119
    bool s3_enable = false;
C
Cai Yudong 已提交
120
    server::Config& config = server::Config::GetInstance();
121
    config.GetStorageConfigS3Enable(s3_enable);
C
Cai Yudong 已提交
122

123
    if (s3_enable) {
C
Cai Yudong 已提交
124 125
        std::string table_path = options.path_ + TABLES_FOLDER + table_id;

C
Cai Yudong 已提交
126
        auto& storage_inst = milvus::storage::S3ClientWrapper::GetInstance();
C
Cai Yudong 已提交
127 128 129 130 131 132
        Status stat = storage_inst.DeleteObjects(table_path);
        if (!stat.ok()) {
            return stat;
        }
    }

S
starlord 已提交
133 134 135
    return Status::OK();
}

S
starlord 已提交
136
Status
S
starlord 已提交
137
CreateTableFilePath(const DBMetaOptions& options, meta::TableFileSchema& table_file) {
S
starlord 已提交
138 139 140
    std::string parent_path = GetTableFileParentFolder(options, table_file);

    auto status = server::CommonUtil::CreateDirectory(parent_path);
S
shengjh 已提交
141
    fiu_do_on("CreateTableFilePath.fail_create", status = Status(DB_INVALID_PATH, ""));
S
starlord 已提交
142 143 144
    if (!status.ok()) {
        ENGINE_LOG_ERROR << status.message();
        return status;
S
starlord 已提交
145 146 147 148 149 150 151
    }

    table_file.location_ = parent_path + "/" + table_file.file_id_;

    return Status::OK();
}

S
starlord 已提交
152
Status
S
starlord 已提交
153
GetTableFilePath(const DBMetaOptions& options, meta::TableFileSchema& table_file) {
S
starlord 已提交
154
    std::string parent_path = ConstructParentFolder(options.path_, table_file);
S
starlord 已提交
155
    std::string file_path = parent_path + "/" + table_file.file_id_;
C
Cai Yudong 已提交
156

157
    bool s3_enable = false;
C
Cai Yudong 已提交
158
    server::Config& config = server::Config::GetInstance();
159
    config.GetStorageConfigS3Enable(s3_enable);
S
shengjh 已提交
160
    fiu_do_on("GetTableFilePath.enable_s3", s3_enable = true);
161
    if (s3_enable) {
C
Cai Yudong 已提交
162 163 164 165 166
        /* need not check file existence */
        table_file.location_ = file_path;
        return Status::OK();
    }

167
    if (boost::filesystem::exists(parent_path)) {
S
starlord 已提交
168 169
        table_file.location_ = file_path;
        return Status::OK();
S
starlord 已提交
170 171 172 173 174
    }

    for (auto& path : options.slave_paths_) {
        parent_path = ConstructParentFolder(path, table_file);
        file_path = parent_path + "/" + table_file.file_id_;
175
        if (boost::filesystem::exists(parent_path)) {
S
starlord 已提交
176 177
            table_file.location_ = file_path;
            return Status::OK();
S
starlord 已提交
178 179 180
        }
    }

S
starlord 已提交
181
    std::string msg = "Table file doesn't exist: " + file_path;
G
groot 已提交
182 183 184
    if (table_file.file_size_ > 0) {  // no need to pop error for empty file
        ENGINE_LOG_ERROR << msg << " in path: " << options.path_ << " for table: " << table_file.table_id_;
    }
S
starlord 已提交
185

S
starlord 已提交
186
    return Status(DB_ERROR, msg);
S
starlord 已提交
187 188
}

S
starlord 已提交
189
Status
S
starlord 已提交
190
DeleteTableFilePath(const DBMetaOptions& options, meta::TableFileSchema& table_file) {
S
starlord 已提交
191 192 193 194 195
    utils::GetTableFilePath(options, table_file);
    boost::filesystem::remove(table_file.location_);
    return Status::OK();
}

196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
Status
DeleteSegment(const DBMetaOptions& options, meta::TableFileSchema& table_file) {
    utils::GetTableFilePath(options, table_file);
    std::string segment_dir;
    GetParentPath(table_file.location_, segment_dir);
    boost::filesystem::remove_all(segment_dir);
    return Status::OK();
}

Status
GetParentPath(const std::string& path, std::string& parent_path) {
    boost::filesystem::path p(path);
    parent_path = p.parent_path().string();
    return Status::OK();
}

S
starlord 已提交
212
bool
S
starlord 已提交
213
IsSameIndex(const TableIndex& index1, const TableIndex& index2) {
214
    return index1.engine_type_ == index2.engine_type_ && index1.extra_params_ == index2.extra_params_ &&
S
starlord 已提交
215
           index1.metric_type_ == index2.metric_type_;
216 217
}

218 219 220 221 222
bool
IsRawIndexType(int32_t type) {
    return (type == (int32_t)EngineType::FAISS_IDMAP) || (type == (int32_t)EngineType::FAISS_BIN_IDMAP);
}

223 224 225 226 227 228 229 230 231 232 233 234 235
bool
IsBinaryIndexType(int32_t index_type) {
    return (index_type == (int32_t)engine::EngineType::FAISS_BIN_IDMAP) ||
           (index_type == (int32_t)engine::EngineType::FAISS_BIN_IVFFLAT);
}

bool
IsBinaryMetricType(int32_t metric_type) {
    return (metric_type == (int32_t)engine::MetricType::HAMMING) ||
           (metric_type == (int32_t)engine::MetricType::JACCARD) ||
           (metric_type == (int32_t)engine::MetricType::TANIMOTO);
}

S
starlord 已提交
236
meta::DateT
S
starlord 已提交
237
GetDate(const std::time_t& t, int day_delta) {
238 239 240 241 242 243
    struct tm ltm;
    localtime_r(&t, &ltm);
    if (day_delta > 0) {
        do {
            ++ltm.tm_mday;
            --day_delta;
S
starlord 已提交
244
        } while (day_delta > 0);
245 246 247 248 249
        mktime(&ltm);
    } else if (day_delta < 0) {
        do {
            --ltm.tm_mday;
            ++day_delta;
S
starlord 已提交
250
        } while (day_delta < 0);
251 252 253 254
        mktime(&ltm);
    } else {
        ltm.tm_mday;
    }
S
starlord 已提交
255
    return ltm.tm_year * 10000 + ltm.tm_mon * 100 + ltm.tm_mday;
256 257
}

S
starlord 已提交
258 259
meta::DateT
GetDateWithDelta(int day_delta) {
260 261 262
    return GetDate(std::time(nullptr), day_delta);
}

S
starlord 已提交
263 264
meta::DateT
GetDate() {
265 266 267
    return GetDate(std::time(nullptr), 0);
}

268
// URI format: dialect://username:password@host:port/database
S
starlord 已提交
269
Status
S
starlord 已提交
270
ParseMetaUri(const std::string& uri, MetaUriInfo& info) {
271 272 273 274 275 276
    std::string dialect_regex = "(.*)";
    std::string username_tegex = "(.*)";
    std::string password_regex = "(.*)";
    std::string host_regex = "(.*)";
    std::string port_regex = "(.*)";
    std::string db_name_regex = "(.*)";
S
starlord 已提交
277 278
    std::string uri_regex_str = dialect_regex + "\\:\\/\\/" + username_tegex + "\\:" + password_regex + "\\@" +
                                host_regex + "\\:" + port_regex + "\\/" + db_name_regex;
279 280 281 282 283 284 285 286 287 288 289 290

    std::regex uri_regex(uri_regex_str);
    std::smatch pieces_match;

    if (std::regex_match(uri, pieces_match, uri_regex)) {
        info.dialect_ = pieces_match[1].str();
        info.username_ = pieces_match[2].str();
        info.password_ = pieces_match[3].str();
        info.host_ = pieces_match[4].str();
        info.port_ = pieces_match[5].str();
        info.db_name_ = pieces_match[6].str();

S
starlord 已提交
291
        // TODO(myh): verify host, port...
292 293 294 295 296 297 298
    } else {
        return Status(DB_INVALID_META_URI, "Invalid meta uri: " + uri);
    }

    return Status::OK();
}

S
starlord 已提交
299 300 301
}  // namespace utils
}  // namespace engine
}  // namespace milvus