Bläddra i källkod

Count zlib buffer memory towards OOM totals.

Part of 11792.

(Uses the zlib-endorsed formula for memory needs for inflate/deflate
from "zconf.h".)
Nick Mathewson 9 år sedan
förälder
incheckning
8e55cafd67
5 ändrade filer med 82 tillägg och 3 borttagningar
  1. 7 1
      changes/bug11792
  2. 63 2
      src/common/torgzip.c
  3. 3 0
      src/common/torgzip.h
  4. 8 0
      src/or/circuitlist.c
  5. 1 0
      src/or/relay.c

+ 7 - 1
changes/bug11792

@@ -2,4 +2,10 @@
     - When closing an edge connection because we've run out of memory,
     - When closing an edge connection because we've run out of memory,
       also count the amount of memory that any tunnelled directory
       also count the amount of memory that any tunnelled directory
       connection attached to that connection had consumed. Part of
       connection attached to that connection had consumed. Part of
-      ticket 11792.
+      ticket 11792.
+
+    - When considering whether we're running low on memory, consider
+      memory that was allocated as part of zlib buffers as well.
+      Count that memory as reclaimed by our OOM handler. Part of
+      ticket 11792.
+

+ 63 - 2
src/common/torgzip.c

@@ -46,6 +46,12 @@
 
 
 #include <zlib.h>
 #include <zlib.h>
 
 
+static size_t tor_zlib_state_size_precalc(int inflate,
+                                          int windowbits, int memlevel);
+
+/** Total number of bytes allocated for zlib state */
+static size_t total_zlib_allocation = 0;
+
 /** Set to 1 if zlib is a version that supports gzip; set to 0 if it doesn't;
 /** Set to 1 if zlib is a version that supports gzip; set to 0 if it doesn't;
  * set to -1 if we haven't checked yet. */
  * set to -1 if we haven't checked yet. */
 static int gzip_is_supported = -1;
 static int gzip_is_supported = -1;
@@ -411,6 +417,9 @@ struct tor_zlib_state_t {
   size_t input_so_far;
   size_t input_so_far;
   /** Number of bytes written so far.  Used to detect zlib bombs. */
   /** Number of bytes written so far.  Used to detect zlib bombs. */
   size_t output_so_far;
   size_t output_so_far;
+
+  /** Approximate number of bytes allocated for this object. */
+  size_t allocation;
 };
 };
 
 
 /** Construct and return a tor_zlib_state_t object using <b>method</b>.  If
 /** Construct and return a tor_zlib_state_t object using <b>method</b>.  If
@@ -420,6 +429,7 @@ tor_zlib_state_t *
 tor_zlib_new(int compress, compress_method_t method)
 tor_zlib_new(int compress, compress_method_t method)
 {
 {
   tor_zlib_state_t *out;
   tor_zlib_state_t *out;
+  int bits;
 
 
   if (method == GZIP_METHOD && !is_gzip_supported()) {
   if (method == GZIP_METHOD && !is_gzip_supported()) {
     /* Old zlib version don't support gzip in inflateInit2 */
     /* Old zlib version don't support gzip in inflateInit2 */
@@ -432,14 +442,19 @@ tor_zlib_new(int compress, compress_method_t method)
  out->stream.zfree = Z_NULL;
  out->stream.zfree = Z_NULL;
  out->stream.opaque = NULL;
  out->stream.opaque = NULL;
  out->compress = compress;
  out->compress = compress;
+ bits = method_bits(method);
  if (compress) {
  if (compress) {
    if (deflateInit2(&out->stream, Z_BEST_COMPRESSION, Z_DEFLATED,
    if (deflateInit2(&out->stream, Z_BEST_COMPRESSION, Z_DEFLATED,
-                    method_bits(method), 8, Z_DEFAULT_STRATEGY) != Z_OK)
+                    bits, 8, Z_DEFAULT_STRATEGY) != Z_OK)
      goto err;
      goto err;
  } else {
  } else {
-   if (inflateInit2(&out->stream, method_bits(method)) != Z_OK)
+   if (inflateInit2(&out->stream, bits) != Z_OK)
      goto err;
      goto err;
  }
  }
+ out->allocation = tor_zlib_state_size_precalc(!compress, bits, 8);
+
+ total_zlib_allocation += out->allocation;
+
  return out;
  return out;
 
 
  err:
  err:
@@ -517,6 +532,8 @@ tor_zlib_free(tor_zlib_state_t *state)
   if (!state)
   if (!state)
     return;
     return;
 
 
+ total_zlib_allocation -= state->allocation;
+
   if (state->compress)
   if (state->compress)
     deflateEnd(&state->stream);
     deflateEnd(&state->stream);
   else
   else
@@ -525,3 +542,47 @@ tor_zlib_free(tor_zlib_state_t *state)
   tor_free(state);
   tor_free(state);
 }
 }
 
 
+/** Return an approximate number of bytes used in RAM to hold a state with
+ * window bits <b>windowBits</b> and compression level 'memlevel' */
+static size_t
+tor_zlib_state_size_precalc(int inflate, int windowbits, int memlevel)
+{
+  windowbits &= 15;
+
+#define A_FEW_KILOBYTES 2048
+
+  if (inflate) {
+    /* From zconf.h:
+
+       "The memory requirements for inflate are (in bytes) 1 << windowBits
+       that is, 32K for windowBits=15 (default value) plus a few kilobytes
+       for small objects."
+    */
+    return sizeof(tor_zlib_state_t) + sizeof(struct z_stream_s) +
+      (1 << 15) + A_FEW_KILOBYTES;
+  } else {
+    /* Also from zconf.h:
+
+       "The memory requirements for deflate are (in bytes):
+            (1 << (windowBits+2)) +  (1 << (memLevel+9))
+        ... plus a few kilobytes for small objects."
+    */
+    return sizeof(tor_zlib_state_t) + sizeof(struct z_stream_s) +
+      (1 << (windowbits + 2)) + (1 << (memlevel + 9)) + A_FEW_KILOBYTES;
+  }
+#undef A_FEW_KILOBYTES
+}
+
+/** Return the approximate number of bytes allocated for <b>state</b>. */
+size_t
+tor_zlib_state_size(const tor_zlib_state_t *state)
+{
+  return state->allocation;
+}
+
+/** Return the approximate number of bytes allocated for all zlib states. */
+size_t
+tor_zlib_get_total_allocation(void)
+{
+  return total_zlib_allocation;
+}

+ 3 - 0
src/common/torgzip.h

@@ -55,5 +55,8 @@ tor_zlib_output_t tor_zlib_process(tor_zlib_state_t *state,
                                    int finish);
                                    int finish);
 void tor_zlib_free(tor_zlib_state_t *state);
 void tor_zlib_free(tor_zlib_state_t *state);
 
 
+size_t tor_zlib_state_size(const tor_zlib_state_t *state);
+size_t tor_zlib_get_total_allocation(void);
+
 #endif
 #endif
 
 

+ 8 - 0
src/or/circuitlist.c

@@ -1811,6 +1811,14 @@ marked_circuit_single_conn_free_bytes(connection_t *conn)
     result += buf_allocation(conn->outbuf);
     result += buf_allocation(conn->outbuf);
     buf_clear(conn->outbuf);
     buf_clear(conn->outbuf);
   }
   }
+  if (conn->type == CONN_TYPE_DIR) {
+    dir_connection_t *dir_conn = TO_DIR_CONN(conn);
+    if (dir_conn->zlib_state) {
+      result += tor_zlib_state_size(dir_conn->zlib_state);
+      tor_zlib_free(dir_conn->zlib_state);
+      dir_conn->zlib_state = NULL;
+    }
+  }
   return result;
   return result;
 }
 }
 
 

+ 1 - 0
src/or/relay.c

@@ -2433,6 +2433,7 @@ cell_queues_check_size(void)
 {
 {
   size_t alloc = cell_queues_get_total_allocation();
   size_t alloc = cell_queues_get_total_allocation();
   alloc += buf_get_total_allocation();
   alloc += buf_get_total_allocation();
+  alloc += tor_zlib_get_total_allocation();
   if (alloc >= get_options()->MaxMemInQueues) {
   if (alloc >= get_options()->MaxMemInQueues) {
     circuits_handle_oom(alloc);
     circuits_handle_oom(alloc);
     return 1;
     return 1;