Repository: matrixorigin/matrixone
Pull request #10601 (2023-07-12 04:51:38)

[feature] logservice: add API to update CN work state in HAKeeper.
Add work state for CN service:

```
type CNStoreInfo struct {
    ...
    WorkState metadata.WorkState
    ...
}

```

Add two APIs to update CN work state:

```
// UpdateCNWorkState updates the work state of CN.
UpdateCNWorkState(ctx context.Context, state pb.CNWorkState) error
// PatchCNStore updates the work state and labels of CN.
PatchCNStore(ctx context.Context, stateLabel pb.CNStateLabel) error
```

## What type of PR is this?

- [ ] API-change
- [ ] BUG
- [ ] Improvement
- [ ] Documentation
- [x] Feature
- [ ] Test and CI
- [ ] Code Refactoring

## Which issue(s) this PR fixes:

issue #10597

## What this PR does / why we need it:

MO cloudl operator will call the APIs to update CN work state.


Patch:
diff --git a/pkg/clusterservice/cluster.go b/pkg/clusterservice/cluster.go
index e780663af..388691e38 100644
--- a/pkg/clusterservice/cluster.go
+++ b/pkg/clusterservice/cluster.go
@@ -250,6 +250,7 @@ func newCNService(cn logpb.CNStore) metadata.CNService {
 		SQLAddress:             cn.SQLAddress,
 		LockServiceAddress:     cn.LockServiceAddress,
 		CtlAddress:             cn.CtlAddress,
+		WorkState:              cn.WorkState,
 		Labels:                 cn.Labels,
 	}
 }
diff --git a/pkg/frontend/mysql_cmd_executor.go b/pkg/frontend/mysql_cmd_executor.go
index 8ab9b991d..5c97b0b8b 100644
--- a/pkg/frontend/mysql_cmd_executor.go
+++ b/pkg/frontend/mysql_cmd_executor.go
@@ -1389,12 +1389,17 @@ func doShowBackendServers(ses *Session) error {
 
 	col3 := new(MysqlColumn)
 	col3.SetColumnType(defines.MYSQL_TYPE_VARCHAR)
-	col3.SetName("Labels")
+	col3.SetName("Work State")
+
+	col4 := new(MysqlColumn)
+	col4.SetColumnType(defines.MYSQL_TYPE_VARCHAR)
+	col4.SetName("Labels")
 
 	mrs := ses.GetMysqlResultSet()
 	mrs.AddColumn(col1)
 	mrs.AddColumn(col2)
 	mrs.AddColumn(col3)
+	mrs.AddColumn(col4)
 
 	var filterLabels = func(labels map[string]string) map[string]string {
 		var reservedLabels = map[string]struct{}{
@@ -1411,14 +1416,15 @@ func doShowBackendServers(ses *Session) error {
 	}
 
 	var appendFn = func(s *metadata.CNService) {
-		row := make([]interface{}, 3)
+		row := make([]interface{}, 4)
 		row[0] = s.ServiceID
 		row[1] = s.SQLAddress
+		row[2] = s.WorkState.String()
 		var labelStr string
 		for key, value := range s.Labels {
 			labelStr += fmt.Sprintf("%s:%s;", key, strings.Join(value.Labels, ","))
 		}
-		row[2] = labelStr
+		row[3] = labelStr
 		mrs.AddRow(row)
 	}
 
diff --git a/pkg/hakeeper/rsm.go b/pkg/hakeeper/rsm.go
index fd23032db..6e7b477e5 100644
--- a/pkg/hakeeper/rsm.go
+++ b/pkg/hakeeper/rsm.go
@@ -161,6 +161,30 @@ func parseUpdateCNLabelCmd(cmd []byte) pb.CNStoreLabel {
 	return result
 }
 
+func parseUpdateCNWorkStateCmd(cmd []byte) pb.CNWorkState {
+	if parseCmdTag(cmd) != pb.UpdateCNWorkState {
+		panic("not a SetCNWorkState cmd")
+	}
+	payload := cmd[headerSize:]
+	var result pb.CNWorkState
+	if err := result.Unmarshal(payload); err != nil {
+		panic(err)
+	}
+	return result
+}
+
+func parsePatchCNStoreCmd(cmd []byte) pb.CNStateLabel {
+	if parseCmdTag(cmd) != pb.PatchCNStore {
+		panic("not a PatchCNStore cmd")
+	}
+	payload := cmd[headerSize:]
+	var result pb.CNStateLabel
+	if err := result.Unmarshal(payload); err != nil {
+		panic(err)
+	}
+	return result
+}
+
 func GetSetStateCmd(state pb.HAKeeperState) []byte {
 	cmd := make([]byte, headerSize+4)
 	binaryEnc.PutUint32(cmd, uint32(pb.SetStateUpdate))
@@ -227,6 +251,24 @@ func GetUpdateCNLabelCmd(label pb.CNStoreLabel) []byte {
 	return cmd
 }
 
+func GetUpdateCNWorkStateCmd(state pb.CNWorkState) []byte {
+	cmd := make([]byte, headerSize+state.Size())
+	binaryEnc.PutUint32(cmd, uint32(pb.UpdateCNWorkState))
+	if _, err := state.MarshalTo(cmd[headerSize:]); err != nil {
+		panic(err)
+	}
+	return cmd
+}
+
+func GetPatchCNStoreCmd(stateLabel pb.CNStateLabel) []byte {
+	cmd := make([]byte, headerSize+stateLabel.Size())
+	binaryEnc.PutUint32(cmd, uint32(pb.PatchCNStore))
+	if _, err := stateLabel.MarshalTo(cmd[headerSize:]); err != nil {
+		panic(err)
+	}
+	return cmd
+}
+
 func NewStateMachine(shardID uint64, replicaID uint64) sm.IStateMachine {
 	if shardID != DefaultHAKeeperShardID {
 		panic(moerr.NewInvalidInputNoCtx("HAKeeper shard ID %d does not match DefaultHAKeeperShardID %d", shardID, DefaultHAKeeperShardID))
@@ -541,6 +583,10 @@ func (s *stateMachine) Update(e sm.Entry) (sm.Result, error) {
 		return s.handleTaskTableUserCmd(cmd), nil
 	case pb.UpdateCNLabel:
 		return s.handleUpdateCNLabel(cmd), nil
+	case pb.UpdateCNWorkState:
+		return s.handleUpdateCNWorkState(cmd), nil
+	case pb.PatchCNStore:
+		return s.handlePatchCNStore(cmd), nil
 	default:
 		panic(moerr.NewInvalidInputNoCtx("unknown haKeeper cmd '%v'", cmd))
 	}
@@ -593,6 +639,7 @@ func (s *stateMachine) handleClusterDetailsQuery(cfg Config) *pb.ClusterDetails
 			LockServiceAddress: info.LockServiceAddress,
 			CtlAddress:         info.CtlAddress,
 			State:              state,
+			WorkState:          info.WorkState,
 			Labels:             info.Labels,
 		}
 		cd.CNStores = append(cd.CNStores, n)
@@ -636,6 +683,16 @@ func (s *stateMachine) handleUpdateCNLabel(cmd []byte) sm.Result {
 	return sm.Result{}
 }
 
+func (s *stateMachine) handleUpdateCNWorkState(cmd []byte) sm.Result {
+	s.state.CNState.UpdateWorkState(parseUpdateCNWorkStateCmd(cmd))
+	return sm.Result{}
+}
+
+func (s *stateMachine) handlePatchCNStore(cmd []byte) sm.Result {
+	s.state.CNState.PatchCNStore(parsePatchCNStoreCmd(cmd))
+	return sm.Result{}
+}
+
 func (s *stateMachine) Lookup(query interface{}) (interface{}, error) {
 	if _, ok := query.(*StateQuery); ok {
 		return s.handleStateQuery(), nil
diff --git a/pkg/logservice/hakeeper_client.go b/pkg/logservice/hakeeper_client.go
index d6c4ac9bb..b72e7f202 100644
--- a/pkg/logservice/hakeeper_client.go
+++ b/pkg/logservice/hakeeper_client.go
@@ -83,6 +83,10 @@ type ProxyHAKeeperClient interface {
 	GetCNState(ctx context.Context) (pb.CNState, error)
 	// UpdateCNLabel updates the labels of CN.
 	UpdateCNLabel(ctx context.Context, label pb.CNStoreLabel) error
+	// UpdateCNWorkState updates the work state of CN.
+	UpdateCNWorkState(ctx context.Context, state pb.CNWorkState) error
+	// PatchCNStore updates the work state and labels of CN.
+	PatchCNStore(ctx context.Context, stateLabel pb.CNStateLabel) error
 }
 
 // TODO: HAKeeper discovery to be implemented
@@ -378,6 +382,40 @@ func (c *managedHAKeeperClient) UpdateCNLabel(ctx context.Context, label pb.CNSt
 	}
 }
 
+// UpdateCNWorkState implements the ProxyHAKeeperClient interface.
+func (c *managedHAKeeperClient) UpdateCNWorkState(ctx context.Context, state pb.CNWorkState) error {
+	for {
+		if err := c.prepareClient(ctx); err != nil {
+			return err
+		}
+		err := c.getClient().updateCNWorkState(ctx, state)
+		if err != nil {
+			c.resetClient()
+		}
+		if c.isRetryableError(err) {
+			continue
+		}
+		return err
+	}
+}
+
+// PatchCNStore implements the ProxyHAKeeperClient interface.
+func (c *managedHAKeeperClient) PatchCNStore(ctx context.Context, stateLabel pb.CNStateLabel) error {
+	for {
+		if err := c.prepareClient(ctx); err != nil {
+			return err
+		}
+		err := c.getClient().patchCNStore(ctx, stateLabel)
+		if err != nil {
+			c.resetClient()
+		}
+		if c.isRetryableError(err) {
+			continue
+		}
+		return err
+	}
+}
+
 func (c *managedHAKeeperClient) isRetryableError(err error) bool {
 	return moerr.IsMoErrCode(err, moerr.ErrNoHAKeeper)
 }
@@ -626,6 +664,30 @@ func (c *hakeeperClient) updateCNLabel(ctx context.Context, label pb.CNStoreLabe
 	return nil
 }
 
+func (c *hakeeperClient) updateCNWorkState(ctx context.Context, state pb.CNWorkState) error {
+	req := pb.Request{
+		Method:      pb.UPDATE_CN_WORK_STATE,
+		CNWorkState: &state,
+	}
+	_, err := c.request(ctx, req)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (c *hakeeperClient) patchCNStore(ctx context.Context, stateLabel pb.CNStateLabel) error {
+	req := pb.Request{
+		Method:       pb.PATCH_CN_STORE,
+		CNStateLabel: &stateLabel,
+	}
+	_, err := c.request(ctx, req)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
 func (c *hakeeperClient) checkIsHAKeeper(ctx context.Context) (bool, error) {
 	req := pb.Request{
 		Method: pb.CHECK_HAKEEPER,
diff --git a/pkg/logservice/service.go b/pkg/logservice/service.go
index 43badc7e7..533c80585 100644
--- a/pkg/logservice/service.go
+++ b/pkg/logservice/service.go
@@ -275,6 +275,10 @@ func (s *Service) handle(ctx context.Context, req pb.Request,
 		return s.handleGetShardInfo(ctx, req), pb.LogRecordResponse{}
 	case pb.UPDATE_CN_LABEL:
 		return s.handleUpdateCNLabel(ctx, req), pb.LogRecordResponse{}
+	case pb.UPDATE_CN_WORK_STATE:
+		return s.handleUpdateCNWorkState(ctx, req), pb.LogRecordResponse{}
+	case pb.PATCH_CN_STORE:
+		return s.handlePatchCNStore(ctx, req), pb.LogRecordResponse{}
 	default:
 		panic("unknown log service method type")
 	}
@@ -458,6 +462,26 @@ func (s *Service) handleUpdateCNLabel(ctx context.Context, req pb.Request) pb.Re
 	return resp
 }
 
+func (s *Service) handleUpdateCNWorkState(ctx context.Context, req pb.Request) pb.Response {
+	workState := req.CNWorkState
+	resp := getResponse(req)
+	if err := s.store.updateCNWorkState(ctx, *workState); err != nil {
+		resp.ErrorCode, resp.ErrorMessage = toErrorCode(err)
+		return resp
+	}
+	return resp
+}
+
+func (s *Service) handlePatchCNStore(ctx context.Context, req pb.Request) pb.Response {
+	stateLabel := req.CNStateLabel
+	resp := getResponse(req)
+	if err := s.store.patchCNStore(ctx, *stateLabel); err != nil {
+		resp.ErrorCode, resp.ErrorMessage = toErrorCode(err)
+		return resp
+	}
+	return resp
+}
+
 func (s *Service) getBackendOptions() []morpc.BackendOption {
 	return []morpc.BackendOption{
 		morpc.WithBackendFilter(func(msg morpc.Message, backendAddr string) bool {
diff --git a/pkg/logservice/store.go b/pkg/logservice/store.go
index 2654ca64a..4a4386e26 100644
--- a/pkg/logservice/store.go
+++ b/pkg/logservice/store.go
@@ -550,6 +550,50 @@ func (l *store) updateCNLabel(ctx context.Context, label pb.CNStoreLabel) error
 	}
 }
 
+func (l *store) updateCNWorkState(ctx context.Context, workState pb.CNWorkState) error {
+	state, err := l.getCheckerState()
+	if err != nil {
+		return err
+	}
+	if _, ok := state.CNState.Stores[workState.UUID]; !ok {
+		return moerr.NewInternalError(ctx, "CN [%s] does not exist", workState.UUID)
+	}
+	cmd := hakeeper.GetUpdateCNWorkStateCmd(workState)
+	session := l.nh.GetNoOPSession(hakeeper.DefaultHAKeeperShardID)
+	if result, err := l.propose(ctx, session, cmd); err != nil {
+		l.runtime.Logger().Error("failed to propose CN work state",
+			zap.String("state", state.String()),
+			zap.Error(err))
+		return handleNotHAKeeperError(ctx, err)
+	} else {
+		var cb pb.CommandBatch
+		MustUnmarshal(&cb, result.Data)
+		return nil
+	}
+}
+
+func (l *store) patchCNStore(ctx context.Context, stateLabel pb.CNStateLabel) error {
+	state, err := l.getCheckerState()
+	if err != nil {
+		return err
+	}
+	if _, ok := state.CNState.Stores[stateLabel.UUID]; !ok {
+		return moerr.NewInternalError(ctx, "CN [%s] does not exist", stateLabel.UUID)
+	}
+	cmd := hakeeper.GetPatchCNStoreCmd(stateLabel)
+	session := l.nh.GetNoOPSession(hakeeper.DefaultHAKeeperShardID)
+	if result, err := l.propose(ctx, session, cmd); err != nil {
+		l.runtime.Logger().Error("failed to propose CN work state",
+			zap.String("state", state.String()),
+			zap.Error(err))
+		return handleNotHAKeeperError(ctx, err)
+	} else {
+		var cb pb.CommandBatch
+		MustUnmarshal(&cb, result.Data)
+		return nil
+	}
+}
+
 func (l *store) decodeCmd(ctx context.Context, e raftpb.Entry) []byte {
 	if e.Type == raftpb.ApplicationEntry {
 		panic(moerr.NewInvalidState(ctx, "unexpected entry type"))
diff --git a/pkg/pb/logservice/logservice.go b/pkg/pb/logservice/logservice.go
index 575bc6a0d..4217fc370 100644
--- a/pkg/pb/logservice/logservice.go
+++ b/pkg/pb/logservice/logservice.go
@@ -73,6 +73,7 @@ func (s *CNState) Update(hb CNStoreHeartbeat, tick uint64) {
 	storeInfo, ok := s.Stores[hb.UUID]
 	if !ok {
 		storeInfo = CNStoreInfo{}
+		storeInfo.WorkState = metadata.WorkState_Working
 		storeInfo.Labels = make(map[string]metadata.LabelList)
 	}
 	storeInfo.Tick = tick
@@ -97,6 +98,42 @@ func (s *CNState) UpdateLabel(label CNStoreLabel) {
 	s.Stores[label.UUID] = storeInfo
 }
 
+// UpdateWorkState updates work state of CN store.
+func (s *CNState) UpdateWorkState(state CNWorkState) {
+	if state.GetState() == metadata.WorkState_Unknown {
+		return
+	}
+	storeInfo, ok := s.Stores[state.UUID]
+	// If the CN store does not exist, we should do nothing and wait for
+	// CN heartbeat.
+	if !ok {
+		return
+	}
+	// If current state is more advanced, do nothing.
+	if storeInfo.WorkState >= state.GetState() {
+		return
+	}
+	storeInfo.WorkState = state.State
+	s.Stores[state.UUID] = storeInfo
+}
+
+// PatchCNStore updates work state and labels of CN store.
+func (s *CNState) PatchCNStore(stateLabel CNStateLabel) {
+	storeInfo, ok := s.Stores[stateLabel.UUID]
+	// If the CN store does not exist, we should do nothing and wait for
+	// CN heartbeat.
+	if !ok {
+		return
+	}
+	if stateLabel.GetState() > storeInfo.WorkState {
+		storeInfo.WorkState = stateLabel.State
+	}
+	if stateLabel.Labels != nil {
+		storeInfo.Labels = stateLabel.Labels
+	}
+	s.Stores[stateLabel.UUID] = storeInfo
+}
+
 // NewDNState creates a new DNState.
 func NewDNState() DNState {
 	return DNState{
diff --git a/pkg/pb/logservice/logservice.pb.go b/pkg/pb/logservice/logservice.pb.go
index 041562608..6dc794648 100644
--- a/pkg/pb/logservice/logservice.pb.go
+++ b/pkg/pb/logservice/logservice.pb.go
@@ -84,22 +84,24 @@ func (NodeState) EnumDescriptor() ([]byte, []int) {
 type MethodType int32
 
 const (
-	TSO_UPDATE          MethodType = 0
-	APPEND              MethodType = 1
-	READ                MethodType = 2
-	TRUNCATE            MethodType = 3
-	GET_TRUNCATE        MethodType = 4
-	CONNECT             MethodType = 5
-	CONNECT_RO          MethodType = 6
-	LOG_HEARTBEAT       MethodType = 7
-	CN_HEARTBEAT        MethodType = 8
-	DN_HEARTBEAT        MethodType = 9
-	CHECK_HAKEEPER      MethodType = 10
-	GET_CLUSTER_DETAILS MethodType = 11
-	GET_SHARD_INFO      MethodType = 12
-	CN_ALLOCATE_ID      MethodType = 13
-	GET_CLUSTER_STATE   MethodType = 14
-	UPDATE_CN_LABEL     MethodType = 15
+	TSO_UPDATE           MethodType = 0
+	APPEND               MethodType = 1
+	READ                 MethodType = 2
+	TRUNCATE             MethodType = 3
+	GET_TRUNCATE         MethodType = 4
+	CONNECT              MethodType = 5
+	CONNECT_RO           MethodType = 6
+	LOG_HEARTBEAT        MethodType = 7
+	CN_HEARTBEAT         MethodType = 8
+	DN_HEARTBEAT         MethodType = 9
+	CHECK_HAKEEPER       MethodType = 10
+	GET_CLUSTER_DETAILS  MethodType = 11
+	GET_SHARD_INFO       MethodType = 12
+	CN_ALLOCATE_ID       MethodType = 13
+	GET_CLUSTER_STATE    MethodType = 14
+	UPDATE_CN_LABEL      MethodType = 15
+	UPDATE_CN_WORK_STATE MethodType = 16
+	PATCH_CN_STORE       MethodType = 17
 )
 
 var MethodType_name = map[int32]string{
@@ -119,25 +121,29 @@ var MethodType_name = map[int32]string{
 	13: "CN_ALLOCATE_ID",
 	14: "GET_CLUSTER_STATE",
 	15: "UPDATE_CN_LABEL",
+	16: "UPDATE_CN_WORK_STATE",
+	17: "PATCH_CN_STORE",
 }
 
 var MethodType_value = map[string]int32{
-	"TSO_UPDATE":          0,
-	"APPEND":              1,
-	"READ":                2,
-	"TRUNCATE":            3,
-	"GET_TRUNCATE":        4,
-	"CONNECT":             5,
-	"CONNECT_RO":          6,
-	"LOG_HEARTBEAT":       7,
-	"CN_HEARTBEAT":        8,
-	"DN_HEARTBEAT":        9,
-	"CHECK_HAKEEPER":      10,
-	"GET_CLUSTER_DETAILS": 11,
-	"GET_SHARD_INFO":      12,
-	"CN_ALLOCATE_ID":      13,
-	"GET_CLUSTER_STATE":   14,
-	"UPDATE_CN_LABEL":     15,
+	"TSO_UPDATE":           0,
+	"APPEND":               1,
+	"READ":                 2,
+	"TRUNCATE":             3,
+	"GET_TRUNCATE":         4,
+	"CONNECT":              5,
+	"CONNECT_RO":           6,
+	"LOG_HEARTBEAT":        7,
+	"CN_HEARTBEAT":         8,
+	"DN_HEARTBEAT":         9,
+	"CHECK_HAKEEPER":       10,
+	"GET_CLUSTER_DETAILS":  11,
+	"GET_SHARD_INFO":       12,
+	"CN_ALLOCATE_ID":       13,
+	"GET_CLUSTER_STATE":    14,
+	"UPDATE_CN_LABEL":      15,
+	"UPDATE_CN_WORK_STATE": 16,
+	"PATCH_CN_STORE":       17,
 }
 
 func (x MethodType) String() string {
@@ -218,6 +224,8 @@ const (
 	SetTaskSchedulerStateUpdate HAKeeperUpdateType = 8
 	SetTaskTableUserUpdate      HAKeeperUpdateType = 9
 	UpdateCNLabel               HAKeeperUpdateType = 10
+	UpdateCNWorkState           HAKeeperUpdateType = 11
+	PatchCNStore                HAKeeperUpdateType = 12
 )
 
 var HAKeeperUpdateType_name = map[int32]string{
@@ -232,6 +240,8 @@ var HAKeeperUpdateType_name = map[int32]string{
 	8:  "SetTaskSchedulerStateUpdate",
 	9:  "SetTaskTableUserUpdate",
 	10: "UpdateCNLabel",
+	11: "UpdateCNWorkState",
+	12: "PatchCNStore",
 }
 
 var HAKeeperUpdateType_value = map[string]int32{
@@ -246,6 +256,8 @@ var HAKeeperUpdateType_value = map[string]int32{
 	"SetTaskSchedulerStateUpdate": 8,
 	"SetTaskTableUserUpdate":      9,
 	"UpdateCNLabel":               10,
+	"UpdateCNWorkState":           11,
+	"PatchCNStore":                12,
 }
 
 func (x HAKeeperUpdateType) String() string {
@@ -420,7 +432,8 @@ type CNStore struct {
 	Role                 metadata.CNRole               `protobuf:"varint,6,opt,name=Role,proto3,enum=metadata.CNRole" json:"Role,omitempty"`
 	Tick                 uint64                        `protobuf:"varint,7,opt,name=Tick,proto3" json:"Tick,omitempty"`
 	State                NodeState                     `protobuf:"varint,8,opt,name=State,proto3,enum=logservice.NodeState" json:"State,omitempty"`
-	Labels               map[string]metadata.LabelList `protobuf:"bytes,9,rep,name=Labels,proto3" json:"Labels" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+	WorkState            metadata.WorkState            `protobuf:"varint,9,opt,name=WorkState,proto3,enum=metadata.WorkState" json:"WorkState,omitempty"`
+	Labels               map[string]metadata.LabelList `protobuf:"bytes,10,rep,name=Labels,proto3" json:"Labels" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
 	XXX_NoUnkeyedLiteral struct{}                      `json:"-"`
 	XXX_unrecognized     []byte                        `json:"-"`
 	XXX_sizecache        int32                         `json:"-"`
@@ -515,6 +528,13 @@ func (m *CNStore) GetState() NodeState {
 	return NormalState
 }
 
+func (m *CNStore) GetWorkState() metadata.WorkState {
+	if m != nil {
+		return m.WorkState
+	}
+	return metadata.WorkState_Unknown
+}
+
 func (m *CNStore) GetLabels() map[string]metadata.LabelList {
 	if m != nil {
 		return m.Labels
@@ -1596,6 +1616,129 @@ func (m *CNStoreLabel) GetLabels() map[string]metadata.LabelList {
 	return nil
 }
 
+type CNWorkState struct {
+	// UUID is the uuid of the CN store.
+	UUID string `protobuf:"bytes,1,opt,name=UUID,proto3" json:"UUID,omitempty"`
+	// State is the CN work state.
+	State                metadata.WorkState `protobuf:"varint,2,opt,name=State,proto3,enum=metadata.WorkState" json:"State,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}           `json:"-"`
+	XXX_unrecognized     []byte             `json:"-"`
+	XXX_sizecache        int32              `json:"-"`
+}
+
+func (m *CNWorkState) Reset()         { *m = CNWorkState{} }
+func (m *CNWorkState) String() string { return proto.CompactTextString(m) }
+func (*CNWorkState) ProtoMessage()    {}
+func (*CNWorkState) Descriptor() ([]byte, []int) {
+	return fileDescriptor_fd1040c5381ab5a7, []int{15}
+}
+func (m *CNWorkState) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *CNWorkState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_CNWorkState.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalToSizedBuffer(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (m *CNWorkState) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_CNWorkState.Merge(m, src)
+}
+func (m *CNWorkState) XXX_Size() int {
+	return m.Size()
+}
+func (m *CNWorkState) XXX_DiscardUnknown() {
+	xxx_messageInfo_CNWorkState.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CNWorkState proto.InternalMessageInfo
+
+func (m *CNWorkState) GetUUID() string {
+	if m != nil {
+		return m.UUID
+	}
+	return ""
+}
+
+func (m *CNWorkState) GetState() metadata.WorkState {
+	if m != nil {
+		return m.State
+	}
+	return metadata.WorkState_Unknown
+}
+
+type CNStateLabel struct {
+	// UUID is the uuid of the CN store.
+	UUID string `protobuf:"bytes,1,opt,name=UUID,proto3" json:"UUID,omitempty"`
+	// State is the CN work state.
+	State metadata.WorkState `protobuf:"varint,2,opt,name=State,proto3,enum=metadata.WorkState" json:"State,omitempty"`
+	// Labels is the labels of the CN store.
+	Labels               map[string]metadata.LabelList `protobuf:"bytes,3,rep,name=Labels,proto3" json:"Labels" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+	XXX_NoUnkeyedLiteral struct{}                      `json:"-"`
+	XXX_unrecognized     []byte                        `json:"-"`
+	XXX_sizecache        int32                         `json:"-"`
+}
+
+func (m *CNStateLabel) Reset()         { *m = CNStateLabel{} }
+func (m *CNStateLabel) String() string { return proto.CompactTextString(m) }
+func (*CNStateLabel) ProtoMessage()    {}
+func (*CNStateLabel) Descriptor() ([]byte, []int) {
+	return fileDescriptor_fd1040c5381ab5a7, []int{16}
+}
+func (m *CNStateLabel) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *CNStateLabel) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_CNStateLabel.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalToSizedBuffer(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (m *CNStateLabel) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_CNStateLabel.Merge(m, src)
+}
+func (m *CNStateLabel) XXX_Size() int {
+	return m.Size()
+}
+func (m *CNStateLabel) XXX_DiscardUnknown() {
+	xxx_messageInfo_CNStateLabel.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CNStateLabel proto.InternalMessageInfo
+
+func (m *CNStateLabel) GetUUID() string {
+	if m != nil {
+		return m.UUID
+	}
+	return ""
+}
+
+func (m *CNStateLabel) GetState() metadata.WorkState {
+	if m != nil {
+		return m.State
+	}
+	return metadata.WorkState_Unknown
+}
+
+func (m *CNStateLabel) GetLabels() map[string]metadata.LabelList {
+	if m != nil {
+		return m.Labels
+	}
+	return nil
+}
+
 type Request struct {
 	RequestID            uint64             `protobuf:"varint,1,opt,name=RequestID,proto3" json:"RequestID,omitempty"`
 	Method               MethodType         `protobuf:"varint,2,opt,name=Method,proto3,enum=logservice.MethodType" json:"Method,omitempty"`
@@ -1606,6 +1749,8 @@ type Request struct {
 	TsoRequest           *TsoRequest        `protobuf:"bytes,7,opt,name=TsoRequest,proto3" json:"TsoRequest,omitempty"`
 	CNAllocateID         *CNAllocateID      `protobuf:"bytes,8,opt,name=CNAllocateID,proto3" json:"CNAllocateID,omitempty"`
 	CNStoreLabel         *CNStoreLabel      `protobuf:"bytes,9,opt,name=CNStoreLabel,proto3" json:"CNStoreLabel,omitempty"`
+	CNWorkState          *CNWorkState       `protobuf:"bytes,10,opt,name=CNWorkState,proto3" json:"CNWorkState,omitempty"`
+	CNStateLabel         *CNStateLabel      `protobuf:"bytes,11,opt,name=CNStateLabel,proto3" json:"CNStateLabel,omitempty"`
 	XXX_NoUnkeyedLiteral struct{}           `json:"-"`
 	XXX_unrecognized     []byte             `json:"-"`
 	XXX_sizecache        int32              `json:"-"`
@@ -1615,7 +1760,7 @@ func (m *Request) Reset()         { *m = Request{} }
 func (m *Request) String() string { return proto.CompactTextString(m) }
 func (*Request) ProtoMessage()    {}
 func (*Request) Descriptor() ([]byte, []int) {
-	return fileDescriptor_fd1040c5381ab5a7, []int{15}
+	return fileDescriptor_fd1040c5381ab5a7, []int{17}
 }
 func (m *Request) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -1707,6 +1852,20 @@ func (m *Request) GetCNStoreLabel() *CNStoreLabel {
 	return nil
 }
 
+func (m *Request) GetCNWorkState() *CNWorkState {
+	if m != nil {
+		return m.CNWorkState
+	}
+	return nil
+}
+
+func (m *Request) GetCNStateLabel() *CNStateLabel {
+	if m != nil {
+		return m.CNStateLabel
+	}
+	return nil
+}
+
 type LogResponse struct {
 	ShardID              uint64   `protobuf:"varint,1,opt,name=ShardID,proto3" json:"ShardID,omitempty"`
 	Lsn                  uint64   `protobuf:"varint,2,opt,name=Lsn,proto3" json:"Lsn,omitempty"`
@@ -1720,7 +1879,7 @@ func (m *LogResponse) Reset()         { *m = LogResponse{} }
 func (m *LogResponse) String() string { return proto.CompactTextString(m) }
 func (*LogResponse) ProtoMessage()    {}
 func (*LogResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_fd1040c5381ab5a7, []int{16}
+	return fileDescriptor_fd1040c5381ab5a7, []int{18}
 }
 func (m *LogResponse) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -1781,7 +1940,7 @@ func (m *AllocateIDResponse) Reset()         { *m = AllocateIDResponse{} }
 func (m *AllocateIDResponse) String() string { return proto.CompactTextString(m) }
 func (*AllocateIDResponse) ProtoMessage()    {}
 func (*AllocateIDResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_fd1040c5381ab5a7, []int{17}
+	return fileDescriptor_fd1040c5381ab5a7, []int{19}
 }
 func (m *AllocateIDResponse) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -1839,7 +1998,7 @@ func (m *Response) Reset()         { *m = Response{} }
 func (m *Response) String() string { return proto.CompactTextString(m) }
 func (*Response) ProtoMessage()    {}
 func (*Response) Descriptor() ([]byte, []int) {
-	return fileDescriptor_fd1040c5381ab5a7, []int{18}
+	return fileDescriptor_fd1040c5381ab5a7, []int{20}
 }
 func (m *Response) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -1963,7 +2122,7 @@ func (m *LogRecordResponse) Reset()         { *m = LogRecordResponse{} }
 func (m *LogRecordResponse) String() string { return proto.CompactTextString(m) }
 func (*LogRecordResponse) ProtoMessage()    {}
 func (*LogRecordResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_fd1040c5381ab5a7, []int{19}
+	return fileDescriptor_fd1040c5381ab5a7, []int{21}
 }
 func (m *LogRecordResponse) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -2010,7 +2169,7 @@ func (m *TsoResponse) Reset()         { *m = TsoResponse{} }
 func (m *TsoResponse) String() string { return proto.CompactTextString(m) }
 func (*TsoResponse) ProtoMessage()    {}
 func (*TsoResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_fd1040c5381ab5a7, []int{20}
+	return fileDescriptor_fd1040c5381ab5a7, []int{22}
 }
 func (m *TsoResponse) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -2060,7 +2219,7 @@ func (m *TaskTableUser) Reset()         { *m = TaskTableUser{} }
 func (m *TaskTableUser) String() string { return proto.CompactTextString(m) }
 func (*TaskTableUser) ProtoMessage()    {}
 func (*TaskTableUser) Descriptor() ([]byte, []int) {
-	return fileDescriptor_fd1040c5381ab5a7, []int{21}
+	return fileDescriptor_fd1040c5381ab5a7, []int{23}
 }
 func (m *TaskTableUser) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -2121,7 +2280,7 @@ func (m *Replica) Reset()         { *m = Replica{} }
 func (m *Replica) String() string { return proto.CompactTextString(m) }
 func (*Replica) ProtoMessage()    {}
 func (*Replica) Descriptor() ([]byte, []int) {
-	return fileDescriptor_fd1040c5381ab5a7, []int{22}
+	return fileDescriptor_fd1040c5381ab5a7, []int{24}
 }
 func (m *Replica) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -2200,7 +2359,7 @@ func (m *ConfigChange) Reset()         { *m = ConfigChange{} }
 func (m *ConfigChange) String() string { return proto.CompactTextString(m) }
 func (*ConfigChange) ProtoMessage()    {}
 func (*ConfigChange) Descriptor() ([]byte, []int) {
-	return fileDescriptor_fd1040c5381ab5a7, []int{23}
+	return fileDescriptor_fd1040c5381ab5a7, []int{25}
 }
 func (m *ConfigChange) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -2262,7 +2421,7 @@ func (m *ShutdownStore) Reset()         { *m = ShutdownStore{} }
 func (m *ShutdownStore) String() string { return proto.CompactTextString(m) }
 func (*ShutdownStore) ProtoMessage()    {}
 func (*ShutdownStore) Descriptor() ([]byte, []int) {
-	return fileDescriptor_fd1040c5381ab5a7, []int{24}
+	return fileDescriptor_fd1040c5381ab5a7, []int{26}
 }
 func (m *ShutdownStore) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -2317,7 +2476,7 @@ func (m *ScheduleCommand) Reset()         { *m = ScheduleCommand{} }
 func (m *ScheduleCommand) String() string { return proto.CompactTextString(m) }
 func (*ScheduleCommand) ProtoMessage()    {}
 func (*ScheduleCommand) Descriptor() ([]byte, []int) {
-	return fileDescriptor_fd1040c5381ab5a7, []int{25}
+	return fileDescriptor_fd1040c5381ab5a7, []int{27}
 }
 func (m *ScheduleCommand) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -2410,7 +2569,7 @@ func (m *CreateTaskService) Reset()         { *m = CreateTaskService{} }
 func (m *CreateTaskService) String() string { return proto.CompactTextString(m) }
 func (*CreateTaskService) ProtoMessage()    {}
 func (*CreateTaskService) Descriptor() ([]byte, []int) {
-	return fileDescriptor_fd1040c5381ab5a7, []int{26}
+	return fileDescriptor_fd1040c5381ab5a7, []int{28}
 }
 func (m *CreateTaskService) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -2465,7 +2624,7 @@ func (m *DeleteCNStore) Reset()         { *m = DeleteCNStore{} }
 func (m *DeleteCNStore) String() string { return proto.CompactTextString(m) }
 func (*DeleteCNStore) ProtoMessage()    {}
 func (*DeleteCNStore) Descriptor() ([]byte, []int) {
-	return fileDescriptor_fd1040c5381ab5a7, []int{27}
+	return fileDescriptor_fd1040c5381ab5a7, []int{29}
 }
 func (m *DeleteCNStore) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -2513,7 +2672,7 @@ func (m *CommandBatch) Reset()         { *m = CommandBatch{} }
 func (m *CommandBatch) String() string { return proto.CompactTextString(m) }
 func (*CommandBatch) ProtoMessage()    {}
 func (*CommandBatch) Descriptor() ([]byte, []int) {
-	return fileDescriptor_fd1040c5381ab5a7, []int{28}
+	return fileDescriptor_fd1040c5381ab5a7, []int{30}
 }
 func (m *CommandBatch) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -2565,7 +2724,8 @@ type CNStoreInfo struct {
 	CtlAddress           string                        `protobuf:"bytes,5,opt,name=CtlAddress,proto3" json:"CtlAddress,omitempty"`
 	Role                 metadata.CNRole               `protobuf:"varint,6,opt,name=Role,proto3,enum=metadata.CNRole" json:"Role,omitempty"`
 	TaskServiceCreated   bool                          `protobuf:"varint,7,opt,name=TaskServiceCreated,proto3" json:"TaskServiceCreated,omitempty"`
-	Labels               map[string]metadata.LabelList `protobuf:"bytes,8,rep,name=Labels,proto3" json:"Labels" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+	WorkState            metadata.WorkState            `protobuf:"varint,8,opt,name=WorkState,proto3,enum=metadata.WorkState" json:"WorkState,omitempty"`
+	Labels               map[string]metadata.LabelList `protobuf:"bytes,9,rep,name=Labels,proto3" json:"Labels" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
 	XXX_NoUnkeyedLiteral struct{}                      `json:"-"`
 	XXX_unrecognized     []byte                        `json:"-"`
 	XXX_sizecache        int32                         `json:"-"`
@@ -2575,7 +2735,7 @@ func (m *CNStoreInfo) Reset()         { *m = CNStoreInfo{} }
 func (m *CNStoreInfo) String() string { return proto.CompactTextString(m) }
 func (*CNStoreInfo) ProtoMessage()    {}
 func (*CNStoreInfo) Descriptor() ([]byte, []int) {
-	return fileDescriptor_fd1040c5381ab5a7, []int{29}
+	return fileDescriptor_fd1040c5381ab5a7, []int{31}
 }
 func (m *CNStoreInfo) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -2653,6 +2813,13 @@ func (m *CNStoreInfo) GetTaskServiceCreated() bool {
 	return false
 }
 
+func (m *CNStoreInfo) GetWorkState() metadata.WorkState {
+	if m != nil {
+		return m.WorkState
+	}
+	return metadata.WorkState_Unknown
+}
+
 func (m *CNStoreInfo) GetLabels() map[string]metadata.LabelList {
 	if m != nil {
 		return m.Labels
@@ -2673,7 +2840,7 @@ func (m *CNState) Reset()         { *m = CNState{} }
 func (m *CNState) String() string { return proto.CompactTextString(m) }
 func (*CNState) ProtoMessage()    {}
 func (*CNState) Descriptor() ([]byte, []int) {
-	return fileDescriptor_fd1040c5381ab5a7, []int{30}
+	return fileDescriptor_fd1040c5381ab5a7, []int{32}
 }
 func (m *CNState) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -2729,7 +2896,7 @@ func (m *DNStoreInfo) Reset()         { *m = DNStoreInfo{} }
 func (m *DNStoreInfo) String() string { return proto.CompactTextString(m) }
 func (*DNStoreInfo) ProtoMessage()    {}
 func (*DNStoreInfo) Descriptor() ([]byte, []int) {
-	return fileDescriptor_fd1040c5381ab5a7, []int{31}
+	return fileDescriptor_fd1040c5381ab5a7, []int{33}
 }
 func (m *DNStoreInfo) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -2820,7 +2987,7 @@ func (m *DNState) Reset()         { *m = DNState{} }
 func (m *DNState) String() string { return proto.CompactTextString(m) }
 func (*DNState) ProtoMessage()    {}
 func (*DNState) Descriptor() ([]byte, []int) {
-	return fileDescriptor_fd1040c5381ab5a7, []int{32}
+	return fileDescriptor_fd1040c5381ab5a7, []int{34}
 }
 func (m *DNState) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -2869,7 +3036,7 @@ func (m *ClusterDetails) Reset()         { *m = ClusterDetails{} }
 func (m *ClusterDetails) String() string { return proto.CompactTextString(m) }
 func (*ClusterDetails) ProtoMessage()    {}
 func (*ClusterDetails) Descriptor() ([]byte, []int) {
-	return fileDescriptor_fd1040c5381ab5a7, []int{33}
+	return fileDescriptor_fd1040c5381ab5a7, []int{35}
 }
 func (m *ClusterDetails) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -2934,7 +3101,7 @@ func (m *ClusterInfo) Reset()         { *m = ClusterInfo{} }
 func (m *ClusterInfo) String() string { return proto.CompactTextString(m) }
 func (*ClusterInfo) ProtoMessage()    {}
 func (*ClusterInfo) Descriptor() ([]byte, []int) {
-	return fileDescriptor_fd1040c5381ab5a7, []int{34}
+	return fileDescriptor_fd1040c5381ab5a7, []int{36}
 }
 func (m *ClusterInfo) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -2990,7 +3157,7 @@ func (m *InitialClusterRequest) Reset()         { *m = InitialClusterRequest{} }
 func (m *InitialClusterRequest) String() string { return proto.CompactTextString(m) }
 func (*InitialClusterRequest) ProtoMessage()    {}
 func (*InitialClusterRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_fd1040c5381ab5a7, []int{35}
+	return fileDescriptor_fd1040c5381ab5a7, []int{37}
 }
 func (m *InitialClusterRequest) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -3057,7 +3224,7 @@ func (m *LogStoreInfo) Reset()         { *m = LogStoreInfo{} }
 func (m *LogStoreInfo) String() string { return proto.CompactTextString(m) }
 func (*LogStoreInfo) ProtoMessage()    {}
 func (*LogStoreInfo) Descriptor() ([]byte, []int) {
-	return fileDescriptor_fd1040c5381ab5a7, []int{36}
+	return fileDescriptor_fd1040c5381ab5a7, []int{38}
 }
 func (m *LogStoreInfo) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -3147,7 +3314,7 @@ func (m *LogState) Reset()         { *m = LogState{} }
 func (m *LogState) String() string { return proto.CompactTextString(m) }
 func (*LogState) ProtoMessage()    {}
 func (*LogState) Descriptor() ([]byte, []int) {
-	return fileDescriptor_fd1040c5381ab5a7, []int{37}
+	return fileDescriptor_fd1040c5381ab5a7, []int{39}
 }
 func (m *LogState) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -3211,7 +3378,7 @@ func (m *CheckerState) Reset()         { *m = CheckerState{} }
 func (m *CheckerState) String() string { return proto.CompactTextString(m) }
 func (*CheckerState) ProtoMessage()    {}
 func (*CheckerState) Descriptor() ([]byte, []int) {
-	return fileDescriptor_fd1040c5381ab5a7, []int{38}
+	return fileDescriptor_fd1040c5381ab5a7, []int{40}
 }
 func (m *CheckerState) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -3330,7 +3497,7 @@ func (m *HAKeeperRSMState) Reset()         { *m = HAKeeperRSMState{} }
 func (m *HAKeeperRSMState) String() string { return proto.CompactTextString(m) }
 func (*HAKeeperRSMState) ProtoMessage()    {}
 func (*HAKeeperRSMState) Descriptor() ([]byte, []int) {
-	return fileDescriptor_fd1040c5381ab5a7, []int{39}
+	return fileDescriptor_fd1040c5381ab5a7, []int{41}
 }
 func (m *HAKeeperRSMState) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -3470,7 +3637,7 @@ func (m *ReplicaInfo) Reset()         { *m = ReplicaInfo{} }
 func (m *ReplicaInfo) String() string { return proto.CompactTextString(m) }
 func (*ReplicaInfo) ProtoMessage()    {}
 func (*ReplicaInfo) Descriptor() ([]byte, []int) {
-	return fileDescriptor_fd1040c5381ab5a7, []int{40}
+	return fileDescriptor_fd1040c5381ab5a7, []int{42}
 }
 func (m *ReplicaInfo) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -3529,7 +3696,7 @@ func (m *ShardInfoQueryResult) Reset()         { *m = ShardInfoQueryResult{} }
 func (m *ShardInfoQueryResult) String() string { return proto.CompactTextString(m) }
 func (*ShardInfoQueryResult) ProtoMessage()    {}
 func (*ShardInfoQueryResult) Descriptor() ([]byte, []int) {
-	return fileDescriptor_fd1040c5381ab5a7, []int{41}
+	return fileDescriptor_fd1040c5381ab5a7, []int{43}
 }
 func (m *ShardInfoQueryResult) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -3623,6 +3790,9 @@ func init() {
 	proto.RegisterType((*TsoRequest)(nil), "logservice.TsoRequest")
 	proto.RegisterType((*CNStoreLabel)(nil), "logservice.CNStoreLabel")
 	proto.RegisterMapType((map[string]metadata.LabelList)(nil), "logservice.CNStoreLabel.LabelsEntry")
+	proto.RegisterType((*CNWorkState)(nil), "logservice.CNWorkState")
+	proto.RegisterType((*CNStateLabel)(nil), "logservice.CNStateLabel")
+	proto.RegisterMapType((map[string]metadata.LabelList)(nil), "logservice.CNStateLabel.LabelsEntry")
 	proto.RegisterType((*Request)(nil), "logservice.Request")
 	proto.RegisterType((*LogResponse)(nil), "logservice.LogResponse")
 	proto.RegisterType((*AllocateIDResponse)(nil), "logservice.AllocateIDResponse")
@@ -3665,195 +3835,203 @@ func init() {
 func init() { proto.RegisterFile("logservice.proto", fileDescriptor_fd1040c5381ab5a7) }
 
 var fileDescriptor_fd1040c5381ab5a7 = []byte{
-	// 3002 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x3a, 0xcd, 0x6f, 0x1b, 0xc7,
-	0xf5, 0xda, 0x25, 0xc5, 0x8f, 0x47, 0x49, 0x5e, 0x8d, 0x24, 0x9b, 0x51, 0xf2, 0x93, 0xf5, 0xdb,
-	0xb8, 0x81, 0xc3, 0x34, 0x34, 0x20, 0x21, 0x41, 0xd2, 0x28, 0x36, 0x28, 0x2e, 0x6d, 0x31, 0xa6,
-	0x29, 0x67, 0x48, 0xf5, 0x10, 0x20, 0x50, 0x57, 0xe4, 0x98, 0x62, 0x45, 0x72, 0xd9, 0xdd, 0xa5,
-	0x63, 0xf5, 0xd4, 0x4b, 0x0b, 0x14, 0xed, 0xa5, 0x68, 0x0e, 0x41, 0x51, 0xf4, 0xd0, 0x4b, 0x0f,
-	0xbd, 0xe6, 0xd0, 0x1e, 0x7b, 0x28, 0x90, 0x63, 0xfe, 0x82, 0xa0, 0x0d, 0xd0, 0x53, 0x0f, 0x05,
-	0x7a, 0xe8, 0xb9, 0x98, 0xaf, 0xdd, 0x19, 0x72, 0x29, 0xdb, 0x89, 0x9b, 0x16, 0xc9, 0x89, 0x3b,
-	0xef, 0x6b, 0xdf, 0xbc, 0x79, 0x5f, 0xf3, 0x96, 0x60, 0x0d, 0xbc, 0x5e, 0x40, 0xfc, 0x87, 0xfd,
-	0x0e, 0x29, 0x8f, 0x7d, 0x2f, 0xf4, 0x10, 0xc4, 0x90, 0xcd, 0x57, 0x7b, 0xfd, 0xf0, 0x74, 0x72,
-	0x52, 0xee, 0x78, 0xc3, 0x1b, 0x3d, 0xaf, 0xe7, 0xdd, 0x60, 0x24, 0x27, 0x93, 0x07, 0x6c, 0xc5,
-	0x16, 0xec, 0x89, 0xb3, 0x6e, 0xae, 0x0c, 0x49, 0xe8, 0x76, 0xdd, 0xd0, 0xe5, 0x6b, 0xfb, 0xf7,
-	0x29, 0xc8, 0x56, 0x9b, 0xad, 0xd0, 0xf3, 0x09, 0x42, 0x90, 0x3e, 0x3a, 0xaa, 0x3b, 0x45, 0x63,
-	0xdb, 0xb8, 0x9e, 0xc7, 0xec, 0x19, 0xbd, 0x04, 0x2b, 0x2d, 0xfe, 0xa6, 0x4a, 0xb7, 0xeb, 0x93,
-	0x20, 0x28, 0x9a, 0x0c, 0x3b, 0x05, 0x45, 0x5b, 0x00, 0xad, 0x77, 0x1b, 0x92, 0x26, 0xc5, 0x68,
-	0x14, 0x08, 0x2a, 0x03, 0x6a, 0x78, 0x9d, 0xb3, 0x29, 0x59, 0x69, 0x46, 0x97, 0x80, 0xa1, 0xf2,
-	0xaa, 0xe1, 0x40, 0xd2, 0x2d, 0x72, 0x79, 0x31, 0x04, 0x5d, 0x83, 0x34, 0xf6, 0x06, 0xa4, 0x98,
-	0xd9, 0x36, 0xae, 0xaf, 0xec, 0x58, 0xe5, 0x68, 0x5b, 0xd5, 0x26, 0x85, 0x63, 0x86, 0xa5, 0x3b,
-	0x6a, 0xf7, 0x3b, 0x67, 0xc5, 0xec, 0xb6, 0x71, 0x3d, 0x8d, 0xd9, 0x33, 0x7a, 0x05, 0x16, 0x5b,
-	0xa1, 0x1b, 0x92, 0x62, 0x8e, 0xb1, 0x6e, 0x94, 0x15, 0xf3, 0x36, 0xbd, 0x2e, 0x61, 0x48, 0xcc,
-	0x69, 0xd0, 0xdb, 0x90, 0x69, 0xb8, 0x27, 0x64, 0x10, 0x14, 0xf3, 0xdb, 0xa9, 0xeb, 0x85, 0x9d,
-	0xab, 0x2a, 0xb5, 0xb0, 0x5b, 0x99, 0x53, 0xd4, 0x46, 0xa1, 0x7f, 0xbe, 0x9f, 0xfe, 0xe4, 0xb3,
-	0xab, 0x0b, 0x58, 0x30, 0x6d, 0x36, 0xa1, 0xa0, 0x20, 0x91, 0x05, 0xa9, 0x33, 0x72, 0x2e, 0xec,
-	0x4b, 0x1f, 0xd1, 0xcb, 0xb0, 0xf8, 0xd0, 0x1d, 0x4c, 0x08, 0xb3, 0x6a, 0x61, 0x67, 0x2d, 0xde,
-	0x07, 0xe3, 0x6b, 0xf4, 0x83, 0x10, 0x73, 0x8a, 0xef, 0x98, 0x6f, 0x18, 0xf6, 0x9f, 0x4c, 0xc8,
-	0x3a, 0xcf, 0xe0, 0xb4, 0xa4, 0x5d, 0x52, 0x49, 0x76, 0x49, 0x3f, 0x81, 0x5d, 0x5e, 0x83, 0x4c,
-	0xeb, 0xd4, 0xf5, 0xbb, 0xf4, 0x68, 0xa8, 0x5d, 0xae, 0xa8, 0xd4, 0x4e, 0x93, 0xe1, 0xea, 0xa3,
-	0x07, 0x9e, 0xb4, 0x07, 0x27, 0x46, 0x3b, 0xb0, 0xde, 0xf0, 0x7a, 0xa1, 0xdb, 0x1f, 0x50, 0x85,
-	0x88, 0x2f, 0xb5, 0xcc, 0x30, 0x2d, 0x13, 0x71, 0x73, 0x3c, 0x27, 0xfb, 0x84, 0x9e, 0x93, 0x9b,
-	0xf6, 0x1c, 0xfb, 0xcf, 0x06, 0xe4, 0x1a, 0x5e, 0xef, 0x7f, 0xc0, 0x88, 0x7b, 0x90, 0xc3, 0x64,
-	0x3c, 0xe8, 0x77, 0x5c, 0x69, 0xc6, 0x4d, 0x95, 0xbe, 0xe1, 0xf5, 0x04, 0x5a, 0xb1, 0x64, 0xc4,
-	0x61, 0xff, 0xc3, 0x80, 0x25, 0xba, 0x0f, 0x69, 0x6a, 0x54, 0x84, 0x2c, 0x5f, 0xf0, 0xed, 0xa4,
-	0xb1, 0x5c, 0xa2, 0x7d, 0xe5, 0x45, 0x26, 0x7b, 0xd1, 0x4b, 0x53, 0x2f, 0x8a, 0xa4, 0x94, 0x25,
-	0x21, 0xf3, 0xd8, 0xf8, 0x75, 0x68, 0x1d, 0x16, 0x6b, 0x63, 0xaf, 0x73, 0x2a, 0xb6, 0xcb, 0x17,
-	0x68, 0x13, 0x72, 0x0d, 0xe2, 0x76, 0x89, 0x5f, 0x77, 0xd8, 0x96, 0xd3, 0x38, 0x5a, 0x33, 0xfb,
-	0x10, 0x7f, 0xc8, 0x82, 0x97, 0xda, 0x87, 0xf8, 0xc3, 0xcd, 0xb7, 0x60, 0x59, 0x7b, 0x81, 0x1a,
-	0x12, 0x69, 0x1e, 0x12, 0xeb, 0x6a, 0x48, 0xe4, 0x55, 0xef, 0x7f, 0x08, 0x2b, 0xba, 0x4d, 0xd0,
-	0x6d, 0xdd, 0x04, 0x4c, 0x4c, 0x61, 0xa7, 0x38, 0x6f, 0x73, 0xfb, 0x39, 0x6a, 0xc3, 0x4f, 0x3f,
-	0xbb, 0x6a, 0x60, 0xdd, 0x74, 0x2f, 0x40, 0x5e, 0x8a, 0x75, 0xd8, 0x7b, 0xd3, 0x38, 0x06, 0xd8,
-	0x1f, 0x9a, 0x60, 0x89, 0x58, 0x3f, 0x20, 0xae, 0x1f, 0x9e, 0x10, 0x37, 0xfc, 0x1a, 0x26, 0xcb,
-	0x32, 0xa0, 0xb6, 0x1b, 0x48, 0xd9, 0x55, 0x9f, 0xb8, 0x21, 0xe9, 0xb2, 0x40, 0xcb, 0xe1, 0x04,
-	0x8c, 0xfd, 0x3a, 0x2c, 0x55, 0x9b, 0x95, 0xc1, 0xc0, 0xeb, 0xb8, 0x21, 0xa9, 0x3b, 0x09, 0xd9,
-	0x6d, 0x1d, 0x16, 0xf7, 0xdd, 0xb0, 0x73, 0x2a, 0x4c, 0xca, 0x17, 0xf6, 0x8f, 0x4d, 0x58, 0x95,
-	0x01, 0x78, 0xb1, 0x3d, 0xb7, 0xa1, 0x80, 0xdd, 0x07, 0xa1, 0x6e, 0x4c, 0x15, 0x94, 0x60, 0xf1,
-	0x54, 0xa2, 0xc5, 0xaf, 0xc1, 0xf2, 0x1d, 0x2f, 0x08, 0xfa, 0x63, 0xdd, 0x98, 0x3a, 0xf0, 0xcb,
-	0x05, 0xe4, 0x1c, 0xfb, 0x65, 0xe6, 0xda, 0xaf, 0x06, 0x05, 0x25, 0x53, 0x5e, 0x10, 0xbe, 0x17,
-	0x7b, 0xe7, 0x1f, 0x4d, 0xb0, 0x9c, 0x67, 0xe9, 0x9d, 0x71, 0x6e, 0x4f, 0x3d, 0x4d, 0x6e, 0x4f,
-	0xde, 0x7e, 0x7a, 0xde, 0xf6, 0xe7, 0xd6, 0x82, 0xc5, 0xa7, 0xae, 0x05, 0x99, 0x27, 0x0c, 0x8c,
-	0xec, 0x4c, 0x2d, 0xf8, 0xa9, 0x09, 0x39, 0xdc, 0xba, 0xc7, 0xd3, 0xb1, 0x05, 0xa9, 0x76, 0xe0,
-	0xc9, 0x54, 0xd4, 0x0e, 0x3c, 0xea, 0xbf, 0xf5, 0x51, 0x97, 0x3c, 0x92, 0xfe, 0xcb, 0x16, 0xd4,
-	0x97, 0x1a, 0xc4, 0x0d, 0xc8, 0x81, 0x37, 0xe0, 0x89, 0x8f, 0x67, 0x44, 0x1d, 0x88, 0x6c, 0x58,
-	0x6a, 0xfb, 0x93, 0x11, 0x8d, 0x8d, 0x6e, 0x23, 0x18, 0x89, 0xec, 0xa8, 0xc1, 0xd0, 0x3b, 0xb0,
-	0xc4, 0x99, 0xfa, 0x41, 0xe8, 0xf9, 0xe7, 0xc2, 0xe7, 0xb4, 0xdc, 0x2c, 0xb5, 0x2b, 0xab, 0x84,
-	0x3c, 0x37, 0x6b, 0xbc, 0x9b, 0xb7, 0x60, 0x75, 0x86, 0xe4, 0x71, 0xd9, 0x35, 0xad, 0x66, 0xd7,
-	0xf7, 0x21, 0xcf, 0x1c, 0xbc, 0xe3, 0xf9, 0x5d, 0xca, 0x48, 0x95, 0x16, 0x8c, 0x54, 0xd7, 0x12,
-	0xa4, 0xdb, 0xe7, 0x63, 0xce, 0xb7, 0xb2, 0x73, 0x59, 0xd3, 0x91, 0xf1, 0x50, 0x2c, 0x66, 0x34,
-	0xd4, 0xfb, 0x1c, 0x37, 0x74, 0x99, 0x61, 0x96, 0x30, 0x7b, 0xb6, 0x3f, 0x32, 0x00, 0x98, 0xfc,
-	0x1f, 0x4c, 0x48, 0xc0, 0x1c, 0xb4, 0xe9, 0x0e, 0x89, 0x74, 0x50, 0xfa, 0xac, 0x46, 0x80, 0xa9,
-	0x47, 0x80, 0x50, 0x27, 0x15, 0xab, 0x53, 0x84, 0xec, 0x3d, 0xf7, 0x51, 0xab, 0xff, 0x43, 0x22,
-	0x2c, 0x2b, 0x97, 0x34, 0x5a, 0xa4, 0x93, 0x3a, 0xa2, 0xf6, 0xc4, 0x00, 0xa6, 0x5a, 0xb3, 0xee,
-	0x30, 0x9f, 0x49, 0x63, 0xf6, 0x6c, 0xdb, 0x00, 0xed, 0xc0, 0x93, 0x9a, 0xad, 0xc3, 0x62, 0xd5,
-	0x9b, 0x8c, 0x42, 0xb1, 0x79, 0xbe, 0xb0, 0xff, 0x6e, 0xd0, 0x6c, 0xc7, 0xa2, 0x8c, 0x75, 0x66,
-	0x89, 0x11, 0xb6, 0x0b, 0xf9, 0xc3, 0x31, 0xf1, 0xdd, 0xb0, 0xef, 0x8d, 0x84, 0xa1, 0x36, 0xf4,
-	0x86, 0x91, 0xf1, 0x1e, 0x8e, 0x71, 0x4c, 0x87, 0xf6, 0xa3, 0x16, 0x93, 0x87, 0xdb, 0xb5, 0x84,
-	0x16, 0x93, 0x11, 0x7c, 0x85, 0x7d, 0xe6, 0xcf, 0xd3, 0x90, 0x95, 0xf6, 0x60, 0xd9, 0x87, 0x3d,
-	0x46, 0x99, 0x29, 0x06, 0xa0, 0x32, 0x64, 0xee, 0x91, 0xf0, 0xd4, 0xeb, 0x26, 0x39, 0x06, 0xc7,
-	0x30, 0xc7, 0x10, 0x54, 0x68, 0x4f, 0xf5, 0x02, 0x76, 0xa0, 0x05, 0x9d, 0x27, 0xc6, 0x8a, 0x3d,
-	0xaa, 0x5e, 0x53, 0x61, 0xf5, 0x3e, 0x4a, 0x73, 0xec, 0xe8, 0x0b, 0x3b, 0xff, 0x37, 0x5d, 0xef,
-	0xb5, 0x5c, 0x88, 0x35, 0x16, 0x74, 0x13, 0x0a, 0xd5, 0x66, 0x2c, 0x61, 0x91, 0x49, 0x78, 0x21,
-	0xc1, 0xe6, 0xb1, 0x00, 0x95, 0x81, 0xf2, 0x3b, 0x0a, 0x7f, 0x66, 0x96, 0xdf, 0x99, 0xe1, 0x57,
-	0x18, 0xd0, 0xeb, 0xaa, 0xb3, 0xb1, 0x94, 0x34, 0x65, 0x80, 0x18, 0x8b, 0x55, 0xb7, 0xdc, 0xd3,
-	0xab, 0x2d, 0x6b, 0x6c, 0xa7, 0x5a, 0x1d, 0x15, 0x8f, 0xf5, 0xda, 0xbc, 0xa7, 0x7b, 0x6f, 0x31,
-	0x9f, 0xc4, 0x1d, 0xe3, 0xb1, 0x46, 0x6d, 0xb7, 0xa0, 0xc0, 0x0e, 0x21, 0x18, 0x7b, 0xa3, 0x80,
-	0x5c, 0x50, 0xa9, 0x44, 0x9c, 0x9a, 0x5a, 0x9c, 0x36, 0xdc, 0x20, 0x8c, 0xa3, 0x57, 0x2e, 0xed,
-	0x32, 0x20, 0x45, 0x5d, 0x45, 0xf6, 0xed, 0xbe, 0xaf, 0xf8, 0x9a, 0x5c, 0xda, 0xff, 0x4a, 0xd3,
-	0xea, 0x2c, 0xc8, 0x9e, 0xad, 0x53, 0xbe, 0x00, 0xf9, 0x9a, 0xef, 0x7b, 0x7e, 0xd5, 0xeb, 0x12,
-	0xa6, 0xe6, 0x32, 0x8e, 0x01, 0x34, 0x93, 0xb3, 0xc5, 0x3d, 0x12, 0x04, 0x6e, 0x8f, 0x88, 0xd6,
-	0x41, 0x83, 0xd1, 0x42, 0x53, 0x0f, 0x0e, 0x2a, 0x77, 0x09, 0x19, 0x13, 0x9f, 0x39, 0x55, 0x0e,
-	0x2b, 0x10, 0x74, 0x4b, 0xb3, 0xa0, 0xf0, 0x9a, 0x2b, 0x33, 0x7e, 0xcf, 0xd1, 0xc2, 0xf1, 0x35,
-	0x9b, 0xd3, 0x03, 0xf4, 0x86, 0x43, 0x77, 0xd4, 0xe5, 0x1d, 0x55, 0x36, 0xe1, 0x00, 0x15, 0x3c,
-	0xd6, 0xa8, 0xd1, 0x9b, 0x50, 0x60, 0xae, 0x24, 0x5e, 0x9f, 0x9b, 0x7d, 0xbd, 0x82, 0xc6, 0x2a,
-	0x2d, 0xda, 0x87, 0x95, 0xea, 0x60, 0x12, 0x84, 0xc4, 0x77, 0x08, 0x2d, 0xc8, 0x81, 0xf0, 0x1d,
-	0xad, 0x33, 0xd2, 0x29, 0xf0, 0x14, 0x07, 0xba, 0x09, 0xf9, 0xb8, 0x47, 0x07, 0xc6, 0xbe, 0xad,
-	0xb2, 0x47, 0xc8, 0x77, 0x27, 0xc4, 0x3f, 0xc7, 0x24, 0x98, 0x0c, 0x42, 0x1c, 0xb3, 0xa0, 0x9b,
-	0x00, 0x8a, 0xe7, 0x17, 0x98, 0x80, 0x2d, 0x55, 0xc0, 0xac, 0x23, 0x61, 0x98, 0xf2, 0xfe, 0x53,
-	0xd2, 0x39, 0x23, 0x3e, 0xbf, 0x9c, 0x2d, 0x25, 0x18, 0x4f, 0xc1, 0x63, 0x8d, 0xda, 0x7e, 0x87,
-	0xb5, 0xab, 0xbc, 0xc8, 0x45, 0x66, 0x79, 0x8d, 0x26, 0x48, 0x0a, 0x09, 0x8a, 0x06, 0x4b, 0xdb,
-	0x1b, 0x33, 0x87, 0x49, 0xb1, 0xe2, 0x28, 0x25, 0xad, 0xfd, 0xa2, 0x76, 0x10, 0xb4, 0xd6, 0x7c,
-	0x97, 0xa5, 0x65, 0x51, 0x6b, 0xd8, 0xc2, 0xbe, 0x03, 0xcb, 0xb4, 0x5f, 0x6a, 0xbb, 0x27, 0x03,
-	0x72, 0x14, 0x10, 0x9f, 0xde, 0xb2, 0xe8, 0xef, 0x28, 0x2e, 0x98, 0xd1, 0x9a, 0xe2, 0xee, 0xbb,
-	0x41, 0xf0, 0x81, 0xe7, 0x77, 0x45, 0x3f, 0x17, 0xad, 0xed, 0x9f, 0x19, 0x54, 0x4b, 0xd6, 0x28,
-	0x26, 0xd6, 0xab, 0xf9, 0x05, 0x57, 0x6b, 0x39, 0x53, 0x53, 0x2d, 0x67, 0x7c, 0x17, 0x4c, 0xab,
-	0x77, 0xc1, 0x2d, 0x96, 0xda, 0xf5, 0xca, 0xab, 0x40, 0xec, 0x5f, 0x99, 0xd4, 0x87, 0x47, 0x0f,
-	0xfa, 0xbd, 0xea, 0xa9, 0x3b, 0xea, 0x11, 0xb4, 0x1b, 0x69, 0x27, 0x2e, 0x6e, 0x6b, 0x7a, 0x57,
-	0xc1, 0x50, 0xb1, 0x05, 0xf9, 0x3e, 0xf6, 0x00, 0x38, 0xbb, 0xd2, 0x8d, 0xe8, 0xe9, 0x5b, 0x79,
-	0x05, 0x8b, 0x72, 0x85, 0x1e, 0xb5, 0x61, 0xa5, 0x3e, 0xea, 0x87, 0x7d, 0x77, 0x70, 0x8f, 0x0c,
-	0x4f, 0x88, 0x2f, 0x8b, 0xee, 0xb7, 0xe7, 0x49, 0x28, 0xeb, 0xe4, 0xbc, 0xf3, 0x9a, 0x92, 0xb1,
-	0x59, 0x81, 0xb5, 0x04, 0xb2, 0xa7, 0xba, 0xdb, 0xbe, 0x0c, 0xcb, 0xad, 0xd3, 0x49, 0xd8, 0xf5,
-	0x3e, 0x18, 0xf1, 0xc9, 0x04, 0x3d, 0x1b, 0xfa, 0x10, 0x1d, 0x99, 0x5c, 0xda, 0xbf, 0x4c, 0xc1,
-	0xa5, 0x56, 0xe7, 0x94, 0x74, 0x27, 0x03, 0x22, 0xa2, 0x3c, 0xf1, 0x74, 0xaf, 0xc1, 0xf2, 0xbe,
-	0xe7, 0x85, 0x41, 0xe8, 0xbb, 0xe3, 0x71, 0x7f, 0xd4, 0x63, 0x2f, 0xcd, 0x61, 0x1d, 0x48, 0x53,
-	0x83, 0x68, 0x9a, 0x99, 0x41, 0x53, 0xcc, 0xa0, 0x5a, 0x6a, 0x50, 0xd0, 0x58, 0xa5, 0xe5, 0x39,
-	0x29, 0x36, 0x95, 0xa8, 0xc6, 0xc5, 0x79, 0xa6, 0xc4, 0xfa, 0xe9, 0xdf, 0x9a, 0xda, 0xb1, 0x28,
-	0xc5, 0xcf, 0xe9, 0x89, 0x41, 0x21, 0xc0, 0x53, 0x16, 0xba, 0x0b, 0xab, 0xfc, 0x2e, 0xa1, 0x5c,
-	0x2e, 0x44, 0x66, 0xd5, 0x3a, 0x82, 0x19, 0x22, 0x3c, 0xcb, 0x47, 0xb5, 0x71, 0xc8, 0x80, 0x84,
-	0x44, 0x14, 0x3e, 0x91, 0x60, 0x35, 0x6d, 0x34, 0x02, 0xac, 0xd3, 0xdb, 0x83, 0x04, 0x6d, 0xd0,
-	0x2e, 0xa4, 0x69, 0xa0, 0x0a, 0xf7, 0xd6, 0x84, 0x69, 0x11, 0x2e, 0x9c, 0x9c, 0x11, 0xb3, 0x9b,
-	0x83, 0x1b, 0x9c, 0xd1, 0xae, 0xf9, 0xc4, 0x0d, 0xa4, 0xaf, 0x68, 0x30, 0xea, 0x2e, 0xda, 0xeb,
-	0x2f, 0x70, 0x17, 0x57, 0xaf, 0x1c, 0xd1, 0x58, 0xc6, 0x88, 0xc7, 0x32, 0xe8, 0x6d, 0xc8, 0x09,
-	0x1a, 0x39, 0x20, 0x7a, 0x5e, 0x3b, 0x06, 0xdd, 0xdb, 0xe4, 0xcd, 0x57, 0xb2, 0xd8, 0xbf, 0x4d,
-	0xd1, 0xa6, 0x8a, 0xbf, 0x90, 0xe6, 0x6b, 0x39, 0x19, 0x33, 0x94, 0xc9, 0xd8, 0x37, 0x6a, 0x36,
-	0x82, 0x2a, 0x51, 0x53, 0x9f, 0x63, 0xe6, 0x7c, 0x31, 0xa1, 0xd3, 0x62, 0xe3, 0xb6, 0xaf, 0xae,
-	0xa7, 0xff, 0xb5, 0xc1, 0x27, 0xfd, 0x62, 0xac, 0xcd, 0x54, 0x90, 0xc5, 0x6b, 0x66, 0xac, 0x4d,
-	0x6f, 0x9c, 0x9c, 0x42, 0x53, 0x8d, 0x83, 0x36, 0x31, 0x14, 0x14, 0x64, 0x82, 0x6a, 0xaf, 0xea,
-	0xaa, 0x5d, 0x99, 0xb3, 0x7b, 0x55, 0xbd, 0x8f, 0x4d, 0x36, 0x0e, 0x79, 0x26, 0x3e, 0xf4, 0x0d,
-	0x9a, 0x60, 0xd0, 0x53, 0x75, 0x9e, 0xe4, 0x54, 0x9d, 0xff, 0xec, 0xa9, 0x3a, 0xc9, 0xa7, 0xfa,
-	0x07, 0x63, 0xba, 0x7d, 0x44, 0xaf, 0x41, 0x4e, 0x10, 0x4b, 0x3d, 0xd7, 0x12, 0x04, 0xc9, 0x1c,
-	0x23, 0x49, 0x29, 0x5b, 0x55, 0xb2, 0x99, 0xb3, 0x6c, 0x55, 0x9d, 0x4d, 0x92, 0xa2, 0x37, 0xd8,
-	0x54, 0x43, 0xf0, 0x71, 0x6f, 0x58, 0x4f, 0xba, 0x2e, 0x0a, 0xc6, 0x98, 0xd8, 0xfe, 0x89, 0x01,
-	0x05, 0xa1, 0x3a, 0x73, 0xc8, 0x37, 0x99, 0xde, 0xdc, 0xad, 0x0c, 0xe1, 0x56, 0x51, 0xc4, 0x09,
-	0x8c, 0xd6, 0xf4, 0x45, 0xe4, 0x68, 0x8f, 0x2b, 0xc1, 0x79, 0xb9, 0xf2, 0x45, 0x25, 0x5a, 0x05,
-	0x4a, 0x63, 0x8e, 0x19, 0xec, 0x5f, 0x18, 0xb0, 0x21, 0xda, 0x0b, 0xa1, 0x8f, 0xbc, 0x13, 0xbe,
-	0x04, 0x2b, 0xcd, 0xc9, 0xf0, 0xf0, 0x41, 0x2c, 0x9c, 0x47, 0xcb, 0x14, 0x94, 0x76, 0x02, 0x0c,
-	0x12, 0xe9, 0xcf, 0xbb, 0x3d, 0x1d, 0x88, 0x4a, 0x60, 0x49, 0xbe, 0x68, 0x0a, 0xca, 0x5b, 0xbf,
-	0x19, 0xb8, 0xfd, 0x23, 0x93, 0x4f, 0xde, 0x2f, 0x0c, 0xd7, 0xaf, 0xf7, 0xf8, 0xf6, 0x63, 0x53,
-	0x7c, 0x47, 0xa2, 0xa1, 0x77, 0x33, 0xca, 0x38, 0xdc, 0x35, 0xb6, 0x67, 0x7c, 0x8c, 0xc5, 0x1e,
-	0x23, 0xd1, 0x63, 0x8f, 0xdb, 0xfe, 0x66, 0x14, 0xba, 0xe6, 0x45, 0xfc, 0x73, 0x63, 0xb7, 0x05,
-	0x05, 0x45, 0x78, 0x42, 0xe7, 0x59, 0xd6, 0x63, 0x77, 0xee, 0x27, 0x12, 0x25, 0x78, 0x99, 0xd0,
-	0x0b, 0x13, 0xc2, 0xe3, 0x84, 0x26, 0x65, 0x84, 0xbf, 0xa5, 0xf4, 0xcb, 0x58, 0xa2, 0xe7, 0xdc,
-	0xd2, 0x42, 0x2f, 0xb1, 0x8a, 0xc4, 0x68, 0x79, 0x5d, 0x56, 0x83, 0x75, 0x37, 0xca, 0x8a, 0x62,
-	0xc6, 0xb4, 0x96, 0x90, 0x0b, 0xe5, 0xd5, 0x42, 0xe6, 0xcf, 0xd7, 0xe3, 0x03, 0x15, 0xbd, 0xec,
-	0x7a, 0xd2, 0x31, 0x48, 0xcf, 0x89, 0x0e, 0x7f, 0x37, 0x2a, 0xac, 0xa2, 0x87, 0x5d, 0x4b, 0x28,
-	0xa7, 0xf2, 0x65, 0xb2, 0x04, 0xdf, 0x90, 0x5f, 0x0a, 0x79, 0xe3, 0xa1, 0xf5, 0x86, 0x72, 0x6c,
-	0xa0, 0x7d, 0x2d, 0x6c, 0x0a, 0xff, 0x14, 0xbd, 0x98, 0xb8, 0xca, 0x66, 0x19, 0xf7, 0xd6, 0x74,
-	0x67, 0xa9, 0x53, 0xe1, 0x04, 0x4e, 0x54, 0x9b, 0xba, 0x65, 0x8a, 0xa9, 0xc0, 0x63, 0x9b, 0xd4,
-	0xa9, 0xbb, 0xe9, 0x65, 0xc8, 0x34, 0xc9, 0xa3, 0xb0, 0xde, 0x65, 0x73, 0x81, 0x34, 0x16, 0x2b,
-	0xfb, 0x9f, 0x59, 0xb0, 0xe4, 0x3e, 0xa2, 0x11, 0x7b, 0x34, 0x50, 0x37, 0xd4, 0x81, 0xba, 0xf4,
-	0x00, 0x53, 0xf1, 0x00, 0x29, 0x56, 0xde, 0x3e, 0xc5, 0x0a, 0x1d, 0x42, 0x81, 0x3f, 0xed, 0x9f,
-	0xdf, 0x25, 0xe7, 0xc5, 0x34, 0x8b, 0x96, 0x57, 0x93, 0x8c, 0x17, 0x4d, 0xce, 0x15, 0x7a, 0x7e,
-	0x7d, 0x53, 0x25, 0x24, 0x7d, 0xa5, 0xfc, 0xef, 0x9f, 0x4d, 0x17, 0xac, 0xa9, 0x9e, 0x5b, 0x36,
-	0x92, 0x3b, 0x17, 0x6e, 0x75, 0x9a, 0x49, 0x4d, 0x15, 0x33, 0x12, 0x51, 0x5d, 0x2d, 0x4b, 0xfc,
-	0xff, 0x0d, 0xaf, 0x5c, 0x28, 0x3e, 0xa2, 0xe6, 0x76, 0x8c, 0xb9, 0xd5, 0x10, 0x80, 0x27, 0x0e,
-	0x01, 0x25, 0x48, 0x0b, 0x5f, 0x28, 0x48, 0x97, 0x9e, 0x22, 0x48, 0xa7, 0x52, 0xca, 0xf2, 0x53,
-	0xa7, 0x94, 0x99, 0x78, 0x59, 0xf9, 0x22, 0xf1, 0xb2, 0x79, 0x13, 0xac, 0x69, 0x87, 0x4c, 0xfe,
-	0x72, 0x9a, 0xfc, 0x99, 0x66, 0xf3, 0x7d, 0xd8, 0x48, 0x3c, 0xe5, 0xa7, 0x4c, 0xcf, 0xda, 0xb0,
-	0x50, 0x11, 0xbf, 0xc7, 0xbe, 0xb1, 0xcf, 0xa9, 0x25, 0x8f, 0x53, 0xce, 0xae, 0x43, 0x41, 0xfd,
-	0x3c, 0xff, 0x25, 0xbe, 0x42, 0xda, 0xbf, 0x31, 0x61, 0x3d, 0x69, 0x2e, 0x78, 0xc1, 0xf4, 0xf9,
-	0xfe, 0xcc, 0xdf, 0x1c, 0xca, 0x8f, 0x9b, 0x32, 0xea, 0x7f, 0x77, 0x98, 0xe9, 0x09, 0x9e, 0xcd,
-	0x9f, 0x1e, 0xda, 0x8f, 0xff, 0xd3, 0xc3, 0x45, 0xad, 0xb5, 0x62, 0x51, 0xc5, 0xd6, 0xa5, 0xef,
-	0x01, 0x1c, 0x8d, 0xbb, 0x6e, 0xc8, 0x67, 0x31, 0x57, 0x60, 0x4d, 0xfb, 0xfe, 0xc8, 0x51, 0xd6,
-	0x02, 0xda, 0x80, 0x55, 0xf9, 0xcd, 0xb1, 0xd1, 0x6a, 0x0a, 0xb0, 0x81, 0xd6, 0xe0, 0x12, 0x75,
-	0x47, 0xa6, 0x8f, 0x00, 0x9a, 0x68, 0x19, 0xf2, 0xed, 0xd6, 0xa1, 0x58, 0xa6, 0x4a, 0x65, 0xc8,
-	0x47, 0xff, 0x59, 0x41, 0x97, 0xa0, 0xd0, 0xf4, 0xfc, 0xa1, 0x3b, 0x60, 0x4b, 0x6b, 0x01, 0x59,
-	0xb0, 0xd4, 0xee, 0x0f, 0x89, 0x37, 0x09, 0x39, 0xc4, 0x28, 0xfd, 0xce, 0x04, 0x88, 0xa7, 0xeb,
-	0x68, 0x05, 0xa0, 0xdd, 0x3a, 0x3c, 0x3e, 0xba, 0xef, 0x54, 0xda, 0x35, 0x6b, 0x01, 0x01, 0x64,
-	0x2a, 0xf7, 0xef, 0xd7, 0x9a, 0x8e, 0x65, 0xa0, 0x1c, 0xa4, 0x71, 0xad, 0xe2, 0x58, 0x26, 0x5a,
-	0x82, 0x5c, 0x1b, 0x1f, 0x35, 0xab, 0x94, 0x26, 0x45, 0x85, 0xde, 0xa9, 0xb5, 0x8f, 0x23, 0x48,
-	0x1a, 0x15, 0x20, 0x5b, 0x3d, 0x6c, 0x36, 0x6b, 0xd5, 0xb6, 0xb5, 0x48, 0x45, 0x8a, 0xc5, 0x31,
-	0x3e, 0xb4, 0x32, 0x68, 0x15, 0x96, 0x1b, 0x87, 0x77, 0x8e, 0x0f, 0x6a, 0x15, 0xdc, 0xde, 0xaf,
-	0x55, 0xda, 0x56, 0x96, 0x4a, 0xa8, 0x36, 0x15, 0x48, 0x8e, 0x42, 0x1c, 0x15, 0x92, 0x47, 0x08,
-	0x56, 0xaa, 0x07, 0xb5, 0xea, 0xdd, 0xe3, 0x83, 0xca, 0xdd, 0x5a, 0xed, 0x7e, 0x0d, 0x5b, 0x40,
-	0x0d, 0x48, 0xdf, 0x5c, 0x6d, 0x1c, 0xb5, 0xda, 0x35, 0x7c, 0xec, 0xd4, 0xda, 0x95, 0x7a, 0xa3,
-	0x65, 0x15, 0x28, 0x31, 0x45, 0xb4, 0x0e, 0x2a, 0xd8, 0x39, 0xae, 0x37, 0x6f, 0x1f, 0x5a, 0x4b,
-	0x4c, 0x40, 0xf3, 0xb8, 0xd2, 0x68, 0x1c, 0x52, 0x2d, 0x8f, 0xeb, 0x8e, 0xb5, 0x4c, 0x0d, 0xad,
-	0x0a, 0x68, 0xb5, 0xa9, 0xfe, 0x2b, 0xcc, 0xd0, 0xcc, 0x02, 0xc7, 0xd5, 0xe6, 0x71, 0xa3, 0xb2,
-	0x5f, 0x6b, 0x58, 0x97, 0x4a, 0x4d, 0x80, 0xf8, 0xa3, 0x29, 0xdd, 0x15, 0x3d, 0x0b, 0x0e, 0xb1,
-	0x16, 0xa8, 0x49, 0xea, 0xa3, 0x90, 0xf8, 0x23, 0x77, 0x60, 0x19, 0xd4, 0xf0, 0xec, 0x64, 0xa3,
-	0x53, 0x5a, 0x15, 0xdf, 0x9f, 0x31, 0xf9, 0x3e, 0xe9, 0x84, 0xa4, 0x6b, 0xa5, 0x4a, 0x25, 0xc8,
-	0x47, 0xdf, 0x16, 0x29, 0x7b, 0x8b, 0x84, 0x6c, 0x65, 0x2d, 0x50, 0x76, 0x3e, 0x29, 0xe2, 0x00,
-	0xa3, 0xf4, 0xa1, 0x09, 0x48, 0x66, 0x76, 0xc5, 0x81, 0xe8, 0x69, 0xf5, 0x3b, 0x67, 0xaa, 0xdf,
-	0x28, 0x9f, 0xbd, 0x22, 0xbf, 0xd9, 0x80, 0x55, 0x67, 0x06, 0x6c, 0xa2, 0xcb, 0xf4, 0x5a, 0xdb,
-	0x9b, 0x86, 0xa7, 0xe8, 0xdb, 0xef, 0x90, 0x30, 0x72, 0xc7, 0x34, 0x7a, 0x6e, 0x26, 0x7d, 0x09,
-	0xd4, 0x22, 0x35, 0x6a, 0x8b, 0x70, 0x67, 0x12, 0xb0, 0x0c, 0x2a, 0xc2, 0xba, 0x7e, 0xf5, 0x11,
-	0x98, 0x2c, 0xba, 0x0a, 0xcf, 0xb7, 0x48, 0x38, 0x5b, 0x3b, 0x05, 0x41, 0x0e, 0x6d, 0xc2, 0x65,
-	0x41, 0x10, 0x25, 0x5f, 0x81, 0xcb, 0x53, 0x13, 0xf2, 0x67, 0x61, 0x35, 0x0b, 0x4a, 0x1f, 0x19,
-	0xb0, 0xac, 0xd5, 0x76, 0x7a, 0x72, 0x12, 0x20, 0x7a, 0x7e, 0x6b, 0x81, 0xea, 0x2f, 0x81, 0xda,
-	0x1c, 0xd5, 0x32, 0xd0, 0xb7, 0xe0, 0xff, 0x67, 0x50, 0x32, 0x45, 0x63, 0xd2, 0x21, 0xfd, 0x87,
-	0xa4, 0x6b, 0x99, 0xe8, 0x79, 0xb8, 0x32, 0x43, 0x76, 0xdb, 0xed, 0x0f, 0xe8, 0x41, 0xaa, 0xef,
-	0xc4, 0x93, 0xd1, 0x88, 0x0a, 0x4e, 0x97, 0x4e, 0x92, 0xba, 0x0b, 0x6a, 0x1a, 0x0d, 0x1a, 0xeb,
-	0x38, 0x8d, 0x91, 0x92, 0x8c, 0x19, 0x4c, 0x2b, 0xf4, 0xc6, 0x63, 0xaa, 0x55, 0xe9, 0x14, 0xac,
-	0xe9, 0xc1, 0x39, 0x75, 0x89, 0x4a, 0xb7, 0x2b, 0xd2, 0x8f, 0xb5, 0x40, 0xad, 0x86, 0xc9, 0xd0,
-	0x7b, 0x48, 0x24, 0xc8, 0xa0, 0xb1, 0xd5, 0x0a, 0x5d, 0x3f, 0x94, 0x10, 0x93, 0x9e, 0x38, 0x95,
-	0x2a, 0x01, 0x29, 0x2a, 0xe5, 0x6e, 0x7f, 0x30, 0x78, 0xcf, 0x1b, 0x9e, 0xf4, 0x89, 0x95, 0x2e,
-	0xbd, 0xa5, 0x0d, 0x9c, 0x29, 0x9a, 0x16, 0x1c, 0x0e, 0xb1, 0x16, 0x68, 0x0e, 0x72, 0x9a, 0x72,
-	0x69, 0xd0, 0x65, 0x35, 0x5a, 0x9a, 0xfb, 0xb5, 0x4f, 0xff, 0xba, 0xb5, 0xf0, 0xc9, 0xe7, 0x5b,
-	0xc6, 0xa7, 0x9f, 0x6f, 0x19, 0x7f, 0xf9, 0x7c, 0xcb, 0x78, 0x6f, 0x57, 0xf9, 0xff, 0xeb, 0xd0,
-	0x0d, 0xfd, 0xfe, 0x23, 0xcf, 0xef, 0xf7, 0xfa, 0x23, 0xb9, 0x18, 0x91, 0x1b, 0xe3, 0xb3, 0xde,
-	0x8d, 0xf1, 0xc9, 0x8d, 0x38, 0xa5, 0x9e, 0x64, 0xd8, 0x9f, 0x5f, 0x77, 0xff, 0x1d, 0x00, 0x00,
-	0xff, 0xff, 0x94, 0x36, 0x4a, 0x8d, 0x5b, 0x2b, 0x00, 0x00,
+	// 3131 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x1a, 0x4d, 0x6f, 0x1b, 0xc7,
+	0x55, 0xbb, 0xa4, 0x44, 0xf2, 0x51, 0x92, 0x57, 0x23, 0xd9, 0x66, 0x94, 0x54, 0x56, 0x37, 0x6e,
+	0xe0, 0x28, 0x0d, 0x8d, 0x4a, 0x48, 0x90, 0x34, 0x8a, 0x0d, 0x8a, 0x4b, 0x5b, 0x8c, 0x68, 0x4a,
+	0x19, 0x52, 0x0d, 0x10, 0x20, 0x50, 0x57, 0xe4, 0x98, 0x62, 0x45, 0x72, 0xd9, 0xdd, 0xa5, 0x63,
+	0xf5, 0xd4, 0x4b, 0x0a, 0x14, 0x3d, 0x15, 0xed, 0x21, 0x28, 0x8a, 0xfe, 0x8a, 0x1c, 0xda, 0x43,
+	0x0f, 0x3d, 0x14, 0xc8, 0x31, 0x97, 0x5c, 0x83, 0x26, 0x40, 0x4f, 0x3d, 0x14, 0xe8, 0xa1, 0xe7,
+	0x62, 0xbe, 0x76, 0x67, 0xc8, 0xa5, 0x24, 0x27, 0x6e, 0x5a, 0x24, 0x27, 0xee, 0xbc, 0xaf, 0x79,
+	0xf3, 0xe6, 0xbd, 0x37, 0x6f, 0xde, 0x10, 0xac, 0x9e, 0xd7, 0x09, 0x88, 0xff, 0xa8, 0xdb, 0x22,
+	0xc5, 0xa1, 0xef, 0x85, 0x1e, 0x82, 0x18, 0xb2, 0xfa, 0x72, 0xa7, 0x1b, 0x9e, 0x8c, 0x8e, 0x8b,
+	0x2d, 0xaf, 0x7f, 0xbb, 0xe3, 0x75, 0xbc, 0xdb, 0x8c, 0xe4, 0x78, 0xf4, 0x90, 0x8d, 0xd8, 0x80,
+	0x7d, 0x71, 0xd6, 0xd5, 0xc5, 0x3e, 0x09, 0xdd, 0xb6, 0x1b, 0xba, 0x7c, 0x6c, 0x7f, 0x96, 0x82,
+	0x4c, 0xb9, 0xde, 0x08, 0x3d, 0x9f, 0x20, 0x04, 0xe9, 0xc3, 0xc3, 0xaa, 0x53, 0x30, 0xd6, 0x8d,
+	0x5b, 0x39, 0xcc, 0xbe, 0xd1, 0x0b, 0xb0, 0xd8, 0xe0, 0x33, 0x95, 0xda, 0x6d, 0x9f, 0x04, 0x41,
+	0xc1, 0x64, 0xd8, 0x31, 0x28, 0x5a, 0x03, 0x68, 0xbc, 0x5d, 0x93, 0x34, 0x29, 0x46, 0xa3, 0x40,
+	0x50, 0x11, 0x50, 0xcd, 0x6b, 0x9d, 0x8e, 0xc9, 0x4a, 0x33, 0xba, 0x04, 0x0c, 0x95, 0x57, 0x0e,
+	0x7b, 0x92, 0x6e, 0x96, 0xcb, 0x8b, 0x21, 0xe8, 0x26, 0xa4, 0xb1, 0xd7, 0x23, 0x85, 0xb9, 0x75,
+	0xe3, 0xd6, 0xe2, 0xa6, 0x55, 0x8c, 0x96, 0x55, 0xae, 0x53, 0x38, 0x66, 0x58, 0xba, 0xa2, 0x66,
+	0xb7, 0x75, 0x5a, 0xc8, 0xac, 0x1b, 0xb7, 0xd2, 0x98, 0x7d, 0xa3, 0x97, 0x60, 0xb6, 0x11, 0xba,
+	0x21, 0x29, 0x64, 0x19, 0xeb, 0xd5, 0xa2, 0x62, 0xde, 0xba, 0xd7, 0x26, 0x0c, 0x89, 0x39, 0x0d,
+	0xfa, 0x01, 0xe4, 0xde, 0xf1, 0xfc, 0x53, 0xce, 0x90, 0x63, 0x0c, 0xcb, 0xf1, 0x5c, 0x11, 0x0a,
+	0xc7, 0x54, 0xe8, 0x4d, 0x98, 0xab, 0xb9, 0xc7, 0xa4, 0x17, 0x14, 0x60, 0x3d, 0x75, 0x2b, 0xbf,
+	0x79, 0x43, 0x9d, 0x40, 0x98, 0xba, 0xc8, 0x29, 0x2a, 0x83, 0xd0, 0x3f, 0xdb, 0x49, 0x7f, 0xfc,
+	0xd9, 0x8d, 0x19, 0x2c, 0x98, 0x56, 0xeb, 0x90, 0x57, 0x90, 0xc8, 0x82, 0xd4, 0x29, 0x39, 0x13,
+	0x5b, 0x42, 0x3f, 0xd1, 0x8b, 0x30, 0xfb, 0xc8, 0xed, 0x8d, 0x08, 0xdb, 0x88, 0xbc, 0xaa, 0x0e,
+	0xe3, 0xab, 0x75, 0x83, 0x10, 0x73, 0x8a, 0x1f, 0x9a, 0xaf, 0x19, 0xf6, 0x5f, 0x4c, 0xc8, 0x38,
+	0x4f, 0x61, 0x83, 0xa5, 0x29, 0x53, 0x49, 0xa6, 0x4c, 0x5f, 0xc2, 0x94, 0xaf, 0xc0, 0x5c, 0xe3,
+	0xc4, 0xf5, 0xdb, 0x74, 0x37, 0xa9, 0x5d, 0xae, 0xab, 0xd4, 0x4e, 0x9d, 0xe1, 0xaa, 0x83, 0x87,
+	0x9e, 0xb4, 0x07, 0x27, 0x46, 0x9b, 0xb0, 0x52, 0xf3, 0x3a, 0xa1, 0xdb, 0xed, 0x51, 0x85, 0x88,
+	0x2f, 0xb5, 0x9c, 0x63, 0x5a, 0x26, 0xe2, 0xa6, 0x38, 0x5b, 0xe6, 0x92, 0xce, 0x96, 0x1d, 0x77,
+	0x36, 0xfb, 0xaf, 0x06, 0x64, 0x6b, 0x5e, 0xe7, 0xff, 0xc0, 0x88, 0xdb, 0x90, 0xc5, 0x64, 0xd8,
+	0xeb, 0xb6, 0x5c, 0x69, 0xc6, 0x55, 0x95, 0xbe, 0xe6, 0x75, 0x04, 0x5a, 0xb1, 0x64, 0xc4, 0x61,
+	0xff, 0xd3, 0x80, 0x79, 0xba, 0x0e, 0x69, 0x6a, 0x54, 0x80, 0x0c, 0x1f, 0xf0, 0xe5, 0xa4, 0xb1,
+	0x1c, 0xa2, 0x1d, 0x65, 0x22, 0x93, 0x4d, 0xf4, 0xc2, 0xd8, 0x44, 0x91, 0x94, 0xa2, 0x24, 0x64,
+	0x1e, 0x1b, 0x4f, 0x87, 0x56, 0x60, 0xb6, 0x32, 0xf4, 0x5a, 0x27, 0x62, 0xb9, 0x7c, 0x80, 0x56,
+	0x21, 0x5b, 0x23, 0x6e, 0x9b, 0xf8, 0x55, 0x87, 0x2d, 0x39, 0x8d, 0xa3, 0x31, 0xb3, 0x0f, 0xf1,
+	0xfb, 0x2c, 0xde, 0xa9, 0x7d, 0x88, 0xdf, 0x5f, 0x7d, 0x03, 0x16, 0xb4, 0x09, 0xd4, 0x90, 0x48,
+	0xf3, 0x90, 0x58, 0x51, 0x43, 0x22, 0xa7, 0x7a, 0xff, 0x23, 0x58, 0xd4, 0x6d, 0x82, 0xee, 0xe9,
+	0x26, 0x60, 0x62, 0xf2, 0x9b, 0x85, 0x69, 0x8b, 0xdb, 0xc9, 0x52, 0x1b, 0x7e, 0xf2, 0xd9, 0x0d,
+	0x03, 0xeb, 0xa6, 0x7b, 0x0e, 0x72, 0x52, 0xac, 0xc3, 0xe6, 0x4d, 0xe3, 0x18, 0x60, 0xff, 0xd6,
+	0x04, 0x4b, 0xc4, 0xfa, 0x2e, 0x71, 0xfd, 0xf0, 0x98, 0xb8, 0xe1, 0x37, 0x30, 0xbf, 0x16, 0x01,
+	0x35, 0xdd, 0x40, 0xca, 0x2e, 0xfb, 0xc4, 0x0d, 0x49, 0x9b, 0x05, 0x5a, 0x16, 0x27, 0x60, 0xec,
+	0x57, 0x61, 0xbe, 0x5c, 0x2f, 0xf5, 0x7a, 0x5e, 0xcb, 0x0d, 0x49, 0xd5, 0x49, 0xc8, 0x6e, 0x2b,
+	0x30, 0xbb, 0xe3, 0x86, 0xad, 0x13, 0x61, 0x52, 0x3e, 0xb0, 0x3f, 0x30, 0x61, 0x49, 0x06, 0xe0,
+	0xf9, 0xf6, 0x5c, 0x87, 0x3c, 0x76, 0x1f, 0x86, 0xba, 0x31, 0x55, 0x50, 0x82, 0xc5, 0x53, 0x89,
+	0x16, 0xbf, 0x09, 0x0b, 0xf7, 0xbd, 0x20, 0xe8, 0x0e, 0x75, 0x63, 0xea, 0xc0, 0xaf, 0x16, 0x90,
+	0x53, 0xec, 0x37, 0x37, 0xd5, 0x7e, 0x15, 0xc8, 0x2b, 0x99, 0xf2, 0x9c, 0xf0, 0x3d, 0xdf, 0x3b,
+	0xff, 0x64, 0x82, 0xe5, 0x3c, 0x4d, 0xef, 0x8c, 0x73, 0x7b, 0xea, 0x49, 0x72, 0x7b, 0xf2, 0xf2,
+	0xd3, 0xd3, 0x96, 0x3f, 0xf5, 0x2c, 0x98, 0x7d, 0xe2, 0xb3, 0x60, 0xee, 0x92, 0x81, 0x91, 0x99,
+	0x38, 0x0b, 0x7e, 0x69, 0x42, 0x16, 0x37, 0x1e, 0xf0, 0x74, 0x6c, 0x41, 0xaa, 0x19, 0x78, 0x32,
+	0x15, 0x35, 0x03, 0x8f, 0xfa, 0x6f, 0x75, 0xd0, 0x26, 0x8f, 0xa5, 0xff, 0xb2, 0x01, 0xf5, 0xa5,
+	0x1a, 0x71, 0x03, 0xb2, 0xeb, 0xf5, 0x78, 0xe2, 0xe3, 0x19, 0x51, 0x07, 0x22, 0x1b, 0xe6, 0x9b,
+	0xfe, 0x68, 0x40, 0x63, 0xa3, 0x5d, 0x0b, 0x06, 0x22, 0x3b, 0x6a, 0x30, 0xf4, 0x16, 0xcc, 0x73,
+	0xa6, 0x6e, 0x10, 0x7a, 0xfe, 0x99, 0xf0, 0x39, 0x2d, 0x37, 0x4b, 0xed, 0x8a, 0x2a, 0x21, 0xcf,
+	0xcd, 0x1a, 0xef, 0xea, 0x5d, 0x58, 0x9a, 0x20, 0xb9, 0x28, 0xbb, 0xa6, 0xd5, 0xec, 0xfa, 0x1e,
+	0xe4, 0x98, 0x83, 0xb7, 0x3c, 0xbf, 0x4d, 0x19, 0xa9, 0xd2, 0x82, 0x91, 0xea, 0xba, 0x01, 0xe9,
+	0xe6, 0xd9, 0x90, 0xf3, 0x2d, 0x6e, 0x5e, 0xd3, 0x74, 0x64, 0x3c, 0x14, 0x8b, 0x19, 0x0d, 0xf5,
+	0x3e, 0xc7, 0x0d, 0x5d, 0x66, 0x98, 0x79, 0xcc, 0xbe, 0xed, 0x0f, 0x0d, 0x00, 0x26, 0xff, 0xa7,
+	0x23, 0x12, 0x30, 0x07, 0xad, 0xbb, 0x7d, 0x22, 0x1d, 0x94, 0x7e, 0xab, 0x11, 0x60, 0xea, 0x11,
+	0x20, 0xd4, 0x49, 0xc5, 0xea, 0x14, 0x20, 0xf3, 0xc0, 0x7d, 0xdc, 0xe8, 0xfe, 0x8c, 0x08, 0xcb,
+	0xca, 0x21, 0x8d, 0x16, 0xe9, 0xa4, 0x8e, 0x38, 0x7b, 0x62, 0x00, 0x53, 0xad, 0x5e, 0x75, 0x98,
+	0xcf, 0xa4, 0x31, 0xfb, 0xb6, 0x6d, 0x80, 0x66, 0xe0, 0x49, 0xcd, 0x56, 0x60, 0xb6, 0xec, 0x8d,
+	0x06, 0xa1, 0x58, 0x3c, 0x1f, 0xd8, 0xff, 0x30, 0x68, 0xb6, 0x63, 0x51, 0xc6, 0x2a, 0xb3, 0xc4,
+	0x08, 0xdb, 0x82, 0xdc, 0xfe, 0x90, 0xf8, 0x6e, 0xd8, 0xf5, 0x06, 0xc2, 0x50, 0x57, 0xf5, 0x82,
+	0x91, 0xf1, 0xee, 0x0f, 0x71, 0x4c, 0x87, 0x76, 0xa2, 0x12, 0x93, 0x87, 0xdb, 0xcd, 0x84, 0x12,
+	0x93, 0x11, 0x7c, 0x8d, 0x75, 0x66, 0x0d, 0xf2, 0xe5, 0x7a, 0x5c, 0x05, 0x27, 0xad, 0xf5, 0x45,
+	0x59, 0xe9, 0x98, 0xd3, 0x0b, 0x69, 0x4e, 0x61, 0x7f, 0x2e, 0x6c, 0xe7, 0x86, 0xe7, 0xd8, 0xee,
+	0xf2, 0xf2, 0x2e, 0xb6, 0x98, 0x9c, 0xe8, 0x6b, 0xb4, 0xd8, 0x07, 0xb3, 0x90, 0x91, 0x1e, 0xc4,
+	0xf2, 0x35, 0xfb, 0x8c, 0x72, 0x79, 0x0c, 0x40, 0x45, 0x98, 0x7b, 0x40, 0xc2, 0x13, 0xaf, 0x9d,
+	0x14, 0x4a, 0x1c, 0xc3, 0x42, 0x49, 0x50, 0xa1, 0x6d, 0x35, 0x6e, 0x58, 0x08, 0xe4, 0x75, 0x9e,
+	0x18, 0x2b, 0xd6, 0xa8, 0xc6, 0x59, 0x89, 0x55, 0x48, 0xd1, 0xc1, 0xc0, 0x82, 0x25, 0xbf, 0xf9,
+	0x9d, 0xf1, 0x0a, 0x49, 0x3b, 0x3d, 0xb0, 0xc6, 0x82, 0xee, 0x50, 0x67, 0x88, 0x25, 0xcc, 0x32,
+	0x09, 0xcf, 0x25, 0x78, 0x69, 0x2c, 0x40, 0x65, 0xa0, 0xfc, 0x8e, 0xc2, 0x3f, 0x37, 0xc9, 0xef,
+	0x4c, 0xf0, 0x2b, 0x0c, 0xe8, 0x55, 0x35, 0x3c, 0x59, 0x12, 0x1f, 0x33, 0x40, 0x8c, 0xc5, 0x6a,
+	0x20, 0x6f, 0xeb, 0xf5, 0x09, 0xbb, 0x0a, 0x8c, 0x15, 0x87, 0x2a, 0x1e, 0xeb, 0xd5, 0xcc, 0xb6,
+	0x1e, 0xef, 0xec, 0xbe, 0x38, 0xc1, 0x1d, 0xe3, 0xb1, 0x9e, 0x1d, 0x5e, 0xd7, 0x02, 0xa8, 0x00,
+	0x8c, 0xf9, 0xba, 0xce, 0x1c, 0xfb, 0xb5, 0x16, 0x6c, 0xdb, 0x7a, 0xb0, 0x14, 0xf2, 0xc9, 0x13,
+	0x4b, 0x3c, 0xd6, 0xa8, 0xed, 0x06, 0xe4, 0xd9, 0xee, 0x07, 0x43, 0x6f, 0x10, 0x90, 0x73, 0x8a,
+	0x0a, 0x91, 0x52, 0x4d, 0x2d, 0xa5, 0xd6, 0xdc, 0x20, 0x8c, 0x13, 0xad, 0x1c, 0xda, 0x45, 0x40,
+	0x8a, 0x9d, 0x14, 0xd9, 0xf7, 0xba, 0xbe, 0xe2, 0xe4, 0x72, 0x68, 0xff, 0x3b, 0x4d, 0x0b, 0x29,
+	0x41, 0xf6, 0x74, 0xa3, 0xe1, 0x39, 0xc8, 0x55, 0x7c, 0xdf, 0xf3, 0xcb, 0x5e, 0x9b, 0x30, 0x35,
+	0x17, 0x70, 0x0c, 0xa0, 0x87, 0x2e, 0x1b, 0x3c, 0x20, 0x41, 0xe0, 0x76, 0x88, 0xa8, 0xf2, 0x34,
+	0x18, 0xad, 0x09, 0xaa, 0xc1, 0x6e, 0x69, 0x8f, 0x90, 0x21, 0xf1, 0x99, 0x37, 0x67, 0xb1, 0x02,
+	0x41, 0x77, 0x35, 0x0b, 0x0a, 0x77, 0xbd, 0x3e, 0x11, 0x70, 0x1c, 0x2d, 0x22, 0x4e, 0xb3, 0x39,
+	0xdd, 0x40, 0xaf, 0xdf, 0x77, 0x07, 0x6d, 0x5e, 0xfc, 0x66, 0x12, 0x36, 0x50, 0xc1, 0x63, 0x8d,
+	0x9a, 0x7a, 0x0e, 0xf3, 0x61, 0x31, 0x7d, 0x76, 0x72, 0x7a, 0x05, 0x8d, 0x55, 0x5a, 0xb4, 0x03,
+	0x8b, 0xe5, 0xde, 0x28, 0x08, 0x89, 0xef, 0x10, 0x5a, 0x3b, 0x05, 0xc2, 0x69, 0xb5, 0x22, 0x56,
+	0xa7, 0xc0, 0x63, 0x1c, 0xe8, 0x0e, 0xe4, 0xe2, 0xeb, 0x14, 0x77, 0xdb, 0x75, 0x95, 0x3d, 0x42,
+	0xbe, 0x3d, 0x22, 0xfe, 0x19, 0x26, 0xc1, 0xa8, 0x17, 0xe2, 0x98, 0x05, 0xdd, 0x01, 0x50, 0x42,
+	0x8e, 0xfb, 0xee, 0x9a, 0x2a, 0x60, 0xd2, 0x91, 0x30, 0x8c, 0x85, 0xdd, 0x09, 0x69, 0x9d, 0x12,
+	0x9f, 0x47, 0xce, 0x7c, 0x82, 0xf1, 0x14, 0x3c, 0xd6, 0xa8, 0xed, 0xb7, 0xd8, 0xcd, 0x82, 0xd7,
+	0x23, 0x91, 0x59, 0x5e, 0xa1, 0x99, 0x99, 0x42, 0x82, 0x82, 0xc1, 0xce, 0x8b, 0xab, 0x13, 0x9b,
+	0x49, 0xb1, 0x62, 0x2b, 0x25, 0xad, 0xfd, 0xbc, 0xb6, 0x11, 0xb4, 0x2c, 0xf8, 0x11, 0x3b, 0x0f,
+	0x44, 0x59, 0xc0, 0x06, 0xf6, 0x7d, 0x58, 0xa0, 0xa5, 0x6d, 0xd3, 0x3d, 0xee, 0x91, 0xc3, 0x80,
+	0xf8, 0xf4, 0x42, 0x4c, 0x7f, 0x07, 0x71, 0x6d, 0x13, 0x8d, 0x29, 0xee, 0xc0, 0x0d, 0x82, 0xf7,
+	0x3d, 0xbf, 0x2d, 0x4a, 0xef, 0x68, 0x6c, 0xff, 0xca, 0xa0, 0x5a, 0xb2, 0x9a, 0x3e, 0xf1, 0x78,
+	0x9c, 0x5e, 0x1b, 0x69, 0xb7, 0x83, 0xd4, 0xd8, 0xed, 0x20, 0xbe, 0xb6, 0xa7, 0xd5, 0x6b, 0xfb,
+	0x1a, 0x3b, 0x53, 0xf4, 0x22, 0x49, 0x81, 0xd8, 0xbf, 0x33, 0xa9, 0x0f, 0x0f, 0x1e, 0x76, 0x3b,
+	0xe5, 0x13, 0x77, 0xd0, 0x21, 0x68, 0x2b, 0xd2, 0x4e, 0xdc, 0xb1, 0x97, 0xf5, 0x02, 0x90, 0xa1,
+	0x62, 0x0b, 0xf2, 0x75, 0x6c, 0x03, 0x70, 0x76, 0xa5, 0x70, 0xd4, 0xcf, 0x0d, 0x65, 0x0a, 0x16,
+	0xe5, 0x0a, 0x3d, 0x6a, 0xc2, 0x62, 0x75, 0xd0, 0x0d, 0xbb, 0x6e, 0xef, 0x01, 0xe9, 0x1f, 0x13,
+	0x5f, 0x9e, 0xf6, 0xdf, 0x9f, 0x26, 0xa1, 0xa8, 0x93, 0xf3, 0x22, 0x79, 0x4c, 0xc6, 0x6a, 0x09,
+	0x96, 0x13, 0xc8, 0x9e, 0xa8, 0x0d, 0xf1, 0x22, 0x2c, 0x34, 0x4e, 0x46, 0x61, 0xdb, 0x7b, 0x7f,
+	0xc0, 0x9b, 0x48, 0x74, 0x6f, 0xe8, 0x47, 0xb4, 0x65, 0x72, 0x68, 0xff, 0x26, 0x05, 0x57, 0x1a,
+	0xad, 0x13, 0xd2, 0x1e, 0xf5, 0x88, 0x88, 0xf2, 0xc4, 0xdd, 0xbd, 0x09, 0x0b, 0x3b, 0x9e, 0x17,
+	0x06, 0xa1, 0xef, 0x0e, 0x87, 0xdd, 0x41, 0x87, 0x4d, 0x9a, 0xc5, 0x3a, 0x90, 0xa6, 0x06, 0x71,
+	0xbf, 0x61, 0x06, 0x4d, 0x31, 0x83, 0x6a, 0xa9, 0x41, 0x41, 0x63, 0x95, 0x96, 0xe7, 0xa4, 0xd8,
+	0x54, 0xa2, 0x0c, 0x28, 0x4c, 0x33, 0x25, 0xd6, 0x77, 0xff, 0xee, 0xd8, 0x8a, 0x45, 0x0d, 0xf0,
+	0x8c, 0x9e, 0x18, 0x14, 0x02, 0x3c, 0x66, 0xa1, 0x3d, 0x58, 0xe2, 0xd7, 0x3e, 0xe5, 0x1e, 0x28,
+	0x32, 0xab, 0x56, 0x8a, 0x4c, 0x10, 0xe1, 0x49, 0x3e, 0xaa, 0x8d, 0x43, 0x7a, 0x24, 0x24, 0xe2,
+	0xc4, 0x15, 0x09, 0x56, 0xd3, 0x46, 0x23, 0xc0, 0x3a, 0xbd, 0xdd, 0x4b, 0xd0, 0x06, 0x6d, 0x41,
+	0x9a, 0x06, 0xaa, 0x70, 0x6f, 0x4d, 0x98, 0x16, 0xe1, 0xc2, 0xc9, 0x19, 0x31, 0xbb, 0xe4, 0xb9,
+	0xc1, 0x29, 0xbd, 0xe0, 0x1c, 0xbb, 0x81, 0xf4, 0x15, 0x0d, 0x46, 0xdd, 0x45, 0x9b, 0xfe, 0x1c,
+	0x77, 0x71, 0xf5, 0x93, 0x23, 0xea, 0xa0, 0x19, 0x71, 0x07, 0x0d, 0xbd, 0x09, 0x59, 0x41, 0x23,
+	0x7b, 0x79, 0xcf, 0x6a, 0xdb, 0xa0, 0x7b, 0x9b, 0x6c, 0x52, 0x48, 0x16, 0xfb, 0xd3, 0x14, 0xad,
+	0x4c, 0xf8, 0x84, 0x34, 0x5f, 0xcb, 0x26, 0xa6, 0xa1, 0x34, 0x31, 0xbf, 0x55, 0x6d, 0x2c, 0xfd,
+	0x55, 0x20, 0x7b, 0xa9, 0x57, 0x81, 0x52, 0x74, 0x01, 0xc9, 0xb1, 0x1d, 0x78, 0x3e, 0xa1, 0x2a,
+	0x64, 0xcd, 0xd4, 0xaf, 0xef, 0xfe, 0xf1, 0x7b, 0x83, 0x3f, 0xfd, 0x88, 0x47, 0x0b, 0xa6, 0x82,
+	0x3c, 0xef, 0x6e, 0x24, 0xd4, 0x8e, 0x45, 0x4e, 0xa1, 0xa9, 0xc6, 0x41, 0xab, 0x18, 0xf2, 0x0a,
+	0x32, 0x41, 0xb5, 0x97, 0x75, 0xd5, 0xae, 0x4f, 0x59, 0xbd, 0xaa, 0xde, 0x47, 0x26, 0x6b, 0x76,
+	0x3d, 0x15, 0xb7, 0xfb, 0x16, 0xf5, 0xa7, 0xe8, 0xae, 0x3a, 0x97, 0xd9, 0x55, 0xe7, 0xbf, 0xbb,
+	0xab, 0x4e, 0xf2, 0xae, 0xfe, 0xd1, 0x18, 0xaf, 0x38, 0xd1, 0x2b, 0x90, 0x15, 0xc4, 0x52, 0xcf,
+	0xe5, 0x04, 0x41, 0x32, 0x2d, 0x49, 0x52, 0xca, 0x56, 0x96, 0x6c, 0xe6, 0x24, 0x5b, 0x59, 0x67,
+	0x93, 0xa4, 0xe8, 0x35, 0xd6, 0xb3, 0x12, 0x7c, 0xdc, 0x1b, 0x56, 0x92, 0xae, 0xb6, 0x82, 0x31,
+	0x26, 0xb6, 0x7f, 0x61, 0x40, 0x5e, 0xa8, 0xce, 0x1c, 0xf2, 0x75, 0xa6, 0x37, 0x77, 0x2b, 0x43,
+	0xb8, 0x55, 0x14, 0x71, 0x02, 0xa3, 0xd5, 0x89, 0x11, 0x39, 0xda, 0xe6, 0x4a, 0x70, 0x5e, 0xae,
+	0x7c, 0x41, 0x89, 0x56, 0x81, 0xd2, 0x98, 0x63, 0x06, 0xfb, 0xd7, 0x06, 0x5c, 0x15, 0x15, 0x89,
+	0xd0, 0x47, 0xde, 0x5f, 0x5f, 0x80, 0xc5, 0xfa, 0xa8, 0xbf, 0xff, 0x30, 0x16, 0xce, 0xa3, 0x65,
+	0x0c, 0x4a, 0x8b, 0x07, 0x06, 0x89, 0xf4, 0xe7, 0x05, 0xa2, 0x0e, 0x44, 0x1b, 0x60, 0x49, 0xbe,
+	0xa8, 0xc7, 0xcd, 0xab, 0xc5, 0x09, 0xb8, 0xfd, 0x73, 0x93, 0xbf, 0xab, 0x9c, 0x1b, 0xae, 0xdf,
+	0xec, 0xe6, 0xfc, 0x47, 0xa6, 0x78, 0x25, 0xa4, 0xa1, 0x77, 0x27, 0xca, 0x38, 0xdc, 0x35, 0xd6,
+	0x27, 0x7c, 0x8c, 0xc5, 0x1e, 0x23, 0xd1, 0x63, 0x8f, 0xdb, 0xfe, 0x4e, 0x14, 0xba, 0xe6, 0x79,
+	0xfc, 0x53, 0x63, 0xb7, 0x01, 0x79, 0x45, 0x78, 0x42, 0xb1, 0x5a, 0xd4, 0x63, 0x77, 0xea, 0x03,
+	0x98, 0x12, 0xbc, 0x4c, 0xe8, 0xb9, 0x09, 0xe1, 0x22, 0xa1, 0x49, 0x19, 0xe1, 0xef, 0x29, 0xfd,
+	0xfe, 0x96, 0xe8, 0x39, 0x77, 0xb5, 0xd0, 0x4b, 0x3c, 0x45, 0x62, 0xb4, 0xbc, 0x61, 0xab, 0xc1,
+	0xba, 0x15, 0x65, 0x45, 0xd1, 0x0f, 0x5b, 0x4e, 0xc8, 0x85, 0xf2, 0x36, 0x22, 0xf3, 0xe7, 0xab,
+	0xf1, 0x86, 0x8a, 0xf2, 0x77, 0x25, 0x69, 0x1b, 0xa4, 0xe7, 0x44, 0x9b, 0xbf, 0x15, 0x1d, 0xac,
+	0xa2, 0xec, 0x5d, 0x4e, 0x38, 0x4e, 0xe5, 0x64, 0xf2, 0x08, 0xbe, 0x2d, 0xbb, 0x99, 0xbc, 0x56,
+	0xd1, 0xca, 0x49, 0xd9, 0x69, 0xd0, 0x7a, 0x9a, 0x75, 0xe1, 0x9f, 0xa2, 0x7c, 0x13, 0xb7, 0xdf,
+	0x0c, 0xe3, 0x5e, 0x1b, 0x2f, 0x46, 0x75, 0x2a, 0x9c, 0xc0, 0x89, 0x2a, 0x63, 0x17, 0x53, 0xd1,
+	0x48, 0xb8, 0xb0, 0xae, 0x1d, 0xbb, 0xce, 0x5e, 0x83, 0xb9, 0x3a, 0x79, 0x1c, 0x56, 0xdb, 0xac,
+	0x95, 0x90, 0xc6, 0x62, 0x64, 0xff, 0x2b, 0x03, 0x96, 0x5c, 0x47, 0xf4, 0x80, 0x12, 0x3d, 0x97,
+	0x18, 0xea, 0x73, 0x89, 0xf4, 0x00, 0x53, 0xf1, 0x00, 0x29, 0x56, 0x5e, 0x58, 0xc5, 0x08, 0xed,
+	0x43, 0x9e, 0x7f, 0xed, 0x9c, 0xed, 0x91, 0xb3, 0x42, 0x9a, 0x45, 0xcb, 0xcb, 0x49, 0xc6, 0x8b,
+	0xde, 0x45, 0x14, 0x7a, 0x7e, 0xe3, 0x53, 0x25, 0x24, 0xbd, 0x41, 0xff, 0xef, 0xf7, 0xa6, 0x0d,
+	0xd6, 0x58, 0x99, 0x1e, 0x14, 0xb2, 0x6c, 0xa9, 0x9b, 0xe7, 0x2e, 0x75, 0x9c, 0x49, 0x4d, 0x15,
+	0x13, 0x12, 0x51, 0x55, 0x3d, 0x96, 0x78, 0x9d, 0xfa, 0xd2, 0xb9, 0xe2, 0x23, 0x6a, 0x6e, 0xc7,
+	0x98, 0x5b, 0x0d, 0x01, 0xb8, 0x74, 0x08, 0x28, 0x41, 0x9a, 0xff, 0x52, 0x41, 0x3a, 0xff, 0x04,
+	0x41, 0x3a, 0x96, 0x52, 0x16, 0x9e, 0x38, 0xa5, 0x4c, 0xc4, 0xcb, 0xe2, 0x97, 0x89, 0x97, 0xd5,
+	0x3b, 0x60, 0x8d, 0x3b, 0x64, 0xf2, 0xbb, 0x78, 0xf2, 0x23, 0xdc, 0xea, 0x7b, 0x70, 0x35, 0x71,
+	0x97, 0x9f, 0x30, 0x3d, 0x6b, 0xfd, 0x45, 0x45, 0xfc, 0x36, 0xfb, 0x07, 0xc5, 0x94, 0xb3, 0xe4,
+	0x22, 0xe5, 0xec, 0x2a, 0xe4, 0xd5, 0x3f, 0x5f, 0x7c, 0x85, 0x37, 0x66, 0xfb, 0x0f, 0x26, 0xac,
+	0x24, 0xb5, 0x12, 0xcf, 0x69, 0x58, 0x1f, 0x4c, 0xfc, 0x89, 0xa5, 0x78, 0x51, 0x63, 0x52, 0xff,
+	0x33, 0xcb, 0x44, 0x4d, 0xf0, 0x74, 0xfe, 0xd2, 0xd2, 0xbc, 0xf8, 0x2f, 0x2d, 0xe7, 0x95, 0xd6,
+	0x8a, 0x45, 0x15, 0x5b, 0x6f, 0xfc, 0x18, 0xe0, 0x70, 0xd8, 0x76, 0x43, 0xde, 0xbe, 0xb9, 0x0e,
+	0xcb, 0xda, 0xeb, 0x32, 0x47, 0x59, 0x33, 0xe8, 0x2a, 0x2c, 0xc9, 0x17, 0xe5, 0x5a, 0xa3, 0x2e,
+	0xc0, 0x06, 0x5a, 0x86, 0x2b, 0xd4, 0x1d, 0x99, 0x3e, 0x02, 0x68, 0xa2, 0x05, 0xc8, 0x35, 0x1b,
+	0xfb, 0x62, 0x98, 0xda, 0x28, 0x42, 0x2e, 0xfa, 0x47, 0x12, 0xba, 0x02, 0xf9, 0xba, 0xe7, 0xf7,
+	0xdd, 0x1e, 0x1b, 0x5a, 0x33, 0xc8, 0x82, 0xf9, 0x66, 0xb7, 0x4f, 0xbc, 0x51, 0xc8, 0x21, 0xc6,
+	0xc6, 0xa7, 0x26, 0x40, 0xdc, 0x90, 0x47, 0x8b, 0x00, 0xcd, 0xc6, 0xfe, 0xd1, 0xe1, 0x81, 0x53,
+	0x6a, 0x56, 0xac, 0x19, 0x04, 0x30, 0x57, 0x3a, 0x38, 0xa8, 0xd4, 0x1d, 0xcb, 0x40, 0x59, 0x48,
+	0xe3, 0x4a, 0xc9, 0xb1, 0x4c, 0x34, 0x0f, 0xd9, 0x26, 0x3e, 0xac, 0x97, 0x29, 0x4d, 0x8a, 0x0a,
+	0xbd, 0x5f, 0x69, 0x1e, 0x45, 0x90, 0x34, 0xca, 0x43, 0xa6, 0xbc, 0x5f, 0xaf, 0x57, 0xca, 0x4d,
+	0x6b, 0x96, 0x8a, 0x14, 0x83, 0x23, 0xbc, 0x6f, 0xcd, 0xa1, 0x25, 0x58, 0xa8, 0xed, 0xdf, 0x3f,
+	0xda, 0xad, 0x94, 0x70, 0x73, 0xa7, 0x52, 0x6a, 0x5a, 0x19, 0x2a, 0xa1, 0x5c, 0x57, 0x20, 0x59,
+	0x0a, 0x71, 0x54, 0x48, 0x0e, 0x21, 0x58, 0x2c, 0xef, 0x56, 0xca, 0x7b, 0x47, 0xbb, 0xa5, 0xbd,
+	0x4a, 0xe5, 0xa0, 0x82, 0x2d, 0xa0, 0x06, 0xa4, 0x33, 0x97, 0x6b, 0x87, 0x8d, 0x66, 0x05, 0x1f,
+	0x39, 0x95, 0x66, 0xa9, 0x5a, 0x6b, 0x58, 0x79, 0x4a, 0x4c, 0x11, 0x8d, 0xdd, 0x12, 0x76, 0x8e,
+	0xaa, 0xf5, 0x7b, 0xfb, 0xd6, 0x3c, 0x13, 0x50, 0x3f, 0x2a, 0xd5, 0x6a, 0xfb, 0x54, 0xcb, 0xa3,
+	0xaa, 0x63, 0x2d, 0x50, 0x43, 0xab, 0x02, 0x1a, 0x4d, 0xaa, 0xff, 0x22, 0x33, 0x34, 0xb3, 0xc0,
+	0x51, 0xb9, 0x7e, 0x54, 0x2b, 0xed, 0x54, 0x6a, 0xd6, 0x15, 0x54, 0x80, 0x95, 0x18, 0xf8, 0xce,
+	0x3e, 0xde, 0x13, 0xe4, 0x16, 0x95, 0x7c, 0x50, 0x6a, 0x96, 0x77, 0x29, 0xa2, 0xd1, 0xdc, 0xc7,
+	0x15, 0x6b, 0x69, 0xa3, 0x0e, 0x10, 0x3f, 0xa0, 0x53, 0x1b, 0xd0, 0x9d, 0xe3, 0x10, 0x6b, 0x86,
+	0x1a, 0xb0, 0x3a, 0x08, 0x89, 0x3f, 0x70, 0x7b, 0x96, 0x41, 0xb7, 0x89, 0xf9, 0x41, 0xb4, 0xa7,
+	0x4b, 0xe2, 0xbf, 0x08, 0x98, 0xfc, 0x84, 0xb4, 0x42, 0xd2, 0xb6, 0x52, 0x1b, 0x1b, 0x90, 0x8b,
+	0xde, 0x99, 0x29, 0x7b, 0x83, 0x84, 0x6c, 0x64, 0xcd, 0x50, 0x76, 0xde, 0x8a, 0xe2, 0x00, 0x63,
+	0xe3, 0xcf, 0x26, 0x20, 0x79, 0x0e, 0x28, 0xee, 0x46, 0xf7, 0xb6, 0xdb, 0x3a, 0x55, 0xbd, 0x4c,
+	0x79, 0xd0, 0x8b, 0xbc, 0xec, 0x2a, 0x2c, 0x39, 0x13, 0x60, 0x13, 0x5d, 0xa3, 0x97, 0xe0, 0xce,
+	0x38, 0x3c, 0x45, 0x67, 0xbf, 0x4f, 0xc2, 0xc8, 0x79, 0xd3, 0xe8, 0x99, 0x89, 0x64, 0x27, 0x50,
+	0xb3, 0xd4, 0x50, 0x0d, 0xc2, 0x5d, 0x4f, 0xc0, 0xe6, 0xa8, 0x59, 0xf5, 0x8b, 0x92, 0xc0, 0x64,
+	0xd0, 0x0d, 0x78, 0xb6, 0x41, 0xc2, 0xc9, 0x93, 0x56, 0x10, 0x64, 0xd1, 0x2a, 0x5c, 0x13, 0x04,
+	0x51, 0xaa, 0x16, 0xb8, 0x1c, 0x35, 0x21, 0xff, 0x16, 0x56, 0xb3, 0x80, 0x2e, 0x4c, 0x82, 0xa2,
+	0xa6, 0x8f, 0x95, 0xa7, 0xae, 0x76, 0x40, 0x33, 0xaa, 0xb8, 0x7e, 0x5a, 0xf3, 0x1b, 0x1f, 0x1a,
+	0xb0, 0xa0, 0x95, 0x0c, 0xd4, 0x21, 0x24, 0x40, 0x5c, 0x25, 0xac, 0x19, 0xba, 0x50, 0x09, 0xd4,
+	0x3a, 0xba, 0x96, 0x81, 0xbe, 0x07, 0xdf, 0x9d, 0x40, 0xc9, 0xcc, 0x8f, 0x49, 0x8b, 0x74, 0x1f,
+	0x91, 0xb6, 0x65, 0xa2, 0x67, 0xe1, 0xfa, 0x04, 0xd9, 0x3d, 0xb7, 0xdb, 0xa3, 0x3b, 0xae, 0xce,
+	0x89, 0x47, 0x83, 0x01, 0x15, 0x9c, 0xde, 0x38, 0x4e, 0x2a, 0x5a, 0xa8, 0x0d, 0x35, 0x68, 0xac,
+	0xe3, 0x38, 0x46, 0x4a, 0x32, 0x26, 0x30, 0x8d, 0xd0, 0x1b, 0x0e, 0xa9, 0x56, 0x1b, 0x27, 0x60,
+	0x8d, 0xb7, 0xf0, 0xa9, 0xef, 0x94, 0xda, 0x6d, 0x91, 0xd5, 0xac, 0x19, 0x6a, 0x5e, 0x4c, 0xfa,
+	0xde, 0x23, 0x22, 0x41, 0x06, 0xb5, 0x63, 0x23, 0x74, 0xfd, 0x50, 0x42, 0x4c, 0xea, 0x1a, 0x54,
+	0xaa, 0x04, 0xa4, 0xa8, 0x94, 0xbd, 0x6e, 0xaf, 0xf7, 0xae, 0xd7, 0x3f, 0xee, 0x12, 0x2b, 0xbd,
+	0xf1, 0x86, 0xd6, 0xfa, 0xa6, 0x68, 0x7a, 0x8e, 0x71, 0x88, 0x35, 0x43, 0x53, 0x9b, 0x53, 0x97,
+	0x43, 0x83, 0x0e, 0xcb, 0xd1, 0xd0, 0xdc, 0xa9, 0x7c, 0xf2, 0xf9, 0xda, 0xcc, 0xc7, 0x5f, 0xac,
+	0x19, 0x9f, 0x7c, 0xb1, 0x66, 0xfc, 0xed, 0x8b, 0x35, 0xe3, 0xdd, 0x2d, 0xe5, 0x7f, 0xd6, 0x7d,
+	0x37, 0xf4, 0xbb, 0x8f, 0x3d, 0xbf, 0xdb, 0xe9, 0x0e, 0xe4, 0x60, 0x40, 0x6e, 0x0f, 0x4f, 0x3b,
+	0xb7, 0x87, 0xc7, 0xb7, 0xe3, 0x4c, 0x7d, 0x3c, 0xc7, 0xfe, 0x64, 0xbd, 0xf5, 0x9f, 0x00, 0x00,
+	0x00, 0xff, 0xff, 0xe0, 0x67, 0xf3, 0x53, 0xc3, 0x2d, 0x00, 0x00,
 }
 
 func (m *CNStore) Marshal() (dAtA []byte, err error) {
@@ -3901,9 +4079,14 @@ func (m *CNStore) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 			dAtA[i] = 0xa
 			i = encodeVarintLogservice(dAtA, i, uint64(baseI-i))
 			i--
-			dAtA[i] = 0x4a
+			dAtA[i] = 0x52
 		}
 	}
+	if m.WorkState != 0 {
+		i = encodeVarintLogservice(dAtA, i, uint64(m.WorkState))
+		i--
+		dAtA[i] = 0x48
+	}
 	if m.State != 0 {
 		i = encodeVarintLogservice(dAtA, i, uint64(m.State))
 		i--
@@ -4792,7 +4975,7 @@ func (m *CNStoreLabel) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 	return len(dAtA) - i, nil
 }
 
-func (m *Request) Marshal() (dAtA []byte, err error) {
+func (m *CNWorkState) Marshal() (dAtA []byte, err error) {
 	size := m.Size()
 	dAtA = make([]byte, size)
 	n, err := m.MarshalToSizedBuffer(dAtA[:size])
@@ -4802,12 +4985,12 @@ func (m *Request) Marshal() (dAtA []byte, err error) {
 	return dAtA[:n], nil
 }
 
-func (m *Request) MarshalTo(dAtA []byte) (int, error) {
+func (m *CNWorkState) MarshalTo(dAtA []byte) (int, error) {
 	size := m.Size()
 	return m.MarshalToSizedBuffer(dAtA[:size])
 }
 
-func (m *Request) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+func (m *CNWorkState) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 	i := len(dAtA)
 	_ = i
 	var l int
@@ -4816,55 +4999,181 @@ func (m *Request) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 		i -= len(m.XXX_unrecognized)
 		copy(dAtA[i:], m.XXX_unrecognized)
 	}
-	if m.CNStoreLabel != nil {
-		{
-			size, err := m.CNStoreLabel.MarshalToSizedBuffer(dAtA[:i])
-			if err != nil {
-				return 0, err
-			}
-			i -= size
-			i = encodeVarintLogservice(dAtA, i, uint64(size))
-		}
+	if m.State != 0 {
+		i = encodeVarintLogservice(dAtA, i, uint64(m.State))
 		i--
-		dAtA[i] = 0x4a
+		dAtA[i] = 0x10
 	}
-	if m.CNAllocateID != nil {
-		{
-			size, err := m.CNAllocateID.MarshalToSizedBuffer(dAtA[:i])
-			if err != nil {
-				return 0, err
-			}
-			i -= size
-			i = encodeVarintLogservice(dAtA, i, uint64(size))
-		}
+	if len(m.UUID) > 0 {
+		i -= len(m.UUID)
+		copy(dAtA[i:], m.UUID)
+		i = encodeVarintLogservice(dAtA, i, uint64(len(m.UUID)))
 		i--
-		dAtA[i] = 0x42
+		dAtA[i] = 0xa
 	}
-	if m.TsoRequest != nil {
-		{
-			size, err := m.TsoRequest.MarshalToSizedBuffer(dAtA[:i])
-			if err != nil {
-				return 0, err
-			}
-			i -= size
-			i = encodeVarintLogservice(dAtA, i, uint64(size))
-		}
-		i--
-		dAtA[i] = 0x3a
+	return len(dAtA) - i, nil
+}
+
+func (m *CNStateLabel) Marshal() (dAtA []byte, err error) {
+	size := m.Size()
+	dAtA = make([]byte, size)
+	n, err := m.MarshalToSizedBuffer(dAtA[:size])
+	if err != nil {
+		return nil, err
 	}
-	if m.DNHeartbeat != nil {
-		{
-			size, err := m.DNHeartbeat.MarshalToSizedBuffer(dAtA[:i])
-			if err != nil {
-				return 0, err
+	return dAtA[:n], nil
+}
+
+func (m *CNStateLabel) MarshalTo(dAtA []byte) (int, error) {
+	size := m.Size()
+	return m.MarshalToSizedBuffer(dAtA[:size])
+}
+
+func (m *CNStateLabel) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+	i := len(dAtA)
+	_ = i
+	var l int
+	_ = l
+	if m.XXX_unrecognized != nil {
+		i -= len(m.XXX_unrecognized)
+		copy(dAtA[i:], m.XXX_unrecognized)
+	}
+	if len(m.Labels) > 0 {
+		for k := range m.Labels {
+			v := m.Labels[k]
+			baseI := i
+			{
+				size, err := (&v).MarshalToSizedBuffer(dAtA[:i])
+				if err != nil {
+					return 0, err
+				}
+				i -= size
+				i = encodeVarintLogservice(dAtA, i, uint64(size))
 			}
-			i -= size
-			i = encodeVarintLogservice(dAtA, i, uint64(size))
+			i--
+			dAtA[i] = 0x12
+			i -= len(k)
+			copy(dAtA[i:], k)
+			i = encodeVarintLogservice(dAtA, i, uint64(len(k)))
+			i--
+			dAtA[i] = 0xa
+			i = encodeVarintLogservice(dAtA, i, uint64(baseI-i))
+			i--
+			dAtA[i] = 0x1a
 		}
-		i--
-		dAtA[i] = 0x32
 	}
-	if m.CNHeartbeat != nil {
+	if m.State != 0 {
+		i = encodeVarintLogservice(dAtA, i, uint64(m.State))
+		i--
+		dAtA[i] = 0x10
+	}
+	if len(m.UUID) > 0 {
+		i -= len(m.UUID)
+		copy(dAtA[i:], m.UUID)
+		i = encodeVarintLogservice(dAtA, i, uint64(len(m.UUID)))
+		i--
+		dAtA[i] = 0xa
+	}
+	return len(dAtA) - i, nil
+}
+
+func (m *Request) Marshal() (dAtA []byte, err error) {
+	size := m.Size()
+	dAtA = make([]byte, size)
+	n, err := m.MarshalToSizedBuffer(dAtA[:size])
+	if err != nil {
+		return nil, err
+	}
+	return dAtA[:n], nil
+}
+
+func (m *Request) MarshalTo(dAtA []byte) (int, error) {
+	size := m.Size()
+	return m.MarshalToSizedBuffer(dAtA[:size])
+}
+
+func (m *Request) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+	i := len(dAtA)
+	_ = i
+	var l int
+	_ = l
+	if m.XXX_unrecognized != nil {
+		i -= len(m.XXX_unrecognized)
+		copy(dAtA[i:], m.XXX_unrecognized)
+	}
+	if m.CNStateLabel != nil {
+		{
+			size, err := m.CNStateLabel.MarshalToSizedBuffer(dAtA[:i])
+			if err != nil {
+				return 0, err
+			}
+			i -= size
+			i = encodeVarintLogservice(dAtA, i, uint64(size))
+		}
+		i--
+		dAtA[i] = 0x5a
+	}
+	if m.CNWorkState != nil {
+		{
+			size, err := m.CNWorkState.MarshalToSizedBuffer(dAtA[:i])
+			if err != nil {
+				return 0, err
+			}
+			i -= size
+			i = encodeVarintLogservice(dAtA, i, uint64(size))
+		}
+		i--
+		dAtA[i] = 0x52
+	}
+	if m.CNStoreLabel != nil {
+		{
+			size, err := m.CNStoreLabel.MarshalToSizedBuffer(dAtA[:i])
+			if err != nil {
+				return 0, err
+			}
+			i -= size
+			i = encodeVarintLogservice(dAtA, i, uint64(size))
+		}
+		i--
+		dAtA[i] = 0x4a
+	}
+	if m.CNAllocateID != nil {
+		{
+			size, err := m.CNAllocateID.MarshalToSizedBuffer(dAtA[:i])
+			if err != nil {
+				return 0, err
+			}
+			i -= size
+			i = encodeVarintLogservice(dAtA, i, uint64(size))
+		}
+		i--
+		dAtA[i] = 0x42
+	}
+	if m.TsoRequest != nil {
+		{
+			size, err := m.TsoRequest.MarshalToSizedBuffer(dAtA[:i])
+			if err != nil {
+				return 0, err
+			}
+			i -= size
+			i = encodeVarintLogservice(dAtA, i, uint64(size))
+		}
+		i--
+		dAtA[i] = 0x3a
+	}
+	if m.DNHeartbeat != nil {
+		{
+			size, err := m.DNHeartbeat.MarshalToSizedBuffer(dAtA[:i])
+			if err != nil {
+				return 0, err
+			}
+			i -= size
+			i = encodeVarintLogservice(dAtA, i, uint64(size))
+		}
+		i--
+		dAtA[i] = 0x32
+	}
+	if m.CNHeartbeat != nil {
 		{
 			size, err := m.CNHeartbeat.MarshalToSizedBuffer(dAtA[:i])
 			if err != nil {
@@ -5653,9 +5962,14 @@ func (m *CNStoreInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 			dAtA[i] = 0xa
 			i = encodeVarintLogservice(dAtA, i, uint64(baseI-i))
 			i--
-			dAtA[i] = 0x42
+			dAtA[i] = 0x4a
 		}
 	}
+	if m.WorkState != 0 {
+		i = encodeVarintLogservice(dAtA, i, uint64(m.WorkState))
+		i--
+		dAtA[i] = 0x40
+	}
 	if m.TaskServiceCreated {
 		i--
 		if m.TaskServiceCreated {
@@ -6627,6 +6941,9 @@ func (m *CNStore) Size() (n int) {
 	if m.State != 0 {
 		n += 1 + sovLogservice(uint64(m.State))
 	}
+	if m.WorkState != 0 {
+		n += 1 + sovLogservice(uint64(m.WorkState))
+	}
 	if len(m.Labels) > 0 {
 		for k, v := range m.Labels {
 			_ = k
@@ -7048,6 +7365,53 @@ func (m *CNStoreLabel) Size() (n int) {
 	return n
 }
 
+func (m *CNWorkState) Size() (n int) {
+	if m == nil {
+		return 0
+	}
+	var l int
+	_ = l
+	l = len(m.UUID)
+	if l > 0 {
+		n += 1 + l + sovLogservice(uint64(l))
+	}
+	if m.State != 0 {
+		n += 1 + sovLogservice(uint64(m.State))
+	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
+	return n
+}
+
+func (m *CNStateLabel) Size() (n int) {
+	if m == nil {
+		return 0
+	}
+	var l int
+	_ = l
+	l = len(m.UUID)
+	if l > 0 {
+		n += 1 + l + sovLogservice(uint64(l))
+	}
+	if m.State != 0 {
+		n += 1 + sovLogservice(uint64(m.State))
+	}
+	if len(m.Labels) > 0 {
+		for k, v := range m.Labels {
+			_ = k
+			_ = v
+			l = v.Size()
+			mapEntrySize := 1 + len(k) + sovLogservice(uint64(len(k))) + 1 + l + sovLogservice(uint64(l))
+			n += mapEntrySize + 1 + sovLogservice(uint64(mapEntrySize))
+		}
+	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
+	return n
+}
+
 func (m *Request) Size() (n int) {
 	if m == nil {
 		return 0
@@ -7086,6 +7450,14 @@ func (m *Request) Size() (n int) {
 		l = m.CNStoreLabel.Size()
 		n += 1 + l + sovLogservice(uint64(l))
 	}
+	if m.CNWorkState != nil {
+		l = m.CNWorkState.Size()
+		n += 1 + l + sovLogservice(uint64(l))
+	}
+	if m.CNStateLabel != nil {
+		l = m.CNStateLabel.Size()
+		n += 1 + l + sovLogservice(uint64(l))
+	}
 	if m.XXX_unrecognized != nil {
 		n += len(m.XXX_unrecognized)
 	}
@@ -7428,6 +7800,9 @@ func (m *CNStoreInfo) Size() (n int) {
 	if m.TaskServiceCreated {
 		n += 2
 	}
+	if m.WorkState != 0 {
+		n += 1 + sovLogservice(uint64(m.WorkState))
+	}
 	if len(m.Labels) > 0 {
 		for k, v := range m.Labels {
 			_ = k
@@ -8071,6 +8446,25 @@ func (m *CNStore) Unmarshal(dAtA []byte) error {
 				}
 			}
 		case 9:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field WorkState", wireType)
+			}
+			m.WorkState = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowLogservice
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				m.WorkState |= metadata.WorkState(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+		case 10:
 			if wireType != 2 {
 				return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType)
 			}
@@ -10801,7 +11195,7 @@ func (m *CNStoreLabel) Unmarshal(dAtA []byte) error {
 	}
 	return nil
 }
-func (m *Request) Unmarshal(dAtA []byte) error {
+func (m *CNWorkState) Unmarshal(dAtA []byte) error {
 	l := len(dAtA)
 	iNdEx := 0
 	for iNdEx < l {
@@ -10824,55 +11218,17 @@ func (m *Request) Unmarshal(dAtA []byte) error {
 		fieldNum := int32(wire >> 3)
 		wireType := int(wire & 0x7)
 		if wireType == 4 {
-			return fmt.Errorf("proto: Request: wiretype end group for non-group")
+			return fmt.Errorf("proto: CNWorkState: wiretype end group for non-group")
 		}
 		if fieldNum <= 0 {
-			return fmt.Errorf("proto: Request: illegal tag %d (wire type %d)", fieldNum, wire)
+			return fmt.Errorf("proto: CNWorkState: illegal tag %d (wire type %d)", fieldNum, wire)
 		}
 		switch fieldNum {
 		case 1:
-			if wireType != 0 {
-				return fmt.Errorf("proto: wrong wireType = %d for field RequestID", wireType)
-			}
-			m.RequestID = 0
-			for shift := uint(0); ; shift += 7 {
-				if shift >= 64 {
-					return ErrIntOverflowLogservice
-				}
-				if iNdEx >= l {
-					return io.ErrUnexpectedEOF
-				}
-				b := dAtA[iNdEx]
-				iNdEx++
-				m.RequestID |= uint64(b&0x7F) << shift
-				if b < 0x80 {
-					break
-				}
-			}
-		case 2:
-			if wireType != 0 {
-				return fmt.Errorf("proto: wrong wireType = %d for field Method", wireType)
-			}
-			m.Method = 0
-			for shift := uint(0); ; shift += 7 {
-				if shift >= 64 {
-					return ErrIntOverflowLogservice
-				}
-				if iNdEx >= l {
-					return io.ErrUnexpectedEOF
-				}
-				b := dAtA[iNdEx]
-				iNdEx++
-				m.Method |= MethodType(b&0x7F) << shift
-				if b < 0x80 {
-					break
-				}
-			}
-		case 3:
 			if wireType != 2 {
-				return fmt.Errorf("proto: wrong wireType = %d for field LogRequest", wireType)
+				return fmt.Errorf("proto: wrong wireType = %d for field UUID", wireType)
 			}
-			var msglen int
+			var stringLen uint64
 			for shift := uint(0); ; shift += 7 {
 				if shift >= 64 {
 					return ErrIntOverflowLogservice
@@ -10882,30 +11238,29 @@ func (m *Request) Unmarshal(dAtA []byte) error {
 				}
 				b := dAtA[iNdEx]
 				iNdEx++
-				msglen |= int(b&0x7F) << shift
+				stringLen |= uint64(b&0x7F) << shift
 				if b < 0x80 {
 					break
 				}
 			}
-			if msglen < 0 {
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
 				return ErrInvalidLengthLogservice
 			}
-			postIndex := iNdEx + msglen
+			postIndex := iNdEx + intStringLen
 			if postIndex < 0 {
 				return ErrInvalidLengthLogservice
 			}
 			if postIndex > l {
 				return io.ErrUnexpectedEOF
 			}
-			if err := m.LogRequest.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
-				return err
-			}
+			m.UUID = string(dAtA[iNdEx:postIndex])
 			iNdEx = postIndex
-		case 4:
-			if wireType != 2 {
-				return fmt.Errorf("proto: wrong wireType = %d for field LogHeartbeat", wireType)
+		case 2:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field State", wireType)
 			}
-			var msglen int
+			m.State = 0
 			for shift := uint(0); ; shift += 7 {
 				if shift >= 64 {
 					return ErrIntOverflowLogservice
@@ -10915,19 +11270,391 @@ func (m *Request) Unmarshal(dAtA []byte) error {
 				}
 				b := dAtA[iNdEx]
 				iNdEx++
-				msglen |= int(b&0x7F) << shift
+				m.State |= metadata.WorkState(b&0x7F) << shift
 				if b < 0x80 {
 					break
 				}
 			}
-			if msglen < 0 {
-				return ErrInvalidLengthLogservice
+		default:
+			iNdEx = preIndex
+			skippy, err := skipLogservice(dAtA[iNdEx:])
+			if err != nil {
+				return err
 			}
-			postIndex := iNdEx + msglen
-			if postIndex < 0 {
+			if (skippy < 0) || (iNdEx+skippy) < 0 {
 				return ErrInvalidLengthLogservice
 			}
-			if postIndex > l {
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
+func (m *CNStateLabel) Unmarshal(dAtA []byte) error {
+	l := len(dAtA)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowLogservice
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := dAtA[iNdEx]
+			iNdEx++
+			wire |= uint64(b&0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: CNStateLabel: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: CNStateLabel: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field UUID", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowLogservice
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= uint64(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthLogservice
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex < 0 {
+				return ErrInvalidLengthLogservice
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.UUID = string(dAtA[iNdEx:postIndex])
+			iNdEx = postIndex
+		case 2:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field State", wireType)
+			}
+			m.State = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowLogservice
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				m.State |= metadata.WorkState(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+		case 3:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowLogservice
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthLogservice
+			}
+			postIndex := iNdEx + msglen
+			if postIndex < 0 {
+				return ErrInvalidLengthLogservice
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if m.Labels == nil {
+				m.Labels = make(map[string]metadata.LabelList)
+			}
+			var mapkey string
+			mapvalue := &metadata.LabelList{}
+			for iNdEx < postIndex {
+				entryPreIndex := iNdEx
+				var wire uint64
+				for shift := uint(0); ; shift += 7 {
+					if shift >= 64 {
+						return ErrIntOverflowLogservice
+					}
+					if iNdEx >= l {
+						return io.ErrUnexpectedEOF
+					}
+					b := dAtA[iNdEx]
+					iNdEx++
+					wire |= uint64(b&0x7F) << shift
+					if b < 0x80 {
+						break
+					}
+				}
+				fieldNum := int32(wire >> 3)
+				if fieldNum == 1 {
+					var stringLenmapkey uint64
+					for shift := uint(0); ; shift += 7 {
+						if shift >= 64 {
+							return ErrIntOverflowLogservice
+						}
+						if iNdEx >= l {
+							return io.ErrUnexpectedEOF
+						}
+						b := dAtA[iNdEx]
+						iNdEx++
+						stringLenmapkey |= uint64(b&0x7F) << shift
+						if b < 0x80 {
+							break
+						}
+					}
+					intStringLenmapkey := int(stringLenmapkey)
+					if intStringLenmapkey < 0 {
+						return ErrInvalidLengthLogservice
+					}
+					postStringIndexmapkey := iNdEx + intStringLenmapkey
+					if postStringIndexmapkey < 0 {
+						return ErrInvalidLengthLogservice
+					}
+					if postStringIndexmapkey > l {
+						return io.ErrUnexpectedEOF
+					}
+					mapkey = string(dAtA[iNdEx:postStringIndexmapkey])
+					iNdEx = postStringIndexmapkey
+				} else if fieldNum == 2 {
+					var mapmsglen int
+					for shift := uint(0); ; shift += 7 {
+						if shift >= 64 {
+							return ErrIntOverflowLogservice
+						}
+						if iNdEx >= l {
+							return io.ErrUnexpectedEOF
+						}
+						b := dAtA[iNdEx]
+						iNdEx++
+						mapmsglen |= int(b&0x7F) << shift
+						if b < 0x80 {
+							break
+						}
+					}
+					if mapmsglen < 0 {
+						return ErrInvalidLengthLogservice
+					}
+					postmsgIndex := iNdEx + mapmsglen
+					if postmsgIndex < 0 {
+						return ErrInvalidLengthLogservice
+					}
+					if postmsgIndex > l {
+						return io.ErrUnexpectedEOF
+					}
+					mapvalue = &metadata.LabelList{}
+					if err := mapvalue.Unmarshal(dAtA[iNdEx:postmsgIndex]); err != nil {
+						return err
+					}
+					iNdEx = postmsgIndex
+				} else {
+					iNdEx = entryPreIndex
+					skippy, err := skipLogservice(dAtA[iNdEx:])
+					if err != nil {
+						return err
+					}
+					if (skippy < 0) || (iNdEx+skippy) < 0 {
+						return ErrInvalidLengthLogservice
+					}
+					if (iNdEx + skippy) > postIndex {
+						return io.ErrUnexpectedEOF
+					}
+					iNdEx += skippy
+				}
+			}
+			m.Labels[mapkey] = *mapvalue
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipLogservice(dAtA[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if (skippy < 0) || (iNdEx+skippy) < 0 {
+				return ErrInvalidLengthLogservice
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
+func (m *Request) Unmarshal(dAtA []byte) error {
+	l := len(dAtA)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowLogservice
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := dAtA[iNdEx]
+			iNdEx++
+			wire |= uint64(b&0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: Request: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: Request: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field RequestID", wireType)
+			}
+			m.RequestID = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowLogservice
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				m.RequestID |= uint64(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+		case 2:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Method", wireType)
+			}
+			m.Method = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowLogservice
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				m.Method |= MethodType(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+		case 3:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field LogRequest", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowLogservice
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthLogservice
+			}
+			postIndex := iNdEx + msglen
+			if postIndex < 0 {
+				return ErrInvalidLengthLogservice
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if err := m.LogRequest.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		case 4:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field LogHeartbeat", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowLogservice
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthLogservice
+			}
+			postIndex := iNdEx + msglen
+			if postIndex < 0 {
+				return ErrInvalidLengthLogservice
+			}
+			if postIndex > l {
 				return io.ErrUnexpectedEOF
 			}
 			if m.LogHeartbeat == nil {
@@ -11117,6 +11844,78 @@ func (m *Request) Unmarshal(dAtA []byte) error {
 				return err
 			}
 			iNdEx = postIndex
+		case 10:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field CNWorkState", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowLogservice
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthLogservice
+			}
+			postIndex := iNdEx + msglen
+			if postIndex < 0 {
+				return ErrInvalidLengthLogservice
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if m.CNWorkState == nil {
+				m.CNWorkState = &CNWorkState{}
+			}
+			if err := m.CNWorkState.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		case 11:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field CNStateLabel", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowLogservice
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthLogservice
+			}
+			postIndex := iNdEx + msglen
+			if postIndex < 0 {
+				return ErrInvalidLengthLogservice
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if m.CNStateLabel == nil {
+				m.CNStateLabel = &CNStateLabel{}
+			}
+			if err := m.CNStateLabel.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
 		default:
 			iNdEx = preIndex
 			skippy, err := skipLogservice(dAtA[iNdEx:])
@@ -13239,6 +14038,25 @@ func (m *CNStoreInfo) Unmarshal(dAtA []byte) error {
 			}
 			m.TaskServiceCreated = bool(v != 0)
 		case 8:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field WorkState", wireType)
+			}
+			m.WorkState = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowLogservice
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				m.WorkState |= metadata.WorkState(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+		case 9:
 			if wireType != 2 {
 				return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType)
 			}
diff --git a/pkg/pb/metadata/metadata.pb.go b/pkg/pb/metadata/metadata.pb.go
index 2cb27146d..d4330468c 100644
--- a/pkg/pb/metadata/metadata.pb.go
+++ b/pkg/pb/metadata/metadata.pb.go
@@ -88,6 +88,38 @@ func (CNRole) EnumDescriptor() ([]byte, []int) {
 	return fileDescriptor_56d9f74966f40d04, []int{1}
 }
 
+// WorkState is the work state of CN service.
+type WorkState int32
+
+const (
+	WorkState_Unknown  WorkState = 0
+	WorkState_Working  WorkState = 1
+	WorkState_Draining WorkState = 2
+	WorkState_Drained  WorkState = 3
+)
+
+var WorkState_name = map[int32]string{
+	0: "Unknown",
+	1: "Working",
+	2: "Draining",
+	3: "Drained",
+}
+
+var WorkState_value = map[string]int32{
+	"Unknown":  0,
+	"Working":  1,
+	"Draining": 2,
+	"Drained":  3,
+}
+
+func (x WorkState) String() string {
+	return proto.EnumName(WorkState_name, int32(x))
+}
+
+func (WorkState) EnumDescriptor() ([]byte, []int) {
+	return fileDescriptor_56d9f74966f40d04, []int{2}
+}
+
 // DNShardRecord is DN shard metadata describing what is a DN shard. It
 // is internally used by HAKeeper to maintain how many DNs available in
 // the system.
@@ -507,8 +539,10 @@ type CNService struct {
 	SQLAddress string `protobuf:"bytes,4,opt,name=SQLAddress,proto3" json:"SQLAddress,omitempty"`
 	// CtlAddress is used to handle ctl request.
 	CtlAddress string `protobuf:"bytes,5,opt,name=CtlAddress,proto3" json:"CtlAddress,omitempty"`
-	// Labels lables on service
-	Labels               map[string]LabelList `protobuf:"bytes,6,rep,name=Labels,proto3" json:"Labels" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+	// WorkState is the work state of CN service.
+	WorkState WorkState `protobuf:"varint,6,opt,name=WorkState,proto3,enum=metadata.WorkState" json:"WorkState,omitempty"`
+	// Labels are labels on CN service.
+	Labels               map[string]LabelList `protobuf:"bytes,7,rep,name=Labels,proto3" json:"Labels" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
 	XXX_NoUnkeyedLiteral struct{}             `json:"-"`
 	XXX_unrecognized     []byte               `json:"-"`
 	XXX_sizecache        int32                `json:"-"`
@@ -582,6 +616,13 @@ func (m *CNService) GetCtlAddress() string {
 	return ""
 }
 
+func (m *CNService) GetWorkState() WorkState {
+	if m != nil {
+		return m.WorkState
+	}
+	return WorkState_Unknown
+}
+
 func (m *CNService) GetLabels() map[string]LabelList {
 	if m != nil {
 		return m.Labels
@@ -743,6 +784,7 @@ func (m *LabelList) GetLabels() []string {
 func init() {
 	proto.RegisterEnum("metadata.ServiceType", ServiceType_name, ServiceType_value)
 	proto.RegisterEnum("metadata.CNRole", CNRole_name, CNRole_value)
+	proto.RegisterEnum("metadata.WorkState", WorkState_name, WorkState_value)
 	proto.RegisterType((*DNShardRecord)(nil), "metadata.DNShardRecord")
 	proto.RegisterType((*DNShard)(nil), "metadata.DNShard")
 	proto.RegisterType((*LogShardRecord)(nil), "metadata.LogShardRecord")
@@ -760,48 +802,51 @@ func init() {
 func init() { proto.RegisterFile("metadata.proto", fileDescriptor_56d9f74966f40d04) }
 
 var fileDescriptor_56d9f74966f40d04 = []byte{
-	// 646 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x55, 0xc1, 0x4e, 0xdb, 0x4c,
-	0x10, 0x66, 0x63, 0xe3, 0xe0, 0x89, 0x7e, 0x64, 0xf6, 0x57, 0xa9, 0x85, 0xaa, 0x80, 0xdc, 0x1e,
-	0x52, 0xd4, 0xc6, 0x25, 0xad, 0xaa, 0xaa, 0x52, 0x0f, 0xe0, 0x54, 0x88, 0xca, 0x32, 0xa9, 0x09,
-	0x55, 0xdb, 0x9b, 0x9d, 0x2c, 0xc6, 0xc2, 0xc9, 0x5a, 0x8e, 0x83, 0xe0, 0x15, 0xfa, 0x0e, 0x7d,
-	0x1f, 0x8e, 0x3c, 0x01, 0xa2, 0x79, 0x92, 0xca, 0x6b, 0x6f, 0x6c, 0x9c, 0x04, 0xb8, 0xf5, 0x94,
-	0x9d, 0xf9, 0xc6, 0xdf, 0xcc, 0xf7, 0xcd, 0xae, 0x02, 0xab, 0x03, 0x12, 0x3b, 0x7d, 0x27, 0x76,
-	0x9a, 0x61, 0x44, 0x63, 0x8a, 0x57, 0x78, 0xbc, 0xf1, 0xda, 0xf3, 0xe3, 0xd3, 0xb1, 0xdb, 0xec,
-	0xd1, 0x81, 0xee, 0x51, 0x8f, 0xea, 0xac, 0xc0, 0x1d, 0x9f, 0xb0, 0x88, 0x05, 0xec, 0x94, 0x7e,
-	0xa8, 0x1d, 0xc0, 0x7f, 0x6d, 0xeb, 0xe8, 0xd4, 0x89, 0xfa, 0x36, 0xe9, 0xd1, 0xa8, 0x8f, 0x55,
-	0xa8, 0xb2, 0xf0, 0xa0, 0xad, 0xa2, 0x2d, 0xd4, 0x10, 0x6d, 0x1e, 0xe2, 0x3a, 0x80, 0x49, 0x3d,
-	0x0e, 0x56, 0x18, 0x58, 0xc8, 0x68, 0xbf, 0x10, 0x54, 0x33, 0x2e, 0xbc, 0x5f, 0xa2, 0x65, 0x5c,
-	0xb5, 0xd6, 0xd3, 0xe6, 0x74, 0xee, 0x3b, 0xf0, 0xde, 0xca, 0xd5, 0xcd, 0xe6, 0xd2, 0xf5, 0xcd,
-	0x26, 0xb2, 0x4b, 0xe3, 0x3c, 0x03, 0xd9, 0x26, 0x61, 0xe0, 0xf7, 0x9c, 0x69, 0xcf, 0x3c, 0x91,
-	0x0c, 0xbb, 0xdb, 0xef, 0x47, 0x64, 0x34, 0x52, 0x85, 0x2d, 0xd4, 0x90, 0x6d, 0x1e, 0x6a, 0xdf,
-	0x60, 0x95, 0x8f, 0xf6, 0xa0, 0xb0, 0x6d, 0x50, 0xac, 0xf1, 0xc0, 0x25, 0xd1, 0xe1, 0x49, 0x46,
-	0x3d, 0xca, 0x5a, 0xcd, 0xe4, 0xb5, 0x18, 0x56, 0x38, 0x2f, 0xfe, 0x52, 0xee, 0x91, 0xa9, 0x54,
-	0x73, 0x95, 0x77, 0xf1, 0x82, 0xcc, 0xf2, 0x74, 0xf7, 0xea, 0xd4, 0x2c, 0xe6, 0x6c, 0x4c, 0x23,
-	0x82, 0x31, 0x88, 0xc7, 0xc7, 0x99, 0x06, 0xd9, 0x66, 0x67, 0xac, 0x83, 0xc4, 0xb8, 0x92, 0xb1,
-	0x85, 0x46, 0xad, 0xb5, 0x36, 0x63, 0xf3, 0x9e, 0x98, 0x74, 0xb6, 0xb3, 0x32, 0xad, 0x93, 0xaa,
-	0x58, 0x48, 0xf8, 0xa6, 0x44, 0x88, 0x67, 0x15, 0x95, 0x18, 0x0d, 0xa8, 0x1a, 0xf7, 0x4c, 0xf8,
-	0x02, 0x44, 0x9b, 0x06, 0x84, 0x29, 0x5b, 0x6d, 0x29, 0x39, 0x9d, 0x61, 0x25, 0x79, 0x9b, 0xa1,
-	0xda, 0x6d, 0x05, 0x64, 0xc3, 0x3a, 0x22, 0xd1, 0xb9, 0xdf, 0x23, 0x89, 0x25, 0xd9, 0x71, 0x4a,
-	0x96, 0x27, 0x70, 0x13, 0xb0, 0x49, 0x7b, 0x67, 0x59, 0x82, 0xdf, 0x82, 0x0a, 0x2b, 0x9b, 0x83,
-	0xe0, 0xf7, 0xb0, 0xde, 0xf1, 0x43, 0x12, 0xf8, 0x43, 0x52, 0xfa, 0x26, 0xbd, 0x39, 0x0b, 0xd0,
-	0xe4, 0xd6, 0x1f, 0x7d, 0x35, 0x79, 0xad, 0xc8, 0x6a, 0x0b, 0x99, 0x04, 0x37, 0xe2, 0x80, 0xe3,
-	0xcb, 0x29, 0x9e, 0x67, 0xf0, 0x27, 0x90, 0x4c, 0xc7, 0x25, 0xc1, 0x48, 0x95, 0x98, 0x95, 0x9b,
-	0x45, 0xed, 0x59, 0xaf, 0x66, 0x5a, 0xf1, 0x79, 0x18, 0x47, 0x97, 0xdc, 0xd7, 0x34, 0xb5, 0x61,
-	0x41, 0xad, 0x00, 0x62, 0x05, 0x84, 0x33, 0x72, 0x99, 0xb9, 0x91, 0x1c, 0xf1, 0x4b, 0x58, 0x3e,
-	0x77, 0x82, 0x71, 0x6a, 0x6d, 0xad, 0xf5, 0x7f, 0x61, 0x53, 0xc9, 0x77, 0xa6, 0x3f, 0x8a, 0xed,
-	0xb4, 0xe2, 0x63, 0xe5, 0x03, 0xd2, 0x7e, 0x0b, 0x20, 0xb7, 0x1f, 0x69, 0xf1, 0x2b, 0x58, 0xeb,
-	0x5e, 0x0c, 0xe7, 0x3a, 0x3c, 0x0b, 0xe0, 0x77, 0xf0, 0xc4, 0xa4, 0x5e, 0xd7, 0xf1, 0x83, 0xb9,
-	0xfe, 0xce, 0x07, 0x17, 0xac, 0x51, 0x5c, 0xb8, 0xc6, 0x87, 0xec, 0xce, 0x9f, 0x82, 0xf4, 0xa8,
-	0xa7, 0x50, 0xd8, 0x4f, 0xb5, 0xbc, 0x9f, 0xf6, 0x3f, 0xd8, 0xcf, 0x73, 0x90, 0xa7, 0x79, 0xbc,
-	0x3e, 0x9d, 0x0d, 0x6d, 0x09, 0x0d, 0x99, 0x37, 0xdd, 0xde, 0x81, 0x5a, 0x36, 0x59, 0xf7, 0x32,
-	0x24, 0x58, 0x82, 0x8a, 0x61, 0x29, 0x4b, 0xc9, 0x6f, 0xdb, 0x52, 0x10, 0xae, 0x82, 0x60, 0x1e,
-	0xee, 0x2b, 0x15, 0x2c, 0xc3, 0x72, 0xc7, 0x3e, 0xfc, 0xfe, 0x43, 0x11, 0xb6, 0x55, 0x90, 0xd2,
-	0xa7, 0x96, 0x54, 0x75, 0x3b, 0x69, 0xf5, 0x6e, 0x47, 0x41, 0x7b, 0xc6, 0xf5, 0x9f, 0x3a, 0xba,
-	0x9a, 0xd4, 0xd1, 0xf5, 0xa4, 0x8e, 0x6e, 0x27, 0x75, 0xf4, 0x73, 0xa7, 0xf0, 0x17, 0x32, 0x70,
-	0xe2, 0xc8, 0xbf, 0xa0, 0x91, 0xef, 0xf9, 0x43, 0x1e, 0x0c, 0x89, 0x1e, 0x9e, 0x79, 0x7a, 0xe8,
-	0xea, 0x5c, 0x8b, 0x2b, 0xb1, 0x7f, 0x93, 0xb7, 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xd1, 0xb9,
-	0x99, 0x4f, 0x98, 0x06, 0x00, 0x00,
+	// 701 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x55, 0xcd, 0x6e, 0xd3, 0x4c,
+	0x14, 0xed, 0xc4, 0x69, 0x12, 0xdf, 0x7c, 0x5f, 0xe5, 0x0e, 0xa2, 0x58, 0x15, 0x4a, 0x2b, 0xc3,
+	0x22, 0x44, 0x90, 0xd0, 0x82, 0x10, 0x42, 0x42, 0xa2, 0x75, 0x50, 0x55, 0x64, 0xb9, 0xc1, 0x49,
+	0xf9, 0xdb, 0x39, 0xc9, 0xd4, 0xb5, 0xe2, 0x78, 0x22, 0xc7, 0x29, 0xed, 0x2b, 0xb0, 0x65, 0xcd,
+	0xfb, 0x74, 0xd9, 0x27, 0xa8, 0xa0, 0x4f, 0x82, 0x66, 0xec, 0x89, 0x5d, 0x27, 0x69, 0xbb, 0x63,
+	0xe5, 0xb9, 0xf7, 0xdc, 0x39, 0x73, 0xce, 0xbd, 0x33, 0x32, 0xac, 0x0c, 0x49, 0x68, 0xf7, 0xed,
+	0xd0, 0xae, 0x8f, 0x02, 0x1a, 0x52, 0x5c, 0x12, 0xf1, 0xfa, 0x33, 0xc7, 0x0d, 0x8f, 0x27, 0xdd,
+	0x7a, 0x8f, 0x0e, 0x1b, 0x0e, 0x75, 0x68, 0x83, 0x17, 0x74, 0x27, 0x47, 0x3c, 0xe2, 0x01, 0x5f,
+	0x45, 0x1b, 0xb5, 0x7d, 0xf8, 0xbf, 0x69, 0xb6, 0x8f, 0xed, 0xa0, 0x6f, 0x91, 0x1e, 0x0d, 0xfa,
+	0x58, 0x85, 0x22, 0x0f, 0xf7, 0x9b, 0x2a, 0xda, 0x44, 0xd5, 0xbc, 0x25, 0x42, 0x5c, 0x01, 0x30,
+	0xa8, 0x23, 0xc0, 0x1c, 0x07, 0x53, 0x19, 0xed, 0x07, 0x82, 0x62, 0xcc, 0x85, 0xf7, 0x32, 0xb4,
+	0x9c, 0xab, 0xbc, 0xfd, 0xa0, 0x3e, 0xd5, 0x7d, 0x0d, 0xde, 0x2d, 0x9d, 0x5f, 0x6e, 0x2c, 0x5d,
+	0x5c, 0x6e, 0x20, 0x2b, 0x23, 0xe7, 0x21, 0xc8, 0x16, 0x19, 0x79, 0x6e, 0xcf, 0x9e, 0x9e, 0x99,
+	0x24, 0x98, 0xd8, 0x9d, 0x7e, 0x3f, 0x20, 0xe3, 0xb1, 0x2a, 0x6d, 0xa2, 0xaa, 0x6c, 0x89, 0x50,
+	0xfb, 0x04, 0x2b, 0x42, 0xda, 0xad, 0xc6, 0x6a, 0xa0, 0x98, 0x93, 0x61, 0x97, 0x04, 0x07, 0x47,
+	0x31, 0xf5, 0x38, 0x3e, 0x6a, 0x26, 0xaf, 0x85, 0x50, 0x12, 0xbc, 0xf8, 0x43, 0xf6, 0x8c, 0xd8,
+	0xa5, 0x9a, 0xb8, 0xbc, 0x8e, 0xa7, 0x6c, 0x66, 0xd5, 0xdd, 0xe8, 0x53, 0x33, 0x79, 0x67, 0x43,
+	0x1a, 0x10, 0x8c, 0x21, 0x7f, 0x78, 0x18, 0x7b, 0x90, 0x2d, 0xbe, 0xc6, 0x0d, 0x28, 0x70, 0x2e,
+	0x26, 0x5b, 0xaa, 0x96, 0xb7, 0x57, 0x67, 0xda, 0xbc, 0x9b, 0x67, 0x27, 0x5b, 0x71, 0x99, 0xd6,
+	0x8a, 0x5c, 0x2c, 0x24, 0x7c, 0x9e, 0x21, 0xc4, 0xb3, 0x8e, 0x32, 0x8c, 0x3a, 0x14, 0xf5, 0x1b,
+	0x14, 0x3e, 0x86, 0xbc, 0x45, 0x3d, 0xc2, 0x9d, 0xad, 0x6c, 0x2b, 0x09, 0x9d, 0x6e, 0xb2, 0xbc,
+	0xc5, 0x51, 0xed, 0xa7, 0x04, 0xb2, 0x6e, 0xb6, 0x49, 0x70, 0xe2, 0xf6, 0x08, 0x6b, 0x49, 0xbc,
+	0x9c, 0x92, 0x25, 0x09, 0x5c, 0x07, 0x6c, 0xd0, 0xde, 0x20, 0x4e, 0x88, 0x5b, 0x90, 0xe3, 0x65,
+	0x73, 0x10, 0xfc, 0x0a, 0xd6, 0x5a, 0xee, 0x88, 0x78, 0xae, 0x4f, 0x32, 0x7b, 0xa2, 0x9b, 0xb3,
+	0x00, 0x65, 0xb7, 0xbe, 0xfd, 0xd1, 0x10, 0xb5, 0x79, 0x5e, 0x9b, 0xca, 0x30, 0x5c, 0x0f, 0x3d,
+	0x81, 0x2f, 0x47, 0x78, 0x92, 0xc1, 0x5b, 0x20, 0x7f, 0xa6, 0xc1, 0xa0, 0x1d, 0xda, 0x21, 0x51,
+	0x0b, 0xdc, 0xfe, 0xbd, 0xc4, 0xfe, 0x14, 0xb2, 0x92, 0x2a, 0xfc, 0x16, 0x0a, 0x86, 0xdd, 0x25,
+	0xde, 0x58, 0x2d, 0xf2, 0xee, 0x6f, 0xa4, 0xdb, 0x15, 0xcb, 0xab, 0x47, 0x15, 0xef, 0xfd, 0x30,
+	0x38, 0x13, 0xa3, 0x88, 0x52, 0xeb, 0x26, 0x94, 0x53, 0x20, 0x56, 0x40, 0x1a, 0x90, 0xb3, 0xb8,
+	0x81, 0x6c, 0x89, 0x9f, 0xc0, 0xf2, 0x89, 0xed, 0x4d, 0xa2, 0x69, 0x94, 0xd3, 0x72, 0xf8, 0x3e,
+	0xc3, 0x1d, 0x87, 0x56, 0x54, 0xf1, 0x26, 0xf7, 0x1a, 0x69, 0xbf, 0x24, 0x90, 0x9b, 0x77, 0x9c,
+	0xca, 0x53, 0x58, 0xed, 0x9c, 0xfa, 0x73, 0x87, 0x32, 0x0b, 0xe0, 0x97, 0x70, 0xdf, 0xa0, 0x4e,
+	0xc7, 0x76, 0xbd, 0xb9, 0x23, 0x99, 0x0f, 0x2e, 0x98, 0x7c, 0x7e, 0xe1, 0xe4, 0x6f, 0x9b, 0x50,
+	0xf2, 0x7a, 0x0a, 0x77, 0x7a, 0x3d, 0x37, 0xcd, 0xa7, 0xf9, 0x0f, 0xe6, 0xf3, 0x08, 0xe4, 0x69,
+	0x1e, 0xaf, 0x4d, 0xb5, 0xa1, 0x4d, 0xa9, 0x2a, 0x8b, 0x43, 0x6b, 0x5b, 0x50, 0x8e, 0x95, 0x75,
+	0xce, 0x46, 0x04, 0x17, 0x20, 0xa7, 0x9b, 0xca, 0x12, 0xfb, 0x36, 0x4d, 0x05, 0xe1, 0x22, 0x48,
+	0xc6, 0xc1, 0x9e, 0x92, 0xc3, 0x32, 0x2c, 0xb7, 0xac, 0x83, 0x2f, 0x5f, 0x15, 0xa9, 0xa6, 0x42,
+	0x21, 0x7a, 0x9d, 0xac, 0xaa, 0xd3, 0x8a, 0xaa, 0x77, 0x5a, 0x0a, 0xaa, 0xbd, 0x4b, 0xdd, 0x69,
+	0x5c, 0x86, 0xe2, 0xa1, 0x3f, 0xf0, 0xe9, 0x77, 0x5f, 0x59, 0x62, 0x01, 0x43, 0x5c, 0xdf, 0x51,
+	0x10, 0xfe, 0x0f, 0x4a, 0xcd, 0xc0, 0x76, 0x7d, 0x16, 0xe5, 0x18, 0xc4, 0x23, 0xd2, 0x57, 0xa4,
+	0x5d, 0xfd, 0xe2, 0x4f, 0x05, 0x9d, 0x5f, 0x55, 0xd0, 0xc5, 0x55, 0x05, 0xfd, 0xbe, 0xaa, 0xa0,
+	0x6f, 0x5b, 0xa9, 0xff, 0xd6, 0xd0, 0x0e, 0x03, 0xf7, 0x94, 0x06, 0xae, 0xe3, 0xfa, 0x22, 0xf0,
+	0x49, 0x63, 0x34, 0x70, 0x1a, 0xa3, 0x6e, 0x43, 0x74, 0xa3, 0x5b, 0xe0, 0xbf, 0xb0, 0x17, 0x7f,
+	0x03, 0x00, 0x00, 0xff, 0xff, 0x5f, 0x07, 0x99, 0xbc, 0x0d, 0x07, 0x00, 0x00,
 }
 
 func (m *DNShardRecord) Marshal() (dAtA []byte, err error) {
@@ -1149,9 +1194,14 @@ func (m *CNService) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 			dAtA[i] = 0xa
 			i = encodeVarintMetadata(dAtA, i, uint64(baseI-i))
 			i--
-			dAtA[i] = 0x32
+			dAtA[i] = 0x3a
 		}
 	}
+	if m.WorkState != 0 {
+		i = encodeVarintMetadata(dAtA, i, uint64(m.WorkState))
+		i--
+		dAtA[i] = 0x30
+	}
 	if len(m.CtlAddress) > 0 {
 		i -= len(m.CtlAddress)
 		copy(dAtA[i:], m.CtlAddress)
@@ -1500,6 +1550,9 @@ func (m *CNService) Size() (n int) {
 	if l > 0 {
 		n += 1 + l + sovMetadata(uint64(l))
 	}
+	if m.WorkState != 0 {
+		n += 1 + sovMetadata(uint64(m.WorkState))
+	}
 	if len(m.Labels) > 0 {
 		for k, v := range m.Labels {
 			_ = k
@@ -2528,6 +2581,25 @@ func (m *CNService) Unmarshal(dAtA []byte) error {
 			m.CtlAddress = string(dAtA[iNdEx:postIndex])
 			iNdEx = postIndex
 		case 6:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field WorkState", wireType)
+			}
+			m.WorkState = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowMetadata
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				m.WorkState |= WorkState(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+		case 7:
 			if wireType != 2 {
 				return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType)
 			}
diff --git a/proto/logservice.proto b/proto/logservice.proto
index f75341cc2..3ca83fba8 100644
--- a/proto/logservice.proto
+++ b/proto/logservice.proto
@@ -44,7 +44,8 @@ message CNStore {
   metadata.CNRole Role               = 6;
   uint64          Tick               = 7;
   NodeState       State              = 8;
-  map<string, metadata.LabelList> Labels = 9 [(gogoproto.nullable) = false];
+  metadata.WorkState WorkState           = 9;
+  map<string, metadata.LabelList> Labels = 10 [(gogoproto.nullable) = false];
 }
 
 message DNStore {
@@ -76,15 +77,15 @@ message LogShardInfo {
   // ShardID is the ID of a Log shard.
   uint64 ShardID               = 1;
   // Replicas is a map of ReplicaID to LogStore UUID, it describe the member
-  // replicas of the shard at the given Epoch. 
+  // replicas of the shard at the given Epoch.
   map<uint64, string> Replicas = 2;
   // Epoch is the epoch value of the Shard, member replicas of the Shard can
-  // change across epochs. 
+  // change across epochs.
   uint64 Epoch                 = 3;
   // LeaderID is the ReplicaID of the leader replica at the given term. When
   // LeaderID is 0, it means there is no leader or the leader is unknown.
   uint64 LeaderID              = 4;
-  // Term is the Raft term value. 
+  // Term is the Raft term value.
   uint64 Term                  = 5;
 
   // TODO: per shard stats like CPU/memory/network usage can be added here
@@ -127,16 +128,16 @@ message LogStoreHeartbeat {
   // Replicas is a list of LogReplicaInfo instances collected on the specified
   // LogStore. Details in Shards are based on the local knowledge of each
   // replica running on the current LogStore, it may not be accurate or
-  // update to date due to various reasons. 
+  // update to date due to various reasons.
   repeated LogReplicaInfo Replicas = 5 [(gogoproto.nullable) = false];
   // TaskServiceCreated task service is created at the current log node
   bool            TaskServiceCreated    = 6;
 };
 
-// DNShardInfo contains information of a launched DN shard. 
+// DNShardInfo contains information of a launched DN shard.
 message DNShardInfo {
   // ShardID uniquely identifies a DN shard. Each DN shard manages a Primary
-  // Key range or hashed Primary Key value range. 
+  // Key range or hashed Primary Key value range.
   uint64 ShardID                 = 1;
   // ReplicaID uniquely identifies a DN shard instance. After repairing a
   // failed DN shard, a new DN shard instance is created with a new ReplicaID
@@ -149,10 +150,10 @@ message DNShardInfo {
 // DNStoreHeartbeat is the periodic message sent to the HAKeeper by DN stores.
 message DNStoreHeartbeat {
   // UUID is the uuid of the DN Store.
-  string UUID                 = 1; 
+  string UUID                 = 1;
   string ServiceAddress       = 2;
   // Shards is a list of DNShardInfo instances collected on the specified
-  // DN store. 
+  // DN store.
   repeated DNShardInfo Shards = 3 [(gogoproto.nullable) = false];
   bool            TaskServiceCreated = 4;
 
@@ -188,6 +189,8 @@ enum MethodType {
   CN_ALLOCATE_ID = 13;
   GET_CLUSTER_STATE = 14;
   UPDATE_CN_LABEL = 15;
+  UPDATE_CN_WORK_STATE = 16;
+  PATCH_CN_STORE = 17;
 };
 
 enum RecordType {
@@ -232,6 +235,22 @@ message CNStoreLabel {
   map<string, metadata.LabelList> Labels = 3 [(gogoproto.nullable) = false];
 }
 
+message CNWorkState {
+  // UUID is the uuid of the CN store.
+  string UUID     = 1;
+  // State is the CN work state.
+  metadata.WorkState State = 2;
+}
+
+message CNStateLabel {
+  // UUID is the uuid of the CN store.
+  string UUID     = 1;
+  // State is the CN work state.
+  metadata.WorkState State = 2;
+  // Labels is the labels of the CN store.
+  map<string, metadata.LabelList> Labels = 3 [(gogoproto.nullable) = false];
+}
+
 message Request {
   uint64 RequestID               = 1;
   MethodType Method              = 2;
@@ -242,6 +261,8 @@ message Request {
   TsoRequest TsoRequest          = 7;
   CNAllocateID CNAllocateID      = 8;
   CNStoreLabel CNStoreLabel      = 9;
+  CNWorkState CNWorkState        = 10;
+  CNStateLabel CNStateLabel      = 11;
 };
 
 message LogResponse {
@@ -293,6 +314,8 @@ enum HAKeeperUpdateType {
   SetTaskSchedulerStateUpdate  = 8;
   SetTaskTableUserUpdate       = 9;
   UpdateCNLabel = 10;
+  UpdateCNWorkState = 11;
+  PatchCNStore = 12;
 }
 
 // HAKeeperState state transition diagram
@@ -425,7 +448,8 @@ message CNStoreInfo {
   string          CtlAddress         = 5;
   metadata.CNRole Role               = 6;
   bool            TaskServiceCreated = 7;
-  map<string, metadata.LabelList> Labels = 8 [(gogoproto.nullable) = false];
+  metadata.WorkState WorkState       = 8;
+  map<string, metadata.LabelList> Labels = 9 [(gogoproto.nullable) = false];
 }
 
 // CNState contains all CN details known to the HAKeeper.
diff --git a/proto/metadata.proto b/proto/metadata.proto
index 550aaee53..7b7bdbaab 100644
--- a/proto/metadata.proto
+++ b/proto/metadata.proto
@@ -118,8 +118,10 @@ message CNService {
   string SQLAddress             = 4;
   // CtlAddress is used to handle ctl request.
   string CtlAddress             = 5;
-  // Labels lables on service
-  map<string, LabelList> Labels = 6 [(gogoproto.nullable) = false];
+  // WorkState is the work state of CN service.
+  WorkState WorkState           = 6;
+  // Labels are labels on CN service.
+  map<string, LabelList> Labels = 7 [(gogoproto.nullable) = false];
 }
 
 // DNService dn service metadata
@@ -144,3 +146,12 @@ message DNService {
 message LabelList {
   repeated string Labels = 1;
 }
+
+// WorkState is the work state of CN service.
+enum WorkState {
+  Unknown  = 0;
+  Working  = 1;
+  Draining = 2;
+  Drained  = 3;
+}
+


Test patch:
diff --git a/pkg/frontend/mysql_cmd_executor_test.go b/pkg/frontend/mysql_cmd_executor_test.go
index c095e150e..10a4f7e19 100644
--- a/pkg/frontend/mysql_cmd_executor_test.go
+++ b/pkg/frontend/mysql_cmd_executor_test.go
@@ -1256,7 +1256,7 @@ func TestMysqlCmdExecutor_HandleShowBackendServers(t *testing.T) {
 		err = mce.handleShowBackendServers(ctx, 0, 1)
 		require.NoError(t, err)
 		rs := ses.GetMysqlResultSet()
-		require.Equal(t, uint64(3), rs.GetColumnCount())
+		require.Equal(t, uint64(4), rs.GetColumnCount())
 		require.Equal(t, uint64(2), rs.GetRowCount())
 	})
 
@@ -1297,7 +1297,7 @@ func TestMysqlCmdExecutor_HandleShowBackendServers(t *testing.T) {
 		err = mce.handleShowBackendServers(ctx, 0, 1)
 		require.NoError(t, err)
 		rs := ses.GetMysqlResultSet()
-		require.Equal(t, uint64(3), rs.GetColumnCount())
+		require.Equal(t, uint64(4), rs.GetColumnCount())
 		require.Equal(t, uint64(1), rs.GetRowCount())
 
 		row, err := rs.GetRow(ctx, 0)
diff --git a/pkg/hakeeper/rsm_test.go b/pkg/hakeeper/rsm_test.go
index ef6a7507e..8abab2078 100644
--- a/pkg/hakeeper/rsm_test.go
+++ b/pkg/hakeeper/rsm_test.go
@@ -726,3 +726,184 @@ func TestHandleUpdateCNLabel(t *testing.T) {
 	assert.True(t, ok)
 	assert.Equal(t, labels.Labels, []string{"1", "2"})
 }
+
+func TestHandleUpdateCNWorkState(t *testing.T) {
+	uuid := "uuid1"
+	tsm1 := NewStateMachine(0, 1).(*stateMachine)
+	state := pb.CNWorkState{
+		UUID:  uuid,
+		State: metadata.WorkState_Unknown,
+	}
+	cmd := GetUpdateCNWorkStateCmd(state)
+	_, err := tsm1.Update(sm.Entry{Cmd: cmd})
+	assert.NoError(t, err)
+
+	s := tsm1.state.CNState
+	assert.Equal(t, 0, len(s.Stores))
+
+	cmd = GetTickCmd()
+	_, err = tsm1.Update(sm.Entry{Cmd: cmd})
+	assert.NoError(t, err)
+
+	hb := pb.CNStoreHeartbeat{
+		UUID: uuid,
+	}
+	data, err := hb.Marshal()
+	require.NoError(t, err)
+	cmd = GetCNStoreHeartbeatCmd(data)
+	_, err = tsm1.Update(sm.Entry{Cmd: cmd})
+	assert.NoError(t, err)
+	s = tsm1.state.CNState
+	assert.Equal(t, 1, len(s.Stores))
+
+	state = pb.CNWorkState{
+		UUID:  uuid,
+		State: metadata.WorkState_Working,
+	}
+	cmd = GetUpdateCNWorkStateCmd(state)
+	_, err = tsm1.Update(sm.Entry{Cmd: cmd})
+	assert.NoError(t, err)
+
+	s = tsm1.state.CNState
+	assert.Equal(t, 1, len(s.Stores))
+	info, ok := s.Stores[uuid]
+	assert.True(t, ok)
+	assert.Equal(t, metadata.WorkState_Working, info.WorkState)
+
+	state = pb.CNWorkState{
+		UUID:  uuid,
+		State: metadata.WorkState_Unknown,
+	}
+	cmd = GetUpdateCNWorkStateCmd(state)
+	_, err = tsm1.Update(sm.Entry{Cmd: cmd})
+	assert.NoError(t, err)
+
+	s = tsm1.state.CNState
+	assert.Equal(t, 1, len(s.Stores))
+	info, ok = s.Stores[uuid]
+	assert.True(t, ok)
+	assert.Equal(t, metadata.WorkState_Working, info.WorkState)
+
+	state = pb.CNWorkState{
+		UUID:  uuid,
+		State: metadata.WorkState_Draining,
+	}
+	cmd = GetUpdateCNWorkStateCmd(state)
+	_, err = tsm1.Update(sm.Entry{Cmd: cmd})
+	assert.NoError(t, err)
+
+	s = tsm1.state.CNState
+	assert.Equal(t, 1, len(s.Stores))
+	info, ok = s.Stores[uuid]
+	assert.True(t, ok)
+	assert.Equal(t, metadata.WorkState_Draining, info.WorkState)
+}
+
+func TestHandlePatchCNStore(t *testing.T) {
+	uuid := "uuid1"
+	tsm1 := NewStateMachine(0, 1).(*stateMachine)
+	stateLabel := pb.CNStateLabel{
+		UUID:  uuid,
+		State: metadata.WorkState_Unknown,
+		Labels: map[string]metadata.LabelList{
+			"account": {Labels: []string{"a", "b"}},
+			"role":    {Labels: []string{"1", "2"}},
+		},
+	}
+	cmd := GetPatchCNStoreCmd(stateLabel)
+	_, err := tsm1.Update(sm.Entry{Cmd: cmd})
+	assert.NoError(t, err)
+
+	s := tsm1.state.CNState
+	assert.Equal(t, 0, len(s.Stores))
+
+	cmd = GetTickCmd()
+	_, err = tsm1.Update(sm.Entry{Cmd: cmd})
+	assert.NoError(t, err)
+
+	hb := pb.CNStoreHeartbeat{
+		UUID: uuid,
+	}
+	data, err := hb.Marshal()
+	require.NoError(t, err)
+	cmd = GetCNStoreHeartbeatCmd(data)
+	_, err = tsm1.Update(sm.Entry{Cmd: cmd})
+	assert.NoError(t, err)
+	s = tsm1.state.CNState
+	assert.Equal(t, 1, len(s.Stores))
+
+	cmd = GetPatchCNStoreCmd(stateLabel)
+	_, err = tsm1.Update(sm.Entry{Cmd: cmd})
+	assert.NoError(t, err)
+
+	s = tsm1.state.CNState
+	assert.Equal(t, 1, len(s.Stores))
+	info, ok := s.Stores[uuid]
+	assert.True(t, ok)
+	assert.Equal(t, metadata.WorkState_Working, info.WorkState)
+	labels, ok := info.Labels["account"]
+	assert.True(t, ok)
+	assert.Equal(t, labels.Labels, []string{"a", "b"})
+	labels, ok = info.Labels["role"]
+	assert.True(t, ok)
+	assert.Equal(t, labels.Labels, []string{"1", "2"})
+
+	stateLabel = pb.CNStateLabel{
+		UUID:  uuid,
+		State: metadata.WorkState_Working,
+	}
+	cmd = GetPatchCNStoreCmd(stateLabel)
+	_, err = tsm1.Update(sm.Entry{Cmd: cmd})
+	assert.NoError(t, err)
+
+	s = tsm1.state.CNState
+	assert.Equal(t, 1, len(s.Stores))
+	info, ok = s.Stores[uuid]
+	assert.True(t, ok)
+	assert.Equal(t, metadata.WorkState_Working, info.WorkState)
+	labels, ok = info.Labels["account"]
+	assert.True(t, ok)
+	assert.Equal(t, labels.Labels, []string{"a", "b"})
+	labels, ok = info.Labels["role"]
+	assert.True(t, ok)
+	assert.Equal(t, labels.Labels, []string{"1", "2"})
+
+	stateLabel = pb.CNStateLabel{
+		UUID: uuid,
+		Labels: map[string]metadata.LabelList{
+			"role": {Labels: []string{"1", "2"}},
+		},
+	}
+	cmd = GetPatchCNStoreCmd(stateLabel)
+	_, err = tsm1.Update(sm.Entry{Cmd: cmd})
+	assert.NoError(t, err)
+
+	s = tsm1.state.CNState
+	assert.Equal(t, 1, len(s.Stores))
+	info, ok = s.Stores[uuid]
+	assert.True(t, ok)
+	assert.Equal(t, metadata.WorkState_Working, info.WorkState)
+	_, ok = info.Labels["account"]
+	assert.False(t, ok)
+	labels, ok = info.Labels["role"]
+	assert.True(t, ok)
+	assert.Equal(t, labels.Labels, []string{"1", "2"})
+
+	stateLabel = pb.CNStateLabel{
+		UUID:  uuid,
+		State: metadata.WorkState_Draining,
+	}
+	cmd = GetPatchCNStoreCmd(stateLabel)
+	_, err = tsm1.Update(sm.Entry{Cmd: cmd})
+	assert.NoError(t, err)
+	s = tsm1.state.CNState
+	assert.Equal(t, 1, len(s.Stores))
+	info, ok = s.Stores[uuid]
+	assert.True(t, ok)
+	assert.Equal(t, metadata.WorkState_Draining, info.WorkState)
+	_, ok = info.Labels["account"]
+	assert.False(t, ok)
+	labels, ok = info.Labels["role"]
+	assert.True(t, ok)
+	assert.Equal(t, labels.Labels, []string{"1", "2"})
+}
diff --git a/pkg/logservice/hakeeper_client_test.go b/pkg/logservice/hakeeper_client_test.go
index a01c02e22..81821228d 100644
--- a/pkg/logservice/hakeeper_client_test.go
+++ b/pkg/logservice/hakeeper_client_test.go
@@ -194,6 +194,7 @@ func TestHAKeeperClientSendCNHeartbeat(t *testing.T) {
 		cn := pb.CNStore{
 			UUID:           s.ID(),
 			ServiceAddress: "addr1",
+			WorkState:      metadata.WorkState_Working,
 		}
 		dn := pb.DNStore{
 			UUID:                 s.ID(),
@@ -486,3 +487,173 @@ func TestHAKeeperClientUpdateCNLabel(t *testing.T) {
 	}
 	runServiceTest(t, true, true, fn)
 }
+
+func TestHAKeeperClientUpdateCNWorkState(t *testing.T) {
+	fn := func(t *testing.T, s *Service) {
+		cfg := HAKeeperClientConfig{
+			ServiceAddresses: []string{testServiceAddress},
+		}
+		ctx, cancel := context.WithTimeout(context.Background(), time.Second)
+		defer cancel()
+		c1, err := NewProxyHAKeeperClient(ctx, cfg)
+		require.NoError(t, err)
+		c2, err := NewCNHAKeeperClient(ctx, cfg)
+		require.NoError(t, err)
+		defer func() {
+			assert.NoError(t, c1.Close())
+			assert.NoError(t, c2.Close())
+		}()
+
+		workState := pb.CNWorkState{
+			UUID:  s.ID(),
+			State: metadata.WorkState_Unknown,
+		}
+		err = c1.UpdateCNWorkState(ctx, workState)
+		require.Error(t, err)
+
+		hb := pb.CNStoreHeartbeat{
+			UUID:           s.ID(),
+			ServiceAddress: "addr1",
+		}
+		_, err = c2.SendCNHeartbeat(ctx, hb)
+		require.NoError(t, err)
+
+		workState = pb.CNWorkState{
+			UUID:  s.ID(),
+			State: metadata.WorkState_Working,
+		}
+		err = c1.UpdateCNWorkState(ctx, workState)
+		require.NoError(t, err)
+
+		state, err := c1.GetClusterState(ctx)
+		require.NoError(t, err)
+		info, ok1 := state.CNState.Stores[s.ID()]
+		assert.True(t, ok1)
+		require.Equal(t, metadata.WorkState_Working, info.WorkState)
+
+		workState = pb.CNWorkState{
+			UUID:  s.ID(),
+			State: metadata.WorkState_Draining,
+		}
+		err = c1.UpdateCNWorkState(ctx, workState)
+		require.NoError(t, err)
+
+		state, err = c1.GetClusterState(ctx)
+		require.NoError(t, err)
+		info, ok1 = state.CNState.Stores[s.ID()]
+		assert.True(t, ok1)
+		require.Equal(t, metadata.WorkState_Draining, info.WorkState)
+
+		workState = pb.CNWorkState{
+			UUID:  s.ID(),
+			State: metadata.WorkState_Working,
+		}
+		err = c1.UpdateCNWorkState(ctx, workState)
+		require.NoError(t, err)
+
+		state, err = c1.GetClusterState(ctx)
+		require.NoError(t, err)
+		info, ok1 = state.CNState.Stores[s.ID()]
+		assert.True(t, ok1)
+		require.Equal(t, metadata.WorkState_Draining, info.WorkState)
+	}
+	runServiceTest(t, true, true, fn)
+}
+
+func TestHAKeeperClientPatchCNStore(t *testing.T) {
+	fn := func(t *testing.T, s *Service) {
+		cfg := HAKeeperClientConfig{
+			ServiceAddresses: []string{testServiceAddress},
+		}
+		ctx, cancel := context.WithTimeout(context.Background(), time.Second)
+		defer cancel()
+		c1, err := NewProxyHAKeeperClient(ctx, cfg)
+		require.NoError(t, err)
+		c2, err := NewCNHAKeeperClient(ctx, cfg)
+		require.NoError(t, err)
+		defer func() {
+			assert.NoError(t, c1.Close())
+			assert.NoError(t, c2.Close())
+		}()
+
+		stateLabel := pb.CNStateLabel{
+			UUID:  s.ID(),
+			State: metadata.WorkState_Unknown,
+			Labels: map[string]metadata.LabelList{
+				"account": {Labels: []string{"a", "b"}},
+				"role":    {Labels: []string{"1", "2"}},
+			},
+		}
+		err = c1.PatchCNStore(ctx, stateLabel)
+		require.Error(t, err)
+
+		hb := pb.CNStoreHeartbeat{
+			UUID:           s.ID(),
+			ServiceAddress: "addr1",
+		}
+		_, err = c2.SendCNHeartbeat(ctx, hb)
+		require.NoError(t, err)
+
+		stateLabel = pb.CNStateLabel{
+			UUID:  s.ID(),
+			State: metadata.WorkState_Working,
+			Labels: map[string]metadata.LabelList{
+				"account": {Labels: []string{"a", "b"}},
+				"role":    {Labels: []string{"1", "2"}},
+			},
+		}
+		err = c1.PatchCNStore(ctx, stateLabel)
+		require.NoError(t, err)
+
+		state, err := c1.GetClusterState(ctx)
+		require.NoError(t, err)
+		info, ok1 := state.CNState.Stores[s.ID()]
+		assert.True(t, ok1)
+		require.Equal(t, metadata.WorkState_Working, info.WorkState)
+		labels1, ok2 := info.Labels["account"]
+		assert.True(t, ok2)
+		assert.Equal(t, labels1.Labels, []string{"a", "b"})
+		labels2, ok3 := info.Labels["role"]
+		assert.True(t, ok3)
+		assert.Equal(t, labels2.Labels, []string{"1", "2"})
+
+		stateLabel = pb.CNStateLabel{
+			UUID:  s.ID(),
+			State: metadata.WorkState_Draining,
+		}
+		err = c1.PatchCNStore(ctx, stateLabel)
+		require.NoError(t, err)
+
+		state, err = c1.GetClusterState(ctx)
+		require.NoError(t, err)
+		info, ok1 = state.CNState.Stores[s.ID()]
+		assert.True(t, ok1)
+		require.Equal(t, metadata.WorkState_Draining, info.WorkState)
+		labels1, ok2 = info.Labels["account"]
+		assert.True(t, ok2)
+		labels2, ok3 = info.Labels["role"]
+		assert.True(t, ok3)
+		assert.Equal(t, labels2.Labels, []string{"1", "2"})
+
+		stateLabel = pb.CNStateLabel{
+			UUID: s.ID(),
+			Labels: map[string]metadata.LabelList{
+				"account": {Labels: []string{"a", "b"}},
+			},
+		}
+		err = c1.PatchCNStore(ctx, stateLabel)
+		require.NoError(t, err)
+
+		state, err = c1.GetClusterState(ctx)
+		require.NoError(t, err)
+		info, ok1 = state.CNState.Stores[s.ID()]
+		assert.True(t, ok1)
+		require.Equal(t, metadata.WorkState_Draining, info.WorkState)
+		labels1, ok2 = info.Labels["account"]
+		assert.True(t, ok2)
+		assert.Equal(t, labels1.Labels, []string{"a", "b"})
+		labels2, ok3 = info.Labels["role"]
+		assert.False(t, ok3)
+	}
+	runServiceTest(t, true, true, fn)
+}
diff --git a/pkg/logservice/service_test.go b/pkg/logservice/service_test.go
index 52c70cf91..8245b4e9f 100644
--- a/pkg/logservice/service_test.go
+++ b/pkg/logservice/service_test.go
@@ -17,7 +17,6 @@ package logservice
 import (
 	"context"
 	"fmt"
-	"github.com/matrixorigin/matrixone/pkg/pb/metadata"
 	"runtime/debug"
 	"sync"
 	"testing"
@@ -31,6 +30,7 @@ import (
 	"github.com/matrixorigin/matrixone/pkg/common/morpc"
 	hapkg "github.com/matrixorigin/matrixone/pkg/hakeeper"
 	pb "github.com/matrixorigin/matrixone/pkg/pb/logservice"
+	"github.com/matrixorigin/matrixone/pkg/pb/metadata"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 )
@@ -905,3 +905,181 @@ func TestServiceHandleCNUpdateLabel(t *testing.T) {
 	}
 	runServiceTest(t, true, true, fn)
 }
+
+func TestServiceHandleCNUpdateWorkState(t *testing.T) {
+	fn := func(t *testing.T, s *Service) {
+		uuid := "uuid1"
+		ctx0, cancel0 := context.WithTimeout(context.Background(), time.Second)
+		defer cancel0()
+		req := pb.Request{
+			Method: pb.UPDATE_CN_WORK_STATE,
+			CNWorkState: &pb.CNWorkState{
+				UUID:  uuid,
+				State: metadata.WorkState_Working,
+			},
+		}
+		resp := s.handleUpdateCNWorkState(ctx0, req)
+		assert.Equal(t, uint32(20101), resp.ErrorCode)
+		assert.Equal(t, fmt.Sprintf("internal error: CN [%s] does not exist", uuid), resp.ErrorMessage)
+
+		ctx1, cancel1 := context.WithTimeout(context.Background(), time.Second)
+		defer cancel1()
+		req = pb.Request{
+			Method: pb.CN_HEARTBEAT,
+			CNHeartbeat: &pb.CNStoreHeartbeat{
+				UUID: uuid,
+			},
+		}
+		resp = s.handleCNHeartbeat(ctx1, req)
+		assert.Equal(t, &pb.CommandBatch{}, resp.CommandBatch)
+		assert.Equal(t, uint32(moerr.Ok), resp.ErrorCode)
+
+		ctx2, cancel2 := context.WithTimeout(context.Background(), time.Second)
+		defer cancel2()
+		req = pb.Request{
+			Method: pb.UPDATE_CN_WORK_STATE,
+			CNWorkState: &pb.CNWorkState{
+				UUID:  uuid,
+				State: metadata.WorkState_Working,
+			},
+		}
+		resp = s.handleUpdateCNWorkState(ctx2, req)
+		assert.Equal(t, uint32(moerr.Ok), resp.ErrorCode)
+
+		ctx3, cancel3 := context.WithTimeout(context.Background(), time.Second)
+		defer cancel3()
+		req = pb.Request{
+			Method: pb.GET_CLUSTER_STATE,
+		}
+		resp = s.handleGetCheckerState(ctx3, req)
+		assert.Equal(t, uint32(moerr.Ok), resp.ErrorCode)
+		assert.NotEmpty(t, resp.CheckerState)
+		info, ok1 := resp.CheckerState.CNState.Stores[uuid]
+		assert.True(t, ok1)
+		assert.Equal(t, metadata.WorkState_Working, info.WorkState)
+
+		ctx4, cancel4 := context.WithTimeout(context.Background(), time.Second)
+		defer cancel4()
+		req = pb.Request{
+			Method: pb.UPDATE_CN_WORK_STATE,
+			CNWorkState: &pb.CNWorkState{
+				UUID:  uuid,
+				State: metadata.WorkState_Unknown,
+			},
+		}
+		resp = s.handleUpdateCNWorkState(ctx4, req)
+		assert.Equal(t, uint32(moerr.Ok), resp.ErrorCode)
+
+		ctx5, cancel5 := context.WithTimeout(context.Background(), time.Second)
+		defer cancel5()
+		req = pb.Request{
+			Method: pb.GET_CLUSTER_STATE,
+		}
+		resp = s.handleGetCheckerState(ctx5, req)
+		assert.Equal(t, uint32(moerr.Ok), resp.ErrorCode)
+		assert.NotEmpty(t, resp.CheckerState)
+		info, ok1 = resp.CheckerState.CNState.Stores[uuid]
+		assert.True(t, ok1)
+		assert.Equal(t, metadata.WorkState_Working, info.WorkState)
+	}
+	runServiceTest(t, true, true, fn)
+}
+
+func TestServiceHandleCNPatchStore(t *testing.T) {
+	fn := func(t *testing.T, s *Service) {
+		uuid := "uuid1"
+		ctx0, cancel0 := context.WithTimeout(context.Background(), time.Second)
+		defer cancel0()
+		req := pb.Request{
+			Method: pb.PATCH_CN_STORE,
+			CNStateLabel: &pb.CNStateLabel{
+				UUID:  uuid,
+				State: metadata.WorkState_Working,
+				Labels: map[string]metadata.LabelList{
+					"account": {Labels: []string{"a", "b"}},
+					"role":    {Labels: []string{"1", "2"}},
+				},
+			},
+		}
+		resp := s.handlePatchCNStore(ctx0, req)
+		assert.Equal(t, uint32(20101), resp.ErrorCode)
+		assert.Equal(t, fmt.Sprintf("internal error: CN [%s] does not exist", uuid), resp.ErrorMessage)
+
+		ctx1, cancel1 := context.WithTimeout(context.Background(), time.Second)
+		defer cancel1()
+		req = pb.Request{
+			Method: pb.CN_HEARTBEAT,
+			CNHeartbeat: &pb.CNStoreHeartbeat{
+				UUID: uuid,
+			},
+		}
+		resp = s.handleCNHeartbeat(ctx1, req)
+		assert.Equal(t, &pb.CommandBatch{}, resp.CommandBatch)
+		assert.Equal(t, uint32(moerr.Ok), resp.ErrorCode)
+
+		ctx2, cancel2 := context.WithTimeout(context.Background(), time.Second)
+		defer cancel2()
+		req = pb.Request{
+			Method: pb.PATCH_CN_STORE,
+			CNStateLabel: &pb.CNStateLabel{
+				UUID:  uuid,
+				State: metadata.WorkState_Working,
+				Labels: map[string]metadata.LabelList{
+					"account": {Labels: []string{"a", "b"}},
+					"role":    {Labels: []string{"1", "2"}},
+				},
+			},
+		}
+		resp = s.handlePatchCNStore(ctx2, req)
+		assert.Equal(t, uint32(moerr.Ok), resp.ErrorCode)
+
+		ctx3, cancel3 := context.WithTimeout(context.Background(), time.Second)
+		defer cancel3()
+		req = pb.Request{
+			Method: pb.GET_CLUSTER_STATE,
+		}
+		resp = s.handleGetCheckerState(ctx3, req)
+		assert.Equal(t, uint32(moerr.Ok), resp.ErrorCode)
+		assert.NotEmpty(t, resp.CheckerState)
+		info, ok1 := resp.CheckerState.CNState.Stores[uuid]
+		assert.True(t, ok1)
+		assert.Equal(t, metadata.WorkState_Working, info.WorkState)
+		labels1, ok2 := info.Labels["account"]
+		assert.True(t, ok2)
+		assert.Equal(t, labels1.Labels, []string{"a", "b"})
+		labels2, ok3 := info.Labels["role"]
+		assert.True(t, ok3)
+		assert.Equal(t, labels2.Labels, []string{"1", "2"})
+
+		ctx4, cancel4 := context.WithTimeout(context.Background(), time.Second)
+		defer cancel4()
+		req = pb.Request{
+			Method: pb.PATCH_CN_STORE,
+			CNStateLabel: &pb.CNStateLabel{
+				UUID:  uuid,
+				State: metadata.WorkState_Draining,
+			},
+		}
+		resp = s.handlePatchCNStore(ctx4, req)
+		assert.Equal(t, uint32(moerr.Ok), resp.ErrorCode)
+
+		ctx5, cancel5 := context.WithTimeout(context.Background(), time.Second)
+		defer cancel5()
+		req = pb.Request{
+			Method: pb.GET_CLUSTER_STATE,
+		}
+		resp = s.handleGetCheckerState(ctx5, req)
+		assert.Equal(t, uint32(moerr.Ok), resp.ErrorCode)
+		assert.NotEmpty(t, resp.CheckerState)
+		info, ok1 = resp.CheckerState.CNState.Stores[uuid]
+		assert.True(t, ok1)
+		assert.Equal(t, metadata.WorkState_Draining, info.WorkState)
+		labels1, ok2 = info.Labels["account"]
+		assert.True(t, ok2)
+		assert.Equal(t, labels1.Labels, []string{"a", "b"})
+		labels2, ok3 = info.Labels["role"]
+		assert.True(t, ok3)
+		assert.Equal(t, labels2.Labels, []string{"1", "2"})
+	}
+	runServiceTest(t, true, true, fn)
+}
diff --git a/pkg/logservice/store_test.go b/pkg/logservice/store_test.go
index 543b6fe1e..a89278418 100644
--- a/pkg/logservice/store_test.go
+++ b/pkg/logservice/store_test.go
@@ -17,7 +17,6 @@ package logservice
 import (
 	"context"
 	"fmt"
-	"github.com/matrixorigin/matrixone/pkg/pb/task"
 	"math"
 	"sync/atomic"
 	"testing"
@@ -33,6 +32,7 @@ import (
 	"github.com/matrixorigin/matrixone/pkg/logutil"
 	pb "github.com/matrixorigin/matrixone/pkg/pb/logservice"
 	"github.com/matrixorigin/matrixone/pkg/pb/metadata"
+	"github.com/matrixorigin/matrixone/pkg/pb/task"
 	"github.com/matrixorigin/matrixone/pkg/taskservice"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
@@ -728,3 +728,156 @@ func TestUpdateCNLabel(t *testing.T) {
 	}
 	runStoreTest(t, fn)
 }
+
+func TestUpdateCNWorkState(t *testing.T) {
+	fn := func(t *testing.T, store *store) {
+		peers := make(map[uint64]dragonboat.Target)
+		peers[1] = store.id()
+		assert.NoError(t, store.startHAKeeperReplica(1, peers, false))
+
+		ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
+		defer cancel()
+
+		uuid := "uuid1"
+		workState := pb.CNWorkState{
+			UUID:  uuid,
+			State: metadata.WorkState_Working,
+		}
+		err := store.updateCNWorkState(ctx, workState)
+		assert.EqualError(t, err, fmt.Sprintf("internal error: CN [%s] does not exist", uuid))
+
+		// begin heartbeat to add CN store.
+		hb := pb.CNStoreHeartbeat{
+			UUID: uuid,
+		}
+		_, err = store.addCNStoreHeartbeat(ctx, hb)
+		assert.NoError(t, err)
+
+		err = store.updateCNWorkState(ctx, workState)
+		assert.NoError(t, err)
+
+		state, err := store.getCheckerState()
+		assert.NoError(t, err)
+		assert.NotEmpty(t, state)
+		info, ok1 := state.CNState.Stores[uuid]
+		assert.True(t, ok1)
+		assert.Equal(t, metadata.WorkState_Working, info.WorkState)
+
+		workState = pb.CNWorkState{
+			UUID:  uuid,
+			State: metadata.WorkState_Draining,
+		}
+		err = store.updateCNWorkState(ctx, workState)
+		assert.NoError(t, err)
+
+		state, err = store.getCheckerState()
+		assert.NoError(t, err)
+		assert.NotEmpty(t, state)
+		info, ok1 = state.CNState.Stores[uuid]
+		assert.True(t, ok1)
+		assert.Equal(t, metadata.WorkState_Draining, info.WorkState)
+
+		workState = pb.CNWorkState{
+			UUID:  uuid,
+			State: metadata.WorkState_Working,
+		}
+		err = store.updateCNWorkState(ctx, workState)
+		assert.NoError(t, err)
+
+		state, err = store.getCheckerState()
+		assert.NoError(t, err)
+		assert.NotEmpty(t, state)
+		info, ok1 = state.CNState.Stores[uuid]
+		assert.True(t, ok1)
+		assert.Equal(t, metadata.WorkState_Draining, info.WorkState)
+	}
+	runStoreTest(t, fn)
+}
+
+func TestPatchCNStore(t *testing.T) {
+	fn := func(t *testing.T, store *store) {
+		peers := make(map[uint64]dragonboat.Target)
+		peers[1] = store.id()
+		assert.NoError(t, store.startHAKeeperReplica(1, peers, false))
+
+		ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
+		defer cancel()
+
+		uuid := "uuid1"
+		stateLabel := pb.CNStateLabel{
+			UUID:  uuid,
+			State: metadata.WorkState_Working,
+			Labels: map[string]metadata.LabelList{
+				"account": {Labels: []string{"a", "b"}},
+				"role":    {Labels: []string{"1", "2"}},
+			},
+		}
+		err := store.patchCNStore(ctx, stateLabel)
+		assert.EqualError(t, err, fmt.Sprintf("internal error: CN [%s] does not exist", uuid))
+
+		// begin heartbeat to add CN store.
+		hb := pb.CNStoreHeartbeat{
+			UUID: uuid,
+		}
+		_, err = store.addCNStoreHeartbeat(ctx, hb)
+		assert.NoError(t, err)
+
+		err = store.patchCNStore(ctx, stateLabel)
+		assert.NoError(t, err)
+
+		state, err := store.getCheckerState()
+		assert.NoError(t, err)
+		assert.NotEmpty(t, state)
+		info, ok1 := state.CNState.Stores[uuid]
+		assert.True(t, ok1)
+		assert.Equal(t, metadata.WorkState_Working, info.WorkState)
+		labels1, ok2 := info.Labels["account"]
+		assert.True(t, ok2)
+		assert.Equal(t, labels1.Labels, []string{"a", "b"})
+		labels2, ok3 := info.Labels["role"]
+		assert.True(t, ok3)
+		assert.Equal(t, labels2.Labels, []string{"1", "2"})
+
+		stateLabel = pb.CNStateLabel{
+			UUID:  uuid,
+			State: metadata.WorkState_Draining,
+		}
+		err = store.patchCNStore(ctx, stateLabel)
+		assert.NoError(t, err)
+
+		state, err = store.getCheckerState()
+		assert.NoError(t, err)
+		assert.NotEmpty(t, state)
+		info, ok1 = state.CNState.Stores[uuid]
+		assert.True(t, ok1)
+		assert.Equal(t, metadata.WorkState_Draining, info.WorkState)
+		labels1, ok2 = info.Labels["account"]
+		assert.True(t, ok2)
+		assert.Equal(t, labels1.Labels, []string{"a", "b"})
+		labels2, ok3 = info.Labels["role"]
+		assert.True(t, ok3)
+		assert.Equal(t, labels2.Labels, []string{"1", "2"})
+
+		stateLabel = pb.CNStateLabel{
+			UUID: uuid,
+			Labels: map[string]metadata.LabelList{
+				"account": {Labels: []string{"a", "b"}},
+			},
+		}
+		err = store.patchCNStore(ctx, stateLabel)
+		assert.NoError(t, err)
+
+		state, err = store.getCheckerState()
+		assert.NoError(t, err)
+		assert.NotEmpty(t, state)
+		info, ok1 = state.CNState.Stores[uuid]
+		assert.True(t, ok1)
+		assert.Equal(t, metadata.WorkState_Draining, info.WorkState)
+		labels1, ok2 = info.Labels["account"]
+		assert.True(t, ok2)
+		assert.Equal(t, labels1.Labels, []string{"a", "b"})
+		_, ok3 = info.Labels["role"]
+		assert.False(t, ok3)
+	}
+	runStoreTest(t, fn)
+}
diff --git a/pkg/pb/logservice/logservice_test.go b/pkg/pb/logservice/logservice_test.go
index 19f27d850..8dbf5f599 100644
--- a/pkg/pb/logservice/logservice_test.go
+++ b/pkg/pb/logservice/logservice_test.go
@@ -42,6 +42,7 @@ func TestCNStateUpdate(t *testing.T) {
 		Tick:           tick1,
 		ServiceAddress: hb1.ServiceAddress,
 		Role:           metadata.CNRole_AP,
+		WorkState:      metadata.WorkState_Working,
 		Labels:         map[string]metadata.LabelList{},
 	})
 
@@ -53,6 +54,7 @@ func TestCNStateUpdate(t *testing.T) {
 		Tick:           tick2,
 		ServiceAddress: hb2.ServiceAddress,
 		Role:           metadata.CNRole_TP,
+		WorkState:      metadata.WorkState_Working,
 		Labels:         map[string]metadata.LabelList{},
 	})
 
@@ -64,6 +66,7 @@ func TestCNStateUpdate(t *testing.T) {
 		Tick:           tick3,
 		ServiceAddress: hb3.ServiceAddress,
 		Role:           metadata.CNRole_TP,
+		WorkState:      metadata.WorkState_Working,
 		Labels:         map[string]metadata.LabelList{},
 	})
 }
@@ -368,6 +371,7 @@ func TestCNLabelUpdate(t *testing.T) {
 		Tick:           tick1,
 		ServiceAddress: hb1.ServiceAddress,
 		Role:           metadata.CNRole_AP,
+		WorkState:      metadata.WorkState_Working,
 		Labels:         map[string]metadata.LabelList{},
 	})
 
@@ -388,6 +392,7 @@ func TestCNLabelUpdate(t *testing.T) {
 		Tick:           tick1,
 		ServiceAddress: hb1.ServiceAddress,
 		Role:           metadata.CNRole_AP,
+		WorkState:      metadata.WorkState_Working,
 		Labels: map[string]metadata.LabelList{
 			"account": {
 				Labels: []string{"a1", "a2"},
@@ -412,6 +417,162 @@ func TestCNLabelUpdate(t *testing.T) {
 		Tick:           tick1,
 		ServiceAddress: hb1.ServiceAddress,
 		Role:           metadata.CNRole_AP,
+		WorkState:      metadata.WorkState_Working,
+		Labels: map[string]metadata.LabelList{
+			"role": {
+				Labels: []string{"r1"},
+			},
+		},
+	})
+}
+
+func TestCNWorkStateUpdate(t *testing.T) {
+	state := CNState{Stores: map[string]CNStoreInfo{}}
+
+	workState := CNWorkState{
+		UUID:  "cn-1",
+		State: metadata.WorkState_Working,
+	}
+	state.UpdateWorkState(workState)
+	// No heartbeat yet, nothing happens.
+	assert.Equal(t, state.Stores[workState.UUID], CNStoreInfo{})
+
+	// Add CN store to HAKeeper.
+	hb1 := CNStoreHeartbeat{UUID: "cn-1", ServiceAddress: "addr-a", Role: metadata.CNRole_AP}
+	tick1 := uint64(100)
+
+	state.Update(hb1, tick1)
+	assert.Equal(t, state.Stores[hb1.UUID], CNStoreInfo{
+		Tick:           tick1,
+		ServiceAddress: hb1.ServiceAddress,
+		Role:           metadata.CNRole_AP,
+		WorkState:      metadata.WorkState_Working,
+		Labels:         map[string]metadata.LabelList{},
+	})
+
+	workState = CNWorkState{
+		UUID:  "cn-1",
+		State: metadata.WorkState_Draining,
+	}
+
+	state.UpdateWorkState(workState)
+	assert.Equal(t, state.Stores[workState.UUID], CNStoreInfo{
+		Tick:           tick1,
+		ServiceAddress: hb1.ServiceAddress,
+		Role:           metadata.CNRole_AP,
+		WorkState:      metadata.WorkState_Draining,
+		Labels:         map[string]metadata.LabelList{},
+	})
+
+	workState = CNWorkState{
+		UUID:  "cn-1",
+		State: metadata.WorkState_Working,
+	}
+
+	state.UpdateWorkState(workState)
+	assert.Equal(t, state.Stores[workState.UUID], CNStoreInfo{
+		Tick:           tick1,
+		ServiceAddress: hb1.ServiceAddress,
+		Role:           metadata.CNRole_AP,
+		WorkState:      metadata.WorkState_Draining,
+		Labels:         map[string]metadata.LabelList{},
+	})
+}
+
+func TestCNStateLabelPatch(t *testing.T) {
+	state := CNState{Stores: map[string]CNStoreInfo{}}
+
+	stateLabel := CNStateLabel{
+		UUID:  "cn-1",
+		State: metadata.WorkState_Working,
+		Labels: map[string]metadata.LabelList{
+			"account": {
+				Labels: []string{"a1", "a2"},
+			},
+			"role": {
+				Labels: []string{"r1"},
+			},
+		},
+	}
+	state.PatchCNStore(stateLabel)
+	// No heartbeat yet, nothing happens.
+	assert.Equal(t, state.Stores[stateLabel.UUID], CNStoreInfo{})
+
+	// Add CN store to HAKeeper.
+	hb1 := CNStoreHeartbeat{UUID: "cn-1", ServiceAddress: "addr-a", Role: metadata.CNRole_AP}
+	tick1 := uint64(100)
+
+	state.Update(hb1, tick1)
+	assert.Equal(t, state.Stores[hb1.UUID], CNStoreInfo{
+		Tick:           tick1,
+		ServiceAddress: hb1.ServiceAddress,
+		Role:           metadata.CNRole_AP,
+		WorkState:      metadata.WorkState_Working,
+		Labels:         map[string]metadata.LabelList{},
+	})
+
+	stateLabel = CNStateLabel{
+		UUID:  "cn-1",
+		State: metadata.WorkState_Draining,
+		Labels: map[string]metadata.LabelList{
+			"account": {
+				Labels: []string{"a1", "a2"},
+			},
+			"role": {
+				Labels: []string{"r1"},
+			},
+		},
+	}
+	state.PatchCNStore(stateLabel)
+	assert.Equal(t, state.Stores[stateLabel.UUID], CNStoreInfo{
+		Tick:           tick1,
+		ServiceAddress: hb1.ServiceAddress,
+		Role:           metadata.CNRole_AP,
+		WorkState:      metadata.WorkState_Draining,
+		Labels: map[string]metadata.LabelList{
+			"account": {
+				Labels: []string{"a1", "a2"},
+			},
+			"role": {
+				Labels: []string{"r1"},
+			},
+		},
+	})
+
+	stateLabel = CNStateLabel{
+		UUID:  "cn-1",
+		State: metadata.WorkState_Drained,
+	}
+	state.PatchCNStore(stateLabel)
+	assert.Equal(t, state.Stores[stateLabel.UUID], CNStoreInfo{
+		Tick:           tick1,
+		ServiceAddress: hb1.ServiceAddress,
+		Role:           metadata.CNRole_AP,
+		WorkState:      metadata.WorkState_Drained,
+		Labels: map[string]metadata.LabelList{
+			"account": {
+				Labels: []string{"a1", "a2"},
+			},
+			"role": {
+				Labels: []string{"r1"},
+			},
+		},
+	})
+
+	stateLabel = CNStateLabel{
+		UUID: "cn-1",
+		Labels: map[string]metadata.LabelList{
+			"role": {
+				Labels: []string{"r1"},
+			},
+		},
+	}
+	state.PatchCNStore(stateLabel)
+	assert.Equal(t, state.Stores[stateLabel.UUID], CNStoreInfo{
+		Tick:           tick1,
+		ServiceAddress: hb1.ServiceAddress,
+		Role:           metadata.CNRole_AP,
+		WorkState:      metadata.WorkState_Drained,
 		Labels: map[string]metadata.LabelList{
 			"role": {
 				Labels: []string{"r1"},