github.com/polarismesh/polaris@v1.17.8/store/boltdb/admin.go (about)

     1  /**
     2   * Tencent is pleased to support the open source community by making Polaris available.
     3   *
     4   * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
     5   *
     6   * Licensed under the BSD 3-Clause License (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at
     9   *
    10   * https://opensource.org/licenses/BSD-3-Clause
    11   *
    12   * Unless required by applicable law or agreed to in writing, software distributed
    13   * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
    14   * CONDITIONS OF ANY KIND, either express or implied. See the License for the
    15   * specific language governing permissions and limitations under the License.
    16   */
    17  
    18  package boltdb
    19  
    20  import (
    21  	"fmt"
    22  	"sync"
    23  	"time"
    24  
    25  	apiservice "github.com/polarismesh/specification/source/go/api/v1/service_manage"
    26  
    27  	"github.com/polarismesh/polaris/common/eventhub"
    28  	"github.com/polarismesh/polaris/common/model"
    29  	"github.com/polarismesh/polaris/common/utils"
    30  	"github.com/polarismesh/polaris/store"
    31  )
    32  
    33  type adminStore struct {
    34  	handler BoltHandler
    35  	leMap   map[string]bool
    36  	mutex   sync.Mutex
    37  }
    38  
    39  // StartLeaderElection
    40  func (m *adminStore) StartLeaderElection(key string) error {
    41  	m.mutex.Lock()
    42  	defer m.mutex.Unlock()
    43  
    44  	_, ok := m.leMap[key]
    45  	if ok {
    46  		return nil
    47  	}
    48  	m.leMap[key] = true
    49  	_ = eventhub.Publish(eventhub.LeaderChangeEventTopic, store.LeaderChangeEvent{Key: key, Leader: true})
    50  	return nil
    51  }
    52  
    53  // IsLeader
    54  func (m *adminStore) IsLeader(key string) bool {
    55  	m.mutex.Lock()
    56  	defer m.mutex.Unlock()
    57  
    58  	v, ok := m.leMap[key]
    59  	if ok {
    60  		return v
    61  	}
    62  	return false
    63  }
    64  
    65  // ListLeaderElections
    66  func (m *adminStore) ListLeaderElections() ([]*model.LeaderElection, error) {
    67  	m.mutex.Lock()
    68  	defer m.mutex.Unlock()
    69  
    70  	var out []*model.LeaderElection
    71  	for k, v := range m.leMap {
    72  		item := &model.LeaderElection{
    73  			ElectKey: k,
    74  			Host:     utils.LocalHost,
    75  			Ctime:    0,
    76  			Mtime:    time.Now().Unix(),
    77  			Valid:    v,
    78  		}
    79  		item.CreateTime = time.Unix(item.Ctime, 0)
    80  		item.ModifyTime = time.Unix(item.Mtime, 0)
    81  
    82  		out = append(out, item)
    83  	}
    84  	return out, nil
    85  }
    86  
    87  // ReleaseLeaderElection
    88  func (m *adminStore) ReleaseLeaderElection(key string) error {
    89  	m.mutex.Lock()
    90  	defer m.mutex.Unlock()
    91  	v, ok := m.leMap[key]
    92  	if !ok {
    93  		return fmt.Errorf("LeaderElection(%s) not started", key)
    94  	}
    95  
    96  	if v {
    97  		m.leMap[key] = false
    98  		_ = eventhub.Publish(eventhub.LeaderChangeEventTopic, store.LeaderChangeEvent{Key: key, Leader: false})
    99  	}
   100  
   101  	return nil
   102  }
   103  
   104  // BatchCleanDeletedInstances
   105  func (m *adminStore) BatchCleanDeletedInstances(timeout time.Duration, batchSize uint32) (uint32, error) {
   106  	mtime := time.Now().Add(-timeout)
   107  	fields := []string{insFieldValid, insFieldModifyTime}
   108  	values, err := m.handler.LoadValuesByFilter(tblNameInstance, fields, &model.Instance{},
   109  		func(m map[string]interface{}) bool {
   110  			valid, ok := m[insFieldValid]
   111  			if !ok {
   112  				return false
   113  			}
   114  			if valid.(bool) {
   115  				return false
   116  			}
   117  
   118  			modifyTime, ok := m[insFieldModifyTime]
   119  			if !ok {
   120  				return false
   121  			}
   122  			if modifyTime.(time.Time).After(mtime) {
   123  				return false
   124  			}
   125  
   126  			return true
   127  		})
   128  	if err != nil {
   129  		return 0, err
   130  	}
   131  	if len(values) == 0 {
   132  		return 0, nil
   133  	}
   134  
   135  	var count uint32 = 0
   136  	keys := make([]string, 0, batchSize)
   137  	for k := range values {
   138  		keys = append(keys, k)
   139  		count++
   140  		if count >= batchSize {
   141  			break
   142  		}
   143  	}
   144  	err = m.handler.DeleteValues(tblNameInstance, keys)
   145  	if err != nil {
   146  		return count, err
   147  	}
   148  	return count, nil
   149  }
   150  
   151  func (m *adminStore) GetUnHealthyInstances(timeout time.Duration, limit uint32) ([]string, error) {
   152  	return m.getUnHealthyInstancesBefore(time.Now().Add(-timeout), limit)
   153  }
   154  
   155  func (m *adminStore) getUnHealthyInstancesBefore(mtime time.Time, limit uint32) ([]string, error) {
   156  	fields := []string{insFieldProto, insFieldValid}
   157  	instances, err := m.handler.LoadValuesByFilter(tblNameInstance, fields, &model.Instance{},
   158  		func(m map[string]interface{}) bool {
   159  
   160  			valid, ok := m[insFieldValid]
   161  			if ok && !valid.(bool) {
   162  				return false
   163  			}
   164  
   165  			insProto, ok := m[insFieldProto]
   166  			if !ok {
   167  				return false
   168  			}
   169  
   170  			ins := insProto.(*apiservice.Instance)
   171  
   172  			insMtime, err := time.Parse("2006-01-02 15:04:05", ins.GetMtime().GetValue())
   173  			if err != nil {
   174  				log.Errorf("[Store][boltdb] parse instance mtime error, %v", err)
   175  				return false
   176  			}
   177  
   178  			if insMtime.Before(mtime) {
   179  				return false
   180  			}
   181  
   182  			if !ins.GetEnableHealthCheck().GetValue() {
   183  				return false
   184  			}
   185  
   186  			if ins.GetHealthy().GetValue() {
   187  				return false
   188  			}
   189  
   190  			return true
   191  		})
   192  
   193  	if err != nil {
   194  		log.Errorf("[Store][boltdb] load instance from kv error, %v", err)
   195  		return nil, err
   196  	}
   197  
   198  	var instanceIds []string
   199  	var count uint32 = 0
   200  	for _, v := range instances {
   201  		instanceIds = append(instanceIds, v.(*model.Instance).ID())
   202  		count += 1
   203  		if count >= limit {
   204  			break
   205  		}
   206  	}
   207  
   208  	return instanceIds, nil
   209  }
   210  
   211  // BatchCleanDeletedClients
   212  func (m *adminStore) BatchCleanDeletedClients(timeout time.Duration, batchSize uint32) (uint32, error) {
   213  	mtime := time.Now().Add(-timeout)
   214  	fields := []string{ClientFieldValid, ClientFieldMtime}
   215  	values, err := m.handler.LoadValuesByFilter(tblClient, fields, &model.Client{},
   216  		func(m map[string]interface{}) bool {
   217  			valid, ok := m[ClientFieldValid]
   218  			if !ok {
   219  				return false
   220  			}
   221  			if valid.(bool) {
   222  				return false
   223  			}
   224  
   225  			modifyTime, ok := m[ClientFieldMtime]
   226  			if !ok {
   227  				return false
   228  			}
   229  			if modifyTime.(time.Time).After(mtime) {
   230  				return false
   231  			}
   232  
   233  			return true
   234  		})
   235  	if err != nil {
   236  		return 0, err
   237  	}
   238  	if len(values) == 0 {
   239  		return 0, nil
   240  	}
   241  
   242  	var count uint32 = 0
   243  	keys := make([]string, 0, batchSize)
   244  	for k := range values {
   245  		keys = append(keys, k)
   246  		count++
   247  		if count >= batchSize {
   248  			break
   249  		}
   250  	}
   251  	err = m.handler.DeleteValues(tblClient, keys)
   252  	if err != nil {
   253  		return count, err
   254  	}
   255  	return count, nil
   256  }