enhance: support add field (#39800)

after the pr merged, we can support to insert, upsert, build index,
query, search in the added field.
can only do the above operates in added field after add field request
complete, which is a sync operate.

compact will be supported in the next pr.
#39718

---------

Signed-off-by: lixinguo <xinguo.li@zilliz.com>
Co-authored-by: lixinguo <xinguo.li@zilliz.com>
This commit is contained in:
smellthemoon 2025-04-02 14:24:31 +08:00 committed by GitHub
parent 37cf9a0dc1
commit cb1e86e17c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
78 changed files with 5991 additions and 2778 deletions

View File

@ -268,6 +268,127 @@ FieldDataImpl<Type, is_type_entire_row>::FillFieldData(
}
}
// used for generate added field which has no related binlogs
template <typename Type, bool is_type_entire_row>
void
FieldDataImpl<Type, is_type_entire_row>::FillFieldData(
std::optional<DefaultValueType> default_value, ssize_t element_count) {
AssertInfo(nullable_, "added field must be nullable");
if (element_count == 0) {
return;
}
null_count_ = default_value.has_value() ? 0 : element_count;
auto valid_data_ptr = [&] {
ssize_t byte_count = (element_count + 7) / 8;
std::shared_ptr<uint8_t[]> valid_data(new uint8_t[byte_count]);
std::fill(valid_data.get(), valid_data.get() + byte_count, 0x00);
return valid_data;
}();
switch (data_type_) {
case DataType::BOOL: {
FixedVector<bool> values(element_count);
if (default_value.has_value()) {
std::fill(
values.begin(), values.end(), default_value->bool_data());
return FillFieldData(values.data(), nullptr, element_count);
}
return FillFieldData(
values.data(), valid_data_ptr.get(), element_count);
}
case DataType::INT8: {
FixedVector<int8_t> values(element_count);
if (default_value.has_value()) {
std::fill(
values.begin(), values.end(), default_value->int_data());
return FillFieldData(values.data(), nullptr, element_count);
}
return FillFieldData(
values.data(), valid_data_ptr.get(), element_count);
}
case DataType::INT16: {
FixedVector<int16_t> values(element_count);
if (default_value.has_value()) {
std::fill(
values.begin(), values.end(), default_value->int_data());
return FillFieldData(values.data(), nullptr, element_count);
}
return FillFieldData(
values.data(), valid_data_ptr.get(), element_count);
}
case DataType::INT32: {
FixedVector<int32_t> values(element_count);
if (default_value.has_value()) {
std::fill(
values.begin(), values.end(), default_value->int_data());
return FillFieldData(values.data(), nullptr, element_count);
}
return FillFieldData(
values.data(), valid_data_ptr.get(), element_count);
}
case DataType::INT64: {
FixedVector<int64_t> values(element_count);
if (default_value.has_value()) {
std::fill(
values.begin(), values.end(), default_value->long_data());
return FillFieldData(values.data(), nullptr, element_count);
}
return FillFieldData(
values.data(), valid_data_ptr.get(), element_count);
}
case DataType::FLOAT: {
FixedVector<float> values(element_count);
if (default_value.has_value()) {
std::fill(
values.begin(), values.end(), default_value->float_data());
return FillFieldData(values.data(), nullptr, element_count);
}
return FillFieldData(
values.data(), valid_data_ptr.get(), element_count);
}
case DataType::DOUBLE: {
FixedVector<double> values(element_count);
if (default_value.has_value()) {
std::fill(
values.begin(), values.end(), default_value->double_data());
return FillFieldData(values.data(), nullptr, element_count);
}
return FillFieldData(
values.data(), valid_data_ptr.get(), element_count);
}
case DataType::STRING:
case DataType::VARCHAR: {
FixedVector<std::string> values(element_count);
if (default_value.has_value()) {
std::fill(
values.begin(), values.end(), default_value->string_data());
return FillFieldData(values.data(), nullptr, element_count);
}
return FillFieldData(
values.data(), valid_data_ptr.get(), element_count);
}
case DataType::JSON: {
// The code here is not referenced.
// A subclass named FieldDataJsonImpl is implemented, which overloads this function.
FixedVector<Json> values(element_count);
return FillFieldData(
values.data(), valid_data_ptr.get(), element_count);
}
case DataType::ARRAY: {
// todo: add array default_value
FixedVector<Array> values(element_count);
return FillFieldData(
values.data(), valid_data_ptr.get(), element_count);
}
default: {
PanicInfo(DataTypeInvalid,
GetName() + "::FillFieldData" +
" not support data type " +
GetDataTypeName(data_type_));
}
}
}
// scalar data
template class FieldDataImpl<bool, true>;
template class FieldDataImpl<unsigned char, false>;

View File

@ -59,6 +59,10 @@ class FieldDataBase {
virtual void
FillFieldData(const std::shared_ptr<arrow::Array> array) = 0;
virtual void
FillFieldData(const std::optional<DefaultValueType> default_value,
ssize_t element_count) = 0;
// For all FieldDataImpl subclasses, this method returns Type* that points
// at all rows in this field data.
virtual void*
@ -169,6 +173,15 @@ class FieldBitsetImpl : public FieldDataBase {
"not implemented for bitset");
}
void
FillFieldData(const std::optional<DefaultValueType> default_value,
ssize_t element_count) override {
PanicInfo(NotImplemented,
"FillFieldData(const const std::optional<DefaultValueType> "
"default_value, "
"ssize_t element_count) not implemented for bitset");
}
virtual void
FillFieldData(const std::shared_ptr<arrow::StringArray>& array) {
PanicInfo(NotImplemented,
@ -357,6 +370,10 @@ class FieldDataImpl : public FieldDataBase {
void
FillFieldData(const std::shared_ptr<arrow::Array> array) override;
void
FillFieldData(const std::optional<DefaultValueType> default_value,
ssize_t element_count) override;
virtual void
FillFieldData(const std::shared_ptr<arrow::StringArray>& array) {
PanicInfo(NotImplemented,
@ -610,6 +627,27 @@ class FieldDataJsonImpl : public FieldDataImpl<Json, true> {
FillFieldData(json_array);
}
// used for generate added field which has no related binlogs
void
FillFieldData(const std::optional<DefaultValueType> default_value,
ssize_t element_count) override {
// todo: add json default_value
AssertInfo(!default_value.has_value(),
"json type not support default_value");
if (element_count == 0) {
return;
}
null_count_ = element_count;
std::lock_guard lck(tell_mutex_);
if (length_ + element_count > get_num_rows()) {
resize_field_data(length_ + element_count);
}
valid_data_.assign((element_count + 7) / 8, 0x00);
length_ += element_count;
}
void
FillFieldData(const std::shared_ptr<arrow::BinaryArray>& array) override {
auto n = array->length();

View File

@ -14,6 +14,7 @@
#include "common/protobuf_utils.h"
#include <boost/lexical_cast.hpp>
#include <optional>
#include "Consts.h"
@ -76,6 +77,13 @@ FieldMeta::ParseFrom(const milvus::proto::schema::FieldSchema& schema_proto) {
auto data_type = DataType(schema_proto.data_type());
auto default_value = [&]() -> std::optional<DefaultValueType> {
if (!schema_proto.has_default_value()) {
return std::nullopt;
}
return schema_proto.default_value();
}();
if (IsVectorDataType(data_type)) {
auto type_map = RepeatedKeyValToMap(schema_proto.type_params());
auto index_map = RepeatedKeyValToMap(schema_proto.index_params());
@ -85,12 +93,19 @@ FieldMeta::ParseFrom(const milvus::proto::schema::FieldSchema& schema_proto) {
AssertInfo(type_map.count("dim"), "dim not found");
dim = boost::lexical_cast<int64_t>(type_map.at("dim"));
}
if (!index_map.count("metric_type")) {
return FieldMeta{
name, field_id, data_type, dim, std::nullopt, false};
return FieldMeta{name,
field_id,
data_type,
dim,
std::nullopt,
false,
default_value};
}
auto metric_type = index_map.at("metric_type");
return FieldMeta{name, field_id, data_type, dim, metric_type, false};
return FieldMeta{
name, field_id, data_type, dim, metric_type, false, default_value};
}
if (IsStringDataType(data_type)) {
@ -123,7 +138,8 @@ FieldMeta::ParseFrom(const milvus::proto::schema::FieldSchema& schema_proto) {
nullable,
enable_match,
enable_analyzer,
type_map};
type_map,
default_value};
}
if (IsArrayDataType(data_type)) {
@ -131,10 +147,11 @@ FieldMeta::ParseFrom(const milvus::proto::schema::FieldSchema& schema_proto) {
field_id,
data_type,
DataType(schema_proto.element_type()),
nullable};
nullable,
default_value};
}
return FieldMeta{name, field_id, data_type, nullable};
return FieldMeta{name, field_id, data_type, nullable, default_value};
}
} // namespace milvus

View File

@ -41,8 +41,16 @@ class FieldMeta {
FieldMeta&
operator=(FieldMeta&&) = default;
FieldMeta(FieldName name, FieldId id, DataType type, bool nullable)
: name_(std::move(name)), id_(id), type_(type), nullable_(nullable) {
FieldMeta(FieldName name,
FieldId id,
DataType type,
bool nullable,
std::optional<DefaultValueType> default_value)
: name_(std::move(name)),
id_(id),
type_(type),
nullable_(nullable),
default_value_(std::move(default_value)) {
Assert(!IsVectorDataType(type_));
}
@ -50,12 +58,14 @@ class FieldMeta {
FieldId id,
DataType type,
int64_t max_length,
bool nullable)
bool nullable,
std::optional<DefaultValueType> default_value)
: name_(std::move(name)),
id_(id),
type_(type),
nullable_(nullable),
string_info_(StringInfo{max_length}) {
string_info_(StringInfo{max_length}),
default_value_(std::move(default_value)) {
Assert(IsStringDataType(type_));
}
@ -66,13 +76,19 @@ class FieldMeta {
bool nullable,
bool enable_match,
bool enable_analyzer,
std::map<std::string, std::string>& params)
std::map<std::string, std::string>& params,
std::optional<DefaultValueType> default_value)
: name_(std::move(name)),
id_(id),
type_(type),
nullable_(nullable),
string_info_(StringInfo{
max_length, enable_match, enable_analyzer, std::move(params)}) {
max_length,
enable_match,
enable_analyzer,
std::move(params),
}),
default_value_(std::move(default_value)) {
Assert(IsStringDataType(type_));
}
@ -80,12 +96,14 @@ class FieldMeta {
FieldId id,
DataType type,
DataType element_type,
bool nullable)
bool nullable,
std::optional<DefaultValueType> default_value)
: name_(std::move(name)),
id_(id),
type_(type),
element_type_(element_type),
nullable_(nullable) {
nullable_(nullable),
default_value_(std::move(default_value)) {
Assert(IsArrayDataType(type_));
}
@ -96,12 +114,14 @@ class FieldMeta {
DataType type,
int64_t dim,
std::optional<knowhere::MetricType> metric_type,
bool nullable)
bool nullable,
std::optional<DefaultValueType> default_value)
: name_(std::move(name)),
id_(id),
type_(type),
nullable_(nullable),
vector_info_(VectorInfo{dim, std::move(metric_type)}) {
vector_info_(VectorInfo{dim, std::move(metric_type)}),
default_value_(std::move(default_value)) {
Assert(IsVectorDataType(type_));
Assert(!nullable);
}
@ -178,6 +198,16 @@ class FieldMeta {
return nullable_;
}
bool
has_default_value() const {
return default_value_.has_value();
}
std::optional<DefaultValueType>
default_value() const {
return default_value_;
}
size_t
get_sizeof() const {
AssertInfo(!IsSparseFloatVectorDataType(type_),
@ -217,6 +247,7 @@ class FieldMeta {
DataType type_ = DataType::NONE;
DataType element_type_ = DataType::NONE;
bool nullable_;
std::optional<DefaultValueType> default_value_;
std::optional<VectorInfo> vector_info_;
std::optional<StringInfo> string_info_;
};

View File

@ -14,6 +14,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cstddef>
#include <optional>
#include <string>
#include <boost/lexical_cast.hpp>
@ -61,9 +62,7 @@ Schema::ParseFrom(const milvus::proto::schema::CollectionSchema& schema_proto) {
return schema;
}
const FieldMeta FieldMeta::RowIdMeta(FieldName("RowID"),
RowFieldID,
DataType::INT64,
false);
const FieldMeta FieldMeta::RowIdMeta(
FieldName("RowID"), RowFieldID, DataType::INT64, false, std::nullopt);
} // namespace milvus

View File

@ -39,7 +39,20 @@ class Schema {
bool nullable = false) {
auto field_id = FieldId(debug_id);
debug_id++;
this->AddField(FieldName(name), field_id, data_type, nullable);
this->AddField(
FieldName(name), field_id, data_type, nullable, std::nullopt);
return field_id;
}
FieldId
AddDebugFieldWithDefaultValue(const std::string& name,
DataType data_type,
DefaultValueType value,
bool nullable = true) {
auto field_id = FieldId(debug_id);
debug_id++;
this->AddField(
FieldName(name), field_id, data_type, nullable, std::move(value));
return field_id;
}
@ -74,8 +87,13 @@ class Schema {
std::optional<knowhere::MetricType> metric_type) {
auto field_id = FieldId(debug_id);
debug_id++;
auto field_meta = FieldMeta(
FieldName(name), field_id, data_type, dim, metric_type, false);
auto field_meta = FieldMeta(FieldName(name),
field_id,
data_type,
dim,
metric_type,
false,
std::nullopt);
this->AddField(std::move(field_meta));
return field_id;
}
@ -85,8 +103,10 @@ class Schema {
AddField(const FieldName& name,
const FieldId id,
DataType data_type,
bool nullable) {
auto field_meta = FieldMeta(name, id, data_type, nullable);
bool nullable,
std::optional<DefaultValueType> default_value) {
auto field_meta =
FieldMeta(name, id, data_type, nullable, std::move(default_value));
this->AddField(std::move(field_meta));
}
@ -97,8 +117,8 @@ class Schema {
DataType data_type,
DataType element_type,
bool nullable) {
auto field_meta =
FieldMeta(name, id, data_type, element_type, nullable);
auto field_meta = FieldMeta(
name, id, data_type, element_type, nullable, std::nullopt);
this->AddField(std::move(field_meta));
}
@ -108,8 +128,14 @@ class Schema {
const FieldId id,
DataType data_type,
int64_t max_length,
bool nullable) {
auto field_meta = FieldMeta(name, id, data_type, max_length, nullable);
bool nullable,
std::optional<DefaultValueType> default_value) {
auto field_meta = FieldMeta(name,
id,
data_type,
max_length,
nullable,
std::move(default_value));
this->AddField(std::move(field_meta));
}
@ -122,7 +148,8 @@ class Schema {
bool nullable,
bool enable_match,
bool enable_analyzer,
std::map<std::string, std::string>& params) {
std::map<std::string, std::string>& params,
std::optional<DefaultValueType> default_value) {
auto field_meta = FieldMeta(name,
id,
data_type,
@ -130,7 +157,8 @@ class Schema {
nullable,
enable_match,
enable_analyzer,
params);
params,
std::move(default_value));
this->AddField(std::move(field_meta));
}
@ -142,8 +170,8 @@ class Schema {
int64_t dim,
std::optional<knowhere::MetricType> metric_type,
bool nullable) {
auto field_meta =
FieldMeta(name, id, data_type, dim, metric_type, false);
auto field_meta = FieldMeta(
name, id, data_type, dim, metric_type, false, std::nullopt);
this->AddField(std::move(field_meta));
}

View File

@ -103,6 +103,7 @@ using VectorArray = proto::schema::VectorField;
using IdArray = proto::schema::IDs;
using InsertRecordProto = proto::segcore::InsertRecord;
using PkType = std::variant<std::monostate, int64_t, std::string>;
using DefaultValueType = proto::schema::ValueField;
inline size_t
GetDataTypeSize(DataType data_type, int dim = 1) {

View File

@ -16,6 +16,7 @@
#include <algorithm>
#include <boost/algorithm/string.hpp>
#include <optional>
#include <sys/errno.h>
#include <unistd.h>
#include <yaml-cpp/yaml.h>
@ -77,6 +78,25 @@ BitmapIndex<T>::Build(const Config& config) {
auto field_datas =
file_manager_->CacheRawDataToMemory(insert_files.value());
auto lack_binlog_rows =
GetValueFromConfig<int64_t>(config, "lack_binlog_rows");
if (lack_binlog_rows.has_value()) {
auto field_schema = file_manager_->GetFieldDataMeta().field_schema;
auto default_value = [&]() -> std::optional<DefaultValueType> {
if (!field_schema.has_default_value()) {
return std::nullopt;
}
return field_schema.default_value();
}();
auto field_data = storage::CreateFieldData(
static_cast<DataType>(field_schema.data_type()),
true,
1,
lack_binlog_rows.value());
field_data->FillFieldData(default_value, lack_binlog_rows.value());
field_datas.insert(field_datas.begin(), field_data);
}
BuildWithFieldData(field_datas);
}
@ -1103,7 +1123,7 @@ template <typename T>
std::optional<T>
BitmapIndex<T>::Reverse_Lookup(size_t idx) const {
AssertInfo(is_built_, "index has not been built");
AssertInfo(idx < total_num_rows_, "out of range of total coun");
AssertInfo(idx < total_num_rows_, "out of range of total count");
if (!valid_bitset_[idx]) {
return std::nullopt;

View File

@ -251,6 +251,25 @@ HybridScalarIndex<T>::Build(const Config& config) {
auto field_datas =
mem_file_manager_->CacheRawDataToMemory(insert_files.value());
auto lack_binlog_rows =
GetValueFromConfig<int64_t>(config, "lack_binlog_rows");
if (lack_binlog_rows.has_value()) {
auto field_schema = mem_file_manager_->GetFieldDataMeta().field_schema;
auto default_value = [&]() -> std::optional<DefaultValueType> {
if (!field_schema.has_default_value()) {
return std::nullopt;
}
return field_schema.default_value();
}();
auto field_data = storage::CreateFieldData(
static_cast<DataType>(field_schema.data_type()),
true,
1,
lack_binlog_rows.value());
field_data->FillFieldData(default_value, lack_binlog_rows.value());
field_datas.insert(field_datas.begin(), field_data);
}
SelectIndexBuildType(field_datas);
BuildInternal(field_datas);
auto index_meta = file_manager_context_.indexMeta;

View File

@ -162,6 +162,24 @@ InvertedIndexTantivy<T>::Build(const Config& config) {
AssertInfo(insert_files.has_value(), "insert_files were empty");
auto field_datas =
mem_file_manager_->CacheRawDataToMemory(insert_files.value());
auto lack_binlog_rows =
GetValueFromConfig<int64_t>(config, "lack_binlog_rows");
if (lack_binlog_rows.has_value()) {
auto field_schema = mem_file_manager_->GetFieldDataMeta().field_schema;
auto default_value = [&]() -> std::optional<DefaultValueType> {
if (!field_schema.has_default_value()) {
return std::nullopt;
}
return field_schema.default_value();
}();
auto field_data = storage::CreateFieldData(
static_cast<DataType>(field_schema.data_type()),
true,
1,
lack_binlog_rows.value());
field_data->FillFieldData(default_value, lack_binlog_rows.value());
field_datas.insert(field_datas.begin(), field_data);
}
BuildWithFieldData(field_datas);
}

View File

@ -57,6 +57,25 @@ ScalarIndexSort<T>::Build(const Config& config) {
auto field_datas =
file_manager_->CacheRawDataToMemory(insert_files.value());
auto lack_binlog_rows =
GetValueFromConfig<int64_t>(config, "lack_binlog_rows");
if (lack_binlog_rows.has_value()) {
auto field_schema = file_manager_->GetFieldDataMeta().field_schema;
auto default_value = [&]() -> std::optional<DefaultValueType> {
if (!field_schema.has_default_value()) {
return std::nullopt;
}
return field_schema.default_value();
}();
auto field_data = storage::CreateFieldData(
static_cast<DataType>(field_schema.data_type()),
true,
1,
lack_binlog_rows.value());
field_data->FillFieldData(default_value, lack_binlog_rows.value());
field_datas.insert(field_datas.begin(), field_data);
}
BuildWithFieldData(field_datas);
}

View File

@ -73,6 +73,25 @@ StringIndexMarisa::Build(const Config& config) {
auto field_datas =
file_manager_->CacheRawDataToMemory(insert_files.value());
auto lack_binlog_rows =
GetValueFromConfig<int64_t>(config, "lack_binlog_rows");
if (lack_binlog_rows.has_value()) {
auto field_schema = file_manager_->GetFieldDataMeta().field_schema;
auto default_value = [&]() -> std::optional<DefaultValueType> {
if (!field_schema.has_default_value()) {
return std::nullopt;
}
return field_schema.default_value();
}();
auto field_data = storage::CreateFieldData(
static_cast<DataType>(field_schema.data_type()),
true,
1,
lack_binlog_rows.value());
field_data->FillFieldData(default_value, lack_binlog_rows.value());
field_datas.insert(field_datas.begin(), field_data);
}
BuildWithFieldData(field_datas);
}

View File

@ -145,6 +145,7 @@ get_config(std::unique_ptr<milvus::proto::indexcgo::BuildIndexInfo>& info) {
if (info->opt_fields().size()) {
config["opt_fields"] = get_opt_field(info->opt_fields());
}
config["lack_binlog_rows"] = info->lack_binlog_rows();
if (info->partition_key_isolation()) {
config["partition_key_isolation"] = info->partition_key_isolation();
}

View File

@ -20,6 +20,7 @@
#include <cstdint>
#include <filesystem>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <unordered_map>
@ -277,8 +278,11 @@ ChunkedSegmentSealedImpl::LoadFieldData(FieldId field_id, FieldDataInfo& data) {
if (system_field_type == SystemFieldType::Timestamp) {
std::vector<Timestamp> timestamps(num_rows);
int64_t offset = 0;
FieldMeta field_meta(
FieldName(""), FieldId(0), DataType::INT64, false);
FieldMeta field_meta(FieldName(""),
FieldId(0),
DataType::INT64,
false,
std::nullopt);
std::shared_ptr<milvus::ArrowDataWrapper> r;
while (data.arrow_reader_channel->pop(r)) {
auto chunk = std::dynamic_pointer_cast<FixedWidthChunk>(
@ -1116,9 +1120,12 @@ ChunkedSegmentSealedImpl::check_search(const query::Plan* plan) const {
auto field_id =
FieldId(absent_fields.find_first().value() + START_USER_FIELDID);
auto& field_meta = schema_->operator[](field_id);
PanicInfo(
FieldNotLoaded,
"User Field(" + field_meta.get_name().get() + ") is not loaded");
// request field may has added field
if (!field_meta.is_nullable()) {
PanicInfo(FieldNotLoaded,
"User Field(" + field_meta.get_name().get() +
") is not loaded");
}
}
}

View File

@ -203,6 +203,12 @@ class ChunkedSegmentSealedImpl : public SegmentSealed {
void
ClearData() override;
bool
is_field_exist(FieldId field_id) const override {
return schema_->get_fields().find(field_id) !=
schema_->get_fields().end();
}
protected:
// blob and row_count
SpanBase

View File

@ -291,9 +291,6 @@ struct InsertRecord {
for (auto& field : schema) {
auto field_id = field.first;
auto& field_meta = field.second;
if (field_meta.is_nullable()) {
this->append_valid_data(field_id);
}
if (pk2offset_ == nullptr && pk_field_id.has_value() &&
pk_field_id.value() == field_id) {
switch (field_meta.get_data_type()) {
@ -324,90 +321,7 @@ struct InsertRecord {
}
}
}
if (field_meta.is_vector()) {
if (field_meta.get_data_type() == DataType::VECTOR_FLOAT) {
this->append_data<FloatVector>(
field_id, field_meta.get_dim(), size_per_chunk);
continue;
} else if (field_meta.get_data_type() ==
DataType::VECTOR_BINARY) {
this->append_data<BinaryVector>(
field_id, field_meta.get_dim(), size_per_chunk);
continue;
} else if (field_meta.get_data_type() ==
DataType::VECTOR_FLOAT16) {
this->append_data<Float16Vector>(
field_id, field_meta.get_dim(), size_per_chunk);
continue;
} else if (field_meta.get_data_type() ==
DataType::VECTOR_BFLOAT16) {
this->append_data<BFloat16Vector>(
field_id, field_meta.get_dim(), size_per_chunk);
continue;
} else if (field_meta.get_data_type() ==
DataType::VECTOR_SPARSE_FLOAT) {
this->append_data<SparseFloatVector>(field_id,
size_per_chunk);
continue;
} else if (field_meta.get_data_type() ==
DataType::VECTOR_INT8) {
this->append_data<Int8Vector>(
field_id, field_meta.get_dim(), size_per_chunk);
continue;
} else {
PanicInfo(DataTypeInvalid,
fmt::format("unsupported vector type",
field_meta.get_data_type()));
}
}
switch (field_meta.get_data_type()) {
case DataType::BOOL: {
this->append_data<bool>(field_id, size_per_chunk);
break;
}
case DataType::INT8: {
this->append_data<int8_t>(field_id, size_per_chunk);
break;
}
case DataType::INT16: {
this->append_data<int16_t>(field_id, size_per_chunk);
break;
}
case DataType::INT32: {
this->append_data<int32_t>(field_id, size_per_chunk);
break;
}
case DataType::INT64: {
this->append_data<int64_t>(field_id, size_per_chunk);
break;
}
case DataType::FLOAT: {
this->append_data<float>(field_id, size_per_chunk);
break;
}
case DataType::DOUBLE: {
this->append_data<double>(field_id, size_per_chunk);
break;
}
case DataType::VARCHAR:
case DataType::TEXT: {
this->append_data<std::string>(field_id, size_per_chunk);
break;
}
case DataType::JSON: {
this->append_data<Json>(field_id, size_per_chunk);
break;
}
case DataType::ARRAY: {
this->append_data<Array>(field_id, size_per_chunk);
break;
}
default: {
PanicInfo(DataTypeInvalid,
fmt::format("unsupported scalar type",
field_meta.get_data_type()));
}
}
append_field_meta(field_id, field_meta, size_per_chunk);
}
}
@ -632,6 +546,95 @@ struct InsertRecord {
return data->get_span_base(chunk_id);
}
void
append_field_meta(FieldId field_id,
const FieldMeta& field_meta,
int64_t size_per_chunk) {
if (field_meta.is_nullable()) {
this->append_valid_data(field_id);
}
if (field_meta.is_vector()) {
if (field_meta.get_data_type() == DataType::VECTOR_FLOAT) {
this->append_data<FloatVector>(
field_id, field_meta.get_dim(), size_per_chunk);
return;
} else if (field_meta.get_data_type() == DataType::VECTOR_BINARY) {
this->append_data<BinaryVector>(
field_id, field_meta.get_dim(), size_per_chunk);
return;
} else if (field_meta.get_data_type() == DataType::VECTOR_FLOAT16) {
this->append_data<Float16Vector>(
field_id, field_meta.get_dim(), size_per_chunk);
return;
} else if (field_meta.get_data_type() ==
DataType::VECTOR_BFLOAT16) {
this->append_data<BFloat16Vector>(
field_id, field_meta.get_dim(), size_per_chunk);
return;
} else if (field_meta.get_data_type() ==
DataType::VECTOR_SPARSE_FLOAT) {
this->append_data<SparseFloatVector>(field_id, size_per_chunk);
return;
} else if (field_meta.get_data_type() == DataType::VECTOR_INT8) {
this->append_data<Int8Vector>(
field_id, field_meta.get_dim(), size_per_chunk);
return;
} else {
PanicInfo(DataTypeInvalid,
fmt::format("unsupported vector type",
field_meta.get_data_type()));
}
}
switch (field_meta.get_data_type()) {
case DataType::BOOL: {
this->append_data<bool>(field_id, size_per_chunk);
return;
}
case DataType::INT8: {
this->append_data<int8_t>(field_id, size_per_chunk);
return;
}
case DataType::INT16: {
this->append_data<int16_t>(field_id, size_per_chunk);
return;
}
case DataType::INT32: {
this->append_data<int32_t>(field_id, size_per_chunk);
return;
}
case DataType::INT64: {
this->append_data<int64_t>(field_id, size_per_chunk);
return;
}
case DataType::FLOAT: {
this->append_data<float>(field_id, size_per_chunk);
return;
}
case DataType::DOUBLE: {
this->append_data<double>(field_id, size_per_chunk);
return;
}
case DataType::VARCHAR:
case DataType::TEXT: {
this->append_data<std::string>(field_id, size_per_chunk);
return;
}
case DataType::JSON: {
this->append_data<Json>(field_id, size_per_chunk);
return;
}
case DataType::ARRAY: {
this->append_data<Array>(field_id, size_per_chunk);
return;
}
default: {
PanicInfo(DataTypeInvalid,
fmt::format("unsupported scalar type",
field_meta.get_data_type()));
}
}
}
// append a column of scalar or sparse float vector type
template <typename Type>
void

View File

@ -13,6 +13,7 @@
#include <cstring>
#include <memory>
#include <numeric>
#include <optional>
#include <queue>
#include <thread>
#include <boost/iterator/counting_iterator.hpp>
@ -80,10 +81,26 @@ SegmentGrowingImpl::Insert(int64_t reserved_offset,
// step 1: check insert data if valid
std::unordered_map<FieldId, int64_t> field_id_to_offset;
int64_t field_offset = 0;
int64_t exist_rows = stats_.mem_size / (sizeof(Timestamp) + sizeof(idx_t));
for (const auto& field : insert_record_proto->fields_data()) {
auto field_id = FieldId(field.field_id());
AssertInfo(!field_id_to_offset.count(field_id), "duplicate field data");
field_id_to_offset.emplace(field_id, field_offset++);
// may be added field, add the null if has existed data
if (exist_rows > 0 && !insert_record_.is_data_exist(field_id)) {
schema_->AddField(FieldName(field.field_name()),
field_id,
DataType(field.type()),
true,
std::nullopt);
auto field_meta = schema_->get_fields().at(field_id);
insert_record_.append_field_meta(
field_id, field_meta, size_per_chunk());
auto data = bulk_subscript_not_exist_field(field_meta, exist_rows);
insert_record_.get_data_base(field_id)->set_data_raw(
0, exist_rows, data.get(), field_meta);
}
}
// step 2: sort timestamp
@ -214,6 +231,26 @@ SegmentGrowingImpl::LoadFieldData(const LoadFieldDataInfo& infos) {
auto& pool =
ThreadPools::GetThreadPool(milvus::ThreadPoolPriority::MIDDLE);
int total = 0;
for (int num : info.entries_nums) {
total += num;
}
if (total != info.row_count) {
AssertInfo(total <= info.row_count,
"binlog number should less than or equal row_count");
auto field_meta = get_schema()[field_id];
AssertInfo(field_meta.is_nullable(),
"nullable must be true when lack rows");
auto lack_num = info.row_count - total;
auto field_data = storage::CreateFieldData(
static_cast<DataType>(field_meta.get_data_type()),
true,
1,
lack_num);
field_data->FillFieldData(field_meta.default_value(), lack_num);
channel->push(field_data);
}
LOG_INFO("segment {} loads field {} with num_rows {}",
this->get_segment_id(),
field_id.get(),
@ -449,8 +486,8 @@ std::unique_ptr<DataArray>
SegmentGrowingImpl::bulk_subscript(FieldId field_id,
const int64_t* seg_offsets,
int64_t count) const {
auto vec_ptr = insert_record_.get_data_base(field_id);
auto& field_meta = schema_->operator[](field_id);
auto vec_ptr = insert_record_.get_data_base(field_id);
if (field_meta.is_vector()) {
auto result = CreateVectorDataArray(count, field_meta);
if (field_meta.get_data_type() == DataType::VECTOR_FLOAT) {
@ -513,6 +550,7 @@ SegmentGrowingImpl::bulk_subscript(FieldId field_id,
AssertInfo(!field_meta.is_vector(),
"Scalar field meta type is vector type");
auto result = CreateScalarDataArray(count, field_meta);
if (field_meta.is_nullable()) {
auto valid_data_ptr = insert_record_.get_valid_data(field_id);

View File

@ -352,6 +352,12 @@ class SegmentGrowingImpl : public SegmentGrowing {
return insert_record_.search_pk(pk, insert_barrier);
}
bool
is_field_exist(FieldId field_id) const override {
return schema_->get_fields().find(field_id) !=
schema_->get_fields().end();
}
protected:
int64_t
num_chunk(FieldId field_id) const override;

View File

@ -59,6 +59,7 @@ SegmentInternalInterface::FillTargetEntry(const query::Plan* plan,
std::unique_ptr<DataArray> field_data;
// fill other entries except primary key by result_offset
for (auto field_id : plan->target_entries_) {
auto& field_meta = plan->schema_[field_id];
if (plan->schema_.get_dynamic_field_id().has_value() &&
plan->schema_.get_dynamic_field_id().value() == field_id &&
!plan->target_dynamic_fields_.empty()) {
@ -67,6 +68,9 @@ SegmentInternalInterface::FillTargetEntry(const query::Plan* plan,
results.seg_offsets_.data(),
size,
target_dynamic_fields));
} else if (!is_field_exist(field_id)) {
field_data =
std::move(bulk_subscript_not_exist_field(field_meta, size));
} else {
field_data = std::move(
bulk_subscript(field_id, results.seg_offsets_.data(), size));
@ -197,10 +201,13 @@ SegmentInternalInterface::FillTargetEntry(
fields_data->AddAllocated(col.release());
continue;
}
std::unique_ptr<DataArray> col;
auto& field_meta = plan->schema_[field_id];
auto col = bulk_subscript(field_id, offsets, size);
if (!is_field_exist(field_id)) {
col = std::move(bulk_subscript_not_exist_field(field_meta, size));
} else {
col = bulk_subscript(field_id, offsets, size);
}
if (field_meta.get_data_type() == DataType::ARRAY) {
col->mutable_scalars()->mutable_array_data()->set_element_type(
proto::schema::DataType(field_meta.get_element_type()));
@ -423,4 +430,102 @@ SegmentInternalInterface::GetTextIndex(FieldId field_id) const {
return iter->second.get();
}
std::unique_ptr<DataArray>
SegmentInternalInterface::bulk_subscript_not_exist_field(
const milvus::FieldMeta& field_meta, int64_t count) const {
auto data_type = field_meta.get_data_type();
if (IsVectorDataType(data_type)) {
PanicInfo(DataTypeInvalid,
fmt::format("unsupported added field type {}",
field_meta.get_data_type()));
}
auto result = CreateScalarDataArray(count, field_meta);
if (field_meta.default_value().has_value()) {
auto res = result->mutable_valid_data()->mutable_data();
for (int64_t i = 0; i < count; ++i) {
res[i] = true;
}
switch (field_meta.get_data_type()) {
case DataType::BOOL: {
auto data_ptr = result->mutable_scalars()
->mutable_bool_data()
->mutable_data()
->mutable_data();
for (int64_t i = 0; i < count; ++i) {
data_ptr[i] = field_meta.default_value()->bool_data();
}
break;
}
case DataType::INT8:
case DataType::INT16:
case DataType::INT32: {
auto data_ptr = result->mutable_scalars()
->mutable_int_data()
->mutable_data()
->mutable_data();
for (int64_t i = 0; i < count; ++i) {
data_ptr[i] = field_meta.default_value()->int_data();
}
break;
}
case DataType::INT64: {
auto data_ptr = result->mutable_scalars()
->mutable_long_data()
->mutable_data()
->mutable_data();
for (int64_t i = 0; i < count; ++i) {
data_ptr[i] = field_meta.default_value()->long_data();
}
break;
}
case DataType::FLOAT: {
auto data_ptr = result->mutable_scalars()
->mutable_float_data()
->mutable_data()
->mutable_data();
for (int64_t i = 0; i < count; ++i) {
data_ptr[i] = field_meta.default_value()->float_data();
}
break;
}
case DataType::DOUBLE: {
auto data_ptr = result->mutable_scalars()
->mutable_double_data()
->mutable_data()
->mutable_data();
for (int64_t i = 0; i < count; ++i) {
data_ptr[i] = field_meta.default_value()->double_data();
}
break;
}
case DataType::VARCHAR: {
auto data_ptr = result->mutable_scalars()
->mutable_string_data()
->mutable_data();
for (int64_t i = 0; i < count; ++i) {
data_ptr->at(i) = field_meta.default_value()->string_data();
}
break;
}
default: {
PanicInfo(DataTypeInvalid,
fmt::format("unsupported default value type {}",
field_meta.get_data_type()));
}
}
return result;
};
for (int64_t i = 0; i < count; ++i) {
auto res = result->mutable_valid_data()->mutable_data();
res[i] = false;
}
return result;
}
} // namespace milvus::segcore

View File

@ -424,6 +424,10 @@ class SegmentInternalInterface : public SegmentInterface {
virtual bool
is_mmap_field(FieldId field_id) const = 0;
virtual std::unique_ptr<DataArray>
bulk_subscript_not_exist_field(const milvus::FieldMeta& field_meta,
int64_t count) const;
protected:
// todo: use an Unified struct for all type in growing/seal segment to store data and valid_data.
// internal API: return chunk_data in span
@ -472,6 +476,8 @@ class SegmentInternalInterface : public SegmentInterface {
PanicInfo(ErrorCode::NotImplemented, "not implemented");
};
virtual bool
is_field_exist(FieldId field_id) const = 0;
// calculate output[i] = Vec[seg_offsets[i]}, where Vec binds to system_type
virtual void
bulk_subscript(SystemFieldType system_type,

View File

@ -19,6 +19,7 @@
#include <cstdint>
#include <filesystem>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <tuple>
@ -321,6 +322,27 @@ SegmentSealedImpl::LoadFieldData(const LoadFieldDataInfo& load_info) {
auto parallel_degree = static_cast<uint64_t>(
DEFAULT_FIELD_MAX_MEMORY_LIMIT / FILE_SLICE_SIZE);
field_data_info.channel->set_capacity(parallel_degree * 2);
int total = 0;
for (int num : info.entries_nums) {
total += num;
}
if (total != info.row_count) {
AssertInfo(total <= info.row_count,
"binlog number should less than row_count");
auto lack_num = info.row_count - total;
auto field_meta = get_schema()[field_id];
AssertInfo(field_meta.is_nullable(),
"nullable must be true when lack rows");
auto field_data = storage::CreateFieldData(
static_cast<DataType>(field_meta.get_data_type()),
true,
1,
lack_num);
field_data->FillFieldData(field_meta.default_value(), lack_num);
field_data_info.channel->push(field_data);
}
// field_data_info.channel.push();
auto& pool =
ThreadPools::GetThreadPool(milvus::ThreadPoolPriority::MIDDLE);
pool.Submit(
@ -1033,8 +1055,8 @@ std::tuple<
MmapChunkDescriptorPtr&
descriptor) {
// For mmap mode, field_meta is unused, so just construct a fake field meta.
auto fm =
FieldMeta(FieldName(""), FieldId(0), milvus::DataType::NONE, false);
auto fm = FieldMeta(
FieldName(""), FieldId(0), milvus::DataType::NONE, false, std::nullopt);
// TODO: add Load() interface for chunk cache when support retrieve_enable, make Read() raise error if cache miss
auto column = cc->Read(data_path, descriptor, fm, true);
cc->Prefetch(data_path);
@ -1216,19 +1238,22 @@ SegmentSealedImpl::check_search(const query::Plan* plan) const {
auto& request_fields = plan->extra_info_opt_.value().involved_fields_;
auto field_ready_bitset =
field_data_ready_bitset_ | index_ready_bitset_ | binlog_index_bitset_;
AssertInfo(request_fields.size() == field_ready_bitset.size(),
"Request fields size not equal to field ready bitset size when "
AssertInfo(request_fields.size() >= field_ready_bitset.size(),
"Request fields size less than field ready bitset size when "
"check search");
auto absent_fields = request_fields - field_ready_bitset;
if (absent_fields.any()) {
// absent_fields.find_first() returns std::optional<>
auto field_id =
FieldId(absent_fields.find_first().value() + START_USER_FIELDID);
auto& field_meta = schema_->operator[](field_id);
PanicInfo(
FieldNotLoaded,
"User Field(" + field_meta.get_name().get() + ") is not loaded");
// request field may has added field
if (!field_meta.is_nullable()) {
PanicInfo(FieldNotLoaded,
"User Field(" + field_meta.get_name().get() +
") is not loaded");
}
}
}

View File

@ -216,6 +216,12 @@ class SegmentSealedImpl : public SegmentSealed {
void
ClearData() override;
bool
is_field_exist(FieldId field_id) const override {
return schema_->get_fields().find(field_id) !=
schema_->get_fields().end();
}
protected:
// blob and row_count
SpanBase

View File

@ -229,6 +229,9 @@ class ArrayBitmapIndexTest : public testing::Test {
config["index_type"] = milvus::index::HYBRID_INDEX_TYPE;
config["insert_files"] = std::vector<std::string>{log_path};
config["bitmap_cardinality_limit"] = "100";
if (has_lack_binlog_row_) {
config["lack_binlog_rows"] = lack_binlog_row_;
}
{
auto build_index =
@ -314,10 +317,18 @@ class ArrayBitmapIndexTest : public testing::Test {
}
auto index_ptr = dynamic_cast<index::ScalarIndex<T>*>(index_.get());
auto bitset = index_ptr->In(test_data.size(), test_data.data());
for (size_t i = 0; i < bitset.size(); i++) {
size_t start = 0;
if (has_lack_binlog_row_) {
// all null here
for (int i = 0; i < lack_binlog_row_; i++) {
ASSERT_EQ(bitset[i], false);
}
start += lack_binlog_row_;
}
for (size_t i = start; i < bitset.size(); i++) {
auto ref = [&]() -> bool {
milvus::Array array = data_[i];
if (nullable_ && !valid_data_[i]) {
milvus::Array array = data_[i - start];
if (nullable_ && !valid_data_[i - start]) {
return false;
}
for (size_t j = 0; j < array.length(); ++j) {
@ -345,6 +356,8 @@ class ArrayBitmapIndexTest : public testing::Test {
FixedVector<bool> valid_data_;
int index_version_;
int index_build_id_;
bool has_lack_binlog_row_{false};
size_t lack_binlog_row_{100};
};
TYPED_TEST_SUITE_P(ArrayBitmapIndexTest);
@ -420,10 +433,39 @@ TYPED_TEST_P(ArrayBitmapIndexTestNullable, CountFuncTest) {
EXPECT_EQ(count, this->nb_);
}
template <typename T>
class ArrayBitmapIndexTestV2 : public ArrayBitmapIndexTest<T> {
public:
virtual void
SetParam() override {
this->nb_ = 10000;
this->cardinality_ = 30;
this->nullable_ = true;
this->index_version_ = 2003;
this->index_build_id_ = 2003;
this->has_lack_binlog_row_ = true;
}
virtual ~ArrayBitmapIndexTestV2() {
}
};
TYPED_TEST_SUITE_P(ArrayBitmapIndexTestV2);
TYPED_TEST_P(ArrayBitmapIndexTestV2, CountFuncTest) {
auto count = this->index_->Count();
if (this->has_lack_binlog_row_) {
EXPECT_EQ(count, this->nb_ + this->lack_binlog_row_);
} else {
EXPECT_EQ(count, this->nb_);
}
}
using BitmapTypeV1 = testing::Types<int32_t, int64_t, std::string>;
REGISTER_TYPED_TEST_SUITE_P(ArrayBitmapIndexTestV1, CountFuncTest);
REGISTER_TYPED_TEST_SUITE_P(ArrayBitmapIndexTestNullable, CountFuncTest);
REGISTER_TYPED_TEST_SUITE_P(ArrayBitmapIndexTestV2, CountFuncTest);
INSTANTIATE_TYPED_TEST_SUITE_P(ArrayBitmapE2ECheckV1,
ArrayBitmapIndexTestV1,
@ -431,4 +473,8 @@ INSTANTIATE_TYPED_TEST_SUITE_P(ArrayBitmapE2ECheckV1,
INSTANTIATE_TYPED_TEST_SUITE_P(ArrayBitmapE2ECheckV1,
ArrayBitmapIndexTestNullable,
BitmapTypeV1);
INSTANTIATE_TYPED_TEST_SUITE_P(ArrayBitmapE2ECheckV1,
ArrayBitmapIndexTestV2,
BitmapTypeV1);

View File

@ -11,6 +11,7 @@
#include <gtest/gtest.h>
#include <boost/format.hpp>
#include <optional>
#include <regex>
#include "index/IndexFactory.h"
@ -122,8 +123,11 @@ class BinlogIndexTest : public ::testing::TestWithParam<Param> {
auto dataset = DataGen(schema, data_n);
// load id
LoadFieldDataInfo row_id_info;
FieldMeta row_id_field_meta(
FieldName("RowID"), RowFieldID, DataType::INT64, false);
FieldMeta row_id_field_meta(FieldName("RowID"),
RowFieldID,
DataType::INT64,
false,
std::nullopt);
auto field_data = std::make_shared<milvus::FieldData<int64_t>>(
DataType::INT64, false);
field_data->FillFieldData(dataset.row_ids_.data(), data_n);
@ -132,8 +136,11 @@ class BinlogIndexTest : public ::testing::TestWithParam<Param> {
segment->LoadFieldData(RowFieldID, field_data_info);
// load ts
LoadFieldDataInfo ts_info;
FieldMeta ts_field_meta(
FieldName("Timestamp"), TimestampFieldID, DataType::INT64, false);
FieldMeta ts_field_meta(FieldName("Timestamp"),
TimestampFieldID,
DataType::INT64,
false,
std::nullopt);
field_data = std::make_shared<milvus::FieldData<int64_t>>(
DataType::INT64, false);
field_data->FillFieldData(dataset.timestamps_.data(), data_n);

View File

@ -10,12 +10,15 @@
// or implied. See the License for the specific language governing permissions and limitations under the License
#include <gtest/gtest.h>
#include <cstddef>
#include <functional>
#include <boost/filesystem.hpp>
#include <optional>
#include <unordered_set>
#include <memory>
#include "common/Tracer.h"
#include "common/Types.h"
#include "index/BitmapIndex.h"
#include "storage/Util.h"
#include "storage/InsertData.h"
@ -71,6 +74,22 @@ class BitmapIndexTest : public testing::Test {
int64_t index_version) {
proto::schema::FieldSchema field_schema;
field_schema.set_nullable(nullable_);
if (has_default_value_) {
auto default_value = field_schema.mutable_default_value();
if constexpr (std::is_same_v<int8_t, T> ||
std::is_same_v<int16_t, T> ||
std::is_same_v<int32_t, T>) {
default_value->set_int_data(10);
} else if constexpr (std::is_same_v<int64_t, T>) {
default_value->set_long_data(10);
} else if constexpr (std::is_same_v<float, T>) {
default_value->set_float_data(10);
} else if constexpr (std::is_same_v<double, T>) {
default_value->set_double_data(10);
} else if constexpr (std::is_same_v<std::string, T>) {
default_value->set_string_data("10");
}
}
if constexpr (std::is_same_v<int8_t, T>) {
field_schema.set_data_type(proto::schema::DataType::Int8);
} else if constexpr (std::is_same_v<int16_t, T>) {
@ -138,6 +157,9 @@ class BitmapIndexTest : public testing::Test {
Config config;
config["index_type"] = milvus::index::BITMAP_INDEX_TYPE;
config["insert_files"] = std::vector<std::string>{log_path};
if (has_lack_binlog_row_) {
config["lack_binlog_rows"] = lack_binlog_row_;
}
auto build_index =
indexbuilder::IndexFactory::GetInstance().CreateIndex(
@ -230,11 +252,26 @@ class BitmapIndexTest : public testing::Test {
}
auto index_ptr = dynamic_cast<index::BitmapIndex<T>*>(index_.get());
auto bitset = index_ptr->In(test_data.size(), test_data.data());
for (size_t i = 0; i < bitset.size(); i++) {
if (nullable_ && !valid_data_[i]) {
size_t start = 0;
if (has_lack_binlog_row_) {
for (int i = 0; i < lack_binlog_row_; i++) {
if (!has_default_value_) {
ASSERT_EQ(bitset[i], false);
} else {
if constexpr (std::is_same_v<std::string, T>) {
ASSERT_EQ(bitset[i], s.find("10") != s.end());
} else {
ASSERT_EQ(bitset[i], s.find(10) != s.end());
}
}
}
start += lack_binlog_row_;
}
for (size_t i = start; i < bitset.size(); i++) {
if (nullable_ && !valid_data_[i - start]) {
ASSERT_EQ(bitset[i], false);
} else {
ASSERT_EQ(bitset[i], s.find(data_[i]) != s.end());
ASSERT_EQ(bitset[i], s.find(data_[i - start]) != s.end());
}
}
}
@ -250,11 +287,26 @@ class BitmapIndexTest : public testing::Test {
}
auto index_ptr = dynamic_cast<index::BitmapIndex<T>*>(index_.get());
auto bitset = index_ptr->NotIn(test_data.size(), test_data.data());
for (size_t i = 0; i < bitset.size(); i++) {
if (nullable_ && !valid_data_[i]) {
size_t start = 0;
if (has_lack_binlog_row_) {
for (int i = 0; i < lack_binlog_row_; i++) {
if (!has_default_value_) {
ASSERT_EQ(bitset[i], false);
} else {
if constexpr (std::is_same_v<std::string, T>) {
ASSERT_EQ(bitset[i], s.find("10") == s.end());
} else {
ASSERT_EQ(bitset[i], s.find(10) == s.end());
}
}
}
start += lack_binlog_row_;
}
for (size_t i = start; i < bitset.size(); i++) {
if (nullable_ && !valid_data_[i - start]) {
ASSERT_EQ(bitset[i], false);
} else {
ASSERT_EQ(bitset[i], s.find(data_[i]) == s.end());
ASSERT_EQ(bitset[i], s.find(data_[i - start]) == s.end());
}
}
}
@ -263,8 +315,20 @@ class BitmapIndexTest : public testing::Test {
TestIsNullFunc() {
auto index_ptr = dynamic_cast<index::BitmapIndex<T>*>(index_.get());
auto bitset = index_ptr->IsNull();
for (size_t i = 0; i < bitset.size(); i++) {
if (nullable_ && !valid_data_[i]) {
size_t start = 0;
if (has_lack_binlog_row_) {
for (int i = 0; i < lack_binlog_row_; i++) {
if (has_default_value_) {
ASSERT_EQ(bitset[i], false);
} else {
ASSERT_EQ(bitset[i], true);
}
}
start += lack_binlog_row_;
}
for (size_t i = start; i < bitset.size(); i++) {
if (nullable_ && !valid_data_[i - start]) {
ASSERT_EQ(bitset[i], true);
} else {
ASSERT_EQ(bitset[i], false);
@ -276,8 +340,20 @@ class BitmapIndexTest : public testing::Test {
TestIsNotNullFunc() {
auto index_ptr = dynamic_cast<index::BitmapIndex<T>*>(index_.get());
auto bitset = index_ptr->IsNotNull();
for (size_t i = 0; i < bitset.size(); i++) {
if (nullable_ && !valid_data_[i]) {
size_t start = 0;
if (has_lack_binlog_row_) {
for (int i = 0; i < lack_binlog_row_; i++) {
if (has_default_value_) {
ASSERT_EQ(bitset[i], true);
} else {
ASSERT_EQ(bitset[i], false);
}
}
start += lack_binlog_row_;
}
for (size_t i = start; i < bitset.size(); i++) {
if (nullable_ && !valid_data_[i - start]) {
ASSERT_EQ(bitset[i], false);
} else {
ASSERT_EQ(bitset[i], true);
@ -289,35 +365,52 @@ class BitmapIndexTest : public testing::Test {
TestCompareValueFunc() {
if constexpr (!std::is_same_v<T, std::string>) {
using RefFunc = std::function<bool(int64_t)>;
std::vector<std::tuple<T, OpType, RefFunc>> test_cases{
std::vector<std::tuple<T, OpType, RefFunc, bool>> test_cases{
{10,
OpType::GreaterThan,
[&](int64_t i) -> bool { return data_[i] > 10; }},
[&](int64_t i) -> bool { return data_[i] > 10; },
false},
{10,
OpType::GreaterEqual,
[&](int64_t i) -> bool { return data_[i] >= 10; }},
[&](int64_t i) -> bool { return data_[i] >= 10; },
true},
{10,
OpType::LessThan,
[&](int64_t i) -> bool { return data_[i] < 10; }},
[&](int64_t i) -> bool { return data_[i] < 10; },
false},
{10,
OpType::LessEqual,
[&](int64_t i) -> bool { return data_[i] <= 10; }},
[&](int64_t i) -> bool { return data_[i] <= 10; },
true},
};
for (const auto& [test_value, op, ref] : test_cases) {
for (const auto& [test_value, op, ref, default_value_res] :
test_cases) {
auto index_ptr =
dynamic_cast<index::BitmapIndex<T>*>(index_.get());
auto bitset = index_ptr->Range(test_value, op);
for (size_t i = 0; i < bitset.size(); i++) {
size_t start = 0;
if (has_lack_binlog_row_) {
for (int i = 0; i < lack_binlog_row_; i++) {
if (has_default_value_) {
ASSERT_EQ(bitset[i], default_value_res);
} else {
ASSERT_EQ(bitset[i], false);
}
}
start += lack_binlog_row_;
}
for (size_t i = start; i < bitset.size(); i++) {
auto ans = bitset[i];
auto should = ref(i);
if (nullable_ && !valid_data_[i]) {
auto should = ref(i - start);
if (nullable_ && !valid_data_[i - start]) {
ASSERT_EQ(ans, false)
<< "op: " << op << ", @" << i << ", ans: " << ans
<< ", ref: " << should;
} else {
ASSERT_EQ(ans, should)
<< "op: " << op << ", @" << i << ", ans: " << ans
<< ", ref: " << should << "|" << data_[i];
<< ", ref: " << should << "|" << data_[i - start];
}
}
}
@ -334,6 +427,7 @@ class BitmapIndexTest : public testing::Test {
bool lower_inclusive;
bool upper_inclusive;
RefFunc ref;
bool default_value_res;
};
std::vector<TestParam> test_cases = {
{
@ -342,6 +436,7 @@ class BitmapIndexTest : public testing::Test {
false,
false,
[&](int64_t i) { return 10 < data_[i] && data_[i] < 30; },
false,
},
{
10,
@ -349,6 +444,7 @@ class BitmapIndexTest : public testing::Test {
true,
false,
[&](int64_t i) { return 10 <= data_[i] && data_[i] < 30; },
true,
},
{
10,
@ -356,6 +452,7 @@ class BitmapIndexTest : public testing::Test {
true,
true,
[&](int64_t i) { return 10 <= data_[i] && data_[i] <= 30; },
true,
},
{
10,
@ -363,6 +460,7 @@ class BitmapIndexTest : public testing::Test {
false,
true,
[&](int64_t i) { return 10 < data_[i] && data_[i] <= 30; },
false,
}};
for (const auto& test_case : test_cases) {
@ -372,10 +470,22 @@ class BitmapIndexTest : public testing::Test {
test_case.lower_inclusive,
test_case.upper_val,
test_case.upper_inclusive);
for (size_t i = 0; i < bitset.size(); i++) {
size_t start = 0;
if (has_lack_binlog_row_) {
for (int i = 0; i < lack_binlog_row_; i++) {
if (has_default_value_) {
ASSERT_EQ(bitset[i], test_case.default_value_res);
} else {
ASSERT_EQ(bitset[i], false);
}
}
start += lack_binlog_row_;
}
for (size_t i = start; i < bitset.size(); i++) {
auto ans = bitset[i];
auto should = test_case.ref(i);
if (nullable_ && !valid_data_[i]) {
auto should = test_case.ref(i - start);
if (nullable_ && !valid_data_[i - start]) {
ASSERT_EQ(ans, false)
<< "lower:" << test_case.lower_val
<< "upper:" << test_case.upper_val << ", @" << i
@ -403,6 +513,9 @@ class BitmapIndexTest : public testing::Test {
std::shared_ptr<storage::ChunkManager> chunk_manager_;
int index_version_;
int index_build_id_;
bool has_default_value_{false};
bool has_lack_binlog_row_{false};
size_t lack_binlog_row_{100};
};
TYPED_TEST_SUITE_P(BitmapIndexTest);
@ -634,4 +747,146 @@ REGISTER_TYPED_TEST_SUITE_P(BitmapIndexTestV4,
INSTANTIATE_TYPED_TEST_SUITE_P(BitmapIndexE2ECheck_Mmap,
BitmapIndexTestV4,
BitmapType);
template <typename T>
class BitmapIndexTestV5 : public BitmapIndexTest<T> {
public:
virtual void
SetParam() override {
this->nb_ = 10000;
this->cardinality_ = 2000;
this->is_mmap_ = true;
this->nullable_ = true;
this->index_version_ = 3003;
this->index_build_id_ = 3003;
this->has_default_value_ = false;
this->has_lack_binlog_row_ = true;
this->lack_binlog_row_ = 100;
}
virtual ~BitmapIndexTestV5() {
}
};
TYPED_TEST_SUITE_P(BitmapIndexTestV5);
TYPED_TEST_P(BitmapIndexTestV5, CountFuncTest) {
auto count = this->index_->Count();
if (this->has_lack_binlog_row_) {
EXPECT_EQ(count, this->nb_ + this->lack_binlog_row_);
} else {
EXPECT_EQ(count, this->nb_);
}
}
TYPED_TEST_P(BitmapIndexTestV5, INFuncTest) {
this->TestInFunc();
}
TYPED_TEST_P(BitmapIndexTestV5, NotINFuncTest) {
this->TestNotInFunc();
}
TYPED_TEST_P(BitmapIndexTestV5, CompareValFuncTest) {
this->TestCompareValueFunc();
}
TYPED_TEST_P(BitmapIndexTestV5, TestRangeCompareFuncTest) {
this->TestRangeCompareFunc();
}
TYPED_TEST_P(BitmapIndexTestV5, IsNullFuncTest) {
this->TestIsNullFunc();
}
TYPED_TEST_P(BitmapIndexTestV5, IsNotNullFuncTest) {
this->TestIsNotNullFunc();
}
using BitmapType =
testing::Types<int8_t, int16_t, int32_t, int64_t, std::string>;
REGISTER_TYPED_TEST_SUITE_P(BitmapIndexTestV5,
CountFuncTest,
INFuncTest,
NotINFuncTest,
CompareValFuncTest,
TestRangeCompareFuncTest,
IsNullFuncTest,
IsNotNullFuncTest);
INSTANTIATE_TYPED_TEST_SUITE_P(BitmapIndexE2ECheck_Mmap,
BitmapIndexTestV5,
BitmapType);
template <typename T>
class BitmapIndexTestV6 : public BitmapIndexTest<T> {
public:
virtual void
SetParam() override {
this->nb_ = 10000;
this->cardinality_ = 2000;
this->is_mmap_ = true;
this->nullable_ = true;
this->index_version_ = 3003;
this->index_build_id_ = 3003;
this->has_default_value_ = true;
this->has_lack_binlog_row_ = true;
this->lack_binlog_row_ = 100;
}
virtual ~BitmapIndexTestV6() {
}
};
TYPED_TEST_SUITE_P(BitmapIndexTestV6);
TYPED_TEST_P(BitmapIndexTestV6, CountFuncTest) {
auto count = this->index_->Count();
if (this->has_lack_binlog_row_) {
EXPECT_EQ(count, this->nb_ + this->lack_binlog_row_);
} else {
EXPECT_EQ(count, this->nb_);
}
}
TYPED_TEST_P(BitmapIndexTestV6, INFuncTest) {
this->TestInFunc();
}
TYPED_TEST_P(BitmapIndexTestV6, NotINFuncTest) {
this->TestNotInFunc();
}
TYPED_TEST_P(BitmapIndexTestV6, CompareValFuncTest) {
this->TestCompareValueFunc();
}
TYPED_TEST_P(BitmapIndexTestV6, TestRangeCompareFuncTest) {
this->TestRangeCompareFunc();
}
TYPED_TEST_P(BitmapIndexTestV6, IsNullFuncTest) {
this->TestIsNullFunc();
}
TYPED_TEST_P(BitmapIndexTestV6, IsNotNullFuncTest) {
this->TestIsNotNullFunc();
}
using BitmapType =
testing::Types<int8_t, int16_t, int32_t, int64_t, std::string>;
REGISTER_TYPED_TEST_SUITE_P(BitmapIndexTestV6,
CountFuncTest,
INFuncTest,
NotINFuncTest,
CompareValFuncTest,
TestRangeCompareFuncTest,
IsNullFuncTest,
IsNotNullFuncTest);
INSTANTIATE_TYPED_TEST_SUITE_P(BitmapIndexE2ECheck_Mmap,
BitmapIndexTestV6,
BitmapType);

View File

@ -815,7 +815,7 @@ TEST(CApiTest, DeleteRepeatedPksFromSealedSegment) {
DeleteSegment(segment);
}
TEST(CApiTest, SearcTestWhenNullable) {
TEST(CApiTest, SearchTestWhenNullable) {
auto c_collection = NewCollection(get_default_schema_config_nullable());
CSegmentInterface segment;
auto status = NewSegment(c_collection, Growing, -1, &segment, false);
@ -4121,9 +4121,13 @@ TEST(CApiTest, SealedSegment_Update_Field_Size) {
TEST(CApiTest, GrowingSegment_Load_Field_Data) {
auto schema = std::make_shared<Schema>();
schema->AddField(FieldName("RowID"), FieldId(0), DataType::INT64, false);
schema->AddField(
FieldName("Timestamp"), FieldId(1), DataType::INT64, false);
FieldName("RowID"), FieldId(0), DataType::INT64, false, std::nullopt);
schema->AddField(FieldName("Timestamp"),
FieldId(1),
DataType::INT64,
false,
std::nullopt);
auto str_fid = schema->AddDebugField("string", DataType::VARCHAR);
auto vec_fid = schema->AddDebugField(
"vector_float", DataType::VECTOR_FLOAT, DIM, "L2");
@ -4152,6 +4156,158 @@ TEST(CApiTest, GrowingSegment_Load_Field_Data) {
DeleteSegment(segment);
}
TEST(CApiTest, GrowingSegment_Load_Field_Data_Lack_Binlog_Rows) {
double double_default_value = 20;
auto schema = std::make_shared<Schema>();
schema->AddField(
FieldName("RowID"), FieldId(0), DataType::INT64, false, std::nullopt);
schema->AddField(FieldName("Timestamp"),
FieldId(1),
DataType::INT64,
false,
std::nullopt);
auto str_fid = schema->AddDebugField("string", DataType::VARCHAR);
auto vec_fid = schema->AddDebugField(
"vector_float", DataType::VECTOR_FLOAT, DIM, "L2");
schema->set_primary_field_id(str_fid);
int N = ROW_COUNT;
auto raw_data = DataGen(schema, N);
auto lack_null_binlog_id =
schema->AddDebugField("lack_null_binlog", DataType::INT8, true);
DefaultValueType default_value;
default_value.set_double_data(double_default_value);
auto lack_default_value_binlog_id = schema->AddDebugFieldWithDefaultValue(
"lack_default_value_binlog", DataType::DOUBLE, default_value);
raw_data.schema_ = schema;
auto segment = CreateGrowingSegment(schema, empty_index_meta).release();
std::vector<int8_t> data1(N / 2);
FixedVector<bool> valid_data1(N / 2);
for (int i = 0; i < N / 2; i++) {
data1[i] = random() % N;
valid_data1[i] = rand() % 2 == 0 ? true : false;
}
auto field_meta = schema->operator[](lack_null_binlog_id);
auto array = milvus::segcore::CreateDataArrayFrom(
data1.data(), valid_data1.data(), N / 2, field_meta);
auto storage_config = get_default_local_storage_config();
auto cm = storage::CreateChunkManager(storage_config);
auto load_info =
PrepareInsertBinlog(1,
2,
3,
storage_config.root_path + "/" + "test_load_sealed",
raw_data,
cm);
raw_data.raw_->mutable_fields_data()->AddAllocated(array.release());
load_info.field_infos.emplace(
lack_null_binlog_id.get(),
FieldBinlogInfo{lack_null_binlog_id.get(),
static_cast<int64_t>(ROW_COUNT),
std::vector<int64_t>{int64_t(0)},
false,
std::vector<std::string>{}});
load_info.field_infos.emplace(
lack_default_value_binlog_id.get(),
FieldBinlogInfo{lack_default_value_binlog_id.get(),
static_cast<int64_t>(ROW_COUNT),
std::vector<int64_t>{int64_t(0)},
false,
std::vector<std::string>{}});
auto status = LoadFieldData(segment, &load_info);
ASSERT_EQ(status.error_code, Success);
ASSERT_EQ(segment->get_real_count(), ROW_COUNT);
ASSERT_NE(segment->get_field_avg_size(str_fid), 0);
DeleteSegment(segment);
}
TEST(CApiTest, SealedSegment_Load_Field_Data_Lack_Binlog_Rows) {
double double_default_value = 20;
auto schema = std::make_shared<Schema>();
schema->AddField(
FieldName("RowID"), FieldId(0), DataType::INT64, false, std::nullopt);
schema->AddField(FieldName("Timestamp"),
FieldId(1),
DataType::INT64,
false,
std::nullopt);
auto str_fid = schema->AddDebugField("string", DataType::VARCHAR);
auto vec_fid = schema->AddDebugField(
"vector_float", DataType::VECTOR_FLOAT, DIM, "L2");
schema->set_primary_field_id(str_fid);
int N = ROW_COUNT;
auto raw_data = DataGen(schema, N);
auto lack_null_binlog_id =
schema->AddDebugField("lack_null_binlog", DataType::INT8, true);
DefaultValueType default_value;
default_value.set_double_data(double_default_value);
auto lack_default_value_binlog_id = schema->AddDebugFieldWithDefaultValue(
"lack_default_value_binlog", DataType::DOUBLE, default_value);
raw_data.schema_ = schema;
auto segment = CreateSealedSegment(schema, empty_index_meta).release();
std::vector<int8_t> data1(N / 2);
FixedVector<bool> valid_data1(N / 2);
for (int i = 0; i < N / 2; i++) {
data1[i] = random() % N;
valid_data1[i] = rand() % 2 == 0 ? true : false;
}
auto field_meta = schema->operator[](lack_null_binlog_id);
auto array = milvus::segcore::CreateDataArrayFrom(
data1.data(), valid_data1.data(), N / 2, field_meta);
auto storage_config = get_default_local_storage_config();
auto cm = storage::CreateChunkManager(storage_config);
auto load_info =
PrepareInsertBinlog(1,
2,
3,
storage_config.root_path + "/" + "test_load_sealed",
raw_data,
cm);
raw_data.raw_->mutable_fields_data()->AddAllocated(array.release());
load_info.field_infos.emplace(
lack_null_binlog_id.get(),
FieldBinlogInfo{lack_null_binlog_id.get(),
static_cast<int64_t>(ROW_COUNT),
std::vector<int64_t>{int64_t(0)},
false,
std::vector<std::string>{}});
load_info.field_infos.emplace(
lack_default_value_binlog_id.get(),
FieldBinlogInfo{lack_default_value_binlog_id.get(),
static_cast<int64_t>(ROW_COUNT),
std::vector<int64_t>{int64_t(0)},
false,
std::vector<std::string>{}});
auto status = LoadFieldData(segment, &load_info);
ASSERT_EQ(status.error_code, Success);
ASSERT_EQ(segment->get_real_count(), ROW_COUNT);
ASSERT_NE(segment->get_field_avg_size(str_fid), 0);
DeleteSegment(segment);
}
TEST(CApiTest, RetriveScalarFieldFromSealedSegmentWithIndex) {
auto schema = std::make_shared<Schema>();
auto i8_fid = schema->AddDebugField("age8", DataType::INT8);

View File

@ -16,6 +16,7 @@
#include <parquet/arrow/reader.h>
#include <unistd.h>
#include <memory>
#include <optional>
#include <string>
#include "boost/filesystem/operations.hpp"
@ -57,8 +58,11 @@ TEST(chunk, test_int64_field) {
s = arrow_reader->GetRecordBatchReader(&rb_reader);
EXPECT_TRUE(s.ok());
FieldMeta field_meta(
FieldName("a"), milvus::FieldId(1), DataType::INT64, false);
FieldMeta field_meta(FieldName("a"),
milvus::FieldId(1),
DataType::INT64,
false,
std::nullopt);
auto chunk = create_chunk(field_meta, 1, rb_reader);
auto span = std::dynamic_pointer_cast<FixedWidthChunk>(chunk)->Span();
EXPECT_EQ(span.row_count(), data.size());
@ -93,8 +97,11 @@ TEST(chunk, test_variable_field) {
s = arrow_reader->GetRecordBatchReader(&rb_reader);
EXPECT_TRUE(s.ok());
FieldMeta field_meta(
FieldName("a"), milvus::FieldId(1), DataType::STRING, false);
FieldMeta field_meta(FieldName("a"),
milvus::FieldId(1),
DataType::STRING,
false,
std::nullopt);
auto chunk = create_chunk(field_meta, 1, rb_reader);
auto views = std::dynamic_pointer_cast<StringChunk>(chunk)->StringViews(
std::nullopt);
@ -132,8 +139,11 @@ TEST(chunk, test_variable_field_nullable) {
s = arrow_reader->GetRecordBatchReader(&rb_reader);
EXPECT_TRUE(s.ok());
FieldMeta field_meta(
FieldName("a"), milvus::FieldId(1), DataType::STRING, true);
FieldMeta field_meta(FieldName("a"),
milvus::FieldId(1),
DataType::STRING,
true,
std::nullopt);
auto chunk = create_chunk(field_meta, 1, rb_reader);
auto views = std::dynamic_pointer_cast<StringChunk>(chunk)->StringViews(
std::nullopt);
@ -183,8 +193,11 @@ TEST(chunk, test_json_field) {
{
auto rb_reader = get_record_batch_reader();
// nullable=false
FieldMeta field_meta(
FieldName("a"), milvus::FieldId(1), DataType::JSON, false);
FieldMeta field_meta(FieldName("a"),
milvus::FieldId(1),
DataType::JSON,
false,
std::nullopt);
auto chunk = create_chunk(field_meta, 1, rb_reader);
{
auto [views, valid] =
@ -211,8 +224,11 @@ TEST(chunk, test_json_field) {
{
auto rb_reader = get_record_batch_reader();
// nullable=true
FieldMeta field_meta(
FieldName("a"), milvus::FieldId(1), DataType::JSON, true);
FieldMeta field_meta(FieldName("a"),
milvus::FieldId(1),
DataType::JSON,
true,
std::nullopt);
auto chunk = create_chunk(field_meta, 1, rb_reader);
{
auto [views, valid] =
@ -291,8 +307,11 @@ TEST(chunk, test_null_int64) {
s = arrow_reader->GetRecordBatchReader(&rb_reader);
EXPECT_TRUE(s.ok());
FieldMeta field_meta(
FieldName("a"), milvus::FieldId(1), DataType::INT64, true);
FieldMeta field_meta(FieldName("a"),
milvus::FieldId(1),
DataType::INT64,
true,
std::nullopt);
auto chunk = create_chunk(field_meta, 1, rb_reader);
auto fixed_chunk = std::dynamic_pointer_cast<FixedWidthChunk>(chunk);
auto span = fixed_chunk->Span();
@ -349,7 +368,8 @@ TEST(chunk, test_array) {
milvus::FieldId(1),
DataType::ARRAY,
DataType::STRING,
false);
false,
std::nullopt);
auto chunk = create_chunk(field_meta, 1, rb_reader);
auto [views, valid] =
std::dynamic_pointer_cast<ArrayChunk>(chunk)->Views(std::nullopt);
@ -408,7 +428,8 @@ TEST(chunk, test_null_array) {
milvus::FieldId(1),
DataType::ARRAY,
DataType::STRING,
true);
true,
std::nullopt);
auto chunk = create_chunk(field_meta, 1, rb_reader);
auto [views, valid] =
std::dynamic_pointer_cast<ArrayChunk>(chunk)->Views(std::nullopt);
@ -478,7 +499,8 @@ TEST(chunk, test_array_views) {
milvus::FieldId(1),
DataType::ARRAY,
DataType::STRING,
true);
true,
std::nullopt);
auto chunk = create_chunk(field_meta, 1, rb_reader);
{
@ -562,7 +584,8 @@ TEST(chunk, test_sparse_float) {
DataType::VECTOR_SPARSE_FLOAT,
kTestSparseDim,
"IP",
false);
false,
std::nullopt);
auto chunk = create_chunk(field_meta, kTestSparseDim, rb_reader);
auto vec = std::dynamic_pointer_cast<SparseFloatVectorChunk>(chunk)->Vec();
for (size_t i = 0; i < n_rows; ++i) {
@ -624,8 +647,11 @@ TEST(chunk, multiple_chunk_mmap) {
s = arrow_reader->GetRecordBatchReader(&rb_reader);
EXPECT_TRUE(s.ok());
FieldMeta field_meta(
FieldName("a"), milvus::FieldId(1), DataType::INT64, false);
FieldMeta field_meta(FieldName("a"),
milvus::FieldId(1),
DataType::INT64,
false,
std::nullopt);
int file_offset = 0;
auto page_size = sysconf(_SC_PAGESIZE);
auto chunk = create_chunk(field_meta, 1, file, file_offset, rb_reader);

View File

@ -17,6 +17,7 @@
#include <gtest/gtest.h>
#include <iostream>
#include <optional>
#include <string>
#include <utility>
#include <vector>
@ -72,14 +73,16 @@ class ChunkCacheTest
milvus::DataType::VECTOR_FLOAT,
dim,
dense_metric_type,
false);
false,
std::nullopt);
sparse_field_meta =
milvus::FieldMeta(milvus::FieldName("fakevec_sparse"),
fake_sparse_vec_id,
milvus::DataType::VECTOR_SPARSE_FLOAT,
dim,
sparse_metric_type,
false);
false,
std::nullopt);
lcm = milvus::storage::LocalChunkManagerSingleton::GetInstance()
.GetChunkManager();

View File

@ -39,6 +39,7 @@
#include "test_utils/DataGen.h"
#include <memory>
#include <numeric>
#include <optional>
#include <string>
#include <unordered_map>
#include <vector>
@ -174,8 +175,11 @@ class TestChunkSegment : public testing::TestWithParam<bool> {
schema->AddDebugField("string1", DataType::VARCHAR, true);
auto str2_fid =
schema->AddDebugField("string2", DataType::VARCHAR, true);
schema->AddField(
FieldName("ts"), TimestampFieldID, DataType::INT64, true);
schema->AddField(FieldName("ts"),
TimestampFieldID,
DataType::INT64,
true,
std::nullopt);
schema->set_primary_field_id(pk_fid);
segment = segcore::CreateSealedSegment(
schema,

View File

@ -15,6 +15,7 @@
// limitations under the License.
#include <gtest/gtest.h>
#include <optional>
#include <string>
#include "storage/DataCodec.h"
@ -794,3 +795,31 @@ TEST(storage, InsertDataJsonNullable) {
ASSERT_EQ(*new_payload->ValidData(), *valid_data);
delete[] valid_data;
}
TEST(storage, InsertDataJsonFillWithNull) {
auto field_data =
milvus::storage::CreateFieldData(storage::DataType::JSON, true);
int64_t size = 2;
uint8_t* valid_data = new uint8_t[1]{0x00};
field_data->FillFieldData(std::nullopt, size);
storage::InsertData insert_data(field_data);
storage::FieldDataMeta field_data_meta{100, 101, 102, 103};
insert_data.SetFieldDataMeta(field_data_meta);
insert_data.SetTimestamps(0, 100);
auto serialized_bytes = insert_data.Serialize(storage::StorageType::Remote);
std::shared_ptr<uint8_t[]> serialized_data_ptr(serialized_bytes.data(),
[&](uint8_t*) {});
auto new_insert_data = storage::DeserializeFileData(
serialized_data_ptr, serialized_bytes.size());
ASSERT_EQ(new_insert_data->GetCodecType(), storage::InsertDataType);
ASSERT_EQ(new_insert_data->GetTimeRage(),
std::make_pair(Timestamp(0), Timestamp(100)));
auto new_payload = new_insert_data->GetFieldData();
ASSERT_EQ(new_payload->get_data_type(), storage::DataType::JSON);
ASSERT_EQ(new_payload->get_num_rows(), size);
ASSERT_EQ(new_payload->get_null_count(), size);
ASSERT_EQ(*new_payload->ValidData(), *valid_data);
delete[] valid_data;
}

View File

@ -15,6 +15,7 @@
#include <cstdint>
#include <limits>
#include <memory>
#include <optional>
#include <regex>
#include <string>
#include <string_view>
@ -3173,8 +3174,11 @@ TEST_P(ExprTest, TestCompareWithScalarIndexNullable2) {
TEST_P(ExprTest, test_term_pk_with_sorted) {
auto schema = std::make_shared<Schema>();
schema->AddField(
FieldName("Timestamp"), FieldId(1), DataType::INT64, false);
schema->AddField(FieldName("Timestamp"),
FieldId(1),
DataType::INT64,
false,
std::nullopt);
auto vec_fid = schema->AddDebugField("fakevec", data_type, 16, metric_type);
auto str1_fid = schema->AddDebugField("string1", DataType::VARCHAR);
auto int64_fid = schema->AddDebugField("int64", DataType::INT64);
@ -4689,8 +4693,11 @@ TEST(Expr, TestExprNOT) {
TEST_P(ExprTest, test_term_pk) {
auto schema = std::make_shared<Schema>();
schema->AddField(
FieldName("Timestamp"), FieldId(1), DataType::INT64, false);
schema->AddField(FieldName("Timestamp"),
FieldId(1),
DataType::INT64,
false,
std::nullopt);
auto vec_fid = schema->AddDebugField("fakevec", data_type, 16, metric_type);
auto str1_fid = schema->AddDebugField("string1", DataType::VARCHAR);
auto int64_fid = schema->AddDebugField("int64", DataType::INT64);

View File

@ -73,6 +73,22 @@ class HybridIndexTestV1 : public testing::Test {
int64_t index_version) {
proto::schema::FieldSchema field_schema;
field_schema.set_nullable(nullable_);
if (has_default_value_) {
auto default_value = field_schema.mutable_default_value();
if constexpr (std::is_same_v<int8_t, T> ||
std::is_same_v<int16_t, T> ||
std::is_same_v<int32_t, T>) {
default_value->set_int_data(10);
} else if constexpr (std::is_same_v<int64_t, T>) {
default_value->set_long_data(10);
} else if constexpr (std::is_same_v<float, T>) {
default_value->set_float_data(10);
} else if constexpr (std::is_same_v<double, T>) {
default_value->set_double_data(10);
} else if constexpr (std::is_same_v<std::string, T>) {
default_value->set_string_data("10");
}
}
if constexpr (std::is_same_v<int8_t, T>) {
field_schema.set_data_type(proto::schema::DataType::Int8);
} else if constexpr (std::is_same_v<int16_t, T>) {
@ -142,6 +158,9 @@ class HybridIndexTestV1 : public testing::Test {
config["index_type"] = milvus::index::HYBRID_INDEX_TYPE;
config["insert_files"] = std::vector<std::string>{log_path};
config["bitmap_cardinality_limit"] = "1000";
if (has_lack_binlog_row_) {
config["lack_binlog_rows"] = lack_binlog_row_;
}
{
auto build_index =
@ -228,11 +247,26 @@ class HybridIndexTestV1 : public testing::Test {
auto index_ptr =
dynamic_cast<index::HybridScalarIndex<T>*>(index_.get());
auto bitset = index_ptr->In(test_data.size(), test_data.data());
for (size_t i = 0; i < bitset.size(); i++) {
if (nullable_ && !valid_data_[i]) {
size_t start = 0;
if (has_lack_binlog_row_) {
for (int i = 0; i < lack_binlog_row_; i++) {
if (!has_default_value_) {
ASSERT_EQ(bitset[i], false);
} else {
if constexpr (std::is_same_v<std::string, T>) {
ASSERT_EQ(bitset[i], s.find("10") != s.end());
} else {
ASSERT_EQ(bitset[i], s.find(10) != s.end());
}
}
}
start += lack_binlog_row_;
}
for (size_t i = start; i < bitset.size(); i++) {
if (nullable_ && !valid_data_[i - start]) {
ASSERT_EQ(bitset[i], false);
} else {
ASSERT_EQ(bitset[i], s.find(data_[i]) != s.end());
ASSERT_EQ(bitset[i], s.find(data_[i - start]) != s.end());
}
}
}
@ -249,11 +283,26 @@ class HybridIndexTestV1 : public testing::Test {
auto index_ptr =
dynamic_cast<index::HybridScalarIndex<T>*>(index_.get());
auto bitset = index_ptr->NotIn(test_data.size(), test_data.data());
for (size_t i = 0; i < bitset.size(); i++) {
if (nullable_ && !valid_data_[i]) {
size_t start = 0;
if (has_lack_binlog_row_) {
for (int i = 0; i < lack_binlog_row_; i++) {
if (!has_default_value_) {
ASSERT_EQ(bitset[i], false);
} else {
if constexpr (std::is_same_v<std::string, T>) {
ASSERT_EQ(bitset[i], s.find("10") == s.end());
} else {
ASSERT_EQ(bitset[i], s.find(10) == s.end());
}
}
}
start += lack_binlog_row_;
}
for (size_t i = start; i < bitset.size(); i++) {
if (nullable_ && !valid_data_[i - start]) {
ASSERT_EQ(bitset[i], false);
} else {
ASSERT_NE(bitset[i], s.find(data_[i]) != s.end());
ASSERT_NE(bitset[i], s.find(data_[i - start]) != s.end());
}
}
}
@ -263,8 +312,19 @@ class HybridIndexTestV1 : public testing::Test {
auto index_ptr =
dynamic_cast<index::HybridScalarIndex<T>*>(index_.get());
auto bitset = index_ptr->IsNull();
for (size_t i = 0; i < bitset.size(); i++) {
if (nullable_ && !valid_data_[i]) {
size_t start = 0;
if (has_lack_binlog_row_) {
for (int i = 0; i < lack_binlog_row_; i++) {
if (has_default_value_) {
ASSERT_EQ(bitset[i], false);
} else {
ASSERT_EQ(bitset[i], true);
}
}
start += lack_binlog_row_;
}
for (size_t i = start; i < bitset.size(); i++) {
if (nullable_ && !valid_data_[i - start]) {
ASSERT_EQ(bitset[i], true);
} else {
ASSERT_EQ(bitset[i], false);
@ -277,8 +337,19 @@ class HybridIndexTestV1 : public testing::Test {
auto index_ptr =
dynamic_cast<index::HybridScalarIndex<T>*>(index_.get());
auto bitset = index_ptr->IsNotNull();
for (size_t i = 0; i < bitset.size(); i++) {
if (nullable_ && !valid_data_[i]) {
size_t start = 0;
if (has_lack_binlog_row_) {
for (int i = 0; i < lack_binlog_row_; i++) {
if (has_default_value_) {
ASSERT_EQ(bitset[i], true);
} else {
ASSERT_EQ(bitset[i], false);
}
}
start += lack_binlog_row_;
}
for (size_t i = start; i < bitset.size(); i++) {
if (nullable_ && !valid_data_[i - start]) {
ASSERT_EQ(bitset[i], false);
} else {
ASSERT_EQ(bitset[i], true);
@ -290,28 +361,44 @@ class HybridIndexTestV1 : public testing::Test {
TestCompareValueFunc() {
if constexpr (!std::is_same_v<T, std::string>) {
using RefFunc = std::function<bool(int64_t)>;
std::vector<std::tuple<T, OpType, RefFunc>> test_cases{
std::vector<std::tuple<T, OpType, RefFunc, bool>> test_cases{
{10,
OpType::GreaterThan,
[&](int64_t i) -> bool { return data_[i] > 10; }},
[&](int64_t i) -> bool { return data_[i] > 10; },
false},
{10,
OpType::GreaterEqual,
[&](int64_t i) -> bool { return data_[i] >= 10; }},
[&](int64_t i) -> bool { return data_[i] >= 10; },
true},
{10,
OpType::LessThan,
[&](int64_t i) -> bool { return data_[i] < 10; }},
[&](int64_t i) -> bool { return data_[i] < 10; },
false},
{10,
OpType::LessEqual,
[&](int64_t i) -> bool { return data_[i] <= 10; }},
[&](int64_t i) -> bool { return data_[i] <= 10; },
true},
};
for (const auto& [test_value, op, ref] : test_cases) {
for (const auto& [test_value, op, ref, default_value_res] :
test_cases) {
auto index_ptr =
dynamic_cast<index::HybridScalarIndex<T>*>(index_.get());
auto bitset = index_ptr->Range(test_value, op);
for (size_t i = 0; i < bitset.size(); i++) {
size_t start = 0;
if (has_lack_binlog_row_) {
for (int i = 0; i < lack_binlog_row_; i++) {
if (has_default_value_) {
ASSERT_EQ(bitset[i], default_value_res);
} else {
ASSERT_EQ(bitset[i], false);
}
}
start += lack_binlog_row_;
}
for (size_t i = start; i < bitset.size(); i++) {
auto ans = bitset[i];
auto should = ref(i);
if (nullable_ && !valid_data_[i]) {
auto should = ref(i - start);
if (nullable_ && !valid_data_[i - start]) {
ASSERT_EQ(ans, false)
<< "op: " << op << ", @" << i << ", ans: " << ans
<< ", ref: " << should;
@ -335,6 +422,7 @@ class HybridIndexTestV1 : public testing::Test {
bool lower_inclusive;
bool upper_inclusive;
RefFunc ref;
bool default_value_res;
};
std::vector<TestParam> test_cases = {
{
@ -343,6 +431,7 @@ class HybridIndexTestV1 : public testing::Test {
false,
false,
[&](int64_t i) { return 10 < data_[i] && data_[i] < 30; },
false,
},
{
10,
@ -350,6 +439,7 @@ class HybridIndexTestV1 : public testing::Test {
true,
false,
[&](int64_t i) { return 10 <= data_[i] && data_[i] < 30; },
true,
},
{
10,
@ -357,6 +447,7 @@ class HybridIndexTestV1 : public testing::Test {
true,
true,
[&](int64_t i) { return 10 <= data_[i] && data_[i] <= 30; },
true,
},
{
10,
@ -364,6 +455,7 @@ class HybridIndexTestV1 : public testing::Test {
false,
true,
[&](int64_t i) { return 10 < data_[i] && data_[i] <= 30; },
false,
}};
for (const auto& test_case : test_cases) {
@ -373,10 +465,21 @@ class HybridIndexTestV1 : public testing::Test {
test_case.lower_inclusive,
test_case.upper_val,
test_case.upper_inclusive);
for (size_t i = 0; i < bitset.size(); i++) {
size_t start = 0;
if (has_lack_binlog_row_) {
for (int i = 0; i < lack_binlog_row_; i++) {
if (has_default_value_) {
ASSERT_EQ(bitset[i], test_case.default_value_res);
} else {
ASSERT_EQ(bitset[i], false);
}
}
start += lack_binlog_row_;
}
for (size_t i = start; i < bitset.size(); i++) {
auto ans = bitset[i];
auto should = test_case.ref(i);
if (nullable_ && !valid_data_[i]) {
auto should = test_case.ref(i - start);
if (nullable_ && !valid_data_[i - start]) {
ASSERT_EQ(ans, false)
<< "lower:" << test_case.lower_val
<< "upper:" << test_case.upper_val << ", @" << i
@ -403,6 +506,9 @@ class HybridIndexTestV1 : public testing::Test {
FixedVector<bool> valid_data_;
int index_build_id_;
int index_version_;
bool has_default_value_{false};
bool has_lack_binlog_row_{false};
size_t lack_binlog_row_{100};
};
TYPED_TEST_SUITE_P(HybridIndexTestV1);
@ -546,6 +652,114 @@ TYPED_TEST_P(HybridIndexTestNullable, TestRangeCompareFuncTest) {
this->TestRangeCompareFunc();
}
template <typename T>
class HybridIndexTestV3 : public HybridIndexTestV1<T> {
public:
virtual void
SetParam() override {
this->nb_ = 10000;
this->cardinality_ = 2000;
this->nullable_ = true;
this->index_version_ = 1003;
this->index_build_id_ = 1003;
this->has_default_value_ = false;
this->has_lack_binlog_row_ = true;
this->lack_binlog_row_ = 100;
}
virtual ~HybridIndexTestV3() {
}
};
TYPED_TEST_SUITE_P(HybridIndexTestV3);
TYPED_TEST_P(HybridIndexTestV3, CountFuncTest) {
auto count = this->index_->Count();
if (this->has_lack_binlog_row_) {
EXPECT_EQ(count, this->nb_ + this->lack_binlog_row_);
} else {
EXPECT_EQ(count, this->nb_);
}
}
TYPED_TEST_P(HybridIndexTestV3, INFuncTest) {
this->TestInFunc();
}
TYPED_TEST_P(HybridIndexTestV3, NotINFuncTest) {
this->TestNotInFunc();
}
TYPED_TEST_P(HybridIndexTestV3, IsNullFuncTest) {
this->TestIsNullFunc();
}
TYPED_TEST_P(HybridIndexTestV3, IsNotNullFuncTest) {
this->TestIsNotNullFunc();
}
TYPED_TEST_P(HybridIndexTestV3, CompareValFuncTest) {
this->TestCompareValueFunc();
}
TYPED_TEST_P(HybridIndexTestV3, TestRangeCompareFuncTest) {
this->TestRangeCompareFunc();
}
template <typename T>
class HybridIndexTestV4 : public HybridIndexTestV1<T> {
public:
virtual void
SetParam() override {
this->nb_ = 10000;
this->cardinality_ = 2000;
this->nullable_ = true;
this->index_version_ = 1003;
this->index_build_id_ = 1003;
this->has_default_value_ = true;
this->has_lack_binlog_row_ = true;
this->lack_binlog_row_ = 100;
}
virtual ~HybridIndexTestV4() {
}
};
TYPED_TEST_SUITE_P(HybridIndexTestV4);
TYPED_TEST_P(HybridIndexTestV4, CountFuncTest) {
auto count = this->index_->Count();
if (this->has_lack_binlog_row_) {
EXPECT_EQ(count, this->nb_ + this->lack_binlog_row_);
} else {
EXPECT_EQ(count, this->nb_);
}
}
TYPED_TEST_P(HybridIndexTestV4, INFuncTest) {
this->TestInFunc();
}
TYPED_TEST_P(HybridIndexTestV4, NotINFuncTest) {
this->TestNotInFunc();
}
TYPED_TEST_P(HybridIndexTestV4, IsNullFuncTest) {
this->TestIsNullFunc();
}
TYPED_TEST_P(HybridIndexTestV4, IsNotNullFuncTest) {
this->TestIsNotNullFunc();
}
TYPED_TEST_P(HybridIndexTestV4, CompareValFuncTest) {
this->TestCompareValueFunc();
}
TYPED_TEST_P(HybridIndexTestV4, TestRangeCompareFuncTest) {
this->TestRangeCompareFunc();
}
using BitmapType =
testing::Types<int8_t, int16_t, int32_t, int64_t, std::string>;
@ -567,6 +781,24 @@ REGISTER_TYPED_TEST_SUITE_P(HybridIndexTestNullable,
CompareValFuncTest,
TestRangeCompareFuncTest);
REGISTER_TYPED_TEST_SUITE_P(HybridIndexTestV3,
CountFuncTest,
INFuncTest,
IsNullFuncTest,
IsNotNullFuncTest,
NotINFuncTest,
CompareValFuncTest,
TestRangeCompareFuncTest);
REGISTER_TYPED_TEST_SUITE_P(HybridIndexTestV4,
CountFuncTest,
INFuncTest,
IsNullFuncTest,
IsNotNullFuncTest,
NotINFuncTest,
CompareValFuncTest,
TestRangeCompareFuncTest);
INSTANTIATE_TYPED_TEST_SUITE_P(HybridIndexE2ECheck_HighCardinality,
HybridIndexTestV2,
BitmapType);
@ -574,3 +806,11 @@ INSTANTIATE_TYPED_TEST_SUITE_P(HybridIndexE2ECheck_HighCardinality,
INSTANTIATE_TYPED_TEST_SUITE_P(HybridIndexE2ECheck_Nullable,
HybridIndexTestNullable,
BitmapType);
INSTANTIATE_TYPED_TEST_SUITE_P(HybridIndexE2ECheck_HasLackNullBinlog,
HybridIndexTestV3,
BitmapType);
INSTANTIATE_TYPED_TEST_SUITE_P(HybridIndexE2ECheck_HasLackDefaultValueBinlog,
HybridIndexTestV4,
BitmapType);

View File

@ -96,7 +96,9 @@ struct ChunkManagerWrapper {
template <typename T,
DataType dtype,
DataType element_type = DataType::NONE,
bool nullable = false>
bool nullable = false,
bool has_lack_binlog_row_ = false,
bool has_default_value_ = false>
void
test_run() {
int64_t collection_id = 1;
@ -105,6 +107,7 @@ test_run() {
int64_t field_id = 101;
int64_t index_build_id = 4000;
int64_t index_version = 4000;
int64_t lack_binlog_row = 100;
auto field_meta = test::gen_field_meta(collection_id,
partition_id,
@ -116,6 +119,20 @@ test_run() {
auto index_meta = test::gen_index_meta(
segment_id, field_id, index_build_id, index_version);
if (has_default_value_) {
auto default_value = field_meta.field_schema.mutable_default_value();
if constexpr (std::is_same_v<int8_t, T> || std::is_same_v<int16_t, T> ||
std::is_same_v<int32_t, T>) {
default_value->set_int_data(20);
} else if constexpr (std::is_same_v<int64_t, T>) {
default_value->set_long_data(20);
} else if constexpr (std::is_same_v<float, T>) {
default_value->set_float_data(20);
} else if constexpr (std::is_same_v<double, T>) {
default_value->set_double_data(20);
}
}
std::string root_path = "/tmp/test-inverted-index/";
auto storage_config = test::gen_local_storage_config(root_path);
auto cm = storage::CreateChunkManager(storage_config);
@ -160,7 +177,7 @@ test_run() {
} else {
field_data->FillFieldData(data.data(), data.size());
}
// std::cout << "length:" << field_data->get_num_rows() << std::endl;
storage::InsertData insert_data(field_data);
insert_data.SetFieldDataMeta(field_meta);
insert_data.SetTimestamps(0, 100);
@ -188,6 +205,9 @@ test_run() {
Config config;
config["index_type"] = milvus::index::INVERTED_INDEX_TYPE;
config["insert_files"] = std::vector<std::string>{log_path};
if (has_lack_binlog_row_) {
config["lack_binlog_rows"] = lack_binlog_row;
}
auto index = indexbuilder::IndexFactory::GetInstance().CreateIndex(
dtype, config, ctx);
@ -215,7 +235,11 @@ test_run() {
index->Load(milvus::tracer::TraceContext{}, config);
auto cnt = index->Count();
ASSERT_EQ(cnt, nb);
if (has_lack_binlog_row_) {
ASSERT_EQ(cnt, nb + lack_binlog_row);
} else {
ASSERT_EQ(cnt, nb);
}
using IndexType = index::ScalarIndex<T>;
auto real_index = dynamic_cast<IndexType*>(index.get());
@ -233,11 +257,23 @@ test_run() {
auto bitset =
real_index->In(test_data.size(), test_data.data());
ASSERT_EQ(cnt, bitset.size());
for (size_t i = 0; i < bitset.size(); i++) {
if (nullable && !valid_data[i]) {
size_t start = 0;
if (has_lack_binlog_row_) {
for (int i = 0; i < lack_binlog_row; i++) {
if (!has_default_value_) {
ASSERT_EQ(bitset[i], false);
} else {
ASSERT_EQ(bitset[i], s.find(20) != s.end());
}
}
start += lack_binlog_row;
}
for (size_t i = start; i < bitset.size(); i++) {
if (nullable && !valid_data[i - start]) {
ASSERT_EQ(bitset[i], false);
} else {
ASSERT_EQ(bitset[i], s.find(data[i]) != s.end());
ASSERT_EQ(bitset[i],
s.find(data[i - start]) != s.end());
}
}
}
@ -253,11 +289,23 @@ test_run() {
auto bitset =
real_index->NotIn(test_data.size(), test_data.data());
ASSERT_EQ(cnt, bitset.size());
for (size_t i = 0; i < bitset.size(); i++) {
if (nullable && !valid_data[i]) {
size_t start = 0;
if (has_lack_binlog_row_) {
for (int i = 0; i < lack_binlog_row; i++) {
if (!has_default_value_) {
ASSERT_EQ(bitset[i], false);
} else {
ASSERT_EQ(bitset[i], s.find(20) == s.end());
}
}
start += lack_binlog_row;
}
for (size_t i = start; i < bitset.size(); i++) {
if (nullable && !valid_data[i - start]) {
ASSERT_EQ(bitset[i], false);
} else {
ASSERT_NE(bitset[i], s.find(data[i]) != s.end());
ASSERT_NE(bitset[i],
s.find(data[i - start]) != s.end());
}
}
}
@ -265,8 +313,19 @@ test_run() {
{
auto bitset = real_index->IsNull();
ASSERT_EQ(cnt, bitset.size());
for (size_t i = 0; i < bitset.size(); i++) {
if (nullable && !valid_data[i]) {
size_t start = 0;
if (has_lack_binlog_row_) {
for (int i = 0; i < lack_binlog_row; i++) {
if (has_default_value_) {
ASSERT_EQ(bitset[i], false);
} else {
ASSERT_EQ(bitset[i], true);
}
}
start += lack_binlog_row;
}
for (size_t i = start; i < bitset.size(); i++) {
if (nullable && !valid_data[i - start]) {
ASSERT_EQ(bitset[i], true);
} else {
ASSERT_EQ(bitset[i], false);
@ -277,8 +336,20 @@ test_run() {
{
auto bitset = real_index->IsNotNull();
ASSERT_EQ(cnt, bitset.size());
for (size_t i = 0; i < bitset.size(); i++) {
if (nullable && !valid_data[i]) {
size_t start = 0;
if (has_lack_binlog_row_) {
for (int i = 0; i < lack_binlog_row; i++) {
if (has_default_value_) {
ASSERT_EQ(bitset[i], true);
} else {
ASSERT_EQ(bitset[i], false);
}
}
start += lack_binlog_row;
}
for (size_t i = start; i < bitset.size(); i++) {
if (nullable && !valid_data[i - start]) {
ASSERT_EQ(bitset[i], false);
} else {
ASSERT_EQ(bitset[i], true);
@ -293,27 +364,51 @@ test_run() {
// range query on boolean is not reasonable.
{
std::vector<std::tuple<T, OpType, RefFunc>> test_cases{
{20,
OpType::GreaterThan,
[&](int64_t i) -> bool { return data[i] > 20; }},
{20,
OpType::GreaterEqual,
[&](int64_t i) -> bool { return data[i] >= 20; }},
{20,
OpType::LessThan,
[&](int64_t i) -> bool { return data[i] < 20; }},
{20,
OpType::LessEqual,
[&](int64_t i) -> bool { return data[i] <= 20; }},
std::vector<std::tuple<T, OpType, RefFunc, bool>> test_cases{
{
20,
OpType::GreaterThan,
[&](int64_t i) -> bool { return data[i] > 20; },
false,
},
{
20,
OpType::GreaterEqual,
[&](int64_t i) -> bool { return data[i] >= 20; },
true,
},
{
20,
OpType::LessThan,
[&](int64_t i) -> bool { return data[i] < 20; },
false,
},
{
20,
OpType::LessEqual,
[&](int64_t i) -> bool { return data[i] <= 20; },
true,
},
};
for (const auto& [test_value, op, ref] : test_cases) {
for (const auto& [test_value, op, ref, default_value_res] :
test_cases) {
auto bitset = real_index->Range(test_value, op);
ASSERT_EQ(cnt, bitset.size());
for (size_t i = 0; i < nb; i++) {
size_t start = 0;
if (has_lack_binlog_row_) {
for (int i = 0; i < lack_binlog_row; i++) {
if (has_default_value_) {
ASSERT_EQ(bitset[i], default_value_res);
} else {
ASSERT_EQ(bitset[i], false);
}
}
start += lack_binlog_row;
}
for (size_t i = start; i < bitset.size(); i++) {
auto ans = bitset[i];
auto should = ref(i);
if (nullable && !valid_data[i]) {
auto should = ref(i - start);
if (nullable && !valid_data[i - start]) {
ASSERT_EQ(ans, false);
} else {
ASSERT_EQ(ans, should)
@ -325,45 +420,73 @@ test_run() {
}
{
std::vector<std::tuple<T, bool, T, bool, RefFunc>> test_cases{
{1,
false,
20,
false,
[&](int64_t i) -> bool {
return 1 < data[i] && data[i] < 20;
}},
{1,
false,
20,
true,
[&](int64_t i) -> bool {
return 1 < data[i] && data[i] <= 20;
}},
{1,
true,
20,
false,
[&](int64_t i) -> bool {
return 1 <= data[i] && data[i] < 20;
}},
{1,
true,
20,
true,
[&](int64_t i) -> bool {
return 1 <= data[i] && data[i] <= 20;
}},
};
for (const auto& [lb, lb_inclusive, ub, ub_inclusive, ref] :
test_cases) {
std::vector<std::tuple<T, bool, T, bool, RefFunc, bool>>
test_cases{
{
1,
false,
20,
false,
[&](int64_t i) -> bool {
return 1 < data[i] && data[i] < 20;
},
false,
},
{
1,
false,
20,
true,
[&](int64_t i) -> bool {
return 1 < data[i] && data[i] <= 20;
},
true,
},
{
1,
true,
20,
false,
[&](int64_t i) -> bool {
return 1 <= data[i] && data[i] < 20;
},
false,
},
{
1,
true,
20,
true,
[&](int64_t i) -> bool {
return 1 <= data[i] && data[i] <= 20;
},
true,
},
};
for (const auto& [lb,
lb_inclusive,
ub,
ub_inclusive,
ref,
default_value_res] : test_cases) {
auto bitset =
real_index->Range(lb, lb_inclusive, ub, ub_inclusive);
ASSERT_EQ(cnt, bitset.size());
for (size_t i = 0; i < nb; i++) {
size_t start = 0;
if (has_lack_binlog_row_) {
for (int i = 0; i < lack_binlog_row; i++) {
if (has_default_value_) {
ASSERT_EQ(bitset[i], default_value_res);
} else {
ASSERT_EQ(bitset[i], false);
}
}
start += lack_binlog_row;
}
for (size_t i = start; i < bitset.size(); i++) {
auto ans = bitset[i];
auto should = ref(i);
if (nullable && !valid_data[i]) {
auto should = ref(i - start);
if (nullable && !valid_data[i - start]) {
ASSERT_EQ(ans, false);
} else {
ASSERT_EQ(ans, should)
@ -377,7 +500,9 @@ test_run() {
}
}
template <bool nullable = false>
template <bool nullable = false,
bool has_lack_binlog_row_ = false,
bool has_default_value_ = false>
void
test_string() {
using T = std::string;
@ -389,6 +514,7 @@ test_string() {
int64_t field_id = 101;
int64_t index_build_id = 4001;
int64_t index_version = 4001;
int64_t lack_binlog_row = 100;
auto field_meta = test::gen_field_meta(collection_id,
partition_id,
@ -400,6 +526,11 @@ test_string() {
auto index_meta = test::gen_index_meta(
segment_id, field_id, index_build_id, index_version);
if (has_default_value_) {
auto default_value = field_meta.field_schema.mutable_default_value();
default_value->set_string_data("20");
}
std::string root_path = "/tmp/test-inverted-index/";
auto storage_config = test::gen_local_storage_config(root_path);
auto cm = storage::CreateChunkManager(storage_config);
@ -463,6 +594,9 @@ test_string() {
Config config;
config["index_type"] = milvus::index::INVERTED_INDEX_TYPE;
config["insert_files"] = std::vector<std::string>{log_path};
if (has_lack_binlog_row_) {
config["lack_binlog_rows"] = lack_binlog_row;
}
auto index = indexbuilder::IndexFactory::GetInstance().CreateIndex(
dtype, config, ctx);
@ -490,7 +624,11 @@ test_string() {
index->Load(milvus::tracer::TraceContext{}, config);
auto cnt = index->Count();
ASSERT_EQ(cnt, nb);
if (has_lack_binlog_row_) {
ASSERT_EQ(cnt, nb + lack_binlog_row);
} else {
ASSERT_EQ(cnt, nb);
}
using IndexType = index::ScalarIndex<T>;
auto real_index = dynamic_cast<IndexType*>(index.get());
@ -505,11 +643,22 @@ test_string() {
}
auto bitset = real_index->In(test_data.size(), test_data.data());
ASSERT_EQ(cnt, bitset.size());
for (size_t i = 0; i < bitset.size(); i++) {
if (nullable && !valid_data[i]) {
size_t start = 0;
if (has_lack_binlog_row_) {
for (int i = 0; i < lack_binlog_row; i++) {
if (!has_default_value_) {
ASSERT_EQ(bitset[i], false);
} else {
ASSERT_EQ(bitset[i], s.find("20") != s.end());
}
}
start += lack_binlog_row;
}
for (size_t i = start; i < bitset.size(); i++) {
if (nullable && !valid_data[i - start]) {
ASSERT_EQ(bitset[i], false);
} else {
ASSERT_EQ(bitset[i], s.find(data[i]) != s.end());
ASSERT_EQ(bitset[i], s.find(data[i - start]) != s.end());
}
}
}
@ -524,11 +673,22 @@ test_string() {
}
auto bitset = real_index->NotIn(test_data.size(), test_data.data());
ASSERT_EQ(cnt, bitset.size());
for (size_t i = 0; i < bitset.size(); i++) {
if (nullable && !valid_data[i]) {
size_t start = 0;
if (has_lack_binlog_row_) {
for (int i = 0; i < lack_binlog_row; i++) {
if (!has_default_value_) {
ASSERT_EQ(bitset[i], false);
} else {
ASSERT_NE(bitset[i], s.find("20") != s.end());
}
}
start += lack_binlog_row;
}
for (size_t i = start; i < bitset.size(); i++) {
if (nullable && !valid_data[i - start]) {
ASSERT_EQ(bitset[i], false);
} else {
ASSERT_NE(bitset[i], s.find(data[i]) != s.end());
ASSERT_NE(bitset[i], s.find(data[i - start]) != s.end());
}
}
}
@ -536,27 +696,51 @@ test_string() {
using RefFunc = std::function<bool(int64_t)>;
{
std::vector<std::tuple<T, OpType, RefFunc>> test_cases{
{"20",
OpType::GreaterThan,
[&](int64_t i) -> bool { return data[i] > "20"; }},
{"20",
OpType::GreaterEqual,
[&](int64_t i) -> bool { return data[i] >= "20"; }},
{"20",
OpType::LessThan,
[&](int64_t i) -> bool { return data[i] < "20"; }},
{"20",
OpType::LessEqual,
[&](int64_t i) -> bool { return data[i] <= "20"; }},
std::vector<std::tuple<T, OpType, RefFunc, bool>> test_cases{
{
"20",
OpType::GreaterThan,
[&](int64_t i) -> bool { return data[i] > "20"; },
false,
},
{
"20",
OpType::GreaterEqual,
[&](int64_t i) -> bool { return data[i] >= "20"; },
true,
},
{
"20",
OpType::LessThan,
[&](int64_t i) -> bool { return data[i] < "20"; },
false,
},
{
"20",
OpType::LessEqual,
[&](int64_t i) -> bool { return data[i] <= "20"; },
true,
},
};
for (const auto& [test_value, op, ref] : test_cases) {
for (const auto& [test_value, op, ref, default_value_res] :
test_cases) {
auto bitset = real_index->Range(test_value, op);
ASSERT_EQ(cnt, bitset.size());
for (size_t i = 0; i < bitset.size(); i++) {
size_t start = 0;
if (has_lack_binlog_row_) {
for (int i = 0; i < lack_binlog_row; i++) {
if (has_default_value_) {
ASSERT_EQ(bitset[i], default_value_res);
} else {
ASSERT_EQ(bitset[i], false);
}
}
start += lack_binlog_row;
}
for (size_t i = start; i < bitset.size(); i++) {
auto ans = bitset[i];
auto should = ref(i);
if (nullable && !valid_data[i]) {
auto should = ref(i - start);
if (nullable && !valid_data[i - start]) {
ASSERT_EQ(ans, false);
} else {
ASSERT_EQ(ans, should)
@ -568,45 +752,72 @@ test_string() {
}
{
std::vector<std::tuple<T, bool, T, bool, RefFunc>> test_cases{
{"1",
false,
"20",
false,
[&](int64_t i) -> bool {
return "1" < data[i] && data[i] < "20";
}},
{"1",
false,
"20",
true,
[&](int64_t i) -> bool {
return "1" < data[i] && data[i] <= "20";
}},
{"1",
true,
"20",
false,
[&](int64_t i) -> bool {
return "1" <= data[i] && data[i] < "20";
}},
{"1",
true,
"20",
true,
[&](int64_t i) -> bool {
return "1" <= data[i] && data[i] <= "20";
}},
std::vector<std::tuple<T, bool, T, bool, RefFunc, bool>> test_cases{
{
"1",
false,
"20",
false,
[&](int64_t i) -> bool {
return "1" < data[i] && data[i] < "20";
},
false,
},
{
"1",
false,
"20",
true,
[&](int64_t i) -> bool {
return "1" < data[i] && data[i] <= "20";
},
true,
},
{
"1",
true,
"20",
false,
[&](int64_t i) -> bool {
return "1" <= data[i] && data[i] < "20";
},
false,
},
{
"1",
true,
"20",
true,
[&](int64_t i) -> bool {
return "1" <= data[i] && data[i] <= "20";
},
true,
},
};
for (const auto& [lb, lb_inclusive, ub, ub_inclusive, ref] :
test_cases) {
for (const auto& [lb,
lb_inclusive,
ub,
ub_inclusive,
ref,
default_value_res] : test_cases) {
auto bitset =
real_index->Range(lb, lb_inclusive, ub, ub_inclusive);
ASSERT_EQ(cnt, bitset.size());
for (size_t i = 0; i < nb; i++) {
size_t start = 0;
if (has_lack_binlog_row_) {
for (int i = 0; i < lack_binlog_row; i++) {
if (has_default_value_) {
ASSERT_EQ(bitset[i], default_value_res);
} else {
ASSERT_EQ(bitset[i], false);
}
}
start += lack_binlog_row;
}
for (size_t i = start; i < bitset.size(); i++) {
auto ans = bitset[i];
auto should = ref(i);
if (nullable && !valid_data[i]) {
auto should = ref(i - start);
if (nullable && !valid_data[i - start]) {
ASSERT_EQ(ans, false);
} else {
ASSERT_EQ(ans, should) << "@" << i << ", ans: " << ans
@ -623,9 +834,20 @@ test_string() {
dataset->Set(index::PREFIX_VALUE, prefix);
auto bitset = real_index->Query(dataset);
ASSERT_EQ(cnt, bitset.size());
for (size_t i = 0; i < bitset.size(); i++) {
auto should = boost::starts_with(data[i], prefix);
if (nullable && !valid_data[i]) {
size_t start = 0;
if (has_lack_binlog_row_) {
for (int i = 0; i < lack_binlog_row; i++) {
if (has_default_value_) {
ASSERT_EQ(bitset[i], boost::starts_with("20", prefix));
} else {
ASSERT_EQ(bitset[i], false);
}
}
start += lack_binlog_row;
}
for (size_t i = start; i < bitset.size(); i++) {
auto should = boost::starts_with(data[i - start], prefix);
if (nullable && !valid_data[i - start]) {
should = false;
}
ASSERT_EQ(bitset[i], should);
@ -637,9 +859,20 @@ test_string() {
auto prefix = data[0];
auto bitset = real_index->RegexQuery(prefix + "(.|\n)*");
ASSERT_EQ(cnt, bitset.size());
for (size_t i = 0; i < bitset.size(); i++) {
auto should = boost::starts_with(data[i], prefix);
if (nullable && !valid_data[i]) {
size_t start = 0;
if (has_lack_binlog_row_) {
for (int i = 0; i < lack_binlog_row; i++) {
if (has_default_value_) {
ASSERT_EQ(bitset[i], boost::starts_with("20", prefix));
} else {
ASSERT_EQ(bitset[i], false);
}
}
start += lack_binlog_row;
}
for (size_t i = start; i < bitset.size(); i++) {
auto should = boost::starts_with(data[i - start], prefix);
if (nullable && !valid_data[i - start]) {
should = false;
}
ASSERT_EQ(bitset[i], should);
@ -672,3 +905,31 @@ TEST(InvertedIndex, Naive) {
test_string<true>();
}
TEST(InvertedIndex, HasLackBinlogRows) {
// lack binlog is null
test_run<int8_t, DataType::INT8, DataType::NONE, true, true>();
test_run<int16_t, DataType::INT16, DataType::NONE, true, true>();
test_run<int32_t, DataType::INT32, DataType::NONE, true, true>();
test_run<int64_t, DataType::INT64, DataType::NONE, true, true>();
test_run<bool, DataType::BOOL, DataType::NONE, true, true>();
test_run<float, DataType::FLOAT, DataType::NONE, true, true>();
test_run<double, DataType::DOUBLE, DataType::NONE, true, true>();
test_string<true, true>();
// lack binlog is default_value
test_run<int8_t, DataType::INT8, DataType::NONE, true, true, true>();
test_run<int16_t, DataType::INT16, DataType::NONE, true, true, true>();
test_run<int32_t, DataType::INT32, DataType::NONE, true, true, true>();
test_run<int64_t, DataType::INT64, DataType::NONE, true, true, true>();
test_run<bool, DataType::BOOL, DataType::NONE, true, true, true>();
test_run<float, DataType::FLOAT, DataType::NONE, true, true, true>();
test_run<double, DataType::DOUBLE, DataType::NONE, true, true, true>();
test_string<true, true, true>();
}

View File

@ -528,6 +528,12 @@ TEST(Query, FillSegment) {
proto.set_name("col");
proto.set_description("asdfhsalkgfhsadg");
auto dim = 16;
bool bool_default_value = true;
int32_t int_default_value = 20;
int64_t long_default_value = 20;
float float_default_value = 20;
double double_default_value = 20;
string varchar_dafualt_vlaue = "20";
{
auto field = proto.add_fields();
@ -594,6 +600,88 @@ TEST(Query, FillSegment) {
return segment;
}());
// add field
{
auto field = proto.add_fields();
field->set_name("lack_null_binlog");
field->set_nullable(true);
field->set_fieldid(103);
field->set_is_primary_key(false);
field->set_description("lack null binlog");
field->set_data_type(pb::schema::DataType::Float);
}
{
auto field = proto.add_fields();
field->set_name("lack_default_value_binlog_bool");
field->set_nullable(true);
field->set_fieldid(104);
field->set_is_primary_key(false);
field->set_description("lack default value binlog");
field->set_data_type(pb::schema::DataType::Bool);
field->mutable_default_value()->set_bool_data(bool_default_value);
}
{
auto field = proto.add_fields();
field->set_name("lack_default_value_binlog_int");
field->set_nullable(true);
field->set_fieldid(105);
field->set_is_primary_key(false);
field->set_description("lack default value binlog");
field->set_data_type(pb::schema::DataType::Int32);
field->mutable_default_value()->set_int_data(int_default_value);
}
{
auto field = proto.add_fields();
field->set_name("lack_default_value_binlog_int64");
field->set_nullable(true);
field->set_fieldid(106);
field->set_is_primary_key(false);
field->set_description("lack default value binlog");
field->set_data_type(pb::schema::DataType::Int64);
field->mutable_default_value()->set_int_data(long_default_value);
}
{
auto field = proto.add_fields();
field->set_name("lack_default_value_binlog_float");
field->set_nullable(true);
field->set_fieldid(107);
field->set_is_primary_key(false);
field->set_description("lack default value binlog");
field->set_data_type(pb::schema::DataType::Float);
field->mutable_default_value()->set_float_data(float_default_value);
}
{
auto field = proto.add_fields();
field->set_name("lack_default_value_binlog_double");
field->set_nullable(true);
field->set_fieldid(108);
field->set_is_primary_key(false);
field->set_description("lack default value binlog");
field->set_data_type(pb::schema::DataType::Double);
field->mutable_default_value()->set_double_data(double_default_value);
}
{
auto field = proto.add_fields();
field->set_name("lack_default_value_binlog_varchar");
field->set_nullable(true);
field->set_fieldid(109);
field->set_is_primary_key(false);
field->set_description("lack default value binlog");
field->set_data_type(pb::schema::DataType::VarChar);
auto str_type_params = field->add_type_params();
str_type_params->set_key(MAX_LENGTH);
str_type_params->set_value(std::to_string(64));
field->mutable_default_value()->set_string_data(varchar_dafualt_vlaue);
}
schema = Schema::ParseFrom(proto);
const char* raw_plan = R"(vector_anns: <
field_id: 100
query_info: <
@ -613,20 +701,33 @@ TEST(Query, FillSegment) {
auto topk = 5;
auto num_queries = 10;
for (auto& segment : segments) {
plan->target_entries_.clear();
plan->target_entries_.push_back(
schema->get_field_id(FieldName("fakevec")));
plan->target_entries_.push_back(
schema->get_field_id(FieldName("the_value")));
plan->target_entries_.push_back(
schema->get_field_id(FieldName("lack_null_binlog")));
plan->target_entries_.push_back(
schema->get_field_id(FieldName("lack_default_value_binlog_bool")));
plan->target_entries_.push_back(
schema->get_field_id(FieldName("lack_default_value_binlog_int")));
plan->target_entries_.push_back(
schema->get_field_id(FieldName("lack_default_value_binlog_int64")));
plan->target_entries_.push_back(
schema->get_field_id(FieldName("lack_default_value_binlog_float")));
plan->target_entries_.push_back(schema->get_field_id(
FieldName("lack_default_value_binlog_double")));
plan->target_entries_.push_back(schema->get_field_id(
FieldName("lack_default_value_binlog_varchar")));
auto result = segment->Search(plan.get(), ph.get(), ts);
result->result_offsets_.resize(topk * num_queries);
segment->FillTargetEntry(plan.get(), *result);
segment->FillPrimaryKeys(plan.get(), *result);
auto& fields_data = result->output_fields_data_;
ASSERT_EQ(fields_data.size(), 2);
ASSERT_EQ(fields_data.size(), 9);
for (auto field_id : plan->target_entries_) {
ASSERT_EQ(fields_data.count(field_id), true);
}
@ -642,6 +743,71 @@ TEST(Query, FillSegment) {
ASSERT_EQ(output_i32_field_data.size(), topk * num_queries);
auto output_i32_valid_data = fields_data.at(i32_field_id)->valid_data();
ASSERT_EQ(output_i32_valid_data.size(), topk * num_queries);
auto float_field_id =
schema->get_field_id(FieldName("lack_null_binlog"));
auto output_float_field_data =
fields_data.at(float_field_id)->scalars().float_data().data();
ASSERT_EQ(output_float_field_data.size(), topk * num_queries);
auto output_float_valid_data =
fields_data.at(float_field_id)->valid_data();
ASSERT_EQ(output_float_valid_data.size(), topk * num_queries);
auto double_field_id =
schema->get_field_id(FieldName("lack_default_value_binlog_double"));
auto output_double_field_data =
fields_data.at(double_field_id)->scalars().double_data().data();
ASSERT_EQ(output_double_field_data.size(), topk * num_queries);
auto output_double_valid_data =
fields_data.at(double_field_id)->valid_data();
ASSERT_EQ(output_double_valid_data.size(), topk * num_queries);
auto bool_field_id =
schema->get_field_id(FieldName("lack_default_value_binlog_bool"));
auto output_bool_field_data =
fields_data.at(bool_field_id)->scalars().bool_data().data();
ASSERT_EQ(output_bool_field_data.size(), topk * num_queries);
auto output_bool_valid_data =
fields_data.at(bool_field_id)->valid_data();
ASSERT_EQ(output_bool_valid_data.size(), topk * num_queries);
auto int_field_id =
schema->get_field_id(FieldName("lack_default_value_binlog_int"));
auto output_int_field_data =
fields_data.at(int_field_id)->scalars().int_data().data();
ASSERT_EQ(output_int_field_data.size(), topk * num_queries);
auto output_int_valid_data = fields_data.at(int_field_id)->valid_data();
ASSERT_EQ(output_int_valid_data.size(), topk * num_queries);
auto int64_field_id =
schema->get_field_id(FieldName("lack_default_value_binlog_int64"));
auto output_int64_field_data =
fields_data.at(int64_field_id)->scalars().long_data().data();
ASSERT_EQ(output_int64_field_data.size(), topk * num_queries);
auto output_int64_valid_data =
fields_data.at(int64_field_id)->valid_data();
ASSERT_EQ(output_int64_valid_data.size(), topk * num_queries);
auto float_field_id_default_value =
schema->get_field_id(FieldName("lack_default_value_binlog_float"));
auto output_float_field_data_default_value =
fields_data.at(float_field_id_default_value)
->scalars()
.float_data()
.data();
ASSERT_EQ(output_float_field_data_default_value.size(),
topk * num_queries);
auto output_float_valid_data_default_value =
fields_data.at(float_field_id_default_value)->valid_data();
ASSERT_EQ(output_float_valid_data_default_value.size(),
topk * num_queries);
auto varchar_field_id = schema->get_field_id(
FieldName("lack_default_value_binlog_varchar"));
auto output_varchar_field_data =
fields_data.at(varchar_field_id)->scalars().string_data().data();
ASSERT_EQ(output_varchar_field_data.size(), topk * num_queries);
auto output_varchar_valid_data =
fields_data.at(varchar_field_id)->valid_data();
ASSERT_EQ(output_varchar_valid_data.size(), topk * num_queries);
for (int i = 0; i < topk * num_queries; i++) {
int64_t val = std::get<int64_t>(result->primary_keys_[i]);
@ -650,6 +816,9 @@ TEST(Query, FillSegment) {
auto std_val = std_vec[internal_offset];
auto std_i32 = std_i32_vec[internal_offset];
auto std_i32_valid = i32_vec_valid_data[internal_offset];
auto std_float_valid = false;
auto std_double = double_default_value;
auto std_double_valid = true;
std::vector<float> std_vfloat(dim);
std::copy_n(std_vfloat_vec.begin() + dim * internal_offset,
dim,
@ -672,6 +841,20 @@ TEST(Query, FillSegment) {
bool i32_valid;
memcpy(&i32_valid, &output_i32_valid_data[i], sizeof(bool));
ASSERT_EQ(i32_valid, std_i32_valid);
// check float field lack null field binlog valid field
bool f_valid;
memcpy(&f_valid, &output_float_valid_data[i], sizeof(bool));
ASSERT_EQ(f_valid, std_float_valid);
// check double field lack default value field binlog
double d;
memcpy(&d, &output_double_field_data[i], sizeof(double));
ASSERT_EQ(d, std_double);
// check double field lack default value field binlog valid field
bool d_valid;
memcpy(&d_valid, &output_double_valid_data[i], sizeof(bool));
ASSERT_EQ(d_valid, std_double_valid);
}
}
}

View File

@ -10,6 +10,7 @@
// or implied. See the License for the specific language governing permissions and limitations under the License
#include <boost/format.hpp>
#include <optional>
#include <gtest/gtest.h>
#include "common/Types.h"
@ -430,7 +431,7 @@ TEST(Sealed, LoadFieldData) {
auto indexing = GenVecIndexing(
N, dim, fakevec.data(), knowhere::IndexEnum::INDEX_FAISS_IVFFLAT);
//
auto segment = CreateSealedSegment(schema);
// std::string dsl = R"({
// "bool": {
@ -915,7 +916,7 @@ TEST(Sealed, LoadScalarIndex) {
LoadFieldDataInfo row_id_info;
FieldMeta row_id_field_meta(
FieldName("RowID"), RowFieldID, DataType::INT64, false);
FieldName("RowID"), RowFieldID, DataType::INT64, false, std::nullopt);
auto field_data =
std::make_shared<milvus::FieldData<int64_t>>(DataType::INT64, false);
field_data->FillFieldData(dataset.row_ids_.data(), N);
@ -924,8 +925,11 @@ TEST(Sealed, LoadScalarIndex) {
segment->LoadFieldData(RowFieldID, field_data_info);
LoadFieldDataInfo ts_info;
FieldMeta ts_field_meta(
FieldName("Timestamp"), TimestampFieldID, DataType::INT64, false);
FieldMeta ts_field_meta(FieldName("Timestamp"),
TimestampFieldID,
DataType::INT64,
false,
std::nullopt);
field_data =
std::make_shared<milvus::FieldData<int64_t>>(DataType::INT64, false);
field_data->FillFieldData(dataset.timestamps_.data(), N);
@ -1461,7 +1465,8 @@ TEST(Sealed, GetVectorFromChunkCache) {
milvus::DataType::VECTOR_FLOAT,
dim,
metric_type,
false);
false,
std::nullopt);
auto rcm = milvus::storage::RemoteChunkManagerSingleton::GetInstance()
.GetRemoteChunkManager();
@ -1561,7 +1566,8 @@ TEST(Sealed, GetSparseVectorFromChunkCache) {
milvus::DataType::VECTOR_SPARSE_FLOAT,
dim,
metric_type,
false);
false,
std::nullopt);
auto data = dataset.get_col<knowhere::sparse::SparseRow<float>>(fakevec_id);
@ -1669,7 +1675,8 @@ TEST(Sealed, WarmupChunkCache) {
milvus::DataType::VECTOR_FLOAT,
dim,
metric_type,
false);
false,
std::nullopt);
auto rcm = milvus::storage::RemoteChunkManagerSingleton::GetInstance()
.GetRemoteChunkManager();

View File

@ -10,6 +10,7 @@
// or implied. See the License for the specific language governing permissions and limitations under the License
#include <gtest/gtest.h>
#include <optional>
#include <string>
#include "common/Schema.h"
@ -33,7 +34,11 @@ GenTestSchema(std::map<std::string, std::string> params = {},
bool nullable = false) {
auto schema = std::make_shared<Schema>();
{
FieldMeta f(FieldName("pk"), FieldId(100), DataType::INT64, false);
FieldMeta f(FieldName("pk"),
FieldId(100),
DataType::INT64,
false,
std::nullopt);
schema->AddField(std::move(f));
schema->set_primary_field_id(FieldId(100));
}
@ -45,7 +50,8 @@ GenTestSchema(std::map<std::string, std::string> params = {},
nullable,
true,
true,
params);
params,
std::nullopt);
schema->AddField(std::move(f));
}
{
@ -54,7 +60,8 @@ GenTestSchema(std::map<std::string, std::string> params = {},
DataType::VECTOR_FLOAT,
16,
knowhere::metric::L2,
false);
false,
std::nullopt);
schema->AddField(std::move(f));
}
return schema;
@ -943,9 +950,13 @@ TEST(TextMatch, SealedJieBaNullable) {
TEST(TextMatch, GrowingLoadData) {
int64_t N = 7;
auto schema = GenTestSchema({}, true);
schema->AddField(FieldName("RowID"), FieldId(0), DataType::INT64, false);
schema->AddField(
FieldName("Timestamp"), FieldId(1), DataType::INT64, false);
FieldName("RowID"), FieldId(0), DataType::INT64, false, std::nullopt);
schema->AddField(FieldName("Timestamp"),
FieldId(1),
DataType::INT64,
false,
std::nullopt);
std::vector<std::string> raw_str = {"football, basketball, pingpang",
"swimming, football",
"golf",

View File

@ -273,6 +273,10 @@ func (m *mockRootCoordClient) ShowCollectionIDs(ctx context.Context, req *rootco
}, nil
}
func (m *mockRootCoordClient) AddCollectionField(ctx context.Context, req *milvuspb.AddCollectionFieldRequest, opts ...grpc.CallOption) (*commonpb.Status, error) {
panic("not implemented") // TODO: Implement
}
func (m *mockRootCoordClient) CreateDatabase(ctx context.Context, in *milvuspb.CreateDatabaseRequest, opts ...grpc.CallOption) (*commonpb.Status, error) {
panic("not implemented") // TODO: Implement
}

View File

@ -1622,6 +1622,8 @@ func (s *Server) BroadcastAlteredCollection(ctx context.Context, req *datapb.Alt
}
clonedColl.Properties = properties
// add field will change the schema
clonedColl.Schema = req.GetSchema()
s.meta.AddCollection(clonedColl)
return merr.Success(), nil
}

View File

@ -160,7 +160,9 @@ func (it *indexBuildTask) PreCheck(ctx context.Context, dependency *taskSchedule
typeParams := dependency.meta.indexMeta.GetTypeParams(segIndex.CollectionID, segIndex.IndexID)
fieldID := dependency.meta.indexMeta.GetFieldIDByIndexID(segIndex.CollectionID, segIndex.IndexID)
binlogIDs := getBinLogIDs(segment, fieldID)
totalRows := getTotalBinlogRows(segment, fieldID)
// When new index parameters are added, these parameters need to be updated to ensure they are included during the index-building process.
if vecindexmgr.GetVecIndexMgrInstance().IsVecIndex(indexType) && Params.KnowhereConfig.Enable.GetAsBool() {
@ -259,6 +261,8 @@ func (it *indexBuildTask) PreCheck(ctx context.Context, dependency *taskSchedule
PartitionKeyIsolation: partitionKeyIsolation,
}
it.req.LackBinlogRows = it.req.NumRows - totalRows
log.Ctx(ctx).Info("index task pre check successfully", zap.Int64("taskID", it.GetTaskID()),
zap.Int64("segID", segment.GetID()),
zap.Int32("CurrentIndexVersion", it.req.GetCurrentIndexVersion()),

View File

@ -285,6 +285,18 @@ func getBinLogIDs(segment *SegmentInfo, fieldID int64) []int64 {
return binlogIDs
}
func getTotalBinlogRows(segment *SegmentInfo, fieldID int64) int64 {
var total int64
for _, fieldBinLog := range segment.GetBinlogs() {
if fieldBinLog.GetFieldID() == fieldID {
for _, binLog := range fieldBinLog.GetBinlogs() {
total += binLog.EntriesNum
}
}
}
return total
}
func CheckCheckPointsHealth(meta *meta) error {
for channel, cp := range meta.GetChannelCheckpoints() {
collectionID := funcutil.GetCollectionIDFromVChannel(channel)

View File

@ -311,10 +311,12 @@ func (it *indexBuildTask) Execute(ctx context.Context) error {
IndexStorePath: it.req.GetIndexStorePath(),
OptFields: optFields,
PartitionKeyIsolation: it.req.GetPartitionKeyIsolation(),
LackBinlogRows: it.req.GetLackBinlogRows(),
}
log.Info("debug create index", zap.Any("buildIndexParams", buildIndexParams))
var err error
it.index, err = indexcgowrapper.CreateIndex(ctx, buildIndexParams)
if err != nil {
if it.index != nil && it.index.CleanLocalData() != nil {

View File

@ -689,6 +689,11 @@ func (s *Server) DescribeCollection(ctx context.Context, request *milvuspb.Descr
return s.proxy.DescribeCollection(ctx, request)
}
// AddCollectionField add a field to collection
func (s *Server) AddCollectionField(ctx context.Context, request *milvuspb.AddCollectionFieldRequest) (*commonpb.Status, error) {
return s.proxy.AddCollectionField(ctx, request)
}
// GetCollectionStatistics notifies Proxy to get a collection's Statistics
func (s *Server) GetCollectionStatistics(ctx context.Context, request *milvuspb.GetCollectionStatisticsRequest) (*milvuspb.GetCollectionStatisticsResponse, error) {
return s.proxy.GetCollectionStatistics(ctx, request)

View File

@ -624,6 +624,18 @@ func (c *Client) ListPolicy(ctx context.Context, req *internalpb.ListPolicyReque
})
}
// CreatePartition create partition
func (c *Client) AddCollectionField(ctx context.Context, in *milvuspb.AddCollectionFieldRequest, opts ...grpc.CallOption) (*commonpb.Status, error) {
in = typeutil.Clone(in)
commonpbutil.UpdateMsgBase(
in.GetBase(),
commonpbutil.FillMsgBaseFromClient(paramtable.GetNodeID(), commonpbutil.WithTargetID(c.grpcClient.GetNodeID())),
)
return wrapGrpcCall(ctx, c, func(client rootcoordpb.RootCoordClient) (*commonpb.Status, error) {
return client.AddCollectionField(ctx, in)
})
}
func (c *Client) CheckHealth(ctx context.Context, req *milvuspb.CheckHealthRequest, opts ...grpc.CallOption) (*milvuspb.CheckHealthResponse, error) {
return wrapGrpcCall(ctx, c, func(client rootcoordpb.RootCoordClient) (*milvuspb.CheckHealthResponse, error) {
return client.CheckHealth(ctx, req)

View File

@ -432,6 +432,11 @@ func (s *Server) ShowCollectionIDs(ctx context.Context, in *rootcoordpb.ShowColl
return s.rootCoord.ShowCollectionIDs(ctx, in)
}
// AddCollectionField adds the specified field.
func (s *Server) AddCollectionField(ctx context.Context, in *milvuspb.AddCollectionFieldRequest) (*commonpb.Status, error) {
return s.rootCoord.AddCollectionField(ctx, in)
}
// CreatePartition creates a partition in a collection
func (s *Server) CreatePartition(ctx context.Context, in *milvuspb.CreatePartitionRequest) (*commonpb.Status, error) {
return s.rootCoord.CreatePartition(ctx, in)

View File

@ -646,6 +646,7 @@ func (kc *Catalog) alterModifyCollection(ctx context.Context, oldColl *model.Col
oldCollClone.ConsistencyLevel = newColl.ConsistencyLevel
oldCollClone.State = newColl.State
oldCollClone.Properties = newColl.Properties
oldCollClone.Fields = newColl.Fields
oldKey := BuildCollectionKey(oldColl.DBID, oldColl.CollectionID)
newKey := BuildCollectionKey(newColl.DBID, oldColl.CollectionID)

View File

@ -38,6 +38,65 @@ func (_m *RootCoord) EXPECT() *RootCoord_Expecter {
return &RootCoord_Expecter{mock: &_m.Mock}
}
// AddCollectionField provides a mock function with given fields: _a0, _a1
func (_m *RootCoord) AddCollectionField(_a0 context.Context, _a1 *milvuspb.AddCollectionFieldRequest) (*commonpb.Status, error) {
ret := _m.Called(_a0, _a1)
if len(ret) == 0 {
panic("no return value specified for AddCollectionField")
}
var r0 *commonpb.Status
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.AddCollectionFieldRequest) (*commonpb.Status, error)); ok {
return rf(_a0, _a1)
}
if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.AddCollectionFieldRequest) *commonpb.Status); ok {
r0 = rf(_a0, _a1)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*commonpb.Status)
}
}
if rf, ok := ret.Get(1).(func(context.Context, *milvuspb.AddCollectionFieldRequest) error); ok {
r1 = rf(_a0, _a1)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// RootCoord_AddCollectionField_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddCollectionField'
type RootCoord_AddCollectionField_Call struct {
*mock.Call
}
// AddCollectionField is a helper method to define mock.On call
// - _a0 context.Context
// - _a1 *milvuspb.AddCollectionFieldRequest
func (_e *RootCoord_Expecter) AddCollectionField(_a0 interface{}, _a1 interface{}) *RootCoord_AddCollectionField_Call {
return &RootCoord_AddCollectionField_Call{Call: _e.mock.On("AddCollectionField", _a0, _a1)}
}
func (_c *RootCoord_AddCollectionField_Call) Run(run func(_a0 context.Context, _a1 *milvuspb.AddCollectionFieldRequest)) *RootCoord_AddCollectionField_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(*milvuspb.AddCollectionFieldRequest))
})
return _c
}
func (_c *RootCoord_AddCollectionField_Call) Return(_a0 *commonpb.Status, _a1 error) *RootCoord_AddCollectionField_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *RootCoord_AddCollectionField_Call) RunAndReturn(run func(context.Context, *milvuspb.AddCollectionFieldRequest) (*commonpb.Status, error)) *RootCoord_AddCollectionField_Call {
_c.Call.Return(run)
return _c
}
// AllocID provides a mock function with given fields: _a0, _a1
func (_m *RootCoord) AllocID(_a0 context.Context, _a1 *rootcoordpb.AllocIDRequest) (*rootcoordpb.AllocIDResponse, error) {
ret := _m.Called(_a0, _a1)

View File

@ -33,6 +33,80 @@ func (_m *MockRootCoordClient) EXPECT() *MockRootCoordClient_Expecter {
return &MockRootCoordClient_Expecter{mock: &_m.Mock}
}
// AddCollectionField provides a mock function with given fields: ctx, in, opts
func (_m *MockRootCoordClient) AddCollectionField(ctx context.Context, in *milvuspb.AddCollectionFieldRequest, opts ...grpc.CallOption) (*commonpb.Status, error) {
_va := make([]interface{}, len(opts))
for _i := range opts {
_va[_i] = opts[_i]
}
var _ca []interface{}
_ca = append(_ca, ctx, in)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
if len(ret) == 0 {
panic("no return value specified for AddCollectionField")
}
var r0 *commonpb.Status
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.AddCollectionFieldRequest, ...grpc.CallOption) (*commonpb.Status, error)); ok {
return rf(ctx, in, opts...)
}
if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.AddCollectionFieldRequest, ...grpc.CallOption) *commonpb.Status); ok {
r0 = rf(ctx, in, opts...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*commonpb.Status)
}
}
if rf, ok := ret.Get(1).(func(context.Context, *milvuspb.AddCollectionFieldRequest, ...grpc.CallOption) error); ok {
r1 = rf(ctx, in, opts...)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockRootCoordClient_AddCollectionField_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddCollectionField'
type MockRootCoordClient_AddCollectionField_Call struct {
*mock.Call
}
// AddCollectionField is a helper method to define mock.On call
// - ctx context.Context
// - in *milvuspb.AddCollectionFieldRequest
// - opts ...grpc.CallOption
func (_e *MockRootCoordClient_Expecter) AddCollectionField(ctx interface{}, in interface{}, opts ...interface{}) *MockRootCoordClient_AddCollectionField_Call {
return &MockRootCoordClient_AddCollectionField_Call{Call: _e.mock.On("AddCollectionField",
append([]interface{}{ctx, in}, opts...)...)}
}
func (_c *MockRootCoordClient_AddCollectionField_Call) Run(run func(ctx context.Context, in *milvuspb.AddCollectionFieldRequest, opts ...grpc.CallOption)) *MockRootCoordClient_AddCollectionField_Call {
_c.Call.Run(func(args mock.Arguments) {
variadicArgs := make([]grpc.CallOption, len(args)-2)
for i, a := range args[2:] {
if a != nil {
variadicArgs[i] = a.(grpc.CallOption)
}
}
run(args[0].(context.Context), args[1].(*milvuspb.AddCollectionFieldRequest), variadicArgs...)
})
return _c
}
func (_c *MockRootCoordClient_AddCollectionField_Call) Return(_a0 *commonpb.Status, _a1 error) *MockRootCoordClient_AddCollectionField_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *MockRootCoordClient_AddCollectionField_Call) RunAndReturn(run func(context.Context, *milvuspb.AddCollectionFieldRequest, ...grpc.CallOption) (*commonpb.Status, error)) *MockRootCoordClient_AddCollectionField_Call {
_c.Call.Return(run)
return _c
}
// AllocID provides a mock function with given fields: ctx, in, opts
func (_m *MockRootCoordClient) AllocID(ctx context.Context, in *rootcoordpb.AllocIDRequest, opts ...grpc.CallOption) (*rootcoordpb.AllocIDResponse, error) {
_va := make([]interface{}, len(opts))

View File

@ -1028,6 +1028,80 @@ func (node *Proxy) DescribeCollection(ctx context.Context, request *milvuspb.Des
return dct.result, nil
}
// AddCollectionField add a field to collection
func (node *Proxy) AddCollectionField(ctx context.Context, request *milvuspb.AddCollectionFieldRequest) (*commonpb.Status, error) {
if err := merr.CheckHealthy(node.GetStateCode()); err != nil {
return merr.Status(err), nil
}
ctx, sp := otel.Tracer(typeutil.ProxyRole).Start(ctx, "Proxy-AddCollectionField")
defer sp.End()
dresp, err := node.DescribeCollection(ctx, &milvuspb.DescribeCollectionRequest{DbName: request.DbName, CollectionName: request.CollectionName})
if err := merr.CheckRPCCall(dresp, err); err != nil {
return merr.Status(err), nil
}
task := &addCollectionFieldTask{
ctx: ctx,
Condition: NewTaskCondition(ctx),
AddCollectionFieldRequest: request,
rootCoord: node.rootCoord,
oldSchema: dresp.GetSchema(),
}
method := "AddCollectionField"
tr := timerecord.NewTimeRecorder(method)
metrics.ProxyFunctionCall.WithLabelValues(strconv.FormatInt(paramtable.GetNodeID(), 10), method,
metrics.TotalLabel, request.GetDbName(), request.GetCollectionName()).Inc()
log := log.Ctx(ctx).With(
zap.String("role", typeutil.ProxyRole),
zap.String("db", request.DbName),
zap.String("collection", request.CollectionName))
log.Info(rpcReceived(method))
if err := node.sched.ddQueue.Enqueue(task); err != nil {
log.Warn(
rpcFailedToEnqueue(method),
zap.Error(err))
metrics.ProxyFunctionCall.WithLabelValues(strconv.FormatInt(paramtable.GetNodeID(), 10), method,
metrics.AbandonLabel, request.GetDbName(), request.GetCollectionName()).Inc()
return merr.Status(err), nil
}
log.Info(
rpcEnqueued(method),
zap.Uint64("BeginTs", task.BeginTs()),
zap.Uint64("EndTs", task.EndTs()))
if err := task.WaitToFinish(); err != nil {
log.Warn(
rpcFailedToWaitToFinish(method),
zap.Error(err),
zap.Uint64("BeginTs", task.BeginTs()),
zap.Uint64("EndTs", task.EndTs()))
metrics.ProxyFunctionCall.WithLabelValues(strconv.FormatInt(paramtable.GetNodeID(), 10), method,
metrics.FailLabel, request.GetDbName(), request.GetCollectionName()).Inc()
return merr.Status(err), nil
}
log.Info(
rpcDone(method),
zap.Uint64("BeginTs", task.BeginTs()),
zap.Uint64("EndTs", task.EndTs()))
metrics.ProxyFunctionCall.WithLabelValues(strconv.FormatInt(paramtable.GetNodeID(), 10), method,
metrics.SuccessLabel, request.GetDbName(), request.GetCollectionName()).Inc()
metrics.ProxyReqLatency.WithLabelValues(strconv.FormatInt(paramtable.GetNodeID(), 10), method).Observe(float64(tr.ElapseSpan().Milliseconds()))
return task.result, nil
}
// GetStatistics get the statistics, such as `num_rows`.
// WARNING: It is an experimental API
func (node *Proxy) GetStatistics(ctx context.Context, request *milvuspb.GetStatisticsRequest) (*milvuspb.GetStatisticsResponse, error) {

View File

@ -860,7 +860,10 @@ func (m *MetaCache) RemoveCollection(ctx context.Context, database, collectionNa
if dbOk {
delete(m.collInfo[database], collectionName)
}
log.Ctx(ctx).Debug("remove collection", zap.String("db", database), zap.String("collection", collectionName))
if database == "" {
delete(m.collInfo[defaultDB], collectionName)
}
log.Ctx(ctx).Debug("remove collection", zap.String("db", database), zap.String("collection", collectionName), zap.Bool("dbok", dbOk))
}
func (m *MetaCache) RemoveCollectionsByID(ctx context.Context, collectionID UniqueID, version uint64, removeVersion bool) []string {

View File

@ -1222,7 +1222,7 @@ func TestSchemaInfo_GetLoadFieldIDs(t *testing.T) {
},
loadFields: nil,
skipDynamicField: false,
expectResult: []int64{common.StartOfUserFieldID, common.StartOfUserFieldID + 1, common.StartOfUserFieldID + 2, common.StartOfUserFieldID + 3, common.StartOfUserFieldID + 4},
expectResult: []int64{},
expectErr: false,
},
{

View File

@ -326,6 +326,61 @@ func (coord *RootCoordMock) GetTimeTickChannel(ctx context.Context, req *interna
}, nil
}
func (coord *RootCoordMock) AddCollectionField(ctx context.Context, req *milvuspb.AddCollectionFieldRequest, opts ...grpc.CallOption) (*commonpb.Status, error) {
code := coord.state.Load().(commonpb.StateCode)
if code != commonpb.StateCode_Healthy {
return &commonpb.Status{
ErrorCode: commonpb.ErrorCode_UnexpectedError,
Reason: fmt.Sprintf("state code = %s", commonpb.StateCode_name[int32(code)]),
}, nil
}
coord.collMtx.Lock()
defer coord.collMtx.Unlock()
collID, exist := coord.collName2ID[req.CollectionName]
if !exist {
return &commonpb.Status{
ErrorCode: commonpb.ErrorCode_CollectionNotExists,
Reason: "collection not exist",
}, nil
}
collInfo, exist := coord.collID2Meta[collID]
if !exist {
return &commonpb.Status{
ErrorCode: commonpb.ErrorCode_CollectionNotExists,
Reason: "collection info not exist",
}, nil
}
fieldSchema := &schemapb.FieldSchema{}
err := proto.Unmarshal(req.Schema, fieldSchema)
if err != nil {
return &commonpb.Status{
ErrorCode: commonpb.ErrorCode_UnexpectedError,
Reason: "invalid parameter",
}, nil
}
fieldSchema.FieldID = int64(common.StartOfUserFieldID + len(collInfo.schema.Fields) + 1)
collInfo.schema.Fields = append(collInfo.schema.Fields, fieldSchema)
ts := uint64(time.Now().Nanosecond())
coord.collID2Meta[collID] = collectionMeta{
name: req.CollectionName,
id: collID,
schema: collInfo.schema,
shardsNum: collInfo.shardsNum,
virtualChannelNames: collInfo.virtualChannelNames,
physicalChannelNames: collInfo.physicalChannelNames,
createdTimestamp: ts,
createdUtcTimestamp: ts,
properties: collInfo.properties,
}
return merr.Success(), nil
}
func (coord *RootCoordMock) CreateCollection(ctx context.Context, req *milvuspb.CreateCollectionRequest, opts ...grpc.CallOption) (*commonpb.Status, error) {
code := coord.state.Load().(commonpb.StateCode)
if code != commonpb.StateCode_Healthy {

View File

@ -31,7 +31,6 @@ import (
"github.com/milvus-io/milvus-proto/go-api/v2/milvuspb"
"github.com/milvus-io/milvus-proto/go-api/v2/schemapb"
"github.com/milvus-io/milvus/internal/types"
"github.com/milvus-io/milvus/internal/util/ctokenizer"
"github.com/milvus-io/milvus/pkg/v2/common"
"github.com/milvus-io/milvus/pkg/v2/log"
"github.com/milvus-io/milvus/pkg/v2/mq/msgstream"
@ -113,6 +112,8 @@ const (
AlterDatabaseTaskName = "AlterDatabaseTaskName"
DescribeDatabaseTaskName = "DescribeDatabaseTaskName"
AddFieldTaskName = "AddFieldTaskName"
// minFloat32 minimum float.
minFloat32 = -1 * float32(math.MaxFloat32)
@ -387,42 +388,7 @@ func (t *createCollectionTask) PreExecute(ctx context.Context) error {
}
for _, field := range t.schema.Fields {
// validate field name
if err := validateFieldName(field.Name); err != nil {
return err
}
// validate dense vector field type parameters
isVectorType := typeutil.IsVectorType(field.DataType)
if isVectorType {
err = validateDimension(field)
if err != nil {
return err
}
}
// valid max length per row parameters
// if max_length not specified, return error
if field.DataType == schemapb.DataType_VarChar ||
field.DataType == schemapb.DataType_Text ||
(field.GetDataType() == schemapb.DataType_Array && field.GetElementType() == schemapb.DataType_VarChar) {
err = validateMaxLengthPerRow(t.schema.Name, field)
if err != nil {
return err
}
}
// valid max capacity for array per row parameters
// if max_capacity not specified, return error
if field.DataType == schemapb.DataType_Array {
if err = validateMaxCapacityPerRow(t.schema.Name, field); err != nil {
return err
}
}
// TODO should remove the index params in the field schema
indexParams := funcutil.KeyValuePair2Map(field.GetIndexParams())
if err = ValidateAutoIndexMmapConfig(isVectorType, indexParams); err != nil {
return err
}
if err := ctokenizer.ValidateTextSchema(field, wasBm25FunctionInputField(t.schema, field)); err != nil {
if err := ValidateField(field, t.schema); err != nil {
return err
}
}
@ -453,6 +419,127 @@ func (t *createCollectionTask) PostExecute(ctx context.Context) error {
return nil
}
type addCollectionFieldTask struct {
baseTask
Condition
*milvuspb.AddCollectionFieldRequest
ctx context.Context
rootCoord types.RootCoordClient
result *commonpb.Status
fieldSchema *schemapb.FieldSchema
oldSchema *schemapb.CollectionSchema
}
func (t *addCollectionFieldTask) TraceCtx() context.Context {
return t.ctx
}
func (t *addCollectionFieldTask) ID() UniqueID {
return t.Base.MsgID
}
func (t *addCollectionFieldTask) SetID(uid UniqueID) {
t.Base.MsgID = uid
}
func (t *addCollectionFieldTask) Name() string {
return AddFieldTaskName
}
func (t *addCollectionFieldTask) Type() commonpb.MsgType {
return t.Base.MsgType
}
func (t *addCollectionFieldTask) BeginTs() Timestamp {
return t.Base.Timestamp
}
func (t *addCollectionFieldTask) EndTs() Timestamp {
return t.Base.Timestamp
}
func (t *addCollectionFieldTask) SetTs(ts Timestamp) {
t.Base.Timestamp = ts
}
func (t *addCollectionFieldTask) OnEnqueue() error {
if t.Base == nil {
t.Base = commonpbutil.NewMsgBase()
}
t.Base.MsgType = commonpb.MsgType_AddCollectionField
t.Base.SourceID = paramtable.GetNodeID()
return nil
}
func (t *addCollectionFieldTask) PreExecute(ctx context.Context) error {
if t.oldSchema == nil {
return merr.WrapErrParameterInvalidMsg("empty old schema in add field task")
}
if t.oldSchema.EnableDynamicField {
return merr.WrapErrParameterInvalidMsg("not support to add field in an enable dynamic field collection")
}
t.fieldSchema = &schemapb.FieldSchema{}
err := proto.Unmarshal(t.GetSchema(), t.fieldSchema)
if err != nil {
return err
}
fieldList := typeutil.NewSet[string]()
for _, schema := range t.oldSchema.Fields {
fieldList.Insert(schema.Name)
}
if len(fieldList) >= Params.ProxyCfg.MaxFieldNum.GetAsInt() {
msg := fmt.Sprintf("The number of fields has reached the maximum value %d", Params.ProxyCfg.MaxFieldNum.GetAsInt())
return merr.WrapErrParameterInvalidMsg(msg)
}
if _, ok := schemapb.DataType_name[int32(t.fieldSchema.DataType)]; !ok || t.fieldSchema.GetDataType() == schemapb.DataType_None {
return merr.WrapErrParameterInvalid("valid field", fmt.Sprintf("field data type: %s is not supported", t.fieldSchema.GetDataType()))
}
if typeutil.IsVectorType(t.fieldSchema.DataType) {
return merr.WrapErrParameterInvalidMsg(fmt.Sprintf("not support to add vector field, field name = %s", t.fieldSchema.Name))
}
if funcutil.SliceContain([]string{common.RowIDFieldName, common.TimeStampFieldName, common.MetaFieldName}, t.fieldSchema.GetName()) {
return merr.WrapErrParameterInvalidMsg(fmt.Sprintf("not support to add system field, field name = %s", t.fieldSchema.Name))
}
if t.fieldSchema.IsPrimaryKey {
return merr.WrapErrParameterInvalidMsg(fmt.Sprintf("not support to add pk field, field name = %s", t.fieldSchema.Name))
}
if !t.fieldSchema.Nullable {
return merr.WrapErrParameterInvalidMsg(fmt.Sprintf("added field must be nullable, please check it, field name = %s", t.fieldSchema.Name))
}
if t.fieldSchema.AutoID {
return merr.WrapErrParameterInvalidMsg(fmt.Sprintf("only primary field can speficy AutoID with true, field name = %s", t.fieldSchema.Name))
}
if t.fieldSchema.GetIsClusteringKey() {
for _, f := range t.oldSchema.Fields {
if f.GetIsClusteringKey() {
return merr.WrapErrParameterInvalidMsg(fmt.Sprintf("already has another clutering key field, field name: %s", t.fieldSchema.GetName()))
}
}
}
if err := ValidateField(t.fieldSchema, t.oldSchema); err != nil {
return err
}
if fieldList.Contain(t.fieldSchema.Name) {
return merr.WrapErrParameterInvalidMsg(fmt.Sprintf("duplicate field name: %s", t.fieldSchema.GetName()))
}
log.Info("PreExecute addField task done", zap.Any("field schema", t.fieldSchema))
return nil
}
func (t *addCollectionFieldTask) Execute(ctx context.Context) error {
var err error
t.result, err = t.rootCoord.AddCollectionField(ctx, t.AddCollectionFieldRequest)
return merr.CheckRPCCall(t.result, err)
}
func (t *addCollectionFieldTask) PostExecute(ctx context.Context) error {
return nil
}
type dropCollectionTask struct {
baseTask
Condition

View File

@ -169,7 +169,7 @@ func (t *searchTask) PreExecute(ctx context.Context) error {
t.request.OutputFields, t.userOutputFields, t.userDynamicFields, t.userRequestedPkFieldExplicitly, err = translateOutputFields(t.request.OutputFields, t.schema, true)
if err != nil {
log.Warn("translate output fields failed", zap.Error(err))
log.Warn("translate output fields failed", zap.Error(err), zap.Any("schema", t.schema))
return err
}
log.Debug("translate output fields",

View File

@ -20,6 +20,7 @@ import (
"bytes"
"context"
"encoding/binary"
"fmt"
"math/rand"
"strconv"
"testing"
@ -667,6 +668,257 @@ func TestTranslateOutputFields(t *testing.T) {
})
}
func TestAddFieldTask(t *testing.T) {
rc := NewRootCoordMock()
ctx := context.Background()
prefix := "TestAddFieldTask"
dbName := ""
collectionName := prefix + funcutil.GenRandomStr()
collectionID := int64(1)
int64Field := "int64"
floatVecField := "fvec"
varCharField := "varChar"
rc.collName2ID[collectionName] = collectionID
rc.collID2Meta[collectionID] = collectionMeta{
name: collectionName,
id: collectionID,
schema: &schemapb.CollectionSchema{
Fields: []*schemapb.FieldSchema{
{FieldID: 100, DataType: schemapb.DataType_Int64, AutoID: true, Name: "ID"},
{
FieldID: 101, DataType: schemapb.DataType_FloatVector, Name: "vector",
TypeParams: []*commonpb.KeyValuePair{
{Key: "dim", Value: "128"},
},
},
},
},
}
fieldName2Type := make(map[string]schemapb.DataType)
fieldName2Type[int64Field] = schemapb.DataType_Int64
fieldName2Type[varCharField] = schemapb.DataType_VarChar
fieldName2Type[floatVecField] = schemapb.DataType_FloatVector
schema := constructCollectionSchemaByDataType(collectionName, fieldName2Type, int64Field, false)
fSchema := &schemapb.FieldSchema{
Name: "add",
DataType: schemapb.DataType_Bool,
Nullable: true,
}
bytes, err := proto.Marshal(fSchema)
assert.NoError(t, err)
task := &addCollectionFieldTask{
Condition: NewTaskCondition(ctx),
AddCollectionFieldRequest: &milvuspb.AddCollectionFieldRequest{
Base: nil,
DbName: dbName,
CollectionName: collectionName,
Schema: bytes,
},
ctx: ctx,
rootCoord: rc,
result: nil,
oldSchema: schema,
}
t.Run("on enqueue", func(t *testing.T) {
err := task.OnEnqueue()
assert.NoError(t, err)
assert.Equal(t, commonpb.MsgType_AddCollectionField, task.Type())
})
t.Run("ctx", func(t *testing.T) {
traceCtx := task.TraceCtx()
assert.NotNil(t, traceCtx)
})
t.Run("id", func(t *testing.T) {
id := UniqueID(uniquegenerator.GetUniqueIntGeneratorIns().GetInt())
task.SetID(id)
assert.Equal(t, id, task.ID())
})
t.Run("name", func(t *testing.T) {
assert.Equal(t, AddFieldTaskName, task.Name())
})
t.Run("ts", func(t *testing.T) {
ts := Timestamp(time.Now().UnixNano())
task.SetTs(ts)
assert.Equal(t, ts, task.BeginTs())
assert.Equal(t, ts, task.EndTs())
})
t.Run("process task", func(t *testing.T) {
var err error
// nil collection schema
task.oldSchema = nil
err = task.PreExecute(ctx)
assert.Error(t, err)
assert.ErrorIs(t, err, merr.ErrParameterInvalid)
bytes, err := proto.Marshal(fSchema)
assert.NoError(t, err)
task.Schema = bytes
task.oldSchema = schema
err = task.PreExecute(ctx)
assert.NoError(t, err)
err = task.Execute(ctx)
assert.NoError(t, err)
assert.Equal(t, commonpb.ErrorCode_Success, task.result.ErrorCode)
err = task.PostExecute(ctx)
assert.NoError(t, err)
})
t.Run("PreExecute", func(t *testing.T) {
var err error
err = task.PreExecute(ctx)
assert.NoError(t, err)
// nil schema
task.Schema = nil
err = task.PreExecute(ctx)
assert.Error(t, err)
assert.ErrorIs(t, err, merr.ErrParameterInvalid)
// not support dynamic field
task.oldSchema.EnableDynamicField = true
err = task.PreExecute(ctx)
assert.Error(t, err)
assert.ErrorIs(t, err, merr.ErrParameterInvalid)
task.oldSchema.EnableDynamicField = false
// too many fields
Params.Save(Params.ProxyCfg.MaxFieldNum.Key, fmt.Sprint(task.oldSchema.Fields))
fSchema := &schemapb.FieldSchema{
Name: "add_field",
}
bytes, err := proto.Marshal(fSchema)
assert.NoError(t, err)
task.Schema = bytes
err = task.PreExecute(ctx)
assert.Error(t, err)
assert.ErrorIs(t, err, merr.ErrParameterInvalid)
Params.Reset(Params.ProxyCfg.MaxFieldNum.Key)
// invalid field type
fSchema = &schemapb.FieldSchema{
DataType: schemapb.DataType_None,
}
bytes, err = proto.Marshal(fSchema)
assert.NoError(t, err)
task.Schema = bytes
err = task.PreExecute(ctx)
assert.Error(t, err)
assert.ErrorIs(t, err, merr.ErrParameterInvalid)
// not support vector field
fSchema = &schemapb.FieldSchema{
DataType: schemapb.DataType_FloatVector,
}
bytes, err = proto.Marshal(fSchema)
assert.NoError(t, err)
task.Schema = bytes
err = task.PreExecute(ctx)
assert.Error(t, err)
assert.ErrorIs(t, err, merr.ErrParameterInvalid)
// not support system field
fSchema = &schemapb.FieldSchema{
Name: common.TimeStampFieldName,
}
bytes, err = proto.Marshal(fSchema)
assert.NoError(t, err)
task.Schema = bytes
err = task.PreExecute(ctx)
assert.Error(t, err)
assert.ErrorIs(t, err, merr.ErrParameterInvalid)
// must be nullable
fSchema = &schemapb.FieldSchema{
Nullable: false,
}
bytes, err = proto.Marshal(fSchema)
assert.NoError(t, err)
task.Schema = bytes
err = task.PreExecute(ctx)
assert.Error(t, err)
assert.ErrorIs(t, err, merr.ErrParameterInvalid)
// not support pk field
fSchema = &schemapb.FieldSchema{
IsPrimaryKey: true,
}
bytes, err = proto.Marshal(fSchema)
assert.NoError(t, err)
task.Schema = bytes
err = task.PreExecute(ctx)
assert.Error(t, err)
assert.ErrorIs(t, err, merr.ErrParameterInvalid)
// not support partition key
Params.Save(Params.ProxyCfg.MustUsePartitionKey.Key, "true")
err = task.PreExecute(ctx)
assert.Error(t, err)
assert.ErrorIs(t, err, merr.ErrParameterInvalid)
Params.Reset(Params.ProxyCfg.MustUsePartitionKey.Key)
// not support autoID
fSchema = &schemapb.FieldSchema{
AutoID: true,
}
bytes, err = proto.Marshal(fSchema)
assert.NoError(t, err)
task.Schema = bytes
err = task.PreExecute(ctx)
assert.Error(t, err)
assert.ErrorIs(t, err, merr.ErrParameterInvalid)
// more ClusteringKey field
fSchema = &schemapb.FieldSchema{
IsClusteringKey: true,
}
bytes, err = proto.Marshal(fSchema)
assert.NoError(t, err)
task.Schema = bytes
task.oldSchema = schema
task.oldSchema.Fields = append(task.oldSchema.Fields, &schemapb.FieldSchema{
IsClusteringKey: true,
})
err = task.PreExecute(ctx)
assert.Error(t, err)
assert.ErrorIs(t, err, merr.ErrParameterInvalid)
// fieldName invalid
fSchema = &schemapb.FieldSchema{
Name: "",
}
bytes, err = proto.Marshal(fSchema)
assert.NoError(t, err)
task.Schema = bytes
err = task.PreExecute(ctx)
assert.Error(t, err)
assert.ErrorIs(t, err, merr.ErrParameterInvalid)
// duplicated FieldName
fSchema = &schemapb.FieldSchema{
Name: varCharField,
}
bytes, err = proto.Marshal(fSchema)
assert.NoError(t, err)
task.Schema = bytes
err = task.PreExecute(ctx)
assert.Error(t, err)
assert.ErrorIs(t, err, merr.ErrParameterInvalid)
})
}
func TestCreateCollectionTask(t *testing.T) {
rc := NewRootCoordMock()
ctx := context.Background()

View File

@ -38,6 +38,7 @@ import (
"github.com/milvus-io/milvus/internal/json"
"github.com/milvus-io/milvus/internal/parser/planparserv2"
"github.com/milvus-io/milvus/internal/types"
"github.com/milvus-io/milvus/internal/util/ctokenizer"
"github.com/milvus-io/milvus/internal/util/function"
"github.com/milvus-io/milvus/internal/util/hookutil"
"github.com/milvus-io/milvus/internal/util/indexparamcheck"
@ -52,6 +53,7 @@ import (
"github.com/milvus-io/milvus/pkg/v2/util/commonpbutil"
"github.com/milvus-io/milvus/pkg/v2/util/contextutil"
"github.com/milvus-io/milvus/pkg/v2/util/crypto"
"github.com/milvus-io/milvus/pkg/v2/util/funcutil"
"github.com/milvus-io/milvus/pkg/v2/util/merr"
"github.com/milvus-io/milvus/pkg/v2/util/metric"
"github.com/milvus-io/milvus/pkg/v2/util/paramtable"
@ -479,6 +481,48 @@ func ValidateFieldAutoID(coll *schemapb.CollectionSchema) error {
return nil
}
func ValidateField(field *schemapb.FieldSchema, schema *schemapb.CollectionSchema) error {
// validate field name
var err error
if err := validateFieldName(field.Name); err != nil {
return err
}
// validate dense vector field type parameters
isVectorType := typeutil.IsVectorType(field.DataType)
if isVectorType {
err = validateDimension(field)
if err != nil {
return err
}
}
// valid max length per row parameters
// if max_length not specified, return error
if field.DataType == schemapb.DataType_VarChar ||
(field.GetDataType() == schemapb.DataType_Array && field.GetElementType() == schemapb.DataType_VarChar) {
err = validateMaxLengthPerRow(schema.Name, field)
if err != nil {
return err
}
}
// valid max capacity for array per row parameters
// if max_capacity not specified, return error
if field.DataType == schemapb.DataType_Array {
if err = validateMaxCapacityPerRow(schema.Name, field); err != nil {
return err
}
}
// TODO should remove the index params in the field schema
indexParams := funcutil.KeyValuePair2Map(field.GetIndexParams())
if err = ValidateAutoIndexMmapConfig(isVectorType, indexParams); err != nil {
return err
}
if err := ctokenizer.ValidateTextSchema(field, wasBm25FunctionInputField(schema, field)); err != nil {
return err
}
return nil
}
func validatePrimaryKey(coll *schemapb.CollectionSchema) error {
idx := -1
for i, field := range coll.Fields {

View File

@ -27,12 +27,12 @@ import (
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"
"github.com/milvus-io/milvus-proto/go-api/v2/milvuspb"
"github.com/milvus-io/milvus-proto/go-api/v2/schemapb"
"github.com/milvus-io/milvus/internal/querycoordv2/meta"
"github.com/milvus-io/milvus/internal/querycoordv2/observers"
"github.com/milvus-io/milvus/internal/querycoordv2/session"
"github.com/milvus-io/milvus/internal/querycoordv2/utils"
"github.com/milvus-io/milvus/pkg/v2/common"
"github.com/milvus-io/milvus/pkg/v2/eventlog"
"github.com/milvus-io/milvus/pkg/v2/log"
"github.com/milvus-io/milvus/pkg/v2/metrics"
@ -54,6 +54,7 @@ type LoadCollectionJob struct {
targetObserver *observers.TargetObserver
collectionObserver *observers.CollectionObserver
nodeMgr *session.NodeManager
collInfo *milvuspb.DescribeCollectionResponse
}
func NewLoadCollectionJob(
@ -95,6 +96,13 @@ func (job *LoadCollectionJob) PreExecute() error {
req.ResourceGroups = []string{meta.DefaultResourceGroupName}
}
var err error
job.collInfo, err = job.broker.DescribeCollection(job.ctx, req.GetCollectionID())
if err != nil {
log.Warn("failed to describe collection from RootCoord", zap.Error(err))
return err
}
collection := job.meta.GetCollection(job.ctx, req.GetCollectionID())
if collection == nil {
return nil
@ -108,14 +116,16 @@ func (job *LoadCollectionJob) PreExecute() error {
return merr.WrapErrParameterInvalid(collection.GetReplicaNumber(), req.GetReplicaNumber(), "can't change the replica number for loaded collection")
}
// handle legacy proxy load request
if len(req.GetLoadFields()) == 0 {
req.LoadFields = lo.FilterMap(req.GetSchema().GetFields(), func(field *schemapb.FieldSchema, _ int) (int64, bool) {
return field.GetFieldID(), field.GetFieldID() >= common.StartOfUserFieldID
reqFieldIDs := req.GetLoadFields()
if !funcutil.SliceSetEqual(collection.GetLoadFields(), reqFieldIDs) && len(req.GetLoadFields()) == 0 {
// here is a compatible logic: meta is still old, but req was sent in new version
// in older versions, a full load will be saved all field id, in newer version, use empty loaded list as all loaded
reqFieldIDs = lo.Map(job.collInfo.GetSchema().GetFields(), func(field *schemapb.FieldSchema, _ int) int64 {
return field.GetFieldID()
})
}
if !funcutil.SliceSetEqual(collection.GetLoadFields(), req.GetLoadFields()) {
if !funcutil.SliceSetEqual(collection.GetLoadFields(), reqFieldIDs) {
log.Warn("collection with different load field list exists, release this collection first before chaning its load fields",
zap.Int64s("loadedFieldIDs", collection.GetLoadFields()),
zap.Int64s("reqFieldIDs", req.GetLoadFields()),
@ -171,18 +181,12 @@ func (job *LoadCollectionJob) Execute() error {
}
}
collectionInfo, err := job.broker.DescribeCollection(job.ctx, req.GetCollectionID())
if err != nil {
log.Warn("failed to describe collection from RootCoord", zap.Error(err))
return err
}
// 2. create replica if not exist
replicas := job.meta.ReplicaManager.GetByCollection(job.ctx, req.GetCollectionID())
if len(replicas) == 0 {
// API of LoadCollection is wired, we should use map[resourceGroupNames]replicaNumber as input, to keep consistency with `TransferReplica` API.
// Then we can implement dynamic replica changed in different resource group independently.
_, err = utils.SpawnReplicasWithRG(job.ctx, job.meta, req.GetCollectionID(), req.GetResourceGroups(), req.GetReplicaNumber(), collectionInfo.GetVirtualChannelNames())
_, err = utils.SpawnReplicasWithRG(job.ctx, job.meta, req.GetCollectionID(), req.GetResourceGroups(), req.GetReplicaNumber(), job.collInfo.GetVirtualChannelNames())
if err != nil {
msg := "failed to spawn replica for collection"
log.Warn(msg, zap.Error(err))
@ -214,7 +218,7 @@ func (job *LoadCollectionJob) Execute() error {
FieldIndexID: req.GetFieldIndexID(),
LoadType: querypb.LoadType_LoadCollection,
LoadFields: req.GetLoadFields(),
DbID: collectionInfo.GetDbId(),
DbID: job.collInfo.GetDbId(),
},
CreatedAt: time.Now(),
LoadSpan: sp,
@ -261,6 +265,7 @@ type LoadPartitionJob struct {
targetObserver *observers.TargetObserver
collectionObserver *observers.CollectionObserver
nodeMgr *session.NodeManager
collInfo *milvuspb.DescribeCollectionResponse
}
func NewLoadPartitionJob(
@ -302,6 +307,13 @@ func (job *LoadPartitionJob) PreExecute() error {
req.ResourceGroups = []string{meta.DefaultResourceGroupName}
}
var err error
job.collInfo, err = job.broker.DescribeCollection(job.ctx, req.GetCollectionID())
if err != nil {
log.Warn("failed to describe collection from RootCoord", zap.Error(err))
return err
}
collection := job.meta.GetCollection(job.ctx, req.GetCollectionID())
if collection == nil {
return nil
@ -313,14 +325,14 @@ func (job *LoadPartitionJob) PreExecute() error {
return merr.WrapErrParameterInvalid(collection.GetReplicaNumber(), req.GetReplicaNumber(), "can't change the replica number for loaded partitions")
}
// handle legacy proxy load request
if len(req.GetLoadFields()) == 0 {
req.LoadFields = lo.FilterMap(req.GetSchema().GetFields(), func(field *schemapb.FieldSchema, _ int) (int64, bool) {
return field.GetFieldID(), field.GetFieldID() >= common.StartOfUserFieldID
})
reqFieldIDs := req.GetLoadFields()
if !funcutil.SliceSetEqual(collection.GetLoadFields(), reqFieldIDs) && len(req.GetLoadFields()) == 0 {
// here is a compatible logic: meta is still old, but req was sent in new version
// in older versions, a full load will be saved all field id, in newer version, use empty loaded list as all loaded
reqFieldIDs = lo.Map(job.collInfo.GetSchema().GetFields(), func(field *schemapb.FieldSchema, _ int) int64 { return field.GetFieldID() })
}
if !funcutil.SliceSetEqual(collection.GetLoadFields(), req.GetLoadFields()) {
if !funcutil.SliceSetEqual(collection.GetLoadFields(), reqFieldIDs) {
log.Warn("collection with different load field list exists, release this collection first before chaning its load fields",
zap.Int64s("loadedFieldIDs", collection.GetLoadFields()),
zap.Int64s("reqFieldIDs", req.GetLoadFields()),
@ -373,16 +385,10 @@ func (job *LoadPartitionJob) Execute() error {
}
}
collectionInfo, err := job.broker.DescribeCollection(job.ctx, req.GetCollectionID())
if err != nil {
log.Warn("failed to describe collection from RootCoord", zap.Error(err))
return err
}
// 2. create replica if not exist
replicas := job.meta.ReplicaManager.GetByCollection(context.TODO(), req.GetCollectionID())
if len(replicas) == 0 {
_, err = utils.SpawnReplicasWithRG(job.ctx, job.meta, req.GetCollectionID(), req.GetResourceGroups(), req.GetReplicaNumber(), collectionInfo.GetVirtualChannelNames())
_, err = utils.SpawnReplicasWithRG(job.ctx, job.meta, req.GetCollectionID(), req.GetResourceGroups(), req.GetReplicaNumber(), job.collInfo.GetVirtualChannelNames())
if err != nil {
msg := "failed to spawn replica for collection"
log.Warn(msg, zap.Error(err))
@ -416,7 +422,7 @@ func (job *LoadPartitionJob) Execute() error {
FieldIndexID: req.GetFieldIndexID(),
LoadType: querypb.LoadType_LoadPartition,
LoadFields: req.GetLoadFields(),
DbID: collectionInfo.GetDbId(),
DbID: job.collInfo.GetDbId(),
},
CreatedAt: time.Now(),
LoadSpan: sp,

View File

@ -26,6 +26,7 @@ import (
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/suite"
"github.com/milvus-io/milvus-proto/go-api/v2/milvuspb"
"github.com/milvus-io/milvus-proto/go-api/v2/rgpb"
"github.com/milvus-io/milvus-proto/go-api/v2/schemapb"
etcdkv "github.com/milvus-io/milvus/internal/kv/etcd"
@ -136,7 +137,15 @@ func (suite *JobSuite) SetupSuite() {
}
suite.broker.EXPECT().DescribeCollection(mock.Anything, mock.Anything).
Return(nil, nil)
Return(&milvuspb.DescribeCollectionResponse{
Schema: &schemapb.CollectionSchema{
Fields: []*schemapb.FieldSchema{
{FieldID: 100},
{FieldID: 101},
{FieldID: 102},
},
},
}, nil)
suite.broker.EXPECT().ListIndexes(mock.Anything, mock.Anything).
Return(nil, nil).Maybe()

View File

@ -257,7 +257,6 @@ func NewCollection(collectionID int64, schema *schemapb.CollectionSchema, indexM
var loadFieldIDs typeutil.Set[int64]
loadSchema := typeutil.Clone(schema)
// if load fields is specified, do filtering logic
// otherwise use all fields for backward compatibility
if len(loadMetaInfo.GetLoadFields()) > 0 {

View File

@ -0,0 +1,122 @@
// Licensed to the LF AI & Data foundation 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.
package rootcoord
import (
"context"
"go.uber.org/zap"
"google.golang.org/protobuf/proto"
"github.com/milvus-io/milvus-proto/go-api/v2/commonpb"
"github.com/milvus-io/milvus-proto/go-api/v2/milvuspb"
"github.com/milvus-io/milvus-proto/go-api/v2/schemapb"
"github.com/milvus-io/milvus/internal/metastore/model"
"github.com/milvus-io/milvus/internal/util/proxyutil"
"github.com/milvus-io/milvus/pkg/v2/log"
)
type addCollectionFieldTask struct {
baseTask
Req *milvuspb.AddCollectionFieldRequest
fieldSchema *schemapb.FieldSchema
}
func (t *addCollectionFieldTask) Prepare(ctx context.Context) error {
if err := CheckMsgType(t.Req.GetBase().GetMsgType(), commonpb.MsgType_AddCollectionField); err != nil {
return err
}
t.fieldSchema = &schemapb.FieldSchema{}
err := proto.Unmarshal(t.Req.Schema, t.fieldSchema)
if err != nil {
return err
}
if err := checkFieldSchema([]*schemapb.FieldSchema{t.fieldSchema}); err != nil {
return err
}
return nil
}
func (t *addCollectionFieldTask) Execute(ctx context.Context) error {
oldColl, err := t.core.meta.GetCollectionByName(ctx, t.Req.GetDbName(), t.Req.GetCollectionName(), t.ts)
if err != nil {
log.Ctx(ctx).Warn("get collection failed during add field",
zap.String("collectionName", t.Req.GetCollectionName()), zap.Uint64("ts", t.ts))
return err
}
id, err := t.core.idAllocator.AllocOne()
if err != nil {
return err
}
// assign field id
t.fieldSchema.FieldID = id
newField := model.UnmarshalFieldModel(t.fieldSchema)
ts := t.GetTs()
return executeAddCollectionFieldTaskSteps(ctx, t.core, oldColl, newField, t.Req, ts)
}
func (t *addCollectionFieldTask) GetLockerKey() LockerKey {
collection := t.core.getCollectionIDStr(t.ctx, t.Req.GetDbName(), t.Req.GetCollectionName(), 0)
return NewLockerKeyChain(
NewClusterLockerKey(false),
NewDatabaseLockerKey(t.Req.GetDbName(), false),
NewCollectionLockerKey(collection, true),
)
}
func executeAddCollectionFieldTaskSteps(ctx context.Context,
core *Core,
col *model.Collection,
newField *model.Field,
req *milvuspb.AddCollectionFieldRequest,
ts Timestamp,
) error {
oldColl := col.Clone()
redoTask := newBaseRedoTask(core.stepExecutor)
redoTask.AddSyncStep(&AddCollectionFieldStep{
baseStep: baseStep{core: core},
oldColl: oldColl,
newField: newField,
ts: ts,
})
req.CollectionID = oldColl.CollectionID
redoTask.AddSyncStep(&BroadcastAlteredCollectionStep{
baseStep: baseStep{core: core},
req: &milvuspb.AlterCollectionRequest{
DbName: req.GetDbName(),
CollectionName: req.GetCollectionName(),
CollectionID: req.GetCollectionID(),
},
core: core,
})
// field needs to be refreshed in the cache
aliases := core.meta.ListAliasesByID(ctx, oldColl.CollectionID)
redoTask.AddSyncStep(&expireCacheStep{
baseStep: baseStep{core: core},
dbName: req.GetDbName(),
collectionNames: append(aliases, req.GetCollectionName()),
collectionID: oldColl.CollectionID,
opts: []proxyutil.ExpireCacheOpt{proxyutil.SetMsgType(commonpb.MsgType_AddCollectionField)},
})
return redoTask.Execute(ctx)
}

View File

@ -0,0 +1,279 @@
// Licensed to the LF AI & Data foundation 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.
package rootcoord
import (
"context"
"testing"
"github.com/cockroachdb/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"google.golang.org/protobuf/proto"
"github.com/milvus-io/milvus-proto/go-api/v2/commonpb"
"github.com/milvus-io/milvus-proto/go-api/v2/milvuspb"
"github.com/milvus-io/milvus-proto/go-api/v2/schemapb"
"github.com/milvus-io/milvus/internal/metastore/model"
mockrootcoord "github.com/milvus-io/milvus/internal/rootcoord/mocks"
"github.com/milvus-io/milvus/pkg/v2/util/merr"
)
func Test_AddCollectionFieldTask_Prepare(t *testing.T) {
t.Run("invalid msg type", func(t *testing.T) {
task := &addCollectionFieldTask{Req: &milvuspb.AddCollectionFieldRequest{Base: &commonpb.MsgBase{MsgType: commonpb.MsgType_DropCollection}}}
err := task.Prepare(context.Background())
assert.Error(t, err)
})
t.Run("check field failed", func(t *testing.T) {
fieldSchema := &schemapb.FieldSchema{
DataType: schemapb.DataType_Int64,
DefaultValue: &schemapb.ValueField{
Data: &schemapb.ValueField_BoolData{
BoolData: false,
},
},
}
bytes, err := proto.Marshal(fieldSchema)
assert.NoError(t, err)
task := &addCollectionFieldTask{Req: &milvuspb.AddCollectionFieldRequest{Base: &commonpb.MsgBase{MsgType: commonpb.MsgType_AddCollectionField}, Schema: bytes}}
err = task.Prepare(context.Background())
assert.Error(t, err)
})
t.Run("normal case", func(t *testing.T) {
fieldSchema := &schemapb.FieldSchema{
DataType: schemapb.DataType_Bool,
DefaultValue: &schemapb.ValueField{
Data: &schemapb.ValueField_BoolData{
BoolData: false,
},
},
}
bytes, err := proto.Marshal(fieldSchema)
assert.NoError(t, err)
task := &addCollectionFieldTask{Req: &milvuspb.AddCollectionFieldRequest{Base: &commonpb.MsgBase{MsgType: commonpb.MsgType_AddCollectionField}, Schema: bytes}}
err = task.Prepare(context.Background())
assert.NoError(t, err)
})
}
func Test_AddCollectionFieldTask_Execute(t *testing.T) {
t.Run("failed to get collection", func(t *testing.T) {
metaTable := mockrootcoord.NewIMetaTable(t)
metaTable.EXPECT().GetCollectionByName(mock.Anything, mock.Anything, "not_existed_coll", mock.Anything).Return(nil, merr.WrapErrCollectionNotFound("not_existed_coll"))
core := newTestCore(withMeta(metaTable))
task := &addCollectionFieldTask{
baseTask: newBaseTask(context.Background(), core),
Req: &milvuspb.AddCollectionFieldRequest{
Base: &commonpb.MsgBase{MsgType: commonpb.MsgType_AlterAlias},
CollectionName: "not_existed_coll",
},
}
err := task.Execute(context.Background())
assert.Error(t, err)
})
t.Run("add field step failed", func(t *testing.T) {
meta := mockrootcoord.NewIMetaTable(t)
meta.On("GetCollectionByName",
mock.Anything,
mock.Anything,
mock.Anything,
mock.Anything,
).Return(&model.Collection{CollectionID: int64(1), Fields: []*model.Field{
{
Name: "pk",
IsPrimaryKey: true,
DataType: schemapb.DataType_Int64,
},
{
Name: "vec",
DataType: schemapb.DataType_FloatVector,
},
}}, nil)
meta.On("AlterCollection",
mock.Anything,
mock.Anything,
mock.Anything,
mock.Anything,
).Return(errors.New("mock"))
meta.On("ListAliasesByID", mock.Anything, mock.Anything).Return([]string{})
alloc := newMockIDAllocator()
core := newTestCore(withValidProxyManager(), withMeta(meta), withIDAllocator(alloc))
task := &addCollectionFieldTask{
baseTask: newBaseTask(context.Background(), core),
Req: &milvuspb.AddCollectionFieldRequest{
Base: &commonpb.MsgBase{MsgType: commonpb.MsgType_AlterAlias},
CollectionName: "coll",
},
fieldSchema: &schemapb.FieldSchema{
Name: "fid",
DataType: schemapb.DataType_Bool,
Nullable: true,
},
}
err := task.Execute(context.Background())
assert.Error(t, err)
})
t.Run("broadcast add field step failed", func(t *testing.T) {
meta := mockrootcoord.NewIMetaTable(t)
meta.On("GetCollectionByName",
mock.Anything,
mock.Anything,
mock.Anything,
mock.Anything,
).Return(&model.Collection{CollectionID: int64(1), Fields: []*model.Field{
{
Name: "pk",
IsPrimaryKey: true,
DataType: schemapb.DataType_Int64,
},
{
Name: "vec",
DataType: schemapb.DataType_FloatVector,
},
}}, nil)
meta.On("AlterCollection",
mock.Anything,
mock.Anything,
mock.Anything,
mock.Anything,
).Return(nil)
meta.On("ListAliasesByID", mock.Anything, mock.Anything).Return([]string{})
broker := newMockBroker()
broker.BroadcastAlteredCollectionFunc = func(ctx context.Context, req *milvuspb.AlterCollectionRequest) error {
return errors.New("mock")
}
alloc := newMockIDAllocator()
core := newTestCore(withValidProxyManager(), withMeta(meta), withBroker(broker), withIDAllocator(alloc))
task := &addCollectionFieldTask{
baseTask: newBaseTask(context.Background(), core),
Req: &milvuspb.AddCollectionFieldRequest{
Base: &commonpb.MsgBase{MsgType: commonpb.MsgType_AlterAlias},
CollectionName: "coll",
},
fieldSchema: &schemapb.FieldSchema{
Name: "fid",
DataType: schemapb.DataType_Bool,
Nullable: true,
},
}
err := task.Execute(context.Background())
assert.Error(t, err)
})
t.Run("expire cache failed", func(t *testing.T) {
meta := mockrootcoord.NewIMetaTable(t)
meta.On("GetCollectionByName",
mock.Anything,
mock.Anything,
mock.Anything,
mock.Anything,
).Return(&model.Collection{CollectionID: int64(1), Fields: []*model.Field{
{
Name: "pk",
IsPrimaryKey: true,
DataType: schemapb.DataType_Int64,
},
{
Name: "vec",
DataType: schemapb.DataType_FloatVector,
},
}}, nil)
meta.On("AlterCollection",
mock.Anything,
mock.Anything,
mock.Anything,
mock.Anything,
).Return(nil)
meta.On("ListAliasesByID", mock.Anything, mock.Anything).Return([]string{})
broker := newMockBroker()
broker.BroadcastAlteredCollectionFunc = func(ctx context.Context, req *milvuspb.AlterCollectionRequest) error {
return nil
}
alloc := newMockIDAllocator()
core := newTestCore(withInvalidProxyManager(), withMeta(meta), withBroker(broker), withIDAllocator(alloc))
task := &addCollectionFieldTask{
baseTask: newBaseTask(context.Background(), core),
Req: &milvuspb.AddCollectionFieldRequest{
Base: &commonpb.MsgBase{MsgType: commonpb.MsgType_AlterAlias},
CollectionName: "coll",
},
fieldSchema: &schemapb.FieldSchema{
Name: "fid",
DataType: schemapb.DataType_Bool,
Nullable: true,
},
}
err := task.Execute(context.Background())
assert.Error(t, err)
})
t.Run("normal case", func(t *testing.T) {
meta := mockrootcoord.NewIMetaTable(t)
meta.On("GetCollectionByName",
mock.Anything,
mock.Anything,
mock.Anything,
mock.Anything,
).Return(&model.Collection{CollectionID: int64(1), Fields: []*model.Field{
{
Name: "pk",
IsPrimaryKey: true,
DataType: schemapb.DataType_Int64,
},
{
Name: "vec",
DataType: schemapb.DataType_FloatVector,
},
}}, nil)
meta.On("AlterCollection",
mock.Anything,
mock.Anything,
mock.Anything,
mock.Anything,
).Return(nil)
meta.On("ListAliasesByID", mock.Anything, mock.Anything).Return([]string{})
broker := newMockBroker()
broker.BroadcastAlteredCollectionFunc = func(ctx context.Context, req *milvuspb.AlterCollectionRequest) error {
return nil
}
alloc := newMockIDAllocator()
core := newTestCore(withValidProxyManager(), withMeta(meta), withBroker(broker), withIDAllocator(alloc))
task := &addCollectionFieldTask{
baseTask: newBaseTask(context.Background(), core),
Req: &milvuspb.AddCollectionFieldRequest{
Base: &commonpb.MsgBase{MsgType: commonpb.MsgType_AlterAlias},
CollectionName: "coll",
},
fieldSchema: &schemapb.FieldSchema{
Name: "fid",
DataType: schemapb.DataType_Bool,
Nullable: true,
},
}
err := task.Execute(context.Background())
assert.NoError(t, err)
})
}

View File

@ -271,7 +271,7 @@ func (b *ServerBroker) BroadcastAlteredCollection(ctx context.Context, req *milv
if resp.ErrorCode != commonpb.ErrorCode_Success {
return errors.New(resp.Reason)
}
log.Ctx(ctx).Info("done to broadcast request to alter collection", zap.String("collectionName", req.GetCollectionName()), zap.Int64("collectionID", req.GetCollectionID()), zap.Any("props", req.GetProperties()))
log.Ctx(ctx).Info("done to broadcast request to alter collection", zap.String("collectionName", req.GetCollectionName()), zap.Int64("collectionID", req.GetCollectionID()), zap.Any("props", req.GetProperties()), zap.Any("field", colMeta.Fields))
return nil
}

View File

@ -19,7 +19,6 @@ package rootcoord
import (
"context"
"fmt"
"math"
"strconv"
"github.com/cockroachdb/errors"
@ -43,7 +42,6 @@ import (
"github.com/milvus-io/milvus/pkg/v2/util/commonpbutil"
"github.com/milvus-io/milvus/pkg/v2/util/funcutil"
"github.com/milvus-io/milvus/pkg/v2/util/merr"
"github.com/milvus-io/milvus/pkg/v2/util/parameterutil"
"github.com/milvus-io/milvus/pkg/v2/util/typeutil"
)
@ -148,101 +146,6 @@ func (t *createCollectionTask) checkMaxCollectionsPerDB(ctx context.Context, db2
return check(maxColNumPerDB)
}
func checkFieldSchema(schema *schemapb.CollectionSchema) error {
for _, fieldSchema := range schema.Fields {
if fieldSchema.GetNullable() && typeutil.IsVectorType(fieldSchema.GetDataType()) {
msg := fmt.Sprintf("vector type not support null, type:%s, name:%s", fieldSchema.GetDataType().String(), fieldSchema.GetName())
return merr.WrapErrParameterInvalidMsg(msg)
}
if fieldSchema.GetNullable() && fieldSchema.IsPrimaryKey {
msg := fmt.Sprintf("primary field not support null, type:%s, name:%s", fieldSchema.GetDataType().String(), fieldSchema.GetName())
return merr.WrapErrParameterInvalidMsg(msg)
}
if fieldSchema.GetDefaultValue() != nil {
if fieldSchema.IsPrimaryKey {
msg := fmt.Sprintf("primary field not support default_value, type:%s, name:%s", fieldSchema.GetDataType().String(), fieldSchema.GetName())
return merr.WrapErrParameterInvalidMsg(msg)
}
dtype := fieldSchema.GetDataType()
if dtype == schemapb.DataType_Array || dtype == schemapb.DataType_JSON || typeutil.IsVectorType(dtype) {
msg := fmt.Sprintf("type not support default_value, type:%s, name:%s", fieldSchema.GetDataType().String(), fieldSchema.GetName())
return merr.WrapErrParameterInvalidMsg(msg)
}
errTypeMismatch := func(fieldName, fieldType, defaultValueType string) error {
msg := fmt.Sprintf("type (%s) of field (%s) is not equal to the type(%s) of default_value", fieldType, fieldName, defaultValueType)
return merr.WrapErrParameterInvalidMsg(msg)
}
switch fieldSchema.GetDefaultValue().Data.(type) {
case *schemapb.ValueField_BoolData:
if dtype != schemapb.DataType_Bool {
return errTypeMismatch(fieldSchema.GetName(), dtype.String(), "DataType_Bool")
}
case *schemapb.ValueField_IntData:
if dtype != schemapb.DataType_Int32 && dtype != schemapb.DataType_Int16 && dtype != schemapb.DataType_Int8 {
return errTypeMismatch(fieldSchema.GetName(), dtype.String(), "DataType_Int")
}
defaultValue := fieldSchema.GetDefaultValue().GetIntData()
if dtype == schemapb.DataType_Int16 {
if defaultValue > math.MaxInt16 || defaultValue < math.MinInt16 {
return merr.WrapErrParameterInvalidRange(math.MinInt16, math.MaxInt16, defaultValue, "default value out of range")
}
}
if dtype == schemapb.DataType_Int8 {
if defaultValue > math.MaxInt8 || defaultValue < math.MinInt8 {
return merr.WrapErrParameterInvalidRange(math.MinInt8, math.MaxInt8, defaultValue, "default value out of range")
}
}
case *schemapb.ValueField_LongData:
if dtype != schemapb.DataType_Int64 {
return errTypeMismatch(fieldSchema.GetName(), dtype.String(), "DataType_Int64")
}
case *schemapb.ValueField_FloatData:
if dtype != schemapb.DataType_Float {
return errTypeMismatch(fieldSchema.GetName(), dtype.String(), "DataType_Float")
}
case *schemapb.ValueField_DoubleData:
if dtype != schemapb.DataType_Double {
return errTypeMismatch(fieldSchema.GetName(), dtype.String(), "DataType_Double")
}
case *schemapb.ValueField_StringData:
if dtype != schemapb.DataType_VarChar {
return errTypeMismatch(fieldSchema.GetName(), dtype.String(), "DataType_VarChar")
}
maxLength, err := parameterutil.GetMaxLength(fieldSchema)
if err != nil {
return err
}
defaultValueLength := len(fieldSchema.GetDefaultValue().GetStringData())
if int64(defaultValueLength) > maxLength {
msg := fmt.Sprintf("the length (%d) of string exceeds max length (%d)", defaultValueLength, maxLength)
return merr.WrapErrParameterInvalid("valid length string", "string length exceeds max length", msg)
}
default:
panic("default value unsupport data type")
}
}
if err := checkDupKvPairs(fieldSchema.GetTypeParams(), "type"); err != nil {
return err
}
if err := checkDupKvPairs(fieldSchema.GetIndexParams(), "index"); err != nil {
return err
}
}
return nil
}
func checkDupKvPairs(params []*commonpb.KeyValuePair, paramType string) error {
set := typeutil.NewSet[string]()
for _, kv := range params {
if set.Contain(kv.GetKey()) {
return merr.WrapErrParameterInvalidMsg("duplicated %s param key \"%s\"", paramType, kv.GetKey())
}
set.Insert(kv.GetKey())
}
return nil
}
func hasSystemFields(schema *schemapb.CollectionSchema, systemFields []string) bool {
for _, f := range schema.GetFields() {
if funcutil.SliceContain(systemFields, f.GetName()) {
@ -252,15 +155,6 @@ func hasSystemFields(schema *schemapb.CollectionSchema, systemFields []string) b
return false
}
func validateFieldDataType(schema *schemapb.CollectionSchema) error {
for _, field := range schema.GetFields() {
if _, ok := schemapb.DataType_name[int32(field.GetDataType())]; !ok || field.GetDataType() == schemapb.DataType_None {
return merr.WrapErrParameterInvalid("valid field", fmt.Sprintf("field data type: %s is not supported", field.GetDataType()))
}
}
return nil
}
func (t *createCollectionTask) validateSchema(ctx context.Context, schema *schemapb.CollectionSchema) error {
log.Ctx(ctx).With(zap.String("CollectionName", t.Req.CollectionName))
if t.Req.GetCollectionName() != schema.GetName() {
@ -269,7 +163,7 @@ func (t *createCollectionTask) validateSchema(ctx context.Context, schema *schem
return merr.WrapErrParameterInvalid("collection name matches schema name", "don't match", msg)
}
if err := checkFieldSchema(schema); err != nil {
if err := checkFieldSchema(schema.GetFields()); err != nil {
return err
}
@ -281,7 +175,7 @@ func (t *createCollectionTask) validateSchema(ctx context.Context, schema *schem
msg := fmt.Sprintf("schema contains system field: %s, %s, %s", RowIDFieldName, TimeStampFieldName, MetaFieldName)
return merr.WrapErrParameterInvalid("schema don't contains system field", "contains", msg)
}
return validateFieldDataType(schema)
return validateFieldDataType(schema.GetFields())
}
func (t *createCollectionTask) assignFieldAndFunctionID(schema *schemapb.CollectionSchema) error {

View File

@ -1079,6 +1079,57 @@ func (c *Core) CreateCollection(ctx context.Context, in *milvuspb.CreateCollecti
return merr.Success(), nil
}
// AddCollectionField add field
func (c *Core) AddCollectionField(ctx context.Context, in *milvuspb.AddCollectionFieldRequest) (*commonpb.Status, error) {
if err := merr.CheckHealthy(c.GetStateCode()); err != nil {
return merr.Status(err), nil
}
metrics.RootCoordDDLReqCounter.WithLabelValues("AddCollectionField", metrics.TotalLabel).Inc()
tr := timerecord.NewTimeRecorder("AddCollectionField")
log.Ctx(ctx).Info("received request to add field",
zap.String("dbName", in.GetDbName()),
zap.String("name", in.GetCollectionName()),
zap.String("role", typeutil.RootCoordRole))
t := &addCollectionFieldTask{
baseTask: newBaseTask(ctx, c),
Req: in,
}
if err := c.scheduler.AddTask(t); err != nil {
log.Ctx(ctx).Info("failed to enqueue request to add field",
zap.String("role", typeutil.RootCoordRole),
zap.Error(err),
zap.String("name", in.GetCollectionName()))
metrics.RootCoordDDLReqCounter.WithLabelValues("AddCollectionField", metrics.FailLabel).Inc()
return merr.Status(err), nil
}
if err := t.WaitToFinish(); err != nil {
log.Ctx(ctx).Info("failed to add field",
zap.String("role", typeutil.RootCoordRole),
zap.Error(err),
zap.String("name", in.GetCollectionName()),
zap.Uint64("ts", t.GetTs()))
metrics.RootCoordDDLReqCounter.WithLabelValues("AddCollectionField", metrics.FailLabel).Inc()
return merr.Status(err), nil
}
metrics.RootCoordDDLReqCounter.WithLabelValues("AddCollectionField", metrics.SuccessLabel).Inc()
metrics.RootCoordDDLReqLatency.WithLabelValues("AddCollectionField").Observe(float64(tr.ElapseSpan().Milliseconds()))
metrics.RootCoordDDLReqLatencyInQueue.WithLabelValues("AddCollectionField").Observe(float64(t.queueDur.Milliseconds()))
log.Ctx(ctx).Info("done to add field",
zap.String("role", typeutil.RootCoordRole),
zap.String("name", in.GetCollectionName()),
zap.Uint64("ts", t.GetTs()))
return merr.Success(), nil
}
// DropCollection drop collection
func (c *Core) DropCollection(ctx context.Context, in *milvuspb.DropCollectionRequest) (*commonpb.Status, error) {
if err := merr.CheckHealthy(c.GetStateCode()); err != nil {

View File

@ -495,6 +495,25 @@ func (b *BroadcastAlteredCollectionStep) Desc() string {
return fmt.Sprintf("broadcast altered collection, collectionID: %d", b.req.CollectionID)
}
type AddCollectionFieldStep struct {
baseStep
oldColl *model.Collection
newField *model.Field
ts Timestamp
}
func (a *AddCollectionFieldStep) Execute(ctx context.Context) ([]nestedStep, error) {
newColl := a.oldColl.Clone()
newColl.Fields = append(newColl.Fields, a.newField)
err := a.core.meta.AlterCollection(ctx, a.oldColl, newColl, a.ts)
log.Ctx(ctx).Info("add field done", zap.Int64("collectionID", a.oldColl.CollectionID), zap.Any("new field", a.newField))
return nil, err
}
func (a *AddCollectionFieldStep) Desc() string {
return fmt.Sprintf("add field, collectionID: %d, fieldID: %d, ts: %d", a.oldColl.CollectionID, a.newField.FieldID, a.ts)
}
type AlterDatabaseStep struct {
baseStep
oldDB *model.Database

View File

@ -19,6 +19,7 @@ package rootcoord
import (
"context"
"fmt"
"math"
"strconv"
"time"
@ -26,6 +27,7 @@ import (
"golang.org/x/sync/errgroup"
"github.com/milvus-io/milvus-proto/go-api/v2/commonpb"
"github.com/milvus-io/milvus-proto/go-api/v2/schemapb"
"github.com/milvus-io/milvus/internal/json"
"github.com/milvus-io/milvus/internal/types"
"github.com/milvus-io/milvus/internal/util/proxyutil"
@ -34,6 +36,7 @@ import (
"github.com/milvus-io/milvus/pkg/v2/mq/msgstream"
"github.com/milvus-io/milvus/pkg/v2/util/merr"
"github.com/milvus-io/milvus/pkg/v2/util/metricsinfo"
"github.com/milvus-io/milvus/pkg/v2/util/parameterutil"
"github.com/milvus-io/milvus/pkg/v2/util/tsoutil"
"github.com/milvus-io/milvus/pkg/v2/util/typeutil"
)
@ -378,3 +381,107 @@ func CheckTimeTickLagExceeded(ctx context.Context, queryCoord types.QueryCoordCl
return nil
}
func checkFieldSchema(fieldSchemas []*schemapb.FieldSchema) error {
for _, fieldSchema := range fieldSchemas {
if fieldSchema.GetNullable() && typeutil.IsVectorType(fieldSchema.GetDataType()) {
msg := fmt.Sprintf("vector type not support null, type:%s, name:%s", fieldSchema.GetDataType().String(), fieldSchema.GetName())
return merr.WrapErrParameterInvalidMsg(msg)
}
if fieldSchema.GetNullable() && fieldSchema.IsPrimaryKey {
msg := fmt.Sprintf("primary field not support null, type:%s, name:%s", fieldSchema.GetDataType().String(), fieldSchema.GetName())
return merr.WrapErrParameterInvalidMsg(msg)
}
if fieldSchema.GetDefaultValue() != nil {
if fieldSchema.IsPrimaryKey {
msg := fmt.Sprintf("primary field not support default_value, type:%s, name:%s", fieldSchema.GetDataType().String(), fieldSchema.GetName())
return merr.WrapErrParameterInvalidMsg(msg)
}
dtype := fieldSchema.GetDataType()
if dtype == schemapb.DataType_Array || dtype == schemapb.DataType_JSON || typeutil.IsVectorType(dtype) {
msg := fmt.Sprintf("type not support default_value, type:%s, name:%s", fieldSchema.GetDataType().String(), fieldSchema.GetName())
return merr.WrapErrParameterInvalidMsg(msg)
}
errTypeMismatch := func(fieldName, fieldType, defaultValueType string) error {
msg := fmt.Sprintf("type (%s) of field (%s) is not equal to the type(%s) of default_value", fieldType, fieldName, defaultValueType)
return merr.WrapErrParameterInvalidMsg(msg)
}
switch fieldSchema.GetDefaultValue().Data.(type) {
case *schemapb.ValueField_BoolData:
if dtype != schemapb.DataType_Bool {
return errTypeMismatch(fieldSchema.GetName(), dtype.String(), "DataType_Bool")
}
case *schemapb.ValueField_IntData:
if dtype != schemapb.DataType_Int32 && dtype != schemapb.DataType_Int16 && dtype != schemapb.DataType_Int8 {
return errTypeMismatch(fieldSchema.GetName(), dtype.String(), "DataType_Int")
}
defaultValue := fieldSchema.GetDefaultValue().GetIntData()
if dtype == schemapb.DataType_Int16 {
if defaultValue > math.MaxInt16 || defaultValue < math.MinInt16 {
return merr.WrapErrParameterInvalidRange(math.MinInt16, math.MaxInt16, defaultValue, "default value out of range")
}
}
if dtype == schemapb.DataType_Int8 {
if defaultValue > math.MaxInt8 || defaultValue < math.MinInt8 {
return merr.WrapErrParameterInvalidRange(math.MinInt8, math.MaxInt8, defaultValue, "default value out of range")
}
}
case *schemapb.ValueField_LongData:
if dtype != schemapb.DataType_Int64 {
return errTypeMismatch(fieldSchema.GetName(), dtype.String(), "DataType_Int64")
}
case *schemapb.ValueField_FloatData:
if dtype != schemapb.DataType_Float {
return errTypeMismatch(fieldSchema.GetName(), dtype.String(), "DataType_Float")
}
case *schemapb.ValueField_DoubleData:
if dtype != schemapb.DataType_Double {
return errTypeMismatch(fieldSchema.GetName(), dtype.String(), "DataType_Double")
}
case *schemapb.ValueField_StringData:
if dtype != schemapb.DataType_VarChar {
return errTypeMismatch(fieldSchema.GetName(), dtype.String(), "DataType_VarChar")
}
maxLength, err := parameterutil.GetMaxLength(fieldSchema)
if err != nil {
return err
}
defaultValueLength := len(fieldSchema.GetDefaultValue().GetStringData())
if int64(defaultValueLength) > maxLength {
msg := fmt.Sprintf("the length (%d) of string exceeds max length (%d)", defaultValueLength, maxLength)
return merr.WrapErrParameterInvalid("valid length string", "string length exceeds max length", msg)
}
default:
panic("default value unsupport data type")
}
}
if err := checkDupKvPairs(fieldSchema.GetTypeParams(), "type"); err != nil {
return err
}
if err := checkDupKvPairs(fieldSchema.GetIndexParams(), "index"); err != nil {
return err
}
}
return nil
}
func checkDupKvPairs(params []*commonpb.KeyValuePair, paramType string) error {
set := typeutil.NewSet[string]()
for _, kv := range params {
if set.Contain(kv.GetKey()) {
return merr.WrapErrParameterInvalidMsg("duplicated %s param key \"%s\"", paramType, kv.GetKey())
}
set.Insert(kv.GetKey())
}
return nil
}
func validateFieldDataType(fieldSchemas []*schemapb.FieldSchema) error {
for _, field := range fieldSchemas {
if _, ok := schemapb.DataType_name[int32(field.GetDataType())]; !ok || field.GetDataType() == schemapb.DataType_None {
return merr.WrapErrParameterInvalid("valid field", fmt.Sprintf("field data type: %s is not supported", field.GetDataType()))
}
}
return nil
}

View File

@ -98,7 +98,13 @@ func Sort(schema *schemapb.CollectionSchema, rr []RecordReader,
batchSize := 100000
builders := make([]array.Builder, len(schema.Fields))
for i, f := range schema.Fields {
b := array.NewBuilder(memory.DefaultAllocator, records[0].Column(f.FieldID).DataType())
// will change later, to do
var b array.Builder
if records[0].Column(f.FieldID) == nil {
b = array.NewBuilder(memory.DefaultAllocator, MilvusDataTypeToArrowType(f.GetDataType(), 1))
} else {
b = array.NewBuilder(memory.DefaultAllocator, records[0].Column(f.FieldID).DataType())
}
b.Reserve(batchSize)
builders[i] = b
}

View File

@ -89,6 +89,10 @@ func (m *GrpcRootCoordClient) SelectGrant(ctx context.Context, in *milvuspb.Sele
return &milvuspb.SelectGrantResponse{}, m.Err
}
func (m *GrpcRootCoordClient) AddCollectionField(ctx context.Context, in *milvuspb.AddCollectionFieldRequest, opts ...grpc.CallOption) (*commonpb.Status, error) {
return &commonpb.Status{}, m.Err
}
func (m *GrpcRootCoordClient) ListPolicy(ctx context.Context, in *internalpb.ListPolicyRequest, opts ...grpc.CallOption) (*internalpb.ListPolicyResponse, error) {
return &internalpb.ListPolicyResponse{}, m.Err
}

View File

@ -59,7 +59,6 @@ func (req *LoadFieldDataRequest) getCLoadFieldDataRequest() (result *cLoadFieldD
for _, field := range req.Fields {
cFieldID := C.int64_t(field.Field.GetFieldID())
status = C.AppendLoadFieldInfo(cLoadFieldDataInfo, cFieldID, rowCount)
if err := ConsumeCStatusIntoError(&status); err != nil {
return nil, errors.Wrapf(err, "AppendLoadFieldInfo failed at fieldID, %d", field.Field.GetFieldID())
@ -77,6 +76,7 @@ func (req *LoadFieldDataRequest) getCLoadFieldDataRequest() (result *cLoadFieldD
C.EnableMmap(cLoadFieldDataInfo, cFieldID, C.bool(field.EnableMMap))
}
if len(req.MMapDir) > 0 {
mmapDir := C.CString(req.MMapDir)
defer C.free(unsafe.Pointer(mmapDir))

View File

@ -79,6 +79,8 @@ const (
// InvalidNodeID indicates that node is not valid in querycoord replica or shard cluster.
InvalidNodeID = int64(-1)
SystemFieldsNum = int64(2)
)
const (
@ -383,7 +385,7 @@ func CollectionLevelResourceGroups(kvs []*commonpb.KeyValuePair) ([]string, erro
// GetCollectionLoadFields returns the load field ids according to the type params.
func GetCollectionLoadFields(schema *schemapb.CollectionSchema, skipDynamicField bool) []int64 {
return lo.FilterMap(schema.GetFields(), func(field *schemapb.FieldSchema, _ int) (int64, bool) {
fields := lo.FilterMap(schema.GetFields(), func(field *schemapb.FieldSchema, _ int) (int64, bool) {
// skip system field
if IsSystemField(field.GetFieldID()) {
return field.GetFieldID(), false
@ -401,6 +403,11 @@ func GetCollectionLoadFields(schema *schemapb.CollectionSchema, skipDynamicField
}
return field.GetFieldID(), v
})
// empty fields list means all fields will be loaded
if len(fields) == len(schema.GetFields())-int(SystemFieldsNum) {
return []int64{}
}
return fields
}
func ShouldFieldBeLoaded(kvs []*commonpb.KeyValuePair) (bool, error) {

View File

@ -755,6 +755,17 @@ message AlterCollectionRequest {
repeated string vChannels = 7;
}
message AddCollectionFieldRequest {
int64 collectionID = 1;
int64 dbID = 2;
schema.FieldSchema field_schema = 3;
schema.CollectionSchema schema = 4;
repeated int64 partitionIDs = 5;
repeated common.KeyDataPair start_positions = 6;
repeated common.KeyValuePair properties = 7;
repeated string vChannels = 8;
}
message GcConfirmRequest {
int64 collection_id = 1;
int64 partition_id = 2; // -1 means whole collection.

File diff suppressed because it is too large Load Diff

View File

@ -82,6 +82,7 @@ message BuildIndexInfo {
repeated OptionalFieldInfo opt_fields = 19;
bool partition_key_isolation = 20;
int32 current_scalar_index_version = 21;
int64 lack_binlog_rows = 22;
}
message LoadTextIndexInfo {

View File

@ -572,6 +572,7 @@ type BuildIndexInfo struct {
OptFields []*OptionalFieldInfo `protobuf:"bytes,19,rep,name=opt_fields,json=optFields,proto3" json:"opt_fields,omitempty"`
PartitionKeyIsolation bool `protobuf:"varint,20,opt,name=partition_key_isolation,json=partitionKeyIsolation,proto3" json:"partition_key_isolation,omitempty"`
CurrentScalarIndexVersion int32 `protobuf:"varint,21,opt,name=current_scalar_index_version,json=currentScalarIndexVersion,proto3" json:"current_scalar_index_version,omitempty"`
LackBinlogRows int64 `protobuf:"varint,22,opt,name=lack_binlog_rows,json=lackBinlogRows,proto3" json:"lack_binlog_rows,omitempty"`
}
func (x *BuildIndexInfo) Reset() {
@ -753,6 +754,13 @@ func (x *BuildIndexInfo) GetCurrentScalarIndexVersion() int32 {
return 0
}
func (x *BuildIndexInfo) GetLackBinlogRows() int64 {
if x != nil {
return x.LackBinlogRows
}
return 0
}
type LoadTextIndexInfo struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@ -927,7 +935,7 @@ var file_index_cgo_msg_proto_rawDesc = []byte{
0x65, 0x6c, 0x64, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09,
0x66, 0x69, 0x65, 0x6c, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x61, 0x74,
0x61, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x64,
0x61, 0x74, 0x61, 0x50, 0x61, 0x74, 0x68, 0x73, 0x22, 0xcd, 0x07, 0x0a, 0x0e, 0x42, 0x75, 0x69,
0x61, 0x74, 0x61, 0x50, 0x61, 0x74, 0x68, 0x73, 0x22, 0xf7, 0x07, 0x0a, 0x0e, 0x42, 0x75, 0x69,
0x6c, 0x64, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x0a, 0x09, 0x63,
0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09,
0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x75, 0x69,
@ -988,27 +996,29 @@ var file_index_cgo_msg_proto_rawDesc = []byte{
0x6e, 0x74, 0x5f, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f,
0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x15, 0x20, 0x01, 0x28, 0x05, 0x52, 0x19, 0x63,
0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x49, 0x6e, 0x64, 0x65,
0x78, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xf7, 0x01, 0x0a, 0x11, 0x4c, 0x6f, 0x61,
0x64, 0x54, 0x65, 0x78, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x18,
0x0a, 0x07, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52,
0x07, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73,
0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69,
0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x44, 0x18, 0x03, 0x20,
0x01, 0x28, 0x03, 0x52, 0x07, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05,
0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x66, 0x69, 0x6c,
0x65, 0x73, 0x12, 0x38, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x05, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x63,
0x68, 0x65, 0x6d, 0x61, 0x52, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x22, 0x0a, 0x0c,
0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x06, 0x20, 0x01,
0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44,
0x12, 0x20, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18,
0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e,
0x49, 0x44, 0x42, 0x35, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2d, 0x69, 0x6f, 0x2f, 0x6d, 0x69, 0x6c, 0x76, 0x75,
0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x69,
0x6e, 0x64, 0x65, 0x78, 0x63, 0x67, 0x6f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
0x78, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x10, 0x6c, 0x61, 0x63, 0x6b,
0x5f, 0x62, 0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x5f, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x16, 0x20, 0x01,
0x28, 0x03, 0x52, 0x0e, 0x6c, 0x61, 0x63, 0x6b, 0x42, 0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x52, 0x6f,
0x77, 0x73, 0x22, 0xf7, 0x01, 0x0a, 0x11, 0x4c, 0x6f, 0x61, 0x64, 0x54, 0x65, 0x78, 0x74, 0x49,
0x6e, 0x64, 0x65, 0x78, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x18, 0x0a, 0x07, 0x46, 0x69, 0x65, 0x6c,
0x64, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x46, 0x69, 0x65, 0x6c, 0x64,
0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20,
0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07,
0x62, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x62,
0x75, 0x69, 0x6c, 0x64, 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18,
0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x38, 0x0a, 0x06,
0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6d,
0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x63, 0x68, 0x65,
0x6d, 0x61, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x06,
0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f,
0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x61,
0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52,
0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x42, 0x35, 0x5a, 0x33,
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x69, 0x6c, 0x76, 0x75,
0x73, 0x2d, 0x69, 0x6f, 0x2f, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f,
0x76, 0x32, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x63, 0x67,
0x6f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (

View File

@ -31,6 +31,15 @@ service RootCoord {
*/
rpc DropCollection(milvus.DropCollectionRequest) returns (common.Status) {}
/**
* @brief This method is used to add collection field.
*
* @param AddCollectionFieldRequest, field schema is going to be added.
*
* @return Status
*/
rpc AddCollectionField(milvus.AddCollectionFieldRequest) returns (common.Status) {}
/**
* @brief This method is used to test collection existence.
*

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,7 @@ const (
RootCoord_GetStatisticsChannel_FullMethodName = "/milvus.proto.rootcoord.RootCoord/GetStatisticsChannel"
RootCoord_CreateCollection_FullMethodName = "/milvus.proto.rootcoord.RootCoord/CreateCollection"
RootCoord_DropCollection_FullMethodName = "/milvus.proto.rootcoord.RootCoord/DropCollection"
RootCoord_AddCollectionField_FullMethodName = "/milvus.proto.rootcoord.RootCoord/AddCollectionField"
RootCoord_HasCollection_FullMethodName = "/milvus.proto.rootcoord.RootCoord/HasCollection"
RootCoord_DescribeCollection_FullMethodName = "/milvus.proto.rootcoord.RootCoord/DescribeCollection"
RootCoord_DescribeCollectionInternal_FullMethodName = "/milvus.proto.rootcoord.RootCoord/DescribeCollectionInternal"
@ -103,6 +104,13 @@ type RootCoordClient interface {
// @return Status
DropCollection(ctx context.Context, in *milvuspb.DropCollectionRequest, opts ...grpc.CallOption) (*commonpb.Status, error)
// *
// @brief This method is used to add collection field.
//
// @param AddCollectionFieldRequest, field schema is going to be added.
//
// @return Status
AddCollectionField(ctx context.Context, in *milvuspb.AddCollectionFieldRequest, opts ...grpc.CallOption) (*commonpb.Status, error)
// *
// @brief This method is used to test collection existence.
//
// @param HasCollectionRequest, collection name is going to be tested.
@ -246,6 +254,15 @@ func (c *rootCoordClient) DropCollection(ctx context.Context, in *milvuspb.DropC
return out, nil
}
func (c *rootCoordClient) AddCollectionField(ctx context.Context, in *milvuspb.AddCollectionFieldRequest, opts ...grpc.CallOption) (*commonpb.Status, error) {
out := new(commonpb.Status)
err := c.cc.Invoke(ctx, RootCoord_AddCollectionField_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *rootCoordClient) HasCollection(ctx context.Context, in *milvuspb.HasCollectionRequest, opts ...grpc.CallOption) (*milvuspb.BoolResponse, error) {
out := new(milvuspb.BoolResponse)
err := c.cc.Invoke(ctx, RootCoord_HasCollection_FullMethodName, in, out, opts...)
@ -727,6 +744,13 @@ type RootCoordServer interface {
// @return Status
DropCollection(context.Context, *milvuspb.DropCollectionRequest) (*commonpb.Status, error)
// *
// @brief This method is used to add collection field.
//
// @param AddCollectionFieldRequest, field schema is going to be added.
//
// @return Status
AddCollectionField(context.Context, *milvuspb.AddCollectionFieldRequest) (*commonpb.Status, error)
// *
// @brief This method is used to test collection existence.
//
// @param HasCollectionRequest, collection name is going to be tested.
@ -836,6 +860,9 @@ func (UnimplementedRootCoordServer) CreateCollection(context.Context, *milvuspb.
func (UnimplementedRootCoordServer) DropCollection(context.Context, *milvuspb.DropCollectionRequest) (*commonpb.Status, error) {
return nil, status.Errorf(codes.Unimplemented, "method DropCollection not implemented")
}
func (UnimplementedRootCoordServer) AddCollectionField(context.Context, *milvuspb.AddCollectionFieldRequest) (*commonpb.Status, error) {
return nil, status.Errorf(codes.Unimplemented, "method AddCollectionField not implemented")
}
func (UnimplementedRootCoordServer) HasCollection(context.Context, *milvuspb.HasCollectionRequest) (*milvuspb.BoolResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method HasCollection not implemented")
}
@ -1091,6 +1118,24 @@ func _RootCoord_DropCollection_Handler(srv interface{}, ctx context.Context, dec
return interceptor(ctx, in, info, handler)
}
func _RootCoord_AddCollectionField_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(milvuspb.AddCollectionFieldRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(RootCoordServer).AddCollectionField(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: RootCoord_AddCollectionField_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(RootCoordServer).AddCollectionField(ctx, req.(*milvuspb.AddCollectionFieldRequest))
}
return interceptor(ctx, in, info, handler)
}
func _RootCoord_HasCollection_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(milvuspb.HasCollectionRequest)
if err := dec(in); err != nil {
@ -2036,6 +2081,10 @@ var RootCoord_ServiceDesc = grpc.ServiceDesc{
MethodName: "DropCollection",
Handler: _RootCoord_DropCollection_Handler,
},
{
MethodName: "AddCollectionField",
Handler: _RootCoord_AddCollectionField_Handler,
},
{
MethodName: "HasCollection",
Handler: _RootCoord_HasCollection_Handler,

View File

@ -57,6 +57,7 @@ message CreateJobRequest {
schema.FieldSchema field = 25;
bool partition_key_isolation = 26;
int32 current_scalar_index_version = 27;
int64 lack_binlog_rows = 28;
}
message QueryJobsRequest {

View File

@ -58,6 +58,7 @@ type CreateJobRequest struct {
Field *schemapb.FieldSchema `protobuf:"bytes,25,opt,name=field,proto3" json:"field,omitempty"`
PartitionKeyIsolation bool `protobuf:"varint,26,opt,name=partition_key_isolation,json=partitionKeyIsolation,proto3" json:"partition_key_isolation,omitempty"`
CurrentScalarIndexVersion int32 `protobuf:"varint,27,opt,name=current_scalar_index_version,json=currentScalarIndexVersion,proto3" json:"current_scalar_index_version,omitempty"`
LackBinlogRows int64 `protobuf:"varint,28,opt,name=lack_binlog_rows,json=lackBinlogRows,proto3" json:"lack_binlog_rows,omitempty"`
}
func (x *CreateJobRequest) Reset() {
@ -281,6 +282,13 @@ func (x *CreateJobRequest) GetCurrentScalarIndexVersion() int32 {
return 0
}
func (x *CreateJobRequest) GetLackBinlogRows() int64 {
if x != nil {
return x.LackBinlogRows
}
return 0
}
type QueryJobsRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@ -1778,7 +1786,7 @@ var file_worker_proto_rawDesc = []byte{
0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x10, 0x64, 0x61,
0x74, 0x61, 0x5f, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x11,
0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x22, 0x9a, 0x09, 0x0a, 0x10, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52,
0x6f, 0x22, 0xc4, 0x09, 0x0a, 0x10, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65,
0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74,
0x65, 0x72, 0x49, 0x44, 0x12, 0x2a, 0x0a, 0x11, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x66, 0x69,
@ -1851,352 +1859,355 @@ var file_worker_proto_rawDesc = []byte{
0x1c, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x5f,
0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x1b, 0x20,
0x01, 0x28, 0x05, 0x52, 0x19, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x63, 0x61, 0x6c,
0x61, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x4c,
0x0a, 0x10, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x44, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x44,
0x12, 0x1a, 0x0a, 0x08, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x44, 0x73, 0x18, 0x02, 0x20, 0x03,
0x28, 0x03, 0x52, 0x08, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x44, 0x73, 0x22, 0xaa, 0x01, 0x0a,
0x11, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52,
0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74,
0x65, 0x72, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6c, 0x75, 0x73,
0x74, 0x65, 0x72, 0x49, 0x44, 0x12, 0x42, 0x0a, 0x0b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x69,
0x6e, 0x66, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6d, 0x69, 0x6c,
0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e,
0x49, 0x6e, 0x64, 0x65, 0x78, 0x54, 0x61, 0x73, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x69,
0x6e, 0x64, 0x65, 0x78, 0x49, 0x6e, 0x66, 0x6f, 0x73, 0x22, 0x4b, 0x0a, 0x0f, 0x44, 0x72, 0x6f,
0x70, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09,
0x61, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x28,
0x0a, 0x10, 0x6c, 0x61, 0x63, 0x6b, 0x5f, 0x62, 0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x5f, 0x72, 0x6f,
0x77, 0x73, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x6c, 0x61, 0x63, 0x6b, 0x42, 0x69,
0x6e, 0x6c, 0x6f, 0x67, 0x52, 0x6f, 0x77, 0x73, 0x22, 0x4c, 0x0a, 0x10, 0x51, 0x75, 0x65, 0x72,
0x79, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09,
0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x62, 0x75,
0x69, 0x6c, 0x64, 0x49, 0x44, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x03, 0x52, 0x08, 0x62, 0x75,
0x69, 0x6c, 0x64, 0x49, 0x44, 0x73, 0x22, 0x14, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x62,
0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xbf, 0x02, 0x0a,
0x13, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75,
0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x74, 0x6f, 0x74,
0x61, 0x6c, 0x5f, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03,
0x52, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x4a, 0x6f, 0x62, 0x4e, 0x75, 0x6d, 0x12, 0x2d, 0x0a,
0x13, 0x69, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x6a, 0x6f, 0x62,
0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x69, 0x6e, 0x50, 0x72,
0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x4a, 0x6f, 0x62, 0x4e, 0x75, 0x6d, 0x12, 0x26, 0x0a, 0x0f,
0x65, 0x6e, 0x71, 0x75, 0x65, 0x75, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x75, 0x6d, 0x18,
0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x65, 0x6e, 0x71, 0x75, 0x65, 0x75, 0x65, 0x4a, 0x6f,
0x62, 0x4e, 0x75, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x73, 0x6c, 0x6f,
0x74, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x61, 0x73, 0x6b, 0x53, 0x6c,
0x6f, 0x74, 0x73, 0x12, 0x38, 0x0a, 0x09, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x73,
0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x4a, 0x6f, 0x62, 0x49,
0x6e, 0x66, 0x6f, 0x52, 0x08, 0x6a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x73, 0x12, 0x1f, 0x0a,
0x0b, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x64, 0x69, 0x73, 0x6b, 0x18, 0x07, 0x20, 0x01,
0x28, 0x08, 0x52, 0x0a, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x44, 0x69, 0x73, 0x6b, 0x22, 0xd6,
0x06, 0x0a, 0x0e, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x44, 0x12,
0x16, 0x0a, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52,
0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x44, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63,
0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x20, 0x0a, 0x0b, 0x70,
0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03,
0x52, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x18, 0x0a,
0x07, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x49, 0x44, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07,
0x66, 0x69, 0x65, 0x6c, 0x64, 0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64,
0x4e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c,
0x64, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3c, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x74,
0x79, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x6d, 0x69, 0x6c, 0x76,
0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e,
0x44, 0x61, 0x74, 0x61, 0x54, 0x79, 0x70, 0x65, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x54,
0x79, 0x70, 0x65, 0x12, 0x59, 0x0a, 0x0d, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73,
0x74, 0x61, 0x74, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x6d, 0x69, 0x6c,
0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e,
0x41, 0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x53,
0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
0x52, 0x0c, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x18,
0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52,
0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x48, 0x0a, 0x0e, 0x73, 0x74, 0x6f, 0x72,
0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x21, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x52, 0x0d, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x64, 0x69, 0x6d, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52,
0x03, 0x64, 0x69, 0x6d, 0x12, 0x2f, 0x0a, 0x14, 0x6d, 0x61, 0x78, 0x5f, 0x74, 0x72, 0x61, 0x69,
0x6e, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x18, 0x0c, 0x20, 0x01,
0x28, 0x01, 0x52, 0x11, 0x6d, 0x61, 0x78, 0x54, 0x72, 0x61, 0x69, 0x6e, 0x53, 0x69, 0x7a, 0x65,
0x52, 0x61, 0x74, 0x69, 0x6f, 0x12, 0x21, 0x0a, 0x0c, 0x6e, 0x75, 0x6d, 0x5f, 0x63, 0x6c, 0x75,
0x73, 0x74, 0x65, 0x72, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x6e, 0x75, 0x6d,
0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x12, 0x36, 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c,
0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x46, 0x69,
0x65, 0x6c, 0x64, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64,
0x12, 0x33, 0x0a, 0x16, 0x6d, 0x69, 0x6e, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f,
0x73, 0x69, 0x7a, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x01,
0x52, 0x13, 0x6d, 0x69, 0x6e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x53, 0x69, 0x7a, 0x65,
0x52, 0x61, 0x74, 0x69, 0x6f, 0x12, 0x33, 0x0a, 0x16, 0x6d, 0x61, 0x78, 0x5f, 0x63, 0x6c, 0x75,
0x73, 0x74, 0x65, 0x72, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x18,
0x10, 0x20, 0x01, 0x28, 0x01, 0x52, 0x13, 0x6d, 0x61, 0x78, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65,
0x72, 0x53, 0x69, 0x7a, 0x65, 0x52, 0x61, 0x74, 0x69, 0x6f, 0x12, 0x28, 0x0a, 0x10, 0x6d, 0x61,
0x78, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x11,
0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x6d, 0x61, 0x78, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72,
0x53, 0x69, 0x7a, 0x65, 0x1a, 0x61, 0x0a, 0x11, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x53,
0x74, 0x61, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79,
0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x36, 0x0a, 0x05, 0x76,
0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6d, 0x69, 0x6c,
0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e,
0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x05, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xaf, 0x06, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61,
0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c,
0x0a, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06,
0x74, 0x61, 0x73, 0x6b, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x74, 0x61,
0x73, 0x6b, 0x49, 0x44, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c,
0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x74,
0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x70,
0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x25, 0x0a, 0x0e, 0x69, 0x6e,
0x73, 0x65, 0x72, 0x74, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x05, 0x20, 0x01,
0x28, 0x09, 0x52, 0x0d, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65,
0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x06,
0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x12,
0x3f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x5f, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x07,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x42, 0x69,
0x6e, 0x6c, 0x6f, 0x67, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x4c, 0x6f, 0x67, 0x73,
0x12, 0x3d, 0x0a, 0x0a, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x08,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x42, 0x69,
0x6e, 0x6c, 0x6f, 0x67, 0x52, 0x09, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x4c, 0x6f, 0x67, 0x73, 0x12,
0x48, 0x0a, 0x0e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x53, 0x74, 0x6f,
0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x73, 0x74, 0x6f, 0x72,
0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3d, 0x0a, 0x06, 0x73, 0x63, 0x68,
0x65, 0x6d, 0x61, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6d, 0x69, 0x6c, 0x76,
0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e,
0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61,
0x52, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x3f, 0x0a, 0x0a, 0x73, 0x75, 0x62, 0x4a,
0x6f, 0x62, 0x54, 0x79, 0x70, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x6d,
0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65,
0x78, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x53, 0x75, 0x62, 0x4a, 0x6f, 0x62, 0x52, 0x0a, 0x73,
0x75, 0x62, 0x4a, 0x6f, 0x62, 0x54, 0x79, 0x70, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x74, 0x61, 0x72,
0x67, 0x65, 0x74, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x0c, 0x20, 0x01,
0x28, 0x03, 0x52, 0x0f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e,
0x74, 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x6f, 0x67, 0x49,
0x44, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x6f,
0x67, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x4c, 0x6f, 0x67, 0x49, 0x44, 0x18,
0x0e, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x4c, 0x6f, 0x67, 0x49, 0x44, 0x12,
0x19, 0x0a, 0x08, 0x6e, 0x75, 0x6d, 0x5f, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28,
0x03, 0x52, 0x07, 0x6e, 0x75, 0x6d, 0x52, 0x6f, 0x77, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f,
0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x74, 0x6c, 0x18, 0x10, 0x20, 0x01,
0x28, 0x03, 0x52, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x74,
0x6c, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x73, 0x18,
0x11, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x54, 0x73,
0x12, 0x21, 0x0a, 0x0c, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
0x18, 0x12, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x74, 0x61, 0x73, 0x6b, 0x56, 0x65, 0x72, 0x73,
0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x62, 0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x4d, 0x61, 0x78,
0x53, 0x69, 0x7a, 0x65, 0x18, 0x13, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x62, 0x69, 0x6e, 0x6c,
0x6f, 0x67, 0x4d, 0x61, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x22, 0xf8, 0x02, 0x0a, 0x12, 0x43, 0x72,
0x65, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x56, 0x32, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x44, 0x12, 0x16,
0x0a, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06,
0x74, 0x61, 0x73, 0x6b, 0x49, 0x44, 0x12, 0x36, 0x0a, 0x08, 0x6a, 0x6f, 0x62, 0x5f, 0x74, 0x79,
0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75,
0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x4a, 0x6f,
0x62, 0x54, 0x79, 0x70, 0x65, 0x52, 0x07, 0x6a, 0x6f, 0x62, 0x54, 0x79, 0x70, 0x65, 0x12, 0x4d,
0x0a, 0x0f, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x65, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x41, 0x6e, 0x61,
0x6c, 0x79, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0e, 0x61,
0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4b, 0x0a,
0x0d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x05,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x69, 0x6e,
0x64, 0x65, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4d, 0x0a, 0x0d, 0x73, 0x74,
0x61, 0x74, 0x73, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x26, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61,
0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x73, 0x74, 0x61,
0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x09, 0x0a, 0x07, 0x72, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x22, 0x84, 0x01, 0x0a, 0x12, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4a, 0x6f,
0x62, 0x73, 0x56, 0x32, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x63,
0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09,
0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x61, 0x73,
0x6b, 0x49, 0x44, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x03, 0x52, 0x07, 0x74, 0x61, 0x73, 0x6b,
0x49, 0x44, 0x73, 0x12, 0x36, 0x0a, 0x08, 0x6a, 0x6f, 0x62, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18,
0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x4a, 0x6f, 0x62, 0x54, 0x79,
0x70, 0x65, 0x52, 0x07, 0x6a, 0x6f, 0x62, 0x54, 0x79, 0x70, 0x65, 0x22, 0x92, 0x03, 0x0a, 0x0d,
0x49, 0x6e, 0x64, 0x65, 0x78, 0x54, 0x61, 0x73, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x18, 0x0a,
0x07, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07,
0x62, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x44, 0x12, 0x35, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x49, 0x6e, 0x64,
0x65, 0x78, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x26,
0x0a, 0x0f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x6b, 0x65, 0x79,
0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x46, 0x69,
0x6c, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c,
0x69, 0x7a, 0x65, 0x64, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52,
0x0e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x53, 0x69, 0x7a, 0x65, 0x12,
0x1f, 0x0a, 0x0b, 0x66, 0x61, 0x69, 0x6c, 0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x05,
0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x66, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e,
0x12, 0x32, 0x0a, 0x15, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65,
0x78, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52,
0x13, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x56, 0x65, 0x72,
0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x0a, 0x13, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x73, 0x74,
0x6f, 0x72, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28,
0x03, 0x52, 0x11, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x56, 0x65, 0x72,
0x73, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x6d, 0x65, 0x6d, 0x5f, 0x73, 0x69, 0x7a, 0x65,
0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x53, 0x69, 0x7a, 0x65, 0x12,
0x3f, 0x0a, 0x1c, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x63, 0x61, 0x6c, 0x61,
0x72, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18,
0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x19, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x63,
0x61, 0x6c, 0x61, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
0x22, 0x4e, 0x0a, 0x0f, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x75,
0x6c, 0x74, 0x73, 0x12, 0x3b, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x54,
0x61, 0x73, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73,
0x22, 0xa3, 0x01, 0x0a, 0x0d, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x75,
0x6c, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01,
0x28, 0x03, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x44, 0x12, 0x32, 0x0a, 0x05, 0x73, 0x74,
0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x6d, 0x69, 0x6c, 0x76,
0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x4a,
0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1f,
0x0a, 0x0b, 0x66, 0x61, 0x69, 0x6c, 0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20,
0x01, 0x28, 0x09, 0x52, 0x0a, 0x66, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12,
0x25, 0x0a, 0x0e, 0x63, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x69, 0x64, 0x73, 0x5f, 0x66, 0x69, 0x6c,
0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x69,
0x64, 0x73, 0x46, 0x69, 0x6c, 0x65, 0x22, 0x4d, 0x0a, 0x0e, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x7a,
0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x3b, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75,
0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6d, 0x69, 0x6c, 0x76,
0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x41,
0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, 0x72, 0x65,
0x73, 0x75, 0x6c, 0x74, 0x73, 0x22, 0x91, 0x05, 0x0a, 0x0b, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52,
0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x44, 0x18,
0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x44, 0x12, 0x32, 0x0a,
0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x6d,
0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65,
0x78, 0x2e, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74,
0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x61, 0x69, 0x6c, 0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e,
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x66, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x61, 0x73,
0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74,
0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x70, 0x61, 0x72,
0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x67, 0x6d,
0x65, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, 0x65, 0x67,
0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65,
0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c,
0x12, 0x3f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x5f, 0x6c, 0x6f, 0x67, 0x73, 0x18,
0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x42,
0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x4c, 0x6f, 0x67,
0x73, 0x12, 0x3d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x73, 0x5f, 0x6c, 0x6f, 0x67, 0x73, 0x18,
0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x42,
0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x52, 0x09, 0x73, 0x74, 0x61, 0x74, 0x73, 0x4c, 0x6f, 0x67, 0x73,
0x12, 0x5a, 0x0a, 0x0f, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x5f, 0x6c,
0x6f, 0x67, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x6d, 0x69, 0x6c, 0x76,
0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x53,
0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x54, 0x65, 0x78, 0x74, 0x53,
0x74, 0x61, 0x74, 0x73, 0x4c, 0x6f, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x74,
0x65, 0x78, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x19, 0x0a, 0x08,
0x6e, 0x75, 0x6d, 0x5f, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07,
0x6e, 0x75, 0x6d, 0x52, 0x6f, 0x77, 0x73, 0x12, 0x3b, 0x0a, 0x09, 0x62, 0x6d, 0x32, 0x35, 0x5f,
0x6c, 0x6f, 0x67, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x69, 0x6c,
0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x46,
0x69, 0x65, 0x6c, 0x64, 0x42, 0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x52, 0x08, 0x62, 0x6d, 0x32, 0x35,
0x4c, 0x6f, 0x67, 0x73, 0x1a, 0x63, 0x0a, 0x12, 0x54, 0x65, 0x78, 0x74, 0x53, 0x74, 0x61, 0x74,
0x73, 0x4c, 0x6f, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x37, 0x0a, 0x05,
0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6d, 0x69,
0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e,
0x54, 0x65, 0x78, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x05,
0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x49, 0x0a, 0x0c, 0x53, 0x74, 0x61,
0x74, 0x73, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x39, 0x0a, 0x07, 0x72, 0x65, 0x73,
0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6d, 0x69, 0x6c,
0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e,
0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, 0x72, 0x65, 0x73,
0x75, 0x6c, 0x74, 0x73, 0x22, 0xeb, 0x02, 0x0a, 0x13, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4a, 0x6f,
0x62, 0x73, 0x56, 0x32, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x06,
0x69, 0x6c, 0x64, 0x49, 0x44, 0x73, 0x22, 0xaa, 0x01, 0x0a, 0x11, 0x51, 0x75, 0x65, 0x72, 0x79,
0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x06,
0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6d,
0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,
0x73, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x44, 0x18, 0x02,
0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x44, 0x12,
0x51, 0x0a, 0x11, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x6a, 0x6f, 0x62, 0x5f, 0x72, 0x65, 0x73,
0x75, 0x6c, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6d, 0x69, 0x6c,
0x42, 0x0a, 0x0b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x03,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x54,
0x61, 0x73, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x49, 0x6e,
0x66, 0x6f, 0x73, 0x22, 0x4b, 0x0a, 0x0f, 0x44, 0x72, 0x6f, 0x70, 0x4a, 0x6f, 0x62, 0x73, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65,
0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74,
0x65, 0x72, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x44, 0x73,
0x18, 0x02, 0x20, 0x03, 0x28, 0x03, 0x52, 0x08, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x44, 0x73,
0x22, 0x14, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xbf, 0x02, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x4a, 0x6f,
0x62, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33,
0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b,
0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f,
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61,
0x74, 0x75, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x6a, 0x6f, 0x62,
0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x74, 0x6f, 0x74, 0x61,
0x6c, 0x4a, 0x6f, 0x62, 0x4e, 0x75, 0x6d, 0x12, 0x2d, 0x0a, 0x13, 0x69, 0x6e, 0x5f, 0x70, 0x72,
0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x03,
0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73,
0x4a, 0x6f, 0x62, 0x4e, 0x75, 0x6d, 0x12, 0x26, 0x0a, 0x0f, 0x65, 0x6e, 0x71, 0x75, 0x65, 0x75,
0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52,
0x0d, 0x65, 0x6e, 0x71, 0x75, 0x65, 0x75, 0x65, 0x4a, 0x6f, 0x62, 0x4e, 0x75, 0x6d, 0x12, 0x1d,
0x0a, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x73, 0x6c, 0x6f, 0x74, 0x73, 0x18, 0x05, 0x20, 0x01,
0x28, 0x03, 0x52, 0x09, 0x74, 0x61, 0x73, 0x6b, 0x53, 0x6c, 0x6f, 0x74, 0x73, 0x12, 0x38, 0x0a,
0x09, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b,
0x32, 0x1b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x6a,
0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x6e, 0x61, 0x62, 0x6c,
0x65, 0x5f, 0x64, 0x69, 0x73, 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x65, 0x6e,
0x61, 0x62, 0x6c, 0x65, 0x44, 0x69, 0x73, 0x6b, 0x22, 0xd6, 0x06, 0x0a, 0x0e, 0x41, 0x6e, 0x61,
0x6c, 0x79, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x63,
0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09,
0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x73,
0x6b, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49,
0x44, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49,
0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69,
0x6f, 0x6e, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x74,
0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x69, 0x65, 0x6c, 0x64,
0x49, 0x44, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x49,
0x44, 0x12, 0x1c, 0x0a, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x06,
0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x12,
0x3c, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x07, 0x20,
0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x54, 0x79,
0x70, 0x65, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x59, 0x0a,
0x0d, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x08,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x7a,
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74,
0x53, 0x74, 0x61, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0c, 0x73, 0x65, 0x67, 0x6d,
0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73,
0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69,
0x6f, 0x6e, 0x12, 0x48, 0x0a, 0x0e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6d, 0x69, 0x6c,
0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e,
0x49, 0x6e, 0x64, 0x65, 0x78, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x48,
0x00, 0x52, 0x0f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x75, 0x6c,
0x74, 0x73, 0x12, 0x54, 0x0a, 0x13, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x65, 0x5f, 0x6a, 0x6f,
0x62, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x22, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69,
0x6e, 0x64, 0x65, 0x78, 0x2e, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x75,
0x6c, 0x74, 0x73, 0x48, 0x00, 0x52, 0x11, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x65, 0x4a, 0x6f,
0x62, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x4e, 0x0a, 0x11, 0x73, 0x74, 0x61, 0x74,
0x73, 0x5f, 0x6a, 0x6f, 0x62, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x05, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65,
0x73, 0x75, 0x6c, 0x74, 0x73, 0x48, 0x00, 0x52, 0x0f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x4a, 0x6f,
0x62, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x42, 0x08, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75,
0x6c, 0x74, 0x22, 0x83, 0x01, 0x0a, 0x11, 0x44, 0x72, 0x6f, 0x70, 0x4a, 0x6f, 0x62, 0x73, 0x56,
0x32, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6c, 0x75, 0x73,
0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x73,
0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03,
0x64, 0x69, 0x6d, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x64, 0x69, 0x6d, 0x12, 0x2f,
0x0a, 0x14, 0x6d, 0x61, 0x78, 0x5f, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x5f, 0x73, 0x69, 0x7a, 0x65,
0x5f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x01, 0x52, 0x11, 0x6d, 0x61,
0x78, 0x54, 0x72, 0x61, 0x69, 0x6e, 0x53, 0x69, 0x7a, 0x65, 0x52, 0x61, 0x74, 0x69, 0x6f, 0x12,
0x21, 0x0a, 0x0c, 0x6e, 0x75, 0x6d, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x18,
0x0d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x6e, 0x75, 0x6d, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65,
0x72, 0x73, 0x12, 0x36, 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x20, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x63, 0x68,
0x65, 0x6d, 0x61, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x33, 0x0a, 0x16, 0x6d, 0x69,
0x6e, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x72,
0x61, 0x74, 0x69, 0x6f, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x01, 0x52, 0x13, 0x6d, 0x69, 0x6e, 0x43,
0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x52, 0x61, 0x74, 0x69, 0x6f, 0x12,
0x33, 0x0a, 0x16, 0x6d, 0x61, 0x78, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x73,
0x69, 0x7a, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x18, 0x10, 0x20, 0x01, 0x28, 0x01, 0x52,
0x13, 0x6d, 0x61, 0x78, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x52,
0x61, 0x74, 0x69, 0x6f, 0x12, 0x28, 0x0a, 0x10, 0x6d, 0x61, 0x78, 0x5f, 0x63, 0x6c, 0x75, 0x73,
0x74, 0x65, 0x72, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e,
0x6d, 0x61, 0x78, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x1a, 0x61,
0x0a, 0x11, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x45, 0x6e,
0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03,
0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x36, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e,
0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
0x01, 0x22, 0xaf, 0x06, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74,
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6c, 0x75, 0x73,
0x74, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6c, 0x75,
0x73, 0x74, 0x65, 0x72, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x44,
0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x03, 0x52, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x44, 0x73,
0x73, 0x74, 0x65, 0x72, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x44,
0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x44, 0x12, 0x22,
0x0a, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x03,
0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
0x49, 0x44, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49,
0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69,
0x6f, 0x6e, 0x49, 0x44, 0x12, 0x25, 0x0a, 0x0e, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x5f, 0x63,
0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x69, 0x6e,
0x73, 0x65, 0x72, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x73,
0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09,
0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x12, 0x3f, 0x0a, 0x0b, 0x69, 0x6e, 0x73,
0x65, 0x72, 0x74, 0x5f, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e,
0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61,
0x74, 0x61, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x42, 0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x52, 0x0a,
0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x3d, 0x0a, 0x0a, 0x64, 0x65,
0x6c, 0x74, 0x61, 0x5f, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e,
0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61,
0x74, 0x61, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x42, 0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x52, 0x09,
0x64, 0x65, 0x6c, 0x74, 0x61, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x48, 0x0a, 0x0e, 0x73, 0x74, 0x6f,
0x72, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x09, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x21, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x12, 0x3d, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x0a, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x06, 0x73, 0x63, 0x68, 0x65,
0x6d, 0x61, 0x12, 0x3f, 0x0a, 0x0a, 0x73, 0x75, 0x62, 0x4a, 0x6f, 0x62, 0x54, 0x79, 0x70, 0x65,
0x18, 0x0b, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x53, 0x74, 0x61, 0x74,
0x73, 0x53, 0x75, 0x62, 0x4a, 0x6f, 0x62, 0x52, 0x0a, 0x73, 0x75, 0x62, 0x4a, 0x6f, 0x62, 0x54,
0x79, 0x70, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x65, 0x67,
0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x74, 0x61,
0x72, 0x67, 0x65, 0x74, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x12, 0x1e, 0x0a,
0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x6f, 0x67, 0x49, 0x44, 0x18, 0x0d, 0x20, 0x01, 0x28,
0x03, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x6f, 0x67, 0x49, 0x44, 0x12, 0x1a, 0x0a,
0x08, 0x65, 0x6e, 0x64, 0x4c, 0x6f, 0x67, 0x49, 0x44, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x03, 0x52,
0x08, 0x65, 0x6e, 0x64, 0x4c, 0x6f, 0x67, 0x49, 0x44, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x75, 0x6d,
0x5f, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6e, 0x75, 0x6d,
0x52, 0x6f, 0x77, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x5f, 0x74, 0x74, 0x6c, 0x18, 0x10, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x63, 0x6f,
0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x74, 0x6c, 0x12, 0x1d, 0x0a, 0x0a, 0x63,
0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x73, 0x18, 0x11, 0x20, 0x01, 0x28, 0x04, 0x52,
0x09, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x54, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x61,
0x73, 0x6b, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x12, 0x20, 0x01, 0x28, 0x03,
0x52, 0x0b, 0x74, 0x61, 0x73, 0x6b, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a,
0x0d, 0x62, 0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x4d, 0x61, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x13,
0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x62, 0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x4d, 0x61, 0x78, 0x53,
0x69, 0x7a, 0x65, 0x22, 0xf8, 0x02, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4a, 0x6f,
0x62, 0x56, 0x32, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6c,
0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63,
0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x73, 0x6b,
0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x44,
0x12, 0x36, 0x0a, 0x08, 0x6a, 0x6f, 0x62, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01,
0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x4a, 0x6f, 0x62, 0x54, 0x79, 0x70, 0x65, 0x52,
0x07, 0x6a, 0x6f, 0x62, 0x54, 0x79, 0x70, 0x65, 0x32, 0xf7, 0x04, 0x0a, 0x09, 0x49, 0x6e, 0x64,
0x65, 0x78, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x50, 0x0a, 0x09, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
0x4a, 0x6f, 0x62, 0x12, 0x24, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4a,
0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6d, 0x69, 0x6c, 0x76,
0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x5a, 0x0a, 0x09, 0x51, 0x75, 0x65, 0x72,
0x79, 0x4a, 0x6f, 0x62, 0x73, 0x12, 0x24, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79,
0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x6d, 0x69,
0x07, 0x6a, 0x6f, 0x62, 0x54, 0x79, 0x70, 0x65, 0x12, 0x4d, 0x0a, 0x0f, 0x61, 0x6e, 0x61, 0x6c,
0x79, 0x7a, 0x65, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x22, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x65, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0e, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x65,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4b, 0x0a, 0x0d, 0x69, 0x6e, 0x64, 0x65, 0x78,
0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24,
0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e,
0x64, 0x65, 0x78, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x12, 0x4d, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x74, 0x73, 0x5f, 0x72, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x6d, 0x69,
0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78,
0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x08, 0x44, 0x72, 0x6f, 0x70, 0x4a, 0x6f, 0x62, 0x73,
0x12, 0x23, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x44, 0x72, 0x6f, 0x70, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74,
0x75, 0x73, 0x22, 0x00, 0x12, 0x60, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x62, 0x53, 0x74,
0x61, 0x74, 0x73, 0x12, 0x26, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x62, 0x53,
0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x6d, 0x69,
0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78,
0x2e, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x54, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
0x4a, 0x6f, 0x62, 0x56, 0x32, 0x12, 0x26, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74,
0x65, 0x4a, 0x6f, 0x62, 0x56, 0x32, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e,
0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d,
0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x60, 0x0a, 0x0b,
0x51, 0x75, 0x65, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x73, 0x56, 0x32, 0x12, 0x26, 0x2e, 0x6d, 0x69,
0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78,
0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x73, 0x56, 0x32, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4a, 0x6f,
0x62, 0x73, 0x56, 0x32, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x52,
0x0a, 0x0a, 0x44, 0x72, 0x6f, 0x70, 0x4a, 0x6f, 0x62, 0x73, 0x56, 0x32, 0x12, 0x25, 0x2e, 0x6d,
0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x42, 0x09, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x84,
0x01, 0x0a, 0x12, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x73, 0x56, 0x32, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72,
0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65,
0x72, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x44, 0x73, 0x18, 0x02,
0x20, 0x03, 0x28, 0x03, 0x52, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x44, 0x73, 0x12, 0x36, 0x0a,
0x08, 0x6a, 0x6f, 0x62, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32,
0x1b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69,
0x6e, 0x64, 0x65, 0x78, 0x2e, 0x4a, 0x6f, 0x62, 0x54, 0x79, 0x70, 0x65, 0x52, 0x07, 0x6a, 0x6f,
0x62, 0x54, 0x79, 0x70, 0x65, 0x22, 0x92, 0x03, 0x0a, 0x0d, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x54,
0x61, 0x73, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x75, 0x69, 0x6c, 0x64,
0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x49,
0x44, 0x12, 0x35, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e,
0x32, 0x1f, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x53, 0x74, 0x61, 0x74,
0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x69, 0x6e, 0x64, 0x65,
0x78, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28,
0x09, 0x52, 0x0d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x46, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x73,
0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x73,
0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x73, 0x65, 0x72, 0x69, 0x61,
0x6c, 0x69, 0x7a, 0x65, 0x64, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x61, 0x69,
0x6c, 0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
0x66, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x15, 0x63, 0x75,
0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x76, 0x65, 0x72, 0x73,
0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x13, 0x63, 0x75, 0x72, 0x72, 0x65,
0x6e, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2e,
0x0a, 0x13, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x76, 0x65,
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x69, 0x6e, 0x64,
0x65, 0x78, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x19,
0x0a, 0x08, 0x6d, 0x65, 0x6d, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04,
0x52, 0x07, 0x6d, 0x65, 0x6d, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x3f, 0x0a, 0x1c, 0x63, 0x75, 0x72,
0x72, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x5f, 0x69, 0x6e, 0x64, 0x65,
0x78, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52,
0x19, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x49, 0x6e,
0x64, 0x65, 0x78, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x4e, 0x0a, 0x0f, 0x49, 0x6e,
0x64, 0x65, 0x78, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x3b, 0x0a,
0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21,
0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e,
0x64, 0x65, 0x78, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x54, 0x61, 0x73, 0x6b, 0x49, 0x6e, 0x66,
0x6f, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x22, 0xa3, 0x01, 0x0a, 0x0d, 0x41,
0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x16, 0x0a, 0x06,
0x74, 0x61, 0x73, 0x6b, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x74, 0x61,
0x73, 0x6b, 0x49, 0x44, 0x12, 0x32, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20,
0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74,
0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x61, 0x69, 0x6c,
0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x66,
0x61, 0x69, 0x6c, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x65, 0x6e,
0x74, 0x72, 0x6f, 0x69, 0x64, 0x73, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0d, 0x63, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x69, 0x64, 0x73, 0x46, 0x69, 0x6c, 0x65,
0x22, 0x4d, 0x0a, 0x0e, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c,
0x74, 0x73, 0x12, 0x3b, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x65,
0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x22,
0x91, 0x05, 0x0a, 0x0b, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12,
0x16, 0x0a, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52,
0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x44, 0x12, 0x32, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x4a, 0x6f, 0x62, 0x53,
0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x66,
0x61, 0x69, 0x6c, 0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
0x52, 0x0a, 0x66, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c,
0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01,
0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44,
0x12, 0x20, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18,
0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e,
0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x18,
0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44,
0x12, 0x18, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28,
0x09, 0x52, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x3f, 0x0a, 0x0b, 0x69, 0x6e,
0x73, 0x65, 0x72, 0x74, 0x5f, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x1e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64,
0x61, 0x74, 0x61, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x42, 0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x52,
0x0a, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x3d, 0x0a, 0x0a, 0x73,
0x74, 0x61, 0x74, 0x73, 0x5f, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x1e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64,
0x61, 0x74, 0x61, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x42, 0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x52,
0x09, 0x73, 0x74, 0x61, 0x74, 0x73, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x5a, 0x0a, 0x0f, 0x74, 0x65,
0x78, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x5f, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x0a, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65,
0x73, 0x75, 0x6c, 0x74, 0x2e, 0x54, 0x65, 0x78, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x4c, 0x6f,
0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x74, 0x65, 0x78, 0x74, 0x53, 0x74, 0x61,
0x74, 0x73, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x75, 0x6d, 0x5f, 0x72, 0x6f,
0x77, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6e, 0x75, 0x6d, 0x52, 0x6f, 0x77,
0x73, 0x12, 0x3b, 0x0a, 0x09, 0x62, 0x6d, 0x32, 0x35, 0x5f, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x0c,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x42, 0x69,
0x6e, 0x6c, 0x6f, 0x67, 0x52, 0x08, 0x62, 0x6d, 0x32, 0x35, 0x4c, 0x6f, 0x67, 0x73, 0x1a, 0x63,
0x0a, 0x12, 0x54, 0x65, 0x78, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x4c, 0x6f, 0x67, 0x73, 0x45,
0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
0x03, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x37, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x65, 0x78, 0x74, 0x49, 0x6e,
0x64, 0x65, 0x78, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,
0x02, 0x38, 0x01, 0x22, 0x49, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x75,
0x6c, 0x74, 0x73, 0x12, 0x39, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52,
0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x22, 0xeb,
0x02, 0x0a, 0x13, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x73, 0x56, 0x32, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61,
0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x63,
0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09,
0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x44, 0x12, 0x51, 0x0a, 0x11, 0x69, 0x6e, 0x64,
0x65, 0x78, 0x5f, 0x6a, 0x6f, 0x62, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x03,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4a,
0x6f, 0x62, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x48, 0x00, 0x52, 0x0f, 0x69, 0x6e, 0x64,
0x65, 0x78, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x54, 0x0a, 0x13,
0x61, 0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x5f, 0x72, 0x65, 0x73, 0x75,
0x6c, 0x74, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6d, 0x69, 0x6c, 0x76,
0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x41,
0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x48, 0x00, 0x52,
0x11, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x75, 0x6c,
0x74, 0x73, 0x12, 0x4e, 0x0a, 0x11, 0x73, 0x74, 0x61, 0x74, 0x73, 0x5f, 0x6a, 0x6f, 0x62, 0x5f,
0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e,
0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64,
0x65, 0x78, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x48,
0x00, 0x52, 0x0f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x75, 0x6c,
0x74, 0x73, 0x42, 0x08, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x83, 0x01, 0x0a,
0x11, 0x44, 0x72, 0x6f, 0x70, 0x4a, 0x6f, 0x62, 0x73, 0x56, 0x32, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x44, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x44,
0x12, 0x18, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x44, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28,
0x03, 0x52, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x44, 0x73, 0x12, 0x36, 0x0a, 0x08, 0x6a, 0x6f,
0x62, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x6d,
0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65,
0x78, 0x2e, 0x44, 0x72, 0x6f, 0x70, 0x4a, 0x6f, 0x62, 0x73, 0x56, 0x32, 0x52, 0x65, 0x71, 0x75,
0x78, 0x2e, 0x4a, 0x6f, 0x62, 0x54, 0x79, 0x70, 0x65, 0x52, 0x07, 0x6a, 0x6f, 0x62, 0x54, 0x79,
0x70, 0x65, 0x32, 0xf7, 0x04, 0x0a, 0x09, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x6f, 0x64, 0x65,
0x12, 0x50, 0x0a, 0x09, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x24, 0x2e,
0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64,
0x65, 0x78, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
0x22, 0x00, 0x42, 0x33, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2d, 0x69, 0x6f, 0x2f, 0x6d, 0x69, 0x6c, 0x76, 0x75,
0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x77,
0x6f, 0x72, 0x6b, 0x65, 0x72, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x22, 0x00, 0x12, 0x5a, 0x0a, 0x09, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x73, 0x12,
0x24, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69,
0x6e, 0x64, 0x65, 0x78, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79,
0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4e,
0x0a, 0x08, 0x44, 0x72, 0x6f, 0x70, 0x4a, 0x6f, 0x62, 0x73, 0x12, 0x23, 0x2e, 0x6d, 0x69, 0x6c,
0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e,
0x44, 0x72, 0x6f, 0x70, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x1b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63,
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x60,
0x0a, 0x0b, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x26, 0x2e,
0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64,
0x65, 0x78, 0x2e, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x47, 0x65, 0x74, 0x4a, 0x6f,
0x62, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
0x12, 0x54, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x56, 0x32, 0x12,
0x26, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69,
0x6e, 0x64, 0x65, 0x78, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x56, 0x32,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74,
0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x60, 0x0a, 0x0b, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4a,
0x6f, 0x62, 0x73, 0x56, 0x32, 0x12, 0x26, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79,
0x4a, 0x6f, 0x62, 0x73, 0x56, 0x32, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e,
0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64,
0x65, 0x78, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x73, 0x56, 0x32, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x52, 0x0a, 0x0a, 0x44, 0x72, 0x6f, 0x70,
0x4a, 0x6f, 0x62, 0x73, 0x56, 0x32, 0x12, 0x25, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x44, 0x72, 0x6f, 0x70,
0x4a, 0x6f, 0x62, 0x73, 0x56, 0x32, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e,
0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d,
0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x42, 0x33, 0x5a, 0x31,
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x69, 0x6c, 0x76, 0x75,
0x73, 0x2d, 0x69, 0x6f, 0x2f, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f,
0x76, 0x32, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x70,
0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (