Merging multiple shard query/search requests into one rpc request if QueryNode is the leader of multiple shards of Collection (#17588)

Signed-off-by: Zach41 <zongmei.zhang@zilliz.com>
pull/18125/head
Zach 2022-07-06 15:06:21 +08:00 committed by GitHub
parent b923994b78
commit 1c9647ff31
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 944 additions and 522 deletions

View File

@ -236,7 +236,7 @@ message ReleaseSegmentsRequest {
message SearchRequest {
internal.SearchRequest req = 1;
string dml_channel = 2;
repeated string dml_channels = 2;
repeated int64 segmentIDs = 3;
bool from_shard_leader = 4;
DataScope scope = 5; // All, Streaming, Historical
@ -244,7 +244,7 @@ message SearchRequest {
message QueryRequest {
internal.RetrieveRequest req = 1;
string dml_channel = 2;
repeated string dml_channels = 2;
repeated int64 segmentIDs = 3;
bool from_shard_leader = 4;
DataScope scope = 5; // All, Streaming, Historical

View File

@ -1714,7 +1714,7 @@ func (m *ReleaseSegmentsRequest) GetScope() DataScope {
type SearchRequest struct {
Req *internalpb.SearchRequest `protobuf:"bytes,1,opt,name=req,proto3" json:"req,omitempty"`
DmlChannel string `protobuf:"bytes,2,opt,name=dml_channel,json=dmlChannel,proto3" json:"dml_channel,omitempty"`
DmlChannels []string `protobuf:"bytes,2,rep,name=dml_channels,json=dmlChannels,proto3" json:"dml_channels,omitempty"`
SegmentIDs []int64 `protobuf:"varint,3,rep,packed,name=segmentIDs,proto3" json:"segmentIDs,omitempty"`
FromShardLeader bool `protobuf:"varint,4,opt,name=from_shard_leader,json=fromShardLeader,proto3" json:"from_shard_leader,omitempty"`
Scope DataScope `protobuf:"varint,5,opt,name=scope,proto3,enum=milvus.proto.query.DataScope" json:"scope,omitempty"`
@ -1755,11 +1755,11 @@ func (m *SearchRequest) GetReq() *internalpb.SearchRequest {
return nil
}
func (m *SearchRequest) GetDmlChannel() string {
func (m *SearchRequest) GetDmlChannels() []string {
if m != nil {
return m.DmlChannel
return m.DmlChannels
}
return ""
return nil
}
func (m *SearchRequest) GetSegmentIDs() []int64 {
@ -1785,7 +1785,7 @@ func (m *SearchRequest) GetScope() DataScope {
type QueryRequest struct {
Req *internalpb.RetrieveRequest `protobuf:"bytes,1,opt,name=req,proto3" json:"req,omitempty"`
DmlChannel string `protobuf:"bytes,2,opt,name=dml_channel,json=dmlChannel,proto3" json:"dml_channel,omitempty"`
DmlChannels []string `protobuf:"bytes,2,rep,name=dml_channels,json=dmlChannels,proto3" json:"dml_channels,omitempty"`
SegmentIDs []int64 `protobuf:"varint,3,rep,packed,name=segmentIDs,proto3" json:"segmentIDs,omitempty"`
FromShardLeader bool `protobuf:"varint,4,opt,name=from_shard_leader,json=fromShardLeader,proto3" json:"from_shard_leader,omitempty"`
Scope DataScope `protobuf:"varint,5,opt,name=scope,proto3,enum=milvus.proto.query.DataScope" json:"scope,omitempty"`
@ -1826,11 +1826,11 @@ func (m *QueryRequest) GetReq() *internalpb.RetrieveRequest {
return nil
}
func (m *QueryRequest) GetDmlChannel() string {
func (m *QueryRequest) GetDmlChannels() []string {
if m != nil {
return m.DmlChannel
return m.DmlChannels
}
return ""
return nil
}
func (m *QueryRequest) GetSegmentIDs() []int64 {
@ -2804,191 +2804,190 @@ func init() {
func init() { proto.RegisterFile("query_coord.proto", fileDescriptor_aab7cc9a69ed26e8) }
var fileDescriptor_aab7cc9a69ed26e8 = []byte{
// 2929 bytes of a gzipped FileDescriptorProto
// 2928 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x3a, 0xc9, 0x8f, 0x1c, 0x57,
0xf9, 0x53, 0xbd, 0x4d, 0xf7, 0xd7, 0x5b, 0xf9, 0x8d, 0x3d, 0xee, 0xf4, 0xcf, 0x4e, 0x9c, 0x72,
0x9c, 0xcc, 0x6f, 0x42, 0xc6, 0x66, 0x1c, 0xa2, 0x04, 0x82, 0x84, 0x3d, 0x13, 0x4f, 0x06, 0xdb,
0x93, 0xa1, 0xda, 0x0e, 0xc8, 0x8a, 0x54, 0x54, 0x57, 0xbd, 0xe9, 0x29, 0xb9, 0x96, 0x76, 0xbd,
0x93, 0xa1, 0xda, 0x0e, 0xc8, 0x8a, 0xd4, 0x54, 0x77, 0xbd, 0xe9, 0x29, 0xb9, 0x96, 0x76, 0xbd,
0xea, 0x71, 0x26, 0x67, 0x84, 0xc4, 0x76, 0x40, 0x5c, 0x51, 0xc4, 0x01, 0x0e, 0x48, 0x44, 0x5c,
0xb8, 0x20, 0x21, 0xc4, 0x8d, 0x2b, 0x12, 0x7f, 0x00, 0x47, 0x04, 0x77, 0xc4, 0x15, 0xbd, 0xa5,
0xf6, 0x2a, 0x77, 0x8f, 0x27, 0x4e, 0x82, 0xc4, 0xad, 0xea, 0x7b, 0xcb, 0xb7, 0x6f, 0xef, 0x3d,
0x38, 0xf3, 0x68, 0x86, 0xfd, 0x63, 0xcd, 0xf0, 0x3c, 0xdf, 0xdc, 0x98, 0xfa, 0x5e, 0xe0, 0x21,
0xe4, 0x58, 0xf6, 0xd1, 0x8c, 0xf0, 0xbf, 0x0d, 0x36, 0x3e, 0xec, 0x18, 0x9e, 0xe3, 0x78, 0x2e,
0x87, 0x0d, 0x3b, 0xc9, 0x19, 0xc3, 0x9e, 0xe5, 0x06, 0xd8, 0x77, 0x75, 0x3b, 0x1c, 0x25, 0xc6,
0x21, 0x76, 0x74, 0xf1, 0x27, 0x9b, 0x7a, 0xa0, 0x27, 0xf7, 0x57, 0xbe, 0x27, 0xc1, 0xea, 0xe8,
0xd0, 0x7b, 0xbc, 0xe5, 0xd9, 0x36, 0x36, 0x02, 0xcb, 0x73, 0x89, 0x8a, 0x1f, 0xcd, 0x30, 0x09,
0xd0, 0x35, 0xa8, 0x8d, 0x75, 0x82, 0x07, 0xd2, 0x25, 0x69, 0xad, 0xbd, 0x79, 0x61, 0x23, 0x45,
0x89, 0x20, 0xe1, 0x2e, 0x99, 0xdc, 0xd4, 0x09, 0x56, 0xd9, 0x4c, 0x84, 0xa0, 0x66, 0x8e, 0x77,
0xb7, 0x07, 0x95, 0x4b, 0xd2, 0x5a, 0x55, 0x65, 0xdf, 0xe8, 0x25, 0xe8, 0x1a, 0xd1, 0xde, 0xbb,
0xdb, 0x64, 0x50, 0xbd, 0x54, 0x5d, 0xab, 0xaa, 0x69, 0xa0, 0xf2, 0x37, 0x09, 0xce, 0xe7, 0xc8,
0x20, 0x53, 0xcf, 0x25, 0x18, 0x5d, 0x87, 0x06, 0x09, 0xf4, 0x60, 0x46, 0x04, 0x25, 0xff, 0x57,
0x48, 0xc9, 0x88, 0x4d, 0x51, 0xc5, 0xd4, 0x3c, 0xda, 0x4a, 0x01, 0x5a, 0xf4, 0x65, 0x38, 0x6b,
0xb9, 0x77, 0xb1, 0xe3, 0xf9, 0xc7, 0xda, 0x14, 0xfb, 0x06, 0x76, 0x03, 0x7d, 0x82, 0x43, 0x1a,
0x57, 0xc2, 0xb1, 0xfd, 0x78, 0x08, 0xbd, 0x01, 0xe7, 0xb9, 0x96, 0x08, 0xf6, 0x8f, 0x2c, 0x03,
0x6b, 0xfa, 0x91, 0x6e, 0xd9, 0xfa, 0xd8, 0xc6, 0x83, 0xda, 0xa5, 0xea, 0x5a, 0x53, 0x3d, 0xc7,
0x86, 0x47, 0x7c, 0xf4, 0x46, 0x38, 0xa8, 0xfc, 0x4a, 0x82, 0x73, 0x94, 0xc3, 0x7d, 0xdd, 0x0f,
0xac, 0x67, 0x20, 0x67, 0x05, 0x3a, 0x49, 0xde, 0x06, 0x55, 0x36, 0x96, 0x82, 0xd1, 0x39, 0xd3,
0x10, 0x3d, 0x95, 0x49, 0x8d, 0xb1, 0x99, 0x82, 0x29, 0xbf, 0x14, 0x06, 0x91, 0xa4, 0xf3, 0x34,
0x8a, 0xc8, 0xe2, 0xac, 0xe4, 0x71, 0x3e, 0x85, 0x1a, 0x94, 0xbf, 0x4b, 0x70, 0xee, 0x8e, 0xa7,
0x9b, 0xb1, 0xc1, 0x7c, 0xf6, 0xe2, 0xfc, 0x3a, 0x34, 0xb8, 0x77, 0x0d, 0x6a, 0x0c, 0xd7, 0x95,
0x34, 0x2e, 0xe1, 0x79, 0x31, 0x85, 0x23, 0x06, 0x50, 0xc5, 0x22, 0x74, 0x05, 0x7a, 0x3e, 0x9e,
0xda, 0x96, 0xa1, 0x6b, 0xee, 0xcc, 0x19, 0x63, 0x7f, 0x50, 0xbf, 0x24, 0xad, 0xd5, 0xd5, 0xae,
0x80, 0xee, 0x31, 0xa0, 0xf2, 0x73, 0x09, 0x06, 0x2a, 0xb6, 0xb1, 0x4e, 0xf0, 0xe7, 0xc9, 0xec,
0x2a, 0x34, 0x5c, 0xcf, 0xc4, 0xbb, 0xdb, 0x8c, 0xd9, 0xaa, 0x2a, 0xfe, 0x94, 0x1f, 0x55, 0xb8,
0x22, 0xbe, 0xe0, 0x76, 0x9d, 0x50, 0x56, 0xfd, 0xd3, 0x51, 0x56, 0xa3, 0x48, 0x59, 0x7f, 0x8a,
0x95, 0xf5, 0x45, 0x17, 0x48, 0xac, 0xd0, 0x7a, 0x4a, 0xa1, 0xbf, 0x96, 0xe0, 0xb9, 0x1d, 0x1c,
0x44, 0xe4, 0x53, 0x7f, 0xc6, 0x5f, 0xd0, 0x60, 0xf5, 0x89, 0x04, 0xc3, 0x22, 0x5a, 0x4f, 0x13,
0xb0, 0x1e, 0xc0, 0x6a, 0x84, 0x43, 0x33, 0x31, 0x31, 0x7c, 0x6b, 0xca, 0xd4, 0xc8, 0x42, 0x57,
0x7b, 0xf3, 0xf2, 0x46, 0x3e, 0x25, 0x6f, 0x64, 0x29, 0x38, 0x17, 0x6d, 0xb1, 0x9d, 0xd8, 0x41,
0xf9, 0x89, 0x04, 0xe7, 0x76, 0x70, 0x30, 0xc2, 0x13, 0x07, 0xbb, 0xc1, 0xae, 0x7b, 0xe0, 0x3d,
0xbd, 0x5c, 0x9f, 0x07, 0x20, 0x62, 0x9f, 0x28, 0xac, 0x26, 0x20, 0x8b, 0xc8, 0x98, 0x65, 0xff,
0x2c, 0x3d, 0xa7, 0x91, 0xdd, 0x57, 0xa0, 0x6e, 0xb9, 0x07, 0x5e, 0x28, 0xaa, 0x17, 0x8a, 0x44,
0x95, 0x44, 0xc6, 0x67, 0x2b, 0x2e, 0xa7, 0xe2, 0x50, 0xf7, 0xcd, 0x3b, 0x58, 0x37, 0xb1, 0x7f,
0x0a, 0x73, 0xcb, 0xb2, 0x5d, 0x29, 0x60, 0xfb, 0xc7, 0x12, 0x9c, 0xcf, 0x21, 0x3c, 0x0d, 0xdf,
0x6f, 0x43, 0x83, 0xd0, 0xcd, 0x42, 0xc6, 0x5f, 0x2a, 0x64, 0x3c, 0x81, 0xee, 0x8e, 0x45, 0x02,
0x55, 0xac, 0x51, 0x3c, 0x90, 0xb3, 0x63, 0xe8, 0x45, 0xe8, 0x18, 0x87, 0xba, 0xeb, 0x62, 0x5b,
0x73, 0x75, 0x87, 0x0b, 0xa0, 0xa5, 0xb6, 0x05, 0x6c, 0x4f, 0x77, 0x30, 0x7a, 0x0e, 0x9a, 0xd4,
0x65, 0x35, 0xcb, 0x0c, 0xd5, 0xbf, 0xcc, 0x5c, 0xd8, 0x24, 0xe8, 0x22, 0x00, 0x1b, 0xd2, 0x4d,
0xd3, 0xe7, 0x69, 0xb4, 0xa5, 0xb6, 0x28, 0xe4, 0x06, 0x05, 0x28, 0x3f, 0x95, 0xa0, 0x43, 0x63,
0xf6, 0x5d, 0x1c, 0xe8, 0x54, 0x0f, 0xe8, 0x2d, 0x68, 0xd9, 0x9e, 0x6e, 0x6a, 0xc1, 0xf1, 0x94,
0xa3, 0xea, 0x65, 0x65, 0xcd, 0x59, 0xa0, 0x8b, 0xee, 0x1d, 0x4f, 0xb1, 0xda, 0xb4, 0xc5, 0xd7,
0x22, 0xf2, 0xce, 0xb9, 0x72, 0xb5, 0xc0, 0x95, 0xbf, 0x5f, 0x87, 0xd5, 0x6f, 0xeb, 0x81, 0x71,
0xb8, 0xed, 0x6c, 0x71, 0x26, 0x4f, 0x61, 0x04, 0x71, 0x6c, 0xab, 0x24, 0x63, 0xdb, 0xa7, 0x16,
0x3b, 0x23, 0x3b, 0xaf, 0x17, 0xd9, 0x39, 0x2d, 0xb2, 0x37, 0xde, 0x17, 0xaa, 0x4a, 0xd8, 0x79,
0x22, 0x07, 0x35, 0x9e, 0x26, 0x07, 0x6d, 0x41, 0x17, 0x7f, 0x68, 0xd8, 0x33, 0xaa, 0x73, 0x86,
0x7d, 0x99, 0x61, 0x7f, 0xbe, 0x00, 0x7b, 0xd2, 0xc9, 0x3a, 0x62, 0xd1, 0xae, 0xa0, 0x81, 0xab,
0xda, 0xc1, 0x81, 0x3e, 0x68, 0x32, 0x32, 0x2e, 0x95, 0xa9, 0x3a, 0xb4, 0x0f, 0xae, 0x6e, 0xfa,
0x87, 0x2e, 0x40, 0x4b, 0x64, 0xbc, 0xdd, 0xed, 0x41, 0x8b, 0x89, 0x2f, 0x06, 0x20, 0x1d, 0xba,
0x22, 0x02, 0x09, 0x0a, 0x81, 0x51, 0xf8, 0x76, 0x11, 0x82, 0x62, 0x65, 0x27, 0x29, 0x27, 0xef,
0xb8, 0x81, 0x7f, 0xac, 0x76, 0x48, 0x02, 0x34, 0xd4, 0xe0, 0x4c, 0x6e, 0x0a, 0x92, 0xa1, 0xfa,
0x10, 0x1f, 0x33, 0x03, 0xa9, 0xaa, 0xf4, 0x13, 0xbd, 0x0e, 0xf5, 0x23, 0xdd, 0x9e, 0x61, 0x66,
0x00, 0xf3, 0x65, 0xc4, 0x27, 0x7f, 0xb5, 0xf2, 0xa6, 0xa4, 0x7c, 0x5c, 0x81, 0xe7, 0x38, 0x6d,
0xd8, 0x0e, 0xf4, 0xcf, 0xd7, 0x16, 0x23, 0x3b, 0xab, 0x9d, 0xc8, 0xce, 0x2e, 0x02, 0x84, 0xc5,
0x8a, 0x65, 0x8a, 0xf4, 0x1e, 0x69, 0xc9, 0x4c, 0x9b, 0x40, 0xeb, 0xa4, 0x26, 0xa0, 0xfc, 0xb1,
0x06, 0x7d, 0x21, 0x3b, 0x3a, 0x83, 0x05, 0x90, 0x0b, 0xd0, 0x8a, 0x52, 0x8f, 0x50, 0x43, 0x0c,
0x40, 0x97, 0xa0, 0x9d, 0x70, 0x1f, 0x21, 0x87, 0x24, 0x68, 0x21, 0x61, 0x84, 0x85, 0x44, 0x2d,
0x51, 0x48, 0x5c, 0x04, 0x38, 0xb0, 0x67, 0xe4, 0x50, 0x0b, 0x2c, 0x07, 0x87, 0x9c, 0x32, 0xc8,
0x3d, 0xcb, 0xc1, 0xe8, 0x06, 0x74, 0xc6, 0x96, 0x6b, 0x7b, 0x13, 0x6d, 0xaa, 0x07, 0x87, 0x64,
0xd0, 0x28, 0x75, 0x98, 0x5b, 0x16, 0xb6, 0xcd, 0x9b, 0x6c, 0xae, 0xda, 0xe6, 0x6b, 0xf6, 0xe9,
0x12, 0xf4, 0x3c, 0xb4, 0xdd, 0x99, 0xa3, 0x79, 0x07, 0x9a, 0xef, 0x3d, 0xa6, 0x2e, 0xc7, 0x50,
0xb8, 0x33, 0xe7, 0xbd, 0x03, 0xd5, 0x7b, 0x4c, 0x43, 0x7f, 0x8b, 0x26, 0x01, 0x62, 0x7b, 0x13,
0x32, 0x68, 0x2e, 0xb4, 0x7f, 0xbc, 0x80, 0xae, 0x36, 0xa9, 0x99, 0xb1, 0xd5, 0xad, 0xc5, 0x56,
0x47, 0x0b, 0xd0, 0xcb, 0xd0, 0x33, 0x3c, 0x67, 0xaa, 0x33, 0x09, 0xdd, 0xf2, 0x3d, 0x87, 0xf9,
0x5b, 0x55, 0xcd, 0x40, 0xd1, 0x16, 0xb4, 0x2d, 0xd7, 0xc4, 0x1f, 0x0a, 0xa7, 0x6c, 0x33, 0x3c,
0x4a, 0x91, 0xca, 0x19, 0xa2, 0x5d, 0x3a, 0x97, 0x29, 0x1d, 0xac, 0xf0, 0x93, 0xd0, 0x8c, 0x14,
0xfa, 0x36, 0xb1, 0x3e, 0xc2, 0x83, 0x0e, 0xd7, 0xa2, 0x80, 0x8d, 0xac, 0x8f, 0x30, 0x2d, 0x92,
0x2d, 0x97, 0x60, 0x3f, 0xd0, 0x84, 0x51, 0x0e, 0xba, 0x2c, 0x6d, 0x75, 0x39, 0x54, 0xf8, 0x92,
0xf2, 0xdb, 0x0a, 0xf4, 0xd2, 0x88, 0xd0, 0x00, 0x96, 0x0f, 0x18, 0x24, 0xb4, 0x9e, 0xf0, 0x97,
0xa2, 0xc5, 0x2e, 0xed, 0xa0, 0x35, 0x46, 0x0b, 0x33, 0x9e, 0xa6, 0xda, 0xe6, 0x30, 0xb6, 0x01,
0x35, 0x02, 0xce, 0x1e, 0xcb, 0x94, 0x55, 0x86, 0xb2, 0xc5, 0x20, 0x2c, 0x4f, 0x0e, 0x60, 0x99,
0xb3, 0x11, 0x9a, 0x4e, 0xf8, 0x4b, 0x47, 0xc6, 0x33, 0x8b, 0x61, 0xe5, 0xa6, 0x13, 0xfe, 0xa2,
0x6d, 0xe8, 0xf0, 0x2d, 0xa7, 0xba, 0xaf, 0x3b, 0xa1, 0xe1, 0xbc, 0x58, 0xe8, 0xee, 0xb7, 0xf1,
0xf1, 0xfb, 0x34, 0x7a, 0xec, 0xeb, 0x96, 0xaf, 0x72, 0x41, 0xef, 0xb3, 0x55, 0x68, 0x0d, 0x64,
0xbe, 0xcb, 0x81, 0x65, 0x63, 0x61, 0x82, 0xcb, 0x2c, 0x19, 0xf7, 0x18, 0xfc, 0x96, 0x65, 0x63,
0x6e, 0x65, 0x11, 0x0b, 0x4c, 0xb4, 0x4d, 0x6e, 0x64, 0x0c, 0x42, 0x05, 0xab, 0xfc, 0xb5, 0x0a,
0x2b, 0xd4, 0xd7, 0x84, 0xdb, 0x9d, 0x22, 0x1a, 0x5d, 0x04, 0x30, 0x49, 0xa0, 0xa5, 0x22, 0x52,
0xcb, 0x24, 0xc1, 0x1e, 0x0f, 0x4a, 0x6f, 0x85, 0x01, 0xa7, 0x5a, 0x5e, 0xeb, 0x66, 0x7c, 0x3f,
0x9f, 0xdc, 0x9e, 0xaa, 0x1b, 0xbe, 0x0c, 0x5d, 0xe2, 0xcd, 0x7c, 0x03, 0x6b, 0xa9, 0xae, 0xa4,
0xc3, 0x81, 0x7b, 0xc5, 0x31, 0xb3, 0x51, 0xd8, 0x95, 0x27, 0xa2, 0xdb, 0xf2, 0xe9, 0x12, 0x5c,
0x33, 0x9b, 0xe0, 0x6e, 0x43, 0x9f, 0xb9, 0x9f, 0x36, 0xf5, 0x08, 0x6f, 0xee, 0x84, 0xd7, 0x66,
0xbc, 0x29, 0x3a, 0x85, 0xbb, 0x4b, 0x26, 0xfb, 0x62, 0xaa, 0xda, 0x63, 0x4b, 0xc3, 0x5f, 0xa2,
0xfc, 0xac, 0x02, 0xab, 0xa2, 0x59, 0x3c, 0xbd, 0x62, 0xcb, 0xd2, 0x4c, 0x18, 0x35, 0xab, 0x4f,
0x68, 0xbf, 0x6a, 0x0b, 0x94, 0x41, 0xf5, 0x82, 0x32, 0x28, 0xdd, 0x82, 0x34, 0x72, 0x2d, 0xc8,
0x75, 0xa8, 0x13, 0xc3, 0x9b, 0x62, 0xa6, 0x86, 0xde, 0xe6, 0xc5, 0x22, 0x35, 0x6c, 0xeb, 0x81,
0x3e, 0xa2, 0x93, 0x54, 0x3e, 0x57, 0xf9, 0x87, 0x04, 0xdd, 0x11, 0xd6, 0x7d, 0xe3, 0x30, 0x14,
0xc6, 0x1b, 0x50, 0xf5, 0xf1, 0x23, 0x21, 0x8b, 0x97, 0x4a, 0x04, 0x9d, 0x5a, 0xa2, 0xd2, 0x05,
0xe8, 0x05, 0x68, 0x9b, 0x8e, 0x1d, 0xc5, 0xa2, 0x0a, 0x0b, 0x0c, 0x60, 0x3a, 0xb6, 0x08, 0x44,
0x19, 0xfa, 0xab, 0x39, 0xfa, 0xd7, 0xe1, 0xcc, 0x81, 0xef, 0x39, 0x1a, 0xab, 0xd3, 0x35, 0x9b,
0x95, 0xe7, 0x4c, 0x58, 0x4d, 0xb5, 0x4f, 0x07, 0x12, 0x55, 0x7b, 0xcc, 0x6b, 0xfd, 0x04, 0xbc,
0xfe, 0x53, 0x82, 0xce, 0xb7, 0xe8, 0x50, 0xc8, 0xea, 0x9b, 0x49, 0x56, 0x5f, 0x2e, 0x61, 0x55,
0xc5, 0x81, 0x6f, 0xe1, 0x23, 0xfc, 0x5f, 0xc6, 0xec, 0x9f, 0x25, 0x18, 0x8e, 0x8e, 0x5d, 0x43,
0xe5, 0xde, 0x74, 0x7a, 0x93, 0xbf, 0x0c, 0xdd, 0xa3, 0x54, 0x93, 0xc4, 0x99, 0xee, 0x1c, 0x25,
0xbb, 0x24, 0x15, 0xe4, 0xb0, 0x16, 0x12, 0xcc, 0x86, 0xc1, 0xed, 0x95, 0x22, 0xaa, 0x33, 0xc4,
0xb1, 0xe0, 0xd0, 0xf7, 0xd3, 0x40, 0xc5, 0x87, 0x95, 0x82, 0x79, 0xe8, 0x3c, 0x2c, 0x8b, 0x86,
0x4c, 0x24, 0x31, 0xee, 0x83, 0x26, 0xcd, 0x61, 0xf1, 0x91, 0x82, 0x65, 0xe6, 0x0b, 0x20, 0x93,
0xaa, 0x2f, 0xaa, 0x9c, 0xcd, 0x9c, 0x7a, 0x4c, 0xa2, 0xfc, 0x41, 0x82, 0xd5, 0x77, 0x75, 0xd7,
0xf4, 0x0e, 0x0e, 0x4e, 0x2f, 0xb9, 0x2d, 0x48, 0x15, 0xd5, 0x8b, 0xb6, 0xeb, 0xa9, 0x45, 0xe8,
0x55, 0x38, 0xe3, 0xf3, 0xe8, 0x65, 0xa6, 0x45, 0x5b, 0x55, 0xe5, 0x70, 0x20, 0x12, 0xd9, 0x6f,
0x2a, 0x80, 0x68, 0xc4, 0xbd, 0xa9, 0xdb, 0xba, 0x6b, 0xe0, 0xa7, 0x27, 0xfd, 0x0a, 0xf4, 0x52,
0x79, 0x22, 0x3a, 0xd9, 0x4f, 0x26, 0x0a, 0x82, 0x6e, 0x43, 0x6f, 0xcc, 0x51, 0x69, 0x3e, 0xd6,
0x89, 0xe7, 0xb2, 0x00, 0xd8, 0x2b, 0xee, 0xcc, 0xef, 0xf9, 0xd6, 0x64, 0x82, 0xfd, 0x2d, 0xcf,
0x35, 0x79, 0xa4, 0xee, 0x8e, 0x43, 0x32, 0xe9, 0x52, 0xe6, 0x5b, 0x51, 0xd2, 0x0c, 0x3b, 0x42,
0x88, 0xb2, 0x26, 0x13, 0x05, 0xc1, 0xba, 0x1d, 0x0b, 0x22, 0x8e, 0x98, 0x32, 0x1f, 0x18, 0x95,
0x1f, 0xcc, 0x14, 0x24, 0x31, 0xe5, 0x77, 0x12, 0xa0, 0xa8, 0x37, 0x62, 0xdd, 0x08, 0xb3, 0xb0,
0xec, 0x52, 0xa9, 0x20, 0x70, 0x5f, 0x80, 0x96, 0x19, 0xae, 0x14, 0x1e, 0x11, 0x03, 0xa8, 0xcf,
0x70, 0x36, 0x34, 0x9a, 0xf1, 0xb0, 0x19, 0x56, 0xda, 0x1c, 0x78, 0x87, 0xc1, 0xd2, 0x39, 0xb0,
0x96, 0xcd, 0x81, 0xc9, 0x73, 0x87, 0x7a, 0xea, 0xdc, 0x41, 0xf9, 0xa4, 0x02, 0x32, 0x8b, 0x67,
0x5b, 0x71, 0x53, 0xb2, 0x10, 0xd1, 0x97, 0xa1, 0x2b, 0xee, 0xbe, 0x52, 0x84, 0x77, 0x1e, 0x25,
0x36, 0x43, 0xd7, 0xe0, 0x2c, 0x9f, 0xe4, 0x63, 0x32, 0xb3, 0xe3, 0x22, 0x93, 0x57, 0x7c, 0xe8,
0x11, 0x0f, 0xa4, 0x74, 0x28, 0x5c, 0x71, 0x1f, 0x56, 0x27, 0xb6, 0x37, 0xd6, 0x6d, 0x2d, 0xad,
0x9e, 0x92, 0x86, 0x2a, 0x6f, 0xf1, 0x67, 0xf9, 0xf2, 0x51, 0x52, 0x87, 0x04, 0xed, 0xd0, 0x36,
0x17, 0x3f, 0x8c, 0x8a, 0x00, 0x71, 0xa4, 0xbc, 0x48, 0x0d, 0xd0, 0xa1, 0x0b, 0xc3, 0x3f, 0xe5,
0x63, 0x09, 0xfa, 0x99, 0xa3, 0xc3, 0x6c, 0xb3, 0x24, 0xe5, 0x9b, 0xa5, 0x37, 0xa1, 0x4e, 0x3b,
0x08, 0x1e, 0xef, 0x7a, 0xc5, 0x85, 0x7c, 0x7a, 0x57, 0x95, 0x2f, 0x40, 0x57, 0x61, 0xa5, 0xe0,
0xa2, 0x45, 0xd8, 0x00, 0xca, 0xdf, 0xb3, 0x28, 0xbf, 0xaf, 0x41, 0x3b, 0x21, 0x8f, 0x39, 0x7d,
0xde, 0x22, 0x67, 0x41, 0x19, 0xf6, 0xaa, 0x79, 0xf6, 0x4a, 0x6e, 0x1a, 0xa8, 0xdd, 0x39, 0xd8,
0xe1, 0x15, 0xb2, 0x28, 0xd7, 0x1d, 0xec, 0xb0, 0xc6, 0x83, 0x9a, 0xe4, 0xcc, 0xe1, 0x1d, 0x1a,
0x77, 0xa7, 0x65, 0x77, 0xe6, 0xb0, 0xfe, 0x2c, 0xdd, 0x1c, 0x2c, 0x3f, 0xa1, 0x39, 0x68, 0xa6,
0x9b, 0x83, 0x94, 0x1f, 0xb5, 0xb2, 0x7e, 0xb4, 0x68, 0xeb, 0x75, 0x0d, 0x56, 0x0c, 0x1f, 0xeb,
0x01, 0x36, 0x6f, 0x1e, 0x6f, 0x45, 0x43, 0x83, 0x36, 0xcb, 0xab, 0x45, 0x43, 0xe8, 0x56, 0x7c,
0x86, 0xc2, 0xb5, 0xdc, 0x61, 0x5a, 0x2e, 0xee, 0x3d, 0x84, 0x6e, 0xb8, 0x92, 0xc3, 0xf0, 0xcc,
0xfe, 0xb2, 0x4d, 0x5f, 0xf7, 0xa9, 0x9a, 0xbe, 0x17, 0xa0, 0x1d, 0x9f, 0x24, 0x90, 0x41, 0x8f,
0x47, 0xbe, 0xe8, 0x28, 0x81, 0xa4, 0x82, 0x41, 0x3f, 0x1d, 0x0c, 0xfe, 0x52, 0x85, 0x5e, 0x5c,
0xee, 0x2f, 0x1c, 0x0a, 0x16, 0xb9, 0x30, 0xdc, 0x03, 0x39, 0x4e, 0xa8, 0x4c, 0x4a, 0x4f, 0xec,
0x58, 0xb2, 0xa7, 0xf3, 0xfd, 0x69, 0xc6, 0xe7, 0x52, 0xe7, 0x9f, 0xb5, 0x13, 0x9d, 0x7f, 0x9e,
0xf2, 0x5e, 0xe9, 0x3a, 0x9c, 0x8b, 0x92, 0x68, 0x8a, 0x6d, 0x5e, 0x4d, 0x9f, 0x0d, 0x07, 0xf7,
0x93, 0xec, 0x97, 0xb8, 0xf1, 0x72, 0x99, 0x1b, 0x67, 0xd5, 0xd8, 0xcc, 0xa9, 0x31, 0x7f, 0xbd,
0xd5, 0x2a, 0xba, 0xde, 0xba, 0x0f, 0x2b, 0xf7, 0x5d, 0x32, 0x1b, 0x13, 0xc3, 0xb7, 0xc6, 0x38,
0x3c, 0x1b, 0x5b, 0x48, 0xad, 0x43, 0x68, 0x8a, 0x78, 0xcd, 0x55, 0xda, 0x52, 0xa3, 0x7f, 0xe5,
0x87, 0x12, 0xac, 0xe6, 0xf7, 0x65, 0x16, 0x13, 0x07, 0x03, 0x29, 0x15, 0x0c, 0xbe, 0x03, 0x2b,
0xf1, 0xf6, 0x5a, 0x6a, 0xe7, 0x92, 0xca, 0xae, 0x80, 0x70, 0x15, 0xc5, 0x7b, 0x84, 0x30, 0xe5,
0x5f, 0x52, 0x74, 0xc2, 0x48, 0x61, 0x13, 0x76, 0x6e, 0x4a, 0x13, 0x94, 0xe7, 0xda, 0x96, 0x1b,
0xb5, 0xa7, 0x82, 0x47, 0x0e, 0x14, 0xed, 0xe9, 0xbb, 0xd0, 0x17, 0x93, 0xa2, 0x3c, 0xb3, 0x60,
0x65, 0xd5, 0xe3, 0xeb, 0xa2, 0x0c, 0x73, 0x05, 0x7a, 0xde, 0xc1, 0x41, 0x12, 0x1f, 0x0f, 0x94,
0x5d, 0x01, 0x15, 0x08, 0xbf, 0x09, 0x72, 0x38, 0xed, 0xa4, 0x99, 0xad, 0x2f, 0x16, 0x46, 0x15,
0xda, 0x0f, 0x24, 0x18, 0xa4, 0xf3, 0x5c, 0x82, 0xfd, 0x93, 0xd7, 0x69, 0x5f, 0x4b, 0x5f, 0x05,
0x5d, 0x79, 0x02, 0x3d, 0x31, 0x1e, 0x71, 0x96, 0xb0, 0xfe, 0x0d, 0x68, 0x45, 0xed, 0x03, 0x6a,
0xc3, 0xf2, 0x7d, 0xf7, 0xb6, 0xeb, 0x3d, 0x76, 0xe5, 0x25, 0xb4, 0x0c, 0xd5, 0x1b, 0xb6, 0x2d,
0x4b, 0xa8, 0x0b, 0xad, 0x51, 0xe0, 0x63, 0xdd, 0xb1, 0xdc, 0x89, 0x5c, 0x41, 0x3d, 0x80, 0x77,
0x2d, 0x12, 0x78, 0xbe, 0x65, 0xe8, 0xb6, 0x5c, 0x5d, 0xff, 0x08, 0x7a, 0x69, 0xaf, 0x47, 0x1d,
0x68, 0xee, 0x79, 0xc1, 0x3b, 0x1f, 0x5a, 0x24, 0x90, 0x97, 0xe8, 0xfc, 0x3d, 0x2f, 0xd8, 0xf7,
0x31, 0xc1, 0x6e, 0x20, 0x4b, 0x08, 0xa0, 0xf1, 0x9e, 0xbb, 0x6d, 0x91, 0x87, 0x72, 0x05, 0xad,
0x88, 0xa4, 0xac, 0xdb, 0xbb, 0xc2, 0x95, 0xe4, 0x2a, 0x5d, 0x1e, 0xfd, 0xd5, 0x90, 0x0c, 0x9d,
0x68, 0xca, 0xce, 0xfe, 0x7d, 0xb9, 0x8e, 0x5a, 0x50, 0xe7, 0x9f, 0x8d, 0x75, 0x13, 0xe4, 0x6c,
0x45, 0x49, 0xf7, 0xe4, 0x4c, 0x44, 0x20, 0x79, 0x89, 0x72, 0x26, 0x4a, 0x7a, 0x59, 0x42, 0x7d,
0x68, 0x27, 0x0a, 0x64, 0xb9, 0x42, 0x01, 0x3b, 0xfe, 0xd4, 0x10, 0xa5, 0x32, 0x27, 0x81, 0xea,
0x7d, 0x9b, 0x4a, 0xa2, 0xb6, 0x7e, 0x13, 0x9a, 0x61, 0x38, 0xa2, 0x53, 0x85, 0x88, 0xe8, 0xaf,
0xbc, 0x84, 0xce, 0x40, 0x37, 0x75, 0x29, 0x2f, 0x4b, 0x08, 0x41, 0x2f, 0xfd, 0x60, 0x42, 0xae,
0x6c, 0xfe, 0xa2, 0x03, 0xc0, 0xeb, 0x35, 0xcf, 0xf3, 0x4d, 0x34, 0x05, 0xb4, 0x83, 0x03, 0x9a,
0x8b, 0x3c, 0x37, 0xcc, 0x23, 0x04, 0x5d, 0x2b, 0x29, 0x6b, 0xf2, 0x53, 0x05, 0xa9, 0xc3, 0xb2,
0xc6, 0x35, 0x33, 0x5d, 0x59, 0x42, 0x0e, 0xc3, 0x78, 0xcf, 0x72, 0xf0, 0x3d, 0xcb, 0x78, 0x18,
0x15, 0x7a, 0xe5, 0x18, 0x33, 0x53, 0x43, 0x8c, 0x99, 0xb0, 0x2f, 0x7e, 0x46, 0x81, 0x6f, 0xb9,
0x93, 0xf0, 0x6a, 0x4f, 0x59, 0x42, 0x8f, 0xe0, 0xec, 0x0e, 0x66, 0xd8, 0x2d, 0x12, 0x58, 0x06,
0x09, 0x11, 0x6e, 0x96, 0x23, 0xcc, 0x4d, 0x3e, 0x21, 0x4a, 0x1b, 0xfa, 0x99, 0x87, 0x4d, 0x68,
0xbd, 0xf8, 0x76, 0xb0, 0xe8, 0x11, 0xd6, 0xf0, 0xd5, 0x85, 0xe6, 0x46, 0xd8, 0x2c, 0xe8, 0xa5,
0x1f, 0xef, 0xa0, 0xff, 0x2f, 0xdb, 0x20, 0xf7, 0x3e, 0x61, 0xb8, 0xbe, 0xc8, 0xd4, 0x08, 0xd5,
0x03, 0x6e, 0x4f, 0xf3, 0x50, 0x15, 0xbe, 0x0d, 0x19, 0x3e, 0xe9, 0x56, 0x55, 0x59, 0x42, 0xdf,
0x85, 0x33, 0xb9, 0x57, 0x14, 0xe8, 0x4b, 0xc5, 0xfd, 0x7a, 0xf1, 0x63, 0x8b, 0x79, 0x18, 0x1e,
0x64, 0xbd, 0xa1, 0x9c, 0xfa, 0xdc, 0xab, 0x9b, 0xc5, 0xa9, 0x4f, 0x6c, 0xff, 0x24, 0xea, 0x4f,
0x8c, 0x61, 0xc6, 0xdc, 0x26, 0xdb, 0x39, 0xbc, 0x56, 0x84, 0xa2, 0xf4, 0x29, 0xc7, 0x70, 0x63,
0xd1, 0xe9, 0x49, 0xeb, 0x4a, 0xbf, 0x16, 0x28, 0x16, 0x5a, 0xe1, 0x0b, 0x87, 0x62, 0xeb, 0x2a,
0x7e, 0x7c, 0xa0, 0x2c, 0xa1, 0x7b, 0xa9, 0x68, 0x88, 0x5e, 0x2e, 0x53, 0x4e, 0xfa, 0x3c, 0x61,
0x9e, 0xdc, 0x34, 0x80, 0x1d, 0x1c, 0xdc, 0xc5, 0x81, 0x6f, 0x19, 0x24, 0xbb, 0xa9, 0xf8, 0x89,
0x27, 0x84, 0x9b, 0xbe, 0x32, 0x77, 0x5e, 0x44, 0xf6, 0x18, 0xda, 0x3b, 0x38, 0x10, 0x87, 0x43,
0x04, 0x95, 0xae, 0x0c, 0x67, 0x84, 0x28, 0xd6, 0xe6, 0x4f, 0x4c, 0x46, 0x94, 0xcc, 0xe3, 0x05,
0x54, 0x2a, 0xdb, 0xfc, 0x93, 0x8a, 0xe2, 0x88, 0x52, 0xf2, 0x1a, 0x42, 0x59, 0xda, 0xfc, 0x37,
0x40, 0x8b, 0xa5, 0x08, 0x9a, 0x7a, 0xfe, 0x97, 0x21, 0x9e, 0x41, 0x86, 0xf8, 0x00, 0xfa, 0x99,
0xbb, 0xf0, 0x62, 0x7d, 0x16, 0x5f, 0x98, 0xcf, 0x33, 0xf9, 0x31, 0xa0, 0xfc, 0x6d, 0x76, 0x71,
0xa8, 0x28, 0xbd, 0xf5, 0x9e, 0x87, 0xe3, 0x7d, 0xfe, 0x9c, 0x24, 0xaa, 0x5e, 0x5f, 0x29, 0xf3,
0xd6, 0xcc, 0xc9, 0xe5, 0xe7, 0x1f, 0x48, 0x9f, 0x7d, 0xa2, 0xf9, 0x00, 0xfa, 0x99, 0x3b, 0x9e,
0x62, 0xed, 0x16, 0x5f, 0x04, 0xcd, 0xdb, 0xfd, 0x33, 0x8c, 0xc8, 0x26, 0xac, 0x14, 0x9c, 0xde,
0xa3, 0xc2, 0x2c, 0x52, 0x7e, 0xcc, 0x3f, 0x8f, 0xa1, 0x11, 0x34, 0xf8, 0x4d, 0x0e, 0x7a, 0xb1,
0xb8, 0x63, 0x48, 0xdc, 0xf2, 0x0c, 0xe7, 0xdd, 0x05, 0x91, 0x99, 0x1d, 0xf0, 0x4d, 0xeb, 0x2c,
0x84, 0xa1, 0xc2, 0x8b, 0xc0, 0xe4, 0x05, 0xcc, 0x70, 0xfe, 0x9d, 0x4b, 0xb8, 0xe9, 0xb3, 0xce,
0x25, 0x37, 0x5f, 0x7f, 0xb0, 0x39, 0xb1, 0x82, 0xc3, 0xd9, 0x98, 0x0a, 0xe9, 0x2a, 0x9f, 0xf9,
0x9a, 0xe5, 0x89, 0xaf, 0xab, 0x21, 0x69, 0x57, 0xd9, 0x4e, 0x57, 0x19, 0x2f, 0xd3, 0xf1, 0xb8,
0xc1, 0x7e, 0xaf, 0xff, 0x27, 0x00, 0x00, 0xff, 0xff, 0x98, 0x70, 0x46, 0x0e, 0x4c, 0x30, 0x00,
0x00,
0xb8, 0x20, 0x21, 0xc4, 0x8d, 0x2b, 0x12, 0x7f, 0x00, 0x47, 0x0e, 0x70, 0x45, 0x5c, 0xd1, 0xdb,
0x6a, 0x2f, 0x77, 0x8f, 0x27, 0x4e, 0x82, 0xc4, 0xad, 0xea, 0x7b, 0xcb, 0xb7, 0x6f, 0xef, 0x3d,
0x38, 0xf3, 0x68, 0x86, 0xfd, 0xe3, 0xe1, 0xd8, 0xf3, 0x7c, 0x73, 0x63, 0xea, 0x7b, 0x81, 0x87,
0x90, 0x63, 0xd9, 0x47, 0x33, 0xc2, 0xff, 0x36, 0xd8, 0x78, 0xbf, 0x35, 0xf6, 0x1c, 0xc7, 0x73,
0x39, 0xac, 0xdf, 0x8a, 0xcf, 0xe8, 0x77, 0x2c, 0x37, 0xc0, 0xbe, 0x6b, 0xd8, 0x72, 0x94, 0x8c,
0x0f, 0xb1, 0x63, 0x88, 0x3f, 0xd5, 0x34, 0x02, 0x23, 0xbe, 0xbf, 0xf6, 0x3d, 0x05, 0x56, 0x07,
0x87, 0xde, 0xe3, 0x2d, 0xcf, 0xb6, 0xf1, 0x38, 0xb0, 0x3c, 0x97, 0xe8, 0xf8, 0xd1, 0x0c, 0x93,
0x00, 0x5d, 0x83, 0xca, 0xc8, 0x20, 0xb8, 0xa7, 0x5c, 0x52, 0xd6, 0x9a, 0x9b, 0x17, 0x36, 0x12,
0x94, 0x08, 0x12, 0xee, 0x92, 0xc9, 0x4d, 0x83, 0x60, 0x9d, 0xcd, 0x44, 0x08, 0x2a, 0xe6, 0x68,
0x77, 0xbb, 0x57, 0xba, 0xa4, 0xac, 0x95, 0x75, 0xf6, 0x8d, 0x5e, 0x82, 0xf6, 0x38, 0xdc, 0x7b,
0x77, 0x9b, 0xf4, 0xca, 0x97, 0xca, 0x6b, 0x65, 0x3d, 0x09, 0xd4, 0xfe, 0xa6, 0xc0, 0xf9, 0x0c,
0x19, 0x64, 0xea, 0xb9, 0x04, 0xa3, 0xeb, 0x50, 0x23, 0x81, 0x11, 0xcc, 0x88, 0xa0, 0xe4, 0xff,
0x72, 0x29, 0x19, 0xb0, 0x29, 0xba, 0x98, 0x9a, 0x45, 0x5b, 0xca, 0x41, 0x8b, 0xbe, 0x0c, 0x67,
0x2d, 0xf7, 0x2e, 0x76, 0x3c, 0xff, 0x78, 0x38, 0xc5, 0xfe, 0x18, 0xbb, 0x81, 0x31, 0xc1, 0x92,
0xc6, 0x15, 0x39, 0xb6, 0x1f, 0x0d, 0xa1, 0x37, 0xe0, 0x3c, 0xd7, 0x12, 0xc1, 0xfe, 0x91, 0x35,
0xc6, 0x43, 0xe3, 0xc8, 0xb0, 0x6c, 0x63, 0x64, 0xe3, 0x5e, 0xe5, 0x52, 0x79, 0xad, 0xae, 0x9f,
0x63, 0xc3, 0x03, 0x3e, 0x7a, 0x43, 0x0e, 0x6a, 0xbf, 0x52, 0xe0, 0x1c, 0xe5, 0x70, 0xdf, 0xf0,
0x03, 0xeb, 0x19, 0xc8, 0x59, 0x83, 0x56, 0x9c, 0xb7, 0x5e, 0x99, 0x8d, 0x25, 0x60, 0x74, 0xce,
0x54, 0xa2, 0xa7, 0x32, 0xa9, 0x30, 0x36, 0x13, 0x30, 0xed, 0x97, 0xc2, 0x20, 0xe2, 0x74, 0x9e,
0x46, 0x11, 0x69, 0x9c, 0xa5, 0x2c, 0xce, 0xa7, 0x50, 0x83, 0xf6, 0x77, 0x05, 0xce, 0xdd, 0xf1,
0x0c, 0x33, 0x32, 0x98, 0xcf, 0x5e, 0x9c, 0x5f, 0x87, 0x1a, 0xf7, 0xae, 0x5e, 0x85, 0xe1, 0xba,
0x92, 0xc4, 0x25, 0x3c, 0x2f, 0xa2, 0x70, 0xc0, 0x00, 0xba, 0x58, 0x84, 0xae, 0x40, 0xc7, 0xc7,
0x53, 0xdb, 0x1a, 0x1b, 0x43, 0x77, 0xe6, 0x8c, 0xb0, 0xdf, 0xab, 0x5e, 0x52, 0xd6, 0xaa, 0x7a,
0x5b, 0x40, 0xf7, 0x18, 0x50, 0xfb, 0xb9, 0x02, 0x3d, 0x1d, 0xdb, 0xd8, 0x20, 0xf8, 0xf3, 0x64,
0x76, 0x15, 0x6a, 0xae, 0x67, 0xe2, 0xdd, 0x6d, 0xc6, 0x6c, 0x59, 0x17, 0x7f, 0xda, 0x8f, 0x4a,
0x5c, 0x11, 0x5f, 0x70, 0xbb, 0x8e, 0x29, 0xab, 0xfa, 0xe9, 0x28, 0xab, 0x96, 0xa7, 0xac, 0x3f,
0x45, 0xca, 0xfa, 0xa2, 0x0b, 0x24, 0x52, 0x68, 0x35, 0xa1, 0xd0, 0x5f, 0x2b, 0xf0, 0xdc, 0x0e,
0x0e, 0x42, 0xf2, 0xa9, 0x3f, 0xe3, 0x2f, 0x68, 0xb0, 0xfa, 0x44, 0x81, 0x7e, 0x1e, 0xad, 0xa7,
0x09, 0x58, 0x0f, 0x60, 0x35, 0xc4, 0x31, 0x34, 0x31, 0x19, 0xfb, 0xd6, 0x94, 0xa9, 0x91, 0x85,
0xae, 0xe6, 0xe6, 0xe5, 0x8d, 0x6c, 0x4a, 0xde, 0x48, 0x53, 0x70, 0x2e, 0xdc, 0x62, 0x3b, 0xb6,
0x83, 0xf6, 0x13, 0x05, 0xce, 0xed, 0xe0, 0x60, 0x80, 0x27, 0x0e, 0x76, 0x83, 0x5d, 0xf7, 0xc0,
0x7b, 0x7a, 0xb9, 0x3e, 0x0f, 0x40, 0xc4, 0x3e, 0x61, 0x58, 0x8d, 0x41, 0x16, 0x91, 0x31, 0xcb,
0xfe, 0x69, 0x7a, 0x4e, 0x23, 0xbb, 0xaf, 0x40, 0xd5, 0x72, 0x0f, 0x3c, 0x29, 0xaa, 0x17, 0xf2,
0x44, 0x15, 0x47, 0xc6, 0x67, 0x6b, 0x2e, 0xa7, 0xe2, 0xd0, 0xf0, 0xcd, 0x3b, 0xd8, 0x30, 0xb1,
0x7f, 0x0a, 0x73, 0x4b, 0xb3, 0x5d, 0xca, 0x61, 0xfb, 0xc7, 0x0a, 0x9c, 0xcf, 0x20, 0x3c, 0x0d,
0xdf, 0x6f, 0x43, 0x8d, 0xd0, 0xcd, 0x24, 0xe3, 0x2f, 0xe5, 0x32, 0x1e, 0x43, 0x77, 0xc7, 0x22,
0x81, 0x2e, 0xd6, 0x68, 0x1e, 0xa8, 0xe9, 0x31, 0xf4, 0x22, 0xb4, 0xc6, 0x87, 0x86, 0xeb, 0x62,
0x7b, 0xe8, 0x1a, 0x0e, 0x17, 0x40, 0x43, 0x6f, 0x0a, 0xd8, 0x9e, 0xe1, 0x60, 0xf4, 0x1c, 0xd4,
0xa9, 0xcb, 0x0e, 0x2d, 0x53, 0xaa, 0x7f, 0x99, 0xb9, 0xb0, 0x49, 0xd0, 0x45, 0x00, 0x36, 0x64,
0x98, 0xa6, 0xcf, 0xd3, 0x68, 0x43, 0x6f, 0x50, 0xc8, 0x0d, 0x0a, 0xd0, 0x7e, 0xaa, 0x40, 0x8b,
0xc6, 0xec, 0xbb, 0x38, 0x30, 0xa8, 0x1e, 0xd0, 0x5b, 0xd0, 0xb0, 0x3d, 0xc3, 0x1c, 0x06, 0xc7,
0x53, 0x8e, 0xaa, 0x93, 0x96, 0x35, 0x67, 0x81, 0x2e, 0xba, 0x77, 0x3c, 0xc5, 0x7a, 0xdd, 0x16,
0x5f, 0x8b, 0xc8, 0x3b, 0xe3, 0xca, 0xe5, 0x1c, 0x57, 0xfe, 0x7e, 0x15, 0x56, 0xbf, 0x6d, 0x04,
0xe3, 0xc3, 0x6d, 0x67, 0x8b, 0x33, 0x79, 0x0a, 0x23, 0x88, 0x62, 0x5b, 0x29, 0x1e, 0xdb, 0x3e,
0xb5, 0xd8, 0x19, 0xda, 0x79, 0x35, 0xcf, 0xce, 0x69, 0x91, 0xbd, 0xf1, 0xbe, 0x50, 0x55, 0xcc,
0xce, 0x63, 0x39, 0xa8, 0xf6, 0x34, 0x39, 0x68, 0x0b, 0xda, 0xf8, 0xc3, 0xb1, 0x3d, 0xa3, 0x3a,
0x67, 0xd8, 0x97, 0x19, 0xf6, 0xe7, 0x73, 0xb0, 0xc7, 0x9d, 0xac, 0x25, 0x16, 0xed, 0x0a, 0x1a,
0xb8, 0xaa, 0x1d, 0x1c, 0x18, 0xbd, 0x3a, 0x23, 0xe3, 0x52, 0x91, 0xaa, 0xa5, 0x7d, 0x70, 0x75,
0xd3, 0x3f, 0x74, 0x01, 0x1a, 0x22, 0xe3, 0xed, 0x6e, 0xf7, 0x1a, 0x4c, 0x7c, 0x11, 0x00, 0x19,
0xd0, 0x16, 0x11, 0x48, 0x50, 0x08, 0x8c, 0xc2, 0xb7, 0xf3, 0x10, 0xe4, 0x2b, 0x3b, 0x4e, 0x39,
0x79, 0xc7, 0x0d, 0xfc, 0x63, 0xbd, 0x45, 0x62, 0xa0, 0xfe, 0x10, 0xce, 0x64, 0xa6, 0x20, 0x15,
0xca, 0x0f, 0xf1, 0x31, 0x33, 0x90, 0xb2, 0x4e, 0x3f, 0xd1, 0xeb, 0x50, 0x3d, 0x32, 0xec, 0x19,
0x66, 0x06, 0x30, 0x5f, 0x46, 0x7c, 0xf2, 0x57, 0x4b, 0x6f, 0x2a, 0xda, 0xc7, 0x25, 0x78, 0x8e,
0xd3, 0x86, 0xed, 0xc0, 0xf8, 0x7c, 0x6d, 0x31, 0xb4, 0xb3, 0xca, 0x89, 0xec, 0xec, 0x22, 0x80,
0x2c, 0x56, 0x2c, 0x53, 0xa4, 0xf7, 0x50, 0x4b, 0x66, 0xd2, 0x04, 0x1a, 0x27, 0x35, 0x01, 0xed,
0x8f, 0x15, 0xe8, 0x0a, 0xd9, 0xd1, 0x19, 0x2c, 0x80, 0x5c, 0x80, 0x46, 0x98, 0x7a, 0x84, 0x1a,
0x22, 0x00, 0xba, 0x04, 0xcd, 0x98, 0xfb, 0x08, 0x39, 0xc4, 0x41, 0x0b, 0x09, 0x43, 0x16, 0x12,
0x95, 0x58, 0x21, 0x71, 0x11, 0xe0, 0xc0, 0x9e, 0x91, 0xc3, 0x61, 0x60, 0x39, 0x58, 0x72, 0xca,
0x20, 0xf7, 0x2c, 0x07, 0xa3, 0x1b, 0xd0, 0x1a, 0x59, 0xae, 0xed, 0x4d, 0x86, 0x53, 0x23, 0x38,
0x24, 0xbd, 0x5a, 0xa1, 0xc3, 0xdc, 0xb2, 0xb0, 0x6d, 0xde, 0x64, 0x73, 0xf5, 0x26, 0x5f, 0xb3,
0x4f, 0x97, 0xa0, 0xe7, 0xa1, 0xe9, 0xce, 0x9c, 0xa1, 0x77, 0x30, 0xf4, 0xbd, 0xc7, 0xd4, 0xe5,
0x18, 0x0a, 0x77, 0xe6, 0xbc, 0x77, 0xa0, 0x7b, 0x8f, 0x69, 0xe8, 0x6f, 0xd0, 0x24, 0x40, 0x6c,
0x6f, 0x42, 0x7a, 0xf5, 0x85, 0xf6, 0x8f, 0x16, 0xd0, 0xd5, 0x26, 0x35, 0x33, 0xb6, 0xba, 0xb1,
0xd8, 0xea, 0x70, 0x01, 0x7a, 0x19, 0x3a, 0x63, 0xcf, 0x99, 0x1a, 0x4c, 0x42, 0xb7, 0x7c, 0xcf,
0x61, 0xfe, 0x56, 0xd6, 0x53, 0x50, 0xb4, 0x05, 0x4d, 0xcb, 0x35, 0xf1, 0x87, 0xc2, 0x29, 0x9b,
0x0c, 0x8f, 0x96, 0xa7, 0x72, 0x86, 0x68, 0x97, 0xce, 0x65, 0x4a, 0x07, 0x4b, 0x7e, 0x12, 0x9a,
0x91, 0xa4, 0x6f, 0x13, 0xeb, 0x23, 0xdc, 0x6b, 0x71, 0x2d, 0x0a, 0xd8, 0xc0, 0xfa, 0x08, 0xd3,
0x22, 0xd9, 0x72, 0x09, 0xf6, 0x83, 0xa1, 0x30, 0xca, 0x5e, 0x9b, 0xa5, 0xad, 0x36, 0x87, 0x0a,
0x5f, 0xd2, 0x7e, 0x5b, 0x82, 0x4e, 0x12, 0x11, 0xea, 0xc1, 0xf2, 0x01, 0x83, 0x48, 0xeb, 0x91,
0xbf, 0x14, 0x2d, 0x76, 0x69, 0x07, 0x3d, 0x64, 0xb4, 0x30, 0xe3, 0xa9, 0xeb, 0x4d, 0x0e, 0x63,
0x1b, 0x50, 0x23, 0xe0, 0xec, 0xb1, 0x4c, 0x59, 0x66, 0x28, 0x1b, 0x0c, 0xc2, 0xf2, 0x64, 0x0f,
0x96, 0x39, 0x1b, 0xd2, 0x74, 0xe4, 0x2f, 0x1d, 0x19, 0xcd, 0x2c, 0x86, 0x95, 0x9b, 0x8e, 0xfc,
0x45, 0xdb, 0xd0, 0xe2, 0x5b, 0x4e, 0x0d, 0xdf, 0x70, 0xa4, 0xe1, 0xbc, 0x98, 0xeb, 0xee, 0xb7,
0xf1, 0xf1, 0xfb, 0x34, 0x7a, 0xec, 0x1b, 0x96, 0xaf, 0x73, 0x41, 0xef, 0xb3, 0x55, 0x68, 0x0d,
0x54, 0xbe, 0xcb, 0x81, 0x65, 0x63, 0x61, 0x82, 0xcb, 0x2c, 0x19, 0x77, 0x18, 0xfc, 0x96, 0x65,
0x63, 0x6e, 0x65, 0x21, 0x0b, 0x4c, 0xb4, 0x75, 0x6e, 0x64, 0x0c, 0x42, 0x05, 0xab, 0xfd, 0xb5,
0x0c, 0x2b, 0xd4, 0xd7, 0x84, 0xdb, 0x9d, 0x22, 0x1a, 0x5d, 0x04, 0x30, 0x49, 0x30, 0x4c, 0x44,
0xa4, 0x86, 0x49, 0x82, 0x3d, 0x1e, 0x94, 0xde, 0x92, 0x01, 0xa7, 0x5c, 0x5c, 0xeb, 0xa6, 0x7c,
0x3f, 0x9b, 0xdc, 0x9e, 0xaa, 0x1b, 0xbe, 0x0c, 0x6d, 0xe2, 0xcd, 0xfc, 0x31, 0x1e, 0x26, 0xba,
0x92, 0x16, 0x07, 0xee, 0xe5, 0xc7, 0xcc, 0x5a, 0x6e, 0x57, 0x1e, 0x8b, 0x6e, 0xcb, 0xa7, 0x4b,
0x70, 0xf5, 0x74, 0x82, 0xbb, 0x0d, 0x5d, 0xe6, 0x7e, 0xc3, 0xa9, 0x47, 0x78, 0x73, 0x27, 0xbc,
0x36, 0xe5, 0x4d, 0xe1, 0x29, 0xdc, 0x5d, 0x32, 0xd9, 0x17, 0x53, 0xf5, 0x0e, 0x5b, 0x2a, 0x7f,
0x89, 0xf6, 0xb3, 0x12, 0xac, 0x8a, 0x66, 0xf1, 0xf4, 0x8a, 0x2d, 0x4a, 0x33, 0x32, 0x6a, 0x96,
0x9f, 0xd0, 0x7e, 0x55, 0x16, 0x28, 0x83, 0xaa, 0x39, 0x65, 0x50, 0xb2, 0x05, 0xa9, 0x65, 0x5a,
0x90, 0xeb, 0x50, 0x25, 0x63, 0x6f, 0x8a, 0x99, 0x1a, 0x3a, 0x9b, 0x17, 0xf3, 0xd4, 0xb0, 0x6d,
0x04, 0xc6, 0x80, 0x4e, 0xd2, 0xf9, 0x5c, 0xed, 0x1f, 0x0a, 0xb4, 0x07, 0xd8, 0xf0, 0xc7, 0x87,
0x52, 0x18, 0x6f, 0x40, 0xd9, 0xc7, 0x8f, 0x84, 0x2c, 0x5e, 0x2a, 0x10, 0x74, 0x62, 0x89, 0x4e,
0x17, 0xd0, 0xd0, 0x61, 0x3a, 0xb6, 0x8c, 0x45, 0xbc, 0x48, 0x6e, 0xe8, 0x4d, 0xd3, 0xb1, 0x65,
0x56, 0x4f, 0x71, 0x50, 0xce, 0x70, 0xb0, 0x0e, 0x67, 0x0e, 0x7c, 0xcf, 0x19, 0xb2, 0x4a, 0x7d,
0x68, 0xb3, 0x02, 0x9d, 0x89, 0xab, 0xae, 0x77, 0xe9, 0x40, 0xac, 0x6e, 0x8f, 0xb8, 0xad, 0x9e,
0x80, 0xdb, 0x7f, 0x2a, 0xd0, 0xfa, 0x16, 0x1d, 0x92, 0xcc, 0xbe, 0x19, 0x67, 0xf6, 0xe5, 0x02,
0x66, 0x75, 0x1c, 0xf8, 0x16, 0x3e, 0xc2, 0xff, 0x75, 0xec, 0xfe, 0x59, 0x81, 0xfe, 0xe0, 0xd8,
0x1d, 0xeb, 0xdc, 0xa3, 0x4e, 0x6f, 0xf6, 0x97, 0xa1, 0x7d, 0x94, 0x68, 0x94, 0x4a, 0x2c, 0xfc,
0xb7, 0x8e, 0xe2, 0x9d, 0x92, 0x0e, 0xaa, 0xac, 0x87, 0x04, 0xb3, 0x32, 0xc0, 0xbd, 0x92, 0x47,
0x75, 0x8a, 0x38, 0x16, 0x20, 0xba, 0x7e, 0x12, 0xa8, 0xf9, 0xb0, 0x92, 0x33, 0x0f, 0x9d, 0x87,
0x65, 0xd1, 0x94, 0x89, 0x44, 0xc6, 0xfd, 0xd0, 0xa4, 0xda, 0x89, 0x8e, 0x15, 0x2c, 0x33, 0x5b,
0x04, 0x99, 0xe8, 0x05, 0x68, 0x86, 0xd5, 0xb3, 0x99, 0x51, 0x8f, 0x49, 0xb4, 0x3f, 0x28, 0xb0,
0xfa, 0xae, 0xe1, 0x9a, 0xde, 0xc1, 0xc1, 0xe9, 0x25, 0xb7, 0x05, 0x89, 0xc2, 0x7a, 0xd1, 0x96,
0x3d, 0xb1, 0x08, 0xbd, 0x0a, 0x67, 0x7c, 0x1e, 0xc1, 0xcc, 0xa4, 0x68, 0xcb, 0xba, 0x2a, 0x07,
0x42, 0x91, 0xfd, 0xa6, 0x04, 0x88, 0x46, 0xdd, 0x9b, 0x86, 0x6d, 0xb8, 0x63, 0xfc, 0xf4, 0xa4,
0x5f, 0x81, 0x4e, 0x22, 0x57, 0x84, 0xa7, 0xfb, 0xf1, 0x64, 0x41, 0xd0, 0x6d, 0xe8, 0x8c, 0x38,
0xaa, 0xa1, 0x8f, 0x0d, 0xe2, 0xb9, 0x2c, 0x08, 0x76, 0xf2, 0xbb, 0xf3, 0x7b, 0xbe, 0x35, 0x99,
0x60, 0x7f, 0xcb, 0x73, 0x4d, 0x1e, 0xad, 0xdb, 0x23, 0x49, 0x26, 0x5d, 0x4a, 0x95, 0x13, 0x25,
0x4e, 0xd9, 0x15, 0x42, 0x98, 0x39, 0x99, 0x28, 0x08, 0x36, 0xec, 0x48, 0x10, 0x51, 0xd4, 0x54,
0xf9, 0xc0, 0xa0, 0xf8, 0x70, 0x26, 0x27, 0x91, 0x69, 0xbf, 0x53, 0x00, 0x85, 0xfd, 0x11, 0xeb,
0x48, 0x98, 0x85, 0xa5, 0x97, 0x2a, 0x39, 0xc1, 0xfb, 0x02, 0x34, 0x4c, 0xb9, 0x52, 0x78, 0x44,
0x04, 0xa0, 0x3e, 0xc3, 0xd9, 0x18, 0xd2, 0xac, 0x87, 0x4d, 0x59, 0x6d, 0x73, 0xe0, 0x1d, 0x06,
0x4b, 0xe6, 0xc1, 0x4a, 0x3a, 0x0f, 0xc6, 0xcf, 0x1e, 0xaa, 0x89, 0xb3, 0x07, 0xed, 0x93, 0x12,
0xa8, 0x2c, 0xa2, 0x6d, 0x45, 0x8d, 0xc9, 0x42, 0x44, 0x5f, 0x86, 0xb6, 0xb8, 0xff, 0x4a, 0x10,
0xde, 0x7a, 0x14, 0xdb, 0x0c, 0x5d, 0x83, 0xb3, 0x7c, 0x92, 0x8f, 0xc9, 0xcc, 0x8e, 0x0a, 0x4d,
0x5e, 0xf5, 0xa1, 0x47, 0x3c, 0x94, 0xd2, 0x21, 0xb9, 0xe2, 0x3e, 0xac, 0x4e, 0x6c, 0x6f, 0x64,
0xd8, 0xc3, 0xa4, 0x7a, 0x0a, 0x9a, 0xaa, 0xac, 0xc5, 0x9f, 0xe5, 0xcb, 0x07, 0x71, 0x1d, 0x12,
0xb4, 0x43, 0x5b, 0x5d, 0xfc, 0x30, 0x2c, 0x04, 0xc4, 0xb1, 0xf2, 0x22, 0x75, 0x40, 0x8b, 0x2e,
0x94, 0x7f, 0xda, 0xc7, 0x0a, 0x74, 0x53, 0xc7, 0x87, 0xe9, 0x86, 0x49, 0xc9, 0x36, 0x4c, 0x6f,
0x42, 0x95, 0x76, 0x11, 0x3c, 0xde, 0x75, 0xf2, 0x8b, 0xf9, 0xe4, 0xae, 0x3a, 0x5f, 0x80, 0xae,
0xc2, 0x4a, 0xce, 0x65, 0x8b, 0xb0, 0x01, 0x94, 0xbd, 0x6b, 0xd1, 0x7e, 0x5f, 0x81, 0x66, 0x4c,
0x1e, 0x73, 0x7a, 0xbd, 0x45, 0xce, 0x83, 0x52, 0xec, 0x95, 0xb3, 0xec, 0x15, 0xdc, 0x36, 0x50,
0xbb, 0x73, 0xb0, 0xc3, 0xab, 0x64, 0x51, 0xb2, 0x3b, 0xd8, 0x61, 0xcd, 0x07, 0x35, 0xc9, 0x99,
0xc3, 0xbb, 0x34, 0xee, 0x4e, 0xcb, 0xee, 0xcc, 0x61, 0x3d, 0x5a, 0xb2, 0x41, 0x58, 0x7e, 0x42,
0x83, 0x50, 0x4f, 0x36, 0x08, 0x09, 0x3f, 0x6a, 0xa4, 0xfd, 0x68, 0xd1, 0xf6, 0xeb, 0x1a, 0xac,
0x8c, 0x7d, 0x6c, 0x04, 0xd8, 0xbc, 0x79, 0xbc, 0x15, 0x0e, 0xf5, 0x9a, 0x2c, 0xaf, 0xe6, 0x0d,
0xa1, 0x5b, 0xd1, 0x39, 0x0a, 0xd7, 0x72, 0x8b, 0x69, 0x39, 0xbf, 0xff, 0x10, 0xba, 0xe1, 0x4a,
0x96, 0xe1, 0x99, 0xfd, 0xa5, 0x1b, 0xbf, 0xf6, 0x53, 0x35, 0x7e, 0x2f, 0x40, 0x33, 0x3a, 0x4d,
0x20, 0xbd, 0x0e, 0x8f, 0x7c, 0xe1, 0x71, 0x02, 0x49, 0x04, 0x83, 0x6e, 0x32, 0x18, 0xfc, 0xa5,
0x0c, 0x9d, 0xa8, 0xe4, 0x5f, 0x38, 0x14, 0x2c, 0x72, 0x69, 0xb8, 0x07, 0x6a, 0x94, 0x50, 0x99,
0x94, 0x9e, 0xd8, 0xb5, 0xa4, 0x4f, 0xe8, 0xbb, 0xd3, 0x94, 0xcf, 0x25, 0xce, 0x40, 0x2b, 0x27,
0x3a, 0x03, 0x3d, 0xe5, 0xdd, 0xd2, 0x75, 0x38, 0x17, 0x26, 0xd1, 0x04, 0xdb, 0xbc, 0xa2, 0x3e,
0x2b, 0x07, 0xf7, 0xe3, 0xec, 0x17, 0xb8, 0xf1, 0x72, 0x91, 0x1b, 0xa7, 0xd5, 0x58, 0xcf, 0xa8,
0x31, 0x7b, 0xc5, 0xd5, 0xc8, 0xbb, 0xe2, 0xba, 0x0f, 0x2b, 0xf7, 0x5d, 0x32, 0x1b, 0x91, 0xb1,
0x6f, 0x8d, 0x70, 0x58, 0x5a, 0x2e, 0xa2, 0xd6, 0x3e, 0xd4, 0x53, 0xd5, 0x69, 0xf8, 0xaf, 0xfd,
0x50, 0x81, 0xd5, 0xec, 0xbe, 0xcc, 0x62, 0xa2, 0x60, 0xa0, 0x24, 0x82, 0xc1, 0x77, 0x60, 0x25,
0xda, 0x3e, 0x59, 0xf7, 0x16, 0x54, 0x76, 0x39, 0x84, 0xeb, 0x28, 0xda, 0x43, 0xc2, 0xb4, 0x7f,
0x29, 0xe1, 0x29, 0x23, 0x85, 0x4d, 0xd8, 0xd9, 0x29, 0x4d, 0x50, 0x9e, 0x6b, 0x5b, 0x6e, 0xd8,
0xa2, 0x0a, 0x1e, 0x39, 0x50, 0xb4, 0xa8, 0xef, 0x42, 0x57, 0x4c, 0x0a, 0xf3, 0xcc, 0x82, 0x95,
0x55, 0x87, 0xaf, 0x0b, 0x33, 0xcc, 0x15, 0xe8, 0x78, 0x07, 0x07, 0x71, 0x7c, 0x3c, 0x50, 0xb6,
0x05, 0x54, 0x20, 0xfc, 0x26, 0xa8, 0x72, 0xda, 0x49, 0x33, 0x5b, 0x57, 0x2c, 0x0c, 0x2b, 0xb4,
0x1f, 0x28, 0xd0, 0x4b, 0xe6, 0xb9, 0x18, 0xfb, 0x27, 0xaf, 0xd3, 0xbe, 0x96, 0xbc, 0x0e, 0xba,
0xf2, 0x04, 0x7a, 0x22, 0x3c, 0xe2, 0x3c, 0x61, 0xfd, 0x1b, 0xd0, 0x08, 0xdb, 0x07, 0xd4, 0x84,
0xe5, 0xfb, 0xee, 0x6d, 0xd7, 0x7b, 0xec, 0xaa, 0x4b, 0x68, 0x19, 0xca, 0x37, 0x6c, 0x5b, 0x55,
0x50, 0x1b, 0x1a, 0x83, 0xc0, 0xc7, 0x86, 0x63, 0xb9, 0x13, 0xb5, 0x84, 0x3a, 0x00, 0xef, 0x5a,
0x24, 0xf0, 0x7c, 0x6b, 0x6c, 0xd8, 0x6a, 0x79, 0xfd, 0x23, 0xe8, 0x24, 0xbd, 0x1e, 0xb5, 0xa0,
0xbe, 0xe7, 0x05, 0xef, 0x7c, 0x68, 0x91, 0x40, 0x5d, 0xa2, 0xf3, 0xf7, 0xbc, 0x60, 0xdf, 0xc7,
0x04, 0xbb, 0x81, 0xaa, 0x20, 0x80, 0xda, 0x7b, 0xee, 0xb6, 0x45, 0x1e, 0xaa, 0x25, 0xb4, 0x22,
0x92, 0xb2, 0x61, 0xef, 0x0a, 0x57, 0x52, 0xcb, 0x74, 0x79, 0xf8, 0x57, 0x41, 0x2a, 0xb4, 0xc2,
0x29, 0x3b, 0xfb, 0xf7, 0xd5, 0x2a, 0x6a, 0x40, 0x95, 0x7f, 0xd6, 0xd6, 0x4d, 0x50, 0xd3, 0x15,
0x25, 0xdd, 0x93, 0x33, 0x11, 0x82, 0xd4, 0x25, 0xca, 0x99, 0x28, 0xe9, 0x55, 0x05, 0x75, 0xa1,
0x19, 0x2b, 0x90, 0xd5, 0x12, 0x05, 0xec, 0xf8, 0xd3, 0xb1, 0x28, 0x95, 0x39, 0x09, 0x54, 0xef,
0xdb, 0x54, 0x12, 0x95, 0xf5, 0x9b, 0x50, 0x97, 0xe1, 0x88, 0x4e, 0x15, 0x22, 0xa2, 0xbf, 0xea,
0x12, 0x3a, 0x03, 0xed, 0xc4, 0xc5, 0xbc, 0xaa, 0x20, 0x04, 0x9d, 0xe4, 0xa3, 0x09, 0xb5, 0xb4,
0xf9, 0x8b, 0x16, 0x00, 0xaf, 0xd7, 0x3c, 0xcf, 0x37, 0xd1, 0x14, 0xd0, 0x0e, 0x0e, 0x68, 0x2e,
0xf2, 0x5c, 0x99, 0x47, 0x08, 0xba, 0x56, 0x50, 0xd6, 0x64, 0xa7, 0x0a, 0x52, 0xfb, 0x45, 0xad,
0x6b, 0x6a, 0xba, 0xb6, 0x84, 0x1c, 0x86, 0xf1, 0x9e, 0xe5, 0xe0, 0x7b, 0xd6, 0xf8, 0x61, 0x58,
0xe8, 0x15, 0x63, 0x4c, 0x4d, 0x95, 0x18, 0x53, 0x61, 0x5f, 0xfc, 0x0c, 0x02, 0xdf, 0x72, 0x27,
0xf2, 0x7a, 0x4f, 0x5b, 0x42, 0x8f, 0xe0, 0xec, 0x0e, 0x66, 0xd8, 0x2d, 0x12, 0x58, 0x63, 0x22,
0x11, 0x6e, 0x16, 0x23, 0xcc, 0x4c, 0x3e, 0x21, 0x4a, 0x1b, 0xba, 0xa9, 0xc7, 0x4d, 0x68, 0x3d,
0xff, 0x86, 0x30, 0xef, 0x21, 0x56, 0xff, 0xd5, 0x85, 0xe6, 0x86, 0xd8, 0x2c, 0xe8, 0x24, 0x1f,
0xf0, 0xa0, 0xff, 0x2f, 0xda, 0x20, 0xf3, 0x46, 0xa1, 0xbf, 0xbe, 0xc8, 0xd4, 0x10, 0xd5, 0x03,
0x6e, 0x4f, 0xf3, 0x50, 0xe5, 0xbe, 0x0f, 0xe9, 0x3f, 0xe9, 0x66, 0x55, 0x5b, 0x42, 0xdf, 0x85,
0x33, 0x99, 0x97, 0x14, 0xe8, 0x4b, 0xf9, 0xfd, 0x7a, 0xfe, 0x83, 0x8b, 0x79, 0x18, 0x1e, 0xa4,
0xbd, 0xa1, 0x98, 0xfa, 0xcc, 0xcb, 0x9b, 0xc5, 0xa9, 0x8f, 0x6d, 0xff, 0x24, 0xea, 0x4f, 0x8c,
0x61, 0xc6, 0xdc, 0x26, 0xdd, 0x39, 0xbc, 0x96, 0x87, 0xa2, 0xf0, 0x39, 0x47, 0x7f, 0x63, 0xd1,
0xe9, 0x71, 0xeb, 0x4a, 0xbe, 0x18, 0xc8, 0x17, 0x5a, 0xee, 0x2b, 0x87, 0x7c, 0xeb, 0xca, 0x7f,
0x80, 0xa0, 0x2d, 0xa1, 0x7b, 0x89, 0x68, 0x88, 0x5e, 0x2e, 0x52, 0x4e, 0xf2, 0x3c, 0x61, 0x9e,
0xdc, 0x86, 0x00, 0x3b, 0x38, 0xb8, 0x8b, 0x03, 0xdf, 0x1a, 0x93, 0xf4, 0xa6, 0xe2, 0x27, 0x9a,
0x20, 0x37, 0x7d, 0x65, 0xee, 0xbc, 0x90, 0xec, 0x11, 0x34, 0x77, 0x70, 0x20, 0x0e, 0x87, 0x08,
0x2a, 0x5c, 0x29, 0x67, 0x48, 0x14, 0x6b, 0xf3, 0x27, 0xc6, 0x23, 0x4a, 0xea, 0x01, 0x03, 0x2a,
0x94, 0x6d, 0xf6, 0x59, 0x45, 0x7e, 0x44, 0x29, 0x78, 0x11, 0xa1, 0x2d, 0x6d, 0xfe, 0x1b, 0xa0,
0xc1, 0x52, 0x04, 0x4d, 0x3d, 0xff, 0xcb, 0x10, 0xcf, 0x20, 0x43, 0x7c, 0x00, 0xdd, 0xd4, 0x7d,
0x78, 0xbe, 0x3e, 0xf3, 0x2f, 0xcd, 0xe7, 0x99, 0xfc, 0x08, 0x50, 0xf6, 0x46, 0x3b, 0x3f, 0x54,
0x14, 0xde, 0x7c, 0xcf, 0xc3, 0xf1, 0x3e, 0x7f, 0x52, 0x12, 0x56, 0xaf, 0xaf, 0x14, 0x79, 0x6b,
0xea, 0xe4, 0xf2, 0xf3, 0x0f, 0xa4, 0xcf, 0x3e, 0xd1, 0x7c, 0x00, 0xdd, 0xd4, 0x3d, 0x4f, 0xbe,
0x76, 0xf3, 0x2f, 0x83, 0xe6, 0xed, 0xfe, 0x19, 0x46, 0x64, 0x13, 0x56, 0x72, 0x4e, 0xef, 0x51,
0x6e, 0x16, 0x29, 0x3e, 0xe6, 0x9f, 0xc7, 0xd0, 0x00, 0x6a, 0xfc, 0x36, 0x07, 0xbd, 0x98, 0xdf,
0x31, 0xc4, 0x6e, 0x7a, 0xfa, 0xf3, 0xee, 0x83, 0xc8, 0xcc, 0x0e, 0xf8, 0xa6, 0x55, 0x16, 0xc2,
0x50, 0xee, 0x65, 0x60, 0xfc, 0x0a, 0xa6, 0x3f, 0xff, 0xd6, 0x45, 0x6e, 0xfa, 0xac, 0x73, 0xc9,
0xcd, 0xd7, 0x1f, 0x6c, 0x4e, 0xac, 0xe0, 0x70, 0x36, 0xa2, 0x42, 0xba, 0xca, 0x67, 0xbe, 0x66,
0x79, 0xe2, 0xeb, 0xaa, 0x24, 0xed, 0x2a, 0xdb, 0xe9, 0x2a, 0xe3, 0x65, 0x3a, 0x1a, 0xd5, 0xd8,
0xef, 0xf5, 0xff, 0x04, 0x00, 0x00, 0xff, 0xff, 0xab, 0x05, 0x7f, 0x12, 0x50, 0x30, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.

View File

@ -2663,7 +2663,7 @@ func (node *Proxy) Query(ctx context.Context, request *milvuspb.QueryRequest) (*
},
request: request,
qc: node.queryCoord,
queryShardPolicy: roundRobinPolicy,
queryShardPolicy: mergeRoundRobinPolicy,
shardMgr: node.shardMgr,
}
@ -3076,7 +3076,7 @@ func (node *Proxy) CalcDistance(ctx context.Context, request *milvuspb.CalcDista
qc: node.queryCoord,
ids: ids.IdArray,
queryShardPolicy: roundRobinPolicy,
queryShardPolicy: mergeRoundRobinPolicy,
shardMgr: node.shardMgr,
}

View File

@ -39,13 +39,21 @@ type QueryNodeMock struct {
withSearchResult *internalpb.SearchResults
withQueryResult *internalpb.RetrieveResults
queryError error
searchError error
}
func (m *QueryNodeMock) Search(ctx context.Context, req *querypb.SearchRequest) (*internalpb.SearchResults, error) {
if m.searchError != nil {
return nil, m.searchError
}
return m.withSearchResult, nil
}
func (m *QueryNodeMock) Query(ctx context.Context, req *querypb.QueryRequest) (*internalpb.RetrieveResults, error) {
if m.queryError != nil {
return nil, m.queryError
}
return m.withQueryResult, nil
}

View File

@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"sync"
"github.com/milvus-io/milvus/internal/log"
"github.com/milvus-io/milvus/internal/types"
@ -11,7 +12,9 @@ import (
"go.uber.org/zap"
)
type pickShardPolicy func(ctx context.Context, mgr *shardClientMgr, query func(UniqueID, types.QueryNode) error, leaders []nodeInfo) error
// type pickShardPolicy func(ctx context.Context, mgr *shardClientMgr, query func(UniqueID, types.QueryNode) error, leaders []nodeInfo) error
type pickShardPolicy func(context.Context, *shardClientMgr, func(context.Context, UniqueID, types.QueryNode, []string) error, map[string][]nodeInfo) error
var (
errBegin = errors.New("begin error")
@ -28,44 +31,115 @@ func updateShardsWithRoundRobin(shardsLeaders map[string][]nodeInfo) {
}
}
func roundRobinPolicy(ctx context.Context, mgr *shardClientMgr, query func(UniqueID, types.QueryNode) error, leaders []nodeInfo) error {
var (
err = errBegin
current = 0
qn types.QueryNode
)
replicaNum := len(leaders)
for err != nil && current < replicaNum {
currentID := leaders[current].nodeID
if err != errBegin {
log.Warn("retry with another QueryNode",
zap.Int("retries numbers", current),
zap.Int64("nodeID", currentID))
// group dml shard leader with same nodeID
func groupShardleadersWithSameQueryNode(
ctx context.Context,
shard2leaders map[string][]nodeInfo,
nexts map[string]int, errSet map[string]error,
mgr *shardClientMgr) (map[int64][]string, map[int64]types.QueryNode, error) {
// check if all leaders were checked
for dml, idx := range nexts {
if idx >= len(shard2leaders[dml]) {
log.Warn("no shard leaders were available",
zap.String("channel", dml),
zap.String("leaders", fmt.Sprintf("%v", shard2leaders[dml])))
if e, ok := errSet[dml]; ok {
return nil, nil, e // return last error recorded
}
return nil, nil, fmt.Errorf("no available shard leader")
}
qn, err = mgr.GetClient(ctx, leaders[current].nodeID)
if err != nil {
log.Warn("fail to get valid QueryNode", zap.Int64("nodeID", currentID),
zap.Error(err))
current++
continue
}
err = query(currentID, qn)
if err != nil {
log.Warn("fail to Query with shard leader",
zap.Int64("nodeID", currentID),
zap.Error(err))
}
current++
}
qnSet := make(map[int64]types.QueryNode)
node2dmls := make(map[int64][]string)
updates := make(map[string]int)
if current == replicaNum && err != nil {
log.Warn("no shard leaders available",
zap.String("leaders", fmt.Sprintf("%v", leaders)), zap.Error(err))
// needs to return the error from query
return err
for dml, idx := range nexts {
updates[dml] = idx + 1
nodeInfo := shard2leaders[dml][idx]
if _, ok := qnSet[nodeInfo.nodeID]; !ok {
qn, err := mgr.GetClient(ctx, nodeInfo.nodeID)
if err != nil {
log.Warn("failed to get shard leader", zap.Int64("nodeID", nodeInfo.nodeID), zap.Error(err))
// if get client failed, just record error and wait for next round to get client and do query
errSet[dml] = err
continue
}
qnSet[nodeInfo.nodeID] = qn
}
if _, ok := node2dmls[nodeInfo.nodeID]; !ok {
node2dmls[nodeInfo.nodeID] = make([]string, 0)
}
node2dmls[nodeInfo.nodeID] = append(node2dmls[nodeInfo.nodeID], dml)
}
// update idxes
for dml, idx := range updates {
nexts[dml] = idx
}
return node2dmls, qnSet, nil
}
// mergeRoundRobinPolicy first group shard leaders with same querynode, then do the query with multiple dml channels
// if request failed, it finds shard leader for failed dml channels, and again groups shard leaders and do the query
//
// Suppose qn0 is the shard leader for dml-channel0 and dml-channel1, if search for dml-channel0 succeeded, but
// failed for dml-channel1. In this case, an error returned from qn0, and next shard leaders for dml-channel0 and dml-channel1 will be
// retrieved and dml-channel0 therefore will again be searched.
//
// TODO: In this senario, qn0 should return a partial success results for dml-channel0, and only retrys for dml-channel1
func mergeRoundRobinPolicy(
ctx context.Context,
mgr *shardClientMgr,
query func(context.Context, UniqueID, types.QueryNode, []string) error,
dml2leaders map[string][]nodeInfo) error {
nexts := make(map[string]int)
errSet := make(map[string]error) // record err for dml channels
for dml := range dml2leaders {
nexts[dml] = 0
}
for len(nexts) > 0 {
node2dmls, nodeset, err := groupShardleadersWithSameQueryNode(ctx, dml2leaders, nexts, errSet, mgr)
if err != nil {
return err
}
wg := &sync.WaitGroup{}
mu := &sync.Mutex{}
wg.Add(len(node2dmls))
for nodeID, channels := range node2dmls {
nodeID := nodeID
channels := channels
qn := nodeset[nodeID]
go func() {
defer wg.Done()
if err := query(ctx, nodeID, qn, channels); err != nil {
log.Warn("failed to do query with node", zap.Int64("nodeID", nodeID),
zap.Strings("dmlChannels", channels), zap.Error(err))
mu.Lock()
defer mu.Unlock()
for _, ch := range channels {
errSet[ch] = err
}
return
}
mu.Lock()
defer mu.Unlock()
for _, channel := range channels {
delete(nexts, channel)
delete(errSet, channel)
}
}()
}
wg.Wait()
if len(nexts) > 0 {
nextSet := make(map[string]int64)
for dml, idx := range nexts {
if idx >= len(dml2leaders[dml]) {
nextSet[dml] = -1
} else {
nextSet[dml] = dml2leaders[dml][idx].nodeID
}
}
log.Warn("retry another query node with round robin", zap.Any("Nexts", nextSet))
}
}
return nil
}

View File

@ -3,15 +3,14 @@ package proxy
import (
"context"
"fmt"
"sort"
"sync"
"testing"
"github.com/milvus-io/milvus/internal/log"
"github.com/milvus-io/milvus/internal/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/milvus-io/milvus/internal/util/mock"
"go.uber.org/zap"
)
@ -54,89 +53,109 @@ func TestUpdateShardsWithRoundRobin(t *testing.T) {
})
}
func TestRoundRobinPolicy(t *testing.T) {
func TestGroupShardLeadersWithSameQueryNode(t *testing.T) {
var err error
Params.Init()
var (
ctx = context.TODO()
)
mockCreator := func(ctx context.Context, addr string) (types.QueryNode, error) {
return &mock.QueryNodeClient{}, nil
mgr := newShardClientMgr()
shard2leaders := map[string][]nodeInfo{
"c0": {{nodeID: 0, address: "fake"}, {nodeID: 1, address: "fake"}, {nodeID: 2, address: "fake"}},
"c1": {{nodeID: 1, address: "fake"}, {nodeID: 2, address: "fake"}, {nodeID: 3, address: "fake"}},
"c2": {{nodeID: 0, address: "fake"}, {nodeID: 2, address: "fake"}, {nodeID: 3, address: "fake"}},
"c3": {{nodeID: 1, address: "fake"}, {nodeID: 3, address: "fake"}, {nodeID: 4, address: "fake"}},
}
mgr.UpdateShardLeaders(nil, shard2leaders)
nexts := map[string]int{
"c0": 0,
"c1": 0,
"c2": 0,
"c3": 0,
}
errSet := map[string]error{}
node2dmls, qnSet, err := groupShardleadersWithSameQueryNode(ctx, shard2leaders, nexts, errSet, mgr)
assert.Nil(t, err)
for nodeID := range node2dmls {
sort.Slice(node2dmls[nodeID], func(i, j int) bool { return node2dmls[nodeID][i] < node2dmls[nodeID][j] })
}
mgr := newShardClientMgr(withShardClientCreator(mockCreator))
dummyLeaders := genShardLeaderInfo("c1", []UniqueID{-1, 1, 2, 3})
mgr.UpdateShardLeaders(nil, dummyLeaders)
t.Run("All fails", func(t *testing.T) {
allFailTests := []struct {
leaderIDs []UniqueID
cli0, err := mgr.GetClient(ctx, 0)
assert.Nil(t, err)
cli1, err := mgr.GetClient(ctx, 1)
assert.Nil(t, err)
cli2, err := mgr.GetClient(ctx, 2)
assert.Nil(t, err)
cli3, err := mgr.GetClient(ctx, 3)
assert.Nil(t, err)
description string
}{
{[]UniqueID{1}, "one invalid shard leader"},
{[]UniqueID{1, 2}, "two invalid shard leaders"},
{[]UniqueID{1, 1}, "two invalid same shard leaders"},
}
assert.Equal(t, node2dmls, map[int64][]string{0: {"c0", "c2"}, 1: {"c1", "c3"}})
assert.Equal(t, qnSet, map[int64]types.QueryNode{0: cli0, 1: cli1})
assert.Equal(t, nexts, map[string]int{"c0": 1, "c1": 1, "c2": 1, "c3": 1})
// delete client1 in client mgr
delete(mgr.clients.data, 1)
node2dmls, qnSet, err = groupShardleadersWithSameQueryNode(ctx, shard2leaders, nexts, errSet, mgr)
assert.Nil(t, err)
for nodeID := range node2dmls {
sort.Slice(node2dmls[nodeID], func(i, j int) bool { return node2dmls[nodeID][i] < node2dmls[nodeID][j] })
}
assert.Equal(t, node2dmls, map[int64][]string{2: {"c1", "c2"}, 3: {"c3"}})
assert.Equal(t, qnSet, map[int64]types.QueryNode{2: cli2, 3: cli3})
assert.Equal(t, nexts, map[string]int{"c0": 2, "c1": 2, "c2": 2, "c3": 2})
assert.NotNil(t, errSet["c0"])
for _, test := range allFailTests {
t.Run(test.description, func(t *testing.T) {
query := (&mockQuery{isvalid: false}).query
nexts["c0"] = 3
_, _, err = groupShardleadersWithSameQueryNode(ctx, shard2leaders, nexts, errSet, mgr)
assert.Equal(t, err, errSet["c0"])
leaders := make([]nodeInfo, 0, len(test.leaderIDs))
for _, ID := range test.leaderIDs {
leaders = append(leaders, nodeInfo{ID, "random-addr"})
nexts["c0"] = 2
nexts["c1"] = 3
_, _, err = groupShardleadersWithSameQueryNode(ctx, shard2leaders, nexts, errSet, mgr)
assert.Equal(t, err, fmt.Errorf("no available shard leader"))
}
}
func TestMergeRoundRobinPolicy(t *testing.T) {
var err error
err := roundRobinPolicy(ctx, mgr, query, leaders)
require.Error(t, err)
})
}
})
Params.Init()
var (
ctx = context.TODO()
)
t.Run("Pass at the first try", func(t *testing.T) {
allPassTests := []struct {
leaderIDs []UniqueID
mgr := newShardClientMgr()
description string
}{
{[]UniqueID{1}, "one valid shard leader"},
{[]UniqueID{1, 2}, "two valid shard leaders"},
{[]UniqueID{1, 1}, "two valid same shard leaders"},
}
shard2leaders := map[string][]nodeInfo{
"c0": {{nodeID: 0, address: "fake"}, {nodeID: 1, address: "fake"}, {nodeID: 2, address: "fake"}},
"c1": {{nodeID: 1, address: "fake"}, {nodeID: 2, address: "fake"}, {nodeID: 3, address: "fake"}},
"c2": {{nodeID: 0, address: "fake"}, {nodeID: 2, address: "fake"}, {nodeID: 3, address: "fake"}},
"c3": {{nodeID: 1, address: "fake"}, {nodeID: 3, address: "fake"}, {nodeID: 4, address: "fake"}},
}
mgr.UpdateShardLeaders(nil, shard2leaders)
for _, test := range allPassTests {
query := (&mockQuery{isvalid: true}).query
leaders := make([]nodeInfo, 0, len(test.leaderIDs))
for _, ID := range test.leaderIDs {
leaders = append(leaders, nodeInfo{ID, "random-addr"})
querier := &mockQuery{}
querier.init()
}
err := roundRobinPolicy(ctx, mgr, query, leaders)
require.NoError(t, err)
}
})
err = mergeRoundRobinPolicy(ctx, mgr, querier.query, shard2leaders)
assert.Nil(t, err)
assert.Equal(t, querier.records(), map[UniqueID][]string{0: {"c0", "c2"}, 1: {"c1", "c3"}})
t.Run("Pass at the second try", func(t *testing.T) {
passAtLast := []struct {
leaderIDs []UniqueID
mockerr := fmt.Errorf("mock query node error")
querier.init()
querier.failset[0] = mockerr
description string
}{
{[]UniqueID{-1, 2}, "invalid vs valid shard leaders"},
{[]UniqueID{-1, -1, 3}, "invalid, invalid, and valid shard leaders"},
}
err = mergeRoundRobinPolicy(ctx, mgr, querier.query, shard2leaders)
assert.Nil(t, err)
assert.Equal(t, querier.records(), map[int64][]string{1: {"c0", "c1", "c3"}, 2: {"c2"}})
for _, test := range passAtLast {
query := (&mockQuery{isvalid: true}).query
leaders := make([]nodeInfo, 0, len(test.leaderIDs))
for _, ID := range test.leaderIDs {
leaders = append(leaders, nodeInfo{ID, "random-addr"})
}
err := roundRobinPolicy(ctx, mgr, query, leaders)
require.NoError(t, err)
}
})
querier.init()
querier.failset[0] = mockerr
querier.failset[2] = mockerr
querier.failset[3] = mockerr
err = mergeRoundRobinPolicy(ctx, mgr, querier.query, shard2leaders)
assert.Equal(t, err, mockerr)
}
func mockQueryNodeCreator(ctx context.Context, address string) (types.QueryNode, error) {
@ -144,17 +163,35 @@ func mockQueryNodeCreator(ctx context.Context, address string) (types.QueryNode,
}
type mockQuery struct {
isvalid bool
mu sync.Mutex
queryset map[UniqueID][]string
failset map[UniqueID]error
}
func (m *mockQuery) query(nodeID UniqueID, qn types.QueryNode) error {
if nodeID == -1 {
return fmt.Errorf("error at condition")
func (m *mockQuery) query(_ context.Context, nodeID UniqueID, qn types.QueryNode, chs []string) error {
m.mu.Lock()
defer m.mu.Unlock()
if err, ok := m.failset[nodeID]; ok {
return err
}
if m.isvalid {
return nil
}
return fmt.Errorf("mock error in query, NodeID=%d", nodeID)
m.queryset[nodeID] = append(m.queryset[nodeID], chs...)
return nil
}
func (m *mockQuery) init() {
m.mu.Lock()
defer m.mu.Unlock()
m.queryset = make(map[int64][]string)
m.failset = make(map[int64]error)
}
func (m *mockQuery) records() map[UniqueID][]string {
m.mu.Lock()
defer m.mu.Unlock()
for nodeID := range m.queryset {
sort.Slice(m.queryset[nodeID], func(i, j int) bool {
return m.queryset[nodeID][i] < m.queryset[nodeID][j]
})
}
return m.queryset
}

View File

@ -6,13 +6,11 @@ import (
"fmt"
"strconv"
"strings"
"sync"
"github.com/milvus-io/milvus/internal/parser/planparserv2"
"github.com/golang/protobuf/proto"
"go.uber.org/zap"
"golang.org/x/sync/errgroup"
"github.com/milvus-io/milvus/internal/log"
"github.com/milvus-io/milvus/internal/metrics"
@ -48,8 +46,6 @@ type queryTask struct {
resultBuf chan *internalpb.RetrieveResults
toReduceResults []*internalpb.RetrieveResults
runningGroup *errgroup.Group
runningGroupCtx context.Context
queryShardPolicy pickShardPolicy
shardMgr *shardClientMgr
@ -92,7 +88,7 @@ func translateToOutputFieldIDs(outputFields []string, schema *schemapb.Collectio
func (t *queryTask) PreExecute(ctx context.Context) error {
if t.queryShardPolicy == nil {
t.queryShardPolicy = roundRobinPolicy
t.queryShardPolicy = mergeRoundRobinPolicy
}
t.Base.MsgType = commonpb.MsgType_Retrieve
@ -228,28 +224,11 @@ func (t *queryTask) Execute(ctx context.Context) error {
}
t.resultBuf = make(chan *internalpb.RetrieveResults, len(shards))
t.toReduceResults = make([]*internalpb.RetrieveResults, 0, len(shards))
t.runningGroup, t.runningGroupCtx = errgroup.WithContext(ctx)
for channelID, leaders := range shards {
channelID := channelID
leaders := leaders
t.runningGroup.Go(func() error {
log.Debug("proxy starting to query one shard",
zap.Int64("msgID", t.ID()),
zap.Int64("collectionID", t.CollectionID),
zap.String("collection name", t.collectionName),
zap.String("shard channel", channelID),
zap.Uint64("timeoutTs", t.TimeoutTimestamp))
err := t.queryShard(t.runningGroupCtx, leaders, channelID)
if err != nil {
return err
}
return nil
})
if err := t.queryShardPolicy(ctx, t.shardMgr, t.queryShard, shards); err != nil {
return err
}
err = t.runningGroup.Wait()
return err
return nil
}
err := executeQuery(WithCache)
@ -274,28 +253,19 @@ func (t *queryTask) PostExecute(ctx context.Context) error {
}()
var err error
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
for {
select {
case <-t.TraceCtx().Done():
log.Warn("proxy", zap.Int64("Query: wait to finish failed, timeout!, msgID:", t.ID()))
return
case <-t.runningGroupCtx.Done():
log.Debug("all queries are finished or canceled", zap.Int64("msgID", t.ID()))
close(t.resultBuf)
for res := range t.resultBuf {
t.toReduceResults = append(t.toReduceResults, res)
log.Debug("proxy receives one query result", zap.Int64("sourceID", res.GetBase().GetSourceID()), zap.Any("msgID", t.ID()))
}
wg.Done()
return
}
}
}()
wg.Wait()
select {
case <-t.TraceCtx().Done():
log.Warn("proxy", zap.Int64("Query: wait to finish failed, timeout!, msgID:", t.ID()))
return nil
default:
log.Debug("all queries are finished or canceled", zap.Int64("msgID", t.ID()))
close(t.resultBuf)
for res := range t.resultBuf {
t.toReduceResults = append(t.toReduceResults, res)
log.Debug("proxy receives one query result", zap.Int64("sourceID", res.GetBase().GetSourceID()), zap.Any("msgID", t.ID()))
}
}
metrics.ProxyDecodeResultLatency.WithLabelValues(strconv.FormatInt(Params.ProxyCfg.GetNodeID(), 10), metrics.QueryLabel).Observe(0.0)
tr.Record("reduceResultStart")
@ -336,44 +306,31 @@ func (t *queryTask) PostExecute(ctx context.Context) error {
return nil
}
func (t *queryTask) queryShard(ctx context.Context, leaders []nodeInfo, channelID string) error {
query := func(nodeID UniqueID, qn types.QueryNode) error {
req := &querypb.QueryRequest{
Req: t.RetrieveRequest,
DmlChannel: channelID,
Scope: querypb.DataScope_All,
}
result, err := qn.Query(ctx, req)
if err != nil {
log.Warn("QueryNode query return error", zap.Int64("msgID", t.ID()),
zap.Int64("nodeID", nodeID), zap.String("channel", channelID), zap.Error(err))
return err
}
if result.GetStatus().GetErrorCode() == commonpb.ErrorCode_NotShardLeader {
log.Warn("QueryNode is not shardLeader", zap.Int64("msgID", t.ID()),
zap.Int64("nodeID", nodeID), zap.String("channel", channelID))
return errInvalidShardLeaders
}
if result.GetStatus().GetErrorCode() != commonpb.ErrorCode_Success {
log.Warn("QueryNode query result error", zap.Int64("msgID", t.ID()),
zap.Int64("nodeID", nodeID), zap.String("reason", result.GetStatus().GetReason()))
return fmt.Errorf("fail to Query, QueryNode ID = %d, reason=%s", nodeID, result.GetStatus().GetReason())
}
log.Debug("get query result", zap.Int64("msgID", t.ID()),
zap.Int64("nodeID", nodeID), zap.String("channelID", channelID))
t.resultBuf <- result
return nil
func (t *queryTask) queryShard(ctx context.Context, nodeID int64, qn types.QueryNode, channelIDs []string) error {
req := &querypb.QueryRequest{
Req: t.RetrieveRequest,
DmlChannels: channelIDs,
Scope: querypb.DataScope_All,
}
err := t.queryShardPolicy(t.TraceCtx(), t.shardMgr, query, leaders)
result, err := qn.Query(ctx, req)
if err != nil {
log.Warn("fail to Query to all shard leaders", zap.Int64("msgID", t.ID()),
zap.Int64("taskID", t.ID()), zap.Any("shard leaders", leaders))
log.Warn("QueryNode query return error", zap.Int64("msgID", t.ID()),
zap.Int64("nodeID", nodeID), zap.Strings("channels", channelIDs), zap.Error(err))
return err
}
if result.GetStatus().GetErrorCode() == commonpb.ErrorCode_NotShardLeader {
log.Warn("QueryNode is not shardLeader", zap.Int64("nodeID", nodeID), zap.Strings("channels", channelIDs))
return errInvalidShardLeaders
}
if result.GetStatus().GetErrorCode() != commonpb.ErrorCode_Success {
log.Warn("QueryNode query result error", zap.Int64("msgID", t.ID()), zap.Int64("nodeID", nodeID),
zap.String("reason", result.GetStatus().GetReason()))
return fmt.Errorf("fail to Query, QueryNode ID = %d, reason=%s", nodeID, result.GetStatus().GetReason())
}
log.Debug("get query result", zap.Int64("msgID", t.ID()), zap.Int64("nodeID", nodeID), zap.Strings("channelIDs", channelIDs))
t.resultBuf <- result
return nil
}

View File

@ -39,6 +39,10 @@ func TestQueryTask_all(t *testing.T) {
expr = fmt.Sprintf("%s > 0", testInt64Field)
hitNum = 10
errPolicy = func(context.Context, *shardClientMgr, func(context.Context, int64, types.QueryNode, []string) error, map[string][]nodeInfo) error {
return fmt.Errorf("fake error")
}
)
mockCreator := func(ctx context.Context, address string) (types.QueryNode, error) {
@ -125,10 +129,8 @@ func TestQueryTask_all(t *testing.T) {
CollectionName: collectionName,
Expr: expr,
},
qc: qc,
queryShardPolicy: roundRobinPolicy,
shardMgr: mgr,
qc: qc,
shardMgr: mgr,
}
assert.NoError(t, task.OnEnqueue())
@ -143,6 +145,11 @@ func TestQueryTask_all(t *testing.T) {
// after preExecute
assert.Greater(t, task.TimeoutTimestamp, typeutil.ZeroTimestamp)
task.ctx = ctx
task.queryShardPolicy = errPolicy
assert.Error(t, task.Execute(ctx))
task.queryShardPolicy = mergeRoundRobinPolicy
result1 := &internalpb.RetrieveResults{
Base: &commonpb.MsgBase{MsgType: commonpb.MsgType_RetrieveResult},
Status: &commonpb.Status{
@ -164,9 +171,27 @@ func TestQueryTask_all(t *testing.T) {
result1.FieldsData = append(result1.FieldsData, generateFieldData(dataType, fieldName, hitNum))
}
task.ctx = ctx
qn.queryError = fmt.Errorf("mock error")
assert.Error(t, task.Execute(ctx))
qn.queryError = nil
qn.withQueryResult = &internalpb.RetrieveResults{
Status: &commonpb.Status{
ErrorCode: commonpb.ErrorCode_NotShardLeader,
},
}
assert.Equal(t, task.Execute(ctx), errInvalidShardLeaders)
qn.withQueryResult = &internalpb.RetrieveResults{
Status: &commonpb.Status{
ErrorCode: commonpb.ErrorCode_UnexpectedError,
},
}
assert.Error(t, task.Execute(ctx))
qn.withQueryResult = result1
task.ctx = ctx
assert.NoError(t, task.Execute(ctx))
assert.NoError(t, task.PostExecute(ctx))

View File

@ -6,13 +6,11 @@ import (
"fmt"
"regexp"
"strconv"
"sync"
"github.com/milvus-io/milvus/internal/parser/planparserv2"
"github.com/golang/protobuf/proto"
"go.uber.org/zap"
"golang.org/x/sync/errgroup"
"github.com/milvus-io/milvus/internal/log"
"github.com/milvus-io/milvus/internal/metrics"
@ -48,8 +46,6 @@ type searchTask struct {
resultBuf chan *internalpb.SearchResults
toReduceResults []*internalpb.SearchResults
runningGroup *errgroup.Group
runningGroupCtx context.Context
searchShardPolicy pickShardPolicy
shardMgr *shardClientMgr
@ -178,7 +174,7 @@ func (t *searchTask) PreExecute(ctx context.Context) error {
defer sp.Finish()
if t.searchShardPolicy == nil {
t.searchShardPolicy = roundRobinPolicy
t.searchShardPolicy = mergeRoundRobinPolicy
}
t.Base.MsgType = commonpb.MsgType_Search
@ -307,25 +303,11 @@ func (t *searchTask) Execute(ctx context.Context) error {
}
t.resultBuf = make(chan *internalpb.SearchResults, len(shard2Leaders))
t.toReduceResults = make([]*internalpb.SearchResults, 0, len(shard2Leaders))
t.runningGroup, t.runningGroupCtx = errgroup.WithContext(ctx)
// TODO: try to merge rpc send to different shard leaders.
// If two shard leader is on the same querynode maybe we should merge request to save rpc
for channelID, leaders := range shard2Leaders {
channelID := channelID
leaders := leaders
t.runningGroup.Go(func() error {
log.Debug("proxy starting to query one shard", zap.Int64("msgID", t.ID()),
zap.Int64("collectionID", t.CollectionID),
zap.String("collection name", t.collectionName),
zap.String("shard channel", channelID),
zap.Uint64("timeoutTs", t.TimeoutTimestamp))
return t.searchShard(t.runningGroupCtx, leaders, channelID)
})
if err := t.searchShardPolicy(ctx, t.shardMgr, t.searchShard, shard2Leaders); err != nil {
log.Warn("failed to do search", zap.Error(err), zap.String("Shards", fmt.Sprintf("%v", shard2Leaders)))
return err
}
err = t.runningGroup.Wait()
return err
return nil
}
err := executeSearch(WithCache)
@ -335,7 +317,7 @@ func (t *searchTask) Execute(ctx context.Context) error {
return executeSearch(WithoutCache)
}
if err != nil {
return fmt.Errorf("fail to search on all shard leaders, err=%w", err)
return fmt.Errorf("fail to search on all shard leaders, err=%v", err)
}
log.Debug("Search Execute done.", zap.Int64("msgID", t.ID()))
@ -350,28 +332,19 @@ func (t *searchTask) PostExecute(ctx context.Context) error {
tr.Elapse("done")
}()
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
for {
select {
case <-t.TraceCtx().Done():
log.Debug("wait to finish timeout!", zap.Int64("msgID", t.ID()))
return
case <-t.runningGroupCtx.Done():
log.Debug("all searches are finished or canceled", zap.Int64("msgID", t.ID()))
close(t.resultBuf)
for res := range t.resultBuf {
t.toReduceResults = append(t.toReduceResults, res)
log.Debug("proxy receives one query result", zap.Int64("sourceID", res.GetBase().GetSourceID()), zap.Int64("msgID", t.ID()))
}
wg.Done()
return
}
select {
// in case timeout happened
case <-t.TraceCtx().Done():
log.Debug("wait to finish timeout!", zap.Int64("msgID", t.ID()))
return nil
default:
log.Debug("all searches are finished or canceled", zap.Int64("msgID", t.ID()))
close(t.resultBuf)
for res := range t.resultBuf {
t.toReduceResults = append(t.toReduceResults, res)
log.Debug("proxy receives one query result", zap.Int64("sourceID", res.GetBase().GetSourceID()), zap.Int64("msgID", t.ID()))
}
}()
wg.Wait()
}
tr.Record("decodeResultStart")
validSearchResults, err := decodeSearchResults(t.toReduceResults)
if err != nil {
@ -434,40 +407,29 @@ func (t *searchTask) PostExecute(ctx context.Context) error {
return nil
}
func (t *searchTask) searchShard(ctx context.Context, leaders []nodeInfo, channelID string) error {
search := func(nodeID UniqueID, qn types.QueryNode) error {
req := &querypb.SearchRequest{
Req: t.SearchRequest,
DmlChannel: channelID,
Scope: querypb.DataScope_All,
}
result, err := qn.Search(ctx, req)
if err != nil {
log.Warn("QueryNode search return error", zap.Int64("msgID", t.ID()),
zap.Int64("nodeID", nodeID), zap.String("channel", channelID), zap.Error(err))
return err
}
if result.GetStatus().GetErrorCode() == commonpb.ErrorCode_NotShardLeader {
log.Warn("QueryNode is not shardLeader", zap.Int64("msgID", t.ID()),
zap.Int64("nodeID", nodeID), zap.String("channel", channelID))
return errInvalidShardLeaders
}
if result.GetStatus().GetErrorCode() != commonpb.ErrorCode_Success {
log.Warn("QueryNode search result error", zap.Int64("msgID", t.ID()),
zap.Int64("nodeID", nodeID), zap.String("reason", result.GetStatus().GetReason()))
return fmt.Errorf("fail to Search, QueryNode ID=%d, reason=%s", nodeID, result.GetStatus().GetReason())
}
t.resultBuf <- result
return nil
func (t *searchTask) searchShard(ctx context.Context, nodeID int64, qn types.QueryNode, channelIDs []string) error {
req := &querypb.SearchRequest{
Req: t.SearchRequest,
DmlChannels: channelIDs,
Scope: querypb.DataScope_All,
}
err := t.searchShardPolicy(t.TraceCtx(), t.shardMgr, search, leaders)
result, err := qn.Search(ctx, req)
if err != nil {
log.Warn("fail to search to all shard leaders", zap.Int64("msgID", t.ID()),
zap.Any("shard leaders", leaders))
log.Warn("QueryNode search return error", zap.Int64("msgID", t.ID()),
zap.Int64("nodeID", nodeID), zap.Strings("channels", channelIDs), zap.Error(err))
return err
}
if result.GetStatus().GetErrorCode() == commonpb.ErrorCode_NotShardLeader {
log.Warn("QueryNode is not shardLeader", zap.Int64("msgID", t.ID()),
zap.Int64("nodeID", nodeID), zap.Strings("channels", channelIDs))
return errInvalidShardLeaders
}
if result.GetStatus().GetErrorCode() != commonpb.ErrorCode_Success {
log.Warn("QueryNode search result error", zap.Int64("msgID", t.ID()), zap.Int64("nodeID", nodeID),
zap.String("reason", result.GetStatus().GetReason()))
return fmt.Errorf("fail to Search, QueryNode ID=%d, reason=%s", nodeID, result.GetStatus().GetReason())
}
t.resultBuf <- result
return nil
}

View File

@ -3,6 +3,7 @@ package proxy
import (
"context"
"errors"
"fmt"
"testing"
"time"
@ -10,6 +11,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/milvus-io/milvus/internal/common"
"github.com/milvus-io/milvus/internal/types"
"github.com/milvus-io/milvus/internal/proto/commonpb"
@ -52,10 +54,6 @@ func TestSearchTask_PostExecute(t *testing.T) {
// no result
qt.resultBuf <- &internalpb.SearchResults{}
mockctx, mockcancel := context.WithCancel(ctx)
qt.runningGroupCtx = mockctx
mockcancel()
err := qt.PostExecute(context.TODO())
assert.NoError(t, err)
assert.Equal(t, qt.result.Status.ErrorCode, commonpb.ErrorCode_Success)
@ -1591,3 +1589,148 @@ func Test_checkIfLoaded(t *testing.T) {
assert.False(t, loaded)
})
}
func TestSearchTask_ErrExecute(t *testing.T) {
Params.Init()
var (
err error
ctx = context.TODO()
rc = NewRootCoordMock()
qc = NewQueryCoordMock(withValidShardLeaders())
qn = &QueryNodeMock{}
shardsNum = int32(2)
collectionName = t.Name() + funcutil.GenRandomStr()
errPolicy = func(context.Context, *shardClientMgr, func(context.Context, int64, types.QueryNode, []string) error, map[string][]nodeInfo) error {
return fmt.Errorf("fake error")
}
)
mockCreator := func(ctx context.Context, address string) (types.QueryNode, error) {
return qn, nil
}
mgr := newShardClientMgr(withShardClientCreator(mockCreator))
rc.Start()
defer rc.Stop()
qc.Start()
defer qc.Stop()
err = InitMetaCache(rc, qc, mgr)
assert.NoError(t, err)
fieldName2Types := map[string]schemapb.DataType{
testBoolField: schemapb.DataType_Bool,
testInt32Field: schemapb.DataType_Int32,
testInt64Field: schemapb.DataType_Int64,
testFloatField: schemapb.DataType_Float,
testDoubleField: schemapb.DataType_Double,
testFloatVecField: schemapb.DataType_FloatVector,
}
if enableMultipleVectorFields {
fieldName2Types[testBinaryVecField] = schemapb.DataType_BinaryVector
}
schema := constructCollectionSchemaByDataType(collectionName, fieldName2Types, testInt64Field, false)
marshaledSchema, err := proto.Marshal(schema)
assert.NoError(t, err)
createColT := &createCollectionTask{
Condition: NewTaskCondition(ctx),
CreateCollectionRequest: &milvuspb.CreateCollectionRequest{
CollectionName: collectionName,
Schema: marshaledSchema,
ShardsNum: shardsNum,
},
ctx: ctx,
rootCoord: rc,
}
require.NoError(t, createColT.OnEnqueue())
require.NoError(t, createColT.PreExecute(ctx))
require.NoError(t, createColT.Execute(ctx))
require.NoError(t, createColT.PostExecute(ctx))
collectionID, err := globalMetaCache.GetCollectionID(ctx, collectionName)
assert.NoError(t, err)
status, err := qc.LoadCollection(ctx, &querypb.LoadCollectionRequest{
Base: &commonpb.MsgBase{
MsgType: commonpb.MsgType_LoadCollection,
SourceID: Params.ProxyCfg.GetNodeID(),
},
CollectionID: collectionID,
})
require.NoError(t, err)
require.Equal(t, commonpb.ErrorCode_Success, status.ErrorCode)
// test begins
task := &searchTask{
Condition: NewTaskCondition(ctx),
SearchRequest: &internalpb.SearchRequest{
Base: &commonpb.MsgBase{
MsgType: commonpb.MsgType_Retrieve,
SourceID: Params.ProxyCfg.GetNodeID(),
},
CollectionID: collectionID,
OutputFieldsId: make([]int64, len(fieldName2Types)),
},
ctx: ctx,
result: &milvuspb.SearchResults{
Status: &commonpb.Status{
ErrorCode: commonpb.ErrorCode_Success,
},
},
request: &milvuspb.SearchRequest{
Base: &commonpb.MsgBase{
MsgType: commonpb.MsgType_Retrieve,
SourceID: Params.ProxyCfg.GetNodeID(),
},
CollectionName: collectionName,
},
qc: qc,
shardMgr: mgr,
}
for i := 0; i < len(fieldName2Types); i++ {
task.SearchRequest.OutputFieldsId[i] = int64(common.StartOfUserFieldID + i)
}
assert.NoError(t, task.OnEnqueue())
task.ctx = ctx
assert.NoError(t, task.PreExecute(ctx))
task.searchShardPolicy = errPolicy
assert.Error(t, task.Execute(ctx))
task.searchShardPolicy = mergeRoundRobinPolicy
qn.searchError = fmt.Errorf("mock error")
assert.Error(t, task.Execute(ctx))
qn.searchError = nil
qn.withSearchResult = &internalpb.SearchResults{
Status: &commonpb.Status{
ErrorCode: commonpb.ErrorCode_NotShardLeader,
},
}
assert.Equal(t, task.Execute(ctx), errInvalidShardLeaders)
qn.withSearchResult = &internalpb.SearchResults{
Status: &commonpb.Status{
ErrorCode: commonpb.ErrorCode_UnexpectedError,
},
}
assert.Error(t, task.Execute(ctx))
result1 := &internalpb.SearchResults{
Status: &commonpb.Status{
ErrorCode: commonpb.ErrorCode_Success,
},
}
qn.withSearchResult = result1
assert.NoError(t, task.Execute(ctx))
}

View File

@ -76,7 +76,7 @@ func benchmarkQueryCollectionSearch(nq int64, b *testing.B) {
iReq, _ := genSearchRequest(nq, IndexFaissIDMap, collection.schema)
queryReq := &queryPb.SearchRequest{
Req: iReq,
DmlChannel: defaultDMLChannel,
DmlChannels: []string{defaultDMLChannel},
SegmentIDs: []UniqueID{defaultSegmentID},
FromShardLeader: true,
Scope: queryPb.DataScope_Historical,

View File

@ -19,8 +19,10 @@ package querynode
import (
"context"
"fmt"
"sync"
"go.uber.org/zap"
"golang.org/x/sync/errgroup"
"github.com/milvus-io/milvus/internal/common"
"github.com/milvus-io/milvus/internal/log"
@ -433,6 +435,61 @@ func (node *QueryNode) isHealthy() bool {
// Search performs replica search tasks.
func (node *QueryNode) Search(ctx context.Context, req *queryPb.SearchRequest) (*internalpb.SearchResults, error) {
log.Debug("Received SearchRequest",
zap.Int64("msgID", req.GetReq().GetBase().GetMsgID()),
zap.Strings("vChannels", req.GetDmlChannels()),
zap.Int64s("segmentIDs", req.GetSegmentIDs()),
zap.Uint64("guaranteeTimestamp", req.GetReq().GetGuaranteeTimestamp()),
zap.Uint64("timeTravel", req.GetReq().GetTravelTimestamp()))
failRet := &internalpb.SearchResults{
Status: &commonpb.Status{
ErrorCode: commonpb.ErrorCode_Success,
},
}
toReduceResults := make([]*internalpb.SearchResults, 0)
runningGp, runningCtx := errgroup.WithContext(ctx)
mu := &sync.Mutex{}
for _, ch := range req.GetDmlChannels() {
ch := ch
req := &querypb.SearchRequest{
Req: req.Req,
DmlChannels: []string{ch},
SegmentIDs: req.SegmentIDs,
FromShardLeader: req.FromShardLeader,
Scope: req.Scope,
}
runningGp.Go(func() error {
ret, err := node.searchWithDmlChannel(runningCtx, req, ch)
mu.Lock()
defer mu.Unlock()
if err != nil {
failRet.Status.Reason = err.Error()
failRet.Status.ErrorCode = commonpb.ErrorCode_UnexpectedError
return err
}
if ret.GetStatus().GetErrorCode() != commonpb.ErrorCode_Success {
failRet.Status.Reason = ret.Status.Reason
failRet.Status.ErrorCode = ret.Status.ErrorCode
return fmt.Errorf("%s", ret.Status.Reason)
}
toReduceResults = append(toReduceResults, ret)
return nil
})
}
if err := runningGp.Wait(); err != nil {
return failRet, nil
}
ret, err := reduceSearchResults(toReduceResults, req.Req.GetNq(), req.Req.GetTopk(), req.Req.GetMetricType())
if err != nil {
failRet.Status.ErrorCode = commonpb.ErrorCode_UnexpectedError
failRet.Status.Reason = err.Error()
return failRet, nil
}
return ret, nil
}
func (node *QueryNode) searchWithDmlChannel(ctx context.Context, req *queryPb.SearchRequest, dmlChannel string) (*internalpb.SearchResults, error) {
metrics.QueryNodeSQCount.WithLabelValues(fmt.Sprint(Params.QueryNodeCfg.GetNodeID()), metrics.SearchLabel, metrics.TotalLabel).Inc()
failRet := &internalpb.SearchResults{
Status: &commonpb.Status{
@ -454,7 +511,7 @@ func (node *QueryNode) Search(ctx context.Context, req *queryPb.SearchRequest) (
log.Debug("Received SearchRequest",
zap.Int64("msgID", msgID),
zap.Bool("fromShardLeader", req.GetFromShardLeader()),
zap.String("vChannel", req.GetDmlChannel()),
zap.String("vChannel", dmlChannel),
zap.Int64s("segmentIDs", req.GetSegmentIDs()),
zap.Uint64("guaranteeTimestamp", req.GetReq().GetGuaranteeTimestamp()),
zap.Uint64("timeTravel", req.GetReq().GetTravelTimestamp()))
@ -464,11 +521,11 @@ func (node *QueryNode) Search(ctx context.Context, req *queryPb.SearchRequest) (
return failRet, nil
}
qs, err := node.queryShardService.getQueryShard(req.GetDmlChannel())
qs, err := node.queryShardService.getQueryShard(dmlChannel)
if err != nil {
log.Warn("Search failed, failed to get query shard",
zap.Int64("msgID", msgID),
zap.String("dml channel", req.GetDmlChannel()),
zap.String("dml channel", dmlChannel),
zap.Error(err))
failRet.Status.ErrorCode = commonpb.ErrorCode_NotShardLeader
failRet.Status.Reason = err.Error()
@ -478,7 +535,7 @@ func (node *QueryNode) Search(ctx context.Context, req *queryPb.SearchRequest) (
log.Debug("start do search",
zap.Int64("msgID", msgID),
zap.Bool("fromShardLeader", req.GetFromShardLeader()),
zap.String("vChannel", req.GetDmlChannel()),
zap.String("vChannel", dmlChannel),
zap.Int64s("segmentIDs", req.GetSegmentIDs()))
tr := timerecord.NewTimeRecorder("")
@ -503,7 +560,7 @@ func (node *QueryNode) Search(ctx context.Context, req *queryPb.SearchRequest) (
}
tr.Elapse(fmt.Sprintf("do search done, msgID = %d, fromSharedLeader = %t, vChannel = %s, segmentIDs = %v",
msgID, req.GetFromShardLeader(), req.GetDmlChannel(), req.GetSegmentIDs()))
msgID, req.GetFromShardLeader(), dmlChannel, req.GetSegmentIDs()))
failRet.Status.ErrorCode = commonpb.ErrorCode_Success
metrics.QueryNodeSQLatencyInQueue.WithLabelValues(fmt.Sprint(Params.QueryNodeCfg.GetNodeID()),
@ -517,10 +574,10 @@ func (node *QueryNode) Search(ctx context.Context, req *queryPb.SearchRequest) (
}
//from Proxy
cluster, ok := qs.clusterService.getShardCluster(req.GetDmlChannel())
cluster, ok := qs.clusterService.getShardCluster(dmlChannel)
if !ok {
failRet.Status.ErrorCode = commonpb.ErrorCode_NotShardLeader
failRet.Status.Reason = fmt.Sprintf("channel %s leader is not here", req.GetDmlChannel())
failRet.Status.Reason = fmt.Sprintf("channel %s leader is not here", dmlChannel)
return failRet, nil
}
@ -563,7 +620,7 @@ func (node *QueryNode) Search(ctx context.Context, req *queryPb.SearchRequest) (
}
tr.Elapse(fmt.Sprintf("start reduce search result, msgID = %d, fromSharedLeader = %t, vChannel = %s, segmentIDs = %v",
msgID, req.GetFromShardLeader(), req.GetDmlChannel(), req.GetSegmentIDs()))
msgID, req.GetFromShardLeader(), dmlChannel, req.GetSegmentIDs()))
results = append(results, streamingResult)
ret, err2 := reduceSearchResults(results, req.Req.GetNq(), req.Req.GetTopk(), req.Req.GetMetricType())
@ -573,7 +630,7 @@ func (node *QueryNode) Search(ctx context.Context, req *queryPb.SearchRequest) (
}
tr.Elapse(fmt.Sprintf("do search done, msgID = %d, fromSharedLeader = %t, vChannel = %s, segmentIDs = %v",
msgID, req.GetFromShardLeader(), req.GetDmlChannel(), req.GetSegmentIDs()))
msgID, req.GetFromShardLeader(), dmlChannel, req.GetSegmentIDs()))
failRet.Status.ErrorCode = commonpb.ErrorCode_Success
latency := tr.ElapseSpan()
@ -584,8 +641,7 @@ func (node *QueryNode) Search(ctx context.Context, req *queryPb.SearchRequest) (
return ret, nil
}
// Query performs replica query tasks.
func (node *QueryNode) Query(ctx context.Context, req *queryPb.QueryRequest) (*internalpb.RetrieveResults, error) {
func (node *QueryNode) queryWithDmlChannel(ctx context.Context, req *queryPb.QueryRequest, dmlChannel string) (*internalpb.RetrieveResults, error) {
metrics.QueryNodeSQCount.WithLabelValues(fmt.Sprint(Params.QueryNodeCfg.GetNodeID()), metrics.QueryLabel, metrics.TotalLabel).Inc()
failRet := &internalpb.RetrieveResults{
Status: &commonpb.Status{
@ -607,7 +663,7 @@ func (node *QueryNode) Query(ctx context.Context, req *queryPb.QueryRequest) (*i
log.Debug("Received QueryRequest",
zap.Int64("msgID", msgID),
zap.Bool("fromShardLeader", req.GetFromShardLeader()),
zap.String("vChannel", req.GetDmlChannel()),
zap.String("vChannel", dmlChannel),
zap.Int64s("segmentIDs", req.GetSegmentIDs()),
zap.Uint64("guaranteeTimestamp", req.GetReq().GetGuaranteeTimestamp()),
zap.Uint64("timeTravel", req.GetReq().GetTravelTimestamp()))
@ -617,9 +673,9 @@ func (node *QueryNode) Query(ctx context.Context, req *queryPb.QueryRequest) (*i
return failRet, nil
}
qs, err := node.queryShardService.getQueryShard(req.GetDmlChannel())
qs, err := node.queryShardService.getQueryShard(dmlChannel)
if err != nil {
log.Warn("Query failed, failed to get query shard", zap.Int64("msgID", msgID), zap.String("dml channel", req.GetDmlChannel()), zap.Error(err))
log.Warn("Query failed, failed to get query shard", zap.Int64("msgID", msgID), zap.String("dml channel", dmlChannel), zap.Error(err))
failRet.Status.Reason = err.Error()
return failRet, nil
}
@ -627,7 +683,7 @@ func (node *QueryNode) Query(ctx context.Context, req *queryPb.QueryRequest) (*i
log.Debug("start do query",
zap.Int64("msgID", msgID),
zap.Bool("fromShardLeader", req.GetFromShardLeader()),
zap.String("vChannel", req.GetDmlChannel()),
zap.String("vChannel", dmlChannel),
zap.Int64s("segmentIDs", req.GetSegmentIDs()))
tr := timerecord.NewTimeRecorder("")
@ -649,7 +705,7 @@ func (node *QueryNode) Query(ctx context.Context, req *queryPb.QueryRequest) (*i
}
tr.Elapse(fmt.Sprintf("do query done, msgID = %d, fromSharedLeader = %t, vChannel = %s, segmentIDs = %v",
msgID, req.GetFromShardLeader(), req.GetDmlChannel(), req.GetSegmentIDs()))
msgID, req.GetFromShardLeader(), dmlChannel, req.GetSegmentIDs()))
failRet.Status.ErrorCode = commonpb.ErrorCode_Success
metrics.QueryNodeSQLatencyInQueue.WithLabelValues(fmt.Sprint(Params.QueryNodeCfg.GetNodeID()),
@ -662,10 +718,10 @@ func (node *QueryNode) Query(ctx context.Context, req *queryPb.QueryRequest) (*i
return queryTask.Ret, nil
}
cluster, ok := qs.clusterService.getShardCluster(req.GetDmlChannel())
cluster, ok := qs.clusterService.getShardCluster(dmlChannel)
if !ok {
failRet.Status.ErrorCode = commonpb.ErrorCode_NotShardLeader
failRet.Status.Reason = fmt.Sprintf("channel %s leader is not here", req.GetDmlChannel())
failRet.Status.Reason = fmt.Sprintf("channel %s leader is not here", dmlChannel)
return failRet, nil
}
@ -707,7 +763,7 @@ func (node *QueryNode) Query(ctx context.Context, req *queryPb.QueryRequest) (*i
}
tr.Elapse(fmt.Sprintf("start reduce query result, msgID = %d, fromSharedLeader = %t, vChannel = %s, segmentIDs = %v",
msgID, req.GetFromShardLeader(), req.GetDmlChannel(), req.GetSegmentIDs()))
msgID, req.GetFromShardLeader(), dmlChannel, req.GetSegmentIDs()))
results = append(results, streamingResult)
ret, err2 := mergeInternalRetrieveResults(results)
@ -717,7 +773,7 @@ func (node *QueryNode) Query(ctx context.Context, req *queryPb.QueryRequest) (*i
}
tr.Elapse(fmt.Sprintf("do query done, msgID = %d, fromSharedLeader = %t, vChannel = %s, segmentIDs = %v",
msgID, req.GetFromShardLeader(), req.GetDmlChannel(), req.GetSegmentIDs()))
msgID, req.GetFromShardLeader(), dmlChannel, req.GetSegmentIDs()))
failRet.Status.ErrorCode = commonpb.ErrorCode_Success
latency := tr.ElapseSpan()
@ -726,6 +782,63 @@ func (node *QueryNode) Query(ctx context.Context, req *queryPb.QueryRequest) (*i
return ret, nil
}
// Query performs replica query tasks.
func (node *QueryNode) Query(ctx context.Context, req *querypb.QueryRequest) (*internalpb.RetrieveResults, error) {
log.Debug("Received QueryRequest", zap.Int64("msgID", req.GetReq().GetBase().GetMsgID()),
zap.Strings("vChannels", req.GetDmlChannels()),
zap.Int64s("segmentIDs", req.GetSegmentIDs()),
zap.Uint64("guaranteeTimestamp", req.Req.GetGuaranteeTimestamp()),
zap.Uint64("timeTravel", req.GetReq().GetTravelTimestamp()))
failRet := &internalpb.RetrieveResults{
Status: &commonpb.Status{
ErrorCode: commonpb.ErrorCode_Success,
},
}
toMergeResults := make([]*internalpb.RetrieveResults, 0)
runningGp, runningCtx := errgroup.WithContext(ctx)
mu := &sync.Mutex{}
for _, ch := range req.GetDmlChannels() {
ch := ch
req := &querypb.QueryRequest{
Req: req.Req,
DmlChannels: []string{ch},
SegmentIDs: req.SegmentIDs,
FromShardLeader: req.FromShardLeader,
Scope: req.Scope,
}
runningGp.Go(func() error {
ret, err := node.queryWithDmlChannel(runningCtx, req, ch)
mu.Lock()
defer mu.Unlock()
if err != nil {
failRet.Status.Reason = err.Error()
failRet.Status.ErrorCode = commonpb.ErrorCode_UnexpectedError
return err
}
if ret.GetStatus().GetErrorCode() != commonpb.ErrorCode_Success {
failRet.Status.Reason = ret.Status.Reason
failRet.Status.ErrorCode = ret.Status.ErrorCode
return fmt.Errorf("%s", ret.Status.Reason)
}
toMergeResults = append(toMergeResults, ret)
return nil
})
}
if err := runningGp.Wait(); err != nil {
return failRet, nil
}
ret, err := mergeInternalRetrieveResults(toMergeResults)
if err != nil {
failRet.Status.ErrorCode = commonpb.ErrorCode_UnexpectedError
failRet.Status.Reason = err.Error()
return failRet, nil
}
return ret, nil
}
// SyncReplicaSegments syncs replica node & segments states
func (node *QueryNode) SyncReplicaSegments(ctx context.Context, req *querypb.SyncReplicaSegmentsRequest) (*commonpb.Status, error) {
if !node.isHealthy() {

View File

@ -477,15 +477,61 @@ func TestImpl_Search(t *testing.T) {
require.NoError(t, err)
node.queryShardService.addQueryShard(defaultCollectionID, defaultDMLChannel, defaultReplicaID)
node.ShardClusterService.addShardCluster(defaultCollectionID, defaultReplicaID, defaultDMLChannel)
// shard cluster not synced
_, err = node.Search(ctx, &queryPb.SearchRequest{
Req: req,
FromShardLeader: false,
DmlChannels: []string{defaultDMLChannel},
})
assert.NoError(t, err)
// shard cluster sync segments
sc, ok := node.ShardClusterService.getShardCluster(defaultDMLChannel)
assert.True(t, ok)
sc.SyncSegments(nil, segmentStateLoaded)
_, err = node.Search(ctx, &queryPb.SearchRequest{
Req: req,
FromShardLeader: false,
DmlChannel: defaultDMLChannel,
DmlChannels: []string{defaultDMLChannel},
})
assert.NoError(t, err)
}
func TestImpl_searchWithDmlChannel(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
node, err := genSimpleQueryNode(ctx)
require.NoError(t, err)
schema := genTestCollectionSchema()
req, err := genSearchRequest(defaultNQ, IndexFaissIDMap, schema)
require.NoError(t, err)
node.queryShardService.addQueryShard(defaultCollectionID, defaultDMLChannel, defaultReplicaID)
node.ShardClusterService.addShardCluster(defaultCollectionID, defaultReplicaID, defaultDMLChannel)
sc, ok := node.ShardClusterService.getShardCluster(defaultDMLChannel)
assert.True(t, ok)
sc.SyncSegments(nil, segmentStateLoaded)
_, err = node.searchWithDmlChannel(ctx, &queryPb.SearchRequest{
Req: req,
FromShardLeader: false,
DmlChannels: []string{defaultDMLChannel},
}, defaultDMLChannel)
assert.NoError(t, err)
// search for wrong dml channel
_, err = node.searchWithDmlChannel(ctx, &queryPb.SearchRequest{
Req: req,
FromShardLeader: false,
DmlChannels: []string{defaultDMLChannel + "_suffix"},
}, defaultDMLChannel)
assert.NoError(t, err)
}
func TestImpl_Query(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
@ -499,15 +545,62 @@ func TestImpl_Query(t *testing.T) {
require.NoError(t, err)
node.queryShardService.addQueryShard(defaultCollectionID, defaultDMLChannel, defaultReplicaID)
node.ShardClusterService.addShardCluster(defaultCollectionID, defaultReplicaID, defaultDMLChannel)
// shard cluster not synced
_, err = node.Query(ctx, &queryPb.QueryRequest{
Req: req,
FromShardLeader: false,
DmlChannels: []string{defaultDMLChannel},
})
assert.NoError(t, err)
// sync cluster segments
sc, ok := node.ShardClusterService.getShardCluster(defaultDMLChannel)
assert.True(t, ok)
sc.SyncSegments(nil, segmentStateLoaded)
_, err = node.Query(ctx, &queryPb.QueryRequest{
Req: req,
FromShardLeader: false,
DmlChannel: defaultDMLChannel,
DmlChannels: []string{defaultDMLChannel},
})
assert.NoError(t, err)
}
func TestImpl_queryWithDmlChannel(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
node, err := genSimpleQueryNode(ctx)
defer node.Stop()
require.NoError(t, err)
schema := genTestCollectionSchema()
req, err := genRetrieveRequest(schema)
require.NoError(t, err)
node.queryShardService.addQueryShard(defaultCollectionID, defaultDMLChannel, defaultReplicaID)
node.ShardClusterService.addShardCluster(defaultCollectionID, defaultReplicaID, defaultDMLChannel)
sc, ok := node.ShardClusterService.getShardCluster(defaultDMLChannel)
assert.True(t, ok)
sc.SyncSegments(nil, segmentStateLoaded)
_, err = node.queryWithDmlChannel(ctx, &queryPb.QueryRequest{
Req: req,
FromShardLeader: false,
DmlChannels: []string{defaultDMLChannel},
}, defaultDMLChannel)
assert.NoError(t, err)
// query for wrong dml channel
_, err = node.queryWithDmlChannel(ctx, &queryPb.QueryRequest{
Req: req,
FromShardLeader: false,
DmlChannels: []string{defaultDMLChannel + "_suffix"},
}, defaultDMLChannel)
assert.NoError(t, err)
}
func TestImpl_SyncReplicaSegments(t *testing.T) {
t.Run("QueryNode not healthy", func(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())

View File

@ -1449,7 +1449,7 @@ func genSearchPlanAndRequests(collection *Collection, indexType string, nq int64
iReq, _ := genSearchRequest(nq, indexType, collection.schema)
queryReq := &querypb.SearchRequest{
Req: iReq,
DmlChannel: defaultDMLChannel,
DmlChannels: []string{defaultDMLChannel},
SegmentIDs: []UniqueID{defaultSegmentID},
FromShardLeader: true,
Scope: querypb.DataScope_Historical,

View File

@ -22,8 +22,6 @@ import (
"fmt"
"sync"
"github.com/golang/protobuf/proto"
"go.uber.org/atomic"
"go.uber.org/zap"
@ -32,6 +30,7 @@ import (
"github.com/milvus-io/milvus/internal/proto/internalpb"
"github.com/milvus-io/milvus/internal/proto/querypb"
"github.com/milvus-io/milvus/internal/util/errorutil"
"github.com/milvus-io/milvus/internal/util/funcutil"
"github.com/milvus-io/milvus/internal/util/typeutil"
)
@ -724,9 +723,8 @@ func (sc *ShardCluster) Search(ctx context.Context, req *querypb.SearchRequest,
if !sc.serviceable() {
return nil, fmt.Errorf("ShardCluster for %s replicaID %d is no available", sc.vchannelName, sc.replicaID)
}
if sc.vchannelName != req.GetDmlChannel() {
return nil, fmt.Errorf("ShardCluster for %s does not match to request channel :%s", sc.vchannelName, req.GetDmlChannel())
if !funcutil.SliceContain(req.GetDmlChannels(), sc.vchannelName) {
return nil, fmt.Errorf("ShardCluster for %s does not match request channels :%v", sc.vchannelName, req.GetDmlChannels())
}
// get node allocation and maintains the inUse reference count
@ -766,10 +764,13 @@ func (sc *ShardCluster) Search(ctx context.Context, req *querypb.SearchRequest,
// dispatch request to followers
for nodeID, segments := range segAllocs {
nodeReq := proto.Clone(req).(*querypb.SearchRequest)
nodeReq.FromShardLeader = true
nodeReq.Scope = querypb.DataScope_Historical
nodeReq.SegmentIDs = segments
nodeReq := &querypb.SearchRequest{
Req: req.Req,
DmlChannels: req.DmlChannels,
FromShardLeader: true,
Scope: querypb.DataScope_Historical,
SegmentIDs: segments,
}
node, ok := sc.getNode(nodeID)
if !ok { // meta dismatch, report error
return nil, fmt.Errorf("ShardCluster for %s replicaID %d is no available", sc.vchannelName, sc.replicaID)
@ -808,8 +809,8 @@ func (sc *ShardCluster) Query(ctx context.Context, req *querypb.QueryRequest, wi
}
// handles only the dml channel part, segment ids is dispatch by cluster itself
if sc.vchannelName != req.GetDmlChannel() {
return nil, fmt.Errorf("ShardCluster for %s does not match to request channel :%s", sc.vchannelName, req.GetDmlChannel())
if !funcutil.SliceContain(req.GetDmlChannels(), sc.vchannelName) {
return nil, fmt.Errorf("ShardCluster for %s does not match to request channels :%v", sc.vchannelName, req.GetDmlChannels())
}
// get node allocation and maintains the inUse reference count
@ -844,10 +845,13 @@ func (sc *ShardCluster) Query(ctx context.Context, req *querypb.QueryRequest, wi
// dispatch request to followers
for nodeID, segments := range segAllocs {
nodeReq := proto.Clone(req).(*querypb.QueryRequest)
nodeReq.FromShardLeader = true
nodeReq.SegmentIDs = segments
nodeReq.Scope = querypb.DataScope_Historical
nodeReq := &querypb.QueryRequest{
Req: req.Req,
FromShardLeader: true,
SegmentIDs: segments,
Scope: querypb.DataScope_Historical,
DmlChannels: req.DmlChannels,
}
node, ok := sc.getNode(nodeID)
if !ok { // meta dismatch, report error
return nil, fmt.Errorf("SharcCluster for %s replicaID %d is no available", sc.vchannelName, sc.replicaID)

View File

@ -1018,7 +1018,7 @@ func TestShardCluster_Search(t *testing.T) {
require.EqualValues(t, unavailable, sc.state.Load())
_, err := sc.Search(ctx, &querypb.SearchRequest{
DmlChannel: vchannelName,
DmlChannels: []string{vchannelName},
}, streamingDoNothing)
assert.Error(t, err)
})
@ -1030,7 +1030,7 @@ func TestShardCluster_Search(t *testing.T) {
defer sc.Close()
_, err := sc.Search(ctx, &querypb.SearchRequest{
DmlChannel: vchannelName + "_suffix",
DmlChannels: []string{vchannelName + "_suffix"},
}, streamingDoNothing)
assert.Error(t, err)
})
@ -1079,7 +1079,7 @@ func TestShardCluster_Search(t *testing.T) {
require.EqualValues(t, available, sc.state.Load())
result, err := sc.Search(ctx, &querypb.SearchRequest{
DmlChannel: vchannelName,
DmlChannels: []string{vchannelName},
}, streamingDoNothing)
assert.NoError(t, err)
assert.Equal(t, len(nodeEvents), len(result))
@ -1129,7 +1129,7 @@ func TestShardCluster_Search(t *testing.T) {
require.EqualValues(t, available, sc.state.Load())
_, err := sc.Search(ctx, &querypb.SearchRequest{
DmlChannel: vchannelName,
DmlChannels: []string{vchannelName},
}, func(ctx context.Context) error { return errors.New("mocked") })
assert.Error(t, err)
})
@ -1186,7 +1186,7 @@ func TestShardCluster_Search(t *testing.T) {
require.EqualValues(t, available, sc.state.Load())
_, err := sc.Search(ctx, &querypb.SearchRequest{
DmlChannel: vchannelName,
DmlChannels: []string{vchannelName},
}, streamingDoNothing)
assert.Error(t, err)
})
@ -1238,7 +1238,7 @@ func TestShardCluster_Search(t *testing.T) {
require.EqualValues(t, available, sc.state.Load())
_, err := sc.Search(ctx, &querypb.SearchRequest{
DmlChannel: vchannelName,
DmlChannels: []string{vchannelName},
}, streamingDoNothing)
assert.Error(t, err)
})
@ -1296,7 +1296,7 @@ func TestShardCluster_Query(t *testing.T) {
require.EqualValues(t, unavailable, sc.state.Load())
_, err := sc.Query(ctx, &querypb.QueryRequest{
DmlChannel: vchannelName,
DmlChannels: []string{vchannelName},
}, streamingDoNothing)
assert.Error(t, err)
})
@ -1309,7 +1309,7 @@ func TestShardCluster_Query(t *testing.T) {
sc.SyncSegments(nil, segmentStateLoaded)
_, err := sc.Query(ctx, &querypb.QueryRequest{
DmlChannel: vchannelName + "_suffix",
DmlChannels: []string{vchannelName + "_suffix"},
}, streamingDoNothing)
assert.Error(t, err)
})
@ -1357,7 +1357,7 @@ func TestShardCluster_Query(t *testing.T) {
require.EqualValues(t, available, sc.state.Load())
result, err := sc.Query(ctx, &querypb.QueryRequest{
DmlChannel: vchannelName,
DmlChannels: []string{vchannelName},
}, streamingDoNothing)
assert.NoError(t, err)
assert.Equal(t, len(nodeEvents), len(result))
@ -1406,7 +1406,7 @@ func TestShardCluster_Query(t *testing.T) {
require.EqualValues(t, available, sc.state.Load())
_, err := sc.Query(ctx, &querypb.QueryRequest{
DmlChannel: vchannelName,
DmlChannels: []string{vchannelName},
}, func(ctx context.Context) error { return errors.New("mocked") })
assert.Error(t, err)
})
@ -1463,7 +1463,7 @@ func TestShardCluster_Query(t *testing.T) {
require.EqualValues(t, available, sc.state.Load())
_, err := sc.Query(ctx, &querypb.QueryRequest{
DmlChannel: vchannelName,
DmlChannels: []string{vchannelName},
}, streamingDoNothing)
assert.Error(t, err)
})
@ -1515,7 +1515,7 @@ func TestShardCluster_Query(t *testing.T) {
require.EqualValues(t, available, sc.state.Load())
_, err := sc.Query(ctx, &querypb.QueryRequest{
DmlChannel: vchannelName,
DmlChannels: []string{vchannelName},
}, streamingDoNothing)
assert.Error(t, err)
})

View File

@ -89,6 +89,10 @@ func (s *searchTask) searchOnStreaming() error {
return errors.New("search context timeout")
}
if len(s.req.GetDmlChannels()) <= 0 {
return errors.New("invalid nil dml channels")
}
// check if collection has been released, check streaming since it's released first
_, err := s.QS.metaReplica.getCollectionByID(s.CollectionID)
if err != nil {
@ -110,7 +114,7 @@ func (s *searchTask) searchOnStreaming() error {
defer searchReq.delete()
// TODO add context
partResults, _, _, sErr := searchStreaming(s.QS.metaReplica, searchReq, s.CollectionID, s.iReq.GetPartitionIDs(), s.req.GetDmlChannel())
partResults, _, _, sErr := searchStreaming(s.QS.metaReplica, searchReq, s.CollectionID, s.iReq.GetPartitionIDs(), s.req.GetDmlChannels()[0])
if sErr != nil {
log.Debug("failed to search streaming data", zap.Int64("msgID", s.ID()),
zap.Int64("collectionID", s.CollectionID), zap.Error(sErr))
@ -181,7 +185,10 @@ func (s *searchTask) estimateCPUUsage() {
if s.DataScope == querypb.DataScope_Streaming {
// assume growing segments num is 5
partitionIDs := s.iReq.GetPartitionIDs()
channel := s.req.GetDmlChannel()
channel := ""
if len(s.req.GetDmlChannels()) > 0 {
channel = s.req.GetDmlChannels()[0]
}
segIDs, err := s.QS.metaReplica.getSegmentIDsByVChannel(partitionIDs, channel, segmentTypeGrowing)
if err != nil {
log.Error("searchTask estimateCPUUsage", zap.Error(err))