util.h

IP转换函数,将二进制的IP地址转化为点分十进制的形式。

/*
* Convert IP (in network order) to string
*/
inline char* ip2a(uint32_t ip, char* addr) {
sprintf(addr, "%d.%d.%d.%d", ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) &
0xff, (ip >> 24) & 0xff);
return addr;
}

hash.hpp/cpp

mangle函数

为解决在不同机器上 C++的二进制兼容问题,使用mangle函数转化源码中的函数,因为在不同的编译器或不同的编译器版本,编译后的名称可能会有不同。

(或是使用seq-hash,测量heavy hitter heavy changers,提升了内存使用率,减少了计算开销,最关键的是可以恢复流的信息

把一个key值按照位分为几个段,分别hash进一个二维表里面,最后再把这些二维表的值合并出这个key)

void mangle(const unsigned char* key, unsigned char* ret_key,
int nbytes) {
unsigned long long new_key = 0;
int i;
for (i=0; i<nbytes; ++i) {
new_key |= key[nbytes-i-1] << (i * 8);
}
new_key = (new_key * 2083697005) & (0xffffffff);
for (i=0; i<nbytes; ++i) {
ret_key[i] = (new_key >> (i * 8)) & 0xff;
}
}

GenHashSeed函数

产生一个随机数的种子返回值。

uint64_t seed = 0;
uint64_t GenHashSeed(int index) {
/*
if (index == 0) {
srand(0);
}
*/
if (seed == 0) {
seed = rand();
}
uint64_t x, y = seed + index;
mangle((const unsigned char*)&y, (unsigned char*)&x, 8);
return AwareHash((uint8_t*)&y, 8, 388650253, 388650319, 1176845762);
}

AwareHash模块

接受参数:原数据、原数据长度。哈希值的初始值为388650253,乘以规模388650319,再和数据相加后,向后移动一个数据,数据有多长就跑几次。数据中心的流量是非常巨大的,要将对如此巨大的流量产生随机分布的哈希值,这个哈希值也将非常巨大,也难怪在自己的虚拟机上,把数值调小了几倍还是溢出。最后对1176845762进行异或处理

/**
* hash function
* @param data the binary to be hashed
* @param n the length of binary to be hashed
*/
static unsigned int AwareHash(const unsigned char* data, unsigned int n) {
unsigned int hash = 388650253;
unsigned int scale = 388650319;
unsigned int hardener = 1176845762;
while( n ) {
hash *= scale;
hash += *data++;
n--;
}
return hash ^ hardener;
}

LDSketch.hpp/cpp

LDSketch更新函数,对一个sketch插入键值对。

可在前部分使用mangle函数encode key值。利用LD_Sketch_find 函数,找到一个位置,再更新到桶内

/*
* Sequential hashign algorithm - encode keys (a.k.a. update step)
*/
void LDSketch_update(LDSketch_t* sk, unsigned char* key, long long val) {
int j, k; // mangle
// mangle(key, key_to_add, tbl->n/8); // add key/val to table
for (j=0; j<sk->h; ++j) {
k = LDSketch_find(sk, key, 0, sk->lgn - 1, j);
//tbl->T[j*tbl->w+k] += val;
dyn_tbl_update(sk->tbl[j*sk->w+k], key, val);
}
//tbl->total += val;
}

LD_Sketch的find函数

找到一个sketch内的key的哈希值。把这个key的副本初始化为0,把key值的每一位复制到副本当中,针对这个副本的前八位按照某种方法处理一次,之后的位置就把key原值复制进去。operator为列数乘以哈希函数的id号加上用户输入的桶的位置,并把operator加入这个桶中。输入这个副本和长度,返回这个键值的哈希值。

unsigned int LDSketch_find(LDSketch_t* tbl, const unsigned char* key, int start_bit,
int end_bit, int row_no) {
unsigned char key_str[50]; // assume n/8 + 4 <= 50
unsigned int oper;
char bit;
unsigned int ret_bucket; int i; // set the key string
memset(key_str, 0, sizeof(key_str));
i = start_bit; // start_bit == 0 in all cases
while (i <= end_bit) {
if (end_bit - i + 1 >= 8) {
key_str[i/8] = key[i/8];
i += 8;
} else {
bit = (key[i/8] & (1 << (8 - ((i%8) + 1)))) > 0 ? 1 : 0;
key_str[i/8] |= (bit << (8 - ((i%8) + 1)));
i++;
}
} // set the operator and add it to key string
//oper = part_no * tbl->[part_no] + array_no;
oper = tbl->h * tbl->tbl_id + row_no;
//oper = row_no;
memcpy(key_str + tbl->lgn/8, &oper, sizeof(unsigned int)); /*
// hash
MD5_CTX md5;
unsigned char digest[16];
MD5_Init(&md5);
MD5_Update(&md5, key_str, tbl->n/8 + sizeof(unsigned int));
MD5_Final(digest, &md5);
memcpy(&ret_bucket, digest, sizeof(unsigned int)); // take 1st 4 bytes
ret_bucket = (ret_bucket % tbl->K);
*/ ret_bucket = AwareHash(key_str,
(unsigned int)(tbl->lgn/8 + sizeof(unsigned int))) % (tbl->w); // return
return ret_bucket;
}

dyn_tbl.hpp/cpp

关键词

关键字的定义,最大长度为13字节。

#define MAX_KEYLEN 13

/**
* Structure of key
*/
typedef struct dyn_tbl_key_s {
/// 13-byte key
unsigned char key[MAX_KEYLEN];
} dyn_tbl_key_t;

哈希键值

定义一个哈希函数的对象。返回该键值的哈希值

/**
* Object for hash
*/
typedef struct {
/// overloaded operation
long operator() (const dyn_tbl_key_t &k) const { return AwareHash((unsigned char*)k.key, MAX_KEYLEN); }
} dyn_tbl_key_hash;

比较函数

定义一个比较函数,判断两个字串是否相等

/**
* Object for equality
*/
typedef struct {
/// overloaded operation
bool operator() (const dyn_tbl_key_t &x, const dyn_tbl_key_t &y) const {
return memcmp(x.key, y.key, MAX_KEYLEN)==0;
}
} dyn_tbl_key_eq;

桶的数据结构

包括A(i,j),V(i,j),L(i,j),e(i,j),T,maximum.

/**
* Bucket structure
*/
typedef struct dyn_tbl_s { /// associative array: A(i,j)
std::unordered_map<dyn_tbl_key_t, long long, dyn_tbl_key_hash, dyn_tbl_key_eq> array; /// total sum: V(i,j)
long long total; /// maximum length of counters allowed, exceeding this value would trigger expansion: l(i, j)
unsigned int max_len; /// total number of decrement: e(i, j)
unsigned int decrement; /// expansion parameter: T
long long T; /// maximum sum among keys, to speed up detection
long long max_value; /***********************
* read only members
***********************/
/// length of keys
unsigned int lgn;
} dyn_tbl_t;

初始化

有参传参,无参置零

dyn_tbl_t* dyn_tbl_init(unsigned int length, int lgn, long long T) {
dyn_tbl_t* ret = (dyn_tbl_t*)calloc(1, sizeof(dyn_tbl_t));
ret->lgn = lgn;
ret->max_len = length;
ret->decrement = 0;
ret->total = 0;
ret->T = T;
ret->max_value = 0;
return ret;
}

destroy

free掉这个桶的内存空间

void dyn_tbl_destroy(dyn_tbl_t* dyn_tbl) {
free(dyn_tbl);
}

重置函数

将桶的参数置零

void dyn_tbl_reset(dyn_tbl_t* dyn_tbl) {
dyn_tbl->array.clear();
dyn_tbl->decrement = 0;
dyn_tbl->total = 0;
dyn_tbl->max_value = 0;
}

复制函数

将桶的参数复制

void dyn_tbl_copy(dyn_tbl_t* dyn_tbl_from, dyn_tbl_t* dyn_tbl_to) {
dyn_tbl_to->array = dyn_tbl_from->array;
dyn_tbl_to->decrement = dyn_tbl_from->decrement;
dyn_tbl_to->total = dyn_tbl_from->total;
dyn_tbl_to->max_len = dyn_tbl_from->max_len;
dyn_tbl_to->max_value = dyn_tbl_from->max_value;
}

输出函数

输出桶内的值,将值输出到文件中。主要输出的是桶内的IP地址的值。

void dyn_tbl_print(dyn_tbl_t* dyn_tbl, const char* output) {
FILE* fp; // open a file
if ((fp = fopen(output, "w")) == NULL) {
fprintf(stderr, "ERR: cannot open %s\n", output);
exit(-1);
} unsigned int len = dyn_tbl->array.size();
fprintf(fp, "length: %u\n", len);
// for(std::unordered_map<dyn_tbl_key_t, long long>::iterator it = dyn_tbl->array.begin(); it != dyn_tbl->array.end(); ++it) {
for(auto it = dyn_tbl->array.begin(); it != dyn_tbl->array.end(); ++it) {
dyn_tbl_key_t key = it->first;
if (dyn_tbl->lgn == 32) {
char addr1[30];
unsigned int* ptr = (unsigned int*) key.key;
fprintf(fp, "%s %lld\n", ip2a(*ptr, addr1), it->second);
}
else {
char addr1[30];
char addr2[30];
unsigned int* ptr = (unsigned int*) key.key;
fprintf(fp, "%s %s %lld\n", ip2a(*ptr, addr1), ip2a(*(ptr+1), addr2), it->second);
}
} // close the file
fclose(fp);
}

返回这个桶内的长度

int dyn_tbl_length(dyn_tbl_t* dyn_tbl) {
return dyn_tbl->array.size();
}

LD-sketch源码阅读的更多相关文章

  1. 【原】FMDB源码阅读(三)

    [原]FMDB源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 FMDB比较优秀的地方就在于对多线程的处理.所以这一篇主要是研究FMDB的多线程处理的实现.而 ...

  2. 【原】FMDB源码阅读(二)

    [原]FMDB源码阅读(二) 本文转载请注明出处 -- polobymulberry-博客园 1. 前言 上一篇只是简单地过了一下FMDB一个简单例子的基本流程,并没有涉及到FMDB的所有方方面面,比 ...

  3. 【原】FMDB源码阅读(一)

    [原]FMDB源码阅读(一) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 说实话,之前的SDWebImage和AFNetworking这两个组件我还是使用过的,但是对于 ...

  4. 【原】AFNetworking源码阅读(五)

    [原]AFNetworking源码阅读(五) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇中提及到了Multipart Request的构建方法- [AFHTTP ...

  5. [PHP源码阅读]explode和implode函数

    explode和implode函数主要用作字符串和数组间转换的操作,比如获取一段参数后根据某个字符分割字符串,或者将一个数组的结果使用一个字符合并成一个字符串输出.在PHP中经常会用到这两个函数,因此 ...

  6. spark源码阅读

    根据spark2.2的编译顺序来确定源码阅读顺序,只阅读核心的基本部分. 1.common目录 ①Tags②Sketch③Networking④Shuffle Streaming Service⑤Un ...

  7. Sping学习笔记(一)----Spring源码阅读环境的搭建

    idea搭建spring源码阅读环境 安装gradle Github下载Spring源码 新建学习spring源码的项目 idea搭建spring源码阅读环境 安装gradle 在官网中下载gradl ...

  8. JDK源码阅读-------自学笔记(一)(java.lang.Object重写toString源码)

    一.前景提要 Object类中定义有public String toString()方法,其返回值是 String 类型. 二.默认返回组成 类名+@+16进制的hashcode,当使用打印方法打印的 ...

  9. 【原】AFNetworking源码阅读(六)

    [原]AFNetworking源码阅读(六) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这一篇的想讲的,一个就是分析一下AFSecurityPolicy文件,看看AF ...

  10. 【原】AFNetworking源码阅读(四)

    [原]AFNetworking源码阅读(四) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇还遗留了很多问题,包括AFURLSessionManagerTaskDe ...

随机推荐

  1. MySQL之单表查询练习

    一.emp表 二.练习 1. 查询出部门编号为30的所有员工2. 所有销售员的姓名.编号和部门编号.3. 找出奖金高于工资的员工.4. 找出奖金高于工资60%的员工.5. 找出部门编号为10中所有经理 ...

  2. js串结构

    朴素匹配算法 //S 主串 T 模式串 //匹配失败,回溯 i = i - j + 1 j = 0 //匹配成功,返回位置 i - j function indexOf(S,T,pos = 0){ l ...

  3. python保存字典和读取字典pickle

    import pickle import numpy as np def save_obj(obj, name): with open(name + '.pkl', 'wb') as f: pickl ...

  4. BZOJ4162:shlw loves matrix II

    传送门 利用Cayley-Hamilton定理,用插值法求出特征多项式 \(P(x)\) 然后 \(M^n\equiv M^n(mod~P(x))(mod~P(x))\) 然后就多项式快速幂+取模 最 ...

  5. 007Spring Security

    01.基于Spring AOP 和 Servlet规范中Filter实现  的安全框架 <dependency> <groupId>org.springframework.se ...

  6. 【转】PHP如何快速读取大文件

    在PHP中,对于文件的读取时,最快捷的方式莫过于使用一些诸如file.file_get_contents之类的函数,简简单单的几行代码就能 很漂亮的完成我们所需要的功能.但当所操作的文件是一个比较大的 ...

  7. Grunt入门学习之(3) -- Gruntfile具体示例

    经过前面的学习,将测试的Gruntfile整合在一起! /** * Created by Administrator on 2017/6/22. */ module.exports = functio ...

  8. winfrom 实现窗体圆角

    在窗体中加入一下代码 #region 窗体圆角的实现 private void ComFrmBase_Resize(object sender, EventArgs e) { if (this.Win ...

  9. VS无法加载Web项目

    在VS中修改Web项目的服务器设置时无法加载改Web项目,提示如下图 原因:因为项目中的EbcBuy.Bll.Users.WebApi.csproj.user文件并没有加入到版本控制文件,所以讲项目还 ...

  10. 沉淀,再出发:Django的简单使用

    沉淀,再出发:Django的简单使用 一.前言     在学习了python的基础语法之后,其实大家都很怀疑python的使用场景,其实python在很多场合都有很强的适应性,就比如说web开发之中使 ...