这与一致性哈希有关,虽然我在概念上理解我需要做什么,但我很难将其转换为代码。
我正在尝试将给定的密钥空间(例如,128位)划分为相等大小的分区。我想要每个分区的上限(最高键)。
基本上,我该怎么做呢?
#define KEYSPACE_BYTE_SIZE 16
#define KEYSPACE_BIT_SIZE (KEYSPACE_BYTE_SIZE * 8)
typedef struct _key
{
char byte[KEYSPACE_BYTE_SIZE];
} key;
key * partition_keyspace( int num_partitions )
{
key * partitions = malloc( sizeof(key) * num_partitions );
// ...
}
修改
我想另一种说法是:
for (i = 0; i < num_partitions; i++)
{
partitions[i] = ((2 ^ KEYSPACE_BIT_SIZE) / num_partitions) * i;
}
当然问题是2 ^ 128是非常大数,并且不能包含在C中用于进行数学运算的任何单个整数变量中(因此char [16] struct )。
我真的不想为此使用大量的库(或任何库)。
修改
虽然,实际上我正在寻找的数字是:
for (i = 0; i < num_partitions; i++)
{
partitions[i] = (((2 ^ KEYSPACE_BIT_SIZE) / num_partitions) * (i + 1)) - 1;
}
答案 0 :(得分:2)
任何特定分区中的最高密钥显然都包含所有1
- 位。如果密钥的n
位较低,而分区ID的m
位较高,那么您需要做的就是运行m
位计数器并连接它与n
个
为了说明,假设一个8位密钥空间,分区的高2位(所以num_partitions = 2^2 = 4
,密钥的低6位。每个分区中的最高密钥将是这四个:
00 111111
01 111111
10 111111
11 111111
为了生成它们,您需要做的就是:
for (int i = 0; i < num_partitions; i++)
highest_key = (i << 6) | 0x3f // where 6 is key_bits and 0x3f is six ones.
当然,这假设num_partitions
是2的幂。
当然,对于与您一样大的密钥空间,它不会像上面那么简单,因为您无法将所有内容都放入单个变量中。尽管如此,原则仍然是一样的。只要你的num_partitions
足够小,你就可以将计数器放入一个普通的int
变量中,将其复制到高位,然后用其他变量填充其余部分是微不足道的。
答案 1 :(得分:0)
我不确定我理解你问题的背景 - 我没有研究过一致的散列。
这个问题几乎相当于“如何排序而不进行排序”。
另一种方法可能是这样做:
iter = seed() #initialize to the bottom of the hash keys
for(i = 0 to partitionbound)
{
iter = nextIter(iter);
}
这是线性时间。但是,它不需要关键空间的先验知识,除了nextIter服从的顺序。
如果您要分区[0,2 ^ 128] - &gt; {values},例如,你正在做一些分布式计算或者你是什么,你运气好得多,因为整数结构良好。
我建议稍微愚蠢的想法是在一个结构中有4个32位整数并编写你自己的bigint例程来解决你需要解决的问题。
如果你有不使用C ++的自由,Common Lisp内置了bigint。我发现它很方便。
如果你有可表示的键......
然而,当在某个空间中使用n个元素寻找一些大小相等的k分区时,我会像这样处理问题:
if( n % k)
{
return "not equal-sized partition!"
}
//could be forking/threading, whatever.
for(int i = 0; i < n; i+=k)
{
process(i, i+k-1);
}
process(bottom, top)
{
sort(a[bottom], a[top]);
return a[top]; //you'll have to figure out where to dump the results.
}
答案 2 :(得分:0)
根据tzaman的回答,这是我的解决方案。它允许最多255个分区(尽管可以更改)。它不需要2 num_partitions的功率...它只会使最后一个分区占用剩下的任何东西。
如果您发现任何错误,请告诉我......:)
key * partition_keyspace( unsigned int num_partitions )
{
assert( num_partitions > 0 );
assert( num_partitions < 0xFF );
key * partitions = (key *) malloc( sizeof(key) * num_partitions );
// fill every bit
memset( partitions, 0xFF, sizeof(key) * num_partitions );
// calculate how many bits of the top byte needs to be filled by 1's
unsigned char fill_bits = 0;
while (num_partitions > (1 << fill_bits)) fill_bits++;
fill_bits = 8 - fill_bits;
// fill the top byte with the base number of 1's
unsigned char fill_part = 0;
for (unsigned int i = 0; i < fill_bits; i++) fill_part |= 1 << i;
// last partition takes up whatever remains, so don't process it (hence the -1)
for (unsigned char i = 0; i < num_partitions - 1; i++)
{
partitions[i].byte[0] = fill_part | (i << fill_bits);
}
return partitions;
}