Browse Source

r11462@Kushana: nickm | 2006-12-07 13:42:21 -0500
Make bandwidth accounting information get stored to the state file as well as bw_accounting. Read from the state file if it is more recent than bw_accounting, or if bw_accounting is not there.


svn:r9044

Nick Mathewson 17 years ago
parent
commit
6c8075d8a0
4 changed files with 81 additions and 47 deletions
  1. 5 0
      ChangeLog
  2. 71 43
      src/or/hibernate.c
  3. 2 2
      src/or/main.c
  4. 3 2
      src/or/or.h

+ 5 - 0
ChangeLog

@@ -1,4 +1,9 @@
 Changes in version 0.1.2.5-xxxx - 200?-??-??
+  o Minor features
+    - Start using the state file to store bandwidth accounting data:
+      the bw_accounting file is now obsolete.  We'll keep generating it
+      for a while for people who are still using 0.1.2.4-alpha.
+
   o Minor bugfixes;
     - Fix a bug when a PF socket is first used.  (Patch from Fabian
       Keil.)

+ 71 - 43
src/or/hibernate.c

@@ -420,12 +420,8 @@ accounting_run_housekeeping(time_t now)
     configure_accounting(now);
   }
   if (time_to_record_bandwidth_usage(now)) {
-    if (accounting_record_bandwidth_usage(now)) {
-      log_err(LD_FS, "Couldn't record bandwidth usage to disk; exiting.");
-      /* This can fail when we're out of fd's, causing a crash.
-       * The current answer is to reserve 32 more than we need, in
-       * set_max_file_descriptors(). */
-      exit(1);
+    if (accounting_record_bandwidth_usage(now, get_or_state())) {
+      log_warn(LD_FS, "Couldn't record bandwidth usage to disk.");
     }
   }
 }
@@ -538,7 +534,7 @@ accounting_set_wakeup_time(void)
 /** Save all our bandwidth tracking information to disk. Return 0 on
  * success, -1 on failure. */
 int
-accounting_record_bandwidth_usage(time_t now)
+accounting_record_bandwidth_usage(time_t now, or_state_t *state)
 {
   char buf[128];
   char fname[512];
@@ -546,8 +542,11 @@ accounting_record_bandwidth_usage(time_t now)
   char time2[ISO_TIME_LEN+1];
   char *cp = buf;
   time_t tmp;
-  /* Format is:
-     Version\nTime\nTime\nRead\nWrite\nSeconds\nExpected-Rate\n */
+  int r;
+
+  /* First, update bw_accounting. Until 0.1.2.5-x, this was the only place
+   * we stored this information. The format is:
+   * Version\nTime\nTime\nRead\nWrite\nSeconds\nExpected-Rate\n */
 
   format_iso_time(time1, interval_start_time);
   format_iso_time(time2, now);
@@ -568,8 +567,17 @@ accounting_record_bandwidth_usage(time_t now)
                (unsigned long)expected_bandwidth_usage);
   tor_snprintf(fname, sizeof(fname), "%s/bw_accounting",
                get_options()->DataDirectory);
+  r = write_str_to_file(fname, buf, 0);
+
+  /* Now update the state */
+  state->AccountingIntervalStart = interval_start_time;
+  state->AccountingBytesReadInInterval = n_bytes_read_in_interval;
+  state->AccountingBytesWrittenInInterval = n_bytes_written_in_interval;
+  state->AccountingSecondsActive = n_seconds_active_in_interval;
+  state->AccountingExpectedUsage = expected_bandwidth_usage;
+  state->dirty = 1;
 
-  return write_str_to_file(fname, buf, 0);
+  return r;
 }
 
 /** Read stored accounting information from disk. Return 0 on success;
@@ -582,60 +590,80 @@ read_bandwidth_usage(void)
   time_t t1, t2;
   uint64_t n_read, n_written;
   uint32_t expected_bw, n_seconds;
-  smartlist_t *elts;
-  int ok;
+  smartlist_t *elts = NULL;
+  int ok, use_state=0, r=-1;
+  or_state_t *state = get_or_state();
 
   tor_snprintf(fname, sizeof(fname), "%s/bw_accounting",
                get_options()->DataDirectory);
-  if (!(s = read_file_to_str(fname, 0, NULL))) {
-    return 0;
-  }
   elts = smartlist_create();
-  smartlist_split_string(elts, s, "\n", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK,0);
-  tor_free(s);
-
-  if (smartlist_len(elts)<1 ||
-      atoi(smartlist_get(elts,0)) != BW_ACCOUNTING_VERSION) {
-    log_warn(LD_ACCT, "Unrecognized bw_accounting file version: %s",
-             (const char*)smartlist_get(elts,0));
-    goto err;
+  if ((s = read_file_to_str(fname, 0, NULL)) == NULL) {
+    /* We have an old-format bw_accounting file. */
+    use_state = 1;
+  }
+  if (!use_state) {
+    smartlist_split_string(elts, s, "\n",
+                           SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK,0);
+    tor_free(s);
+
+    if (smartlist_len(elts)<1 ||
+        atoi(smartlist_get(elts,0)) != BW_ACCOUNTING_VERSION) {
+      log_warn(LD_ACCT, "Unrecognized bw_accounting file version: %s",
+               (const char*)smartlist_get(elts,0));
+      use_state = 1;
+    }
   }
-  if (smartlist_len(elts) < 7) {
+  if (!use_state && smartlist_len(elts) < 7) {
     log_warn(LD_ACCT, "Corrupted bw_accounting file: %d lines",
              smartlist_len(elts));
-    goto err;
+    use_state = 1;
+  }
+  if (!use_state && parse_iso_time(smartlist_get(elts,2), &t2)) {
+    log_warn(LD_ACCT, "Error parsing bandwidth usage last-written time");
+    use_state = 1;
   }
+  if (use_state || t2 <= state->LastWritten) {
+    /* Okay; it looks like the state file is more up-to-date than the
+     * bw_accounting file, or the bw_accounting file is nonexistant,
+     * or the bw_accounting file is corrupt.
+     */
+    log_info(LD_ACCT, "Reading bandwdith accounting data from state file");
+    n_bytes_read_in_interval = state->AccountingBytesReadInInterval;
+    n_bytes_written_in_interval = state->AccountingBytesWrittenInInterval;
+    n_seconds_active_in_interval = state->AccountingSecondsActive;
+    interval_start_time = state->AccountingIntervalStart;
+    expected_bandwidth_usage = state->AccountingExpectedUsage;
+    r = 0;
+    goto done;
+  }
+
   if (parse_iso_time(smartlist_get(elts,1), &t1)) {
     log_warn(LD_ACCT, "Error parsing bandwidth usage start time.");
-    goto err;
-  }
-  if (parse_iso_time(smartlist_get(elts,2), &t2)) {
-    log_warn(LD_ACCT, "Error parsing bandwidth usage last-written time");
-    goto err;
+    goto done;
   }
   n_read = tor_parse_uint64(smartlist_get(elts,3), 10, 0, UINT64_MAX,
                             &ok, NULL);
   if (!ok) {
     log_warn(LD_ACCT, "Error parsing number of bytes read");
-    goto err;
+    goto done;
   }
   n_written = tor_parse_uint64(smartlist_get(elts,4), 10, 0, UINT64_MAX,
                                &ok, NULL);
   if (!ok) {
     log_warn(LD_ACCT, "Error parsing number of bytes written");
-    goto err;
+    goto done;
   }
   n_seconds = (uint32_t)tor_parse_ulong(smartlist_get(elts,5), 10,0,ULONG_MAX,
                                         &ok, NULL);
   if (!ok) {
     log_warn(LD_ACCT, "Error parsing number of seconds live");
-    goto err;
+    goto done;
   }
   expected_bw =(uint32_t)tor_parse_ulong(smartlist_get(elts,6), 10,0,ULONG_MAX,
                                         &ok, NULL);
   if (!ok) {
     log_warn(LD_ACCT, "Error parsing expected bandwidth");
-    goto err;
+    goto done;
   }
 
   n_bytes_read_in_interval = n_read;
@@ -656,14 +684,14 @@ read_bandwidth_usage(void)
        (unsigned long)((uint64_t)expected_bandwidth_usage*1024/60),
        U64_PRINTF_ARG(n_bytes_read_in_interval),
        U64_PRINTF_ARG(n_bytes_written_in_interval));
-  SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp));
-  smartlist_free(elts);
 
-  return 0;
- err:
-  SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp));
-  smartlist_free(elts);
-  return -1;
+  r = 0;
+ done:
+  if (elts) {
+    SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp));
+    smartlist_free(elts);
+  }
+  return r;
 }
 
 /** Return true iff we have sent/received all the bytes we are willing
@@ -731,7 +759,7 @@ hibernate_begin(int new_state, time_t now)
   }
 
   hibernate_state = new_state;
-  accounting_record_bandwidth_usage(now);
+  accounting_record_bandwidth_usage(now, get_or_state());
 }
 
 /** Called when we've been hibernating and our timeout is reached. */
@@ -798,7 +826,7 @@ hibernate_go_dormant(time_t now)
       connection_mark_for_close(conn);
   }
 
-  accounting_record_bandwidth_usage(now);
+  accounting_record_bandwidth_usage(now, get_or_state());
 }
 
 /** Called when hibernate_end_time has arrived. */

+ 2 - 2
src/or/main.c

@@ -1066,7 +1066,7 @@ do_hup(void)
 
   log_notice(LD_GENERAL,"Received reload signal (hup). Reloading config.");
   if (accounting_is_enabled(options))
-    accounting_record_bandwidth_usage(time(NULL));
+    accounting_record_bandwidth_usage(time(NULL), get_or_state());
 
   router_reset_warnings();
   routerlist_reset_warnings();
@@ -1594,7 +1594,7 @@ tor_cleanup(void)
     if (options->PidFile)
       unlink(options->PidFile);
     if (accounting_is_enabled(options))
-      accounting_record_bandwidth_usage(time(NULL));
+      accounting_record_bandwidth_usage(time(NULL), get_or_state());
     or_state_save();
   }
   tor_free_all(0); /* move tor_free_all back into the ifdef below later. XXX*/

+ 3 - 2
src/or/or.h

@@ -1655,9 +1655,10 @@ typedef struct {
 /** Persistent state for an onion router, as saved to disk. */
 typedef struct {
   uint32_t _magic;
+  /** True iff this state has been changed since it was last read/written
+   * to the disk. */
   int dirty;
 
-  /* XXXX These options aren't actually attached to anything yet. */
   time_t LastWritten;
   time_t AccountingIntervalStart;
   uint64_t AccountingBytesReadInInterval;
@@ -2261,7 +2262,7 @@ int accounting_is_enabled(or_options_t *options);
 void configure_accounting(time_t now);
 void accounting_run_housekeeping(time_t now);
 void accounting_add_bytes(size_t n_read, size_t n_written, int seconds);
-int accounting_record_bandwidth_usage(time_t now);
+int accounting_record_bandwidth_usage(time_t now, or_state_t *state);
 void hibernate_begin_shutdown(void);
 int we_are_hibernating(void);
 void consider_hibernation(time_t now);