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 ...
随机推荐
- nasm汇编一些需要注意的地方
经常用msam或tasm的童鞋一下转换到nasm下可能觉得不怎么适应,它们应该先去晓习一下gas的语法,然后就适应了-that's only a joke! :) section .data v101 ...
- Greenplum测试部署笔记
按照官方Readme文档在Ubunut16.04上成功编译安装Greenplum最新代码(now:2017-11-12 21:40) 按照文档安装的过程中主要出现两个问题: 1.Root用户安装会卡在 ...
- Django1.6版本的PG数据库定义手动升级
Django1.7以后添加了migration功能,数据库定义的升级完全实现自动化,之前是通过一个叫south的app来做的.这篇文章谈一下1.6下的手动更新升级. 1.table create和ta ...
- Django之代码风格
1 代码风格 稍微关注一下下面这些代码标准风格指导规则将会对你大有益处,我们高度建议你通读词章,即便你此时可能正想跳过它. 1.1 让你的代码保持可读性的重要性 代码在读方面的重要性胜过写.一个代码块 ...
- 与班尼特·胡迪一起做生意 (HZUN-2261)
与班尼特·胡迪一起做生意 AC Time Limit: 1 s Memory Limit: 256 MB Description 马爷作为2-80X的资深土财主,靠着敏锐的商业嗅觉不断 ...
- memcached usage
https://github.com/ragnor/simple-spring-memcached/wiki/Getting-Started 1) maven <dependency> & ...
- 面向对象的WebAPI框架XXL-HEX
<面向对象的WebAPI框架XXL-HEX> 一.简介 1.1 概述 XXL-HEX 是一个简单易用的WebAPI框架, 拥有 "面向对象.数据加密.跨语言" 的 ...
- Linux(二十二)Ubuntu安装和配置
Ubuntu的介绍 Ubuntu是一个以桌面应用为主的开源GNU/Linux操作系统,Ubuntu是基于GNU/Linux,支持x86.amd64(即x64)和ppc架构,由全球化的专业开发团队(Ca ...
- Flask入门之Bootstrap介绍使用和Flask-Nav快速导航栏
一.Bootstrap Bootstrap,来自 Twitter,是目前最受欢迎的前端框架. Python中,同样可以使用Bootstrap. 1. 导入Bootstrap库 from flask_b ...
- spring boot之从零开始开发自己的网站
概述 首先要感谢两位大神,该项目的想法来源自tale和MyBlog,本项目的想法. 做了一些改造,增加了一些功能和一些代码的重构,并且更换了博客主题. 关于项目,对于开发的练手项目,能够工程化,严谨一 ...