go zookeeper包解析

zookeeper客户端连接对象
 

Conn对象:负责客户端的连接,sessionTimeout 指服务端连接缓存的记录时间,在这个时间内ephemeral nodes(选举主的标志节点)和watches会被保留。若有多个ip,conn会随机选择其中一个连接,连接不上则换一个。

connect方法会返回一个接受通道,在connect中会启动一个协程连接server,若成功会将一些事件值发送给接受通道,最后为了防止阻塞其他线程,会关闭接收通道。


func Connect(servers []string, sessionTimeout time.Duration, options ...connOption) (*Conn, <-chan Event, error) {
    ...
	go func() {
		conn.loop()
		conn.flushRequests(ErrClosing)
		conn.invalidateWatches(ErrClosing)
		close(conn.eventChan)
	}()
	return conn, ec, nil
}
Exists方法:检查节点是否存在
//返回的Stat为节点的状态属性
func (c *Conn) Exists(path string) (bool, *Stat, error) {
//验证路径的有效性,包括开头、字符串符合编码等
	if err := validatePath(path, false); err != nil {
		return false, nil, err
	}

	res := &existsResponse{}
//封装请求
	_, err := c.request(opExists, &existsRequest{Path: path, Watch: false}, res, nil)
	exists := true
//判断其中一个错误类型,是否是节点不存在,如果是节点不存在则不报错
	if err == ErrNoNode {
		exists = false
		err = nil
	}
	return exists, &res.Stat, err
}

request方法向服务器请求中都会用到,比较常见,也就是常见的client/server模式

func (c *Conn) queueRequest(opcode int32, req interface{}, res interface{}, recvFunc 
func(*request, *responseHeader, error)) <-chan response {
//封装rq请求
	rq := &request{
		xid:        c.nextXid(),
		opcode:     opcode,
		pkt:        req,
		recvStruct: res,
		recvChan:   make(chan response, 1),
		recvFunc:   recvFunc,
	}
//将rq通过通道发送至对等到通道到来的处理请求的协程序
	c.sendChan <- rq
//返回一个等到响应到来的通道,意思是处理请求协程完成后,会将这个结果发送给这个通道
	return rq.recvChan
}


func (c *Conn) request(opcode int32, req interface{}, res interface{}, recvFunc func(*request, *responseHeader, error)) (int64, error) {
//request会一直阻塞等待这个通道结果,结果可能有错误,处理时需要判定
	r := <-c.queueRequest(opcode, req, res, recvFunc)
	return r.zxid, r.err
}

除exits方法外,还有许多类似的请求判断节点的状态的方法,例如conn.children,采用都是利用对应的通道发送请求得到子节点,服务端处理并回应请求的方式来进行。conn.Sync(parentNode)是让parentNode保持是最新的节点,同步最新的数据

另外,值得注意的是exitsW方法(带有w的方法)有一个回调函数参数,该参数会在拿到请求结果后进行调用

e

func (c *Conn) ExistsW(path string) (bool, *Stat, <-chan Event, error) {
	if err := validatePath(path, false); err != nil {
		return false, nil, nil, err
	}

	var ech <-chan Event
	res := &existsResponse{}
	_, err := c.request(opExists, &existsRequest{Path: path, Watch: true}, res, func(req *request, res *responseHeader, err error) {
//回调函数使用
		if err == nil {
			ech = c.addWatcher(path, watchTypeData)
		} else if err == ErrNoNode {
			ech = c.addWatcher(path, watchTypeExist)
		}
	})
	exists := true
	if err == ErrNoNode {
		exists = false
		err = nil
	}
	if err != nil {
		return false, nil, nil, err
	}
	return exists, &res.Stat, ech, err
}

上面中出现了一个常用的函数conn.addWatcher(),conn会将wathers加入watchers集合中,Map的值是一个通道值,用来阻塞监听的结果的到来。所以若这个通道接受到值,则说明节点类型改变成功或者节点成功创建。

//接受一个节点路径和watchType(整形类型值)
func (c *Conn) addWatcher(path string, watchType watchType) <-chan Event {
//互斥锁
	c.watchersLock.Lock()
	defer c.watchersLock.Unlock()

	ch := make(chan Event, 1)
	wpt := watchPathType{path, watchType}
//watchers 数组    map[watchPathType][]chan Event
	c.watchers[wpt] = append(c.watchers[wpt], ch)
	return ch
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值