aboutsummaryrefslogtreecommitdiff
path: root/src/statistics/gnunet-service-statistics.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2012-03-04 20:59:41 +0000
committerChristian Grothoff <christian@grothoff.org>2012-03-04 20:59:41 +0000
commitfa2373ff7a4291216be7c00f76e276ee60aec654 (patch)
tree7f5da264095f18358b3abe772d88498ba6627407 /src/statistics/gnunet-service-statistics.c
parent6cdff36159de7a4fe5bc31564cc7dc3a2f94b0ed (diff)
downloadgnunet-fa2373ff7a4291216be7c00f76e276ee60aec654.tar.gz
gnunet-fa2373ff7a4291216be7c00f76e276ee60aec654.zip
make gnunet-service-statistics not exit on external shutdown signal as long as there are connected clients to be managed
Diffstat (limited to 'src/statistics/gnunet-service-statistics.c')
-rw-r--r--src/statistics/gnunet-service-statistics.c157
1 files changed, 110 insertions, 47 deletions
diff --git a/src/statistics/gnunet-service-statistics.c b/src/statistics/gnunet-service-statistics.c
index a890d6d8e..c57013987 100644
--- a/src/statistics/gnunet-service-statistics.c
+++ b/src/statistics/gnunet-service-statistics.c
@@ -41,14 +41,29 @@
41struct WatchEntry 41struct WatchEntry
42{ 42{
43 43
44 /**
45 * Watch entries are kept in a linked list.
46 */
44 struct WatchEntry *next; 47 struct WatchEntry *next;
45 48
49 /**
50 * Watch entries are kept in a linked list.
51 */
46 struct WatchEntry *prev; 52 struct WatchEntry *prev;
47 53
54 /**
55 * For which client is this watch entry?
56 */
48 struct GNUNET_SERVER_Client *client; 57 struct GNUNET_SERVER_Client *client;
49 58
59 /**
60 * Last value we communicated to the client for this watch entry.
61 */
50 uint64_t last_value; 62 uint64_t last_value;
51 63
64 /**
65 * Unique watch number for this client and this watched value.
66 */
52 uint32_t wid; 67 uint32_t wid;
53 68
54}; 69};
@@ -59,13 +74,24 @@ struct WatchEntry
59 */ 74 */
60struct ClientEntry 75struct ClientEntry
61{ 76{
62 77 /**
78 * Clients are kept in a linked list.
79 */
63 struct ClientEntry *next; 80 struct ClientEntry *next;
64 81
82 /**
83 * Clients are kept in a linked list.
84 */
65 struct ClientEntry *prev; 85 struct ClientEntry *prev;
66 86
87 /**
88 * Corresponding server handle.
89 */
67 struct GNUNET_SERVER_Client *client; 90 struct GNUNET_SERVER_Client *client;
68 91
92 /**
93 * Maximum watch ID used by this client so far.
94 */
69 uint32_t max_wid; 95 uint32_t max_wid;
70 96
71}; 97};
@@ -138,11 +164,22 @@ static const struct GNUNET_CONFIGURATION_Handle *cfg;
138 */ 164 */
139static struct StatsEntry *start; 165static struct StatsEntry *start;
140 166
167/**
168 * Head of linked list of connected clients.
169 */
141static struct ClientEntry *client_head; 170static struct ClientEntry *client_head;
142 171
172/**
173 * Tail of linked list of connected clients.
174 */
143static struct ClientEntry *client_tail; 175static struct ClientEntry *client_tail;
144 176
145/** 177/**
178 * Handle to our server.
179 */
180static struct GNUNET_SERVER_Handle *srv;
181
182/**
146 * Our notification context. 183 * Our notification context.
147 */ 184 */
148static struct GNUNET_SERVER_NotificationContext *nc; 185static struct GNUNET_SERVER_NotificationContext *nc;
@@ -152,7 +189,19 @@ static struct GNUNET_SERVER_NotificationContext *nc;
152 */ 189 */
153static uint32_t uidgen; 190static uint32_t uidgen;
154 191
192/**
193 * Set to YES if we are shutting down as soon as possible.
194 */
195static int in_shutdown;
196
155 197
198/**
199 * Inject a message to our server with a client of 'NULL'.
200 *
201 * @param cls the 'struct GNUNET_SERVER_Handle'
202 * @param client unused
203 * @param msg message to inject
204 */
156static void 205static void
157inject_message (void *cls, void *client, const struct GNUNET_MessageHeader *msg) 206inject_message (void *cls, void *client, const struct GNUNET_MessageHeader *msg)
158{ 207{
@@ -219,6 +268,7 @@ load (struct GNUNET_SERVER_Handle *server)
219 GNUNET_free (fn); 268 GNUNET_free (fn);
220} 269}
221 270
271
222/** 272/**
223 * Write persistent statistics to disk. 273 * Write persistent statistics to disk.
224 */ 274 */
@@ -272,6 +322,9 @@ save ()
272 322
273/** 323/**
274 * Transmit the given stats value. 324 * Transmit the given stats value.
325 *
326 * @param client receiver of the value
327 * @param e value to transmit
275 */ 328 */
276static void 329static void
277transmit (struct GNUNET_SERVER_Client *client, const struct StatsEntry *e) 330transmit (struct GNUNET_SERVER_Client *client, const struct StatsEntry *e)
@@ -294,11 +347,9 @@ transmit (struct GNUNET_SERVER_Client *client, const struct StatsEntry *e)
294 GNUNET_assert (size == 347 GNUNET_assert (size ==
295 GNUNET_STRINGS_buffer_fill ((char *) &m[1], size, 2, 348 GNUNET_STRINGS_buffer_fill ((char *) &m[1], size, 2,
296 e->service, e->name)); 349 e->service, e->name));
297#if DEBUG_STATISTICS
298 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 350 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
299 "Transmitting value for `%s:%s' (%d): %llu\n", e->service, 351 "Transmitting value for `%s:%s' (%d): %llu\n", e->service,
300 e->name, e->persistent, e->value); 352 e->name, e->persistent, e->value);
301#endif
302 GNUNET_SERVER_notification_context_unicast (nc, client, &m->header, 353 GNUNET_SERVER_notification_context_unicast (nc, client, &m->header,
303 GNUNET_NO); 354 GNUNET_NO);
304 GNUNET_free (m); 355 GNUNET_free (m);
@@ -307,6 +358,11 @@ transmit (struct GNUNET_SERVER_Client *client, const struct StatsEntry *e)
307 358
308/** 359/**
309 * Does this entry match the request? 360 * Does this entry match the request?
361 *
362 * @param e an entry
363 * @param service name of service to match
364 * @param name value to match
365 * @return 1 if they match, 0 if not
310 */ 366 */
311static int 367static int
312matches (const struct StatsEntry *e, const char *service, const char *name) 368matches (const struct StatsEntry *e, const char *service, const char *name)
@@ -316,6 +372,12 @@ matches (const struct StatsEntry *e, const char *service, const char *name)
316} 372}
317 373
318 374
375/**
376 * Find a client entry for the given client handle, or create one.
377 *
378 * @param client handle to match
379 * @return corresponding client entry struct
380 */
319static struct ClientEntry * 381static struct ClientEntry *
320make_client_entry (struct GNUNET_SERVER_Client *client) 382make_client_entry (struct GNUNET_SERVER_Client *client)
321{ 383{
@@ -368,18 +430,12 @@ handle_get (void *cls, struct GNUNET_SERVER_Client *client,
368 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); 430 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
369 return; 431 return;
370 } 432 }
371#if DEBUG_STATISTICS
372 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 433 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
373 "Received request for statistics on `%s:%s'\n", 434 "Received request for statistics on `%s:%s'\n",
374 strlen (service) ? service : "*", strlen (name) ? name : "*"); 435 strlen (service) ? service : "*", strlen (name) ? name : "*");
375#endif 436 for (pos = start; NULL != pos; pos = pos->next)
376 pos = start;
377 while (pos != NULL)
378 {
379 if (matches (pos, service, name)) 437 if (matches (pos, service, name))
380 transmit (client, pos); 438 transmit (client, pos);
381 pos = pos->next;
382 }
383 end.size = htons (sizeof (struct GNUNET_MessageHeader)); 439 end.size = htons (sizeof (struct GNUNET_MessageHeader));
384 end.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_END); 440 end.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_END);
385 GNUNET_SERVER_notification_context_unicast (nc, client, &end, GNUNET_NO); 441 GNUNET_SERVER_notification_context_unicast (nc, client, &end, GNUNET_NO);
@@ -387,29 +443,31 @@ handle_get (void *cls, struct GNUNET_SERVER_Client *client,
387} 443}
388 444
389 445
446/**
447 * Notify all clients listening about a change to a value.
448 *
449 * @param se value that changed
450 */
390static void 451static void
391notify_change (struct StatsEntry *se) 452notify_change (struct StatsEntry *se)
392{ 453{
393 struct GNUNET_STATISTICS_WatchValueMessage wvm; 454 struct GNUNET_STATISTICS_WatchValueMessage wvm;
394 struct WatchEntry *pos; 455 struct WatchEntry *pos;
395 456
396 pos = se->we_head; 457 for (pos = se->we_head; NULL != pos; pos = pos->next)
397 while (pos != NULL)
398 { 458 {
399 if (pos->last_value != se->value) 459 if (pos->last_value == se->value)
400 { 460 continue;
401 wvm.header.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_WATCH_VALUE); 461 wvm.header.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_WATCH_VALUE);
402 wvm.header.size = 462 wvm.header.size =
403 htons (sizeof (struct GNUNET_STATISTICS_WatchValueMessage)); 463 htons (sizeof (struct GNUNET_STATISTICS_WatchValueMessage));
404 wvm.flags = htonl (se->persistent ? GNUNET_STATISTICS_PERSIST_BIT : 0); 464 wvm.flags = htonl (se->persistent ? GNUNET_STATISTICS_PERSIST_BIT : 0);
405 wvm.wid = htonl (pos->wid); 465 wvm.wid = htonl (pos->wid);
406 wvm.reserved = htonl (0); 466 wvm.reserved = htonl (0);
407 wvm.value = GNUNET_htonll (se->value); 467 wvm.value = GNUNET_htonll (se->value);
408 GNUNET_SERVER_notification_context_unicast (nc, pos->client, &wvm.header, 468 GNUNET_SERVER_notification_context_unicast (nc, pos->client, &wvm.header,
409 GNUNET_NO); 469 GNUNET_NO);
410 pos->last_value = se->value; 470 pos->last_value = se->value;
411 }
412 pos = pos->next;
413 } 471 }
414} 472}
415 473
@@ -458,11 +516,9 @@ handle_set (void *cls, struct GNUNET_SERVER_Client *client,
458 } 516 }
459 flags = ntohl (msg->flags); 517 flags = ntohl (msg->flags);
460 value = GNUNET_ntohll (msg->value); 518 value = GNUNET_ntohll (msg->value);
461#if DEBUG_STATISTICS
462 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 519 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
463 "Received request to update statistic on `%s:%s' (%u) to/by %llu\n", 520 "Received request to update statistic on `%s:%s' (%u) to/by %llu\n",
464 service, name, (unsigned int) flags, (unsigned long long) value); 521 service, name, (unsigned int) flags, (unsigned long long) value);
465#endif
466 pos = start; 522 pos = start;
467 prev = NULL; 523 prev = NULL;
468 while (pos != NULL) 524 while (pos != NULL)
@@ -499,11 +555,9 @@ handle_set (void *cls, struct GNUNET_SERVER_Client *client,
499 pos->next = start; 555 pos->next = start;
500 start = pos; 556 start = pos;
501 } 557 }
502#if DEBUG_STATISTICS
503 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 558 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
504 "Statistic `%s:%s' updated to value %llu.\n", service, name, 559 "Statistic `%s:%s' updated to value %llu.\n", service, name,
505 pos->value); 560 pos->value);
506#endif
507 if (changed) 561 if (changed)
508 notify_change (pos); 562 notify_change (pos);
509 GNUNET_SERVER_receive_done (client, GNUNET_OK); 563 GNUNET_SERVER_receive_done (client, GNUNET_OK);
@@ -525,11 +579,9 @@ handle_set (void *cls, struct GNUNET_SERVER_Client *client,
525 pos->name = &pos->service[strlen (pos->service) + 1]; 579 pos->name = &pos->service[strlen (pos->service) + 1];
526 580
527 start = pos; 581 start = pos;
528#if DEBUG_STATISTICS
529 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 582 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
530 "New statistic on `%s:%s' with value %llu created.\n", service, 583 "New statistic on `%s:%s' with value %llu created.\n", service,
531 name, pos->value); 584 name, pos->value);
532#endif
533 GNUNET_SERVER_receive_done (client, GNUNET_OK); 585 GNUNET_SERVER_receive_done (client, GNUNET_OK);
534} 586}
535 587
@@ -571,11 +623,9 @@ handle_watch (void *cls, struct GNUNET_SERVER_Client *client,
571 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); 623 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
572 return; 624 return;
573 } 625 }
574#if DEBUG_STATISTICS
575 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 626 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
576 "Received request to watch statistic on `%s:%s'\n", service, 627 "Received request to watch statistic on `%s:%s'\n", service,
577 name); 628 name);
578#endif
579 pos = start; 629 pos = start;
580 while (pos != NULL) 630 while (pos != NULL)
581 { 631 {
@@ -613,27 +663,18 @@ handle_watch (void *cls, struct GNUNET_SERVER_Client *client,
613 663
614 664
615/** 665/**
616 * Task run during shutdown. 666 * Actually perform the shutdown.
617 *
618 * @param cls unused
619 * @param tc unused
620 */ 667 */
621static void 668static void
622shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 669do_shutdown ()
623{ 670{
624 struct ClientEntry *ce;
625 struct WatchEntry *we; 671 struct WatchEntry *we;
626 struct StatsEntry *se; 672 struct StatsEntry *se;
627 673
628 save (); 674 save ();
629 GNUNET_SERVER_notification_context_destroy (nc); 675 GNUNET_SERVER_notification_context_destroy (nc);
630 nc = NULL; 676 nc = NULL;
631 while (NULL != (ce = client_head)) 677 GNUNET_assert (NULL == client_head);
632 {
633 GNUNET_SERVER_client_drop (ce->client);
634 GNUNET_CONTAINER_DLL_remove (client_head, client_tail, ce);
635 GNUNET_free (ce);
636 }
637 while (NULL != (se = start)) 678 while (NULL != (se = start))
638 { 679 {
639 start = se->next; 680 start = se->next;
@@ -645,6 +686,23 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
645 } 686 }
646 GNUNET_free (se); 687 GNUNET_free (se);
647 } 688 }
689 GNUNET_SERVER_destroy (srv);
690}
691
692
693/**
694 * Task run during shutdown.
695 *
696 * @param cls unused
697 * @param tc unused
698 */
699static void
700shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
701{
702 in_shutdown = GNUNET_YES;
703 if (NULL != client_head)
704 return;
705 do_shutdown ();
648} 706}
649 707
650 708
@@ -689,6 +747,9 @@ handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
689 } 747 }
690 se = se->next; 748 se = se->next;
691 } 749 }
750 if ( (NULL == client_head) &&
751 (GNUNET_YES == in_shutdown) )
752 do_shutdown ();
692} 753}
693 754
694 755
@@ -710,7 +771,9 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
710 {NULL, NULL, 0, 0} 771 {NULL, NULL, 0, 0}
711 }; 772 };
712 cfg = c; 773 cfg = c;
774 srv = server;
713 GNUNET_SERVER_add_handlers (server, handlers); 775 GNUNET_SERVER_add_handlers (server, handlers);
776 GNUNET_SERVER_ignore_shutdown (server, GNUNET_YES);
714 nc = GNUNET_SERVER_notification_context_create (server, 16); 777 nc = GNUNET_SERVER_notification_context_create (server, 16);
715 GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL); 778 GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
716 load (server); 779 load (server);