aboutsummaryrefslogtreecommitdiff
path: root/src/dht/gnunet-service-dht.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2011-09-13 10:17:17 +0000
committerChristian Grothoff <christian@grothoff.org>2011-09-13 10:17:17 +0000
commitd56d318035765539f8c064b91d8bf8bd8d93d78c (patch)
treeb602e4ff32ac27944c77237f394a0ebde2cd02cc /src/dht/gnunet-service-dht.c
parentbf51e53605502d2fb868655451b5d169994a62d5 (diff)
downloadgnunet-d56d318035765539f8c064b91d8bf8bd8d93d78c.tar.gz
gnunet-d56d318035765539f8c064b91d8bf8bd8d93d78c.zip
remove non-binary peer selection strategies
Diffstat (limited to 'src/dht/gnunet-service-dht.c')
-rw-r--r--src/dht/gnunet-service-dht.c466
1 files changed, 16 insertions, 450 deletions
diff --git a/src/dht/gnunet-service-dht.c b/src/dht/gnunet-service-dht.c
index 055fbe1fd..4b61ec67b 100644
--- a/src/dht/gnunet-service-dht.c
+++ b/src/dht/gnunet-service-dht.c
@@ -171,38 +171,6 @@
171 */ 171 */
172#define MAX_REPLY_TIMES 8 172#define MAX_REPLY_TIMES 8
173 173
174enum ConvergenceOptions
175{
176 /**
177 * Use the linear method for convergence.
178 */
179 DHT_CONVERGE_LINEAR,
180
181 /**
182 * Converge using a fast converging square
183 * function.
184 */
185 DHT_CONVERGE_SQUARE,
186
187 /**
188 * Converge using a slower exponential
189 * function.
190 */
191 DHT_CONVERGE_EXPONENTIAL,
192
193 /**
194 * Don't do any special convergence, allow
195 * the algorithm to hopefully route to closer
196 * peers more often.
197 */
198 DHT_CONVERGE_RANDOM,
199
200 /**
201 * Binary convergence, start routing to closest
202 * only after set number of hops.
203 */
204 DHT_CONVERGE_BINARY
205};
206 174
207/** 175/**
208 * Linked list of messages to send to clients. 176 * Linked list of messages to send to clients.
@@ -693,10 +661,6 @@ struct RepublishContext
693 661
694}; 662};
695 663
696/**
697 * Which kind of convergence will we be using?
698 */
699static enum ConvergenceOptions converge_option;
700 664
701/** 665/**
702 * Modifier for the convergence function 666 * Modifier for the convergence function
@@ -3210,144 +3174,6 @@ am_closest_peer (const GNUNET_HashCode * target,
3210 3174
3211 3175
3212/** 3176/**
3213 * Return this peers adjusted value based on the convergence
3214 * function chosen. This is the key function for randomized
3215 * routing decisions.
3216 *
3217 * @param target the key of the request
3218 * @param peer the peer we would like the value of
3219 * @param hops number of hops this message has already traveled
3220 *
3221 * @return bit distance from target to peer raised to an exponent
3222 * adjusted based on the current routing convergence algorithm
3223 *
3224 */
3225static unsigned long long
3226converge_distance (const GNUNET_HashCode * target, struct PeerInfo *peer,
3227 unsigned int hops)
3228{
3229 unsigned long long ret;
3230 unsigned int other_matching_bits;
3231 double base_converge_modifier = .1; /* Value that "looks" good (when plotted), have to start somewhere */
3232 double temp_modifier;
3233 double calc_value;
3234 double exponent;
3235 int curr_max_hops;
3236
3237 if (use_max_hops)
3238 curr_max_hops = max_hops;
3239 else
3240 curr_max_hops = (estimate_diameter () + 1) * 2;
3241
3242 if (converge_modifier > 0)
3243 temp_modifier = converge_modifier * base_converge_modifier;
3244 else
3245 {
3246 temp_modifier = base_converge_modifier;
3247 base_converge_modifier = 0.0;
3248 }
3249
3250 GNUNET_assert (temp_modifier > 0);
3251
3252 other_matching_bits =
3253 GNUNET_CRYPTO_hash_matching_bits (target, &peer->id.hashPubKey);
3254
3255 switch (converge_option)
3256 {
3257 case DHT_CONVERGE_RANDOM:
3258 return 1; /* Always return 1, choose equally among all peers */
3259 case DHT_CONVERGE_LINEAR:
3260 calc_value = hops * curr_max_hops * temp_modifier;
3261 break;
3262 case DHT_CONVERGE_SQUARE:
3263 /**
3264 * Simple square based curve.
3265 */
3266 calc_value =
3267 (sqrt (hops) / sqrt (curr_max_hops)) * (curr_max_hops /
3268 (curr_max_hops *
3269 temp_modifier));
3270 break;
3271 case DHT_CONVERGE_EXPONENTIAL:
3272 /**
3273 * Simple exponential curve.
3274 */
3275 if (base_converge_modifier > 0)
3276 calc_value = (temp_modifier * hops * hops) / curr_max_hops;
3277 else
3278 calc_value = (hops * hops) / curr_max_hops;
3279 break;
3280 case DHT_CONVERGE_BINARY:
3281 /**
3282 * If below the cutoff, route randomly (return 1),
3283 * If above the cutoff, return the maximum possible
3284 * value first (always route to closest, because
3285 * they are sorted.)
3286 */
3287
3288 if (hops >= converge_modifier) /* Past cutoff */
3289 {
3290 return ULLONG_MAX;
3291 }
3292 /* Fall through */
3293 default:
3294 return 1;
3295 }
3296
3297 /* Take the log (base e) of the number of bits matching the other peer */
3298 exponent = log (other_matching_bits);
3299
3300 /* Check if we would overflow; our largest possible value is 2^64 approx. e^44.361419555836498 */
3301 if (exponent * calc_value >= 44.361419555836498)
3302 return ULLONG_MAX;
3303
3304 /* Clear errno and all math exceptions */
3305 errno = 0;
3306 feclearexcept (FE_ALL_EXCEPT);
3307 ret = (unsigned long long) pow (other_matching_bits, calc_value);
3308 if ((errno != 0) ||
3309 fetestexcept (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW))
3310 {
3311 if (0 != fetestexcept (FE_OVERFLOW))
3312 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "FE_OVERFLOW\n");
3313 if (0 != fetestexcept (FE_INVALID))
3314 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "FE_INVALID\n");
3315 if (0 != fetestexcept (FE_UNDERFLOW))
3316 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "FE_UNDERFLOW\n");
3317 return 0;
3318 }
3319 else
3320 return ret;
3321}
3322
3323/**
3324 * Comparison function for two struct PeerInfo's
3325 * which have already had their matching bits to
3326 * some target calculated.
3327 *
3328 * @param p1 a pointer pointer to a struct PeerInfo
3329 * @param p2 a pointer pointer to a struct PeerInfo
3330 *
3331 * @return 0 if equidistant to target,
3332 * -1 if p1 is closer,
3333 * 1 if p2 is closer
3334 */
3335static int
3336compare_peers (const void *p1, const void *p2)
3337{
3338 struct PeerInfo **first = (struct PeerInfo **) p1;
3339 struct PeerInfo **second = (struct PeerInfo **) p2;
3340
3341 if ((*first)->matching_bits > (*second)->matching_bits)
3342 return -1;
3343 if ((*first)->matching_bits < (*second)->matching_bits)
3344 return 1;
3345 else
3346 return 0;
3347}
3348
3349
3350/**
3351 * Select a peer from the routing table that would be a good routing 3177 * Select a peer from the routing table that would be a good routing
3352 * destination for sending a message for "target". The resulting peer 3178 * destination for sending a message for "target". The resulting peer
3353 * must not be in the set of blocked peers.<p> 3179 * must not be in the set of blocked peers.<p>
@@ -3367,30 +3193,18 @@ select_peer (const GNUNET_HashCode * target,
3367 struct GNUNET_CONTAINER_BloomFilter *bloom, unsigned int hops) 3193 struct GNUNET_CONTAINER_BloomFilter *bloom, unsigned int hops)
3368{ 3194{
3369 unsigned int bc; 3195 unsigned int bc;
3370 unsigned int i;
3371 unsigned int count; 3196 unsigned int count;
3372 unsigned int offset; 3197 unsigned int selected;
3373 int closest_bucket;
3374 struct PeerInfo *pos; 3198 struct PeerInfo *pos;
3375 struct PeerInfo *sorted_closest[bucket_size];
3376 unsigned long long temp_converge_distance;
3377 unsigned long long total_distance;
3378 unsigned long long selected;
3379
3380#if DEBUG_DHT > 1
3381 unsigned long long stats_total_distance;
3382 double sum;
3383#endif
3384 /* For kademlia */
3385 unsigned int distance; 3199 unsigned int distance;
3386 unsigned int largest_distance; 3200 unsigned int largest_distance;
3387 struct PeerInfo *chosen; 3201 struct PeerInfo *chosen;
3388 3202
3389 total_distance = 0; 3203 /** If we are doing kademlia routing (saves some cycles) */
3390 /** If we are doing kademlia routing, or converge is binary (saves some cycles) */ 3204 if ( (strict_kademlia == GNUNET_YES) ||
3391 if ((strict_kademlia == GNUNET_YES) || 3205 (hops >= converge_modifier) )
3392 ((converge_option == DHT_CONVERGE_BINARY) && (hops >= converge_modifier)))
3393 { 3206 {
3207 /* greedy selection (closest peer that is not in bloomfilter) */
3394 largest_distance = 0; 3208 largest_distance = 0;
3395 chosen = NULL; 3209 chosen = NULL;
3396 for (bc = lowest_bucket; bc < MAX_BUCKETS; bc++) 3210 for (bc = lowest_bucket; bc < MAX_BUCKETS; bc++)
@@ -3414,284 +3228,59 @@ select_peer (const GNUNET_HashCode * target,
3414 pos = pos->next; 3228 pos = pos->next;
3415 } 3229 }
3416 } 3230 }
3417
3418 if ((largest_distance > 0) && (chosen != NULL)) 3231 if ((largest_distance > 0) && (chosen != NULL))
3419 { 3232 {
3420 GNUNET_CONTAINER_bloomfilter_add (bloom, &chosen->id.hashPubKey); 3233 GNUNET_CONTAINER_bloomfilter_add (bloom, &chosen->id.hashPubKey);
3421 return chosen; 3234 return chosen;
3422 } 3235 }
3423 else 3236 return NULL; /* no peer available or we are the closest */
3424 {
3425 return NULL;
3426 }
3427 } 3237 }
3428 3238
3429 /* GNUnet-style */
3430 total_distance = 0;
3431 /* Three steps: order peers in closest bucket (most matching bits).
3432 * Then go over all LOWER buckets (matching same bits we do)
3433 * Then go over all HIGHER buckets (matching less then we do)
3434 */
3435 3239
3436 closest_bucket = find_current_bucket (target); 3240 /* select "random" peer */
3437 GNUNET_assert (closest_bucket >= lowest_bucket); 3241 /* count number of peers that are available and not filtered */
3438 pos = k_buckets[closest_bucket].head;
3439 count = 0; 3242 count = 0;
3440 offset = 0; /* Need offset as well as count in case peers are bloomfiltered */ 3243 for (bc = lowest_bucket; bc < MAX_BUCKETS; bc++)
3441 memset (sorted_closest, 0, sizeof (sorted_closest));
3442 /* Put any peers in the closest bucket in the sorting array */
3443 while ((pos != NULL) && (count < bucket_size))
3444 {
3445 if (GNUNET_YES ==
3446 GNUNET_CONTAINER_bloomfilter_test (bloom, &pos->id.hashPubKey))
3447 {
3448 count++;
3449 pos = pos->next;
3450 continue; /* Ignore bloomfiltered peers */
3451 }
3452 pos->matching_bits =
3453 GNUNET_CRYPTO_hash_matching_bits (&pos->id.hashPubKey, target);
3454 sorted_closest[offset] = pos;
3455 pos = pos->next;
3456 offset++;
3457 count++;
3458 }
3459
3460 /* Sort the peers in descending order */
3461 qsort (&sorted_closest[0], offset, sizeof (struct PeerInfo *),
3462 &compare_peers);
3463
3464 /* Put the sorted closest peers into the possible bins first, in case of overflow. */
3465 for (i = 0; i < offset; i++)
3466 {
3467 temp_converge_distance =
3468 converge_distance (target, sorted_closest[i], hops);
3469 if (GNUNET_YES ==
3470 GNUNET_CONTAINER_bloomfilter_test (bloom,
3471 &sorted_closest[i]->id.hashPubKey))
3472 break; /* Ignore bloomfiltered peers */
3473 if (total_distance + temp_converge_distance > total_distance) /* Handle largest case and overflow */
3474 total_distance += temp_converge_distance;
3475 else
3476 break; /* overflow case */
3477 }
3478
3479 /* Now handle peers in lower buckets (matches same # of bits as target) */
3480 for (bc = lowest_bucket; bc < closest_bucket; bc++)
3481 { 3244 {
3482 pos = k_buckets[bc].head; 3245 pos = k_buckets[bc].head;
3483 count = 0;
3484 while ((pos != NULL) && (count < bucket_size)) 3246 while ((pos != NULL) && (count < bucket_size))
3485 { 3247 {
3486 if (GNUNET_YES == 3248 if (GNUNET_YES ==
3487 GNUNET_CONTAINER_bloomfilter_test (bloom, &pos->id.hashPubKey)) 3249 GNUNET_CONTAINER_bloomfilter_test (bloom, &pos->id.hashPubKey))
3488 { 3250 {
3489 count++;
3490 pos = pos->next; 3251 pos = pos->next;
3491 continue; /* Ignore bloomfiltered peers */ 3252 continue; /* Ignore bloomfiltered peers */
3492 } 3253 }
3493 temp_converge_distance = converge_distance (target, pos, hops);
3494 if (total_distance + temp_converge_distance > total_distance) /* Handle largest case and overflow */
3495 total_distance += temp_converge_distance;
3496 else
3497 break; /* overflow case */
3498 pos = pos->next;
3499 count++; 3254 count++;
3500 }
3501 }
3502
3503 /* Now handle all the further away peers */
3504 for (bc = closest_bucket + 1; bc < MAX_BUCKETS; bc++)
3505 {
3506 pos = k_buckets[bc].head;
3507 count = 0;
3508 while ((pos != NULL) && (count < bucket_size))
3509 {
3510 if (GNUNET_YES ==
3511 GNUNET_CONTAINER_bloomfilter_test (bloom, &pos->id.hashPubKey))
3512 {
3513 count++;
3514 pos = pos->next;
3515 continue; /* Ignore bloomfiltered peers */
3516 }
3517 temp_converge_distance = converge_distance (target, pos, hops);
3518 if (total_distance + temp_converge_distance > total_distance) /* Handle largest case and overflow */
3519 total_distance += temp_converge_distance;
3520 else
3521 break; /* overflow case */
3522 pos = pos->next; 3255 pos = pos->next;
3523 count++;
3524 } 3256 }
3525 } 3257 }
3526 3258 if (count == 0) /* No peers to select from! */
3527 if (total_distance == 0) /* No peers to select from! */
3528 { 3259 {
3529 increment_stats ("# failed to select peer"); 3260 increment_stats ("# failed to select peer");
3530 return NULL; 3261 return NULL;
3531 } 3262 }
3532
3533#if DEBUG_DHT_ROUTING > 1
3534 sum = 0.0;
3535 /* PRINT STATS */
3536 /* Put the sorted closest peers into the possible bins first, in case of overflow. */
3537 stats_total_distance = 0;
3538 for (i = 0; i < offset; i++)
3539 {
3540 if (GNUNET_YES ==
3541 GNUNET_CONTAINER_bloomfilter_test (bloom,
3542 &sorted_closest[i]->id.hashPubKey))
3543 break; /* Ignore bloomfiltered peers */
3544 temp_converge_distance =
3545 converge_distance (target, sorted_closest[i], hops);
3546 if (stats_total_distance + temp_converge_distance > stats_total_distance) /* Handle largest case and overflow */
3547 stats_total_distance += temp_converge_distance;
3548 else
3549 break; /* overflow case */
3550 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3551 "Choose %d matching bits (%d bits match me) (%.2f percent) converge ret %llu\n",
3552 GNUNET_CRYPTO_hash_matching_bits (&sorted_closest[i]->id.
3553 hashPubKey, target),
3554 GNUNET_CRYPTO_hash_matching_bits (&sorted_closest[i]->id.
3555 hashPubKey,
3556 &my_identity.hashPubKey),
3557 (temp_converge_distance / (double) total_distance) * 100,
3558 temp_converge_distance);
3559 }
3560
3561 /* Now handle peers in lower buckets (matches same # of bits as target) */
3562 for (bc = lowest_bucket; bc < closest_bucket; bc++)
3563 {
3564 pos = k_buckets[bc].head;
3565 count = 0;
3566 while ((pos != NULL) && (count < bucket_size))
3567 {
3568 if (GNUNET_YES ==
3569 GNUNET_CONTAINER_bloomfilter_test (bloom, &pos->id.hashPubKey))
3570 {
3571 count++;
3572 pos = pos->next;
3573 continue; /* Ignore bloomfiltered peers */
3574 }
3575 temp_converge_distance = converge_distance (target, pos, hops);
3576 if (stats_total_distance + temp_converge_distance > stats_total_distance) /* Handle largest case and overflow */
3577 stats_total_distance += temp_converge_distance;
3578 else
3579 break; /* overflow case */
3580 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3581 "Choose %d matching bits (%d bits match me) (%.2f percent) converge ret %llu\n",
3582 GNUNET_CRYPTO_hash_matching_bits (&pos->id.hashPubKey,
3583 target),
3584 GNUNET_CRYPTO_hash_matching_bits (&pos->id.hashPubKey,
3585 &my_identity.hashPubKey),
3586 (temp_converge_distance / (double) total_distance) * 100,
3587 temp_converge_distance);
3588 pos = pos->next;
3589 count++;
3590 }
3591 }
3592
3593 /* Now handle all the further away peers */
3594 for (bc = closest_bucket + 1; bc < MAX_BUCKETS; bc++)
3595 {
3596 pos = k_buckets[bc].head;
3597 count = 0;
3598 while ((pos != NULL) && (count < bucket_size))
3599 {
3600 if (GNUNET_YES ==
3601 GNUNET_CONTAINER_bloomfilter_test (bloom, &pos->id.hashPubKey))
3602 {
3603 count++;
3604 pos = pos->next;
3605 continue; /* Ignore bloomfiltered peers */
3606 }
3607 temp_converge_distance = converge_distance (target, pos, hops);
3608 if (stats_total_distance + temp_converge_distance > stats_total_distance) /* Handle largest case and overflow */
3609 stats_total_distance += temp_converge_distance;
3610 else
3611 break; /* overflow case */
3612 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3613 "Choose %d matching bits (%d bits match me) (%.2f percent) converge ret %llu\n",
3614 GNUNET_CRYPTO_hash_matching_bits (&pos->id.hashPubKey,
3615 target),
3616 GNUNET_CRYPTO_hash_matching_bits (&pos->id.hashPubKey,
3617 &my_identity.hashPubKey),
3618 (temp_converge_distance / (double) total_distance) * 100,
3619 temp_converge_distance);
3620 pos = pos->next;
3621 count++;
3622 }
3623 }
3624 /* END PRINT STATS */
3625#endif
3626
3627 /* Now actually choose a peer */ 3263 /* Now actually choose a peer */
3628 selected = 3264 selected =
3629 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, total_distance); 3265 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, count);
3630 3266 count = 0;
3631 /* Go over closest sorted peers. */ 3267 for (bc = lowest_bucket; bc < MAX_BUCKETS; bc++)
3632 for (i = 0; i < offset; i++)
3633 {
3634 if (GNUNET_YES ==
3635 GNUNET_CONTAINER_bloomfilter_test (bloom,
3636 &sorted_closest[i]->id.hashPubKey))
3637 break; /* Ignore bloomfiltered peers */
3638 temp_converge_distance =
3639 converge_distance (target, sorted_closest[i], hops);
3640 if (temp_converge_distance >= selected)
3641 return sorted_closest[i];
3642 else
3643 selected -= temp_converge_distance;
3644 }
3645
3646 /* Now handle peers in lower buckets (matches same # of bits as target) */
3647 for (bc = lowest_bucket; bc < closest_bucket; bc++)
3648 {
3649 pos = k_buckets[bc].head;
3650 count = 0;
3651 while ((pos != NULL) && (count < bucket_size))
3652 {
3653 if (GNUNET_YES ==
3654 GNUNET_CONTAINER_bloomfilter_test (bloom, &pos->id.hashPubKey))
3655 {
3656 count++;
3657 pos = pos->next;
3658 continue; /* Ignore bloomfiltered peers */
3659 }
3660 temp_converge_distance = converge_distance (target, pos, hops);
3661 if (temp_converge_distance >= selected)
3662 return pos;
3663 else
3664 selected -= temp_converge_distance;
3665 pos = pos->next;
3666 count++;
3667 }
3668 }
3669
3670 /* Now handle all the further away peers */
3671 for (bc = closest_bucket + 1; bc < MAX_BUCKETS; bc++)
3672 { 3268 {
3673 pos = k_buckets[bc].head; 3269 pos = k_buckets[bc].head;
3674 count = 0;
3675 while ((pos != NULL) && (count < bucket_size)) 3270 while ((pos != NULL) && (count < bucket_size))
3676 { 3271 {
3677 if (GNUNET_YES == 3272 if (GNUNET_YES ==
3678 GNUNET_CONTAINER_bloomfilter_test (bloom, &pos->id.hashPubKey)) 3273 GNUNET_CONTAINER_bloomfilter_test (bloom, &pos->id.hashPubKey))
3679 { 3274 {
3680 count++;
3681 pos = pos->next; 3275 pos = pos->next;
3682 continue; /* Ignore bloomfiltered peers */ 3276 continue; /* Ignore bloomfiltered peers */
3683 } 3277 }
3684 temp_converge_distance = converge_distance (target, pos, hops); 3278 if (0 == selected)
3685 if (temp_converge_distance >= selected) 3279 return pos;
3686 return pos;
3687 else
3688 selected -= temp_converge_distance;
3689 pos = pos->next; 3280 pos = pos->next;
3690 count++;
3691 } 3281 }
3692 } 3282 }
3693 3283 GNUNET_break (0);
3694 increment_stats ("# failed to select peer");
3695 return NULL; 3284 return NULL;
3696} 3285}
3697 3286
@@ -5491,29 +5080,6 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
5491 } 5080 }
5492#endif 5081#endif
5493 5082
5494 converge_option = DHT_CONVERGE_BINARY;
5495 if (GNUNET_YES ==
5496 GNUNET_CONFIGURATION_get_value_yesno (cfg, "dht", "converge_linear"))
5497 {
5498 converge_option = DHT_CONVERGE_LINEAR;
5499 }
5500 else if (GNUNET_YES ==
5501 GNUNET_CONFIGURATION_get_value_yesno (cfg, "dht",
5502 "converge_exponential"))
5503 {
5504 converge_option = DHT_CONVERGE_EXPONENTIAL;
5505 }
5506 else if (GNUNET_YES ==
5507 GNUNET_CONFIGURATION_get_value_yesno (cfg, "dht", "converge_random"))
5508 {
5509 converge_option = DHT_CONVERGE_RANDOM;
5510 }
5511 else if (GNUNET_YES ==
5512 GNUNET_CONFIGURATION_get_value_yesno (cfg, "dht", "converge_binary"))
5513 {
5514 converge_option = DHT_CONVERGE_BINARY;
5515 }
5516
5517 converge_modifier = 4.0; 5083 converge_modifier = 4.0;
5518 if (GNUNET_OK == 5084 if (GNUNET_OK ==
5519 GNUNET_CONFIGURATION_get_value_string (cfg, "dht", "converge_modifier", 5085 GNUNET_CONFIGURATION_get_value_string (cfg, "dht", "converge_modifier",