/** * Task that looks at the 'retry_heap' and transmits all of the requests * on the heap that are ready for transmission. Then re-schedules * itself (unless the heap is empty). * * @param cls unused * @param tc scheduler context */ static void transmit_next_request_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct ClientQueryRecord *cqr; struct GNUNET_TIME_Relative delay; retry_task = GNUNET_SCHEDULER_NO_TASK; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; while (NULL != (cqr = GNUNET_CONTAINER_heap_remove_root (retry_heap))) { cqr->hnode = NULL; delay = GNUNET_TIME_absolute_get_remaining (cqr->retry_time); if (delay.rel_value_us > 0) { cqr->hnode = GNUNET_CONTAINER_heap_insert (retry_heap, cqr, cqr->retry_time.abs_value_us); retry_task = GNUNET_SCHEDULER_add_delayed (delay, &transmit_next_request_task, NULL); return; } transmit_request (cqr); cqr->hnode = GNUNET_CONTAINER_heap_insert (retry_heap, cqr, cqr->retry_time.abs_value_us); } }
/** * Store an item in the datastore. * * @param cls closure * @param key key for the item * @param size number of bytes in data * @param data content stored * @param type type of the content * @param priority priority of the content * @param anonymity anonymity-level for the content * @param replication replication-level for the content * @param expiration expiration time for the content * @param msg set to error message * @return GNUNET_OK on success */ static int heap_plugin_put (void *cls, const struct GNUNET_HashCode * key, uint32_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, uint32_t replication, struct GNUNET_TIME_Absolute expiration, char **msg) { struct Plugin *plugin = cls; struct Value *value; value = GNUNET_malloc (sizeof (struct Value) + size); value->key = *key; value->data = &value[1]; value->expire_heap = GNUNET_CONTAINER_heap_insert (plugin->by_expiration, value, expiration.abs_value); value->replication_heap = GNUNET_CONTAINER_heap_insert (plugin->by_replication, value, replication); value->expiration = expiration; if (0 == anonymity) { struct ZeroAnonByType *zabt; for (zabt = plugin->zero_head; NULL != zabt; zabt = zabt->next) if (zabt->type == type) break; if (NULL == zabt) { zabt = GNUNET_malloc (sizeof (struct ZeroAnonByType)); zabt->type = type; GNUNET_CONTAINER_DLL_insert (plugin->zero_head, plugin->zero_tail, zabt); } if (zabt->array_size == zabt->array_pos) { GNUNET_array_grow (zabt->array, zabt->array_size, zabt->array_size * 2 + 4); } value->zero_anon_offset = zabt->array_pos; zabt->array[zabt->array_pos++] = value; } value->size = size; value->priority = priority; value->anonymity = anonymity; value->replication = replication; value->type = type; memcpy (&value[1], data, size); GNUNET_CONTAINER_multihashmap_put (plugin->keyvalue, &value->key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); plugin->size += size; return GNUNET_OK; }
/** * Figure out when and how to transmit to the given peer. * * @param cls the 'struct PeerPlan' * @param tc scheduler context */ static void schedule_peer_transmission (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerPlan *pp = cls; struct GSF_RequestPlan *rp; size_t msize; struct GNUNET_TIME_Relative delay; pp->task = GNUNET_SCHEDULER_NO_TASK; if (NULL != pp->pth) { GSF_peer_transmit_cancel_ (pp->pth); pp->pth = NULL; } /* move ready requests to priority queue */ while ((NULL != (rp = GNUNET_CONTAINER_heap_peek (pp->delay_heap))) && (GNUNET_TIME_absolute_get_remaining (rp->earliest_transmission).rel_value == 0)) { GNUNET_assert (rp == GNUNET_CONTAINER_heap_remove_root (pp->delay_heap)); rp->hn = GNUNET_CONTAINER_heap_insert (pp->priority_heap, rp, rp->priority); } if (0 == GNUNET_CONTAINER_heap_get_size (pp->priority_heap)) { /* priority heap (still) empty, check for delay... */ rp = GNUNET_CONTAINER_heap_peek (pp->delay_heap); if (NULL == rp) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No active requests for plan %p.\n", pp); return; /* both queues empty */ } delay = GNUNET_TIME_absolute_get_remaining (rp->earliest_transmission); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sleeping for %llu ms before retrying requests on plan %p.\n", (unsigned long long) delay.rel_value, pp); GNUNET_STATISTICS_set (GSF_stats, gettext_noop ("# delay heap timeout"), delay.rel_value, GNUNET_NO); pp->task = GNUNET_SCHEDULER_add_delayed (delay, &schedule_peer_transmission, pp); return; } #if INSANE_STATISTICS GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# query plans executed"), 1, GNUNET_NO); #endif /* process from priority heap */ rp = GNUNET_CONTAINER_heap_peek (pp->priority_heap); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing query plan %p\n", rp); GNUNET_assert (NULL != rp); msize = GSF_pending_request_get_message_ (get_latest (rp), 0, NULL); pp->pth = GSF_peer_transmit_ (pp->cp, GNUNET_YES, rp->priority, GNUNET_TIME_UNIT_FOREVER_REL, msize, &transmit_message_callback, pp); GNUNET_assert (NULL != pp->pth); }
/** * Get a random item for replication. Returns a single, not expired, * random item from those with the highest replication counters. The * item's replication counter is decremented by one IF it was positive * before. Call 'proc' with all values ZERO or NULL if the datastore * is empty. * * @param cls closure * @param proc function to call the value (once only). * @param proc_cls closure for proc */ static void heap_plugin_get_replication (void *cls, PluginDatumProcessor proc, void *proc_cls) { struct Plugin *plugin = cls; struct Value *value; value = GNUNET_CONTAINER_heap_remove_root (plugin->by_replication); if (NULL == value) { proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } if (value->replication > 0) { value->replication--; value->replication_heap = GNUNET_CONTAINER_heap_insert (plugin->by_replication, value, value->replication); } else { /* need a better way to pick a random item, replication level is always 0 */ value->replication_heap = GNUNET_CONTAINER_heap_insert (plugin->by_replication, value, value->replication); value = GNUNET_CONTAINER_heap_walk_get_next (plugin->by_replication); } if (GNUNET_NO == proc (proc_cls, &value->key, value->size, &value[1], value->type, value->priority, value->anonymity, value->expiration, (uint64_t) (long) value)) delete_value (plugin, value); }
/** * Add a new entry to our routing table. * * @param sender peer that originated the request * @param type type of the block * @param options options for processing * @param key key for the content * @param xquery extended query * @param xquery_size number of bytes in xquery * @param reply_bf bloomfilter to filter duplicates * @param reply_bf_mutator mutator for reply_bf */ void GDS_ROUTING_add (const struct GNUNET_PeerIdentity *sender, enum GNUNET_BLOCK_Type type, enum GNUNET_DHT_RouteOption options, const struct GNUNET_HashCode * key, const void *xquery, size_t xquery_size, const struct GNUNET_CONTAINER_BloomFilter *reply_bf, uint32_t reply_bf_mutator) { struct RecentRequest *recent_req; while (GNUNET_CONTAINER_heap_get_size (recent_heap) >= DHT_MAX_RECENT) expire_oldest_entry (); GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# Entries added to routing table"), 1, GNUNET_NO); recent_req = GNUNET_malloc (sizeof (struct RecentRequest) + xquery_size); recent_req->peer = *sender; recent_req->key = *key; recent_req->reply_bf = GNUNET_CONTAINER_bloomfilter_copy (reply_bf); recent_req->type = type; recent_req->options = options; recent_req->xquery = &recent_req[1]; memcpy (&recent_req[1], xquery, xquery_size); recent_req->xquery_size = xquery_size; recent_req->reply_bf_mutator = reply_bf_mutator; if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_get_multiple (recent_map, key, &try_combine_recent, recent_req)) { GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# DHT requests combined"), 1, GNUNET_NO); return; } recent_req->heap_node = GNUNET_CONTAINER_heap_insert (recent_heap, recent_req, GNUNET_TIME_absolute_get ().abs_value); GNUNET_CONTAINER_multihashmap_put (recent_map, key, recent_req, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); }
/** * Handler for DHT GET messages from the client. * * @param cls closure for the service * @param client the client we received this message from * @param message the actual message received */ static void handle_dht_local_get (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct GNUNET_DHT_ClientGetMessage *get; struct ClientQueryRecord *cqr; size_t xquery_size; const char *xquery; uint16_t size; size = ntohs (message->size); if (size < sizeof (struct GNUNET_DHT_ClientGetMessage)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } xquery_size = size - sizeof (struct GNUNET_DHT_ClientGetMessage); get = (const struct GNUNET_DHT_ClientGetMessage *) message; xquery = (const char *) &get[1]; GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# GET requests received from clients"), 1, GNUNET_NO); LOG (GNUNET_ERROR_TYPE_DEBUG, "Received GET request for %s from local client %p, xq: %.*s\n", GNUNET_h2s (&get->key), client, xquery_size, xquery); LOG_TRAFFIC (GNUNET_ERROR_TYPE_DEBUG, "XDHT CLIENT-GET %s @ %u\n", GNUNET_h2s (&get->key), getpid ()); cqr = GNUNET_malloc (sizeof (struct ClientQueryRecord) + xquery_size); cqr->key = get->key; cqr->client = find_active_client (client); cqr->xquery = (void *) &cqr[1]; memcpy (&cqr[1], xquery, xquery_size); cqr->hnode = GNUNET_CONTAINER_heap_insert (retry_heap, cqr, 0); cqr->retry_frequency = GNUNET_TIME_UNIT_SECONDS; cqr->retry_time = GNUNET_TIME_absolute_get (); cqr->unique_id = get->unique_id; cqr->xquery_size = xquery_size; cqr->replication = ntohl (get->desired_replication_level); cqr->msg_options = ntohl (get->options); cqr->type = ntohl (get->type); // FIXME use cqr->key, set multihashmap create to GNUNET_YES GNUNET_CONTAINER_multihashmap_put (forward_map, &get->key, cqr, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); GDS_CLIENTS_process_get (ntohl (get->options), ntohl (get->type), 0, ntohl (get->desired_replication_level), 1, GDS_NEIGHBOURS_get_id(), &get->key); /* start remote requests */ if (GNUNET_SCHEDULER_NO_TASK != retry_task) GNUNET_SCHEDULER_cancel (retry_task); retry_task = GNUNET_SCHEDULER_add_now (&transmit_next_request_task, NULL); /* perform local lookup */ GDS_DATACACHE_handle_get (&get->key, cqr->type, cqr->xquery, xquery_size, NULL, 0); GNUNET_SERVER_receive_done (client, GNUNET_OK); }
static int check () { struct GNUNET_CONTAINER_Heap *myHeap; struct GNUNET_CONTAINER_HeapNode *n1; struct GNUNET_CONTAINER_HeapNode *n2; struct GNUNET_CONTAINER_HeapNode *n3; struct GNUNET_CONTAINER_HeapNode *n4; struct GNUNET_CONTAINER_HeapNode *n5; struct GNUNET_CONTAINER_HeapNode *n6; struct GNUNET_CONTAINER_HeapNode *n7; struct GNUNET_CONTAINER_HeapNode *n8; const char *r; myHeap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); // GNUNET_CONTAINER_heap_remove_root heap empty, taking if-branch n1 = GNUNET_CONTAINER_heap_remove_root (myHeap); GNUNET_assert (NULL == n1); // GNUNET_CONTAINER_heap_peek heap empty, taking if-branch n1 = GNUNET_CONTAINER_heap_peek (myHeap); GNUNET_assert (NULL == n1); // GNUNET_CONTAINER_heap_walk_get_next: heap empty, taking if-branch n1 = GNUNET_CONTAINER_heap_walk_get_next (myHeap); GNUNET_assert (NULL == n1); n1 = GNUNET_CONTAINER_heap_insert (myHeap, "11", 11); GNUNET_assert (NULL != n1); // GNUNET_CONTAINER_heap_peek not empty, taking if-branch n2 = NULL; n2 = GNUNET_CONTAINER_heap_peek (myHeap); GNUNET_assert (NULL != n2); // GNUNET_CONTAINER_heap_walk_get_next: 1 element n1 = NULL; n1 = GNUNET_CONTAINER_heap_walk_get_next (myHeap); GNUNET_assert (NULL != n1); GNUNET_CONTAINER_heap_iterate (myHeap, &iterator_callback, NULL); GNUNET_assert (1 == GNUNET_CONTAINER_heap_get_size (myHeap)); n2 = GNUNET_CONTAINER_heap_insert (myHeap, "78", 78); GNUNET_assert (2 == GNUNET_CONTAINER_heap_get_size (myHeap)); GNUNET_assert (0 == strcmp ("78", GNUNET_CONTAINER_heap_remove_node (n2))); GNUNET_assert (1 == GNUNET_CONTAINER_heap_get_size (myHeap)); GNUNET_CONTAINER_heap_iterate (myHeap, &iterator_callback, NULL); n3 = GNUNET_CONTAINER_heap_insert (myHeap, "15", 5); GNUNET_CONTAINER_heap_update_cost (myHeap, n3, 15); GNUNET_assert (2 == GNUNET_CONTAINER_heap_get_size (myHeap)); GNUNET_CONTAINER_heap_iterate (myHeap, &iterator_callback, NULL); n4 = GNUNET_CONTAINER_heap_insert (myHeap, "50", 50); GNUNET_CONTAINER_heap_update_cost (myHeap, n4, 50); GNUNET_assert (3 == GNUNET_CONTAINER_heap_get_size (myHeap)); GNUNET_CONTAINER_heap_iterate (myHeap, &iterator_callback, NULL); n5 = GNUNET_CONTAINER_heap_insert (myHeap, "100", 100); n6 = GNUNET_CONTAINER_heap_insert (myHeap, "30/200", 30); GNUNET_assert (5 == GNUNET_CONTAINER_heap_get_size (myHeap)); GNUNET_CONTAINER_heap_remove_node (n5); r = GNUNET_CONTAINER_heap_remove_root (myHeap); /* n1 */ GNUNET_assert (NULL != r); GNUNET_assert (0 == strcmp ("11", r)); GNUNET_CONTAINER_heap_update_cost (myHeap, n6, 200); GNUNET_CONTAINER_heap_remove_node (n3); r = GNUNET_CONTAINER_heap_remove_root (myHeap); /* n4 */ GNUNET_assert (NULL != r); GNUNET_assert (0 == strcmp ("50", r)); r = GNUNET_CONTAINER_heap_remove_root (myHeap); /* n6 */ GNUNET_assert (NULL != r); GNUNET_assert (0 == strcmp ("30/200", r)); GNUNET_assert (0 == GNUNET_CONTAINER_heap_get_size (myHeap)); GNUNET_CONTAINER_heap_destroy (myHeap); // My additions to a complete testcase // Testing a GNUNET_CONTAINER_HEAP_ORDER_MIN // Testing remove_node myHeap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); GNUNET_CONTAINER_heap_update_cost (myHeap, n1, 15); r = GNUNET_CONTAINER_heap_remove_node (n1); GNUNET_assert (NULL != r); GNUNET_assert (0 == strcmp ("10", r)); n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 10); GNUNET_CONTAINER_heap_walk_get_next (myHeap); r = GNUNET_CONTAINER_heap_remove_node (n2); GNUNET_assert (NULL != r); GNUNET_assert (0 == strcmp ("20", r)); r = GNUNET_CONTAINER_heap_remove_node (n1); GNUNET_assert (NULL != r); GNUNET_assert (0 == strcmp ("10", r)); n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 10); n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 10); GNUNET_CONTAINER_heap_remove_node (n2); GNUNET_CONTAINER_heap_remove_node (n1); r = GNUNET_CONTAINER_heap_remove_root (myHeap); GNUNET_assert (NULL != r); GNUNET_assert (0 == strcmp ("30", r)); n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 10); n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 10); GNUNET_CONTAINER_heap_remove_node (n2); GNUNET_CONTAINER_heap_remove_node (n1); r = GNUNET_CONTAINER_heap_remove_node (n3); GNUNET_assert (NULL != r); GNUNET_assert (0 == strcmp ("30", r)); n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 20); n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 30); GNUNET_assert (0 == nstrcmp ("20", GNUNET_CONTAINER_heap_remove_node (n2))); GNUNET_assert (0 == nstrcmp ("10", GNUNET_CONTAINER_heap_remove_root (myHeap))); GNUNET_assert (0 == nstrcmp ("30", GNUNET_CONTAINER_heap_remove_root (myHeap))); n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 20); n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 30); n4 = GNUNET_CONTAINER_heap_insert (myHeap, "40", 40); n5 = GNUNET_CONTAINER_heap_insert (myHeap, "50", 50); n6 = GNUNET_CONTAINER_heap_insert (myHeap, "60", 60); // Inserting nodes deeper in the tree with lower costs n7 = GNUNET_CONTAINER_heap_insert (myHeap, "70", 10); n8 = GNUNET_CONTAINER_heap_insert (myHeap, "80", 10); GNUNET_assert (0 == nstrcmp ("30", GNUNET_CONTAINER_heap_remove_node (n3))); // Cleaning up... GNUNET_assert (0 == nstrcmp ("60", GNUNET_CONTAINER_heap_remove_node (n6))); GNUNET_assert (0 == nstrcmp ("50", GNUNET_CONTAINER_heap_remove_node (n5))); // Testing heap_walk_get_next GNUNET_CONTAINER_heap_walk_get_next (myHeap); GNUNET_CONTAINER_heap_walk_get_next (myHeap); GNUNET_CONTAINER_heap_walk_get_next (myHeap);; GNUNET_CONTAINER_heap_walk_get_next (myHeap); GNUNET_CONTAINER_heap_walk_get_next (myHeap); GNUNET_assert (0 == nstrcmp ("10", GNUNET_CONTAINER_heap_remove_node (n1))); GNUNET_assert (0 == nstrcmp ("20", GNUNET_CONTAINER_heap_remove_node (n2))); GNUNET_assert (0 == nstrcmp ("40", GNUNET_CONTAINER_heap_remove_node (n4))); GNUNET_assert (0 == nstrcmp ("70", GNUNET_CONTAINER_heap_remove_node (n7))); GNUNET_assert (0 == nstrcmp ("80", GNUNET_CONTAINER_heap_remove_node (n8))); // End Testing remove_node // Testing a GNUNET_CONTAINER_HEAP_ORDER_MAX GNUNET_CONTAINER_heap_destroy (myHeap); myHeap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MAX); n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); GNUNET_CONTAINER_heap_update_cost (myHeap, n1, 15); GNUNET_assert (0 == nstrcmp ("10", GNUNET_CONTAINER_heap_remove_node (n1))); n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 10); GNUNET_CONTAINER_heap_walk_get_next (myHeap); GNUNET_assert (0 == nstrcmp ("20", GNUNET_CONTAINER_heap_remove_node (n2))); GNUNET_assert (0 == nstrcmp ("10", GNUNET_CONTAINER_heap_remove_node (n1))); n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 10); n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 10); GNUNET_CONTAINER_heap_remove_node (n2); GNUNET_CONTAINER_heap_remove_node (n1); GNUNET_assert (0 == nstrcmp ("30", GNUNET_CONTAINER_heap_remove_root (myHeap))); n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 10); n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 10); GNUNET_CONTAINER_heap_remove_node (n2); GNUNET_CONTAINER_heap_remove_node (n1); GNUNET_assert (0 == nstrcmp ("30", GNUNET_CONTAINER_heap_remove_node (n3))); n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 20); n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 30); n4 = GNUNET_CONTAINER_heap_insert (myHeap, "40", 40); n5 = GNUNET_CONTAINER_heap_insert (myHeap, "50", 50); n6 = GNUNET_CONTAINER_heap_insert (myHeap, "60", 60); // Inserting nodes deeper in the tree with lower costs n7 = GNUNET_CONTAINER_heap_insert (myHeap, "70", 10); n8 = GNUNET_CONTAINER_heap_insert (myHeap, "80", 10); GNUNET_assert (0 == nstrcmp ("30", GNUNET_CONTAINER_heap_remove_node (n3))); // Cleaning up... GNUNET_assert (0 == nstrcmp ("60", GNUNET_CONTAINER_heap_remove_node (n6))); GNUNET_assert (0 == nstrcmp ("50", GNUNET_CONTAINER_heap_remove_node (n5))); // Testing heap_walk_get_next GNUNET_CONTAINER_heap_walk_get_next (myHeap); GNUNET_CONTAINER_heap_walk_get_next (myHeap); GNUNET_CONTAINER_heap_walk_get_next (myHeap);; GNUNET_CONTAINER_heap_walk_get_next (myHeap); GNUNET_CONTAINER_heap_walk_get_next (myHeap); GNUNET_assert (0 == nstrcmp ("10", GNUNET_CONTAINER_heap_remove_node (n1))); GNUNET_assert (0 == nstrcmp ("20", GNUNET_CONTAINER_heap_remove_node (n2))); GNUNET_assert (0 == nstrcmp ("40", GNUNET_CONTAINER_heap_remove_node (n4))); GNUNET_assert (0 == nstrcmp ("70", GNUNET_CONTAINER_heap_remove_node (n7))); GNUNET_assert (0 == nstrcmp ("80", GNUNET_CONTAINER_heap_remove_node (n8))); // End Testing remove_node GNUNET_CONTAINER_heap_destroy (myHeap); return 0; }
/** * Insert the given request plan into the heap with the appropriate weight. * * @param pp associated peer's plan * @param rp request to plan */ static void plan (struct PeerPlan *pp, struct GSF_RequestPlan *rp) { #define N ((double)128.0) /** * Running average delay we currently impose. */ static double avg_delay; struct GSF_PendingRequestData *prd; struct GNUNET_TIME_Relative delay; GNUNET_assert (rp->pp == pp); GNUNET_STATISTICS_set (GSF_stats, gettext_noop ("# average retransmission delay (ms)"), total_delay * 1000LL / plan_count, GNUNET_NO); prd = GSF_pending_request_get_data_ (rp->pe_head->pr); if (rp->transmission_counter < 8) delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, rp->transmission_counter); else if (rp->transmission_counter < 32) delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 8 + (1LL << (rp->transmission_counter - 8))); else delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 8 + (1LL << 24)); delay.rel_value = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, delay.rel_value + 1); /* Add 0.01 to avg_delay to avoid division-by-zero later */ avg_delay = (((avg_delay * (N - 1.0)) + delay.rel_value) / N) + 0.01; /* * For the priority, we need to consider a few basic rules: * 1) if we just started requesting (delay is small), we should * virtually always have a priority of zero. * 2) for requests with average latency, our priority should match * the average priority observed on the network * 3) even the longest-running requests should not be WAY out of * the observed average (thus we bound by a factor of 2) * 4) we add +1 to the observed average priority to avoid everyone * staying put at zero (2 * 0 = 0...). * * Using the specific calculation below, we get: * * delay = 0 => priority = 0; * delay = avg delay => priority = running-average-observed-priority; * delay >> avg_delay => priority = 2 * running-average-observed-priority; * * which satisfies all of the rules above. * * Note: M_PI_4 = PI/4 = arctan(1) */ rp->priority = round ((GSF_current_priorities + 1.0) * atan (delay.rel_value / avg_delay)) / M_PI_4; /* Note: usage of 'round' and 'atan' requires -lm */ if (rp->transmission_counter != 0) delay.rel_value += TTL_DECREMENT; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Considering (re)transmission number %u in %llu ms\n", (unsigned int) rp->transmission_counter, (unsigned long long) delay.rel_value); rp->earliest_transmission = GNUNET_TIME_relative_to_absolute (delay); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Earliest (re)transmission for `%s' in %us\n", GNUNET_h2s (&prd->query), rp->transmission_counter); GNUNET_assert (rp->hn == NULL); if (GNUNET_TIME_absolute_get_remaining (rp->earliest_transmission).rel_value == 0) rp->hn = GNUNET_CONTAINER_heap_insert (pp->priority_heap, rp, rp->priority); else rp->hn = GNUNET_CONTAINER_heap_insert (pp->delay_heap, rp, rp->earliest_transmission.abs_value); GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains_value (pp->plan_map, get_rp_key (rp), rp)); if (GNUNET_SCHEDULER_NO_TASK != pp->task) GNUNET_SCHEDULER_cancel (pp->task); pp->task = GNUNET_SCHEDULER_add_now (&schedule_peer_transmission, pp); #undef N }
/** * Figure out when and how to transmit to the given peer. * * @param cls the `struct PeerPlan` */ static void schedule_peer_transmission (void *cls) { struct PeerPlan *pp = cls; struct GSF_RequestPlan *rp; struct GNUNET_TIME_Relative delay; if (NULL != pp->task) { pp->task = NULL; } else { GNUNET_assert (NULL != pp->env); pp->env = NULL; } /* move ready requests to priority queue */ while ((NULL != (rp = GNUNET_CONTAINER_heap_peek (pp->delay_heap))) && (0 == GNUNET_TIME_absolute_get_remaining (rp->earliest_transmission).rel_value_us)) { GNUNET_assert (rp == GNUNET_CONTAINER_heap_remove_root (pp->delay_heap)); rp->hn = GNUNET_CONTAINER_heap_insert (pp->priority_heap, rp, rp->priority); } if (0 == GNUNET_CONTAINER_heap_get_size (pp->priority_heap)) { /* priority heap (still) empty, check for delay... */ rp = GNUNET_CONTAINER_heap_peek (pp->delay_heap); if (NULL == rp) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No active requests for plan %p.\n", pp); return; /* both queues empty */ } delay = GNUNET_TIME_absolute_get_remaining (rp->earliest_transmission); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sleeping for %s before retrying requests on plan %p.\n", GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES), pp); GNUNET_STATISTICS_set (GSF_stats, gettext_noop ("# delay heap timeout (ms)"), delay.rel_value_us / 1000LL, GNUNET_NO); pp->task = GNUNET_SCHEDULER_add_delayed (delay, &schedule_peer_transmission, pp); return; } #if INSANE_STATISTICS GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# query plans executed"), 1, GNUNET_NO); #endif /* process from priority heap */ rp = GNUNET_CONTAINER_heap_remove_root (pp->priority_heap); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing query plan %p\n", rp); GNUNET_assert (NULL != rp); rp->hn = NULL; rp->last_transmission = GNUNET_TIME_absolute_get (); rp->transmission_counter++; total_delay++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing plan %p executed %u times, planning retransmission\n", rp, rp->transmission_counter); GNUNET_assert (NULL == pp->env); pp->env = GSF_pending_request_get_message_ (get_latest (rp)); GNUNET_MQ_notify_sent (pp->env, &schedule_peer_transmission, pp); GSF_peer_transmit_ (pp->cp, GNUNET_YES, rp->priority, pp->env); GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# query messages sent to other peers"), 1, GNUNET_NO); plan (pp, rp); }