Algorithm-ConsistentHash-Ketama
view release on metacpan or search on metacpan
xs/Ketama.xs view on Meta::CPAN
int len;
p->numbuckets++;
p->totalweight += weight;
if (p->numbuckets == 1) {
Newxz( p->buckets, p->numbuckets, PerlKetama_Bucket );
} else {
Renew( p->buckets, p->numbuckets, PerlKetama_Bucket );
}
len = strlen(server);
Newxz( p->buckets[p->numbuckets - 1].label, len + 1, char );
Copy(server, p->buckets[p->numbuckets - 1].label, len + 1, char);
p->buckets[p->numbuckets - 1].weight = weight;
PerlKetama_clear_continuum( p );
}
static void
PerlKetama_remove_bucket(PerlKetama *p, char *server)
{
unsigned int i;
for( i = 0; i < p->numbuckets; i++ ) {
if ( strEQ(p->buckets[i].label, server) ) {
Safefree(p->buckets[i].label);
p->totalweight -= p->buckets[i].weight;
for( i += 1; i < p->numbuckets; i++) {
StructCopy(&(p->buckets[i]), &(p->buckets[i - 1]), PerlKetama_Bucket);
}
p->numbuckets--;
Renew(p->buckets, p->numbuckets, PerlKetama_Bucket);
i = p->numbuckets;
}
}
PerlKetama_clear_continuum( p );
}
static int
PerlKetama_buckets(PerlKetama *p)
{
unsigned int i;
SV *sv;
dSP;
PerlKetama_Bucket s;
SP -= 1; /* must offset for object */
for(i = 0; i < p->numbuckets; i++) {
{
s = p->buckets[i];
ENTER;
SAVETMPS;
PUSHMARK(SP);
mXPUSHp( "Algorithm::ConsistentHash::Ketama::Bucket", 41 );
mXPUSHp( "label", 5 );
mXPUSHp( s.label, strlen(s.label) );
mXPUSHp( "weight", 6 );
mXPUSHi( s.weight );
PUTBACK;
call_method("new", G_SCALAR);
SPAGAIN;
sv = POPs;
SvREFCNT_inc(sv);
PUTBACK;
FREETMPS;
LEAVE;
}
XPUSHs( sv );
}
return p->numbuckets;
}
static int
PerlKetama_continuum_compare( PerlKetama_Continuum_Point *a, PerlKetama_Continuum_Point *b )
{
if (a->point < b->point) return -1;
if (a->point > b->point) return 1;
return 0;
}
#define MAX_SS_BUF 8192
static void
PerlKetama_create_continuum( PerlKetama *ketama )
{
unsigned int i, k, h;
char ss[MAX_SS_BUF];
unsigned char digest[16];
unsigned int continuum_idx;
PerlKetama_Continuum_Point *continuum;
continuum_idx = 0;
Newxz(continuum, ketama->numbuckets * 160, PerlKetama_Continuum_Point);
for ( i = 0; i < ketama->numbuckets; i++ ) {
PerlKetama_Bucket *b = ketama->buckets + i;
float pct = b->weight / (float) ketama->totalweight;
unsigned int k_limit = floorf(pct * 40.0 * ketama->numbuckets);
for ( k = 0; k < k_limit; k++ ) {
/* 40 hashes, 4 numbers per hash = 160 points per bucket */
if (snprintf(ss, MAX_SS_BUF, "%s-%d", b->label, k) >= MAX_SS_BUF) {
croak("snprintf() overflow detected for key '%s-%d'. Please use shorter labels", b->label, k);
}
PerlKetama_md5_digest(ss, strlen(ss), digest);
for( h = 0; h < 4; h++ ) {
continuum[ continuum_idx ].point = ( digest[3 + h * 4] << 24 )
| ( digest[2 + h * 4] << 16 )
| ( digest[1 + h * 4] << 8 )
| ( digest[h * 4] )
;
continuum[ continuum_idx ].bucket = b;
continuum_idx++;
}
}
}
Renew( continuum, continuum_idx, PerlKetama_Continuum_Point );
qsort( (void *) continuum, continuum_idx, sizeof(PerlKetama_Continuum_Point), (compfn) PerlKetama_continuum_compare );
if (ketama->numpoints > 0) {
Safefree(ketama->continuum);
}
( run in 2.429 seconds using v1.01-cache-2.11-cpan-13bb782fe5a )