dubbo.apache.org/dubbo-go/v3@v3.1.1/config_center/zookeeper/listener.go (about)

     1  /*
     2   * Licensed to the Apache Software Foundation (ASF) under one or more
     3   * contributor license agreements.  See the NOTICE file distributed with
     4   * this work for additional information regarding copyright ownership.
     5   * The ASF licenses this file to You under the Apache License, Version 2.0
     6   * (the "License"); you may not use this file except in compliance with
     7   * the License.  You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  
    18  package zookeeper
    19  
    20  import (
    21  	"strings"
    22  	"sync"
    23  )
    24  
    25  import (
    26  	"dubbo.apache.org/dubbo-go/v3/common/constant"
    27  	"dubbo.apache.org/dubbo-go/v3/config_center"
    28  	"dubbo.apache.org/dubbo-go/v3/metrics"
    29  	metricsConfigCenter "dubbo.apache.org/dubbo-go/v3/metrics/config_center"
    30  	"dubbo.apache.org/dubbo-go/v3/remoting"
    31  	"dubbo.apache.org/dubbo-go/v3/remoting/zookeeper"
    32  )
    33  
    34  // CacheListener defines keyListeners and rootPath
    35  type CacheListener struct {
    36  	// key is zkNode Path and value is set of listeners
    37  	keyListeners    sync.Map
    38  	zkEventListener *zookeeper.ZkEventListener
    39  	rootPath        string
    40  }
    41  
    42  // NewCacheListener creates a new CacheListener
    43  func NewCacheListener(rootPath string, listener *zookeeper.ZkEventListener) *CacheListener {
    44  	return &CacheListener{zkEventListener: listener, rootPath: rootPath}
    45  }
    46  
    47  // AddListener will add a listener if loaded
    48  func (l *CacheListener) AddListener(key string, listener config_center.ConfigurationListener) {
    49  	// FIXME do not use Client.ExistW, cause it has a bug(can not watch zk node that do not exist)
    50  	_, _, _, err := l.zkEventListener.Client.Conn.ExistsW(key)
    51  	// reference from https://stackoverflow.com/questions/34018908/golang-why-dont-we-have-a-set-datastructure
    52  	// make a map[your type]struct{} like set in java
    53  	if err != nil {
    54  		return
    55  	}
    56  	listeners, loaded := l.keyListeners.LoadOrStore(key, map[config_center.ConfigurationListener]struct{}{listener: {}})
    57  	if loaded {
    58  		listeners.(map[config_center.ConfigurationListener]struct{})[listener] = struct{}{}
    59  		l.keyListeners.Store(key, listeners)
    60  	}
    61  }
    62  
    63  // RemoveListener will delete a listener if loaded
    64  func (l *CacheListener) RemoveListener(key string, listener config_center.ConfigurationListener) {
    65  	listeners, loaded := l.keyListeners.Load(key)
    66  	if loaded {
    67  		delete(listeners.(map[config_center.ConfigurationListener]struct{}), listener)
    68  	}
    69  }
    70  
    71  // DataChange changes all listeners' event
    72  func (l *CacheListener) DataChange(event remoting.Event) bool {
    73  	changeType := event.Action
    74  	if event.Content == "" {
    75  		changeType = remoting.EventTypeDel
    76  	}
    77  
    78  	key, group := l.pathToKeyGroup(event.Path)
    79  	defer metrics.Publish(metricsConfigCenter.NewIncMetricEvent(key, group, changeType, metricsConfigCenter.Zookeeper))
    80  	if listeners, ok := l.keyListeners.Load(event.Path); ok {
    81  		for listener := range listeners.(map[config_center.ConfigurationListener]struct{}) {
    82  			listener.Process(&config_center.ConfigChangeEvent{
    83  				Key:        key,
    84  				Value:      event.Content,
    85  				ConfigType: changeType,
    86  			})
    87  		}
    88  		return true
    89  	}
    90  	return false
    91  }
    92  
    93  func (l *CacheListener) pathToKeyGroup(path string) (string, string) {
    94  	if len(path) == 0 {
    95  		return path, ""
    96  	}
    97  	groupKey := strings.Replace(strings.Replace(path, l.rootPath+constant.PathSeparator, "", -1), constant.PathSeparator, constant.DotSeparator, -1)
    98  	index := strings.Index(groupKey, constant.DotSeparator)
    99  	return groupKey[index+1:], groupKey[0:index]
   100  }