未验证 提交 5ce06de3 编写于 作者: C congqixia 提交者: GitHub

Add context usage and fix defer issue (#5796)

Signed-off-by: NCongqi Xia <congqi.xia@zilliz.com>
上级 f28403b9
...@@ -71,7 +71,6 @@ func (mr *MilvusRoles) Run(localMsg bool) { ...@@ -71,7 +71,6 @@ func (mr *MilvusRoles) Run(localMsg bool) {
} }
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
defer cancel()
if mr.EnableMaster { if mr.EnableMaster {
var ms *components.MasterService var ms *components.MasterService
...@@ -328,4 +327,7 @@ func (mr *MilvusRoles) Run(localMsg bool) { ...@@ -328,4 +327,7 @@ func (mr *MilvusRoles) Run(localMsg bool) {
syscall.SIGQUIT) syscall.SIGQUIT)
sig := <-sc sig := <-sc
fmt.Printf("Get %s signal to exit\n", sig.String()) fmt.Printf("Get %s signal to exit\n", sig.String())
// some deferred Stop has race with context cancel
cancel()
} }
...@@ -71,7 +71,7 @@ func NewIDAllocator(ctx context.Context, metaRoot string, etcdEndpoints []string ...@@ -71,7 +71,7 @@ func NewIDAllocator(ctx context.Context, metaRoot string, etcdEndpoints []string
func (ia *IDAllocator) Start() error { func (ia *IDAllocator) Start() error {
var err error var err error
ia.masterClient, err = msc.NewClient(ia.metaRoot, ia.etcdEndpoints, 3*time.Second) ia.masterClient, err = msc.NewClient(ia.Ctx, ia.metaRoot, ia.etcdEndpoints, 3*time.Second)
if err != nil { if err != nil {
panic(err) panic(err)
} }
......
...@@ -84,7 +84,7 @@ func CreateServer(ctx context.Context, factory msgstream.Factory) (*Server, erro ...@@ -84,7 +84,7 @@ func CreateServer(ctx context.Context, factory msgstream.Factory) (*Server, erro
return datanodeclient.NewClient(addr, 3*time.Second) return datanodeclient.NewClient(addr, 3*time.Second)
} }
s.masterClientCreator = func(addr string) (types.MasterService, error) { s.masterClientCreator = func(addr string) (types.MasterService, error) {
return masterclient.NewClient(Params.MetaRootPath, Params.EtcdEndpoints, masterClientTimout) return masterclient.NewClient(ctx, Params.MetaRootPath, Params.EtcdEndpoints, masterClientTimout)
} }
return s, nil return s, nil
......
...@@ -70,7 +70,7 @@ func NewServer(ctx context.Context, factory msgstream.Factory) (*Server, error) ...@@ -70,7 +70,7 @@ func NewServer(ctx context.Context, factory msgstream.Factory) (*Server, error)
msFactory: factory, msFactory: factory,
grpcErrChan: make(chan error), grpcErrChan: make(chan error),
newMasterServiceClient: func() (types.MasterService, error) { newMasterServiceClient: func() (types.MasterService, error) {
return msc.NewClient(dn.Params.MetaRootPath, dn.Params.EtcdEndpoints, 3*time.Second) return msc.NewClient(ctx1, dn.Params.MetaRootPath, dn.Params.EtcdEndpoints, 3*time.Second)
}, },
newDataServiceClient: func(etcdMetaRoot string, etcdEndpoints []string, timeout time.Duration) types.DataService { newDataServiceClient: func(etcdMetaRoot string, etcdEndpoints []string, timeout time.Duration) types.DataService {
return dsc.NewClient(etcdMetaRoot, etcdEndpoints, timeout) return dsc.NewClient(etcdMetaRoot, etcdEndpoints, timeout)
......
...@@ -13,6 +13,7 @@ package grpcmasterserviceclient ...@@ -13,6 +13,7 @@ package grpcmasterserviceclient
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"time" "time"
...@@ -61,8 +62,13 @@ func getMasterServiceAddr(sess *sessionutil.Session) (string, error) { ...@@ -61,8 +62,13 @@ func getMasterServiceAddr(sess *sessionutil.Session) (string, error) {
return ms.Address, nil return ms.Address, nil
} }
func NewClient(metaRoot string, etcdEndpoints []string, timeout time.Duration) (*GrpcClient, error) { // NewClient create master service client with specified ectd info and timeout
sess := sessionutil.NewSession(context.Background(), metaRoot, etcdEndpoints) // ctx execution control context
// metaRoot is the path in etcd for master registration
// etcdEndpoints are the address list for etcd end points
// timeout is default setting for each grpc call
func NewClient(ctx context.Context, metaRoot string, etcdEndpoints []string, timeout time.Duration) (*GrpcClient, error) {
sess := sessionutil.NewSession(ctx, metaRoot, etcdEndpoints)
if sess == nil { if sess == nil {
err := fmt.Errorf("new session error, maybe can not connect to etcd") err := fmt.Errorf("new session error, maybe can not connect to etcd")
log.Debug("MasterServiceClient NewClient failed", zap.Error(err)) log.Debug("MasterServiceClient NewClient failed", zap.Error(err))
...@@ -72,7 +78,7 @@ func NewClient(metaRoot string, etcdEndpoints []string, timeout time.Duration) ( ...@@ -72,7 +78,7 @@ func NewClient(metaRoot string, etcdEndpoints []string, timeout time.Duration) (
return &GrpcClient{ return &GrpcClient{
grpcClient: nil, grpcClient: nil,
conn: nil, conn: nil,
ctx: context.Background(), ctx: ctx,
timeout: timeout, timeout: timeout,
reconnTry: 300, reconnTry: 300,
recallTry: 3, recallTry: 3,
...@@ -84,7 +90,17 @@ func (c *GrpcClient) connect() error { ...@@ -84,7 +90,17 @@ func (c *GrpcClient) connect() error {
tracer := opentracing.GlobalTracer() tracer := opentracing.GlobalTracer()
var err error var err error
getMasterServiceAddrFn := func() error { getMasterServiceAddrFn := func() error {
c.addr, err = getMasterServiceAddr(c.sess) ch := make(chan struct{}, 1)
var err error
go func() {
c.addr, err = getMasterServiceAddr(c.sess)
ch <- struct{}{}
}()
select {
case <-c.ctx.Done():
return retry.NoRetryError(errors.New("context canceled"))
case <-ch:
}
if err != nil { if err != nil {
return err return err
} }
...@@ -99,16 +115,26 @@ func (c *GrpcClient) connect() error { ...@@ -99,16 +115,26 @@ func (c *GrpcClient) connect() error {
log.Debug("MasterServiceClient try reconnect ", zap.String("address", c.addr)) log.Debug("MasterServiceClient try reconnect ", zap.String("address", c.addr))
ctx, cancelFunc := context.WithTimeout(c.ctx, c.timeout) ctx, cancelFunc := context.WithTimeout(c.ctx, c.timeout)
defer cancelFunc() defer cancelFunc()
conn, err := grpc.DialContext(ctx, c.addr, grpc.WithInsecure(), grpc.WithBlock(), var conn *grpc.ClientConn
grpc.WithUnaryInterceptor( var err error
otgrpc.OpenTracingClientInterceptor(tracer)), ch := make(chan struct{}, 1)
grpc.WithStreamInterceptor( go func() {
otgrpc.OpenTracingStreamClientInterceptor(tracer))) conn, err = grpc.DialContext(ctx, c.addr, grpc.WithInsecure(), grpc.WithBlock(),
if err != nil { grpc.WithUnaryInterceptor(
return err otgrpc.OpenTracingClientInterceptor(tracer)),
grpc.WithStreamInterceptor(
otgrpc.OpenTracingStreamClientInterceptor(tracer)))
ch <- struct{}{}
}()
select {
case <-c.ctx.Done():
return retry.NoRetryError(errors.New("context canceled"))
case <-ch:
} }
c.conn = conn if err == nil {
return nil c.conn = conn
}
return err
} }
err = retry.Retry(c.reconnTry, 500*time.Millisecond, connectGrpcFunc) err = retry.Retry(c.reconnTry, 500*time.Millisecond, connectGrpcFunc)
...@@ -143,18 +169,31 @@ func (c *GrpcClient) Register() error { ...@@ -143,18 +169,31 @@ func (c *GrpcClient) Register() error {
} }
func (c *GrpcClient) recall(caller func() (interface{}, error)) (interface{}, error) { func (c *GrpcClient) recall(caller func() (interface{}, error)) (interface{}, error) {
ret, err := caller() ch := make(chan struct{}, 1)
if err == nil { var ret interface{}
return ret, nil var err error
} go func() {
for i := 0; i < c.recallTry; i++ { ret, err = caller()
err = c.connect()
if err == nil { if err == nil {
ret, err = caller() ch <- struct{}{}
return
}
for i := 0; i < c.recallTry; i++ {
err = c.connect()
if err == nil { if err == nil {
return ret, nil ret, err = caller()
if err == nil {
ch <- struct{}{}
return
}
} }
} }
ch <- struct{}{}
}()
select {
case <-c.ctx.Done():
return nil, errors.New("context canceled")
case <-ch:
} }
return ret, err return ret, err
} }
......
...@@ -255,7 +255,7 @@ func TestGrpcService(t *testing.T) { ...@@ -255,7 +255,7 @@ func TestGrpcService(t *testing.T) {
svr.masterService.UpdateStateCode(internalpb.StateCode_Healthy) svr.masterService.UpdateStateCode(internalpb.StateCode_Healthy)
cli, err := grpcmasterserviceclient.NewClient(cms.Params.MetaRootPath, cms.Params.EtcdEndpoints, 3*time.Second) cli, err := grpcmasterserviceclient.NewClient(context.Background(), cms.Params.MetaRootPath, cms.Params.EtcdEndpoints, 3*time.Second)
assert.Nil(t, err) assert.Nil(t, err)
err = cli.Init() err = cli.Init()
......
...@@ -127,7 +127,6 @@ func (s *Server) Run() error { ...@@ -127,7 +127,6 @@ func (s *Server) Run() error {
} }
func (s *Server) init() error { func (s *Server) init() error {
ctx := context.Background()
var err error var err error
Params.Init() Params.Init()
if !funcutil.CheckPortAvailable(Params.Port) { if !funcutil.CheckPortAvailable(Params.Port) {
...@@ -171,7 +170,7 @@ func (s *Server) init() error { ...@@ -171,7 +170,7 @@ func (s *Server) init() error {
masterServiceAddr := Params.MasterAddress masterServiceAddr := Params.MasterAddress
log.Debug("ProxyNode", zap.String("master address", masterServiceAddr)) log.Debug("ProxyNode", zap.String("master address", masterServiceAddr))
timeout := 3 * time.Second timeout := 3 * time.Second
s.masterServiceClient, err = grpcmasterserviceclient.NewClient(proxynode.Params.MetaRootPath, proxynode.Params.EtcdEndpoints, timeout) s.masterServiceClient, err = grpcmasterserviceclient.NewClient(s.ctx, proxynode.Params.MetaRootPath, proxynode.Params.EtcdEndpoints, timeout)
if err != nil { if err != nil {
log.Debug("ProxyNode new masterServiceClient failed ", zap.Error(err)) log.Debug("ProxyNode new masterServiceClient failed ", zap.Error(err))
return err return err
...@@ -181,7 +180,7 @@ func (s *Server) init() error { ...@@ -181,7 +180,7 @@ func (s *Server) init() error {
log.Debug("ProxyNode new masterServiceClient Init ", zap.Error(err)) log.Debug("ProxyNode new masterServiceClient Init ", zap.Error(err))
return err return err
} }
err = funcutil.WaitForComponentHealthy(ctx, s.masterServiceClient, "MasterService", 1000000, time.Millisecond*200) err = funcutil.WaitForComponentHealthy(s.ctx, s.masterServiceClient, "MasterService", 1000000, time.Millisecond*200)
if err != nil { if err != nil {
log.Debug("ProxyNode WaitForComponentHealthy master service failed ", zap.Error(err)) log.Debug("ProxyNode WaitForComponentHealthy master service failed ", zap.Error(err))
......
...@@ -78,7 +78,6 @@ func NewServer(ctx context.Context, factory msgstream.Factory) (*Server, error) ...@@ -78,7 +78,6 @@ func NewServer(ctx context.Context, factory msgstream.Factory) (*Server, error)
} }
func (s *Server) init() error { func (s *Server) init() error {
ctx := context.Background()
Params.Init() Params.Init()
Params.LoadFromEnv() Params.LoadFromEnv()
Params.LoadFromArgs() Params.LoadFromArgs()
...@@ -122,7 +121,7 @@ func (s *Server) init() error { ...@@ -122,7 +121,7 @@ func (s *Server) init() error {
} }
log.Debug("QueryNode start to wait for QueryService ready") log.Debug("QueryNode start to wait for QueryService ready")
err = funcutil.WaitForComponentInitOrHealthy(ctx, queryService, "QueryService", 1000000, time.Millisecond*200) err = funcutil.WaitForComponentInitOrHealthy(s.ctx, queryService, "QueryService", 1000000, time.Millisecond*200)
if err != nil { if err != nil {
log.Debug("QueryNode wait for QueryService ready failed", zap.Error(err)) log.Debug("QueryNode wait for QueryService ready failed", zap.Error(err))
panic(err) panic(err)
...@@ -138,7 +137,7 @@ func (s *Server) init() error { ...@@ -138,7 +137,7 @@ func (s *Server) init() error {
addr := Params.MasterAddress addr := Params.MasterAddress
log.Debug("QueryNode start to new MasterServiceClient", zap.Any("QueryServiceAddress", addr)) log.Debug("QueryNode start to new MasterServiceClient", zap.Any("QueryServiceAddress", addr))
masterService, err := msc.NewClient(qn.Params.MetaRootPath, qn.Params.EtcdEndpoints, 3*time.Second) masterService, err := msc.NewClient(s.ctx, qn.Params.MetaRootPath, qn.Params.EtcdEndpoints, 3*time.Second)
if err != nil { if err != nil {
log.Debug("QueryNode new MasterServiceClient failed", zap.Error(err)) log.Debug("QueryNode new MasterServiceClient failed", zap.Error(err))
panic(err) panic(err)
...@@ -154,7 +153,7 @@ func (s *Server) init() error { ...@@ -154,7 +153,7 @@ func (s *Server) init() error {
panic(err) panic(err)
} }
log.Debug("QueryNode start to wait for MasterService ready") log.Debug("QueryNode start to wait for MasterService ready")
err = funcutil.WaitForComponentHealthy(ctx, masterService, "MasterService", 1000000, time.Millisecond*200) err = funcutil.WaitForComponentHealthy(s.ctx, masterService, "MasterService", 1000000, time.Millisecond*200)
if err != nil { if err != nil {
log.Debug("QueryNode wait for MasterService ready failed", zap.Error(err)) log.Debug("QueryNode wait for MasterService ready failed", zap.Error(err))
panic(err) panic(err)
...@@ -180,7 +179,7 @@ func (s *Server) init() error { ...@@ -180,7 +179,7 @@ func (s *Server) init() error {
} }
// wait IndexService healthy // wait IndexService healthy
log.Debug("QueryNode start to wait for IndexService ready") log.Debug("QueryNode start to wait for IndexService ready")
err = funcutil.WaitForComponentHealthy(ctx, indexService, "IndexService", 1000000, time.Millisecond*200) err = funcutil.WaitForComponentHealthy(s.ctx, indexService, "IndexService", 1000000, time.Millisecond*200)
if err != nil { if err != nil {
log.Debug("QueryNode wait for IndexService ready failed", zap.Error(err)) log.Debug("QueryNode wait for IndexService ready failed", zap.Error(err))
panic(err) panic(err)
...@@ -203,7 +202,7 @@ func (s *Server) init() error { ...@@ -203,7 +202,7 @@ func (s *Server) init() error {
panic(err) panic(err)
} }
log.Debug("QueryNode start to wait for DataService ready") log.Debug("QueryNode start to wait for DataService ready")
err = funcutil.WaitForComponentInitOrHealthy(ctx, dataService, "DataService", 1000000, time.Millisecond*200) err = funcutil.WaitForComponentInitOrHealthy(s.ctx, dataService, "DataService", 1000000, time.Millisecond*200)
if err != nil { if err != nil {
log.Debug("QueryNode wait for DataService ready failed", zap.Error(err)) log.Debug("QueryNode wait for DataService ready failed", zap.Error(err))
panic(err) panic(err)
......
...@@ -88,7 +88,6 @@ func (s *Server) Run() error { ...@@ -88,7 +88,6 @@ func (s *Server) Run() error {
} }
func (s *Server) init() error { func (s *Server) init() error {
ctx := context.Background()
Params.Init() Params.Init()
qs.Params.Init() qs.Params.Init()
qs.Params.Port = Params.Port qs.Params.Port = Params.Port
...@@ -109,7 +108,7 @@ func (s *Server) init() error { ...@@ -109,7 +108,7 @@ func (s *Server) init() error {
// --- Master Server Client --- // --- Master Server Client ---
log.Debug("QueryService try to new MasterService client", zap.Any("MasterServiceAddress", Params.MasterAddress)) log.Debug("QueryService try to new MasterService client", zap.Any("MasterServiceAddress", Params.MasterAddress))
masterService, err := msc.NewClient(qs.Params.MetaRootPath, qs.Params.EtcdEndpoints, 3*time.Second) masterService, err := msc.NewClient(s.loopCtx, qs.Params.MetaRootPath, qs.Params.EtcdEndpoints, 3*time.Second)
if err != nil { if err != nil {
log.Debug("QueryService try to new MasterService client failed", zap.Error(err)) log.Debug("QueryService try to new MasterService client failed", zap.Error(err))
panic(err) panic(err)
...@@ -126,7 +125,7 @@ func (s *Server) init() error { ...@@ -126,7 +125,7 @@ func (s *Server) init() error {
} }
// wait for master init or healthy // wait for master init or healthy
log.Debug("QueryService try to wait for MasterService ready") log.Debug("QueryService try to wait for MasterService ready")
err = funcutil.WaitForComponentInitOrHealthy(ctx, masterService, "MasterService", 1000000, time.Millisecond*200) err = funcutil.WaitForComponentInitOrHealthy(s.loopCtx, masterService, "MasterService", 1000000, time.Millisecond*200)
if err != nil { if err != nil {
log.Debug("QueryService wait for MasterService ready failed", zap.Error(err)) log.Debug("QueryService wait for MasterService ready failed", zap.Error(err))
panic(err) panic(err)
...@@ -150,7 +149,7 @@ func (s *Server) init() error { ...@@ -150,7 +149,7 @@ func (s *Server) init() error {
panic(err) panic(err)
} }
log.Debug("QueryService try to wait for DataService ready") log.Debug("QueryService try to wait for DataService ready")
err = funcutil.WaitForComponentInitOrHealthy(ctx, dataService, "DataService", 1000000, time.Millisecond*200) err = funcutil.WaitForComponentInitOrHealthy(s.loopCtx, dataService, "DataService", 1000000, time.Millisecond*200)
if err != nil { if err != nil {
log.Debug("QueryService wait for DataService ready failed", zap.Error(err)) log.Debug("QueryService wait for DataService ready failed", zap.Error(err))
panic(err) panic(err)
......
...@@ -101,12 +101,10 @@ func (node *ProxyNode) Register() error { ...@@ -101,12 +101,10 @@ func (node *ProxyNode) Register() error {
} }
func (node *ProxyNode) Init() error { func (node *ProxyNode) Init() error {
ctx := context.Background()
// wait for dataservice state changed to Healthy // wait for dataservice state changed to Healthy
if node.dataService != nil { if node.dataService != nil {
log.Debug("ProxyNode wait for dataService ready") log.Debug("ProxyNode wait for dataService ready")
err := funcutil.WaitForComponentHealthy(ctx, node.dataService, "DataService", 1000000, time.Millisecond*200) err := funcutil.WaitForComponentHealthy(node.ctx, node.dataService, "DataService", 1000000, time.Millisecond*200)
if err != nil { if err != nil {
log.Debug("ProxyNode wait for dataService ready failed", zap.Error(err)) log.Debug("ProxyNode wait for dataService ready failed", zap.Error(err))
return err return err
...@@ -117,7 +115,7 @@ func (node *ProxyNode) Init() error { ...@@ -117,7 +115,7 @@ func (node *ProxyNode) Init() error {
// wait for queryService state changed to Healthy // wait for queryService state changed to Healthy
if node.queryService != nil { if node.queryService != nil {
log.Debug("ProxyNode wait for queryService ready") log.Debug("ProxyNode wait for queryService ready")
err := funcutil.WaitForComponentHealthy(ctx, node.queryService, "QueryService", 1000000, time.Millisecond*200) err := funcutil.WaitForComponentHealthy(node.ctx, node.queryService, "QueryService", 1000000, time.Millisecond*200)
if err != nil { if err != nil {
log.Debug("ProxyNode wait for queryService ready failed", zap.Error(err)) log.Debug("ProxyNode wait for queryService ready failed", zap.Error(err))
return err return err
...@@ -128,7 +126,7 @@ func (node *ProxyNode) Init() error { ...@@ -128,7 +126,7 @@ func (node *ProxyNode) Init() error {
// wait for indexservice state changed to Healthy // wait for indexservice state changed to Healthy
if node.indexService != nil { if node.indexService != nil {
log.Debug("ProxyNode wait for indexService ready") log.Debug("ProxyNode wait for indexService ready")
err := funcutil.WaitForComponentHealthy(ctx, node.indexService, "IndexService", 1000000, time.Millisecond*200) err := funcutil.WaitForComponentHealthy(node.ctx, node.indexService, "IndexService", 1000000, time.Millisecond*200)
if err != nil { if err != nil {
log.Debug("ProxyNode wait for indexService ready failed", zap.Error(err)) log.Debug("ProxyNode wait for indexService ready failed", zap.Error(err))
return err return err
...@@ -137,7 +135,7 @@ func (node *ProxyNode) Init() error { ...@@ -137,7 +135,7 @@ func (node *ProxyNode) Init() error {
} }
if node.queryService != nil { if node.queryService != nil {
resp, err := node.queryService.CreateQueryChannel(ctx, &querypb.CreateQueryChannelRequest{}) resp, err := node.queryService.CreateQueryChannel(node.ctx, &querypb.CreateQueryChannelRequest{})
if err != nil { if err != nil {
log.Debug("ProxyNode CreateQueryChannel failed", zap.Error(err)) log.Debug("ProxyNode CreateQueryChannel failed", zap.Error(err))
return err return err
...@@ -187,7 +185,7 @@ func (node *ProxyNode) Init() error { ...@@ -187,7 +185,7 @@ func (node *ProxyNode) Init() error {
node.idAllocator = idAllocator node.idAllocator = idAllocator
node.idAllocator.PeerID = Params.ProxyID node.idAllocator.PeerID = Params.ProxyID
tsoAllocator, err := NewTimestampAllocator(node.masterService, Params.ProxyID) tsoAllocator, err := NewTimestampAllocator(node.ctx, node.masterService, Params.ProxyID)
if err != nil { if err != nil {
return err return err
} }
......
...@@ -22,12 +22,14 @@ import ( ...@@ -22,12 +22,14 @@ import (
) )
type TimestampAllocator struct { type TimestampAllocator struct {
ctx context.Context
masterService types.MasterService masterService types.MasterService
peerID UniqueID peerID UniqueID
} }
func NewTimestampAllocator(master types.MasterService, peerID UniqueID) (*TimestampAllocator, error) { func NewTimestampAllocator(ctx context.Context, master types.MasterService, peerID UniqueID) (*TimestampAllocator, error) {
a := &TimestampAllocator{ a := &TimestampAllocator{
ctx: ctx,
peerID: peerID, peerID: peerID,
masterService: master, masterService: master,
} }
...@@ -35,7 +37,7 @@ func NewTimestampAllocator(master types.MasterService, peerID UniqueID) (*Timest ...@@ -35,7 +37,7 @@ func NewTimestampAllocator(master types.MasterService, peerID UniqueID) (*Timest
} }
func (ta *TimestampAllocator) Alloc(count uint32) ([]Timestamp, error) { func (ta *TimestampAllocator) Alloc(count uint32) ([]Timestamp, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) ctx, cancel := context.WithTimeout(ta.ctx, 5*time.Second)
req := &masterpb.AllocTimestampRequest{ req := &masterpb.AllocTimestampRequest{
Base: &commonpb.MsgBase{ Base: &commonpb.MsgBase{
MsgType: commonpb.MsgType_RequestTSO, MsgType: commonpb.MsgType_RequestTSO,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册