ValidationUtil.cpp 10.7 KB
Newer Older
J
jinhai 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
// 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.

S
starlord 已提交
18
#include "utils/ValidationUtil.h"
J
jinhai 已提交
19
#include "Log.h"
S
starlord 已提交
20
#include "db/engine/ExecutionEngine.h"
J
jinhai 已提交
21

Z
zhiru 已提交
22
#include <arpa/inet.h>
S
starlord 已提交
23
#include <cuda_runtime.h>
Z
zhiru 已提交
24
#include <algorithm>
J
JinHai-CN 已提交
25
#include <cmath>
S
starlord 已提交
26 27
#include <regex>
#include <string>
Z
zhiru 已提交
28

J
jinhai 已提交
29 30 31
namespace milvus {
namespace server {

32 33
constexpr size_t TABLE_NAME_SIZE_LIMIT = 255;
constexpr int64_t TABLE_DIMENSION_LIMIT = 16384;
S
starlord 已提交
34
constexpr int32_t INDEX_FILE_SIZE_LIMIT = 4096;  // index trigger size max = 4096 MB
J
jinhai 已提交
35

S
starlord 已提交
36
Status
S
starlord 已提交
37
ValidationUtil::ValidateTableName(const std::string& table_name) {
J
jinhai 已提交
38 39
    // Table name shouldn't be empty.
    if (table_name.empty()) {
40
        std::string msg = "Table name should not be empty.";
S
starlord 已提交
41 42
        SERVER_LOG_ERROR << msg;
        return Status(SERVER_INVALID_TABLE_NAME, msg);
J
jinhai 已提交
43 44
    }

45
    std::string invalid_msg = "Invalid table name: " + table_name + ". ";
J
jinhai 已提交
46
    // Table name size shouldn't exceed 16384.
47
    if (table_name.size() > TABLE_NAME_SIZE_LIMIT) {
48
        std::string msg = invalid_msg + "The length of a table name must be less than 255 characters.";
S
starlord 已提交
49 50
        SERVER_LOG_ERROR << msg;
        return Status(SERVER_INVALID_TABLE_NAME, msg);
J
jinhai 已提交
51 52 53 54 55
    }

    // Table name first character should be underscore or character.
    char first_char = table_name[0];
    if (first_char != '_' && std::isalpha(first_char) == 0) {
56
        std::string msg = invalid_msg + "The first character of a table name must be an underscore or letter.";
S
starlord 已提交
57 58
        SERVER_LOG_ERROR << msg;
        return Status(SERVER_INVALID_TABLE_NAME, msg);
J
jinhai 已提交
59 60 61 62 63 64
    }

    int64_t table_name_size = table_name.size();
    for (int64_t i = 1; i < table_name_size; ++i) {
        char name_char = table_name[i];
        if (name_char != '_' && std::isalnum(name_char) == 0) {
65
            std::string msg = invalid_msg + "Table name can only contain numbers, letters, and underscores.";
S
starlord 已提交
66 67
            SERVER_LOG_ERROR << msg;
            return Status(SERVER_INVALID_TABLE_NAME, msg);
J
jinhai 已提交
68 69 70
        }
    }

S
starlord 已提交
71
    return Status::OK();
J
jinhai 已提交
72 73
}

S
starlord 已提交
74
Status
75
ValidationUtil::ValidateTableDimension(int64_t dimension) {
76 77 78
    if (dimension <= 0 || dimension > TABLE_DIMENSION_LIMIT) {
        std::string msg = "Invalid table dimension: " + std::to_string(dimension) + ". "
            + "The table dimension must be within the range of 1 ~ 16384.";
S
starlord 已提交
79 80
        SERVER_LOG_ERROR << msg;
        return Status(SERVER_INVALID_VECTOR_DIMENSION, msg);
S
starlord 已提交
81
    } else {
S
starlord 已提交
82
        return Status::OK();
J
jinhai 已提交
83 84 85
    }
}

S
starlord 已提交
86
Status
87
ValidationUtil::ValidateTableIndexType(int32_t index_type) {
S
starlord 已提交
88 89
    int engine_type = static_cast<int>(engine::EngineType(index_type));
    if (engine_type <= 0 || engine_type > static_cast<int>(engine::EngineType::MAX_VALUE)) {
90 91
        std::string msg = "Invalid index type: " + std::to_string(index_type) + ". "
            + "Make sure the index type is in IndexType list.";
S
starlord 已提交
92 93
        SERVER_LOG_ERROR << msg;
        return Status(SERVER_INVALID_INDEX_TYPE, msg);
J
jinhai 已提交
94
    }
95

96 97 98 99 100 101 102 103 104
#ifndef CUSTOMIZATION
    // special case, hybird index only available in customize faiss library
    if (engine_type == static_cast<int>(engine::EngineType::FAISS_IVFSQ8H)) {
        std::string msg = "Unsupported index type: " + std::to_string(index_type);
        SERVER_LOG_ERROR << msg;
        return Status(SERVER_INVALID_INDEX_TYPE, msg);
    }
#endif

S
starlord 已提交
105
    return Status::OK();
J
jinhai 已提交
106 107
}

S
starlord 已提交
108
Status
S
starlord 已提交
109
ValidationUtil::ValidateTableIndexNlist(int32_t nlist) {
Z
zhiru 已提交
110
    if (nlist <= 0) {
111 112
        std::string msg = "Invalid index nlist: " + std::to_string(nlist) + ". "
            + "The index nlist must be greater than 0.";
S
starlord 已提交
113 114
        SERVER_LOG_ERROR << msg;
        return Status(SERVER_INVALID_INDEX_NLIST, msg);
S
starlord 已提交
115 116
    }

S
starlord 已提交
117
    return Status::OK();
S
starlord 已提交
118 119
}

S
starlord 已提交
120
Status
121
ValidationUtil::ValidateTableIndexFileSize(int64_t index_file_size) {
Z
zhiru 已提交
122
    if (index_file_size <= 0 || index_file_size > INDEX_FILE_SIZE_LIMIT) {
123 124 125
        std::string msg = "Invalid index file size: " + std::to_string(index_file_size) + ". "
            + "The index file size must be within the range of 1 ~ "
            + std::to_string(INDEX_FILE_SIZE_LIMIT) + ".";
S
starlord 已提交
126 127
        SERVER_LOG_ERROR << msg;
        return Status(SERVER_INVALID_INDEX_FILE_SIZE, msg);
S
starlord 已提交
128 129
    }

S
starlord 已提交
130
    return Status::OK();
S
starlord 已提交
131 132
}

S
starlord 已提交
133
Status
S
starlord 已提交
134
ValidationUtil::ValidateTableIndexMetricType(int32_t metric_type) {
S
starlord 已提交
135 136
    if (metric_type != static_cast<int32_t>(engine::MetricType::L2) &&
        metric_type != static_cast<int32_t>(engine::MetricType::IP)) {
137 138
        std::string msg = "Invalid index metric type: " + std::to_string(metric_type) + ". "
            + "Make sure the metric type is either MetricType.L2 or MetricType.IP.";
S
starlord 已提交
139 140
        SERVER_LOG_ERROR << msg;
        return Status(SERVER_INVALID_INDEX_METRIC_TYPE, msg);
S
starlord 已提交
141
    }
S
starlord 已提交
142
    return Status::OK();
S
starlord 已提交
143 144
}

S
starlord 已提交
145
Status
S
starlord 已提交
146
ValidationUtil::ValidateSearchTopk(int64_t top_k, const engine::meta::TableSchema& table_schema) {
147
    if (top_k <= 0 || top_k > 2048) {
148 149
        std::string msg = "Invalid topk: " + std::to_string(top_k) + ". "
            + "The topk must be within the range of 1 ~ 2048.";
S
starlord 已提交
150 151
        SERVER_LOG_ERROR << msg;
        return Status(SERVER_INVALID_TOPK, msg);
152 153
    }

S
starlord 已提交
154
    return Status::OK();
155 156
}

S
starlord 已提交
157
Status
S
starlord 已提交
158
ValidationUtil::ValidateSearchNprobe(int64_t nprobe, const engine::meta::TableSchema& table_schema) {
159
    if (nprobe <= 0 || nprobe > table_schema.nlist_) {
160 161
        std::string msg = "Invalid nprobe: " + std::to_string(nprobe) + ". "
            + "The nprobe must be within the range of 1 ~ index nlist.";
S
starlord 已提交
162 163
        SERVER_LOG_ERROR << msg;
        return Status(SERVER_INVALID_NPROBE, msg);
164 165
    }

S
starlord 已提交
166
    return Status::OK();
167 168
}

S
starlord 已提交
169
Status
170 171 172
ValidationUtil::ValidateGpuIndex(uint32_t gpu_index) {
    int num_devices = 0;
    auto cuda_err = cudaGetDeviceCount(&num_devices);
S
starlord 已提交
173
    if (cuda_err != cudaSuccess) {
S
starlord 已提交
174 175 176
        std::string msg = "Failed to get gpu card number, cuda error:" + std::to_string(cuda_err);
        SERVER_LOG_ERROR << msg;
        return Status(SERVER_UNEXPECTED_ERROR, msg);
177 178
    }

Z
zhiru 已提交
179
    if (gpu_index >= num_devices) {
S
starlord 已提交
180 181 182
        std::string msg = "Invalid gpu index: " + std::to_string(gpu_index);
        SERVER_LOG_ERROR << msg;
        return Status(SERVER_INVALID_ARGUMENT, msg);
183 184
    }

S
starlord 已提交
185
    return Status::OK();
186 187
}

S
starlord 已提交
188
Status
S
starlord 已提交
189
ValidationUtil::GetGpuMemory(uint32_t gpu_index, size_t& memory) {
190 191 192
    cudaDeviceProp deviceProp;
    auto cuda_err = cudaGetDeviceProperties(&deviceProp, gpu_index);
    if (cuda_err) {
S
starlord 已提交
193 194 195
        std::string msg = "Failed to get gpu properties, cuda error:" + std::to_string(cuda_err);
        SERVER_LOG_ERROR << msg;
        return Status(SERVER_UNEXPECTED_ERROR, msg);
196 197 198
    }

    memory = deviceProp.totalGlobalMem;
S
starlord 已提交
199
    return Status::OK();
200 201
}

S
starlord 已提交
202
Status
S
starlord 已提交
203
ValidationUtil::ValidateIpAddress(const std::string& ip_address) {
Z
zhiru 已提交
204 205 206 207
    struct in_addr address;

    int result = inet_pton(AF_INET, ip_address.c_str(), &address);

Z
zhiru 已提交
208
    switch (result) {
S
starlord 已提交
209 210
        case 1:
            return Status::OK();
S
starlord 已提交
211 212 213 214 215 216 217 218 219 220
        case 0: {
            std::string msg = "Invalid IP address: " + ip_address;
            SERVER_LOG_ERROR << msg;
            return Status(SERVER_INVALID_ARGUMENT, msg);
        }
        default: {
            std::string msg = "IP address conversion error: " + ip_address;
            SERVER_LOG_ERROR << msg;
            return Status(SERVER_UNEXPECTED_ERROR, msg);
        }
Z
zhiru 已提交
221 222 223
    }
}

S
starlord 已提交
224
Status
S
starlord 已提交
225
ValidationUtil::ValidateStringIsNumber(const std::string& str) {
Y
yudong.cai 已提交
226 227
    if (str.empty() || !std::all_of(str.begin(), str.end(), ::isdigit)) {
        return Status(SERVER_INVALID_ARGUMENT, "Invalid number");
Z
zhiru 已提交
228
    }
Y
yudong.cai 已提交
229 230
    try {
        int32_t value = std::stoi(str);
S
starlord 已提交
231
    } catch (...) {
Y
yudong.cai 已提交
232
        return Status(SERVER_INVALID_ARGUMENT, "Invalid number");
Z
zhiru 已提交
233
    }
Y
yudong.cai 已提交
234
    return Status::OK();
Z
zhiru 已提交
235 236
}

S
starlord 已提交
237
Status
S
starlord 已提交
238
ValidationUtil::ValidateStringIsBool(const std::string& str) {
Y
yudong.cai 已提交
239 240
    std::string s = str;
    std::transform(s.begin(), s.end(), s.begin(), ::tolower);
S
starlord 已提交
241
    if (s == "true" || s == "on" || s == "yes" || s == "1" || s == "false" || s == "off" || s == "no" || s == "0" ||
Y
yudong.cai 已提交
242
        s.empty()) {
S
starlord 已提交
243
        return Status::OK();
Z
zhiru 已提交
244
    }
S
starlord 已提交
245
    return Status(SERVER_INVALID_ARGUMENT, "Invalid boolean: " + str);
Z
zhiru 已提交
246 247
}

S
starlord 已提交
248
Status
S
starlord 已提交
249
ValidationUtil::ValidateStringIsFloat(const std::string& str) {
Y
yudong.cai 已提交
250 251
    try {
        float val = std::stof(str);
S
starlord 已提交
252
    } catch (...) {
Y
yudong.cai 已提交
253
        return Status(SERVER_INVALID_ARGUMENT, "Invalid float: " + str);
Z
zhiru 已提交
254
    }
Y
yudong.cai 已提交
255
    return Status::OK();
Z
zhiru 已提交
256 257
}

S
starlord 已提交
258
Status
S
starlord 已提交
259
ValidationUtil::ValidateDbURI(const std::string& uri) {
Z
zhiru 已提交
260 261 262 263 264 265
    std::string dialectRegex = "(.*)";
    std::string usernameRegex = "(.*)";
    std::string passwordRegex = "(.*)";
    std::string hostRegex = "(.*)";
    std::string portRegex = "(.*)";
    std::string dbNameRegex = "(.*)";
S
starlord 已提交
266 267
    std::string uriRegexStr = dialectRegex + "\\:\\/\\/" + usernameRegex + "\\:" + passwordRegex + "\\@" + hostRegex +
                              "\\:" + portRegex + "\\/" + dbNameRegex;
Z
zhiru 已提交
268 269 270 271 272 273 274 275 276 277 278 279 280
    std::regex uriRegex(uriRegexStr);
    std::smatch pieces_match;

    bool okay = true;

    if (std::regex_match(uri, pieces_match, uriRegex)) {
        std::string dialect = pieces_match[1].str();
        std::transform(dialect.begin(), dialect.end(), dialect.begin(), ::tolower);
        if (dialect.find("mysql") == std::string::npos && dialect.find("sqlite") == std::string::npos) {
            SERVER_LOG_ERROR << "Invalid dialect in URI: dialect = " << dialect;
            okay = false;
        }

S
starlord 已提交
281 282 283 284 285 286 287 288 289 290 291
        /*
         *      Could be DNS, skip checking
         *
                std::string host = pieces_match[4].str();
                if (!host.empty() && host != "localhost") {
                    if (ValidateIpAddress(host) != SERVER_SUCCESS) {
                        SERVER_LOG_ERROR << "Invalid host ip address in uri = " << host;
                        okay = false;
                    }
                }
        */
Z
zhiru 已提交
292 293 294

        std::string port = pieces_match[5].str();
        if (!port.empty()) {
S
starlord 已提交
295 296
            auto status = ValidateStringIsNumber(port);
            if (!status.ok()) {
Z
zhiru 已提交
297 298 299 300
                SERVER_LOG_ERROR << "Invalid port in uri = " << port;
                okay = false;
            }
        }
S
starlord 已提交
301
    } else {
Z
zhiru 已提交
302 303 304 305
        SERVER_LOG_ERROR << "Wrong URI format: URI = " << uri;
        okay = false;
    }

S
starlord 已提交
306
    return (okay ? Status::OK() : Status(SERVER_INVALID_ARGUMENT, "Invalid db backend uri"));
Z
zhiru 已提交
307 308
}

S
starlord 已提交
309 310
}  // namespace server
}  // namespace milvus