-
Notifications
You must be signed in to change notification settings - Fork 721
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
client: refine serviceModeKeeper code #6201
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -240,19 +240,38 @@ func WithMaxErrorRetry(count int) ClientOption { | |
|
||
var _ Client = (*client)(nil) | ||
|
||
// serviceModeKeeper is for service mode switching | ||
// serviceModeKeeper is for service mode switching. | ||
type serviceModeKeeper struct { | ||
svcModeMutex sync.RWMutex | ||
// RMutex here is for the future usage that there might be multiple goroutines | ||
// triggering service mode switching concurrently. | ||
sync.RWMutex | ||
serviceMode pdpb.ServiceMode | ||
tsoClient atomic.Value | ||
tsoClient atomic.Value // *tsoClient | ||
tsoSvcDiscovery ServiceDiscovery | ||
} | ||
|
||
func (smk *serviceModeKeeper) close() { | ||
smk.Lock() | ||
defer smk.Unlock() | ||
switch smk.serviceMode { | ||
case pdpb.ServiceMode_API_SVC_MODE: | ||
smk.tsoSvcDiscovery.Close() | ||
fallthrough | ||
case pdpb.ServiceMode_PD_SVC_MODE: | ||
if tsoCli := smk.tsoClient.Load(); tsoCli != nil { | ||
tsoCli.(*tsoClient).Close() | ||
} | ||
case pdpb.ServiceMode_UNKNOWN_SVC_MODE: | ||
} | ||
} | ||
|
||
type client struct { | ||
keyspaceID uint32 | ||
svrUrls []string | ||
pdSvcDiscovery ServiceDiscovery | ||
tokenDispatcher *tokenDispatcher | ||
|
||
// For service mode switching. | ||
serviceModeKeeper | ||
|
||
// For internal usage. | ||
|
@@ -348,12 +367,7 @@ func (c *client) Close() { | |
c.cancel() | ||
c.wg.Wait() | ||
|
||
if tsoClient := c.getTSOClient(); tsoClient != nil { | ||
tsoClient.Close() | ||
} | ||
if c.tsoSvcDiscovery != nil { | ||
c.tsoSvcDiscovery.Close() | ||
} | ||
c.serviceModeKeeper.close() | ||
c.pdSvcDiscovery.Close() | ||
|
||
if c.tokenDispatcher != nil { | ||
|
@@ -364,57 +378,56 @@ func (c *client) Close() { | |
} | ||
|
||
func (c *client) setServiceMode(newMode pdpb.ServiceMode) { | ||
c.svcModeMutex.Lock() | ||
defer c.svcModeMutex.Unlock() | ||
|
||
c.Lock() | ||
defer c.Unlock() | ||
if newMode == c.serviceMode { | ||
return | ||
} | ||
|
||
log.Info("changing service mode", zap.String("old-mode", pdpb.ServiceMode_name[int32(c.serviceMode)]), | ||
zap.String("new-mode", pdpb.ServiceMode_name[int32(newMode)])) | ||
|
||
if newMode == pdpb.ServiceMode_UNKNOWN_SVC_MODE { | ||
log.Warn("intend to switch to unknown service mode. do nothing") | ||
return | ||
} | ||
|
||
var newTSOCli *tsoClient | ||
tsoSvcDiscovery := c.tsoSvcDiscovery | ||
ctx, cancel := context.WithCancel(c.ctx) | ||
|
||
if newMode == pdpb.ServiceMode_PD_SVC_MODE { | ||
newTSOCli = newTSOClient(ctx, cancel, c.option, c.keyspaceID, | ||
c.pdSvcDiscovery, c.pdSvcDiscovery.(tsoAllocatorEventSource), &pdTSOStreamBuilderFactory{}) | ||
newTSOCli.Setup() | ||
} else { | ||
tsoSvcDiscovery = newTSOServiceDiscovery(ctx, cancel, MetaStorageClient(c), | ||
log.Info("[pd] changing service mode", | ||
zap.String("old-mode", c.serviceMode.String()), | ||
zap.String("new-mode", newMode.String())) | ||
// Re-create a new TSO client. | ||
var ( | ||
newTSOCli *tsoClient | ||
newTSOSvcDiscovery ServiceDiscovery | ||
) | ||
switch newMode { | ||
case pdpb.ServiceMode_PD_SVC_MODE: | ||
newTSOCli = newTSOClient(c.ctx, c.option, c.keyspaceID, | ||
c.pdSvcDiscovery, &pdTSOStreamBuilderFactory{}) | ||
case pdpb.ServiceMode_API_SVC_MODE: | ||
newTSOSvcDiscovery = newTSOServiceDiscovery(c.ctx, MetaStorageClient(c), | ||
c.GetClusterID(c.ctx), c.keyspaceID, c.svrUrls, c.tlsCfg, c.option) | ||
newTSOCli = newTSOClient(ctx, cancel, c.option, c.keyspaceID, | ||
tsoSvcDiscovery, tsoSvcDiscovery.(tsoAllocatorEventSource), &tsoTSOStreamBuilderFactory{}) | ||
if err := tsoSvcDiscovery.Init(); err != nil { | ||
cancel() | ||
log.Error("failed to initialize tso service discovery. keep the current service mode", | ||
zap.Strings("svr-urls", c.svrUrls), zap.String("current-mode", pdpb.ServiceMode_name[int32(c.serviceMode)]), zap.Error(err)) | ||
newTSOCli = newTSOClient(c.ctx, c.option, c.keyspaceID, | ||
newTSOSvcDiscovery, &tsoTSOStreamBuilderFactory{}) | ||
if err := newTSOSvcDiscovery.Init(); err != nil { | ||
log.Error("[pd] failed to initialize tso service discovery. keep the current service mode", | ||
zap.Strings("svr-urls", c.svrUrls), zap.String("current-mode", c.serviceMode.String()), zap.Error(err)) | ||
return | ||
} | ||
newTSOCli.Setup() | ||
} | ||
|
||
// cleanup the old tso client | ||
if oldTSOCli := c.getTSOClient(); oldTSOCli != nil { | ||
oldTSOCli.Close() | ||
} | ||
if c.serviceMode == pdpb.ServiceMode_API_SVC_MODE { | ||
c.tsoSvcDiscovery.Close() | ||
case pdpb.ServiceMode_UNKNOWN_SVC_MODE: | ||
log.Warn("[pd] intend to switch to unknown service mode, just return") | ||
return | ||
} | ||
|
||
c.tsoSvcDiscovery = tsoSvcDiscovery | ||
newTSOCli.Setup() | ||
// Replace the old TSO client. | ||
oldTSOClient := c.getTSOClient() | ||
c.tsoClient.Store(newTSOCli) | ||
|
||
log.Info("service mode changed", zap.String("old-mode", pdpb.ServiceMode_name[int32(c.serviceMode)]), | ||
zap.String("new-mode", pdpb.ServiceMode_name[int32(newMode)])) | ||
oldTSOClient.Close() | ||
// Replace the old TSO service discovery if needed. | ||
oldTSOSvcDiscovery := c.tsoSvcDiscovery | ||
if newTSOSvcDiscovery != nil { | ||
c.tsoSvcDiscovery = newTSOSvcDiscovery | ||
// Close the old TSO service discovery safely after both the old client | ||
// and service discovery are replaced. | ||
if oldTSOSvcDiscovery != nil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Placeing "if oldTSOSvcDiscovery != nil {...}" here is very accurate, but reduced readability. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. either way is ok. |
||
oldTSOSvcDiscovery.Close() | ||
} | ||
} | ||
c.serviceMode = newMode | ||
log.Info("[pd] service mode changed", | ||
zap.String("old-mode", c.serviceMode.String()), | ||
zap.String("new-mode", newMode.String())) | ||
} | ||
|
||
func (c *client) getTSOClient() *tsoClient { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -91,8 +91,11 @@ type tsoClient struct { | |
} | ||
|
||
// newTSOClient returns a new TSO client. | ||
func newTSOClient(ctx context.Context, cancel context.CancelFunc, option *option, keyspaceID uint32, | ||
svcDiscovery ServiceDiscovery, eventSrc tsoAllocatorEventSource, factory tsoStreamBuilderFactory) *tsoClient { | ||
func newTSOClient( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the code style I preferred when I use the other programming languages, such as c++ and Java, but the coding style I used in this code (on the left side) is referred to other places in the code base, though there seems to be multiple coding styles. Do we have a uniform coding style or the style just needs to pass go format check? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are no strong principles here, I just want to make the parameters group as lines to reduce the one-line length. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok. I don't have strong preference. Your change here looks good to me. |
||
ctx context.Context, option *option, keyspaceID uint32, | ||
svcDiscovery ServiceDiscovery, factory tsoStreamBuilderFactory, | ||
) *tsoClient { | ||
ctx, cancel := context.WithCancel(ctx) | ||
c := &tsoClient{ | ||
ctx: ctx, | ||
cancel: cancel, | ||
|
@@ -105,6 +108,7 @@ func newTSOClient(ctx context.Context, cancel context.CancelFunc, option *option | |
updateTSOConnectionCtxsCh: make(chan struct{}, 1), | ||
} | ||
|
||
eventSrc := svcDiscovery.(tsoAllocatorEventSource) | ||
eventSrc.SetTSOLocalServAddrsUpdatedCallback(c.updateTSOLocalServAddrs) | ||
eventSrc.SetTSOGlobalServAddrUpdatedCallback(c.updateTSOGlobalServAddr) | ||
c.svcDiscovery.AddServiceAddrsSwitchedCallback(c.scheduleUpdateTSOConnectionCtxs) | ||
|
@@ -124,6 +128,9 @@ func (c *tsoClient) Setup() { | |
|
||
// Close closes the TSO client | ||
func (c *tsoClient) Close() { | ||
if c == nil { | ||
return | ||
} | ||
log.Info("closing tso client") | ||
|
||
c.cancel() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer to keep this lock. Originally, I used the corresponding read lock in the getTSOClient, but eventually I used atomic.Value() to store tsoClient and removed the read lock. After that, I still decided to keep this lock and the critical section in the setServiceMode() for the following reasons:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added the lock back. PTAL.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good. The change looks good to me.