mirror of
https://gitee.com/milvus-io/milvus.git
synced 2025-12-06 17:18:35 +08:00
enhance: streaming node client implementation (#34653)
issue: #33285 - add streaming node grpc client wrapper - add unittest for streaming node grpc client side - fix binary unsafe bug for message --------- Signed-off-by: chyezh <chyezh@outlook.com>
This commit is contained in:
parent
ed057e6fce
commit
86eff6e589
@ -580,6 +580,17 @@ dataNode:
|
||||
memoryBufferRatio: 0.1 # The ratio of memory buffer of clustering compaction. Data larger than threshold will be spilled to storage.
|
||||
workPoolSize: 8
|
||||
|
||||
streamingNode:
|
||||
# can specify ip for example
|
||||
# ip: 127.0.0.1
|
||||
ip: # if not specify address, will use the first unicastable address as local ip
|
||||
port: 19532
|
||||
grpc:
|
||||
serverMaxSendSize: 536870912
|
||||
serverMaxRecvSize: 536870912
|
||||
clientMaxSendSize: 268435456
|
||||
clientMaxRecvSize: 268435456
|
||||
|
||||
# Configures the system log output.
|
||||
log:
|
||||
level: info # Only supports debug, info, warn, error, panic, or fatal. Default 'info'.
|
||||
|
||||
@ -11,6 +11,15 @@ packages:
|
||||
github.com/milvus-io/milvus/internal/streamingnode/client/manager:
|
||||
interfaces:
|
||||
ManagerClient:
|
||||
github.com/milvus-io/milvus/internal/streamingnode/client/handler/assignment:
|
||||
interfaces:
|
||||
Watcher:
|
||||
github.com/milvus-io/milvus/internal/streamingnode/client/handler/producer:
|
||||
interfaces:
|
||||
Producer:
|
||||
github.com/milvus-io/milvus/internal/streamingnode/client/handler/consumer:
|
||||
interfaces:
|
||||
Consumer:
|
||||
github.com/milvus-io/milvus/internal/streamingnode/server/wal:
|
||||
interfaces:
|
||||
OpenerBuilder:
|
||||
@ -30,6 +39,10 @@ packages:
|
||||
StreamingNodeHandlerService_ConsumeServer:
|
||||
StreamingNodeHandlerService_ProduceServer:
|
||||
StreamingCoordAssignmentService_AssignmentDiscoverServer:
|
||||
StreamingNodeManagerServiceClient:
|
||||
StreamingNodeHandlerServiceClient:
|
||||
StreamingNodeHandlerService_ConsumeClient:
|
||||
StreamingNodeHandlerService_ProduceClient:
|
||||
github.com/milvus-io/milvus/internal/streamingnode/server/walmanager:
|
||||
interfaces:
|
||||
Manager:
|
||||
@ -40,9 +53,13 @@ packages:
|
||||
interfaces:
|
||||
Discoverer:
|
||||
AssignmentDiscoverWatcher:
|
||||
github.com/milvus-io/milvus/internal/util/streamingutil/service/lazygrpc:
|
||||
interfaces:
|
||||
Service:
|
||||
github.com/milvus-io/milvus/internal/util/streamingutil/service/resolver:
|
||||
interfaces:
|
||||
Resolver:
|
||||
Builder:
|
||||
google.golang.org/grpc/resolver:
|
||||
interfaces:
|
||||
ClientConn:
|
||||
|
||||
@ -0,0 +1,178 @@
|
||||
// Code generated by mockery v2.32.4. DO NOT EDIT.
|
||||
|
||||
package mock_streamingpb
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
grpc "google.golang.org/grpc"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
streamingpb "github.com/milvus-io/milvus/internal/proto/streamingpb"
|
||||
)
|
||||
|
||||
// MockStreamingNodeHandlerServiceClient is an autogenerated mock type for the StreamingNodeHandlerServiceClient type
|
||||
type MockStreamingNodeHandlerServiceClient struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type MockStreamingNodeHandlerServiceClient_Expecter struct {
|
||||
mock *mock.Mock
|
||||
}
|
||||
|
||||
func (_m *MockStreamingNodeHandlerServiceClient) EXPECT() *MockStreamingNodeHandlerServiceClient_Expecter {
|
||||
return &MockStreamingNodeHandlerServiceClient_Expecter{mock: &_m.Mock}
|
||||
}
|
||||
|
||||
// Consume provides a mock function with given fields: ctx, opts
|
||||
func (_m *MockStreamingNodeHandlerServiceClient) Consume(ctx context.Context, opts ...grpc.CallOption) (streamingpb.StreamingNodeHandlerService_ConsumeClient, error) {
|
||||
_va := make([]interface{}, len(opts))
|
||||
for _i := range opts {
|
||||
_va[_i] = opts[_i]
|
||||
}
|
||||
var _ca []interface{}
|
||||
_ca = append(_ca, ctx)
|
||||
_ca = append(_ca, _va...)
|
||||
ret := _m.Called(_ca...)
|
||||
|
||||
var r0 streamingpb.StreamingNodeHandlerService_ConsumeClient
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, ...grpc.CallOption) (streamingpb.StreamingNodeHandlerService_ConsumeClient, error)); ok {
|
||||
return rf(ctx, opts...)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, ...grpc.CallOption) streamingpb.StreamingNodeHandlerService_ConsumeClient); ok {
|
||||
r0 = rf(ctx, opts...)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(streamingpb.StreamingNodeHandlerService_ConsumeClient)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, ...grpc.CallOption) error); ok {
|
||||
r1 = rf(ctx, opts...)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockStreamingNodeHandlerServiceClient_Consume_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Consume'
|
||||
type MockStreamingNodeHandlerServiceClient_Consume_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Consume is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - opts ...grpc.CallOption
|
||||
func (_e *MockStreamingNodeHandlerServiceClient_Expecter) Consume(ctx interface{}, opts ...interface{}) *MockStreamingNodeHandlerServiceClient_Consume_Call {
|
||||
return &MockStreamingNodeHandlerServiceClient_Consume_Call{Call: _e.mock.On("Consume",
|
||||
append([]interface{}{ctx}, opts...)...)}
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerServiceClient_Consume_Call) Run(run func(ctx context.Context, opts ...grpc.CallOption)) *MockStreamingNodeHandlerServiceClient_Consume_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
variadicArgs := make([]grpc.CallOption, len(args)-1)
|
||||
for i, a := range args[1:] {
|
||||
if a != nil {
|
||||
variadicArgs[i] = a.(grpc.CallOption)
|
||||
}
|
||||
}
|
||||
run(args[0].(context.Context), variadicArgs...)
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerServiceClient_Consume_Call) Return(_a0 streamingpb.StreamingNodeHandlerService_ConsumeClient, _a1 error) *MockStreamingNodeHandlerServiceClient_Consume_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerServiceClient_Consume_Call) RunAndReturn(run func(context.Context, ...grpc.CallOption) (streamingpb.StreamingNodeHandlerService_ConsumeClient, error)) *MockStreamingNodeHandlerServiceClient_Consume_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Produce provides a mock function with given fields: ctx, opts
|
||||
func (_m *MockStreamingNodeHandlerServiceClient) Produce(ctx context.Context, opts ...grpc.CallOption) (streamingpb.StreamingNodeHandlerService_ProduceClient, error) {
|
||||
_va := make([]interface{}, len(opts))
|
||||
for _i := range opts {
|
||||
_va[_i] = opts[_i]
|
||||
}
|
||||
var _ca []interface{}
|
||||
_ca = append(_ca, ctx)
|
||||
_ca = append(_ca, _va...)
|
||||
ret := _m.Called(_ca...)
|
||||
|
||||
var r0 streamingpb.StreamingNodeHandlerService_ProduceClient
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, ...grpc.CallOption) (streamingpb.StreamingNodeHandlerService_ProduceClient, error)); ok {
|
||||
return rf(ctx, opts...)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, ...grpc.CallOption) streamingpb.StreamingNodeHandlerService_ProduceClient); ok {
|
||||
r0 = rf(ctx, opts...)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(streamingpb.StreamingNodeHandlerService_ProduceClient)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, ...grpc.CallOption) error); ok {
|
||||
r1 = rf(ctx, opts...)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockStreamingNodeHandlerServiceClient_Produce_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Produce'
|
||||
type MockStreamingNodeHandlerServiceClient_Produce_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Produce is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - opts ...grpc.CallOption
|
||||
func (_e *MockStreamingNodeHandlerServiceClient_Expecter) Produce(ctx interface{}, opts ...interface{}) *MockStreamingNodeHandlerServiceClient_Produce_Call {
|
||||
return &MockStreamingNodeHandlerServiceClient_Produce_Call{Call: _e.mock.On("Produce",
|
||||
append([]interface{}{ctx}, opts...)...)}
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerServiceClient_Produce_Call) Run(run func(ctx context.Context, opts ...grpc.CallOption)) *MockStreamingNodeHandlerServiceClient_Produce_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
variadicArgs := make([]grpc.CallOption, len(args)-1)
|
||||
for i, a := range args[1:] {
|
||||
if a != nil {
|
||||
variadicArgs[i] = a.(grpc.CallOption)
|
||||
}
|
||||
}
|
||||
run(args[0].(context.Context), variadicArgs...)
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerServiceClient_Produce_Call) Return(_a0 streamingpb.StreamingNodeHandlerService_ProduceClient, _a1 error) *MockStreamingNodeHandlerServiceClient_Produce_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerServiceClient_Produce_Call) RunAndReturn(run func(context.Context, ...grpc.CallOption) (streamingpb.StreamingNodeHandlerService_ProduceClient, error)) *MockStreamingNodeHandlerServiceClient_Produce_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// NewMockStreamingNodeHandlerServiceClient creates a new instance of MockStreamingNodeHandlerServiceClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewMockStreamingNodeHandlerServiceClient(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *MockStreamingNodeHandlerServiceClient {
|
||||
mock := &MockStreamingNodeHandlerServiceClient{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
@ -0,0 +1,398 @@
|
||||
// Code generated by mockery v2.32.4. DO NOT EDIT.
|
||||
|
||||
package mock_streamingpb
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
metadata "google.golang.org/grpc/metadata"
|
||||
|
||||
streamingpb "github.com/milvus-io/milvus/internal/proto/streamingpb"
|
||||
)
|
||||
|
||||
// MockStreamingNodeHandlerService_ConsumeClient is an autogenerated mock type for the StreamingNodeHandlerService_ConsumeClient type
|
||||
type MockStreamingNodeHandlerService_ConsumeClient struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type MockStreamingNodeHandlerService_ConsumeClient_Expecter struct {
|
||||
mock *mock.Mock
|
||||
}
|
||||
|
||||
func (_m *MockStreamingNodeHandlerService_ConsumeClient) EXPECT() *MockStreamingNodeHandlerService_ConsumeClient_Expecter {
|
||||
return &MockStreamingNodeHandlerService_ConsumeClient_Expecter{mock: &_m.Mock}
|
||||
}
|
||||
|
||||
// CloseSend provides a mock function with given fields:
|
||||
func (_m *MockStreamingNodeHandlerService_ConsumeClient) CloseSend() error {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func() error); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockStreamingNodeHandlerService_ConsumeClient_CloseSend_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CloseSend'
|
||||
type MockStreamingNodeHandlerService_ConsumeClient_CloseSend_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// CloseSend is a helper method to define mock.On call
|
||||
func (_e *MockStreamingNodeHandlerService_ConsumeClient_Expecter) CloseSend() *MockStreamingNodeHandlerService_ConsumeClient_CloseSend_Call {
|
||||
return &MockStreamingNodeHandlerService_ConsumeClient_CloseSend_Call{Call: _e.mock.On("CloseSend")}
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ConsumeClient_CloseSend_Call) Run(run func()) *MockStreamingNodeHandlerService_ConsumeClient_CloseSend_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ConsumeClient_CloseSend_Call) Return(_a0 error) *MockStreamingNodeHandlerService_ConsumeClient_CloseSend_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ConsumeClient_CloseSend_Call) RunAndReturn(run func() error) *MockStreamingNodeHandlerService_ConsumeClient_CloseSend_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Context provides a mock function with given fields:
|
||||
func (_m *MockStreamingNodeHandlerService_ConsumeClient) Context() context.Context {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 context.Context
|
||||
if rf, ok := ret.Get(0).(func() context.Context); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(context.Context)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockStreamingNodeHandlerService_ConsumeClient_Context_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Context'
|
||||
type MockStreamingNodeHandlerService_ConsumeClient_Context_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Context is a helper method to define mock.On call
|
||||
func (_e *MockStreamingNodeHandlerService_ConsumeClient_Expecter) Context() *MockStreamingNodeHandlerService_ConsumeClient_Context_Call {
|
||||
return &MockStreamingNodeHandlerService_ConsumeClient_Context_Call{Call: _e.mock.On("Context")}
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ConsumeClient_Context_Call) Run(run func()) *MockStreamingNodeHandlerService_ConsumeClient_Context_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ConsumeClient_Context_Call) Return(_a0 context.Context) *MockStreamingNodeHandlerService_ConsumeClient_Context_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ConsumeClient_Context_Call) RunAndReturn(run func() context.Context) *MockStreamingNodeHandlerService_ConsumeClient_Context_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Header provides a mock function with given fields:
|
||||
func (_m *MockStreamingNodeHandlerService_ConsumeClient) Header() (metadata.MD, error) {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 metadata.MD
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func() (metadata.MD, error)); ok {
|
||||
return rf()
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func() metadata.MD); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(metadata.MD)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func() error); ok {
|
||||
r1 = rf()
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockStreamingNodeHandlerService_ConsumeClient_Header_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Header'
|
||||
type MockStreamingNodeHandlerService_ConsumeClient_Header_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Header is a helper method to define mock.On call
|
||||
func (_e *MockStreamingNodeHandlerService_ConsumeClient_Expecter) Header() *MockStreamingNodeHandlerService_ConsumeClient_Header_Call {
|
||||
return &MockStreamingNodeHandlerService_ConsumeClient_Header_Call{Call: _e.mock.On("Header")}
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ConsumeClient_Header_Call) Run(run func()) *MockStreamingNodeHandlerService_ConsumeClient_Header_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ConsumeClient_Header_Call) Return(_a0 metadata.MD, _a1 error) *MockStreamingNodeHandlerService_ConsumeClient_Header_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ConsumeClient_Header_Call) RunAndReturn(run func() (metadata.MD, error)) *MockStreamingNodeHandlerService_ConsumeClient_Header_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Recv provides a mock function with given fields:
|
||||
func (_m *MockStreamingNodeHandlerService_ConsumeClient) Recv() (*streamingpb.ConsumeResponse, error) {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 *streamingpb.ConsumeResponse
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func() (*streamingpb.ConsumeResponse, error)); ok {
|
||||
return rf()
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func() *streamingpb.ConsumeResponse); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*streamingpb.ConsumeResponse)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func() error); ok {
|
||||
r1 = rf()
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockStreamingNodeHandlerService_ConsumeClient_Recv_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Recv'
|
||||
type MockStreamingNodeHandlerService_ConsumeClient_Recv_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Recv is a helper method to define mock.On call
|
||||
func (_e *MockStreamingNodeHandlerService_ConsumeClient_Expecter) Recv() *MockStreamingNodeHandlerService_ConsumeClient_Recv_Call {
|
||||
return &MockStreamingNodeHandlerService_ConsumeClient_Recv_Call{Call: _e.mock.On("Recv")}
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ConsumeClient_Recv_Call) Run(run func()) *MockStreamingNodeHandlerService_ConsumeClient_Recv_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ConsumeClient_Recv_Call) Return(_a0 *streamingpb.ConsumeResponse, _a1 error) *MockStreamingNodeHandlerService_ConsumeClient_Recv_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ConsumeClient_Recv_Call) RunAndReturn(run func() (*streamingpb.ConsumeResponse, error)) *MockStreamingNodeHandlerService_ConsumeClient_Recv_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// RecvMsg provides a mock function with given fields: m
|
||||
func (_m *MockStreamingNodeHandlerService_ConsumeClient) RecvMsg(m interface{}) error {
|
||||
ret := _m.Called(m)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(interface{}) error); ok {
|
||||
r0 = rf(m)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockStreamingNodeHandlerService_ConsumeClient_RecvMsg_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RecvMsg'
|
||||
type MockStreamingNodeHandlerService_ConsumeClient_RecvMsg_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// RecvMsg is a helper method to define mock.On call
|
||||
// - m interface{}
|
||||
func (_e *MockStreamingNodeHandlerService_ConsumeClient_Expecter) RecvMsg(m interface{}) *MockStreamingNodeHandlerService_ConsumeClient_RecvMsg_Call {
|
||||
return &MockStreamingNodeHandlerService_ConsumeClient_RecvMsg_Call{Call: _e.mock.On("RecvMsg", m)}
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ConsumeClient_RecvMsg_Call) Run(run func(m interface{})) *MockStreamingNodeHandlerService_ConsumeClient_RecvMsg_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(interface{}))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ConsumeClient_RecvMsg_Call) Return(_a0 error) *MockStreamingNodeHandlerService_ConsumeClient_RecvMsg_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ConsumeClient_RecvMsg_Call) RunAndReturn(run func(interface{}) error) *MockStreamingNodeHandlerService_ConsumeClient_RecvMsg_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Send provides a mock function with given fields: _a0
|
||||
func (_m *MockStreamingNodeHandlerService_ConsumeClient) Send(_a0 *streamingpb.ConsumeRequest) error {
|
||||
ret := _m.Called(_a0)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(*streamingpb.ConsumeRequest) error); ok {
|
||||
r0 = rf(_a0)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockStreamingNodeHandlerService_ConsumeClient_Send_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Send'
|
||||
type MockStreamingNodeHandlerService_ConsumeClient_Send_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Send is a helper method to define mock.On call
|
||||
// - _a0 *streamingpb.ConsumeRequest
|
||||
func (_e *MockStreamingNodeHandlerService_ConsumeClient_Expecter) Send(_a0 interface{}) *MockStreamingNodeHandlerService_ConsumeClient_Send_Call {
|
||||
return &MockStreamingNodeHandlerService_ConsumeClient_Send_Call{Call: _e.mock.On("Send", _a0)}
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ConsumeClient_Send_Call) Run(run func(_a0 *streamingpb.ConsumeRequest)) *MockStreamingNodeHandlerService_ConsumeClient_Send_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(*streamingpb.ConsumeRequest))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ConsumeClient_Send_Call) Return(_a0 error) *MockStreamingNodeHandlerService_ConsumeClient_Send_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ConsumeClient_Send_Call) RunAndReturn(run func(*streamingpb.ConsumeRequest) error) *MockStreamingNodeHandlerService_ConsumeClient_Send_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// SendMsg provides a mock function with given fields: m
|
||||
func (_m *MockStreamingNodeHandlerService_ConsumeClient) SendMsg(m interface{}) error {
|
||||
ret := _m.Called(m)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(interface{}) error); ok {
|
||||
r0 = rf(m)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockStreamingNodeHandlerService_ConsumeClient_SendMsg_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SendMsg'
|
||||
type MockStreamingNodeHandlerService_ConsumeClient_SendMsg_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// SendMsg is a helper method to define mock.On call
|
||||
// - m interface{}
|
||||
func (_e *MockStreamingNodeHandlerService_ConsumeClient_Expecter) SendMsg(m interface{}) *MockStreamingNodeHandlerService_ConsumeClient_SendMsg_Call {
|
||||
return &MockStreamingNodeHandlerService_ConsumeClient_SendMsg_Call{Call: _e.mock.On("SendMsg", m)}
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ConsumeClient_SendMsg_Call) Run(run func(m interface{})) *MockStreamingNodeHandlerService_ConsumeClient_SendMsg_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(interface{}))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ConsumeClient_SendMsg_Call) Return(_a0 error) *MockStreamingNodeHandlerService_ConsumeClient_SendMsg_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ConsumeClient_SendMsg_Call) RunAndReturn(run func(interface{}) error) *MockStreamingNodeHandlerService_ConsumeClient_SendMsg_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Trailer provides a mock function with given fields:
|
||||
func (_m *MockStreamingNodeHandlerService_ConsumeClient) Trailer() metadata.MD {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 metadata.MD
|
||||
if rf, ok := ret.Get(0).(func() metadata.MD); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(metadata.MD)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockStreamingNodeHandlerService_ConsumeClient_Trailer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Trailer'
|
||||
type MockStreamingNodeHandlerService_ConsumeClient_Trailer_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Trailer is a helper method to define mock.On call
|
||||
func (_e *MockStreamingNodeHandlerService_ConsumeClient_Expecter) Trailer() *MockStreamingNodeHandlerService_ConsumeClient_Trailer_Call {
|
||||
return &MockStreamingNodeHandlerService_ConsumeClient_Trailer_Call{Call: _e.mock.On("Trailer")}
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ConsumeClient_Trailer_Call) Run(run func()) *MockStreamingNodeHandlerService_ConsumeClient_Trailer_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ConsumeClient_Trailer_Call) Return(_a0 metadata.MD) *MockStreamingNodeHandlerService_ConsumeClient_Trailer_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ConsumeClient_Trailer_Call) RunAndReturn(run func() metadata.MD) *MockStreamingNodeHandlerService_ConsumeClient_Trailer_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// NewMockStreamingNodeHandlerService_ConsumeClient creates a new instance of MockStreamingNodeHandlerService_ConsumeClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewMockStreamingNodeHandlerService_ConsumeClient(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *MockStreamingNodeHandlerService_ConsumeClient {
|
||||
mock := &MockStreamingNodeHandlerService_ConsumeClient{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
@ -0,0 +1,398 @@
|
||||
// Code generated by mockery v2.32.4. DO NOT EDIT.
|
||||
|
||||
package mock_streamingpb
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
metadata "google.golang.org/grpc/metadata"
|
||||
|
||||
streamingpb "github.com/milvus-io/milvus/internal/proto/streamingpb"
|
||||
)
|
||||
|
||||
// MockStreamingNodeHandlerService_ProduceClient is an autogenerated mock type for the StreamingNodeHandlerService_ProduceClient type
|
||||
type MockStreamingNodeHandlerService_ProduceClient struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type MockStreamingNodeHandlerService_ProduceClient_Expecter struct {
|
||||
mock *mock.Mock
|
||||
}
|
||||
|
||||
func (_m *MockStreamingNodeHandlerService_ProduceClient) EXPECT() *MockStreamingNodeHandlerService_ProduceClient_Expecter {
|
||||
return &MockStreamingNodeHandlerService_ProduceClient_Expecter{mock: &_m.Mock}
|
||||
}
|
||||
|
||||
// CloseSend provides a mock function with given fields:
|
||||
func (_m *MockStreamingNodeHandlerService_ProduceClient) CloseSend() error {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func() error); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockStreamingNodeHandlerService_ProduceClient_CloseSend_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CloseSend'
|
||||
type MockStreamingNodeHandlerService_ProduceClient_CloseSend_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// CloseSend is a helper method to define mock.On call
|
||||
func (_e *MockStreamingNodeHandlerService_ProduceClient_Expecter) CloseSend() *MockStreamingNodeHandlerService_ProduceClient_CloseSend_Call {
|
||||
return &MockStreamingNodeHandlerService_ProduceClient_CloseSend_Call{Call: _e.mock.On("CloseSend")}
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ProduceClient_CloseSend_Call) Run(run func()) *MockStreamingNodeHandlerService_ProduceClient_CloseSend_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ProduceClient_CloseSend_Call) Return(_a0 error) *MockStreamingNodeHandlerService_ProduceClient_CloseSend_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ProduceClient_CloseSend_Call) RunAndReturn(run func() error) *MockStreamingNodeHandlerService_ProduceClient_CloseSend_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Context provides a mock function with given fields:
|
||||
func (_m *MockStreamingNodeHandlerService_ProduceClient) Context() context.Context {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 context.Context
|
||||
if rf, ok := ret.Get(0).(func() context.Context); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(context.Context)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockStreamingNodeHandlerService_ProduceClient_Context_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Context'
|
||||
type MockStreamingNodeHandlerService_ProduceClient_Context_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Context is a helper method to define mock.On call
|
||||
func (_e *MockStreamingNodeHandlerService_ProduceClient_Expecter) Context() *MockStreamingNodeHandlerService_ProduceClient_Context_Call {
|
||||
return &MockStreamingNodeHandlerService_ProduceClient_Context_Call{Call: _e.mock.On("Context")}
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ProduceClient_Context_Call) Run(run func()) *MockStreamingNodeHandlerService_ProduceClient_Context_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ProduceClient_Context_Call) Return(_a0 context.Context) *MockStreamingNodeHandlerService_ProduceClient_Context_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ProduceClient_Context_Call) RunAndReturn(run func() context.Context) *MockStreamingNodeHandlerService_ProduceClient_Context_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Header provides a mock function with given fields:
|
||||
func (_m *MockStreamingNodeHandlerService_ProduceClient) Header() (metadata.MD, error) {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 metadata.MD
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func() (metadata.MD, error)); ok {
|
||||
return rf()
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func() metadata.MD); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(metadata.MD)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func() error); ok {
|
||||
r1 = rf()
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockStreamingNodeHandlerService_ProduceClient_Header_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Header'
|
||||
type MockStreamingNodeHandlerService_ProduceClient_Header_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Header is a helper method to define mock.On call
|
||||
func (_e *MockStreamingNodeHandlerService_ProduceClient_Expecter) Header() *MockStreamingNodeHandlerService_ProduceClient_Header_Call {
|
||||
return &MockStreamingNodeHandlerService_ProduceClient_Header_Call{Call: _e.mock.On("Header")}
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ProduceClient_Header_Call) Run(run func()) *MockStreamingNodeHandlerService_ProduceClient_Header_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ProduceClient_Header_Call) Return(_a0 metadata.MD, _a1 error) *MockStreamingNodeHandlerService_ProduceClient_Header_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ProduceClient_Header_Call) RunAndReturn(run func() (metadata.MD, error)) *MockStreamingNodeHandlerService_ProduceClient_Header_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Recv provides a mock function with given fields:
|
||||
func (_m *MockStreamingNodeHandlerService_ProduceClient) Recv() (*streamingpb.ProduceResponse, error) {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 *streamingpb.ProduceResponse
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func() (*streamingpb.ProduceResponse, error)); ok {
|
||||
return rf()
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func() *streamingpb.ProduceResponse); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*streamingpb.ProduceResponse)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func() error); ok {
|
||||
r1 = rf()
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockStreamingNodeHandlerService_ProduceClient_Recv_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Recv'
|
||||
type MockStreamingNodeHandlerService_ProduceClient_Recv_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Recv is a helper method to define mock.On call
|
||||
func (_e *MockStreamingNodeHandlerService_ProduceClient_Expecter) Recv() *MockStreamingNodeHandlerService_ProduceClient_Recv_Call {
|
||||
return &MockStreamingNodeHandlerService_ProduceClient_Recv_Call{Call: _e.mock.On("Recv")}
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ProduceClient_Recv_Call) Run(run func()) *MockStreamingNodeHandlerService_ProduceClient_Recv_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ProduceClient_Recv_Call) Return(_a0 *streamingpb.ProduceResponse, _a1 error) *MockStreamingNodeHandlerService_ProduceClient_Recv_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ProduceClient_Recv_Call) RunAndReturn(run func() (*streamingpb.ProduceResponse, error)) *MockStreamingNodeHandlerService_ProduceClient_Recv_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// RecvMsg provides a mock function with given fields: m
|
||||
func (_m *MockStreamingNodeHandlerService_ProduceClient) RecvMsg(m interface{}) error {
|
||||
ret := _m.Called(m)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(interface{}) error); ok {
|
||||
r0 = rf(m)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockStreamingNodeHandlerService_ProduceClient_RecvMsg_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RecvMsg'
|
||||
type MockStreamingNodeHandlerService_ProduceClient_RecvMsg_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// RecvMsg is a helper method to define mock.On call
|
||||
// - m interface{}
|
||||
func (_e *MockStreamingNodeHandlerService_ProduceClient_Expecter) RecvMsg(m interface{}) *MockStreamingNodeHandlerService_ProduceClient_RecvMsg_Call {
|
||||
return &MockStreamingNodeHandlerService_ProduceClient_RecvMsg_Call{Call: _e.mock.On("RecvMsg", m)}
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ProduceClient_RecvMsg_Call) Run(run func(m interface{})) *MockStreamingNodeHandlerService_ProduceClient_RecvMsg_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(interface{}))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ProduceClient_RecvMsg_Call) Return(_a0 error) *MockStreamingNodeHandlerService_ProduceClient_RecvMsg_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ProduceClient_RecvMsg_Call) RunAndReturn(run func(interface{}) error) *MockStreamingNodeHandlerService_ProduceClient_RecvMsg_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Send provides a mock function with given fields: _a0
|
||||
func (_m *MockStreamingNodeHandlerService_ProduceClient) Send(_a0 *streamingpb.ProduceRequest) error {
|
||||
ret := _m.Called(_a0)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(*streamingpb.ProduceRequest) error); ok {
|
||||
r0 = rf(_a0)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockStreamingNodeHandlerService_ProduceClient_Send_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Send'
|
||||
type MockStreamingNodeHandlerService_ProduceClient_Send_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Send is a helper method to define mock.On call
|
||||
// - _a0 *streamingpb.ProduceRequest
|
||||
func (_e *MockStreamingNodeHandlerService_ProduceClient_Expecter) Send(_a0 interface{}) *MockStreamingNodeHandlerService_ProduceClient_Send_Call {
|
||||
return &MockStreamingNodeHandlerService_ProduceClient_Send_Call{Call: _e.mock.On("Send", _a0)}
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ProduceClient_Send_Call) Run(run func(_a0 *streamingpb.ProduceRequest)) *MockStreamingNodeHandlerService_ProduceClient_Send_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(*streamingpb.ProduceRequest))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ProduceClient_Send_Call) Return(_a0 error) *MockStreamingNodeHandlerService_ProduceClient_Send_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ProduceClient_Send_Call) RunAndReturn(run func(*streamingpb.ProduceRequest) error) *MockStreamingNodeHandlerService_ProduceClient_Send_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// SendMsg provides a mock function with given fields: m
|
||||
func (_m *MockStreamingNodeHandlerService_ProduceClient) SendMsg(m interface{}) error {
|
||||
ret := _m.Called(m)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(interface{}) error); ok {
|
||||
r0 = rf(m)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockStreamingNodeHandlerService_ProduceClient_SendMsg_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SendMsg'
|
||||
type MockStreamingNodeHandlerService_ProduceClient_SendMsg_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// SendMsg is a helper method to define mock.On call
|
||||
// - m interface{}
|
||||
func (_e *MockStreamingNodeHandlerService_ProduceClient_Expecter) SendMsg(m interface{}) *MockStreamingNodeHandlerService_ProduceClient_SendMsg_Call {
|
||||
return &MockStreamingNodeHandlerService_ProduceClient_SendMsg_Call{Call: _e.mock.On("SendMsg", m)}
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ProduceClient_SendMsg_Call) Run(run func(m interface{})) *MockStreamingNodeHandlerService_ProduceClient_SendMsg_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(interface{}))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ProduceClient_SendMsg_Call) Return(_a0 error) *MockStreamingNodeHandlerService_ProduceClient_SendMsg_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ProduceClient_SendMsg_Call) RunAndReturn(run func(interface{}) error) *MockStreamingNodeHandlerService_ProduceClient_SendMsg_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Trailer provides a mock function with given fields:
|
||||
func (_m *MockStreamingNodeHandlerService_ProduceClient) Trailer() metadata.MD {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 metadata.MD
|
||||
if rf, ok := ret.Get(0).(func() metadata.MD); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(metadata.MD)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockStreamingNodeHandlerService_ProduceClient_Trailer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Trailer'
|
||||
type MockStreamingNodeHandlerService_ProduceClient_Trailer_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Trailer is a helper method to define mock.On call
|
||||
func (_e *MockStreamingNodeHandlerService_ProduceClient_Expecter) Trailer() *MockStreamingNodeHandlerService_ProduceClient_Trailer_Call {
|
||||
return &MockStreamingNodeHandlerService_ProduceClient_Trailer_Call{Call: _e.mock.On("Trailer")}
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ProduceClient_Trailer_Call) Run(run func()) *MockStreamingNodeHandlerService_ProduceClient_Trailer_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ProduceClient_Trailer_Call) Return(_a0 metadata.MD) *MockStreamingNodeHandlerService_ProduceClient_Trailer_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeHandlerService_ProduceClient_Trailer_Call) RunAndReturn(run func() metadata.MD) *MockStreamingNodeHandlerService_ProduceClient_Trailer_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// NewMockStreamingNodeHandlerService_ProduceClient creates a new instance of MockStreamingNodeHandlerService_ProduceClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewMockStreamingNodeHandlerService_ProduceClient(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *MockStreamingNodeHandlerService_ProduceClient {
|
||||
mock := &MockStreamingNodeHandlerService_ProduceClient{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
@ -0,0 +1,250 @@
|
||||
// Code generated by mockery v2.32.4. DO NOT EDIT.
|
||||
|
||||
package mock_streamingpb
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
grpc "google.golang.org/grpc"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
streamingpb "github.com/milvus-io/milvus/internal/proto/streamingpb"
|
||||
)
|
||||
|
||||
// MockStreamingNodeManagerServiceClient is an autogenerated mock type for the StreamingNodeManagerServiceClient type
|
||||
type MockStreamingNodeManagerServiceClient struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type MockStreamingNodeManagerServiceClient_Expecter struct {
|
||||
mock *mock.Mock
|
||||
}
|
||||
|
||||
func (_m *MockStreamingNodeManagerServiceClient) EXPECT() *MockStreamingNodeManagerServiceClient_Expecter {
|
||||
return &MockStreamingNodeManagerServiceClient_Expecter{mock: &_m.Mock}
|
||||
}
|
||||
|
||||
// Assign provides a mock function with given fields: ctx, in, opts
|
||||
func (_m *MockStreamingNodeManagerServiceClient) Assign(ctx context.Context, in *streamingpb.StreamingNodeManagerAssignRequest, opts ...grpc.CallOption) (*streamingpb.StreamingNodeManagerAssignResponse, error) {
|
||||
_va := make([]interface{}, len(opts))
|
||||
for _i := range opts {
|
||||
_va[_i] = opts[_i]
|
||||
}
|
||||
var _ca []interface{}
|
||||
_ca = append(_ca, ctx, in)
|
||||
_ca = append(_ca, _va...)
|
||||
ret := _m.Called(_ca...)
|
||||
|
||||
var r0 *streamingpb.StreamingNodeManagerAssignResponse
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *streamingpb.StreamingNodeManagerAssignRequest, ...grpc.CallOption) (*streamingpb.StreamingNodeManagerAssignResponse, error)); ok {
|
||||
return rf(ctx, in, opts...)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *streamingpb.StreamingNodeManagerAssignRequest, ...grpc.CallOption) *streamingpb.StreamingNodeManagerAssignResponse); ok {
|
||||
r0 = rf(ctx, in, opts...)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*streamingpb.StreamingNodeManagerAssignResponse)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *streamingpb.StreamingNodeManagerAssignRequest, ...grpc.CallOption) error); ok {
|
||||
r1 = rf(ctx, in, opts...)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockStreamingNodeManagerServiceClient_Assign_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Assign'
|
||||
type MockStreamingNodeManagerServiceClient_Assign_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Assign is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - in *streamingpb.StreamingNodeManagerAssignRequest
|
||||
// - opts ...grpc.CallOption
|
||||
func (_e *MockStreamingNodeManagerServiceClient_Expecter) Assign(ctx interface{}, in interface{}, opts ...interface{}) *MockStreamingNodeManagerServiceClient_Assign_Call {
|
||||
return &MockStreamingNodeManagerServiceClient_Assign_Call{Call: _e.mock.On("Assign",
|
||||
append([]interface{}{ctx, in}, opts...)...)}
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeManagerServiceClient_Assign_Call) Run(run func(ctx context.Context, in *streamingpb.StreamingNodeManagerAssignRequest, opts ...grpc.CallOption)) *MockStreamingNodeManagerServiceClient_Assign_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
variadicArgs := make([]grpc.CallOption, len(args)-2)
|
||||
for i, a := range args[2:] {
|
||||
if a != nil {
|
||||
variadicArgs[i] = a.(grpc.CallOption)
|
||||
}
|
||||
}
|
||||
run(args[0].(context.Context), args[1].(*streamingpb.StreamingNodeManagerAssignRequest), variadicArgs...)
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeManagerServiceClient_Assign_Call) Return(_a0 *streamingpb.StreamingNodeManagerAssignResponse, _a1 error) *MockStreamingNodeManagerServiceClient_Assign_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeManagerServiceClient_Assign_Call) RunAndReturn(run func(context.Context, *streamingpb.StreamingNodeManagerAssignRequest, ...grpc.CallOption) (*streamingpb.StreamingNodeManagerAssignResponse, error)) *MockStreamingNodeManagerServiceClient_Assign_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// CollectStatus provides a mock function with given fields: ctx, in, opts
|
||||
func (_m *MockStreamingNodeManagerServiceClient) CollectStatus(ctx context.Context, in *streamingpb.StreamingNodeManagerCollectStatusRequest, opts ...grpc.CallOption) (*streamingpb.StreamingNodeManagerCollectStatusResponse, error) {
|
||||
_va := make([]interface{}, len(opts))
|
||||
for _i := range opts {
|
||||
_va[_i] = opts[_i]
|
||||
}
|
||||
var _ca []interface{}
|
||||
_ca = append(_ca, ctx, in)
|
||||
_ca = append(_ca, _va...)
|
||||
ret := _m.Called(_ca...)
|
||||
|
||||
var r0 *streamingpb.StreamingNodeManagerCollectStatusResponse
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *streamingpb.StreamingNodeManagerCollectStatusRequest, ...grpc.CallOption) (*streamingpb.StreamingNodeManagerCollectStatusResponse, error)); ok {
|
||||
return rf(ctx, in, opts...)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *streamingpb.StreamingNodeManagerCollectStatusRequest, ...grpc.CallOption) *streamingpb.StreamingNodeManagerCollectStatusResponse); ok {
|
||||
r0 = rf(ctx, in, opts...)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*streamingpb.StreamingNodeManagerCollectStatusResponse)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *streamingpb.StreamingNodeManagerCollectStatusRequest, ...grpc.CallOption) error); ok {
|
||||
r1 = rf(ctx, in, opts...)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockStreamingNodeManagerServiceClient_CollectStatus_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CollectStatus'
|
||||
type MockStreamingNodeManagerServiceClient_CollectStatus_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// CollectStatus is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - in *streamingpb.StreamingNodeManagerCollectStatusRequest
|
||||
// - opts ...grpc.CallOption
|
||||
func (_e *MockStreamingNodeManagerServiceClient_Expecter) CollectStatus(ctx interface{}, in interface{}, opts ...interface{}) *MockStreamingNodeManagerServiceClient_CollectStatus_Call {
|
||||
return &MockStreamingNodeManagerServiceClient_CollectStatus_Call{Call: _e.mock.On("CollectStatus",
|
||||
append([]interface{}{ctx, in}, opts...)...)}
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeManagerServiceClient_CollectStatus_Call) Run(run func(ctx context.Context, in *streamingpb.StreamingNodeManagerCollectStatusRequest, opts ...grpc.CallOption)) *MockStreamingNodeManagerServiceClient_CollectStatus_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
variadicArgs := make([]grpc.CallOption, len(args)-2)
|
||||
for i, a := range args[2:] {
|
||||
if a != nil {
|
||||
variadicArgs[i] = a.(grpc.CallOption)
|
||||
}
|
||||
}
|
||||
run(args[0].(context.Context), args[1].(*streamingpb.StreamingNodeManagerCollectStatusRequest), variadicArgs...)
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeManagerServiceClient_CollectStatus_Call) Return(_a0 *streamingpb.StreamingNodeManagerCollectStatusResponse, _a1 error) *MockStreamingNodeManagerServiceClient_CollectStatus_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeManagerServiceClient_CollectStatus_Call) RunAndReturn(run func(context.Context, *streamingpb.StreamingNodeManagerCollectStatusRequest, ...grpc.CallOption) (*streamingpb.StreamingNodeManagerCollectStatusResponse, error)) *MockStreamingNodeManagerServiceClient_CollectStatus_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Remove provides a mock function with given fields: ctx, in, opts
|
||||
func (_m *MockStreamingNodeManagerServiceClient) Remove(ctx context.Context, in *streamingpb.StreamingNodeManagerRemoveRequest, opts ...grpc.CallOption) (*streamingpb.StreamingNodeManagerRemoveResponse, error) {
|
||||
_va := make([]interface{}, len(opts))
|
||||
for _i := range opts {
|
||||
_va[_i] = opts[_i]
|
||||
}
|
||||
var _ca []interface{}
|
||||
_ca = append(_ca, ctx, in)
|
||||
_ca = append(_ca, _va...)
|
||||
ret := _m.Called(_ca...)
|
||||
|
||||
var r0 *streamingpb.StreamingNodeManagerRemoveResponse
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *streamingpb.StreamingNodeManagerRemoveRequest, ...grpc.CallOption) (*streamingpb.StreamingNodeManagerRemoveResponse, error)); ok {
|
||||
return rf(ctx, in, opts...)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *streamingpb.StreamingNodeManagerRemoveRequest, ...grpc.CallOption) *streamingpb.StreamingNodeManagerRemoveResponse); ok {
|
||||
r0 = rf(ctx, in, opts...)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*streamingpb.StreamingNodeManagerRemoveResponse)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *streamingpb.StreamingNodeManagerRemoveRequest, ...grpc.CallOption) error); ok {
|
||||
r1 = rf(ctx, in, opts...)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockStreamingNodeManagerServiceClient_Remove_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Remove'
|
||||
type MockStreamingNodeManagerServiceClient_Remove_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Remove is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - in *streamingpb.StreamingNodeManagerRemoveRequest
|
||||
// - opts ...grpc.CallOption
|
||||
func (_e *MockStreamingNodeManagerServiceClient_Expecter) Remove(ctx interface{}, in interface{}, opts ...interface{}) *MockStreamingNodeManagerServiceClient_Remove_Call {
|
||||
return &MockStreamingNodeManagerServiceClient_Remove_Call{Call: _e.mock.On("Remove",
|
||||
append([]interface{}{ctx, in}, opts...)...)}
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeManagerServiceClient_Remove_Call) Run(run func(ctx context.Context, in *streamingpb.StreamingNodeManagerRemoveRequest, opts ...grpc.CallOption)) *MockStreamingNodeManagerServiceClient_Remove_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
variadicArgs := make([]grpc.CallOption, len(args)-2)
|
||||
for i, a := range args[2:] {
|
||||
if a != nil {
|
||||
variadicArgs[i] = a.(grpc.CallOption)
|
||||
}
|
||||
}
|
||||
run(args[0].(context.Context), args[1].(*streamingpb.StreamingNodeManagerRemoveRequest), variadicArgs...)
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeManagerServiceClient_Remove_Call) Return(_a0 *streamingpb.StreamingNodeManagerRemoveResponse, _a1 error) *MockStreamingNodeManagerServiceClient_Remove_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockStreamingNodeManagerServiceClient_Remove_Call) RunAndReturn(run func(context.Context, *streamingpb.StreamingNodeManagerRemoveRequest, ...grpc.CallOption) (*streamingpb.StreamingNodeManagerRemoveResponse, error)) *MockStreamingNodeManagerServiceClient_Remove_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// NewMockStreamingNodeManagerServiceClient creates a new instance of MockStreamingNodeManagerServiceClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewMockStreamingNodeManagerServiceClient(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *MockStreamingNodeManagerServiceClient {
|
||||
mock := &MockStreamingNodeManagerServiceClient{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
@ -0,0 +1,158 @@
|
||||
// Code generated by mockery v2.32.4. DO NOT EDIT.
|
||||
|
||||
package mock_assignment
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
types "github.com/milvus-io/milvus/pkg/streaming/util/types"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// MockWatcher is an autogenerated mock type for the Watcher type
|
||||
type MockWatcher struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type MockWatcher_Expecter struct {
|
||||
mock *mock.Mock
|
||||
}
|
||||
|
||||
func (_m *MockWatcher) EXPECT() *MockWatcher_Expecter {
|
||||
return &MockWatcher_Expecter{mock: &_m.Mock}
|
||||
}
|
||||
|
||||
// Close provides a mock function with given fields:
|
||||
func (_m *MockWatcher) Close() {
|
||||
_m.Called()
|
||||
}
|
||||
|
||||
// MockWatcher_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
|
||||
type MockWatcher_Close_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Close is a helper method to define mock.On call
|
||||
func (_e *MockWatcher_Expecter) Close() *MockWatcher_Close_Call {
|
||||
return &MockWatcher_Close_Call{Call: _e.mock.On("Close")}
|
||||
}
|
||||
|
||||
func (_c *MockWatcher_Close_Call) Run(run func()) *MockWatcher_Close_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockWatcher_Close_Call) Return() *MockWatcher_Close_Call {
|
||||
_c.Call.Return()
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockWatcher_Close_Call) RunAndReturn(run func()) *MockWatcher_Close_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Get provides a mock function with given fields: ctx, channel
|
||||
func (_m *MockWatcher) Get(ctx context.Context, channel string) *types.PChannelInfoAssigned {
|
||||
ret := _m.Called(ctx, channel)
|
||||
|
||||
var r0 *types.PChannelInfoAssigned
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) *types.PChannelInfoAssigned); ok {
|
||||
r0 = rf(ctx, channel)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*types.PChannelInfoAssigned)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockWatcher_Get_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Get'
|
||||
type MockWatcher_Get_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Get is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - channel string
|
||||
func (_e *MockWatcher_Expecter) Get(ctx interface{}, channel interface{}) *MockWatcher_Get_Call {
|
||||
return &MockWatcher_Get_Call{Call: _e.mock.On("Get", ctx, channel)}
|
||||
}
|
||||
|
||||
func (_c *MockWatcher_Get_Call) Run(run func(ctx context.Context, channel string)) *MockWatcher_Get_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(string))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockWatcher_Get_Call) Return(_a0 *types.PChannelInfoAssigned) *MockWatcher_Get_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockWatcher_Get_Call) RunAndReturn(run func(context.Context, string) *types.PChannelInfoAssigned) *MockWatcher_Get_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Watch provides a mock function with given fields: ctx, channel, previous
|
||||
func (_m *MockWatcher) Watch(ctx context.Context, channel string, previous *types.PChannelInfoAssigned) error {
|
||||
ret := _m.Called(ctx, channel, previous)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, *types.PChannelInfoAssigned) error); ok {
|
||||
r0 = rf(ctx, channel, previous)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockWatcher_Watch_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Watch'
|
||||
type MockWatcher_Watch_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Watch is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - channel string
|
||||
// - previous *types.PChannelInfoAssigned
|
||||
func (_e *MockWatcher_Expecter) Watch(ctx interface{}, channel interface{}, previous interface{}) *MockWatcher_Watch_Call {
|
||||
return &MockWatcher_Watch_Call{Call: _e.mock.On("Watch", ctx, channel, previous)}
|
||||
}
|
||||
|
||||
func (_c *MockWatcher_Watch_Call) Run(run func(ctx context.Context, channel string, previous *types.PChannelInfoAssigned)) *MockWatcher_Watch_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(string), args[2].(*types.PChannelInfoAssigned))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockWatcher_Watch_Call) Return(_a0 error) *MockWatcher_Watch_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockWatcher_Watch_Call) RunAndReturn(run func(context.Context, string, *types.PChannelInfoAssigned) error) *MockWatcher_Watch_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// NewMockWatcher creates a new instance of MockWatcher. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewMockWatcher(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *MockWatcher {
|
||||
mock := &MockWatcher{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
@ -0,0 +1,148 @@
|
||||
// Code generated by mockery v2.32.4. DO NOT EDIT.
|
||||
|
||||
package mock_consumer
|
||||
|
||||
import mock "github.com/stretchr/testify/mock"
|
||||
|
||||
// MockConsumer is an autogenerated mock type for the Consumer type
|
||||
type MockConsumer struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type MockConsumer_Expecter struct {
|
||||
mock *mock.Mock
|
||||
}
|
||||
|
||||
func (_m *MockConsumer) EXPECT() *MockConsumer_Expecter {
|
||||
return &MockConsumer_Expecter{mock: &_m.Mock}
|
||||
}
|
||||
|
||||
// Close provides a mock function with given fields:
|
||||
func (_m *MockConsumer) Close() {
|
||||
_m.Called()
|
||||
}
|
||||
|
||||
// MockConsumer_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
|
||||
type MockConsumer_Close_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Close is a helper method to define mock.On call
|
||||
func (_e *MockConsumer_Expecter) Close() *MockConsumer_Close_Call {
|
||||
return &MockConsumer_Close_Call{Call: _e.mock.On("Close")}
|
||||
}
|
||||
|
||||
func (_c *MockConsumer_Close_Call) Run(run func()) *MockConsumer_Close_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockConsumer_Close_Call) Return() *MockConsumer_Close_Call {
|
||||
_c.Call.Return()
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockConsumer_Close_Call) RunAndReturn(run func()) *MockConsumer_Close_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Done provides a mock function with given fields:
|
||||
func (_m *MockConsumer) Done() <-chan struct{} {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 <-chan struct{}
|
||||
if rf, ok := ret.Get(0).(func() <-chan struct{}); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(<-chan struct{})
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockConsumer_Done_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Done'
|
||||
type MockConsumer_Done_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Done is a helper method to define mock.On call
|
||||
func (_e *MockConsumer_Expecter) Done() *MockConsumer_Done_Call {
|
||||
return &MockConsumer_Done_Call{Call: _e.mock.On("Done")}
|
||||
}
|
||||
|
||||
func (_c *MockConsumer_Done_Call) Run(run func()) *MockConsumer_Done_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockConsumer_Done_Call) Return(_a0 <-chan struct{}) *MockConsumer_Done_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockConsumer_Done_Call) RunAndReturn(run func() <-chan struct{}) *MockConsumer_Done_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Error provides a mock function with given fields:
|
||||
func (_m *MockConsumer) Error() error {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func() error); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockConsumer_Error_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Error'
|
||||
type MockConsumer_Error_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Error is a helper method to define mock.On call
|
||||
func (_e *MockConsumer_Expecter) Error() *MockConsumer_Error_Call {
|
||||
return &MockConsumer_Error_Call{Call: _e.mock.On("Error")}
|
||||
}
|
||||
|
||||
func (_c *MockConsumer_Error_Call) Run(run func()) *MockConsumer_Error_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockConsumer_Error_Call) Return(_a0 error) *MockConsumer_Error_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockConsumer_Error_Call) RunAndReturn(run func() error) *MockConsumer_Error_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// NewMockConsumer creates a new instance of MockConsumer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewMockConsumer(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *MockConsumer {
|
||||
mock := &MockConsumer{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
@ -0,0 +1,251 @@
|
||||
// Code generated by mockery v2.32.4. DO NOT EDIT.
|
||||
|
||||
package mock_producer
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
message "github.com/milvus-io/milvus/pkg/streaming/util/message"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
types "github.com/milvus-io/milvus/pkg/streaming/util/types"
|
||||
)
|
||||
|
||||
// MockProducer is an autogenerated mock type for the Producer type
|
||||
type MockProducer struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type MockProducer_Expecter struct {
|
||||
mock *mock.Mock
|
||||
}
|
||||
|
||||
func (_m *MockProducer) EXPECT() *MockProducer_Expecter {
|
||||
return &MockProducer_Expecter{mock: &_m.Mock}
|
||||
}
|
||||
|
||||
// Assignment provides a mock function with given fields:
|
||||
func (_m *MockProducer) Assignment() types.PChannelInfoAssigned {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 types.PChannelInfoAssigned
|
||||
if rf, ok := ret.Get(0).(func() types.PChannelInfoAssigned); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
r0 = ret.Get(0).(types.PChannelInfoAssigned)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockProducer_Assignment_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Assignment'
|
||||
type MockProducer_Assignment_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Assignment is a helper method to define mock.On call
|
||||
func (_e *MockProducer_Expecter) Assignment() *MockProducer_Assignment_Call {
|
||||
return &MockProducer_Assignment_Call{Call: _e.mock.On("Assignment")}
|
||||
}
|
||||
|
||||
func (_c *MockProducer_Assignment_Call) Run(run func()) *MockProducer_Assignment_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockProducer_Assignment_Call) Return(_a0 types.PChannelInfoAssigned) *MockProducer_Assignment_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockProducer_Assignment_Call) RunAndReturn(run func() types.PChannelInfoAssigned) *MockProducer_Assignment_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Available provides a mock function with given fields:
|
||||
func (_m *MockProducer) Available() <-chan struct{} {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 <-chan struct{}
|
||||
if rf, ok := ret.Get(0).(func() <-chan struct{}); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(<-chan struct{})
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockProducer_Available_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Available'
|
||||
type MockProducer_Available_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Available is a helper method to define mock.On call
|
||||
func (_e *MockProducer_Expecter) Available() *MockProducer_Available_Call {
|
||||
return &MockProducer_Available_Call{Call: _e.mock.On("Available")}
|
||||
}
|
||||
|
||||
func (_c *MockProducer_Available_Call) Run(run func()) *MockProducer_Available_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockProducer_Available_Call) Return(_a0 <-chan struct{}) *MockProducer_Available_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockProducer_Available_Call) RunAndReturn(run func() <-chan struct{}) *MockProducer_Available_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Close provides a mock function with given fields:
|
||||
func (_m *MockProducer) Close() {
|
||||
_m.Called()
|
||||
}
|
||||
|
||||
// MockProducer_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
|
||||
type MockProducer_Close_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Close is a helper method to define mock.On call
|
||||
func (_e *MockProducer_Expecter) Close() *MockProducer_Close_Call {
|
||||
return &MockProducer_Close_Call{Call: _e.mock.On("Close")}
|
||||
}
|
||||
|
||||
func (_c *MockProducer_Close_Call) Run(run func()) *MockProducer_Close_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockProducer_Close_Call) Return() *MockProducer_Close_Call {
|
||||
_c.Call.Return()
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockProducer_Close_Call) RunAndReturn(run func()) *MockProducer_Close_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// IsAvailable provides a mock function with given fields:
|
||||
func (_m *MockProducer) IsAvailable() bool {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 bool
|
||||
if rf, ok := ret.Get(0).(func() bool); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
r0 = ret.Get(0).(bool)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockProducer_IsAvailable_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsAvailable'
|
||||
type MockProducer_IsAvailable_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// IsAvailable is a helper method to define mock.On call
|
||||
func (_e *MockProducer_Expecter) IsAvailable() *MockProducer_IsAvailable_Call {
|
||||
return &MockProducer_IsAvailable_Call{Call: _e.mock.On("IsAvailable")}
|
||||
}
|
||||
|
||||
func (_c *MockProducer_IsAvailable_Call) Run(run func()) *MockProducer_IsAvailable_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockProducer_IsAvailable_Call) Return(_a0 bool) *MockProducer_IsAvailable_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockProducer_IsAvailable_Call) RunAndReturn(run func() bool) *MockProducer_IsAvailable_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Produce provides a mock function with given fields: ctx, msg
|
||||
func (_m *MockProducer) Produce(ctx context.Context, msg message.MutableMessage) (message.MessageID, error) {
|
||||
ret := _m.Called(ctx, msg)
|
||||
|
||||
var r0 message.MessageID
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, message.MutableMessage) (message.MessageID, error)); ok {
|
||||
return rf(ctx, msg)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, message.MutableMessage) message.MessageID); ok {
|
||||
r0 = rf(ctx, msg)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(message.MessageID)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, message.MutableMessage) error); ok {
|
||||
r1 = rf(ctx, msg)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockProducer_Produce_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Produce'
|
||||
type MockProducer_Produce_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Produce is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - msg message.MutableMessage
|
||||
func (_e *MockProducer_Expecter) Produce(ctx interface{}, msg interface{}) *MockProducer_Produce_Call {
|
||||
return &MockProducer_Produce_Call{Call: _e.mock.On("Produce", ctx, msg)}
|
||||
}
|
||||
|
||||
func (_c *MockProducer_Produce_Call) Run(run func(ctx context.Context, msg message.MutableMessage)) *MockProducer_Produce_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(message.MutableMessage))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockProducer_Produce_Call) Return(_a0 message.MessageID, _a1 error) *MockProducer_Produce_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockProducer_Produce_Call) RunAndReturn(run func(context.Context, message.MutableMessage) (message.MessageID, error)) *MockProducer_Produce_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// NewMockProducer creates a new instance of MockProducer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewMockProducer(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *MockProducer {
|
||||
mock := &MockProducer{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
@ -109,17 +109,17 @@ func (_c *MockManager_GetAllAvailableChannels_Call) RunAndReturn(run func() ([]t
|
||||
return _c
|
||||
}
|
||||
|
||||
// GetAvailableWAL provides a mock function with given fields: channel
|
||||
func (_m *MockManager) GetAvailableWAL(channel types.PChannelInfo) (wal.WAL, error) {
|
||||
ret := _m.Called(channel)
|
||||
// GetAvailableWAL provides a mock function with given fields: _a0
|
||||
func (_m *MockManager) GetAvailableWAL(_a0 types.PChannelInfo) (wal.WAL, error) {
|
||||
ret := _m.Called(_a0)
|
||||
|
||||
var r0 wal.WAL
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(types.PChannelInfo) (wal.WAL, error)); ok {
|
||||
return rf(channel)
|
||||
return rf(_a0)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(types.PChannelInfo) wal.WAL); ok {
|
||||
r0 = rf(channel)
|
||||
r0 = rf(_a0)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(wal.WAL)
|
||||
@ -127,7 +127,7 @@ func (_m *MockManager) GetAvailableWAL(channel types.PChannelInfo) (wal.WAL, err
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(types.PChannelInfo) error); ok {
|
||||
r1 = rf(channel)
|
||||
r1 = rf(_a0)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
@ -141,12 +141,12 @@ type MockManager_GetAvailableWAL_Call struct {
|
||||
}
|
||||
|
||||
// GetAvailableWAL is a helper method to define mock.On call
|
||||
// - channel types.PChannelInfo
|
||||
func (_e *MockManager_Expecter) GetAvailableWAL(channel interface{}) *MockManager_GetAvailableWAL_Call {
|
||||
return &MockManager_GetAvailableWAL_Call{Call: _e.mock.On("GetAvailableWAL", channel)}
|
||||
// - _a0 types.PChannelInfo
|
||||
func (_e *MockManager_Expecter) GetAvailableWAL(_a0 interface{}) *MockManager_GetAvailableWAL_Call {
|
||||
return &MockManager_GetAvailableWAL_Call{Call: _e.mock.On("GetAvailableWAL", _a0)}
|
||||
}
|
||||
|
||||
func (_c *MockManager_GetAvailableWAL_Call) Run(run func(channel types.PChannelInfo)) *MockManager_GetAvailableWAL_Call {
|
||||
func (_c *MockManager_GetAvailableWAL_Call) Run(run func(_a0 types.PChannelInfo)) *MockManager_GetAvailableWAL_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(types.PChannelInfo))
|
||||
})
|
||||
|
||||
@ -0,0 +1,176 @@
|
||||
// Code generated by mockery v2.32.4. DO NOT EDIT.
|
||||
|
||||
package mock_lazygrpc
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
grpc "google.golang.org/grpc"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// MockService is an autogenerated mock type for the Service type
|
||||
type MockService[T interface{}] struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type MockService_Expecter[T interface{}] struct {
|
||||
mock *mock.Mock
|
||||
}
|
||||
|
||||
func (_m *MockService[T]) EXPECT() *MockService_Expecter[T] {
|
||||
return &MockService_Expecter[T]{mock: &_m.Mock}
|
||||
}
|
||||
|
||||
// Close provides a mock function with given fields:
|
||||
func (_m *MockService[T]) Close() {
|
||||
_m.Called()
|
||||
}
|
||||
|
||||
// MockService_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
|
||||
type MockService_Close_Call[T interface{}] struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Close is a helper method to define mock.On call
|
||||
func (_e *MockService_Expecter[T]) Close() *MockService_Close_Call[T] {
|
||||
return &MockService_Close_Call[T]{Call: _e.mock.On("Close")}
|
||||
}
|
||||
|
||||
func (_c *MockService_Close_Call[T]) Run(run func()) *MockService_Close_Call[T] {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockService_Close_Call[T]) Return() *MockService_Close_Call[T] {
|
||||
_c.Call.Return()
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockService_Close_Call[T]) RunAndReturn(run func()) *MockService_Close_Call[T] {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// GetConn provides a mock function with given fields: ctx
|
||||
func (_m *MockService[T]) GetConn(ctx context.Context) (*grpc.ClientConn, error) {
|
||||
ret := _m.Called(ctx)
|
||||
|
||||
var r0 *grpc.ClientConn
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context) (*grpc.ClientConn, error)); ok {
|
||||
return rf(ctx)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context) *grpc.ClientConn); ok {
|
||||
r0 = rf(ctx)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*grpc.ClientConn)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
|
||||
r1 = rf(ctx)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockService_GetConn_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetConn'
|
||||
type MockService_GetConn_Call[T interface{}] struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// GetConn is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
func (_e *MockService_Expecter[T]) GetConn(ctx interface{}) *MockService_GetConn_Call[T] {
|
||||
return &MockService_GetConn_Call[T]{Call: _e.mock.On("GetConn", ctx)}
|
||||
}
|
||||
|
||||
func (_c *MockService_GetConn_Call[T]) Run(run func(ctx context.Context)) *MockService_GetConn_Call[T] {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockService_GetConn_Call[T]) Return(_a0 *grpc.ClientConn, _a1 error) *MockService_GetConn_Call[T] {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockService_GetConn_Call[T]) RunAndReturn(run func(context.Context) (*grpc.ClientConn, error)) *MockService_GetConn_Call[T] {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// GetService provides a mock function with given fields: ctx
|
||||
func (_m *MockService[T]) GetService(ctx context.Context) (T, error) {
|
||||
ret := _m.Called(ctx)
|
||||
|
||||
var r0 T
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context) (T, error)); ok {
|
||||
return rf(ctx)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context) T); ok {
|
||||
r0 = rf(ctx)
|
||||
} else {
|
||||
r0 = ret.Get(0).(T)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
|
||||
r1 = rf(ctx)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockService_GetService_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetService'
|
||||
type MockService_GetService_Call[T interface{}] struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// GetService is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
func (_e *MockService_Expecter[T]) GetService(ctx interface{}) *MockService_GetService_Call[T] {
|
||||
return &MockService_GetService_Call[T]{Call: _e.mock.On("GetService", ctx)}
|
||||
}
|
||||
|
||||
func (_c *MockService_GetService_Call[T]) Run(run func(ctx context.Context)) *MockService_GetService_Call[T] {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockService_GetService_Call[T]) Return(_a0 T, _a1 error) *MockService_GetService_Call[T] {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockService_GetService_Call[T]) RunAndReturn(run func(context.Context) (T, error)) *MockService_GetService_Call[T] {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// NewMockService creates a new instance of MockService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewMockService[T interface{}](t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *MockService[T] {
|
||||
mock := &MockService[T]{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
@ -0,0 +1,209 @@
|
||||
// Code generated by mockery v2.32.4. DO NOT EDIT.
|
||||
|
||||
package mock_resolver
|
||||
|
||||
import (
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
resolver "google.golang.org/grpc/resolver"
|
||||
|
||||
serviceresolver "github.com/milvus-io/milvus/internal/util/streamingutil/service/resolver"
|
||||
)
|
||||
|
||||
// MockBuilder is an autogenerated mock type for the Builder type
|
||||
type MockBuilder struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type MockBuilder_Expecter struct {
|
||||
mock *mock.Mock
|
||||
}
|
||||
|
||||
func (_m *MockBuilder) EXPECT() *MockBuilder_Expecter {
|
||||
return &MockBuilder_Expecter{mock: &_m.Mock}
|
||||
}
|
||||
|
||||
// Build provides a mock function with given fields: target, cc, opts
|
||||
func (_m *MockBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) {
|
||||
ret := _m.Called(target, cc, opts)
|
||||
|
||||
var r0 resolver.Resolver
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(resolver.Target, resolver.ClientConn, resolver.BuildOptions) (resolver.Resolver, error)); ok {
|
||||
return rf(target, cc, opts)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(resolver.Target, resolver.ClientConn, resolver.BuildOptions) resolver.Resolver); ok {
|
||||
r0 = rf(target, cc, opts)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(resolver.Resolver)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(resolver.Target, resolver.ClientConn, resolver.BuildOptions) error); ok {
|
||||
r1 = rf(target, cc, opts)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockBuilder_Build_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Build'
|
||||
type MockBuilder_Build_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Build is a helper method to define mock.On call
|
||||
// - target resolver.Target
|
||||
// - cc resolver.ClientConn
|
||||
// - opts resolver.BuildOptions
|
||||
func (_e *MockBuilder_Expecter) Build(target interface{}, cc interface{}, opts interface{}) *MockBuilder_Build_Call {
|
||||
return &MockBuilder_Build_Call{Call: _e.mock.On("Build", target, cc, opts)}
|
||||
}
|
||||
|
||||
func (_c *MockBuilder_Build_Call) Run(run func(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions)) *MockBuilder_Build_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(resolver.Target), args[1].(resolver.ClientConn), args[2].(resolver.BuildOptions))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockBuilder_Build_Call) Return(_a0 resolver.Resolver, _a1 error) *MockBuilder_Build_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockBuilder_Build_Call) RunAndReturn(run func(resolver.Target, resolver.ClientConn, resolver.BuildOptions) (resolver.Resolver, error)) *MockBuilder_Build_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Close provides a mock function with given fields:
|
||||
func (_m *MockBuilder) Close() {
|
||||
_m.Called()
|
||||
}
|
||||
|
||||
// MockBuilder_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
|
||||
type MockBuilder_Close_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Close is a helper method to define mock.On call
|
||||
func (_e *MockBuilder_Expecter) Close() *MockBuilder_Close_Call {
|
||||
return &MockBuilder_Close_Call{Call: _e.mock.On("Close")}
|
||||
}
|
||||
|
||||
func (_c *MockBuilder_Close_Call) Run(run func()) *MockBuilder_Close_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockBuilder_Close_Call) Return() *MockBuilder_Close_Call {
|
||||
_c.Call.Return()
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockBuilder_Close_Call) RunAndReturn(run func()) *MockBuilder_Close_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Resolver provides a mock function with given fields:
|
||||
func (_m *MockBuilder) Resolver() serviceresolver.Resolver {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 serviceresolver.Resolver
|
||||
if rf, ok := ret.Get(0).(func() serviceresolver.Resolver); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(serviceresolver.Resolver)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockBuilder_Resolver_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Resolver'
|
||||
type MockBuilder_Resolver_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Resolver is a helper method to define mock.On call
|
||||
func (_e *MockBuilder_Expecter) Resolver() *MockBuilder_Resolver_Call {
|
||||
return &MockBuilder_Resolver_Call{Call: _e.mock.On("Resolver")}
|
||||
}
|
||||
|
||||
func (_c *MockBuilder_Resolver_Call) Run(run func()) *MockBuilder_Resolver_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockBuilder_Resolver_Call) Return(_a0 serviceresolver.Resolver) *MockBuilder_Resolver_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockBuilder_Resolver_Call) RunAndReturn(run func() serviceresolver.Resolver) *MockBuilder_Resolver_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Scheme provides a mock function with given fields:
|
||||
func (_m *MockBuilder) Scheme() string {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func() string); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockBuilder_Scheme_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Scheme'
|
||||
type MockBuilder_Scheme_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Scheme is a helper method to define mock.On call
|
||||
func (_e *MockBuilder_Expecter) Scheme() *MockBuilder_Scheme_Call {
|
||||
return &MockBuilder_Scheme_Call{Call: _e.mock.On("Scheme")}
|
||||
}
|
||||
|
||||
func (_c *MockBuilder_Scheme_Call) Run(run func()) *MockBuilder_Scheme_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockBuilder_Scheme_Call) Return(_a0 string) *MockBuilder_Scheme_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockBuilder_Scheme_Call) RunAndReturn(run func() string) *MockBuilder_Scheme_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// NewMockBuilder creates a new instance of MockBuilder. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewMockBuilder(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *MockBuilder {
|
||||
mock := &MockBuilder{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
22
internal/streamingnode/client/handler/assignment/watcher.go
Normal file
22
internal/streamingnode/client/handler/assignment/watcher.go
Normal file
@ -0,0 +1,22 @@
|
||||
package assignment
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/milvus-io/milvus/pkg/streaming/util/types"
|
||||
)
|
||||
|
||||
var _ Watcher = (*watcherImpl)(nil)
|
||||
|
||||
// Watcher is the interface for the channel assignment.
|
||||
type Watcher interface {
|
||||
// Get gets the channel assignment.
|
||||
Get(ctx context.Context, channel string) *types.PChannelInfoAssigned
|
||||
|
||||
// Watch watches the channel assignment.
|
||||
// Block until new term is coming.
|
||||
Watch(ctx context.Context, channel string, previous *types.PChannelInfoAssigned) error
|
||||
|
||||
// Close stop the watcher.
|
||||
Close()
|
||||
}
|
||||
108
internal/streamingnode/client/handler/assignment/watcher_impl.go
Normal file
108
internal/streamingnode/client/handler/assignment/watcher_impl.go
Normal file
@ -0,0 +1,108 @@
|
||||
package assignment
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/service/discoverer"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/service/resolver"
|
||||
"github.com/milvus-io/milvus/pkg/log"
|
||||
"github.com/milvus-io/milvus/pkg/streaming/util/types"
|
||||
"github.com/milvus-io/milvus/pkg/util/syncutil"
|
||||
)
|
||||
|
||||
func NewWatcher(r resolver.Resolver) Watcher {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
w := &watcherImpl{
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
r: r,
|
||||
cond: *syncutil.NewContextCond(&sync.Mutex{}),
|
||||
assignments: make(map[string]types.PChannelInfoAssigned),
|
||||
}
|
||||
go w.execute()
|
||||
return w
|
||||
}
|
||||
|
||||
// watcherImpl is the implementation of the assignment watcher.
|
||||
type watcherImpl struct {
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
r resolver.Resolver
|
||||
cond syncutil.ContextCond
|
||||
assignments map[string]types.PChannelInfoAssigned // map pchannel to node.
|
||||
}
|
||||
|
||||
// execute starts the watcher.
|
||||
func (w *watcherImpl) execute() {
|
||||
log.Info("assignment watcher start")
|
||||
var err error
|
||||
defer func() {
|
||||
// error can be ignored here, so use info level log here.
|
||||
log.Info("assignment watcher close", zap.Error(err))
|
||||
}()
|
||||
|
||||
// error can be ignored here, error is always cancel by watcher's close as expected.
|
||||
// otherwise, the resolver's close is unexpected.
|
||||
err = w.r.Watch(w.ctx, func(state discoverer.VersionedState) error {
|
||||
w.updateAssignment(state)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// updateAssignment updates the assignment.
|
||||
func (w *watcherImpl) updateAssignment(state discoverer.VersionedState) {
|
||||
newAssignments := make(map[string]types.PChannelInfoAssigned)
|
||||
for _, assignments := range state.ChannelAssignmentInfo() {
|
||||
for _, pChannelInfo := range assignments.Channels {
|
||||
newAssignments[pChannelInfo.Name] = types.PChannelInfoAssigned{
|
||||
Channel: pChannelInfo,
|
||||
Node: assignments.NodeInfo,
|
||||
}
|
||||
}
|
||||
}
|
||||
w.cond.LockAndBroadcast()
|
||||
w.assignments = newAssignments
|
||||
w.cond.L.Unlock()
|
||||
}
|
||||
|
||||
// Get gets the current pchannel assignment.
|
||||
func (w *watcherImpl) Get(ctx context.Context, channel string) *types.PChannelInfoAssigned {
|
||||
w.cond.L.Lock()
|
||||
defer w.cond.L.Unlock()
|
||||
|
||||
if info, ok := w.assignments[channel]; ok {
|
||||
return &info
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Watch watches the channel assignment.
|
||||
func (w *watcherImpl) Watch(ctx context.Context, channel string, previous *types.PChannelInfoAssigned) error {
|
||||
w.cond.L.Lock()
|
||||
|
||||
term := types.InitialTerm
|
||||
if previous != nil {
|
||||
term = previous.Channel.Term
|
||||
}
|
||||
|
||||
for {
|
||||
if info, ok := w.assignments[channel]; ok {
|
||||
if info.Channel.Term > term {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err := w.cond.Wait(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
w.cond.L.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close closes the watcher.
|
||||
func (w *watcherImpl) Close() {
|
||||
w.cancel()
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
package assignment
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"google.golang.org/grpc/resolver"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/mocks/util/streamingutil/service/mock_resolver"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/service/attributes"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/service/discoverer"
|
||||
"github.com/milvus-io/milvus/pkg/streaming/util/types"
|
||||
"github.com/milvus-io/milvus/pkg/util/typeutil"
|
||||
)
|
||||
|
||||
func TestWatcher(t *testing.T) {
|
||||
r := mock_resolver.NewMockResolver(t)
|
||||
|
||||
ch := make(chan discoverer.VersionedState)
|
||||
r.EXPECT().Watch(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, f func(s discoverer.VersionedState) error) error {
|
||||
for {
|
||||
select {
|
||||
case v, ok := <-ch:
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
f(v)
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
})
|
||||
w := NewWatcher(r)
|
||||
defer w.Close()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
|
||||
defer cancel()
|
||||
a := w.Get(ctx, "test_pchannel")
|
||||
assert.Nil(t, a)
|
||||
err := w.Watch(ctx, "test_pchannel", nil)
|
||||
assert.ErrorIs(t, err, context.DeadlineExceeded)
|
||||
|
||||
ch <- discoverer.VersionedState{
|
||||
Version: typeutil.VersionInt64(1),
|
||||
State: resolver.State{
|
||||
Addresses: []resolver.Address{
|
||||
{
|
||||
Addr: "test_addr",
|
||||
BalancerAttributes: attributes.WithChannelAssignmentInfo(
|
||||
new(attributes.Attributes),
|
||||
&types.StreamingNodeAssignment{
|
||||
NodeInfo: types.StreamingNodeInfo{
|
||||
ServerID: 1,
|
||||
Address: "test_addr",
|
||||
},
|
||||
Channels: map[string]types.PChannelInfo{
|
||||
"test_pchannel": {
|
||||
Name: "test_pchannel",
|
||||
Term: 1,
|
||||
},
|
||||
"test_pchannel_2": {
|
||||
Name: "test_pchannel_2",
|
||||
Term: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
err = w.Watch(context.Background(), "test_pchannel", nil)
|
||||
assert.NoError(t, err)
|
||||
a = w.Get(ctx, "test_pchannel")
|
||||
assert.NotNil(t, a)
|
||||
assert.Equal(t, int64(1), a.Channel.Term)
|
||||
|
||||
err = w.Watch(context.Background(), "test_pchannel_2", nil)
|
||||
assert.NoError(t, err)
|
||||
a = w.Get(ctx, "test_pchannel_2")
|
||||
assert.NotNil(t, a)
|
||||
assert.Equal(t, int64(2), a.Channel.Term)
|
||||
|
||||
ctx, cancel = context.WithTimeout(context.Background(), 10*time.Millisecond)
|
||||
defer cancel()
|
||||
err = w.Watch(ctx, "test_pchannel", a)
|
||||
assert.ErrorIs(t, err, context.DeadlineExceeded)
|
||||
}
|
||||
18
internal/streamingnode/client/handler/consumer/consumer.go
Normal file
18
internal/streamingnode/client/handler/consumer/consumer.go
Normal file
@ -0,0 +1,18 @@
|
||||
package consumer
|
||||
|
||||
var _ Consumer = (*consumerImpl)(nil)
|
||||
|
||||
// Consumer is the interface that wraps the basic consume method on grpc stream.
|
||||
// Consumer is work on a single stream on grpc,
|
||||
// so Consumer cannot recover from failure because of the stream is broken.
|
||||
type Consumer interface {
|
||||
// Error returns the error of scanner failed.
|
||||
// Will block until scanner is closed or Chan is dry out.
|
||||
Error() error
|
||||
|
||||
// Done returns a channel which will be closed when scanner is finished or closed.
|
||||
Done() <-chan struct{}
|
||||
|
||||
// Close the consumer, release the underlying resources.
|
||||
Close()
|
||||
}
|
||||
181
internal/streamingnode/client/handler/consumer/consumer_impl.go
Normal file
181
internal/streamingnode/client/handler/consumer/consumer_impl.go
Normal file
@ -0,0 +1,181 @@
|
||||
package consumer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/cockroachdb/errors"
|
||||
"go.uber.org/zap"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/proto/streamingpb"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/service/contextutil"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/status"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/typeconverter"
|
||||
"github.com/milvus-io/milvus/pkg/log"
|
||||
"github.com/milvus-io/milvus/pkg/streaming/util/message"
|
||||
"github.com/milvus-io/milvus/pkg/streaming/util/options"
|
||||
"github.com/milvus-io/milvus/pkg/streaming/util/types"
|
||||
"github.com/milvus-io/milvus/pkg/util/syncutil"
|
||||
)
|
||||
|
||||
// ConsumerOptions is the options for creating a consumer.
|
||||
type ConsumerOptions struct {
|
||||
// The cosume target
|
||||
Assignment *types.PChannelInfoAssigned
|
||||
|
||||
// DeliverPolicy is the deliver policy of the consumer.
|
||||
DeliverPolicy options.DeliverPolicy
|
||||
|
||||
// DeliverFilters is the deliver filters of the consumer.
|
||||
DeliverFilters []options.DeliverFilter
|
||||
|
||||
// Handler is the message handler used to handle message after recv from consumer.
|
||||
MessageHandler message.Handler
|
||||
}
|
||||
|
||||
// CreateConsumer creates a new consumer client.
|
||||
func CreateConsumer(
|
||||
ctx context.Context,
|
||||
opts *ConsumerOptions,
|
||||
handlerClient streamingpb.StreamingNodeHandlerServiceClient,
|
||||
) (Consumer, error) {
|
||||
ctx, err := createConsumeRequest(ctx, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO: configurable or auto adjust grpc.MaxCallRecvMsgSize
|
||||
streamClient, err := handlerClient.Consume(ctx, grpc.MaxCallRecvMsgSize(8388608))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Recv the first response from server.
|
||||
// It must be a create response.
|
||||
resp, err := streamClient.Recv()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
createResp := resp.GetCreate()
|
||||
if createResp == nil {
|
||||
return nil, status.NewInvalidRequestSeq("first message arrive must be create response")
|
||||
}
|
||||
cli := &consumerImpl{
|
||||
walName: createResp.GetWalName(),
|
||||
assignment: *opts.Assignment,
|
||||
grpcStreamClient: streamClient,
|
||||
handlerClient: handlerClient,
|
||||
logger: log.With(
|
||||
zap.String("walName", createResp.GetWalName()),
|
||||
zap.String("pchannel", opts.Assignment.Channel.Name),
|
||||
zap.Int64("term", opts.Assignment.Channel.Term),
|
||||
zap.Int64("streamingNodeID", opts.Assignment.Node.ServerID)),
|
||||
msgHandler: opts.MessageHandler,
|
||||
finishErr: syncutil.NewFuture[error](),
|
||||
}
|
||||
go cli.execute()
|
||||
return cli, nil
|
||||
}
|
||||
|
||||
// createConsumeRequest creates the consume request.
|
||||
func createConsumeRequest(ctx context.Context, opts *ConsumerOptions) (context.Context, error) {
|
||||
// select server to consume.
|
||||
ctx = contextutil.WithPickServerID(ctx, opts.Assignment.Node.ServerID)
|
||||
// create the consumer request.
|
||||
deliverPolicy, err := typeconverter.NewProtoFromDeliverPolicy(opts.DeliverPolicy)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "at convert deliver policy")
|
||||
}
|
||||
deliverFilters, err := typeconverter.NewProtosFromDeliverFilters(opts.DeliverFilters)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "at convert deliver filters")
|
||||
}
|
||||
return contextutil.WithCreateConsumer(ctx, &streamingpb.CreateConsumerRequest{
|
||||
Pchannel: typeconverter.NewProtoFromPChannelInfo(opts.Assignment.Channel),
|
||||
DeliverPolicy: deliverPolicy,
|
||||
DeliverFilters: deliverFilters,
|
||||
}), nil
|
||||
}
|
||||
|
||||
type consumerImpl struct {
|
||||
walName string
|
||||
assignment types.PChannelInfoAssigned
|
||||
grpcStreamClient streamingpb.StreamingNodeHandlerService_ConsumeClient
|
||||
handlerClient streamingpb.StreamingNodeHandlerServiceClient
|
||||
logger *log.MLogger
|
||||
msgHandler message.Handler
|
||||
finishErr *syncutil.Future[error]
|
||||
}
|
||||
|
||||
// Close close the consumer client.
|
||||
func (c *consumerImpl) Close() {
|
||||
// Send the close request to server.
|
||||
if err := c.grpcStreamClient.Send(&streamingpb.ConsumeRequest{
|
||||
Request: &streamingpb.ConsumeRequest_Close{},
|
||||
}); err != nil {
|
||||
c.logger.Warn("send close request failed", zap.Error(err))
|
||||
}
|
||||
// close the grpc client stream.
|
||||
if err := c.grpcStreamClient.CloseSend(); err != nil {
|
||||
c.logger.Warn("close grpc stream failed", zap.Error(err))
|
||||
}
|
||||
<-c.finishErr.Done()
|
||||
}
|
||||
|
||||
// Error returns the error of the consumer client.
|
||||
func (c *consumerImpl) Error() error {
|
||||
return c.finishErr.Get()
|
||||
}
|
||||
|
||||
// Done returns a channel that closes when the consumer client is closed.
|
||||
func (c *consumerImpl) Done() <-chan struct{} {
|
||||
return c.finishErr.Done()
|
||||
}
|
||||
|
||||
// execute starts the recv loop.
|
||||
func (c *consumerImpl) execute() {
|
||||
c.recvLoop()
|
||||
}
|
||||
|
||||
// recvLoop is the recv arm of the grpc stream.
|
||||
// Throughput of the grpc framework should be ok to use single stream to receive message.
|
||||
// Once throughput is not enough, look at https://grpc.io/docs/guides/performance/ to find the solution.
|
||||
func (c *consumerImpl) recvLoop() (err error) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
c.logger.Warn("recv arm of stream closed with unexpected error", zap.Error(err))
|
||||
} else {
|
||||
c.logger.Info("recv arm of stream closed")
|
||||
}
|
||||
c.finishErr.Set(err)
|
||||
c.msgHandler.Close()
|
||||
}()
|
||||
|
||||
for {
|
||||
resp, err := c.grpcStreamClient.Recv()
|
||||
if errors.Is(err, io.EOF) {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch resp := resp.Response.(type) {
|
||||
case *streamingpb.ConsumeResponse_Consume:
|
||||
msgID, err := message.UnmarshalMessageID(c.walName, resp.Consume.GetId().GetId())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.msgHandler.Handle(message.NewImmutableMesasge(
|
||||
msgID,
|
||||
resp.Consume.GetMessage().GetPayload(),
|
||||
resp.Consume.GetMessage().GetProperties(),
|
||||
))
|
||||
case *streamingpb.ConsumeResponse_Close:
|
||||
// Should receive io.EOF after that.
|
||||
// Do nothing at current implementation.
|
||||
default:
|
||||
c.logger.Warn("unknown response type", zap.Any("response", resp))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
package consumer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/mocks/proto/mock_streamingpb"
|
||||
"github.com/milvus-io/milvus/internal/proto/streamingpb"
|
||||
"github.com/milvus-io/milvus/pkg/streaming/util/message"
|
||||
"github.com/milvus-io/milvus/pkg/streaming/util/options"
|
||||
"github.com/milvus-io/milvus/pkg/streaming/util/types"
|
||||
"github.com/milvus-io/milvus/pkg/streaming/walimpls/impls/walimplstest"
|
||||
)
|
||||
|
||||
func TestConsumer(t *testing.T) {
|
||||
c := mock_streamingpb.NewMockStreamingNodeHandlerServiceClient(t)
|
||||
cc := mock_streamingpb.NewMockStreamingNodeHandlerService_ConsumeClient(t)
|
||||
recvCh := make(chan *streamingpb.ConsumeResponse, 10)
|
||||
cc.EXPECT().Recv().RunAndReturn(func() (*streamingpb.ConsumeResponse, error) {
|
||||
msg, ok := <-recvCh
|
||||
if !ok {
|
||||
return nil, io.EOF
|
||||
}
|
||||
return msg, nil
|
||||
})
|
||||
sendCh := make(chan *streamingpb.ConsumeRequest, 10)
|
||||
cc.EXPECT().Send(mock.Anything).RunAndReturn(func(cr *streamingpb.ConsumeRequest) error {
|
||||
sendCh <- cr
|
||||
return nil
|
||||
})
|
||||
c.EXPECT().Consume(mock.Anything, mock.Anything).Return(cc, nil)
|
||||
cc.EXPECT().CloseSend().RunAndReturn(func() error {
|
||||
recvCh <- &streamingpb.ConsumeResponse{Response: &streamingpb.ConsumeResponse_Close{}}
|
||||
close(recvCh)
|
||||
return nil
|
||||
})
|
||||
|
||||
ctx := context.Background()
|
||||
resultCh := make(message.ChanMessageHandler, 1)
|
||||
opts := &ConsumerOptions{
|
||||
Assignment: &types.PChannelInfoAssigned{
|
||||
Channel: types.PChannelInfo{Name: "test", Term: 1},
|
||||
Node: types.StreamingNodeInfo{ServerID: 1, Address: "localhost"},
|
||||
},
|
||||
DeliverPolicy: options.DeliverPolicyAll(),
|
||||
DeliverFilters: []options.DeliverFilter{
|
||||
options.DeliverFilterVChannel("test-1"),
|
||||
options.DeliverFilterTimeTickGT(100),
|
||||
},
|
||||
MessageHandler: resultCh,
|
||||
}
|
||||
|
||||
recvCh <- &streamingpb.ConsumeResponse{
|
||||
Response: &streamingpb.ConsumeResponse_Create{
|
||||
Create: &streamingpb.CreateConsumerResponse{
|
||||
WalName: "test",
|
||||
},
|
||||
},
|
||||
}
|
||||
recvCh <- &streamingpb.ConsumeResponse{
|
||||
Response: &streamingpb.ConsumeResponse_Consume{
|
||||
Consume: &streamingpb.ConsumeMessageReponse{
|
||||
Id: &streamingpb.MessageID{
|
||||
Id: walimplstest.NewTestMessageID(1).Marshal(),
|
||||
},
|
||||
Message: &streamingpb.Message{
|
||||
Payload: []byte{},
|
||||
Properties: make(map[string]string),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
consumer, err := CreateConsumer(ctx, opts, c)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, consumer)
|
||||
consumer.Close()
|
||||
msg := <-resultCh
|
||||
assert.True(t, msg.MessageID().EQ(walimplstest.NewTestMessageID(1)))
|
||||
<-consumer.Done()
|
||||
assert.NoError(t, consumer.Error())
|
||||
}
|
||||
151
internal/streamingnode/client/handler/handler_client.go
Normal file
151
internal/streamingnode/client/handler/handler_client.go
Normal file
@ -0,0 +1,151 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/proto/streamingpb"
|
||||
"github.com/milvus-io/milvus/internal/streamingnode/client/handler/assignment"
|
||||
"github.com/milvus-io/milvus/internal/streamingnode/client/handler/consumer"
|
||||
"github.com/milvus-io/milvus/internal/streamingnode/client/handler/producer"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/service/balancer/picker"
|
||||
streamingserviceinterceptor "github.com/milvus-io/milvus/internal/util/streamingutil/service/interceptor"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/service/lazygrpc"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/service/resolver"
|
||||
"github.com/milvus-io/milvus/pkg/streaming/util/message"
|
||||
"github.com/milvus-io/milvus/pkg/streaming/util/options"
|
||||
"github.com/milvus-io/milvus/pkg/streaming/util/types"
|
||||
"github.com/milvus-io/milvus/pkg/tracer"
|
||||
"github.com/milvus-io/milvus/pkg/util/interceptor"
|
||||
"github.com/milvus-io/milvus/pkg/util/lifetime"
|
||||
"github.com/milvus-io/milvus/pkg/util/lock"
|
||||
"github.com/milvus-io/milvus/pkg/util/paramtable"
|
||||
"github.com/milvus-io/milvus/pkg/util/typeutil"
|
||||
)
|
||||
|
||||
var _ HandlerClient = (*handlerClientImpl)(nil)
|
||||
|
||||
type (
|
||||
Producer = producer.Producer
|
||||
Consumer = consumer.Consumer
|
||||
)
|
||||
|
||||
// ProducerOptions is the options for creating a producer.
|
||||
type ProducerOptions struct {
|
||||
// PChannel is the pchannel of the producer.
|
||||
PChannel string
|
||||
}
|
||||
|
||||
// ConsumerOptions is the options for creating a consumer.
|
||||
type ConsumerOptions struct {
|
||||
// PChannel is the pchannel of the consumer.
|
||||
PChannel string
|
||||
|
||||
// DeliverPolicy is the deliver policy of the consumer.
|
||||
DeliverPolicy options.DeliverPolicy
|
||||
|
||||
// DeliverFilters is the deliver filters of the consumer.
|
||||
DeliverFilters []options.DeliverFilter
|
||||
|
||||
// Handler is the message handler used to handle message after recv from consumer.
|
||||
MessageHandler message.Handler
|
||||
}
|
||||
|
||||
// HandlerClient is the interface that wraps streamingpb.StreamingNodeHandlerServiceClient.
|
||||
// HandlerClient wraps the PChannel Assignment Service Discovery.
|
||||
// Provides the ability to create pchannel-level producer and consumer.
|
||||
type HandlerClient interface {
|
||||
// CreateProducer creates a producer.
|
||||
// Producer is a stream client without keep alive promise.
|
||||
// It will be available until context canceled, active close, streaming error or remote server wal closing.
|
||||
// Because of there's no more ProducerOptions except PChannel, so a producer of same PChannel is shared by reference count.
|
||||
CreateProducer(ctx context.Context, opts *ProducerOptions) (Producer, error)
|
||||
|
||||
// CreateConsumer creates a consumer.
|
||||
// Consumer is a stream client without keep alive promise.
|
||||
// It will be available until context canceled, active close, streaming error or remote server wal closing.
|
||||
// A consumer will not share stream connection with other consumers.
|
||||
CreateConsumer(ctx context.Context, opts *ConsumerOptions) (Consumer, error)
|
||||
|
||||
// Close closes the handler client.
|
||||
// It will only stop the underlying service discovery, but don't stop the producer and consumer created by it.
|
||||
// So please close Producer and Consumer created by it before close the handler client.
|
||||
Close()
|
||||
}
|
||||
|
||||
// NewHandlerClient creates a new handler client.
|
||||
func NewHandlerClient(w types.AssignmentDiscoverWatcher) HandlerClient {
|
||||
rb := resolver.NewChannelAssignmentBuilder(w)
|
||||
dialTimeout := paramtable.Get().StreamingNodeGrpcClientCfg.DialTimeout.GetAsDuration(time.Millisecond)
|
||||
dialOptions := getDialOptions(rb)
|
||||
conn := lazygrpc.NewConn(func(ctx context.Context) (*grpc.ClientConn, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, dialTimeout)
|
||||
defer cancel()
|
||||
return grpc.DialContext(
|
||||
ctx,
|
||||
resolver.ChannelAssignmentResolverScheme+":///"+typeutil.StreamingNodeRole,
|
||||
dialOptions..., // TODO: we should use dynamic service config in future by add it to resolver.
|
||||
)
|
||||
})
|
||||
watcher := assignment.NewWatcher(rb.Resolver())
|
||||
return &handlerClientImpl{
|
||||
lifetime: lifetime.NewLifetime(lifetime.Working),
|
||||
service: lazygrpc.WithServiceCreator(conn, streamingpb.NewStreamingNodeHandlerServiceClient),
|
||||
rb: rb,
|
||||
watcher: watcher,
|
||||
rebalanceTrigger: w,
|
||||
sharedProducers: make(map[string]*typeutil.WeakReference[Producer]),
|
||||
sharedProducerKeyLock: lock.NewKeyLock[string](),
|
||||
newProducer: producer.CreateProducer,
|
||||
newConsumer: consumer.CreateConsumer,
|
||||
}
|
||||
}
|
||||
|
||||
// getDialOptions returns grpc dial options.
|
||||
func getDialOptions(rb resolver.Builder) []grpc.DialOption {
|
||||
cfg := ¶mtable.Get().StreamingNodeGrpcClientCfg
|
||||
retryPolicy := cfg.GetDefaultRetryPolicy()
|
||||
retryPolicy["retryableStatusCodes"] = []string{"UNAVAILABLE"}
|
||||
defaultServiceConfig := map[string]interface{}{
|
||||
"loadBalancingConfig": []map[string]interface{}{
|
||||
{picker.ServerIDPickerBalancerName: map[string]interface{}{}},
|
||||
},
|
||||
"methodConfig": []map[string]interface{}{
|
||||
{
|
||||
"name": []map[string]string{
|
||||
{"service": "milvus.proto.streaming.StreamingNodeHandlerService"},
|
||||
},
|
||||
"waitForReady": true,
|
||||
"retryPolicy": retryPolicy,
|
||||
},
|
||||
},
|
||||
}
|
||||
defaultServiceConfigJSON, err := json.Marshal(defaultServiceConfig)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
dialOptions := cfg.GetDialOptionsFromConfig()
|
||||
dialOptions = append(dialOptions,
|
||||
grpc.WithBlock(),
|
||||
grpc.WithResolvers(rb),
|
||||
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||
grpc.WithChainUnaryInterceptor(
|
||||
otelgrpc.UnaryClientInterceptor(tracer.GetInterceptorOpts()...),
|
||||
interceptor.ClusterInjectionUnaryClientInterceptor(),
|
||||
streamingserviceinterceptor.NewStreamingServiceUnaryClientInterceptor(),
|
||||
),
|
||||
grpc.WithChainStreamInterceptor(
|
||||
otelgrpc.StreamClientInterceptor(tracer.GetInterceptorOpts()...),
|
||||
interceptor.ClusterInjectionStreamClientInterceptor(),
|
||||
streamingserviceinterceptor.NewStreamingServiceStreamClientInterceptor(),
|
||||
),
|
||||
grpc.WithReturnConnectionError(),
|
||||
grpc.WithDefaultServiceConfig(string(defaultServiceConfigJSON)),
|
||||
)
|
||||
return dialOptions
|
||||
}
|
||||
216
internal/streamingnode/client/handler/handler_client_impl.go
Normal file
216
internal/streamingnode/client/handler/handler_client_impl.go
Normal file
@ -0,0 +1,216 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
"github.com/cockroachdb/errors"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/proto/streamingpb"
|
||||
"github.com/milvus-io/milvus/internal/streamingnode/client/handler/assignment"
|
||||
"github.com/milvus-io/milvus/internal/streamingnode/client/handler/consumer"
|
||||
"github.com/milvus-io/milvus/internal/streamingnode/client/handler/producer"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/service/balancer/picker"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/service/lazygrpc"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/service/resolver"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/status"
|
||||
"github.com/milvus-io/milvus/pkg/log"
|
||||
"github.com/milvus-io/milvus/pkg/streaming/util/types"
|
||||
"github.com/milvus-io/milvus/pkg/util/lifetime"
|
||||
"github.com/milvus-io/milvus/pkg/util/lock"
|
||||
"github.com/milvus-io/milvus/pkg/util/typeutil"
|
||||
)
|
||||
|
||||
var errWaitNextBackoff = errors.New("wait for next backoff")
|
||||
|
||||
type handlerClientImpl struct {
|
||||
lifetime lifetime.Lifetime[lifetime.State]
|
||||
service lazygrpc.Service[streamingpb.StreamingNodeHandlerServiceClient]
|
||||
rb resolver.Builder
|
||||
watcher assignment.Watcher
|
||||
rebalanceTrigger types.AssignmentRebalanceTrigger
|
||||
sharedProducers map[string]*typeutil.WeakReference[Producer] // map the pchannel to shared producer.
|
||||
sharedProducerKeyLock *lock.KeyLock[string]
|
||||
newProducer func(ctx context.Context, opts *producer.ProducerOptions, handler streamingpb.StreamingNodeHandlerServiceClient) (Producer, error)
|
||||
newConsumer func(ctx context.Context, opts *consumer.ConsumerOptions, handlerClient streamingpb.StreamingNodeHandlerServiceClient) (Consumer, error)
|
||||
}
|
||||
|
||||
// CreateProducer creates a producer.
|
||||
func (hc *handlerClientImpl) CreateProducer(ctx context.Context, opts *ProducerOptions) (Producer, error) {
|
||||
if hc.lifetime.Add(lifetime.IsWorking) != nil {
|
||||
return nil, status.NewOnShutdownError("handler client is closed")
|
||||
}
|
||||
defer hc.lifetime.Done()
|
||||
|
||||
p, err := hc.createHandlerAfterStreamingNodeReady(ctx, opts.PChannel, func(ctx context.Context, assign *types.PChannelInfoAssigned) (any, error) {
|
||||
// Wait for handler service is ready.
|
||||
handlerService, err := hc.service.GetService(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return hc.createOrGetSharedProducer(ctx, &producer.ProducerOptions{Assignment: assign}, handlerService)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p.(Producer), nil
|
||||
}
|
||||
|
||||
// CreateConsumer creates a consumer.
|
||||
func (hc *handlerClientImpl) CreateConsumer(ctx context.Context, opts *ConsumerOptions) (Consumer, error) {
|
||||
if hc.lifetime.Add(lifetime.IsWorking) != nil {
|
||||
return nil, status.NewOnShutdownError("handler client is closed")
|
||||
}
|
||||
defer hc.lifetime.Done()
|
||||
|
||||
c, err := hc.createHandlerAfterStreamingNodeReady(ctx, opts.PChannel, func(ctx context.Context, assign *types.PChannelInfoAssigned) (any, error) {
|
||||
// Wait for handler service is ready.
|
||||
handlerService, err := hc.service.GetService(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return hc.newConsumer(ctx, &consumer.ConsumerOptions{
|
||||
Assignment: assign,
|
||||
DeliverPolicy: opts.DeliverPolicy,
|
||||
DeliverFilters: opts.DeliverFilters,
|
||||
MessageHandler: opts.MessageHandler,
|
||||
}, handlerService)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.(Consumer), nil
|
||||
}
|
||||
|
||||
// createHandlerAfterStreamingNodeReady creates a handler until streaming node ready.
|
||||
// If streaming node is not ready, it will block until new assignment term is coming or context timeout.
|
||||
func (hc *handlerClientImpl) createHandlerAfterStreamingNodeReady(ctx context.Context, pchannel string, create func(ctx context.Context, assign *types.PChannelInfoAssigned) (any, error)) (any, error) {
|
||||
logger := log.With(zap.String("pchannel", pchannel))
|
||||
// TODO: backoff should be configurable.
|
||||
backoff := backoff.NewExponentialBackOff()
|
||||
for {
|
||||
assign := hc.watcher.Get(ctx, pchannel)
|
||||
if assign != nil {
|
||||
// Find assignment, try to create producer on this assignment.
|
||||
c, err := create(ctx, assign)
|
||||
if err == nil {
|
||||
return c, nil
|
||||
}
|
||||
logger.Warn("create handler failed", zap.Any("assignment", assign), zap.Error(err))
|
||||
|
||||
// Check if the error is permanent failure until new assignment.
|
||||
if isPermanentFailureUntilNewAssignment(err) {
|
||||
reportErr := hc.rebalanceTrigger.ReportAssignmentError(ctx, assign.Channel, err)
|
||||
logger.Info("report assignment error", zap.NamedError("assignmentError", err), zap.Error(reportErr))
|
||||
}
|
||||
} else {
|
||||
log.Warn("assignment not found")
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
nextBackoff := backoff.NextBackOff()
|
||||
logger.Info("wait for next backoff", zap.Duration("nextBackoff", nextBackoff))
|
||||
isAssignemtChange, err := hc.waitForNextBackoff(ctx, pchannel, assign, nextBackoff)
|
||||
cost := time.Since(start)
|
||||
if err != nil {
|
||||
logger.Warn("wait for next backoff failed", zap.Error(err), zap.Duration("cost", cost))
|
||||
return nil, err
|
||||
}
|
||||
logger.Info("wait for next backoff done", zap.Bool("isAssignmentChange", isAssignemtChange), zap.Duration("cost", cost))
|
||||
}
|
||||
}
|
||||
|
||||
// waitForNextBackoff waits for next backoff.
|
||||
func (hc *handlerClientImpl) waitForNextBackoff(ctx context.Context, pchannel string, assign *types.PChannelInfoAssigned, nextBackoff time.Duration) (bool, error) {
|
||||
ctx, cancel := context.WithTimeoutCause(ctx, nextBackoff, errWaitNextBackoff)
|
||||
defer cancel()
|
||||
// Block until new assignment term is coming.
|
||||
err := hc.watcher.Watch(ctx, pchannel, assign)
|
||||
if err == nil || errors.Is(context.Cause(ctx), errWaitNextBackoff) {
|
||||
return err == nil, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
// getFromSharedProducers gets a shared producer from shared producers.A
|
||||
func (hc *handlerClientImpl) getFromSharedProducers(channelInfo types.PChannelInfo) Producer {
|
||||
weakProducerRef, ok := hc.sharedProducers[channelInfo.Name]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
strongProducerRef := weakProducerRef.Upgrade()
|
||||
if strongProducerRef == nil {
|
||||
// upgrade failure means the outer producer is all closed.
|
||||
// remove the weak ref and create again.
|
||||
delete(hc.sharedProducers, channelInfo.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
p := newSharedProducer(strongProducerRef)
|
||||
if !p.IsAvailable() || p.Assignment().Channel.Term < channelInfo.Term {
|
||||
// if the producer is not available or the term is less than expected.
|
||||
// close it and return to create new one.
|
||||
p.Close()
|
||||
delete(hc.sharedProducers, channelInfo.Name)
|
||||
return nil
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// createOrGetSharedProducer creates or get a shared producer.
|
||||
// because vchannel in same pchannel can share the same producer.
|
||||
func (hc *handlerClientImpl) createOrGetSharedProducer(
|
||||
ctx context.Context,
|
||||
opts *producer.ProducerOptions,
|
||||
handlerService streamingpb.StreamingNodeHandlerServiceClient,
|
||||
) (Producer, error) {
|
||||
hc.sharedProducerKeyLock.Lock(opts.Assignment.Channel.Name)
|
||||
defer hc.sharedProducerKeyLock.Unlock(opts.Assignment.Channel.Name)
|
||||
|
||||
// check if shared producer is created within key lock.
|
||||
if p := hc.getFromSharedProducers(opts.Assignment.Channel); p != nil {
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// create a new producer and insert it into shared producers.
|
||||
newProducer, err := hc.newProducer(ctx, opts, handlerService)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newStrongProducerRef := typeutil.NewSharedReference(newProducer)
|
||||
// store a weak ref and return a strong ref.
|
||||
returned := newStrongProducerRef.Clone()
|
||||
stored := newStrongProducerRef.Downgrade()
|
||||
hc.sharedProducers[opts.Assignment.Channel.Name] = stored
|
||||
return newSharedProducer(returned), nil
|
||||
}
|
||||
|
||||
// Close closes the handler client.
|
||||
func (hc *handlerClientImpl) Close() {
|
||||
hc.lifetime.SetState(lifetime.Stopped)
|
||||
hc.lifetime.Wait()
|
||||
hc.lifetime.Close()
|
||||
|
||||
hc.watcher.Close()
|
||||
hc.service.Close()
|
||||
hc.rb.Close()
|
||||
}
|
||||
|
||||
// isPermanentFailureUntilNewAssignment checks if the error is permanent failure until new assignment.
|
||||
// If the encounter this error, client should notify the assignment service to rebalance the assignment and update discovery result.
|
||||
// block until new assignment term is coming or context timeout.
|
||||
func isPermanentFailureUntilNewAssignment(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
// The error is reported by grpc balancer at client that the sub connection is not exist (remote server is down at view of session).
|
||||
if picker.IsErrSubConnNoExist(err) {
|
||||
return true
|
||||
}
|
||||
// The error is reported by remote server that the wal is not exist at remote server.
|
||||
streamingServiceErr := status.AsStreamingError(err)
|
||||
return streamingServiceErr.IsWrongStreamingNode()
|
||||
}
|
||||
145
internal/streamingnode/client/handler/handler_client_test.go
Normal file
145
internal/streamingnode/client/handler/handler_client_test.go
Normal file
@ -0,0 +1,145 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/mocks/proto/mock_streamingpb"
|
||||
"github.com/milvus-io/milvus/internal/mocks/streamingnode/client/handler/mock_assignment"
|
||||
"github.com/milvus-io/milvus/internal/mocks/streamingnode/client/handler/mock_consumer"
|
||||
"github.com/milvus-io/milvus/internal/mocks/streamingnode/client/handler/mock_producer"
|
||||
"github.com/milvus-io/milvus/internal/mocks/util/streamingutil/service/mock_lazygrpc"
|
||||
"github.com/milvus-io/milvus/internal/mocks/util/streamingutil/service/mock_resolver"
|
||||
"github.com/milvus-io/milvus/internal/proto/streamingpb"
|
||||
"github.com/milvus-io/milvus/internal/streamingnode/client/handler/consumer"
|
||||
"github.com/milvus-io/milvus/internal/streamingnode/client/handler/producer"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/status"
|
||||
"github.com/milvus-io/milvus/pkg/mocks/streaming/util/mock_types"
|
||||
"github.com/milvus-io/milvus/pkg/streaming/util/message"
|
||||
"github.com/milvus-io/milvus/pkg/streaming/util/options"
|
||||
"github.com/milvus-io/milvus/pkg/streaming/util/types"
|
||||
"github.com/milvus-io/milvus/pkg/util/lifetime"
|
||||
"github.com/milvus-io/milvus/pkg/util/lock"
|
||||
"github.com/milvus-io/milvus/pkg/util/paramtable"
|
||||
"github.com/milvus-io/milvus/pkg/util/typeutil"
|
||||
)
|
||||
|
||||
func TestHandlerClient(t *testing.T) {
|
||||
assignment := &types.PChannelInfoAssigned{
|
||||
Channel: types.PChannelInfo{Name: "pchannel", Term: 1},
|
||||
Node: types.StreamingNodeInfo{ServerID: 1, Address: "localhost"},
|
||||
}
|
||||
|
||||
service := mock_lazygrpc.NewMockService[streamingpb.StreamingNodeHandlerServiceClient](t)
|
||||
handlerServiceClient := mock_streamingpb.NewMockStreamingNodeHandlerServiceClient(t)
|
||||
service.EXPECT().GetService(mock.Anything).Return(handlerServiceClient, nil)
|
||||
rb := mock_resolver.NewMockBuilder(t)
|
||||
rb.EXPECT().Close().Run(func() {})
|
||||
w := mock_assignment.NewMockWatcher(t)
|
||||
w.EXPECT().Close().Run(func() {})
|
||||
|
||||
p := mock_producer.NewMockProducer(t)
|
||||
p.EXPECT().IsAvailable().Return(true)
|
||||
p.EXPECT().Assignment().Return(*assignment)
|
||||
p.EXPECT().Close().Run(func() {})
|
||||
c := mock_consumer.NewMockConsumer(t)
|
||||
c.EXPECT().Close().Run(func() {})
|
||||
|
||||
rebalanceTrigger := mock_types.NewMockAssignmentRebalanceTrigger(t)
|
||||
rebalanceTrigger.EXPECT().ReportAssignmentError(mock.Anything, mock.Anything, mock.Anything).Return(nil)
|
||||
|
||||
pK := 0
|
||||
handler := &handlerClientImpl{
|
||||
lifetime: lifetime.NewLifetime(lifetime.Working),
|
||||
service: service,
|
||||
rb: rb,
|
||||
watcher: w,
|
||||
rebalanceTrigger: rebalanceTrigger,
|
||||
sharedProducers: make(map[string]*typeutil.WeakReference[producer.Producer]),
|
||||
sharedProducerKeyLock: lock.NewKeyLock[string](),
|
||||
newProducer: func(ctx context.Context, opts *producer.ProducerOptions, handler streamingpb.StreamingNodeHandlerServiceClient) (Producer, error) {
|
||||
if pK == 0 {
|
||||
pK++
|
||||
return nil, status.NewUnmatchedChannelTerm("pchannel", 1, 2)
|
||||
}
|
||||
return p, nil
|
||||
},
|
||||
newConsumer: func(ctx context.Context, opts *consumer.ConsumerOptions, handlerClient streamingpb.StreamingNodeHandlerServiceClient) (Consumer, error) {
|
||||
return c, nil
|
||||
},
|
||||
}
|
||||
ctx := context.Background()
|
||||
|
||||
k := 0
|
||||
w.EXPECT().Get(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, s string) *types.PChannelInfoAssigned {
|
||||
if k == 0 {
|
||||
k++
|
||||
return nil
|
||||
}
|
||||
return assignment
|
||||
})
|
||||
w.EXPECT().Watch(mock.Anything, mock.Anything, mock.Anything).Return(nil)
|
||||
|
||||
producer, err := handler.CreateProducer(ctx, &ProducerOptions{PChannel: "pchannel"})
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, producer)
|
||||
producer2, err := handler.CreateProducer(ctx, &ProducerOptions{PChannel: "pchannel"})
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, producer)
|
||||
p.EXPECT().IsAvailable().Unset()
|
||||
p.EXPECT().IsAvailable().Return(false)
|
||||
producer3, err := handler.CreateProducer(ctx, &ProducerOptions{PChannel: "pchannel"})
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, producer3)
|
||||
producer.Close()
|
||||
producer2.Close()
|
||||
producer3.Close()
|
||||
|
||||
producer4, err := handler.CreateProducer(ctx, &ProducerOptions{PChannel: "pchannel"})
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, producer4)
|
||||
producer4.Close()
|
||||
|
||||
consumer, err := handler.CreateConsumer(ctx, &ConsumerOptions{
|
||||
PChannel: "pchannel",
|
||||
DeliverPolicy: options.DeliverPolicyAll(),
|
||||
DeliverFilters: []options.DeliverFilter{
|
||||
options.DeliverFilterTimeTickGT(10),
|
||||
options.DeliverFilterTimeTickGTE(10),
|
||||
options.DeliverFilterVChannel("vchannel"),
|
||||
},
|
||||
MessageHandler: make(message.ChanMessageHandler),
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, consumer)
|
||||
consumer.Close()
|
||||
|
||||
service.EXPECT().Close().Return()
|
||||
handler.Close()
|
||||
producer, err = handler.CreateProducer(ctx, nil)
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, producer)
|
||||
|
||||
consumer, err = handler.CreateConsumer(ctx, nil)
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, consumer)
|
||||
}
|
||||
|
||||
func TestDial(t *testing.T) {
|
||||
paramtable.Init()
|
||||
|
||||
w := mock_types.NewMockAssignmentDiscoverWatcher(t)
|
||||
w.EXPECT().AssignmentDiscover(mock.Anything, mock.Anything).RunAndReturn(
|
||||
func(ctx context.Context, f func(*types.VersionedStreamingNodeAssignments) error) error {
|
||||
return context.Canceled
|
||||
},
|
||||
)
|
||||
handler := NewHandlerClient(w)
|
||||
assert.NotNil(t, handler)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
handler.Close()
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package producer
|
||||
|
||||
import (
|
||||
"github.com/milvus-io/milvus/internal/proto/streamingpb"
|
||||
"github.com/milvus-io/milvus/pkg/streaming/util/message"
|
||||
)
|
||||
|
||||
// produceGrpcClient is a wrapped producer server of log messages.
|
||||
type produceGrpcClient struct {
|
||||
streamingpb.StreamingNodeHandlerService_ProduceClient
|
||||
}
|
||||
|
||||
// SendProduceMessage sends the produce message to server.
|
||||
func (p *produceGrpcClient) SendProduceMessage(requestID int64, msg message.MutableMessage) error {
|
||||
return p.Send(&streamingpb.ProduceRequest{
|
||||
Request: &streamingpb.ProduceRequest_Produce{
|
||||
Produce: &streamingpb.ProduceMessageRequest{
|
||||
RequestId: requestID,
|
||||
Message: &streamingpb.Message{
|
||||
Payload: msg.Payload(),
|
||||
Properties: msg.Properties().ToRawMap(),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// SendClose sends the close request to server.
|
||||
func (p *produceGrpcClient) SendClose() error {
|
||||
return p.Send(&streamingpb.ProduceRequest{
|
||||
Request: &streamingpb.ProduceRequest_Close{
|
||||
Close: &streamingpb.CloseProducerRequest{},
|
||||
},
|
||||
})
|
||||
}
|
||||
30
internal/streamingnode/client/handler/producer/producer.go
Normal file
30
internal/streamingnode/client/handler/producer/producer.go
Normal file
@ -0,0 +1,30 @@
|
||||
package producer
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/milvus-io/milvus/pkg/streaming/util/message"
|
||||
"github.com/milvus-io/milvus/pkg/streaming/util/types"
|
||||
)
|
||||
|
||||
var _ Producer = (*producerImpl)(nil)
|
||||
|
||||
// Producer is the interface that wraps the basic produce method on grpc stream.
|
||||
// Producer is work on a single stream on grpc,
|
||||
// so Producer cannot recover from failure because of the stream is broken.
|
||||
type Producer interface {
|
||||
// Assignment returns the assignment of the producer.
|
||||
Assignment() types.PChannelInfoAssigned
|
||||
|
||||
// Produce sends the produce message to server.
|
||||
Produce(ctx context.Context, msg message.MutableMessage) (message.MessageID, error)
|
||||
|
||||
// Check if a producer is available.
|
||||
IsAvailable() bool
|
||||
|
||||
// Available returns a channel that will be closed when the producer is unavailable.
|
||||
Available() <-chan struct{}
|
||||
|
||||
// Close close the producer client.
|
||||
Close()
|
||||
}
|
||||
312
internal/streamingnode/client/handler/producer/producer_impl.go
Normal file
312
internal/streamingnode/client/handler/producer/producer_impl.go
Normal file
@ -0,0 +1,312 @@
|
||||
package producer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/cockroachdb/errors"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/proto/streamingpb"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/service/contextutil"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/status"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/typeconverter"
|
||||
"github.com/milvus-io/milvus/pkg/log"
|
||||
"github.com/milvus-io/milvus/pkg/streaming/util/message"
|
||||
"github.com/milvus-io/milvus/pkg/streaming/util/types"
|
||||
"github.com/milvus-io/milvus/pkg/util/lifetime"
|
||||
"github.com/milvus-io/milvus/pkg/util/typeutil"
|
||||
)
|
||||
|
||||
// ProducerOptions is the options for creating a producer.
|
||||
type ProducerOptions struct {
|
||||
// The produce target
|
||||
Assignment *types.PChannelInfoAssigned
|
||||
}
|
||||
|
||||
// CreateProducer create a new producer client.
|
||||
func CreateProducer(
|
||||
ctx context.Context,
|
||||
opts *ProducerOptions,
|
||||
handler streamingpb.StreamingNodeHandlerServiceClient,
|
||||
) (Producer, error) {
|
||||
ctx = createProduceRequest(ctx, opts)
|
||||
streamClient, err := handler.Produce(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Initialize the producer client.
|
||||
produceClient := &produceGrpcClient{
|
||||
streamClient,
|
||||
}
|
||||
|
||||
// Recv the first response from server.
|
||||
// It must be a create response.
|
||||
resp, err := produceClient.Recv()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
createResp := resp.GetCreate()
|
||||
if createResp == nil {
|
||||
return nil, status.NewInvalidRequestSeq("first message arrive must be create response")
|
||||
}
|
||||
|
||||
// Initialize the producer client finished.
|
||||
cli := &producerImpl{
|
||||
assignment: *opts.Assignment,
|
||||
walName: createResp.GetWalName(),
|
||||
logger: log.With(
|
||||
zap.String("walName", createResp.GetWalName()),
|
||||
zap.String("pchannel", opts.Assignment.Channel.Name),
|
||||
zap.Int64("term", opts.Assignment.Channel.Term),
|
||||
zap.Int64("streamingNodeID", opts.Assignment.Node.ServerID)),
|
||||
lifetime: lifetime.NewLifetime[lifetime.State](lifetime.Working),
|
||||
idAllocator: typeutil.NewIDAllocator(),
|
||||
grpcStreamClient: produceClient,
|
||||
pendingRequests: sync.Map{},
|
||||
requestCh: make(chan *produceRequest),
|
||||
sendExitCh: make(chan struct{}),
|
||||
finishedCh: make(chan struct{}),
|
||||
}
|
||||
|
||||
// Start the producer client.
|
||||
go cli.execute()
|
||||
return cli, nil
|
||||
}
|
||||
|
||||
// createProduceRequest creates the produce request.
|
||||
func createProduceRequest(ctx context.Context, opts *ProducerOptions) context.Context {
|
||||
// select server to consume.
|
||||
ctx = contextutil.WithPickServerID(ctx, opts.Assignment.Node.ServerID)
|
||||
// select channel to consume.
|
||||
return contextutil.WithCreateProducer(ctx, &streamingpb.CreateProducerRequest{
|
||||
Pchannel: typeconverter.NewProtoFromPChannelInfo(opts.Assignment.Channel),
|
||||
})
|
||||
}
|
||||
|
||||
// Expected message sequence:
|
||||
// CreateProducer
|
||||
// ProduceRequest 1 -> ProduceResponse Or Error 1
|
||||
// ProduceRequest 2 -> ProduceResponse Or Error 2
|
||||
// ProduceRequest 3 -> ProduceResponse Or Error 3
|
||||
// CloseProducer
|
||||
type producerImpl struct {
|
||||
assignment types.PChannelInfoAssigned
|
||||
walName string
|
||||
logger *log.MLogger
|
||||
lifetime lifetime.Lifetime[lifetime.State]
|
||||
idAllocator *typeutil.IDAllocator
|
||||
grpcStreamClient *produceGrpcClient
|
||||
|
||||
pendingRequests sync.Map
|
||||
requestCh chan *produceRequest
|
||||
sendExitCh chan struct{}
|
||||
finishedCh chan struct{}
|
||||
}
|
||||
|
||||
type produceRequest struct {
|
||||
ctx context.Context
|
||||
msg message.MutableMessage
|
||||
respCh chan produceResponse
|
||||
}
|
||||
|
||||
type produceResponse struct {
|
||||
id message.MessageID
|
||||
err error
|
||||
}
|
||||
|
||||
// Assignment returns the assignment of the producer.
|
||||
func (p *producerImpl) Assignment() types.PChannelInfoAssigned {
|
||||
return p.assignment
|
||||
}
|
||||
|
||||
// Produce sends the produce message to server.
|
||||
func (p *producerImpl) Produce(ctx context.Context, msg message.MutableMessage) (message.MessageID, error) {
|
||||
if p.lifetime.Add(lifetime.IsWorking) != nil {
|
||||
return nil, status.NewOnShutdownError("producer client is shutting down")
|
||||
}
|
||||
defer p.lifetime.Done()
|
||||
|
||||
respCh := make(chan produceResponse, 1)
|
||||
req := &produceRequest{
|
||||
ctx: ctx,
|
||||
msg: msg,
|
||||
respCh: respCh,
|
||||
}
|
||||
|
||||
// Send the produce message to server.
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
case p.requestCh <- req:
|
||||
case <-p.sendExitCh:
|
||||
return nil, status.NewInner("producer stream client is closed")
|
||||
}
|
||||
|
||||
// Wait for the response from server or context timeout.
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
case resp := <-respCh:
|
||||
return resp.id, resp.err
|
||||
}
|
||||
}
|
||||
|
||||
// execute executes the producer client.
|
||||
func (p *producerImpl) execute() {
|
||||
defer close(p.finishedCh)
|
||||
|
||||
errSendCh := p.startSend()
|
||||
errRecvCh := p.startRecv()
|
||||
|
||||
// Wait for send and recv arm to exit.
|
||||
err := <-errRecvCh
|
||||
<-errSendCh
|
||||
|
||||
// Clear all pending request.
|
||||
p.pendingRequests.Range(func(key, value interface{}) bool {
|
||||
value.(*produceRequest).respCh <- produceResponse{
|
||||
err: status.NewUnknownError(fmt.Sprintf("request sent but no response returned, %v", err)),
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// IsAvailable returns whether the producer is available.
|
||||
func (p *producerImpl) IsAvailable() bool {
|
||||
select {
|
||||
case <-p.Available():
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Available returns a channel that will be closed when the producer is unavailable.
|
||||
func (p *producerImpl) Available() <-chan struct{} {
|
||||
return p.sendExitCh
|
||||
}
|
||||
|
||||
// Close close the producer client.
|
||||
func (p *producerImpl) Close() {
|
||||
// Wait for all message has been sent.
|
||||
p.lifetime.SetState(lifetime.Stopped)
|
||||
p.lifetime.Wait()
|
||||
close(p.requestCh)
|
||||
|
||||
// Wait for send and recv arm to exit.
|
||||
<-p.finishedCh
|
||||
}
|
||||
|
||||
// startSend starts the send loop.
|
||||
func (p *producerImpl) startSend() <-chan struct{} {
|
||||
ch := make(chan struct{})
|
||||
go func() {
|
||||
_ = p.sendLoop()
|
||||
close(ch)
|
||||
}()
|
||||
return ch
|
||||
}
|
||||
|
||||
// startRecv starts the recv loop.
|
||||
func (p *producerImpl) startRecv() <-chan error {
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
errCh <- p.recvLoop()
|
||||
}()
|
||||
return errCh
|
||||
}
|
||||
|
||||
// sendLoop sends the produce message to server.
|
||||
func (p *producerImpl) sendLoop() (err error) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
p.logger.Warn("send arm of stream closed by unexpected error", zap.Error(err))
|
||||
} else {
|
||||
p.logger.Info("send arm of stream closed")
|
||||
}
|
||||
close(p.sendExitCh)
|
||||
if err := p.grpcStreamClient.CloseSend(); err != nil {
|
||||
p.logger.Warn("failed to close send", zap.Error(err))
|
||||
}
|
||||
}()
|
||||
|
||||
for req := range p.requestCh {
|
||||
requestID := p.idAllocator.Allocate()
|
||||
// Store the request to pending request map.
|
||||
p.pendingRequests.Store(requestID, req)
|
||||
// Send the produce message to server.
|
||||
if err := p.grpcStreamClient.SendProduceMessage(requestID, req.msg); err != nil {
|
||||
// If send failed, remove the request from pending request map and return error to client.
|
||||
p.notifyRequest(requestID, produceResponse{
|
||||
err: err,
|
||||
})
|
||||
return err
|
||||
}
|
||||
}
|
||||
// all message has been sent, sent close response.
|
||||
return p.grpcStreamClient.SendClose()
|
||||
}
|
||||
|
||||
// recvLoop receives the produce response from server.
|
||||
func (p *producerImpl) recvLoop() (err error) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
p.logger.Warn("recv arm of stream closed by unexpected error", zap.Error(err))
|
||||
return
|
||||
}
|
||||
p.logger.Info("recv arm of stream closed")
|
||||
}()
|
||||
|
||||
for {
|
||||
resp, err := p.grpcStreamClient.Recv()
|
||||
if errors.Is(err, io.EOF) {
|
||||
p.logger.Debug("stream closed successful")
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch resp := resp.Response.(type) {
|
||||
case *streamingpb.ProduceResponse_Produce:
|
||||
var result produceResponse
|
||||
switch produceResp := resp.Produce.Response.(type) {
|
||||
case *streamingpb.ProduceMessageResponse_Result:
|
||||
msgID, err := message.UnmarshalMessageID(
|
||||
p.walName,
|
||||
produceResp.Result.GetId().GetId(),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result = produceResponse{
|
||||
id: msgID,
|
||||
}
|
||||
case *streamingpb.ProduceMessageResponse_Error:
|
||||
result = produceResponse{
|
||||
err: status.New(produceResp.Error.Code, produceResp.Error.Cause),
|
||||
}
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
p.notifyRequest(resp.Produce.RequestId, result)
|
||||
case *streamingpb.ProduceResponse_Close:
|
||||
// recv io.EOF after this message.
|
||||
default:
|
||||
// skip message here.
|
||||
p.logger.Error("unknown response type", zap.Any("response", resp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// notifyRequest notify the request has been returned from server.
|
||||
func (p *producerImpl) notifyRequest(requestID int64, resp produceResponse) {
|
||||
pendingRequest, loaded := p.pendingRequests.LoadAndDelete(requestID)
|
||||
if loaded {
|
||||
p.logger.Debug("recv send produce message from server", zap.Int64("requestID", requestID))
|
||||
pendingRequest.(*produceRequest).respCh <- resp
|
||||
}
|
||||
}
|
||||
112
internal/streamingnode/client/handler/producer/producer_test.go
Normal file
112
internal/streamingnode/client/handler/producer/producer_test.go
Normal file
@ -0,0 +1,112 @@
|
||||
package producer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/mocks/proto/mock_streamingpb"
|
||||
"github.com/milvus-io/milvus/internal/proto/streamingpb"
|
||||
"github.com/milvus-io/milvus/pkg/streaming/util/message"
|
||||
"github.com/milvus-io/milvus/pkg/streaming/util/types"
|
||||
"github.com/milvus-io/milvus/pkg/streaming/walimpls/impls/walimplstest"
|
||||
)
|
||||
|
||||
func TestProducer(t *testing.T) {
|
||||
c := mock_streamingpb.NewMockStreamingNodeHandlerServiceClient(t)
|
||||
cc := mock_streamingpb.NewMockStreamingNodeHandlerService_ProduceClient(t)
|
||||
recvCh := make(chan *streamingpb.ProduceResponse, 10)
|
||||
cc.EXPECT().Recv().RunAndReturn(func() (*streamingpb.ProduceResponse, error) {
|
||||
msg, ok := <-recvCh
|
||||
if !ok {
|
||||
return nil, io.EOF
|
||||
}
|
||||
return msg, nil
|
||||
})
|
||||
sendCh := make(chan struct{}, 5)
|
||||
cc.EXPECT().Send(mock.Anything).RunAndReturn(func(pr *streamingpb.ProduceRequest) error {
|
||||
sendCh <- struct{}{}
|
||||
return nil
|
||||
})
|
||||
c.EXPECT().Produce(mock.Anything, mock.Anything).Return(cc, nil)
|
||||
cc.EXPECT().CloseSend().RunAndReturn(func() error {
|
||||
recvCh <- &streamingpb.ProduceResponse{Response: &streamingpb.ProduceResponse_Close{}}
|
||||
close(recvCh)
|
||||
return nil
|
||||
})
|
||||
|
||||
ctx := context.Background()
|
||||
opts := &ProducerOptions{
|
||||
Assignment: &types.PChannelInfoAssigned{
|
||||
Channel: types.PChannelInfo{Name: "test", Term: 1},
|
||||
Node: types.StreamingNodeInfo{ServerID: 1, Address: "localhost"},
|
||||
},
|
||||
}
|
||||
|
||||
recvCh <- &streamingpb.ProduceResponse{
|
||||
Response: &streamingpb.ProduceResponse_Create{
|
||||
Create: &streamingpb.CreateProducerResponse{
|
||||
WalName: "test",
|
||||
},
|
||||
},
|
||||
}
|
||||
producer, err := CreateProducer(ctx, opts, c)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, producer)
|
||||
ch := make(chan struct{})
|
||||
go func() {
|
||||
msgID, err := producer.Produce(ctx, message.NewMutableMessageBuilder().
|
||||
WithMessageType(message.MessageTypeUnknown).
|
||||
WithPayload([]byte{}).
|
||||
BuildMutable())
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, msgID)
|
||||
msgID, err = producer.Produce(ctx, message.NewMutableMessageBuilder().
|
||||
WithMessageType(message.MessageTypeUnknown).
|
||||
WithPayload([]byte{}).
|
||||
BuildMutable())
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, msgID)
|
||||
close(ch)
|
||||
}()
|
||||
<-sendCh
|
||||
recvCh <- &streamingpb.ProduceResponse{
|
||||
Response: &streamingpb.ProduceResponse_Produce{
|
||||
Produce: &streamingpb.ProduceMessageResponse{
|
||||
RequestId: 1,
|
||||
Response: &streamingpb.ProduceMessageResponse_Error{
|
||||
Error: &streamingpb.StreamingError{Code: 1},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
<-sendCh
|
||||
recvCh <- &streamingpb.ProduceResponse{
|
||||
Response: &streamingpb.ProduceResponse_Produce{
|
||||
Produce: &streamingpb.ProduceMessageResponse{
|
||||
RequestId: 2,
|
||||
Response: &streamingpb.ProduceMessageResponse_Result{
|
||||
Result: &streamingpb.ProduceMessageResponseResult{
|
||||
Id: &streamingpb.MessageID{Id: walimplstest.NewTestMessageID(1).Marshal()},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
<-ch
|
||||
|
||||
ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
|
||||
defer cancel()
|
||||
_, err = producer.Produce(ctx, message.NewMutableMessageBuilder().
|
||||
WithMessageType(message.MessageTypeUnknown).
|
||||
WithPayload([]byte{}).
|
||||
BuildMutable())
|
||||
assert.ErrorIs(t, err, context.DeadlineExceeded)
|
||||
assert.True(t, producer.IsAvailable())
|
||||
producer.Close()
|
||||
assert.False(t, producer.IsAvailable())
|
||||
}
|
||||
51
internal/streamingnode/client/handler/shared_producer.go
Normal file
51
internal/streamingnode/client/handler/shared_producer.go
Normal file
@ -0,0 +1,51 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/streamingnode/client/handler/producer"
|
||||
"github.com/milvus-io/milvus/pkg/streaming/util/message"
|
||||
"github.com/milvus-io/milvus/pkg/streaming/util/types"
|
||||
"github.com/milvus-io/milvus/pkg/util/typeutil"
|
||||
)
|
||||
|
||||
var _ producer.Producer = (*sharedProducer)(nil)
|
||||
|
||||
// newSharedProducer creates a shared producer.
|
||||
func newSharedProducer(ref *typeutil.SharedReference[Producer]) sharedProducer {
|
||||
return sharedProducer{
|
||||
SharedReference: ref,
|
||||
}
|
||||
}
|
||||
|
||||
// sharedProducer is a shared producer.
|
||||
type sharedProducer struct {
|
||||
*typeutil.SharedReference[Producer]
|
||||
}
|
||||
|
||||
// Clone clones the shared producer.
|
||||
func (sp sharedProducer) Clone() *sharedProducer {
|
||||
return &sharedProducer{
|
||||
SharedReference: sp.SharedReference.Clone(),
|
||||
}
|
||||
}
|
||||
|
||||
// Assignment returns the assignment of the producer.
|
||||
func (sp sharedProducer) Assignment() types.PChannelInfoAssigned {
|
||||
return sp.Deref().Assignment()
|
||||
}
|
||||
|
||||
// Produce sends the produce message to server.
|
||||
func (sp sharedProducer) Produce(ctx context.Context, msg message.MutableMessage) (message.MessageID, error) {
|
||||
return sp.Deref().Produce(ctx, msg)
|
||||
}
|
||||
|
||||
// Check if a producer is available.
|
||||
func (sp sharedProducer) IsAvailable() bool {
|
||||
return sp.Deref().IsAvailable()
|
||||
}
|
||||
|
||||
// Available returns a channel that will be closed when the producer is unavailable.
|
||||
func (sp sharedProducer) Available() <-chan struct{} {
|
||||
return sp.Deref().Available()
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
package manager
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/milvus-io/milvus/pkg/streaming/util/types"
|
||||
)
|
||||
|
||||
type ManagerClient interface {
|
||||
// WatchNodeChanged returns a channel that receive a node change.
|
||||
WatchNodeChanged(ctx context.Context) (<-chan struct{}, error)
|
||||
|
||||
// CollectStatus collects status of all wal instances in all streamingnode.
|
||||
CollectAllStatus(ctx context.Context) (map[int64]*types.StreamingNodeStatus, error)
|
||||
|
||||
// Assign a wal instance for the channel on log node of given server id.
|
||||
Assign(ctx context.Context, pchannel types.PChannelInfoAssigned) error
|
||||
|
||||
// Remove the wal instance for the channel on log node of given server id.
|
||||
Remove(ctx context.Context, pchannel types.PChannelInfoAssigned) error
|
||||
|
||||
// Close closes the manager client.
|
||||
Close()
|
||||
}
|
||||
112
internal/streamingnode/client/manager/manager_client.go
Normal file
112
internal/streamingnode/client/manager/manager_client.go
Normal file
@ -0,0 +1,112 @@
|
||||
package manager
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
clientv3 "go.etcd.io/etcd/client/v3"
|
||||
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/proto/streamingpb"
|
||||
"github.com/milvus-io/milvus/internal/util/sessionutil"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/service/balancer/picker"
|
||||
streamingserviceinterceptor "github.com/milvus-io/milvus/internal/util/streamingutil/service/interceptor"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/service/lazygrpc"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/service/resolver"
|
||||
"github.com/milvus-io/milvus/pkg/streaming/util/types"
|
||||
"github.com/milvus-io/milvus/pkg/tracer"
|
||||
"github.com/milvus-io/milvus/pkg/util/interceptor"
|
||||
"github.com/milvus-io/milvus/pkg/util/lifetime"
|
||||
"github.com/milvus-io/milvus/pkg/util/paramtable"
|
||||
"github.com/milvus-io/milvus/pkg/util/typeutil"
|
||||
)
|
||||
|
||||
// ManagerClient is the client to manage wal instances in all streamingnode.
|
||||
// ManagerClient wraps the Session Service Discovery.
|
||||
// Provides the ability to assign and remove wal instances for the channel on streaming node.
|
||||
type ManagerClient interface {
|
||||
// WatchNodeChanged returns a channel that receive the signal that a streaming node change.
|
||||
WatchNodeChanged(ctx context.Context) (<-chan struct{}, error)
|
||||
|
||||
// CollectAllStatus collects status of all streamingnode, such as load balance attributes.
|
||||
CollectAllStatus(ctx context.Context) (map[int64]*types.StreamingNodeStatus, error)
|
||||
|
||||
// Assign a wal instance for the channel on streaming node of given server id.
|
||||
Assign(ctx context.Context, pchannel types.PChannelInfoAssigned) error
|
||||
|
||||
// Remove the wal instance for the channel on streaming node of given server id.
|
||||
Remove(ctx context.Context, pchannel types.PChannelInfoAssigned) error
|
||||
|
||||
// Close closes the manager client.
|
||||
// It close the underlying connection, stop the node watcher and release all resources.
|
||||
Close()
|
||||
}
|
||||
|
||||
// NewManagerClient creates a new manager client.
|
||||
func NewManagerClient(etcdCli *clientv3.Client) ManagerClient {
|
||||
role := sessionutil.GetSessionPrefixByRole(typeutil.StreamingNodeRole)
|
||||
rb := resolver.NewSessionBuilder(etcdCli, role)
|
||||
dialTimeout := paramtable.Get().StreamingNodeGrpcClientCfg.DialTimeout.GetAsDuration(time.Millisecond)
|
||||
dialOptions := getDialOptions(rb)
|
||||
conn := lazygrpc.NewConn(func(ctx context.Context) (*grpc.ClientConn, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, dialTimeout)
|
||||
defer cancel()
|
||||
return grpc.DialContext(
|
||||
ctx,
|
||||
resolver.SessionResolverScheme+":///"+typeutil.StreamingNodeRole,
|
||||
dialOptions...,
|
||||
)
|
||||
})
|
||||
return &managerClientImpl{
|
||||
lifetime: lifetime.NewLifetime(lifetime.Working),
|
||||
rb: rb,
|
||||
service: lazygrpc.WithServiceCreator(conn, streamingpb.NewStreamingNodeManagerServiceClient),
|
||||
}
|
||||
}
|
||||
|
||||
// getDialOptions returns grpc dial options.
|
||||
func getDialOptions(rb resolver.Builder) []grpc.DialOption {
|
||||
cfg := ¶mtable.Get().StreamingNodeGrpcClientCfg
|
||||
retryPolicy := cfg.GetDefaultRetryPolicy()
|
||||
retryPolicy["retryableStatusCodes"] = []string{"UNAVAILABLE"}
|
||||
defaultServiceConfig := map[string]interface{}{
|
||||
"loadBalancingConfig": []map[string]interface{}{
|
||||
{picker.ServerIDPickerBalancerName: map[string]interface{}{}},
|
||||
},
|
||||
"methodConfig": []map[string]interface{}{
|
||||
{
|
||||
"name": []map[string]string{
|
||||
{"service": "milvus.proto.streaming.StreamingNodeManagerService"},
|
||||
},
|
||||
"waitForReady": true,
|
||||
"retryPolicy": retryPolicy,
|
||||
},
|
||||
},
|
||||
}
|
||||
defaultServiceConfigJSON, err := json.Marshal(defaultServiceConfig)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
dialOptions := cfg.GetDialOptionsFromConfig()
|
||||
dialOptions = append(dialOptions,
|
||||
grpc.WithBlock(),
|
||||
grpc.WithResolvers(rb),
|
||||
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||
grpc.WithChainUnaryInterceptor(
|
||||
otelgrpc.UnaryClientInterceptor(tracer.GetInterceptorOpts()...),
|
||||
interceptor.ClusterInjectionUnaryClientInterceptor(),
|
||||
streamingserviceinterceptor.NewStreamingServiceUnaryClientInterceptor(),
|
||||
),
|
||||
grpc.WithChainStreamInterceptor(
|
||||
otelgrpc.StreamClientInterceptor(tracer.GetInterceptorOpts()...),
|
||||
interceptor.ClusterInjectionStreamClientInterceptor(),
|
||||
streamingserviceinterceptor.NewStreamingServiceStreamClientInterceptor(),
|
||||
),
|
||||
grpc.WithReturnConnectionError(),
|
||||
grpc.WithDefaultServiceConfig(string(defaultServiceConfigJSON)),
|
||||
)
|
||||
return dialOptions
|
||||
}
|
||||
191
internal/streamingnode/client/manager/manager_client_impl.go
Normal file
191
internal/streamingnode/client/manager/manager_client_impl.go
Normal file
@ -0,0 +1,191 @@
|
||||
package manager
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/proto/streamingpb"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/service/balancer/picker"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/service/contextutil"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/service/discoverer"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/service/lazygrpc"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/service/resolver"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/status"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/typeconverter"
|
||||
"github.com/milvus-io/milvus/pkg/log"
|
||||
"github.com/milvus-io/milvus/pkg/streaming/util/types"
|
||||
"github.com/milvus-io/milvus/pkg/util/lifetime"
|
||||
)
|
||||
|
||||
var _ ManagerClient = (*managerClientImpl)(nil)
|
||||
|
||||
// managerClientImpl implements ManagerClient.
|
||||
type managerClientImpl struct {
|
||||
lifetime lifetime.Lifetime[lifetime.State]
|
||||
|
||||
rb resolver.Builder
|
||||
service lazygrpc.Service[streamingpb.StreamingNodeManagerServiceClient]
|
||||
}
|
||||
|
||||
func (c *managerClientImpl) WatchNodeChanged(ctx context.Context) (<-chan struct{}, error) {
|
||||
if c.lifetime.Add(lifetime.IsWorking) != nil {
|
||||
return nil, status.NewOnShutdownError("manager client is closing")
|
||||
}
|
||||
defer c.lifetime.Done()
|
||||
|
||||
resultCh := make(chan struct{}, 1)
|
||||
go func() {
|
||||
defer close(resultCh)
|
||||
c.rb.Resolver().Watch(ctx, func(state resolver.VersionedState) error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-c.lifetime.CloseCh():
|
||||
return status.NewOnShutdownError("manager client is closing")
|
||||
case resultCh <- struct{}{}:
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}()
|
||||
return resultCh, nil
|
||||
}
|
||||
|
||||
// CollectAllStatus collects status in all underlying streamingnode.
|
||||
func (c *managerClientImpl) CollectAllStatus(ctx context.Context) (map[int64]*types.StreamingNodeStatus, error) {
|
||||
if c.lifetime.Add(lifetime.IsWorking) != nil {
|
||||
return nil, status.NewOnShutdownError("manager client is closing")
|
||||
}
|
||||
defer c.lifetime.Done()
|
||||
|
||||
// Get all discovered streamingnode.
|
||||
state := c.rb.Resolver().GetLatestState()
|
||||
if len(state.State.Addresses) == 0 {
|
||||
return make(map[int64]*types.StreamingNodeStatus), nil
|
||||
}
|
||||
|
||||
// Collect status of all streamingnode.
|
||||
result, err := c.getAllStreamingNodeStatus(ctx, state)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Collect status may cost some time, so we need to check the lifetime again.
|
||||
newState := c.rb.Resolver().GetLatestState()
|
||||
if newState.Version.GT(state.Version) {
|
||||
newSession := newState.Sessions()
|
||||
for serverID := range result {
|
||||
if session, ok := newSession[serverID]; !ok {
|
||||
result[serverID].Err = types.ErrNotAlive
|
||||
} else if session.Stopping {
|
||||
result[serverID].Err = types.ErrStopping
|
||||
}
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (c *managerClientImpl) getAllStreamingNodeStatus(ctx context.Context, state discoverer.VersionedState) (map[int64]*types.StreamingNodeStatus, error) {
|
||||
// wait for manager service ready.
|
||||
manager, err := c.service.GetService(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
g, _ := errgroup.WithContext(ctx)
|
||||
g.SetLimit(10)
|
||||
var mu sync.Mutex
|
||||
result := make(map[int64]*types.StreamingNodeStatus, len(state.State.Addresses))
|
||||
for serverID, session := range state.Sessions() {
|
||||
serverID := serverID
|
||||
address := session.Address
|
||||
g.Go(func() error {
|
||||
ctx := contextutil.WithPickServerID(ctx, serverID)
|
||||
resp, err := manager.CollectStatus(ctx, &streamingpb.StreamingNodeManagerCollectStatusRequest{})
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
result[serverID] = &types.StreamingNodeStatus{
|
||||
StreamingNodeInfo: types.StreamingNodeInfo{
|
||||
ServerID: serverID,
|
||||
Address: address,
|
||||
},
|
||||
Err: err,
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Warn("collect status failed, skip", zap.Int64("serverID", serverID), zap.Error(err))
|
||||
return err
|
||||
}
|
||||
log.Debug("collect status success", zap.Int64("serverID", serverID), zap.Any("status", resp))
|
||||
return nil
|
||||
})
|
||||
}
|
||||
g.Wait()
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Assign a wal instance for the channel on log node of given server id.
|
||||
func (c *managerClientImpl) Assign(ctx context.Context, pchannel types.PChannelInfoAssigned) error {
|
||||
if c.lifetime.Add(lifetime.IsWorking) != nil {
|
||||
return status.NewOnShutdownError("manager client is closing")
|
||||
}
|
||||
defer c.lifetime.Done()
|
||||
|
||||
// wait for manager service ready.
|
||||
manager, err := c.service.GetService(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Select a log node to assign the wal instance.
|
||||
ctx = contextutil.WithPickServerID(ctx, pchannel.Node.ServerID)
|
||||
_, err = manager.Assign(ctx, &streamingpb.StreamingNodeManagerAssignRequest{
|
||||
Pchannel: typeconverter.NewProtoFromPChannelInfo(pchannel.Channel),
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// Remove the wal instance for the channel on log node of given server id.
|
||||
func (c *managerClientImpl) Remove(ctx context.Context, pchannel types.PChannelInfoAssigned) error {
|
||||
if c.lifetime.Add(lifetime.IsWorking) != nil {
|
||||
return status.NewOnShutdownError("manager client is closing")
|
||||
}
|
||||
defer c.lifetime.Done()
|
||||
|
||||
// wait for manager service ready.
|
||||
manager, err := c.service.GetService(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Select a streaming node to remove the wal instance.
|
||||
ctx = contextutil.WithPickServerID(ctx, pchannel.Node.ServerID)
|
||||
_, err = manager.Remove(ctx, &streamingpb.StreamingNodeManagerRemoveRequest{
|
||||
Pchannel: typeconverter.NewProtoFromPChannelInfo(pchannel.Channel),
|
||||
})
|
||||
// The following error can be treated as success.
|
||||
// 1. err is nil, a real remove operation at streaming node has been happened.
|
||||
// 2. err is ErrSubConnNoExist, the streaming node is not alive at view of session, so the wal on it is already removed.
|
||||
// 3. err is SkippedOperation, the streaming node is not the owner of the wal, so the wal on it is already removed.
|
||||
if err == nil || picker.IsErrSubConnNoExist(err) {
|
||||
return nil
|
||||
}
|
||||
statusErr := status.AsStreamingError(err)
|
||||
if statusErr == nil || statusErr.IsSkippedOperation() {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Close closes the manager client.
|
||||
func (c *managerClientImpl) Close() {
|
||||
c.lifetime.SetState(lifetime.Stopped)
|
||||
c.lifetime.Wait()
|
||||
c.lifetime.Close()
|
||||
|
||||
c.service.Close()
|
||||
c.rb.Close()
|
||||
}
|
||||
174
internal/streamingnode/client/manager/manager_test.go
Normal file
174
internal/streamingnode/client/manager/manager_test.go
Normal file
@ -0,0 +1,174 @@
|
||||
package manager
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/resolver"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/mocks/proto/mock_streamingpb"
|
||||
"github.com/milvus-io/milvus/internal/mocks/util/streamingutil/service/mock_lazygrpc"
|
||||
"github.com/milvus-io/milvus/internal/mocks/util/streamingutil/service/mock_resolver"
|
||||
"github.com/milvus-io/milvus/internal/proto/streamingpb"
|
||||
"github.com/milvus-io/milvus/internal/util/sessionutil"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/service/attributes"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/service/contextutil"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/service/discoverer"
|
||||
"github.com/milvus-io/milvus/pkg/streaming/util/types"
|
||||
"github.com/milvus-io/milvus/pkg/util/etcd"
|
||||
"github.com/milvus-io/milvus/pkg/util/lifetime"
|
||||
"github.com/milvus-io/milvus/pkg/util/paramtable"
|
||||
"github.com/milvus-io/milvus/pkg/util/typeutil"
|
||||
)
|
||||
|
||||
func TestManager(t *testing.T) {
|
||||
rb := mock_resolver.NewMockBuilder(t)
|
||||
managerService := mock_lazygrpc.NewMockService[streamingpb.StreamingNodeManagerServiceClient](t)
|
||||
m := &managerClientImpl{
|
||||
lifetime: lifetime.NewLifetime(lifetime.Working),
|
||||
rb: rb,
|
||||
service: managerService,
|
||||
}
|
||||
r := mock_resolver.NewMockResolver(t)
|
||||
rb.EXPECT().Resolver().Return(r)
|
||||
r.EXPECT().Watch(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, f func(discoverer.VersionedState) error) error {
|
||||
f(discoverer.VersionedState{})
|
||||
return context.Canceled
|
||||
})
|
||||
|
||||
// Test WatchNodeChanged.
|
||||
resultCh, err := m.WatchNodeChanged(context.Background())
|
||||
assert.NoError(t, err)
|
||||
_, ok := <-resultCh
|
||||
assert.True(t, ok)
|
||||
_, ok = <-resultCh
|
||||
assert.False(t, ok)
|
||||
|
||||
// Test CollectAllStatus
|
||||
r.EXPECT().GetLatestState().RunAndReturn(func() discoverer.VersionedState {
|
||||
return discoverer.VersionedState{
|
||||
Version: typeutil.VersionInt64(1),
|
||||
State: resolver.State{},
|
||||
}
|
||||
})
|
||||
// Not address here.
|
||||
nodes, err := m.CollectAllStatus(context.Background())
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, nodes, 0)
|
||||
|
||||
// Has address.
|
||||
managerServiceClient := mock_streamingpb.NewMockStreamingNodeManagerServiceClient(t)
|
||||
managerService.EXPECT().GetService(mock.Anything).RunAndReturn(func(ctx context.Context) (streamingpb.StreamingNodeManagerServiceClient, error) {
|
||||
return managerServiceClient, nil
|
||||
})
|
||||
managerServiceClient.EXPECT().CollectStatus(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, snmcsr *streamingpb.StreamingNodeManagerCollectStatusRequest, co ...grpc.CallOption) (*streamingpb.StreamingNodeManagerCollectStatusResponse, error) {
|
||||
return &streamingpb.StreamingNodeManagerCollectStatusResponse{}, nil
|
||||
})
|
||||
|
||||
i := 0
|
||||
states := []map[uint64]bool{
|
||||
{1: false, 2: false, 3: true},
|
||||
{1: true, 2: false},
|
||||
}
|
||||
r.EXPECT().GetLatestState().Unset()
|
||||
r.EXPECT().GetLatestState().RunAndReturn(func() discoverer.VersionedState {
|
||||
s := newVersionedState(int64(i), states[i])
|
||||
i++
|
||||
return s
|
||||
})
|
||||
|
||||
nodes, err = m.CollectAllStatus(context.Background())
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, nodes, 3)
|
||||
assert.ErrorIs(t, nodes[3].Err, types.ErrNotAlive)
|
||||
assert.ErrorIs(t, nodes[1].Err, types.ErrStopping)
|
||||
|
||||
// Test Assign
|
||||
serverID := int64(2)
|
||||
managerServiceClient.EXPECT().Assign(mock.Anything, mock.Anything).RunAndReturn(
|
||||
func(ctx context.Context, snmcsr *streamingpb.StreamingNodeManagerAssignRequest, co ...grpc.CallOption) (*streamingpb.StreamingNodeManagerAssignResponse, error) {
|
||||
pickedServerID, ok := contextutil.GetPickServerID(ctx)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, serverID, pickedServerID)
|
||||
return nil, nil
|
||||
})
|
||||
err = m.Assign(context.Background(), types.PChannelInfoAssigned{
|
||||
Channel: types.PChannelInfo{Name: "p", Term: 1},
|
||||
Node: types.StreamingNodeInfo{ServerID: serverID},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Test Remove
|
||||
serverID = int64(2)
|
||||
managerServiceClient.EXPECT().Remove(mock.Anything, mock.Anything).RunAndReturn(
|
||||
func(ctx context.Context, snmrr *streamingpb.StreamingNodeManagerRemoveRequest, co ...grpc.CallOption) (*streamingpb.StreamingNodeManagerRemoveResponse, error) {
|
||||
pickedServerID, ok := contextutil.GetPickServerID(ctx)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, serverID, pickedServerID)
|
||||
return nil, nil
|
||||
})
|
||||
err = m.Remove(context.Background(), types.PChannelInfoAssigned{
|
||||
Channel: types.PChannelInfo{Name: "p", Term: 1},
|
||||
Node: types.StreamingNodeInfo{ServerID: serverID},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Test Close
|
||||
managerService.EXPECT().Close().Return()
|
||||
rb.EXPECT().Close().Return()
|
||||
m.Close()
|
||||
|
||||
nodes, err = m.CollectAllStatus(context.Background())
|
||||
assert.Nil(t, nodes)
|
||||
assert.Error(t, err)
|
||||
err = m.Assign(context.Background(), types.PChannelInfoAssigned{})
|
||||
assert.Error(t, err)
|
||||
err = m.Remove(context.Background(), types.PChannelInfoAssigned{})
|
||||
assert.Error(t, err)
|
||||
resultCh, err = m.WatchNodeChanged(context.Background())
|
||||
assert.Nil(t, resultCh)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func newVersionedState(version int64, serverIDs map[uint64]bool) discoverer.VersionedState {
|
||||
state := discoverer.VersionedState{
|
||||
Version: typeutil.VersionInt64(version),
|
||||
State: resolver.State{
|
||||
Addresses: make([]resolver.Address, 0, len(serverIDs)),
|
||||
},
|
||||
}
|
||||
|
||||
for serverID, stopping := range serverIDs {
|
||||
state.State.Addresses = append(state.State.Addresses, resolver.Address{
|
||||
Addr: fmt.Sprintf("localhost:%d", serverID),
|
||||
BalancerAttributes: attributes.WithSession(
|
||||
new(attributes.Attributes), &sessionutil.SessionRaw{
|
||||
ServerID: int64(serverID),
|
||||
Stopping: stopping,
|
||||
},
|
||||
),
|
||||
})
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
func TestDial(t *testing.T) {
|
||||
paramtable.Init()
|
||||
|
||||
err := etcd.InitEtcdServer(true, "", t.TempDir(), "stdout", "info")
|
||||
assert.NoError(t, err)
|
||||
defer etcd.StopEtcdServer()
|
||||
c, err := etcd.GetEmbedEtcdClient()
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, c)
|
||||
|
||||
client := NewManagerClient(c)
|
||||
assert.NotNil(t, client)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
client.Close()
|
||||
}
|
||||
@ -12,9 +12,9 @@ import (
|
||||
"go.uber.org/atomic"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/milvus-io/milvus-proto/go-api/v2/commonpb"
|
||||
"github.com/milvus-io/milvus/internal/mocks"
|
||||
"github.com/milvus-io/milvus/internal/proto/rootcoordpb"
|
||||
"github.com/milvus-io/milvus/pkg/util/merr"
|
||||
)
|
||||
|
||||
func NewMockRootCoordClient(t *testing.T) *mocks.MockRootCoordClient {
|
||||
@ -27,9 +27,7 @@ func NewMockRootCoordClient(t *testing.T) *mocks.MockRootCoordClient {
|
||||
}
|
||||
c := counter.Add(uint64(atr.Count))
|
||||
return &rootcoordpb.AllocTimestampResponse{
|
||||
Status: &commonpb.Status{
|
||||
ErrorCode: commonpb.ErrorCode_Success,
|
||||
},
|
||||
Status: merr.Success(),
|
||||
Timestamp: c - uint64(atr.Count),
|
||||
Count: atr.Count,
|
||||
}, nil
|
||||
@ -42,11 +40,9 @@ func NewMockRootCoordClient(t *testing.T) *mocks.MockRootCoordClient {
|
||||
}
|
||||
c := counter.Add(uint64(atr.Count))
|
||||
return &rootcoordpb.AllocIDResponse{
|
||||
Status: &commonpb.Status{
|
||||
ErrorCode: commonpb.ErrorCode_Success,
|
||||
},
|
||||
ID: int64(c - uint64(atr.Count)),
|
||||
Count: atr.Count,
|
||||
Status: merr.Success(),
|
||||
ID: int64(c - uint64(atr.Count)),
|
||||
Count: atr.Count,
|
||||
}, nil
|
||||
},
|
||||
).Maybe()
|
||||
|
||||
@ -3,9 +3,10 @@ package attributes
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/util/sessionutil"
|
||||
"github.com/milvus-io/milvus/pkg/streaming/util/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAttributes(t *testing.T) {
|
||||
@ -38,6 +39,5 @@ func TestAttributes(t *testing.T) {
|
||||
|
||||
attr = new(Attributes)
|
||||
attr = WithServerID(attr, 1)
|
||||
serverID = GetServerID(attr)
|
||||
assert.Equal(t, int64(1), *GetServerID(attr))
|
||||
}
|
||||
|
||||
@ -23,9 +23,9 @@
|
||||
package balancer
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/cockroachdb/errors"
|
||||
"google.golang.org/grpc/balancer"
|
||||
"google.golang.org/grpc/balancer/base"
|
||||
"google.golang.org/grpc/connectivity"
|
||||
|
||||
@ -15,7 +15,7 @@ func NewStreamingServiceUnaryServerInterceptor() grpc.UnaryServerInterceptor {
|
||||
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
|
||||
resp, err := handler(ctx, req)
|
||||
if err == nil {
|
||||
return resp, err
|
||||
return resp, nil
|
||||
}
|
||||
// Streaming Service Method should be overwrite the response error code.
|
||||
if strings.HasPrefix(info.FullMethod, streamingpb.ServiceMethodPrefix) {
|
||||
@ -35,7 +35,7 @@ func NewStreamingServiceStreamServerInterceptor() grpc.StreamServerInterceptor {
|
||||
return func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
|
||||
err := handler(srv, ss)
|
||||
if err == nil {
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
|
||||
// Streaming Service Method should be overwrite the response error code.
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
package resolver
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/cockroachdb/errors"
|
||||
clientv3 "go.etcd.io/etcd/client/v3"
|
||||
"go.uber.org/zap"
|
||||
"google.golang.org/grpc/resolver"
|
||||
|
||||
@ -4,13 +4,14 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"google.golang.org/grpc/resolver"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/mocks/google.golang.org/grpc/mock_resolver"
|
||||
"github.com/milvus-io/milvus/internal/mocks/util/streamingutil/service/mock_discoverer"
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/service/discoverer"
|
||||
"github.com/milvus-io/milvus/pkg/util/typeutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"google.golang.org/grpc/resolver"
|
||||
)
|
||||
|
||||
func TestNewBuilder(t *testing.T) {
|
||||
|
||||
@ -2,8 +2,8 @@ package resolver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/cockroachdb/errors"
|
||||
"google.golang.org/grpc/resolver"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/util/streamingutil/service/discoverer"
|
||||
|
||||
@ -160,9 +160,11 @@ func (r *resolverWithDiscoverer) doDiscover() {
|
||||
// Update all grpc resolver.
|
||||
r.logger.Info("service discover update, update resolver", zap.Any("state", state), zap.Int("resolver_count", len(grpcResolvers)))
|
||||
for watcher := range grpcResolvers {
|
||||
// update operation do not block.
|
||||
// Update operation do not block.
|
||||
// Only return error if the resolver is closed, so just print a info log and delete the resolver.
|
||||
if err := watcher.Update(state); err != nil {
|
||||
r.logger.Info("resolver is closed, unregister the resolver", zap.Error(err))
|
||||
// updateError is always context.Canceled.
|
||||
r.logger.Info("resolver is closed, unregister the resolver", zap.NamedError("updateError", err))
|
||||
delete(grpcResolvers, watcher)
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,13 +90,15 @@ type ComponentParam struct {
|
||||
DataNodeGrpcServerCfg GrpcServerConfig
|
||||
IndexNodeGrpcServerCfg GrpcServerConfig
|
||||
|
||||
RootCoordGrpcClientCfg GrpcClientConfig
|
||||
ProxyGrpcClientCfg GrpcClientConfig
|
||||
QueryCoordGrpcClientCfg GrpcClientConfig
|
||||
QueryNodeGrpcClientCfg GrpcClientConfig
|
||||
DataCoordGrpcClientCfg GrpcClientConfig
|
||||
DataNodeGrpcClientCfg GrpcClientConfig
|
||||
IndexNodeGrpcClientCfg GrpcClientConfig
|
||||
RootCoordGrpcClientCfg GrpcClientConfig
|
||||
ProxyGrpcClientCfg GrpcClientConfig
|
||||
QueryCoordGrpcClientCfg GrpcClientConfig
|
||||
QueryNodeGrpcClientCfg GrpcClientConfig
|
||||
DataCoordGrpcClientCfg GrpcClientConfig
|
||||
DataNodeGrpcClientCfg GrpcClientConfig
|
||||
IndexNodeGrpcClientCfg GrpcClientConfig
|
||||
StreamingCoordGrpcClientCfg GrpcClientConfig
|
||||
StreamingNodeGrpcClientCfg GrpcClientConfig
|
||||
|
||||
IntegrationTestCfg integrationTestConfig
|
||||
|
||||
@ -151,6 +153,8 @@ func (p *ComponentParam) init(bt *BaseTable) {
|
||||
p.DataCoordGrpcClientCfg.Init("dataCoord", bt)
|
||||
p.DataNodeGrpcClientCfg.Init("dataNode", bt)
|
||||
p.IndexNodeGrpcClientCfg.Init("indexNode", bt)
|
||||
p.StreamingCoordGrpcClientCfg.Init("streamingCoord", bt)
|
||||
p.StreamingNodeGrpcClientCfg.Init("streamingNode", bt)
|
||||
|
||||
p.IntegrationTestCfg.init(bt)
|
||||
}
|
||||
|
||||
@ -19,8 +19,12 @@ package paramtable
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/backoff"
|
||||
"google.golang.org/grpc/keepalive"
|
||||
|
||||
"github.com/milvus-io/milvus/pkg/log"
|
||||
"github.com/milvus-io/milvus/pkg/util/funcutil"
|
||||
@ -219,6 +223,7 @@ type GrpcClientConfig struct {
|
||||
MaxAttempts ParamItem `refreshable:"false"`
|
||||
InitialBackoff ParamItem `refreshable:"false"`
|
||||
MaxBackoff ParamItem `refreshable:"false"`
|
||||
BackoffMultiplier ParamItem `refreshable:"false"`
|
||||
MinResetInterval ParamItem `refreshable:"false"`
|
||||
MaxCancelError ParamItem `refreshable:"false"`
|
||||
MinSessionCheckInterval ParamItem `refreshable:"false"`
|
||||
@ -397,6 +402,14 @@ func (p *GrpcClientConfig) Init(domain string, base *BaseTable) {
|
||||
}
|
||||
p.MaxBackoff.Init(base.mgr)
|
||||
|
||||
p.BackoffMultiplier = ParamItem{
|
||||
Key: "grpc.client.backoffMultiplier",
|
||||
Version: "2.5.0",
|
||||
DefaultValue: "2.0",
|
||||
Export: true,
|
||||
}
|
||||
p.BackoffMultiplier.Init(base.mgr)
|
||||
|
||||
compressionEnabled := fmt.Sprintf("%t", DefaultCompressionEnabled)
|
||||
p.CompressionEnabled = ParamItem{
|
||||
Key: "grpc.client.compressionEnabled",
|
||||
@ -478,3 +491,42 @@ func (p *GrpcClientConfig) Init(domain string, base *BaseTable) {
|
||||
}
|
||||
p.MaxCancelError.Init(base.mgr)
|
||||
}
|
||||
|
||||
// GetDialOptionsFromConfig returns grpc dial options from config.
|
||||
func (p *GrpcClientConfig) GetDialOptionsFromConfig() []grpc.DialOption {
|
||||
compress := ""
|
||||
if p.CompressionEnabled.GetAsBool() {
|
||||
compress = "zstd"
|
||||
}
|
||||
return []grpc.DialOption{
|
||||
grpc.WithDefaultCallOptions(
|
||||
grpc.MaxCallRecvMsgSize(p.ClientMaxRecvSize.GetAsInt()),
|
||||
grpc.MaxCallSendMsgSize(p.ClientMaxSendSize.GetAsInt()),
|
||||
grpc.UseCompressor(compress),
|
||||
),
|
||||
grpc.WithKeepaliveParams(keepalive.ClientParameters{
|
||||
Time: p.KeepAliveTime.GetAsDuration(time.Millisecond),
|
||||
Timeout: p.KeepAliveTimeout.GetAsDuration(time.Millisecond),
|
||||
PermitWithoutStream: true,
|
||||
}),
|
||||
grpc.WithConnectParams(grpc.ConnectParams{
|
||||
Backoff: backoff.Config{
|
||||
BaseDelay: 100 * time.Millisecond,
|
||||
Multiplier: 1.6,
|
||||
Jitter: 0.2,
|
||||
MaxDelay: 3 * time.Second,
|
||||
},
|
||||
MinConnectTimeout: p.DialTimeout.GetAsDuration(time.Millisecond),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
// GetDefaultRetryPolicy returns default grpc retry policy.
|
||||
func (p *GrpcClientConfig) GetDefaultRetryPolicy() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"maxAttempts": p.MaxAttempts.GetAsInt(),
|
||||
"initialBackoff": fmt.Sprintf("%fs", p.InitialBackoff.GetAsFloat()),
|
||||
"maxBackoff": fmt.Sprintf("%fs", p.MaxBackoff.GetAsFloat()),
|
||||
"backoffMultiplier": p.BackoffMultiplier.GetAsFloat(),
|
||||
}
|
||||
}
|
||||
|
||||
99
pkg/util/typeutil/shared_reference.go
Normal file
99
pkg/util/typeutil/shared_reference.go
Normal file
@ -0,0 +1,99 @@
|
||||
package typeutil
|
||||
|
||||
import (
|
||||
"go.uber.org/atomic"
|
||||
)
|
||||
|
||||
// Closable is an interface that can be closed or release the resource.
|
||||
type Closable interface {
|
||||
Close()
|
||||
}
|
||||
|
||||
// SharedReference is a reference type that can be shared with only one close operation.
|
||||
// Without supported of determined destructor, A safe SharedReference is rely on user's behavior.
|
||||
type SharedReference[T Closable] struct {
|
||||
inner T
|
||||
strongCnt *atomic.Int32
|
||||
}
|
||||
|
||||
// NewSharedReference creates a new SharedReference with the inner object.
|
||||
func NewSharedReference[T Closable](inner T) *SharedReference[T] {
|
||||
return &SharedReference[T]{
|
||||
inner: inner,
|
||||
strongCnt: atomic.NewInt32(1),
|
||||
}
|
||||
}
|
||||
|
||||
// Deref returns the inner object.
|
||||
// Deref should only be called if the reference is not closed.
|
||||
// Otherwise UB happens.
|
||||
func (sr *SharedReference[T]) Deref() T {
|
||||
return sr.inner
|
||||
}
|
||||
|
||||
// Clone returns a new SharedReference with the same inner object.
|
||||
// Clone should only be called if the reference is not closed.
|
||||
// Otherwise UB happens.
|
||||
func (sr *SharedReference[T]) Clone() *SharedReference[T] {
|
||||
n := sr.strongCnt.Load()
|
||||
|
||||
for {
|
||||
if n == 0 {
|
||||
panic("SharedReference: Clone on a closed reference")
|
||||
}
|
||||
if sr.strongCnt.CompareAndSwap(n, n+1) {
|
||||
break
|
||||
}
|
||||
n = sr.strongCnt.Load()
|
||||
}
|
||||
return sr
|
||||
}
|
||||
|
||||
// Downgrade returns a new WeakReference with the same inner object.
|
||||
// After downgrade, the SharedReference can not be used.
|
||||
func (sr *SharedReference[T]) Downgrade() *WeakReference[T] {
|
||||
w := &WeakReference[T]{
|
||||
inner: sr.inner,
|
||||
strongCnt: sr.strongCnt,
|
||||
}
|
||||
sr.Close()
|
||||
return w
|
||||
}
|
||||
|
||||
// Close closes the reference, should only be called once at a sharedReference.
|
||||
// After called this method, all other method of the SharedReference should not be called any more.
|
||||
// if the reference count is 0, the inner object will be closed.
|
||||
func (sr *SharedReference[T]) Close() {
|
||||
sr.strongCnt.Load()
|
||||
refcnt := sr.strongCnt.Dec()
|
||||
if refcnt < 0 {
|
||||
panic("SharedReference: Close on a closed reference")
|
||||
}
|
||||
if refcnt == 0 {
|
||||
sr.inner.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// WeakReference is a weak reference type that can be shared with only one close operation.
|
||||
type WeakReference[T Closable] struct {
|
||||
inner T
|
||||
strongCnt *atomic.Int32
|
||||
// TODO: add weak ref count in future.
|
||||
}
|
||||
|
||||
func (wr *WeakReference[T]) Upgrade() *SharedReference[T] {
|
||||
n := wr.strongCnt.Load()
|
||||
for {
|
||||
// There's no strong reference of dLogImpl, so it's impossible to create a DLogRef.
|
||||
if n == 0 {
|
||||
return nil
|
||||
}
|
||||
if wr.strongCnt.CompareAndSwap(n, n+1) {
|
||||
return &SharedReference[T]{
|
||||
inner: wr.inner,
|
||||
strongCnt: wr.strongCnt,
|
||||
}
|
||||
}
|
||||
n = wr.strongCnt.Load()
|
||||
}
|
||||
}
|
||||
81
pkg/util/typeutil/shared_reference_test.go
Normal file
81
pkg/util/typeutil/shared_reference_test.go
Normal file
@ -0,0 +1,81 @@
|
||||
package typeutil
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"go.uber.org/atomic"
|
||||
)
|
||||
|
||||
type closer struct {
|
||||
t *testing.T
|
||||
closed atomic.Bool
|
||||
}
|
||||
|
||||
func (c *closer) Close() {
|
||||
assert.True(c.t, c.closed.CompareAndSwap(false, true))
|
||||
}
|
||||
|
||||
func TestSharedReference(t *testing.T) {
|
||||
// test downgrade and upgrade
|
||||
closer1 := &closer{t: t}
|
||||
r := NewSharedReference(closer1)
|
||||
w := r.Downgrade()
|
||||
assert.Nil(t, w.Upgrade())
|
||||
assert.True(t, closer1.closed.Load())
|
||||
|
||||
// test concurrent
|
||||
closer1 = &closer{t: t}
|
||||
|
||||
r = NewSharedReference(closer1)
|
||||
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(4)
|
||||
r1 := r.Clone()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
defer r1.Close()
|
||||
for i := 0; i < 1000; i++ {
|
||||
r3 := r1.Clone()
|
||||
r3.Close()
|
||||
}
|
||||
}()
|
||||
r2 := r.Clone()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
defer r2.Close()
|
||||
for i := 0; i < 1000; i++ {
|
||||
r := r2.Clone()
|
||||
r.Close()
|
||||
}
|
||||
}()
|
||||
r3 := r.Clone().Downgrade()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
r := r3.Upgrade()
|
||||
r.Close()
|
||||
}()
|
||||
r4 := r.Clone().Downgrade()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
r := r4.Upgrade()
|
||||
r.Close()
|
||||
}()
|
||||
wg.Wait()
|
||||
|
||||
assert.False(t, r.Deref().closed.Load())
|
||||
r.Close()
|
||||
assert.True(t, closer1.closed.Load())
|
||||
|
||||
assert.Panics(t, func() {
|
||||
r.Clone()
|
||||
})
|
||||
|
||||
closer1 = &closer{t: t}
|
||||
r = NewSharedReference(closer1)
|
||||
r.Close()
|
||||
assert.Panics(t, func() {
|
||||
r.Close()
|
||||
})
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user