diff options
author | Christian Grothoff <christian@grothoff.org> | 2014-12-23 22:08:47 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2014-12-23 22:08:47 +0000 |
commit | f3575010be1a53abe6a27b5e5c4d2d60f46ba805 (patch) | |
tree | b8685067df250ac92e78414df3063315fc15adc0 /src | |
parent | 912d1dc85990d15f2ce7fcfb837dc37cd327833b (diff) | |
download | gnunet-f3575010be1a53abe6a27b5e5c4d2d60f46ba805.tar.gz gnunet-f3575010be1a53abe6a27b5e5c4d2d60f46ba805.zip |
-cleaning up stats code, use separate structures per subsystem for faster processing
Diffstat (limited to 'src')
-rw-r--r-- | src/include/gnunet_statistics_service.h | 14 | ||||
-rw-r--r-- | src/statistics/gnunet-service-statistics.c | 624 | ||||
-rw-r--r-- | src/statistics/statistics.h | 26 |
3 files changed, 451 insertions, 213 deletions
diff --git a/src/include/gnunet_statistics_service.h b/src/include/gnunet_statistics_service.h index 41788d67e..2b55ad175 100644 --- a/src/include/gnunet_statistics_service.h +++ b/src/include/gnunet_statistics_service.h | |||
@@ -61,11 +61,12 @@ struct GNUNET_STATISTICS_Handle; | |||
61 | * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not | 61 | * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not |
62 | * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration | 62 | * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration |
63 | */ | 63 | */ |
64 | typedef int (*GNUNET_STATISTICS_Iterator) (void *cls, | 64 | typedef int |
65 | const char *subsystem, | 65 | (*GNUNET_STATISTICS_Iterator) (void *cls, |
66 | const char *name, | 66 | const char *subsystem, |
67 | uint64_t value, | 67 | const char *name, |
68 | int is_persistent); | 68 | uint64_t value, |
69 | int is_persistent); | ||
69 | 70 | ||
70 | 71 | ||
71 | /** | 72 | /** |
@@ -81,8 +82,7 @@ GNUNET_STATISTICS_create (const char *subsystem, | |||
81 | 82 | ||
82 | 83 | ||
83 | /** | 84 | /** |
84 | * Destroy a handle (free all state associated with | 85 | * Destroy a handle (free all state associated with it). |
85 | * it). | ||
86 | * | 86 | * |
87 | * @param h statistics handle to destroy | 87 | * @param h statistics handle to destroy |
88 | * @param sync_first set to #GNUNET_YES if pending SET requests should | 88 | * @param sync_first set to #GNUNET_YES if pending SET requests should |
diff --git a/src/statistics/gnunet-service-statistics.c b/src/statistics/gnunet-service-statistics.c index 4d8251cf4..dbf1ecd14 100644 --- a/src/statistics/gnunet-service-statistics.c +++ b/src/statistics/gnunet-service-statistics.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | (C) 2009, 2010, 2012 Christian Grothoff (and other contributing authors) | 3 | (C) 2009, 2010, 2012, 2014 Christian Grothoff (and other contributing authors) |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 5 | GNUnet is free software; you can redistribute it and/or modify |
6 | it under the terms of the GNU General Public License as published | 6 | it under the terms of the GNU General Public License as published |
@@ -76,21 +76,11 @@ struct WatchEntry | |||
76 | 76 | ||
77 | 77 | ||
78 | /** | 78 | /** |
79 | * Client entry. | 79 | * We keep the statistics organized by subsystem for faster |
80 | * lookup during SET operations. | ||
80 | */ | 81 | */ |
81 | struct ClientEntry | 82 | struct SubsystemEntry; |
82 | { | ||
83 | /** | ||
84 | * Corresponding server handle. | ||
85 | */ | ||
86 | struct GNUNET_SERVER_Client *client; | ||
87 | 83 | ||
88 | /** | ||
89 | * Maximum watch ID used by this client so far. | ||
90 | */ | ||
91 | uint32_t max_wid; | ||
92 | |||
93 | }; | ||
94 | 84 | ||
95 | /** | 85 | /** |
96 | * Entry in the statistics list. | 86 | * Entry in the statistics list. |
@@ -103,21 +93,20 @@ struct StatsEntry | |||
103 | struct StatsEntry *next; | 93 | struct StatsEntry *next; |
104 | 94 | ||
105 | /** | 95 | /** |
106 | * Name of the service, points into the middle of @e msg. | 96 | * This is a linked list. |
107 | */ | 97 | */ |
108 | const char *service; | 98 | struct StatsEntry *prev; |
109 | 99 | ||
110 | /** | 100 | /** |
111 | * Name for the value, points into the middle of @e msg. | 101 | * Subsystem this entry belongs to. |
112 | */ | 102 | */ |
113 | const char *name; | 103 | struct SubsystemEntry *subsystem; |
114 | 104 | ||
115 | /** | 105 | /** |
116 | * Message that can be used to set this value, | 106 | * Name for the value stored by this entry, allocated at the end of |
117 | * stored at the end of the memory used by | ||
118 | * this struct. | 107 | * this struct. |
119 | */ | 108 | */ |
120 | struct GNUNET_STATISTICS_SetMessage *msg; | 109 | const char *name; |
121 | 110 | ||
122 | /** | 111 | /** |
123 | * Watch context for changes to this value, or NULL for none. | 112 | * Watch context for changes to this value, or NULL for none. |
@@ -146,21 +135,85 @@ struct StatsEntry | |||
146 | 135 | ||
147 | /** | 136 | /** |
148 | * Is this value set? | 137 | * Is this value set? |
149 | * #GNUNET_NO : value is n/a, #GNUNET_YES: value is valid | 138 | * #GNUNET_NO: value is n/a, #GNUNET_YES: value is valid |
150 | */ | 139 | */ |
151 | int set; | 140 | int set; |
152 | 141 | ||
153 | }; | 142 | }; |
154 | 143 | ||
144 | |||
145 | /** | ||
146 | * We keep the statistics organized by subsystem for faster | ||
147 | * lookup during SET operations. | ||
148 | */ | ||
149 | struct SubsystemEntry | ||
150 | { | ||
151 | /** | ||
152 | * Subsystems are kept in a DLL. | ||
153 | */ | ||
154 | struct SubsystemEntry *next; | ||
155 | |||
156 | /** | ||
157 | * Subsystems are kept in a DLL. | ||
158 | */ | ||
159 | struct SubsystemEntry *prev; | ||
160 | |||
161 | /** | ||
162 | * Head of list of values kept for this subsystem. | ||
163 | */ | ||
164 | struct StatsEntry *stat_head; | ||
165 | |||
166 | /** | ||
167 | * Tail of list of values kept for this subsystem. | ||
168 | */ | ||
169 | struct StatsEntry *stat_tail; | ||
170 | |||
171 | /** | ||
172 | * Name of the subsystem this entry is for, allocated at | ||
173 | * the end of this struct, do not free(). | ||
174 | */ | ||
175 | const char *service; | ||
176 | |||
177 | }; | ||
178 | |||
179 | |||
180 | /** | ||
181 | * Client entry. | ||
182 | */ | ||
183 | struct ClientEntry | ||
184 | { | ||
185 | /** | ||
186 | * Corresponding server handle. | ||
187 | */ | ||
188 | struct GNUNET_SERVER_Client *client; | ||
189 | |||
190 | /** | ||
191 | * Which subsystem is this client writing to (SET/UPDATE)? | ||
192 | */ | ||
193 | struct SubsystemEntry *subsystem; | ||
194 | |||
195 | /** | ||
196 | * Maximum watch ID used by this client so far. | ||
197 | */ | ||
198 | uint32_t max_wid; | ||
199 | |||
200 | }; | ||
201 | |||
202 | |||
155 | /** | 203 | /** |
156 | * Our configuration. | 204 | * Our configuration. |
157 | */ | 205 | */ |
158 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | 206 | static const struct GNUNET_CONFIGURATION_Handle *cfg; |
159 | 207 | ||
160 | /** | 208 | /** |
161 | * Linked list of our active statistics. | 209 | * Head of linked list of subsystems with active statistics. |
162 | */ | 210 | */ |
163 | static struct StatsEntry *start; | 211 | static struct SubsystemEntry *sub_head; |
212 | |||
213 | /** | ||
214 | * Tail of linked list of subsystems with active statistics. | ||
215 | */ | ||
216 | static struct SubsystemEntry *sub_tail; | ||
164 | 217 | ||
165 | /** | 218 | /** |
166 | * Number of connected clients. | 219 | * Number of connected clients. |
@@ -196,7 +249,8 @@ static int in_shutdown; | |||
196 | * @param msg message to inject | 249 | * @param msg message to inject |
197 | */ | 250 | */ |
198 | static int | 251 | static int |
199 | inject_message (void *cls, void *client, | 252 | inject_message (void *cls, |
253 | void *client, | ||
200 | const struct GNUNET_MessageHeader *msg) | 254 | const struct GNUNET_MessageHeader *msg) |
201 | { | 255 | { |
202 | struct GNUNET_SERVER_Handle *server = cls; | 256 | struct GNUNET_SERVER_Handle *server = cls; |
@@ -220,7 +274,6 @@ load (struct GNUNET_SERVER_Handle *server) | |||
220 | uint64_t fsize; | 274 | uint64_t fsize; |
221 | char *buf; | 275 | char *buf; |
222 | struct GNUNET_SERVER_MessageStreamTokenizer *mst; | 276 | struct GNUNET_SERVER_MessageStreamTokenizer *mst; |
223 | char *emsg; | ||
224 | 277 | ||
225 | if (GNUNET_OK != | 278 | if (GNUNET_OK != |
226 | GNUNET_CONFIGURATION_get_value_filename (cfg, | 279 | GNUNET_CONFIGURATION_get_value_filename (cfg, |
@@ -234,7 +287,10 @@ load (struct GNUNET_SERVER_Handle *server) | |||
234 | return; | 287 | return; |
235 | } | 288 | } |
236 | if ( (GNUNET_OK != | 289 | if ( (GNUNET_OK != |
237 | GNUNET_DISK_file_size (fn, &fsize, GNUNET_NO, GNUNET_YES)) || | 290 | GNUNET_DISK_file_size (fn, |
291 | &fsize, | ||
292 | GNUNET_NO, | ||
293 | GNUNET_YES)) || | ||
238 | (0 == fsize) ) | 294 | (0 == fsize) ) |
239 | { | 295 | { |
240 | GNUNET_free (fn); | 296 | GNUNET_free (fn); |
@@ -248,26 +304,36 @@ load (struct GNUNET_SERVER_Handle *server) | |||
248 | GNUNET_free (fn); | 304 | GNUNET_free (fn); |
249 | return; | 305 | return; |
250 | } | 306 | } |
251 | if (GNUNET_OK != GNUNET_BIO_read (rh, fn, buf, fsize)) | 307 | if (GNUNET_OK != |
308 | GNUNET_BIO_read (rh, | ||
309 | fn, | ||
310 | buf, | ||
311 | fsize)) | ||
252 | { | 312 | { |
253 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "read", fn); | 313 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, |
254 | GNUNET_break (GNUNET_OK == GNUNET_BIO_read_close (rh, &emsg)); | 314 | "read", |
315 | fn); | ||
316 | GNUNET_break (GNUNET_OK == | ||
317 | GNUNET_BIO_read_close (rh, NULL)); | ||
255 | GNUNET_free (buf); | 318 | GNUNET_free (buf); |
256 | GNUNET_free_non_null (emsg); | ||
257 | GNUNET_free (fn); | 319 | GNUNET_free (fn); |
258 | return; | 320 | return; |
259 | } | 321 | } |
260 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 322 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
261 | _("Loading %llu bytes of statistics from `%s'\n"), | 323 | _("Loading %llu bytes of statistics from `%s'\n"), |
262 | fsize, fn); | 324 | fsize, fn); |
263 | mst = GNUNET_SERVER_mst_create (&inject_message, server); | 325 | mst = GNUNET_SERVER_mst_create (&inject_message, |
326 | server); | ||
264 | GNUNET_break (GNUNET_OK == | 327 | GNUNET_break (GNUNET_OK == |
265 | GNUNET_SERVER_mst_receive (mst, NULL, buf, fsize, | 328 | GNUNET_SERVER_mst_receive (mst, NULL, |
266 | GNUNET_YES, GNUNET_NO)); | 329 | buf, fsize, |
330 | GNUNET_YES, | ||
331 | GNUNET_NO)); | ||
267 | GNUNET_SERVER_mst_destroy (mst); | 332 | GNUNET_SERVER_mst_destroy (mst); |
268 | GNUNET_free (buf); | 333 | GNUNET_free (buf); |
269 | GNUNET_break (GNUNET_OK == GNUNET_BIO_read_close (rh, &emsg)); | 334 | GNUNET_break (GNUNET_OK == |
270 | GNUNET_free_non_null (emsg); | 335 | GNUNET_BIO_read_close (rh, |
336 | NULL)); | ||
271 | GNUNET_free (fn); | 337 | GNUNET_free (fn); |
272 | } | 338 | } |
273 | 339 | ||
@@ -278,11 +344,15 @@ load (struct GNUNET_SERVER_Handle *server) | |||
278 | static void | 344 | static void |
279 | save () | 345 | save () |
280 | { | 346 | { |
347 | struct SubsystemEntry *se; | ||
281 | struct StatsEntry *pos; | 348 | struct StatsEntry *pos; |
282 | char *fn; | 349 | char *fn; |
283 | struct GNUNET_BIO_WriteHandle *wh; | 350 | struct GNUNET_BIO_WriteHandle *wh; |
284 | uint16_t size; | 351 | uint16_t size; |
285 | unsigned long long total; | 352 | unsigned long long total; |
353 | size_t nlen; | ||
354 | size_t slen; | ||
355 | struct GNUNET_STATISTICS_SetMessage *msg; | ||
286 | 356 | ||
287 | if (GNUNET_OK != | 357 | if (GNUNET_OK != |
288 | GNUNET_CONFIGURATION_get_value_filename (cfg, | 358 | GNUNET_CONFIGURATION_get_value_filename (cfg, |
@@ -298,33 +368,72 @@ save () | |||
298 | (void) GNUNET_DISK_directory_create_for_file (fn); | 368 | (void) GNUNET_DISK_directory_create_for_file (fn); |
299 | wh = GNUNET_BIO_write_open (fn); | 369 | wh = GNUNET_BIO_write_open (fn); |
300 | total = 0; | 370 | total = 0; |
301 | while (NULL != (pos = start)) | 371 | while (NULL != (se = sub_head)) |
302 | { | 372 | { |
303 | start = pos->next; | 373 | GNUNET_CONTAINER_DLL_remove (sub_head, |
304 | if ((pos->persistent) && (NULL != wh)) | 374 | sub_tail, |
375 | se); | ||
376 | slen = strlen (se->service) + 1; | ||
377 | while (NULL != (pos = se->stat_head)) | ||
305 | { | 378 | { |
306 | size = htons (pos->msg->header.size); | 379 | GNUNET_CONTAINER_DLL_remove (se->stat_head, |
307 | if (GNUNET_OK != GNUNET_BIO_write (wh, pos->msg, size)) | 380 | se->stat_tail, |
381 | pos); | ||
382 | if ((pos->persistent) && (NULL != wh)) | ||
308 | { | 383 | { |
309 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "write", fn); | 384 | nlen = strlen (pos->name) + 1; |
310 | if (GNUNET_OK != GNUNET_BIO_write_close (wh)) | 385 | size = sizeof (struct GNUNET_STATISTICS_SetMessage) + nlen + slen; |
311 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "close", fn); | 386 | GNUNET_assert (size < UINT16_MAX); |
312 | wh = NULL; | 387 | msg = GNUNET_malloc (size); |
388 | |||
389 | msg->header.size = htons ((uint16_t) size); | ||
390 | msg->header.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_SET); | ||
391 | GNUNET_assert (nlen + slen == | ||
392 | GNUNET_STRINGS_buffer_fill ((char *) &msg[1], | ||
393 | nlen + slen, | ||
394 | 2, | ||
395 | se->service, | ||
396 | pos->name)); | ||
397 | msg->flags = htonl (pos->persistent ? GNUNET_STATISTICS_SETFLAG_PERSISTENT : 0); | ||
398 | msg->value = GNUNET_htonll (pos->value); | ||
399 | if (GNUNET_OK != GNUNET_BIO_write (wh, | ||
400 | msg, | ||
401 | size)) | ||
402 | { | ||
403 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, | ||
404 | "write", | ||
405 | fn); | ||
406 | if (GNUNET_OK != GNUNET_BIO_write_close (wh)) | ||
407 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, | ||
408 | "close", | ||
409 | fn); | ||
410 | wh = NULL; | ||
411 | } | ||
412 | else | ||
413 | { | ||
414 | total += size; | ||
415 | } | ||
416 | GNUNET_free (msg); | ||
313 | } | 417 | } |
314 | else | 418 | GNUNET_free (pos); |
315 | total += size; | ||
316 | } | 419 | } |
317 | GNUNET_free (pos); | 420 | GNUNET_free (se); |
318 | } | 421 | } |
319 | if (NULL != wh) | 422 | if (NULL != wh) |
320 | { | 423 | { |
321 | if (GNUNET_OK != GNUNET_BIO_write_close (wh)) | 424 | if (GNUNET_OK != |
322 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "close", fn); | 425 | GNUNET_BIO_write_close (wh)) |
323 | if (total == 0) | 426 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, |
324 | GNUNET_break (0 == UNLINK (fn)); | 427 | "close", |
428 | fn); | ||
429 | if (0 == total) | ||
430 | GNUNET_break (0 == | ||
431 | UNLINK (fn)); | ||
325 | else | 432 | else |
326 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 433 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
327 | _("Wrote %llu bytes of statistics to `%s'\n"), total, fn); | 434 | _("Wrote %llu bytes of statistics to `%s'\n"), |
435 | total, | ||
436 | fn); | ||
328 | } | 437 | } |
329 | GNUNET_free_non_null (fn); | 438 | GNUNET_free_non_null (fn); |
330 | } | 439 | } |
@@ -343,9 +452,9 @@ transmit (struct GNUNET_SERVER_Client *client, | |||
343 | struct GNUNET_STATISTICS_ReplyMessage *m; | 452 | struct GNUNET_STATISTICS_ReplyMessage *m; |
344 | size_t size; | 453 | size_t size; |
345 | 454 | ||
346 | size = | 455 | size = sizeof (struct GNUNET_STATISTICS_ReplyMessage) + |
347 | sizeof (struct GNUNET_STATISTICS_ReplyMessage) + strlen (e->service) + 1 + | 456 | strlen (e->subsystem->service) + 1 + |
348 | strlen (e->name) + 1; | 457 | strlen (e->name) + 1; |
349 | GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE); | 458 | GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE); |
350 | m = GNUNET_malloc (size); | 459 | m = GNUNET_malloc (size); |
351 | m->header.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_VALUE); | 460 | m->header.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_VALUE); |
@@ -356,11 +465,14 @@ transmit (struct GNUNET_SERVER_Client *client, | |||
356 | m->value = GNUNET_htonll (e->value); | 465 | m->value = GNUNET_htonll (e->value); |
357 | size -= sizeof (struct GNUNET_STATISTICS_ReplyMessage); | 466 | size -= sizeof (struct GNUNET_STATISTICS_ReplyMessage); |
358 | GNUNET_assert (size == | 467 | GNUNET_assert (size == |
359 | GNUNET_STRINGS_buffer_fill ((char *) &m[1], size, 2, | 468 | GNUNET_STRINGS_buffer_fill ((char *) &m[1], |
360 | e->service, e->name)); | 469 | size, |
470 | 2, | ||
471 | e->subsystem->service, | ||
472 | e->name)); | ||
361 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 473 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
362 | "Transmitting value for `%s:%s' (%d): %llu\n", | 474 | "Transmitting value for `%s:%s' (%d): %llu\n", |
363 | e->service, | 475 | e->subsystem->service, |
364 | e->name, | 476 | e->name, |
365 | e->persistent, | 477 | e->persistent, |
366 | e->value); | 478 | e->value); |
@@ -371,24 +483,6 @@ transmit (struct GNUNET_SERVER_Client *client, | |||
371 | 483 | ||
372 | 484 | ||
373 | /** | 485 | /** |
374 | * Does this entry match the request? | ||
375 | * | ||
376 | * @param e an entry | ||
377 | * @param service name of service to match | ||
378 | * @param name value to match | ||
379 | * @return 1 if they match, 0 if not | ||
380 | */ | ||
381 | static int | ||
382 | matches (const struct StatsEntry *e, | ||
383 | const char *service, | ||
384 | const char *name) | ||
385 | { | ||
386 | return ((0 == strlen (service)) || (0 == strcmp (service, e->service))) && | ||
387 | ((0 == strlen (name)) || (0 == strcmp (name, e->name))); | ||
388 | } | ||
389 | |||
390 | |||
391 | /** | ||
392 | * Find a client entry for the given client handle, or create one. | 486 | * Find a client entry for the given client handle, or create one. |
393 | * | 487 | * |
394 | * @param client handle to match | 488 | * @param client handle to match |
@@ -399,7 +493,6 @@ make_client_entry (struct GNUNET_SERVER_Client *client) | |||
399 | { | 493 | { |
400 | struct ClientEntry *ce; | 494 | struct ClientEntry *ce; |
401 | 495 | ||
402 | GNUNET_assert (NULL != client); | ||
403 | ce = GNUNET_SERVER_client_get_user_context (client, | 496 | ce = GNUNET_SERVER_client_get_user_context (client, |
404 | struct ClientEntry); | 497 | struct ClientEntry); |
405 | if (NULL != ce) | 498 | if (NULL != ce) |
@@ -433,33 +526,54 @@ handle_get (void *cls, | |||
433 | const struct GNUNET_MessageHeader *message) | 526 | const struct GNUNET_MessageHeader *message) |
434 | { | 527 | { |
435 | struct GNUNET_MessageHeader end; | 528 | struct GNUNET_MessageHeader end; |
436 | char *service; | 529 | const char *service; |
437 | char *name; | 530 | const char *name; |
531 | size_t slen; | ||
532 | size_t nlen; | ||
533 | struct SubsystemEntry *se; | ||
438 | struct StatsEntry *pos; | 534 | struct StatsEntry *pos; |
439 | size_t size; | 535 | size_t size; |
440 | 536 | ||
441 | if ( (NULL != client) && | 537 | if (NULL == make_client_entry (client)) |
442 | (NULL == make_client_entry (client)) ) | ||
443 | return; /* new client during shutdown */ | 538 | return; /* new client during shutdown */ |
444 | size = ntohs (message->size) - sizeof (struct GNUNET_MessageHeader); | 539 | size = ntohs (message->size) - sizeof (struct GNUNET_MessageHeader); |
445 | if (size != | 540 | if (size != |
446 | GNUNET_STRINGS_buffer_tokenize ((const char *) &message[1], size, 2, | 541 | GNUNET_STRINGS_buffer_tokenize ((const char *) &message[1], |
447 | &service, &name)) | 542 | size, |
543 | 2, | ||
544 | &service, | ||
545 | &name)) | ||
448 | { | 546 | { |
449 | GNUNET_break (0); | 547 | GNUNET_break (0); |
450 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | 548 | GNUNET_SERVER_receive_done (client, |
549 | GNUNET_SYSERR); | ||
451 | return; | 550 | return; |
452 | } | 551 | } |
552 | slen = strlen (service); | ||
553 | nlen = strlen (name); | ||
453 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 554 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
454 | "Received request for statistics on `%s:%s'\n", | 555 | "Received request for statistics on `%s:%s'\n", |
455 | strlen (service) ? service : "*", | 556 | slen ? service : "*", |
456 | strlen (name) ? name : "*"); | 557 | nlen ? name : "*"); |
457 | for (pos = start; NULL != pos; pos = pos->next) | 558 | for (se = sub_head; NULL != se; se = se->next) |
458 | if (matches (pos, service, name)) | 559 | { |
560 | if (! ( (0 == slen) || | ||
561 | (0 == strcmp (service, se->service))) ) | ||
562 | continue; | ||
563 | for (pos = se->stat_head; NULL != pos; pos = pos->next) | ||
564 | { | ||
565 | if (! ( (0 == nlen) || | ||
566 | (0 == strcmp (name, pos->name))) ) | ||
567 | continue; | ||
459 | transmit (client, pos); | 568 | transmit (client, pos); |
569 | } | ||
570 | } | ||
460 | end.size = htons (sizeof (struct GNUNET_MessageHeader)); | 571 | end.size = htons (sizeof (struct GNUNET_MessageHeader)); |
461 | end.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_END); | 572 | end.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_END); |
462 | GNUNET_SERVER_notification_context_unicast (nc, client, &end, GNUNET_NO); | 573 | GNUNET_SERVER_notification_context_unicast (nc, |
574 | client, | ||
575 | &end, | ||
576 | GNUNET_NO); | ||
463 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | 577 | GNUNET_SERVER_receive_done (client, GNUNET_OK); |
464 | } | 578 | } |
465 | 579 | ||
@@ -489,11 +603,13 @@ notify_change (struct StatsEntry *se) | |||
489 | wvm.header.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_WATCH_VALUE); | 603 | wvm.header.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_WATCH_VALUE); |
490 | wvm.header.size = | 604 | wvm.header.size = |
491 | htons (sizeof (struct GNUNET_STATISTICS_WatchValueMessage)); | 605 | htons (sizeof (struct GNUNET_STATISTICS_WatchValueMessage)); |
492 | wvm.flags = htonl (se->persistent ? GNUNET_STATISTICS_PERSIST_BIT : 0); | 606 | wvm.flags = htonl (se->persistent ? GNUNET_STATISTICS_SETFLAG_PERSISTENT : 0); |
493 | wvm.wid = htonl (pos->wid); | 607 | wvm.wid = htonl (pos->wid); |
494 | wvm.reserved = htonl (0); | 608 | wvm.reserved = htonl (0); |
495 | wvm.value = GNUNET_htonll (se->value); | 609 | wvm.value = GNUNET_htonll (se->value); |
496 | GNUNET_SERVER_notification_context_unicast (nc, pos->client, &wvm.header, | 610 | GNUNET_SERVER_notification_context_unicast (nc, |
611 | pos->client, | ||
612 | &wvm.header, | ||
497 | GNUNET_NO); | 613 | GNUNET_NO); |
498 | pos->last_value = se->value; | 614 | pos->last_value = se->value; |
499 | } | 615 | } |
@@ -501,6 +617,77 @@ notify_change (struct StatsEntry *se) | |||
501 | 617 | ||
502 | 618 | ||
503 | /** | 619 | /** |
620 | * Find the subsystem entry of the given name for the specified client. | ||
621 | * | ||
622 | * @param ce client looking for the subsystem, may contain a hint | ||
623 | * to find the entry faster, can be NULL | ||
624 | * @param service name of the subsystem to look for | ||
625 | * @return subsystem entry, never NULL (subsystem entry is created if necessary) | ||
626 | */ | ||
627 | static struct SubsystemEntry * | ||
628 | find_subsystem_entry (struct ClientEntry *ce, | ||
629 | const char *service) | ||
630 | { | ||
631 | size_t slen; | ||
632 | struct SubsystemEntry *se; | ||
633 | |||
634 | if (NULL != ce) | ||
635 | se = ce->subsystem; | ||
636 | else | ||
637 | se = NULL; | ||
638 | if ( (NULL == se) || | ||
639 | (0 != strcmp (service, | ||
640 | se->service)) ) | ||
641 | { | ||
642 | for (se = sub_head; NULL != se; se = se->next) | ||
643 | if (0 == strcmp (service, | ||
644 | se->service)) | ||
645 | break; | ||
646 | if (NULL != ce) | ||
647 | ce->subsystem = se; | ||
648 | } | ||
649 | if (NULL != se) | ||
650 | return se; | ||
651 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
652 | "Allocating new subsystem entry `%s'\n", | ||
653 | service); | ||
654 | slen = strlen (service) + 1; | ||
655 | se = GNUNET_malloc (sizeof (struct SubsystemEntry) + | ||
656 | slen); | ||
657 | memcpy (&se[1], | ||
658 | service, | ||
659 | slen); | ||
660 | se->service = (const char *) &se[1]; | ||
661 | GNUNET_CONTAINER_DLL_insert (sub_head, | ||
662 | sub_tail, | ||
663 | se); | ||
664 | if (NULL != ce) | ||
665 | ce->subsystem = se; | ||
666 | return se; | ||
667 | } | ||
668 | |||
669 | |||
670 | /** | ||
671 | * Find the statistics entry of the given subsystem. | ||
672 | * | ||
673 | * @param subsystem subsystem to look in | ||
674 | * @param name name of the entry to look for | ||
675 | * @return statistis entry, or NULL if not found | ||
676 | */ | ||
677 | static struct StatsEntry * | ||
678 | find_stat_entry (struct SubsystemEntry *se, | ||
679 | const char *name) | ||
680 | { | ||
681 | struct StatsEntry *pos; | ||
682 | |||
683 | for (pos = se->stat_head; NULL != pos; pos = pos->next) | ||
684 | if (0 == strcmp (name, pos->name)) | ||
685 | return pos; | ||
686 | return NULL; | ||
687 | } | ||
688 | |||
689 | |||
690 | /** | ||
504 | * Handle SET-message. | 691 | * Handle SET-message. |
505 | * | 692 | * |
506 | * @param cls closure | 693 | * @param cls closure |
@@ -512,21 +699,24 @@ handle_set (void *cls, | |||
512 | struct GNUNET_SERVER_Client *client, | 699 | struct GNUNET_SERVER_Client *client, |
513 | const struct GNUNET_MessageHeader *message) | 700 | const struct GNUNET_MessageHeader *message) |
514 | { | 701 | { |
515 | char *service; | 702 | const char *service; |
516 | char *name; | 703 | const char *name; |
704 | size_t nlen; | ||
517 | uint16_t msize; | 705 | uint16_t msize; |
518 | uint16_t size; | 706 | uint16_t size; |
519 | const struct GNUNET_STATISTICS_SetMessage *msg; | 707 | const struct GNUNET_STATISTICS_SetMessage *msg; |
708 | struct SubsystemEntry *se; | ||
709 | struct ClientEntry *ce; | ||
520 | struct StatsEntry *pos; | 710 | struct StatsEntry *pos; |
521 | struct StatsEntry *prev; | ||
522 | uint32_t flags; | 711 | uint32_t flags; |
523 | uint64_t value; | 712 | uint64_t value; |
524 | int64_t delta; | 713 | int64_t delta; |
525 | int changed; | 714 | int changed; |
526 | int initial_set; | 715 | int initial_set; |
527 | 716 | ||
717 | ce = NULL; | ||
528 | if ( (NULL != client) && | 718 | if ( (NULL != client) && |
529 | (NULL == make_client_entry (client)) ) | 719 | (NULL == (ce = make_client_entry (client))) ) |
530 | return; /* new client during shutdown */ | 720 | return; /* new client during shutdown */ |
531 | msize = ntohs (message->size); | 721 | msize = ntohs (message->size); |
532 | if (msize < sizeof (struct GNUNET_STATISTICS_SetMessage)) | 722 | if (msize < sizeof (struct GNUNET_STATISTICS_SetMessage)) |
@@ -537,77 +727,91 @@ handle_set (void *cls, | |||
537 | } | 727 | } |
538 | size = msize - sizeof (struct GNUNET_STATISTICS_SetMessage); | 728 | size = msize - sizeof (struct GNUNET_STATISTICS_SetMessage); |
539 | msg = (const struct GNUNET_STATISTICS_SetMessage *) message; | 729 | msg = (const struct GNUNET_STATISTICS_SetMessage *) message; |
540 | |||
541 | if (size != | 730 | if (size != |
542 | GNUNET_STRINGS_buffer_tokenize ((const char *) &msg[1], size, 2, &service, | 731 | GNUNET_STRINGS_buffer_tokenize ((const char *) &msg[1], |
732 | size, | ||
733 | 2, | ||
734 | &service, | ||
543 | &name)) | 735 | &name)) |
544 | { | 736 | { |
545 | GNUNET_break (0); | 737 | GNUNET_break (0); |
546 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | 738 | GNUNET_SERVER_receive_done (client, |
739 | GNUNET_SYSERR); | ||
547 | return; | 740 | return; |
548 | } | 741 | } |
742 | se = find_subsystem_entry (ce, service); | ||
549 | flags = ntohl (msg->flags); | 743 | flags = ntohl (msg->flags); |
550 | value = GNUNET_ntohll (msg->value); | 744 | value = GNUNET_ntohll (msg->value); |
551 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 745 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
552 | "Received request to update statistic on `%s:%s' (%u) to/by %llu\n", | 746 | "Received request to update statistic on `%s:%s' (%u) to/by %llu\n", |
553 | service, name, (unsigned int) flags, (unsigned long long) value); | 747 | service, |
554 | pos = start; | 748 | name, |
555 | prev = NULL; | 749 | (unsigned int) flags, |
556 | while (pos != NULL) | 750 | (unsigned long long) value); |
751 | pos = find_stat_entry (se, name); | ||
752 | if (NULL != pos) | ||
557 | { | 753 | { |
558 | if (matches (pos, service, name)) | 754 | initial_set = 0; |
755 | if (0 == (flags & GNUNET_STATISTICS_SETFLAG_RELATIVE)) | ||
559 | { | 756 | { |
560 | initial_set = 0; | 757 | changed = (pos->value != value); |
561 | if ((flags & GNUNET_STATISTICS_SETFLAG_RELATIVE) == 0) | 758 | pos->value = value; |
759 | } | ||
760 | else | ||
761 | { | ||
762 | delta = (int64_t) value; | ||
763 | if ((delta < 0) && (pos->value < -delta)) | ||
562 | { | 764 | { |
563 | changed = (pos->value != value); | 765 | changed = (0 != pos->value); |
564 | pos->value = value; | 766 | pos->value = 0; |
565 | } | 767 | } |
566 | else | 768 | else |
567 | { | 769 | { |
568 | delta = (int64_t) value; | 770 | changed = (0 != delta); |
569 | if ((delta < 0) && (pos->value < -delta)) | 771 | GNUNET_break ( (delta <= 0) || |
570 | { | 772 | (pos->value + delta > pos->value) ); |
571 | changed = (pos->value != 0); | 773 | pos->value += delta; |
572 | pos->value = 0; | ||
573 | } | ||
574 | else | ||
575 | { | ||
576 | changed = (delta != 0); | ||
577 | GNUNET_break ((delta <= 0) || (pos->value + delta > pos->value)); | ||
578 | pos->value += delta; | ||
579 | } | ||
580 | } | ||
581 | if (GNUNET_NO == pos->set) | ||
582 | { | ||
583 | pos->set = GNUNET_YES; | ||
584 | initial_set = 1; | ||
585 | } | ||
586 | pos->msg->value = GNUNET_htonll (pos->value); | ||
587 | pos->msg->flags = msg->flags; | ||
588 | pos->persistent = (0 != (flags & GNUNET_STATISTICS_SETFLAG_PERSISTENT)); | ||
589 | if (prev != NULL) | ||
590 | { | ||
591 | /* move to front for faster setting next time! */ | ||
592 | prev->next = pos->next; | ||
593 | pos->next = start; | ||
594 | start = pos; | ||
595 | } | 774 | } |
596 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
597 | "Statistic `%s:%s' updated to value %llu.\n", service, name, | ||
598 | pos->value); | ||
599 | if ((changed) || (1 == initial_set)) | ||
600 | notify_change (pos); | ||
601 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
602 | return; | ||
603 | } | 775 | } |
604 | prev = pos; | 776 | if (GNUNET_NO == pos->set) |
605 | pos = pos->next; | 777 | { |
778 | pos->set = GNUNET_YES; | ||
779 | initial_set = 1; | ||
780 | } | ||
781 | pos->persistent = (0 != (flags & GNUNET_STATISTICS_SETFLAG_PERSISTENT)); | ||
782 | if (pos != se->stat_head) | ||
783 | { | ||
784 | /* move to front for faster setting next time! */ | ||
785 | GNUNET_CONTAINER_DLL_remove (se->stat_head, | ||
786 | se->stat_tail, | ||
787 | pos); | ||
788 | GNUNET_CONTAINER_DLL_insert (se->stat_head, | ||
789 | se->stat_tail, | ||
790 | pos); | ||
791 | } | ||
792 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
793 | "Statistic `%s:%s' updated to value %llu (%d).\n", | ||
794 | service, | ||
795 | name, | ||
796 | pos->value, | ||
797 | pos->persistent); | ||
798 | if ( (changed) || | ||
799 | (1 == initial_set) ) | ||
800 | notify_change (pos); | ||
801 | GNUNET_SERVER_receive_done (client, | ||
802 | GNUNET_OK); | ||
803 | return; | ||
606 | } | 804 | } |
607 | pos = GNUNET_malloc (sizeof (struct StatsEntry) + msize); | 805 | /* not found, create a new entry */ |
608 | pos->next = start; | 806 | nlen = strlen (name) + 1; |
609 | if (((flags & GNUNET_STATISTICS_SETFLAG_RELATIVE) == 0) || | 807 | pos = GNUNET_malloc (sizeof (struct StatsEntry) + nlen); |
610 | (0 < (int64_t) GNUNET_ntohll (msg->value))) | 808 | memcpy (&pos[1], |
809 | name, | ||
810 | nlen); | ||
811 | pos->name = (const char *) &pos[1]; | ||
812 | pos->subsystem = se; | ||
813 | if ( (0 == (flags & GNUNET_STATISTICS_SETFLAG_RELATIVE)) || | ||
814 | (0 < (int64_t) GNUNET_ntohll (msg->value)) ) | ||
611 | { | 815 | { |
612 | pos->value = GNUNET_ntohll (msg->value); | 816 | pos->value = GNUNET_ntohll (msg->value); |
613 | pos->set = GNUNET_YES; | 817 | pos->set = GNUNET_YES; |
@@ -618,18 +822,16 @@ handle_set (void *cls, | |||
618 | } | 822 | } |
619 | pos->uid = uidgen++; | 823 | pos->uid = uidgen++; |
620 | pos->persistent = (0 != (flags & GNUNET_STATISTICS_SETFLAG_PERSISTENT)); | 824 | pos->persistent = (0 != (flags & GNUNET_STATISTICS_SETFLAG_PERSISTENT)); |
621 | pos->msg = (void *) &pos[1]; | 825 | GNUNET_CONTAINER_DLL_insert (se->stat_head, |
622 | memcpy (pos->msg, message, ntohs (message->size)); | 826 | se->stat_tail, |
623 | pos->service = (const char *) &pos->msg[1]; | 827 | pos); |
624 | pos->name = &pos->service[strlen (pos->service) + 1]; | ||
625 | |||
626 | start = pos; | ||
627 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 828 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
628 | "New statistic on `%s:%s' with value %llu created.\n", | 829 | "New statistic on `%s:%s' with value %llu created.\n", |
629 | service, | 830 | service, |
630 | name, | 831 | name, |
631 | pos->value); | 832 | pos->value); |
632 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | 833 | GNUNET_SERVER_receive_done (client, |
834 | GNUNET_OK); | ||
633 | } | 835 | } |
634 | 836 | ||
635 | 837 | ||
@@ -645,18 +847,20 @@ handle_watch (void *cls, | |||
645 | struct GNUNET_SERVER_Client *client, | 847 | struct GNUNET_SERVER_Client *client, |
646 | const struct GNUNET_MessageHeader *message) | 848 | const struct GNUNET_MessageHeader *message) |
647 | { | 849 | { |
648 | char *service; | 850 | const char *service; |
649 | char *name; | 851 | const char *name; |
650 | uint16_t msize; | 852 | uint16_t msize; |
651 | uint16_t size; | 853 | uint16_t size; |
854 | struct SubsystemEntry *se; | ||
652 | struct StatsEntry *pos; | 855 | struct StatsEntry *pos; |
653 | struct ClientEntry *ce; | 856 | struct ClientEntry *ce; |
654 | struct WatchEntry *we; | 857 | struct WatchEntry *we; |
655 | size_t slen; | 858 | size_t nlen; |
656 | 859 | ||
657 | if (NULL == nc) | 860 | if (NULL == nc) |
658 | { | 861 | { |
659 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | 862 | GNUNET_SERVER_receive_done (client, |
863 | GNUNET_SYSERR); | ||
660 | return; | 864 | return; |
661 | } | 865 | } |
662 | GNUNET_SERVER_client_mark_monitor (client); | 866 | GNUNET_SERVER_client_mark_monitor (client); |
@@ -670,8 +874,11 @@ handle_watch (void *cls, | |||
670 | } | 874 | } |
671 | size = msize - sizeof (struct GNUNET_MessageHeader); | 875 | size = msize - sizeof (struct GNUNET_MessageHeader); |
672 | if (size != | 876 | if (size != |
673 | GNUNET_STRINGS_buffer_tokenize ((const char *) &message[1], size, 2, | 877 | GNUNET_STRINGS_buffer_tokenize ((const char *) &message[1], |
674 | &service, &name)) | 878 | size, |
879 | 2, | ||
880 | &service, | ||
881 | &name)) | ||
675 | { | 882 | { |
676 | GNUNET_break (0); | 883 | GNUNET_break (0); |
677 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | 884 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); |
@@ -681,27 +888,21 @@ handle_watch (void *cls, | |||
681 | "Received request to watch statistic on `%s:%s'\n", | 888 | "Received request to watch statistic on `%s:%s'\n", |
682 | service, | 889 | service, |
683 | name); | 890 | name); |
684 | for (pos = start; NULL != pos; pos = pos->next) | 891 | se = find_subsystem_entry (ce, service); |
685 | if (matches (pos, service, name)) | 892 | pos = find_stat_entry (se, name); |
686 | break; | 893 | if (NULL == pos) |
687 | if (pos == NULL) | ||
688 | { | 894 | { |
689 | pos = | 895 | nlen = strlen (name) + 1; |
690 | GNUNET_malloc (sizeof (struct StatsEntry) + | 896 | pos = GNUNET_malloc (sizeof (struct StatsEntry) + |
691 | sizeof (struct GNUNET_STATISTICS_SetMessage) + size); | 897 | nlen); |
692 | pos->next = start; | 898 | memcpy (&pos[1], name, nlen); |
899 | pos->name = (const char *) &pos[1]; | ||
900 | pos->subsystem = se; | ||
901 | GNUNET_CONTAINER_DLL_insert (se->stat_head, | ||
902 | se->stat_tail, | ||
903 | pos); | ||
693 | pos->uid = uidgen++; | 904 | pos->uid = uidgen++; |
694 | pos->set = GNUNET_NO; | 905 | pos->set = GNUNET_NO; |
695 | pos->msg = (void *) &pos[1]; | ||
696 | pos->msg->header.size = | ||
697 | htons (sizeof (struct GNUNET_STATISTICS_SetMessage) + size); | ||
698 | pos->msg->header.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_SET); | ||
699 | pos->service = (const char *) &pos->msg[1]; | ||
700 | slen = strlen (service) + 1; | ||
701 | memcpy ((void *) pos->service, service, slen); | ||
702 | pos->name = &pos->service[slen]; | ||
703 | memcpy ((void *) pos->name, name, strlen (name) + 1); | ||
704 | start = pos; | ||
705 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 906 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
706 | "New statistic on `%s:%s' with value %llu created.\n", | 907 | "New statistic on `%s:%s' with value %llu created.\n", |
707 | service, | 908 | service, |
@@ -715,7 +916,7 @@ handle_watch (void *cls, | |||
715 | GNUNET_CONTAINER_DLL_insert (pos->we_head, | 916 | GNUNET_CONTAINER_DLL_insert (pos->we_head, |
716 | pos->we_tail, | 917 | pos->we_tail, |
717 | we); | 918 | we); |
718 | if (pos->value != 0) | 919 | if (0 != pos->value) |
719 | notify_change (pos); | 920 | notify_change (pos); |
720 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | 921 | GNUNET_SERVER_receive_done (client, GNUNET_OK); |
721 | } | 922 | } |
@@ -728,7 +929,8 @@ static void | |||
728 | do_shutdown () | 929 | do_shutdown () |
729 | { | 930 | { |
730 | struct WatchEntry *we; | 931 | struct WatchEntry *we; |
731 | struct StatsEntry *se; | 932 | struct StatsEntry *pos; |
933 | struct SubsystemEntry *se; | ||
732 | 934 | ||
733 | if (NULL == nc) | 935 | if (NULL == nc) |
734 | return; | 936 | return; |
@@ -736,15 +938,25 @@ do_shutdown () | |||
736 | GNUNET_SERVER_notification_context_destroy (nc); | 938 | GNUNET_SERVER_notification_context_destroy (nc); |
737 | nc = NULL; | 939 | nc = NULL; |
738 | GNUNET_assert (0 == client_count); | 940 | GNUNET_assert (0 == client_count); |
739 | while (NULL != (se = start)) | 941 | while (NULL != (se = sub_head)) |
740 | { | 942 | { |
741 | start = se->next; | 943 | GNUNET_CONTAINER_DLL_remove (sub_head, |
742 | while (NULL != (we = se->we_head)) | 944 | sub_tail, |
945 | se); | ||
946 | while (NULL != (pos = se->stat_head)) | ||
743 | { | 947 | { |
744 | GNUNET_CONTAINER_DLL_remove (se->we_head, | 948 | GNUNET_CONTAINER_DLL_remove (se->stat_head, |
745 | se->we_tail, | 949 | se->stat_tail, |
746 | we); | 950 | pos); |
747 | GNUNET_free (we); | 951 | while (NULL != (we = pos->we_head)) |
952 | { | ||
953 | GNUNET_break (0); | ||
954 | GNUNET_CONTAINER_DLL_remove (pos->we_head, | ||
955 | pos->we_tail, | ||
956 | we); | ||
957 | GNUNET_free (we); | ||
958 | } | ||
959 | GNUNET_free (pos); | ||
748 | } | 960 | } |
749 | GNUNET_free (se); | 961 | GNUNET_free (se); |
750 | } | 962 | } |
@@ -781,7 +993,8 @@ handle_client_disconnect (void *cls, | |||
781 | struct ClientEntry *ce; | 993 | struct ClientEntry *ce; |
782 | struct WatchEntry *we; | 994 | struct WatchEntry *we; |
783 | struct WatchEntry *wen; | 995 | struct WatchEntry *wen; |
784 | struct StatsEntry *se; | 996 | struct StatsEntry *pos; |
997 | struct SubsystemEntry *se; | ||
785 | 998 | ||
786 | if (NULL == client) | 999 | if (NULL == client) |
787 | return; | 1000 | return; |
@@ -792,19 +1005,22 @@ handle_client_disconnect (void *cls, | |||
792 | GNUNET_SERVER_client_set_user_context (client, | 1005 | GNUNET_SERVER_client_set_user_context (client, |
793 | NULL); | 1006 | NULL); |
794 | client_count--; | 1007 | client_count--; |
795 | se = start; | 1008 | for (se = sub_head; NULL != se; se = se->next) |
796 | while (NULL != se) | ||
797 | { | 1009 | { |
798 | wen = se->we_head; | 1010 | for (pos = se->stat_head; NULL != pos; pos = pos->next) |
799 | while (NULL != (we = wen)) | ||
800 | { | 1011 | { |
801 | wen = we->next; | 1012 | wen = pos->we_head; |
802 | if (we->client != client) | 1013 | while (NULL != (we = wen)) |
803 | continue; | 1014 | { |
804 | GNUNET_CONTAINER_DLL_remove (se->we_head, se->we_tail, we); | 1015 | wen = we->next; |
805 | GNUNET_free (we); | 1016 | if (we->client != client) |
1017 | continue; | ||
1018 | GNUNET_CONTAINER_DLL_remove (pos->we_head, | ||
1019 | pos->we_tail, | ||
1020 | we); | ||
1021 | GNUNET_free (we); | ||
1022 | } | ||
806 | } | 1023 | } |
807 | se = se->next; | ||
808 | } | 1024 | } |
809 | if ( (0 == client_count) && | 1025 | if ( (0 == client_count) && |
810 | (GNUNET_YES == in_shutdown) ) | 1026 | (GNUNET_YES == in_shutdown) ) |
@@ -832,9 +1048,12 @@ run (void *cls, | |||
832 | }; | 1048 | }; |
833 | cfg = c; | 1049 | cfg = c; |
834 | srv = server; | 1050 | srv = server; |
835 | GNUNET_SERVER_add_handlers (server, handlers); | 1051 | GNUNET_SERVER_add_handlers (server, |
1052 | handlers); | ||
836 | nc = GNUNET_SERVER_notification_context_create (server, 16); | 1053 | nc = GNUNET_SERVER_notification_context_create (server, 16); |
837 | GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL); | 1054 | GNUNET_SERVER_disconnect_notify (server, |
1055 | &handle_client_disconnect, | ||
1056 | NULL); | ||
838 | load (server); | 1057 | load (server); |
839 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, | 1058 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, |
840 | &shutdown_task, | 1059 | &shutdown_task, |
@@ -854,7 +1073,8 @@ main (int argc, char *const *argv) | |||
854 | { | 1073 | { |
855 | return (GNUNET_OK == | 1074 | return (GNUNET_OK == |
856 | GNUNET_SERVICE_run (argc, argv, "statistics", | 1075 | GNUNET_SERVICE_run (argc, argv, "statistics", |
857 | GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN, &run, NULL)) ? 0 : 1; | 1076 | GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN, |
1077 | &run, NULL)) ? 0 : 1; | ||
858 | } | 1078 | } |
859 | 1079 | ||
860 | #ifdef LINUX | 1080 | #ifdef LINUX |
diff --git a/src/statistics/statistics.h b/src/statistics/statistics.h index 3aa59da9d..35c2aca2c 100644 --- a/src/statistics/statistics.h +++ b/src/statistics/statistics.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | (C) 2001, 2002, 2003, 2004, 2009 Christian Grothoff (and other contributing authors) | 3 | (C) 2001-2014 Christian Grothoff (and other contributing authors) |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 5 | GNUnet is free software; you can redistribute it and/or modify |
6 | it under the terms of the GNU General Public License as published | 6 | it under the terms of the GNU General Public License as published |
@@ -47,7 +47,8 @@ struct GNUNET_STATISTICS_ReplyMessage | |||
47 | /** | 47 | /** |
48 | * Unique numerical identifier for the value (will | 48 | * Unique numerical identifier for the value (will |
49 | * not change during the same client-session). Highest | 49 | * not change during the same client-session). Highest |
50 | * bit will be set for persistent values. | 50 | * bit will be set for persistent values (see |
51 | * #GNUNET_STATISTICS_PERSIST_BIT). | ||
51 | */ | 52 | */ |
52 | uint32_t uid GNUNET_PACKED; | 53 | uint32_t uid GNUNET_PACKED; |
53 | 54 | ||
@@ -58,14 +59,31 @@ struct GNUNET_STATISTICS_ReplyMessage | |||
58 | 59 | ||
59 | }; | 60 | }; |
60 | 61 | ||
62 | /** | ||
63 | * Flag for the `struct GNUNET_STATISTICS_ReplyMessage` UID only. | ||
64 | * Note that other messages use #GNUNET_STATISTICS_SETFLAG_PERSISTENT. | ||
65 | */ | ||
61 | #define GNUNET_STATISTICS_PERSIST_BIT (1<<31) | 66 | #define GNUNET_STATISTICS_PERSIST_BIT (1<<31) |
62 | 67 | ||
68 | /** | ||
69 | * The value being set is an absolute change. | ||
70 | */ | ||
63 | #define GNUNET_STATISTICS_SETFLAG_ABSOLUTE 0 | 71 | #define GNUNET_STATISTICS_SETFLAG_ABSOLUTE 0 |
64 | 72 | ||
73 | /** | ||
74 | * The value being set is a relative change. | ||
75 | */ | ||
65 | #define GNUNET_STATISTICS_SETFLAG_RELATIVE 1 | 76 | #define GNUNET_STATISTICS_SETFLAG_RELATIVE 1 |
66 | 77 | ||
78 | /** | ||
79 | * The value being set is to be persistent (note that | ||
80 | * this bit can be combined with #GNUNET_STATISTICS_SETFLAG_RELATIVE). | ||
81 | * This value must not be used for the `uid` member of | ||
82 | * `struct GNUNET_STATISTICS_ReplyMessage`! | ||
83 | */ | ||
67 | #define GNUNET_STATISTICS_SETFLAG_PERSISTENT 2 | 84 | #define GNUNET_STATISTICS_SETFLAG_PERSISTENT 2 |
68 | 85 | ||
86 | |||
69 | /** | 87 | /** |
70 | * Message to set a statistic. Followed | 88 | * Message to set a statistic. Followed |
71 | * by the subsystem name and the name of | 89 | * by the subsystem name and the name of |
@@ -74,7 +92,7 @@ struct GNUNET_STATISTICS_ReplyMessage | |||
74 | struct GNUNET_STATISTICS_SetMessage | 92 | struct GNUNET_STATISTICS_SetMessage |
75 | { | 93 | { |
76 | /** | 94 | /** |
77 | * Type: GNUNET_MESSAGE_TYPE_STATISTICS_SET | 95 | * Type: #GNUNET_MESSAGE_TYPE_STATISTICS_SET |
78 | */ | 96 | */ |
79 | struct GNUNET_MessageHeader header; | 97 | struct GNUNET_MessageHeader header; |
80 | 98 | ||
@@ -99,7 +117,7 @@ struct GNUNET_STATISTICS_SetMessage | |||
99 | struct GNUNET_STATISTICS_WatchValueMessage | 117 | struct GNUNET_STATISTICS_WatchValueMessage |
100 | { | 118 | { |
101 | /** | 119 | /** |
102 | * Type: GNUNET_MESSAGE_TYPE_STATISTICS_WATCH_VALUE | 120 | * Type: #GNUNET_MESSAGE_TYPE_STATISTICS_WATCH_VALUE |
103 | */ | 121 | */ |
104 | struct GNUNET_MessageHeader header; | 122 | struct GNUNET_MessageHeader header; |
105 | 123 | ||