如何通过算法划分密钥空间?

时间:2010-05-28 20:19:16

标签: hash data-partitioning

这与一致性哈希有关,虽然我在概念上理解我需要做什么,但我很难将其转换为代码。

我正在尝试将给定的密钥空间(例如,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;
}

3 个答案:

答案 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;
}