consistent.go 源码阅读
import (
"errors"
"hash/crc32"
"sort"
"strconv"
"sync"
)
type uints []uint32 //实现 sort接口
// Len returns the length of the uints array.
func (x uints) Len() int { return len(x) }
// Less returns true if element i is less than element j.
func (x uints) Less(i, j int) bool { return x[i] < x[j] }
// Swap exchanges elements i and j.
func (x uints) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
// ErrEmptyCircle is the error returned when trying to get an element when nothing has been added to hash.
var ErrEmptyCircle = errors.New("empty circle")
// Consistent holds the information about the members of the consistent hash circle.
//Consistent 数据结构
type Consistent struct {
circle map[uint32]string
members map[string]bool
sortedHashes uints
NumberOfReplicas int
count int64
scratch [64]byte
sync.RWMutex
}
// New creates a new Consistent object with a default setting of 20 replicas for each entry.
//
// To change the number of replicas, set NumberOfReplicas before adding entries.
func New() *Consistent {
c := new(Consistent)
c.NumberOfReplicas = 20
c.circle = make(map[uint32]string)
c.members = make(map[string]bool)
return c
}
// eltKey generates a string key for an element with an index.
func (c *Consistent) eltKey(elt string, idx int) string {
// return elt + "|" + strconv.Itoa(idx)
return strconv.Itoa(idx) + elt
}
// Add inserts a string element in the consistent hash.
func (c *Consistent) Add(elt string) {
c.Lock()
defer c.Unlock()
c.add(elt)
}
// need c.Lock() before calling
func (c *Consistent) add(elt string) {
for i := 0; i < c.NumberOfReplicas; i++ {
c.circle[c.hashKey(c.eltKey(elt, i))] = elt
}
c.members[elt] = true
c.updateSortedHashes()
c.count++
}
// Remove removes an element from the hash.
func (c *Consistent) Remove(elt string) {
c.Lock()
defer c.Unlock()
c.remove(elt)
}
// need c.Lock() before calling
func (c *Consistent) remove(elt string) {
for i := 0; i < c.NumberOfReplicas; i++ {
delete(c.circle, c.hashKey(c.eltKey(elt, i)))
}
delete(c.members, elt)
c.updateSortedHashes()
c.count--
}
// Set sets all the elements in the hash. If there are existing elements not
// present in elts, they will be removed.
func (c *Consistent) Set(elts []string) {
c.Lock()
defer c.Unlock()
for k := range c.members {
found := false
for _, v := range elts {
if k == v {
found = true
break
}
}
if !found {
c.remove(k)
}
}
for _, v := range elts {
_, exists := c.members[v]
if exists {
continue
}
c.add(v)
}
}
func (c *Consistent) Members() []string {
c.RLock()
defer c.RUnlock()
var m []string
for k := range c.members {
m = append(m, k)
}
return m
}
// Get returns an element close to where name hashes to in the circle.
func (c *Consistent) Get(name string) (string, error) {
c.RLock()
defer c.RUnlock()
if len(c.circle) == 0 {
return "", ErrEmptyCircle
}
key := c.hashKey(name)
i := c.search(key)
return c.circle[c.sortedHashes[i]], nil
}
func (c *Consistent) search(key uint32) (i int) {
f := func(x int) bool {
return c.sortedHashes[x] > key
}
i = sort.Search(len(c.sortedHashes), f)
if i >= len(c.sortedHashes) {
i = 0
}
return
}
// GetTwo returns the two closest distinct elements to the name input in the circle.
func (c *Consistent) GetTwo(name string) (string, string, error) {
c.RLock()
defer c.RUnlock()
if len(c.circle) == 0 {
return "", "", ErrEmptyCircle
}
key := c.hashKey(name)
i := c.search(key)
a := c.circle[c.sortedHashes[i]]
if c.count == 1 {
return a, "", nil
}
start := i
var b string
for i = start + 1; i != start; i++ {
if i >= len(c.sortedHashes) {
i = 0
}
b = c.circle[c.sortedHashes[i]]
if b != a {
break
}
}
return a, b, nil
}
// GetN returns the N closest distinct elements to the name input in the circle.
func (c *Consistent) GetN(name string, n int) ([]string, error) {
c.RLock()
defer c.RUnlock()
if len(c.circle) == 0 {
return nil, ErrEmptyCircle
}
if c.count < int64(n) {
n = int(c.count)
}
var (
key = c.hashKey(name)
i = c.search(key)
start = i
res = make([]string, 0, n)
elem = c.circle[c.sortedHashes[i]]
)
res = append(res, elem)
if len(res) == n {
return res, nil
}
for i = start + 1; i != start; i++ {
if i >= len(c.sortedHashes) {
i = 0
}
elem = c.circle[c.sortedHashes[i]]
if !sliceContainsMember(res, elem) {
res = append(res, elem)
}
if len(res) == n {
break
}
}
return res, nil
}
func (c *Consistent) hashKey(key string) uint32 {
if len(key) < 64 {
var scratch [64]byte
copy(scratch[:], key)
return crc32.ChecksumIEEE(scratch[:len(key)])
}
return crc32.ChecksumIEEE([]byte(key))
}
func (c *Consistent) updateSortedHashes() {
hashes := c.sortedHashes[:0]
//reallocate if we're holding on to too much (1/4th)
if cap(c.sortedHashes)/(c.NumberOfReplicas*4) > len(c.circle) {
hashes = nil
}
for k := range c.circle {
hashes = append(hashes, k)
}
sort.Sort(hashes)
c.sortedHashes = hashes
}
func sliceContainsMember(set []string, member string) bool {
for _, m := range set {
if m == member {
return true
}
}
return false
}
consistent.go 源码阅读的更多相关文章
- 【原】FMDB源码阅读(三)
[原]FMDB源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 FMDB比较优秀的地方就在于对多线程的处理.所以这一篇主要是研究FMDB的多线程处理的实现.而 ...
- 【原】FMDB源码阅读(二)
[原]FMDB源码阅读(二) 本文转载请注明出处 -- polobymulberry-博客园 1. 前言 上一篇只是简单地过了一下FMDB一个简单例子的基本流程,并没有涉及到FMDB的所有方方面面,比 ...
- 【原】FMDB源码阅读(一)
[原]FMDB源码阅读(一) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 说实话,之前的SDWebImage和AFNetworking这两个组件我还是使用过的,但是对于 ...
- 【原】AFNetworking源码阅读(六)
[原]AFNetworking源码阅读(六) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这一篇的想讲的,一个就是分析一下AFSecurityPolicy文件,看看AF ...
- 【原】AFNetworking源码阅读(五)
[原]AFNetworking源码阅读(五) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇中提及到了Multipart Request的构建方法- [AFHTTP ...
- 【原】AFNetworking源码阅读(四)
[原]AFNetworking源码阅读(四) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇还遗留了很多问题,包括AFURLSessionManagerTaskDe ...
- 【原】AFNetworking源码阅读(三)
[原]AFNetworking源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇的话,主要是讲了如何通过构建一个request来生成一个data tas ...
- 【原】AFNetworking源码阅读(二)
[原]AFNetworking源码阅读(二) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇中我们在iOS Example代码中提到了AFHTTPSessionMa ...
- 【原】AFNetworking源码阅读(一)
[原]AFNetworking源码阅读(一) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 AFNetworking版本:3.0.4 由于我平常并没有经常使用AFNetw ...
随机推荐
- js获取Session的值
纯htm页面必须采用AJAX了, ASP页面:var manager='<%=session("manager")%>', ASPX页面:var manager='&l ...
- 远离压力,提高效率——Getting things done读书笔记
一.确定时间.空间和工具 二.收集阶段:填充工作篮 1. 这有助于你认识到自己面对的工用量. 2. 同时让你清楚"隧道的终点"在哪 ...
- python笔记--2--字符串、正则表达式
字符串 ASCII码采用1个字节来对字符进行编码,最多只能表示256个符号. UTF-8以3个字节表示中文 GB2312是我国制定的中文编码,使用1个字节表示英语,2个字节表示中文:GBK是GB231 ...
- H5之postMessage 。实现跨域
对于跨域我们有很多的解决方案,今天我来分享一下postMessage的那点事,postMessage是html5新增的一个解决跨域的一个方法,不过很可惜万恶的ie6,7不支持 postMessage( ...
- Space Golf~物理题目
Description You surely have never heard of this new planet surface exploration scheme, as it is bein ...
- Java Code Style
近期困惑于团队成员代码风格迥异,代码质量不可控,作为一名老司机,忧患于后期服务的可维护性,多次一对一的代码Review,耗时耗力不说,效果也不明显.痛定思痛,多次反思之后得出结论:无规矩不成方圆,可靠 ...
- C++的拷贝构造函数、operator=运算符重载,深拷贝和浅拷贝、explicit关键字
原文地址:https://blog.csdn.net/shine_journey/article/details/53081523 1.在C++编码过程中,类的创建十分频繁. 简单的功能,当然不用考虑 ...
- Hadoop的多节点集群启动,唯独没有namenode进程?(血淋淋教训,一定拍快照)(四十五)
前言 大家在搭建hadoop集群时,第一次格式化后,一路要做好快照.别随便动不动缺少什么进程,就来个格式化. 问题描述:启动hadoop时报namenode未初始化:java.io.IOExcepti ...
- 第三方支付设计——账户体系
第三方支付架构设计之-帐户体系 一, 什么是第三方支付? 什么是第三方支付?相信很多人对这个名字很熟悉,不管是从各种媒体等都经常听到,可以说是耳熟能熟.但,如果非得给这个名词 ...
- 分享一下在aspx页面弹框的设置代码
public static class MessageBox { /// <summary> /// 显示消息提示对话框 /// </summary> /// <para ...