[or-cvs] r9047: Revise logic used to flush state to disk. Now, we try to bat (in tor/trunk: . src/or)

nickm at seul.org nickm at seul.org
Thu Dec 7 20:11:33 UTC 2006


Author: nickm
Date: 2006-12-07 15:11:30 -0500 (Thu, 07 Dec 2006)
New Revision: 9047

Modified:
   tor/trunk/
   tor/trunk/ChangeLog
   tor/trunk/src/or/circuitbuild.c
   tor/trunk/src/or/config.c
   tor/trunk/src/or/hibernate.c
   tor/trunk/src/or/main.c
   tor/trunk/src/or/or.h
   tor/trunk/src/or/rephist.c
Log:
 r11468 at Kushana:  nickm | 2006-12-07 14:56:57 -0500
 Revise logic used to flush state to disk. Now, we try to batch non-urgent changes so that we do not do too many writes, and we save very-non-urgent changes every once in a rare while, and we never save more than once per second.



Property changes on: tor/trunk
___________________________________________________________________
 svk:merge ticket from /tor/trunk [r11468] on c95137ef-5f19-0410-b913-86e773d04f59

Modified: tor/trunk/ChangeLog
===================================================================
--- tor/trunk/ChangeLog	2006-12-07 20:11:24 UTC (rev 9046)
+++ tor/trunk/ChangeLog	2006-12-07 20:11:30 UTC (rev 9047)
@@ -3,6 +3,9 @@
     - 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.
+    - Try to batch changes to the state so that we do as few disk writes
+      as possible while still storing important things in a timely
+      fashion.
 
   o Minor bugfixes;
     - Fix a bug when a PF socket is first used.  (Patch from Fabian

Modified: tor/trunk/src/or/circuitbuild.c
===================================================================
--- tor/trunk/src/or/circuitbuild.c	2006-12-07 20:11:24 UTC (rev 9046)
+++ tor/trunk/src/or/circuitbuild.c	2006-12-07 20:11:30 UTC (rev 9047)
@@ -2376,13 +2376,16 @@
 }
 
 /** Our list of entry guards has changed, or some element of one
- * of our entry guards has changed. Write the changes to disk. */
+ * of our entry guards has changed. Write the changes to disk within
+ * the next 5 minutes.
+ */
 static void
 entry_guards_changed(void)
 {
   entry_guards_dirty = 1;
 
-  or_state_save();
+  /* or_state_save() will call entry_guards_update_state(). */
+  or_state_mark_dirty(get_or_state(), time(NULL)+600);
 }
 
 /** If the entry guard info has not changed, do nothing and return.
@@ -2433,7 +2436,7 @@
         next = &(line->next);
       }
     });
-  state->dirty = 1;
+  or_state_mark_dirty(get_or_state(), 0);
   entry_guards_dirty = 0;
 }
 

Modified: tor/trunk/src/or/config.c
===================================================================
--- tor/trunk/src/or/config.c	2006-12-07 20:11:24 UTC (rev 9046)
+++ tor/trunk/src/or/config.c	2006-12-07 20:11:30 UTC (rev 9047)
@@ -3934,8 +3934,8 @@
   or_state_set(new_state);
   new_state = NULL;
   if (!contents) {
-    global_state->dirty = 1;
-    or_state_save();
+    global_state->next_write = 0;
+    or_state_save(time(NULL));
   }
   r = 0;
 
@@ -3950,7 +3950,7 @@
 
 /** Write the persistent state to disk. Return 0 for success, <0 on failure. */
 int
-or_state_save(void)
+or_state_save(time_t now)
 {
   char *state, *contents;
   char tbuf[ISO_TIME_LEN+1];
@@ -3959,12 +3959,15 @@
 
   tor_assert(global_state);
 
+  if (global_state->next_write > now)
+    return 0;
+
+  /* Call everything else that might dirty the state even more, in order
+   * to avoid redundant writes. */
   entry_guards_update_state(global_state);
   rep_hist_update_state(global_state);
+  accounting_run_housekeeping(now);
 
-  if (!global_state->dirty)
-    return 0;
-
   global_state->LastWritten = time(NULL);
   tor_free(global_state->TorVersion);
   global_state->TorVersion = tor_strdup("Tor " VERSION);
@@ -3988,7 +3991,7 @@
   tor_free(fname);
   tor_free(contents);
 
-  global_state->dirty = 0;
+  global_state->next_write = TIME_MAX;
   return 0;
 }
 

Modified: tor/trunk/src/or/hibernate.c
===================================================================
--- tor/trunk/src/or/hibernate.c	2006-12-07 20:11:24 UTC (rev 9046)
+++ tor/trunk/src/or/hibernate.c	2006-12-07 20:11:30 UTC (rev 9047)
@@ -391,8 +391,8 @@
 static INLINE int
 time_to_record_bandwidth_usage(time_t now)
 {
-  /* Note every 60 sec */
-#define NOTE_INTERVAL (60)
+  /* Note every 600 sec */
+#define NOTE_INTERVAL (600)
   /* Or every 20 megabytes */
 #define NOTE_BYTES 20*(1024*1024)
   static uint64_t last_read_bytes_noted = 0;
@@ -575,7 +575,7 @@
   state->AccountingBytesWrittenInInterval = n_bytes_written_in_interval;
   state->AccountingSecondsActive = n_seconds_active_in_interval;
   state->AccountingExpectedUsage = expected_bandwidth_usage;
-  state->dirty = 1;
+  or_state_mark_dirty(state, 60);
 
   return r;
 }
@@ -760,6 +760,7 @@
 
   hibernate_state = new_state;
   accounting_record_bandwidth_usage(now, get_or_state());
+  or_state_mark_dirty(get_or_state(), 0);
 }
 
 /** Called when we've been hibernating and our timeout is reached. */
@@ -827,6 +828,7 @@
   }
 
   accounting_record_bandwidth_usage(now, get_or_state());
+  or_state_mark_dirty(get_or_state(), 0);
 }
 
 /** Called when hibernate_end_time has arrived. */

Modified: tor/trunk/src/or/main.c
===================================================================
--- tor/trunk/src/or/main.c	2006-12-07 20:11:24 UTC (rev 9046)
+++ tor/trunk/src/or/main.c	2006-12-07 20:11:30 UTC (rev 9047)
@@ -830,9 +830,6 @@
      * and the rend cache. */
     rep_history_clean(now - options->RephistTrackTime);
     rend_cache_clean();
-    /* And while we are at it, save the state with bandwidth history
-     * and more. */
-    or_state_save();
  }
 
   /* 2b. Once per minute, regenerate and upload the descriptor if the old
@@ -935,6 +932,10 @@
    */
   close_closeable_connections();
 
+  /** 8b. And if anything in our state is ready to get flushed to disk, we
+   * flush it. */
+  or_state_save(now);
+
   /** 9. and if we're a server, check whether our DNS is telling stories to
    * us. */
   if (server_mode(options) && time_to_check_for_wildcarded_dns < now) {
@@ -1595,7 +1596,8 @@
       unlink(options->PidFile);
     if (accounting_is_enabled(options))
       accounting_record_bandwidth_usage(time(NULL), get_or_state());
-    or_state_save();
+    or_state_mark_dirty(get_or_state(), 0); /* force an immediate save. */
+    or_state_save(time(NULL));
   }
   tor_free_all(0); /* move tor_free_all back into the ifdef below later. XXX*/
   crypto_global_cleanup();

Modified: tor/trunk/src/or/or.h
===================================================================
--- tor/trunk/src/or/or.h	2006-12-07 20:11:24 UTC (rev 9046)
+++ tor/trunk/src/or/or.h	2006-12-07 20:11:30 UTC (rev 9047)
@@ -1655,19 +1655,30 @@
 /** 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;
+  /** The time at which we next plan to write the state to the disk.  Equal to
+   * TIME_MAX if there are no saveable changes, 0 if there are changes that
+   * should be saved right away. */
+  time_t next_write;
 
+  /** When was the state last written to disk? */
   time_t LastWritten;
+
+  /** Fields for */
   time_t AccountingIntervalStart;
   uint64_t AccountingBytesReadInInterval;
   uint64_t AccountingBytesWrittenInInterval;
   int AccountingSecondsActive;
   uint64_t AccountingExpectedUsage;
 
+  /** A list of Entry Guard-related configuration lines. */
   config_line_t *EntryGuards;
 
+  /** These fields hold information on the history of bandwidth usage for
+   * servers.  The "Ends" fields hold the time when we last updated the
+   * bandwidth usage. The "Interval" fields hold the granularity, in seconds,
+   * of the entries of Values.  The "Values" lists hold decimal string
+   * representations of the number of bytes read or written in each
+   * interval. */
   time_t      BWHistoryReadEnds;
   int         BWHistoryReadInterval;
   smartlist_t *BWHistoryReadValues;
@@ -1675,11 +1686,24 @@
   int         BWHistoryWriteInterval;
   smartlist_t *BWHistoryWriteValues;
 
+  /** What version of Tor write this state file? */
   char *TorVersion;
 
+  /** holds any unrecognized values we found in the state file, in the order
+   * in which we found them. */
   config_line_t *ExtraLines;
 } or_state_t;
 
+static void or_state_mark_dirty(or_state_t *state, time_t when);
+/** Change the next_write time of <b>state</b> to <b>when</b>, unless the
+ * state is already scheduled to be written to disk earlier than <b>when</b>.
+ */
+static INLINE void or_state_mark_dirty(or_state_t *state, time_t when)
+{
+  if (state->next_write > when)
+    state->next_write = when;
+}
+
 #define MAX_SOCKS_REPLY_LEN 1024
 #define MAX_SOCKS_ADDR_LEN 256
 #define SOCKS_COMMAND_CONNECT 0x01
@@ -1897,7 +1921,7 @@
 
 or_state_t *get_or_state(void);
 int or_state_load(void);
-int or_state_save(void);
+int or_state_save(time_t now);
 
 int config_getinfo_helper(const char *question, char **answer);
 

Modified: tor/trunk/src/or/rephist.c
===================================================================
--- tor/trunk/src/or/rephist.c	2006-12-07 20:11:24 UTC (rev 9046)
+++ tor/trunk/src/or/rephist.c	2006-12-07 20:11:30 UTC (rev 9047)
@@ -666,6 +666,8 @@
     if (! server_mode(get_options())) {
       /* Clients don't need to store bandwidth history persistently;
        * force these values to the defaults. */
+      if (*s_begins != 0 || *s_interval != 900)
+        or_state_mark_dirty(get_or_state(), time(NULL)+600);
       *s_begins = 0;
       *s_interval = 900;
       *s_values = smartlist_create();
@@ -682,7 +684,8 @@
       smartlist_split_string(*s_values, buf, ",", SPLIT_SKIP_SPACE, 0);
   }
   tor_free(buf);
-  state->dirty = 1;
+  if (server_mode(get_options()))
+    or_state_mark_dirty(get_or_state(), time(NULL)+(2*3600));
 }
 
 /** Set bandwidth history from our saved state. */



More information about the tor-commits mailing list