Count zlib buffer memory towards OOM totals.

Part of 11792.

(Uses the zlib-endorsed formula for memory needs for inflate/deflate
from "zconf.h".)
This commit is contained in:
Nick Mathewson 2014-08-19 10:59:15 -04:00
parent ec59167cae
commit 8e55cafd67
5 changed files with 82 additions and 3 deletions

View File

@ -3,3 +3,9 @@
also count the amount of memory that any tunnelled directory
connection attached to that connection had consumed. Part of
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.

View File

@ -46,6 +46,12 @@
#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 we haven't checked yet. */
static int gzip_is_supported = -1;
@ -411,6 +417,9 @@ struct tor_zlib_state_t {
size_t input_so_far;
/** Number of bytes written so far. Used to detect zlib bombs. */
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
@ -420,6 +429,7 @@ tor_zlib_state_t *
tor_zlib_new(int compress, compress_method_t method)
{
tor_zlib_state_t *out;
int bits;
if (method == GZIP_METHOD && !is_gzip_supported()) {
/* 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.opaque = NULL;
out->compress = compress;
bits = method_bits(method);
if (compress) {
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;
} else {
if (inflateInit2(&out->stream, method_bits(method)) != Z_OK)
if (inflateInit2(&out->stream, bits) != Z_OK)
goto err;
}
out->allocation = tor_zlib_state_size_precalc(!compress, bits, 8);
total_zlib_allocation += out->allocation;
return out;
err:
@ -517,6 +532,8 @@ tor_zlib_free(tor_zlib_state_t *state)
if (!state)
return;
total_zlib_allocation -= state->allocation;
if (state->compress)
deflateEnd(&state->stream);
else
@ -525,3 +542,47 @@ tor_zlib_free(tor_zlib_state_t *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;
}

View File

@ -55,5 +55,8 @@ tor_zlib_output_t tor_zlib_process(tor_zlib_state_t *state,
int finish);
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

View File

@ -1811,6 +1811,14 @@ marked_circuit_single_conn_free_bytes(connection_t *conn)
result += buf_allocation(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;
}

View File

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