集合散列是一种算法,它解决了与一致散列相同的问题:
…允许客户端实现分布式协议的算法
将给定对象放置在哪个站点(或代理)上。
集合哈希具有以下属性。
低开销:使用的哈希函数是高效的,因此客户端的开销非常低。
负载平衡:由于散列函数是随机的,所以n个站点中的每一个都有可能接收到对象O
穿过各个地点。
高命中率:由于所有客户端都同意将对象O放置到同一站点中,因此,每次获取或放置O时,都会产生
最大命中率的效用。对象o将始终是
找到它,除非它在so被某个替换算法逐出。
最小中断:当站点失败时,只需要重新映射映射映射到该站点的对象。破坏是在尽可能小的范围内
水平,如
[1]。
-Wikipedia: Rendezvous hashing
好极了。现在,我已经实现了一个修改版本,它将一组密钥映射到before的存储箱中,并且看起来工作得非常出色:
斯宾斯C:
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <limits.h>
#include <assert.h>
#include <math.h>
//#include <blake2.h>
#define MAX(x, y) ((x) > (y) ? (x) : (y))
#define NODES 20
#define KEYS 16777216
#define CSKIP 1048576
__uint128_t hashes[NODES] = {0};
int count[NODES] = {0};
static inline int rendezvous (__uint128_t *pool, uint64_t id) {
register int x, bin = 0;
register __uint128_t max = 0, cache;
for (x = 0; x < NODES; x++) {
// blake2 ((void *) &cache, &pool[x], &id, sizeof (cache), sizeof (pool[x]), sizeof (id));
cache = pool[x] * ~id;
max = MAX (max, cache);
bin = max == cache ? x : bin;
}
return bin;
}
int main (int argc, char **argv) {
assert (fread (hashes, sizeof (hashes[0]), NODES, stdin) == NODES);
register int x, bin;
for (x = 0; x < KEYS; x++) {
bin = rendezvous (hashes, x);
count[bin]++;
if (!(x % CSKIP)) {fprintf (stdout, "%i\n", x);}
}
fputs ("\n\n\n\n\n\n\n\n", stdout);
float avg = (float) KEYS / (float) NODES;
float mad = 0;
for (x = 0; x < NODES; x++) {
fprintf (stdout, "Bin %i\t: %i\n", x, count[x]);
mad += abs ((float) count[x] - avg);
}
fputs ("\n\n\n\n\n\n\n\n", stdout);
fprintf (stdout, "avg: keys/bin\t= %f\n", avg);
mad /= (float) NODES;
fprintf (stdout, "mad: keys/bin\t= %f\n", mad);
float moa = mad / avg;
moa *= 100;
fprintf (stdout, "mad / avg\t= %05.2f %%\n", moa);
return 0;
}
当使用
gcc sbins.c -lm
编译并使用cat /dev/urandom | ./a.out
运行时,它似乎分布得相当好:1048576
2097152
3145728
4194304
5242880
6291456
7340032
8388608
9437184
10485760
11534336
12582912
13631488
14680064
15728640
Bin 0 : 838966
Bin 1 : 838596
Bin 2 : 839535
Bin 3 : 838835
Bin 4 : 839220
Bin 5 : 838759
Bin 6 : 838907
Bin 7 : 838903
Bin 8 : 838302
Bin 9 : 838726
Bin 10 : 838522
Bin 11 : 838034
Bin 12 : 839020
Bin 13 : 839334
Bin 14 : 838898
Bin 15 : 838905
Bin 16 : 838984
Bin 17 : 838753
Bin 18 : 838956
Bin 19 : 839061
avg: keys/bin = 838860.812500
mad: keys/bin = 235.500000
mad / avg = 00.03 %
到目前为止,一切都好。所以过了一段时间(也就是现在),我实际上需要编写使用它的代码我知道我需要副本,所以我想我只需存储、排序和返回一个列表,而不是总是选择最高的值最后,为了完成这项任务,我在两个文件中创建了一组类似的例程,基于上面所写的内容:
rendezvous.h(包含实际集合代码的头文件):
#pragma once
// adapted from
// http://git.io/pgkqvw
// (haneefmubarak/experiments/rendezvous)
//=== Includes
#include <stdint.h>
#include <stdlib.h>
//=== Structures
typedef struct {
__uint128_t val;
int bin;
} rdv;
//=== Special
#define SORT_NAME rendezvous
#define SORT_TYPE rdv
#define SORT_CMP(x, y) ((((rdv)x).val) - (((rdv)y).val))
#include "./deps/sort/sort.h"
//=== Functions
static inline int *rendezvous (__uint128_t *pool, uint64_t id, int nodes) {
register int x;
// store temporary results
rdv *cache = malloc (nodes * sizeof (rdv));
if (!cache)
return NULL;
int *bin = malloc (nodes * sizeof (int));
if (!bin) {
free (cache);
return NULL;
}
// calculate for each server
for (x = 0; x < nodes; x++) {
cache[x].val = pool[x] * ~id;
cache[x].bin = x;
}
// sort the results
rendezvous_tim_sort (cache, nodes);
// extract the results
for (x = 0; x < nodes; x++) {
bin[x] = cache[x].bin;
}
// cleanup
free (cache);
return bin;
}
还有一个测试程序:
试验/会合.c(试验):
#include <stdio.h>
#include <assert.h>
#include "../rendezvous.h"
#define NODES 20
#define REPFAC 4
#define KEYS 16777216
#define CSKIP 1048576
__uint128_t hashes[NODES] = {0};
int count[REPFAC][NODES] = {{0}};
int main (int argc, char **argv) {
assert (fread (hashes, sizeof (hashes[0]), NODES, stdin) == NODES);
register uint64_t x, y;
register int *bin;
for (x = 0; x < KEYS; x++) {
bin = rendezvous (hashes, x, NODES);
for (y = 0; y < REPFAC; y++)
count[y][bin[y]] += 1;
free (bin);
if (!(x % CSKIP)) {fprintf (stdout, "%llu\n", x);}
}
for (x = 0; x < REPFAC; x++) {
fputs ("\n\n\n\n\n\n\n\n", stdout);
fprintf (stdout, "RepSet %llu\n", x);
for (y = 0; y < NODES; y++)
fprintf (stdout, "Bin %llu\t: %i\n", y, count[x][y]);
}
return 0;
}
注意:文件“sort.h”来自github:swenson/sort。
但是,当使用
gcc rendezvous.c
编译此文件并使用cat /dev/urandom | ./a.out
运行它时,代码似乎失败了:0
1048576
2097152
3145728
4194304
5242880
6291456
7340032
8388608
9437184
10485760
11534336
12582912
13631488
14680064
15728640
RepSet 0
Bin 0 : 0
Bin 1 : 16777216
Bin 2 : 0
Bin 3 : 0
Bin 4 : 0
Bin 5 : 0
Bin 6 : 0
Bin 7 : 0
Bin 8 : 0
Bin 9 : 0
Bin 10 : 0
Bin 11 : 0
Bin 12 : 0
Bin 13 : 0
Bin 14 : 0
Bin 15 : 0
Bin 16 : 0
Bin 17 : 0
Bin 18 : 0
Bin 19 : 0
RepSet 1
Bin 0 : 0
Bin 1 : 0
Bin 2 : 16777216
Bin 3 : 0
Bin 4 : 0
Bin 5 : 0
Bin 6 : 0
Bin 7 : 0
Bin 8 : 0
Bin 9 : 0
Bin 10 : 0
Bin 11 : 0
Bin 12 : 0
Bin 13 : 0
Bin 14 : 0
Bin 15 : 0
Bin 16 : 0
Bin 17 : 0
Bin 18 : 0
Bin 19 : 0
RepSet 2
Bin 0 : 0
Bin 1 : 0
Bin 2 : 0
Bin 3 : 16777216
Bin 4 : 0
Bin 5 : 0
Bin 6 : 0
Bin 7 : 0
Bin 8 : 0
Bin 9 : 0
Bin 10 : 0
Bin 11 : 0
Bin 12 : 0
Bin 13 : 0
Bin 14 : 0
Bin 15 : 0
Bin 16 : 0
Bin 17 : 0
Bin 18 : 0
Bin 19 : 0
RepSet 3
Bin 0 : 0
Bin 1 : 0
Bin 2 : 0
Bin 3 : 0
Bin 4 : 16777216
Bin 5 : 0
Bin 6 : 0
Bin 7 : 0
Bin 8 : 0
Bin 9 : 0
Bin 10 : 0
Bin 11 : 0
Bin 12 : 0
Bin 13 : 0
Bin 14 : 0
Bin 15 : 0
Bin 16 : 0
Bin 17 : 0
Bin 18 : 0
Bin 19 : 0
我试图找出问题的原因。我甚至认为我可能有一个优先级问题,或者有什么
count[y][bin[y]]++
的问题,所以我改变了,但是没有用我认为错误在rendezvous.h
中,但在这一点上,我几乎没有什么想法,也没有任何线索。理想情况下,第二个程序的输出应该均匀分布,类似于第一个程序。但我找不到唯一一个被填满的箱子。
那么我怎样才能让程序正常工作呢如有任何帮助,我们将不胜感激。
最佳答案
重新调整比较器算法请记住,您使用的是无符号值。因此,这方面的比较器:
#define SORT_CMP(x, y) ((((rdv)x).val) - (((rdv)y).val))
如果
x.val
永远小于y.val
将下溢。反过来,这又使得任何人假设一个标准的“负、零、正”结果来规定“少、等、大”都将失败。它们都将是“更大的”(假设底流返回正数;陷阱条件不受影响;技术上是它的ub),或者充其量是“相等的”…好。。。平等。我修改了您的代码以使用
qsort()
和一个比较器,简单地说:int cmp_rdv(const void *arg1, const void* arg2)
{
const rdv* lhs = arg1;
const rdv* rhs = arg2;
return (lhs->val < rhs->val) ? -1 : (rhs->val < lhs->val);
}
然后按原样调用它,抛出旧算法:
// calculate for each server
for (x = 0; x < nodes; x++) {
cache[x].val = pool[x] * ~id;
cache[x].bin = x;
}
// sort the results
qsort(cache, nodes, sizeof(*cache), cmp_rdv);
// extract the results
for (x = 0; x < nodes; x++) {
bin[x] = cache[x].bin;
}
结果如下,很可能是你要找的(我清理了墙壁上的新线,为自己的理智添加了一些禁忌)。
0
1048576
2097152
3145728
4194304
5242880
6291456
7340032
8388608
9437184
10485760
11534336
12582912
13631488
14680064
15728640
RepSet 0
Bin 0 : 838214
Bin 1 : 838719
Bin 2 : 838792
Bin 3 : 839251
Bin 4 : 838699
Bin 5 : 838436
Bin 6 : 838827
Bin 7 : 839038
Bin 8 : 839062
Bin 9 : 838787
Bin 10 : 839000
Bin 11 : 838683
Bin 12 : 839024
Bin 13 : 838922
Bin 14 : 838847
Bin 15 : 839312
Bin 16 : 838980
Bin 17 : 838607
Bin 18 : 839191
Bin 19 : 838825
RepSet 1
Bin 0 : 840405
Bin 1 : 838603
Bin 2 : 838612
Bin 3 : 837891
Bin 4 : 839700
Bin 5 : 839559
Bin 6 : 838918
Bin 7 : 838834
Bin 8 : 839128
Bin 9 : 838711
Bin 10 : 838930
Bin 11 : 839856
Bin 12 : 838654
Bin 13 : 837914
Bin 14 : 838665
Bin 15 : 837965
Bin 16 : 838278
Bin 17 : 839167
Bin 18 : 837817
Bin 19 : 839609
RepSet 2
Bin 0 : 838054
Bin 1 : 838727
Bin 2 : 838852
Bin 3 : 839306
Bin 4 : 837806
Bin 5 : 838103
Bin 6 : 838929
Bin 7 : 837990
Bin 8 : 837851
Bin 9 : 838877
Bin 10 : 838228
Bin 11 : 837360
Bin 12 : 839282
Bin 13 : 840473
Bin 14 : 839353
Bin 15 : 840022
Bin 16 : 840401
Bin 17 : 838826
Bin 18 : 840139
Bin 19 : 838637
RepSet 3
Bin 0 : 838545
Bin 1 : 840246
Bin 2 : 839210
Bin 3 : 839441
Bin 4 : 838555
Bin 5 : 838835
Bin 6 : 838539
Bin 7 : 839562
Bin 8 : 838275
Bin 9 : 839164
Bin 10 : 839194
Bin 11 : 840005
Bin 12 : 838463
Bin 13 : 837821
Bin 14 : 839498
Bin 15 : 838393
Bin 16 : 837376
Bin 17 : 838632
Bin 18 : 839393
Bin 19 : 838069
我没有下载你提到的分类源,只是因为我很懒(为什么撒谎?)。但我确实检查了当您不提供时默认值是什么,它是:
#define SORT_CMP(x, y) ((x) < (y) ? -1 : ((x) == (y) ? 0 : 1))
证实我的怀疑,他们需要我们都习惯提供的小于零/大于零的标准三重奏你可能需要你的jus算法来匹配这个格式,它会给你你想要的。
祝你好运。
关于c - 如何使此集合哈希代码起作用?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25589098/