github.com/polarismesh/polaris@v1.17.8/cache/client/client.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 cache_client
    19  
    20  import (
    21  	"sort"
    22  	"sync"
    23  	"time"
    24  
    25  	"go.uber.org/zap"
    26  	"golang.org/x/sync/singleflight"
    27  
    28  	types "github.com/polarismesh/polaris/cache/api"
    29  	"github.com/polarismesh/polaris/common/log"
    30  	"github.com/polarismesh/polaris/common/model"
    31  	"github.com/polarismesh/polaris/store"
    32  )
    33  
    34  var (
    35  	_ types.ClientCache = (*clientCache)(nil)
    36  )
    37  
    38  // clientCache 客户端缓存的类
    39  type clientCache struct {
    40  	*types.BaseCache
    41  
    42  	storage         store.Store
    43  	lastMtimeLogged int64
    44  	clients         map[string]*model.Client // instance id -> instance
    45  	lock            sync.RWMutex
    46  	singleFlight    *singleflight.Group
    47  	lastUpdateTime  time.Time
    48  }
    49  
    50  // name 获取资源名称
    51  func (c *clientCache) Name() string {
    52  	return types.ClientName
    53  }
    54  
    55  // LastMtime 最后一次更新时间
    56  func (c *clientCache) LastMtime() time.Time {
    57  	return c.BaseCache.LastMtime(c.Name())
    58  }
    59  
    60  // NewClientCache 新建一个clientCache
    61  func NewClientCache(storage store.Store, cacheMgr types.CacheManager) types.ClientCache {
    62  	return &clientCache{
    63  		BaseCache: types.NewBaseCache(storage, cacheMgr),
    64  		storage:   storage,
    65  		clients:   map[string]*model.Client{},
    66  	}
    67  }
    68  
    69  // initialize 初始化函数
    70  func (c *clientCache) Initialize(_ map[string]interface{}) error {
    71  	c.singleFlight = &singleflight.Group{}
    72  	c.lastUpdateTime = time.Unix(0, 0)
    73  	return nil
    74  }
    75  
    76  // update 更新缓存函数
    77  func (c *clientCache) Update() error {
    78  	// 多个线程竞争,只有一个线程进行更新
    79  	_, err, _ := c.singleFlight.Do(c.Name(), func() (interface{}, error) {
    80  		defer func() {
    81  			c.lastMtimeLogged = types.LogLastMtime(c.lastMtimeLogged, c.LastMtime().Unix(), "Client")
    82  			c.reportMetricsInfo()
    83  		}()
    84  		return nil, c.DoCacheUpdate(c.Name(), c.realUpdate)
    85  	})
    86  
    87  	return err
    88  }
    89  
    90  func (c *clientCache) realUpdate() (map[string]time.Time, int64, error) {
    91  	// 拉取diff前的所有数据
    92  	start := time.Now()
    93  	clients, err := c.storage.GetMoreClients(c.LastFetchTime(), c.IsFirstUpdate())
    94  	if err != nil {
    95  		log.Errorf("[Cache][Client] update get storage more err: %s", err.Error())
    96  		return nil, -1, err
    97  	}
    98  	timeDiff := time.Since(start)
    99  	lastMtimes, update, del := c.setClients(clients)
   100  	if timeDiff > 1*time.Second {
   101  		log.Info("[Cache][Client] get more clients",
   102  			zap.Int("update", update), zap.Int("delete", del),
   103  			zap.Time("last", c.LastMtime()), zap.Duration("used", time.Since(start)))
   104  	}
   105  
   106  	c.lastUpdateTime = time.Now()
   107  	return lastMtimes, int64(len(clients)), nil
   108  }
   109  
   110  func (c *clientCache) getClient(id string) (*model.Client, bool) {
   111  	c.lock.RLock()
   112  	defer c.lock.RUnlock()
   113  
   114  	client, ok := c.clients[id]
   115  	return client, ok
   116  }
   117  
   118  func (c *clientCache) deleteClient(id string) {
   119  	c.lock.Lock()
   120  	delete(c.clients, id)
   121  	c.lock.Unlock()
   122  }
   123  
   124  func (c *clientCache) storeClient(id string, client *model.Client) {
   125  	c.lock.Lock()
   126  	c.clients[id] = client
   127  	c.lock.Unlock()
   128  }
   129  
   130  // setClients 保存client到内存中
   131  // 返回:更新个数,删除个数
   132  func (c *clientCache) setClients(clients map[string]*model.Client) (map[string]time.Time, int, int) {
   133  	if len(clients) == 0 {
   134  		return nil, 0, 0
   135  	}
   136  
   137  	lastMtime := c.LastMtime().Unix()
   138  	update := 0
   139  	del := 0
   140  	progress := 0
   141  	for _, client := range clients {
   142  		progress++
   143  		if progress%50000 == 0 {
   144  			log.Infof("[Cache][Client] set clients progress: %d / %d", progress, len(clients))
   145  		}
   146  
   147  		modifyTime := client.ModifyTime().Unix()
   148  		if lastMtime < modifyTime {
   149  			lastMtime = modifyTime
   150  		}
   151  
   152  		id := client.Proto().GetId().GetValue()
   153  		_, itemExist := c.getClient(id)
   154  		// 待删除的instance
   155  		if !client.Valid() {
   156  			del++
   157  			c.deleteClient(id)
   158  			if itemExist {
   159  				c.Manager.OnEvent(client, types.EventDeleted)
   160  			}
   161  			continue
   162  		}
   163  
   164  		// 有修改或者新增的数据
   165  		update++
   166  		c.storeClient(id, client)
   167  		if !itemExist {
   168  			c.Manager.OnEvent(client, types.EventCreated)
   169  		} else {
   170  			c.Manager.OnEvent(client, types.EventUpdated)
   171  		}
   172  	}
   173  
   174  	return map[string]time.Time{
   175  		c.Name(): time.Unix(lastMtime, 0),
   176  	}, update, del
   177  }
   178  
   179  // clear
   180  //
   181  //	@return error
   182  func (c *clientCache) Clear() error {
   183  	c.BaseCache.Clear()
   184  	c.lock.Lock()
   185  	c.clients = map[string]*model.Client{}
   186  	c.lock.Unlock()
   187  	return nil
   188  }
   189  
   190  // GetClient get client
   191  // @param id
   192  // @return *model.Client
   193  func (c *clientCache) GetClient(id string) *model.Client {
   194  	if id == "" {
   195  		return nil
   196  	}
   197  
   198  	value, ok := c.getClient(id)
   199  	if !ok {
   200  		return nil
   201  	}
   202  
   203  	return value
   204  }
   205  
   206  // IteratorClients 迭代
   207  func (c *clientCache) IteratorClients(iterProc types.ClientIterProc) {
   208  	c.lock.RLock()
   209  	defer c.lock.RUnlock()
   210  
   211  	for key := range c.clients {
   212  		if !iterProc(key, c.clients[key]) {
   213  			break
   214  		}
   215  	}
   216  }
   217  
   218  // GetClientsByFilter Query client information
   219  func (c *clientCache) GetClientsByFilter(filters map[string]string, offset, limit uint32) (uint32,
   220  	[]*model.Client, error) {
   221  	var (
   222  		ret                 = make([]*model.Client, 0, 16)
   223  		host, hasHost       = filters["host"]
   224  		clientType, hasType = filters["type"]
   225  		version, hasVer     = filters["version"]
   226  		id, hasId           = filters["id"]
   227  	)
   228  	c.IteratorClients(func(_ string, value *model.Client) bool {
   229  		if hasHost && value.Proto().GetHost().GetValue() != host {
   230  			return true
   231  		}
   232  		if hasType && value.Proto().GetType().String() != clientType {
   233  			return true
   234  		}
   235  		if hasVer && value.Proto().GetVersion().GetValue() != version {
   236  			return true
   237  		}
   238  		if hasId && value.Proto().GetId().GetValue() != id {
   239  			return true
   240  		}
   241  
   242  		ret = append(ret, value)
   243  		return true
   244  	})
   245  
   246  	return uint32(len(ret)), doClientPage(ret, offset, limit), nil
   247  }
   248  
   249  // doClientPage 进行分页, 仅用于控制台查询时的排序
   250  func doClientPage(ret []*model.Client, offset, limit uint32) []*model.Client {
   251  	clients := make([]*model.Client, 0, len(ret))
   252  	beginIndex := offset
   253  	endIndex := beginIndex + limit
   254  	totalCount := uint32(len(ret))
   255  	if totalCount == 0 || beginIndex >= endIndex || beginIndex >= totalCount {
   256  		return clients
   257  	}
   258  
   259  	if endIndex > totalCount {
   260  		endIndex = totalCount
   261  	}
   262  
   263  	clients = append(clients, ret...)
   264  	sort.Slice(clients, func(i, j int) bool {
   265  		return clients[i].ModifyTime().After(clients[j].ModifyTime())
   266  	})
   267  
   268  	return clients[beginIndex:endIndex]
   269  }