commit a32083bd03625c1d99a32971c1c1a574d7e6e014 Author: Nick Mathewson nickm@torproject.org Date: Sun Apr 16 17:47:28 2017 -0400
Add consensus_cache_entry spooling support to spooled_resource_t --- src/or/dirserv.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++------ src/or/dirserv.h | 14 +++++++++++-- 2 files changed, 70 insertions(+), 8 deletions(-)
diff --git a/src/or/dirserv.c b/src/or/dirserv.c index e76fd93..bdf40b6 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -13,6 +13,7 @@ #include "command.h" #include "connection.h" #include "connection_or.h" +#include "conscache.h" #include "control.h" #include "directory.h" #include "dirserv.h" @@ -3392,6 +3393,9 @@ spooled_resource_new(dir_spool_source_t source, default: spooled->spool_eagerly = 1; break; + case DIR_SPOOL_CONSENSUS_CACHE_ENTRY: + tor_assert_unreached(); + break; } tor_assert(digestlen <= sizeof(spooled->digest)); if (digest) @@ -3399,6 +3403,33 @@ spooled_resource_new(dir_spool_source_t source, return spooled; }
+/** + * Create a new spooled_resource_t to spool the contents of <b>entry</b> to + * the user. Return the spooled object on success, or NULL on failure (which + * is probably caused by a failure to map the body of the item from disk). + * + * Adds a reference to entry's reference counter. + */ +spooled_resource_t * +spooled_resource_new_from_cache_entry(consensus_cache_entry_t *entry) +{ + spooled_resource_t *spooled = tor_malloc_zero(sizeof(spooled_resource_t)); + spooled->spool_source = DIR_SPOOL_CONSENSUS_CACHE_ENTRY; + spooled->spool_eagerly = 0; + consensus_cache_entry_incref(entry); + spooled->consensus_cache_entry = entry; + + int r = consensus_cache_entry_get_body(entry, + &spooled->cce_body, + &spooled->cce_len); + if (r == 0) { + return spooled; + } else { + spooled_resource_free(spooled); + return NULL; + } +} + /** Release all storage held by <b>spooled</b>. */ void spooled_resource_free(spooled_resource_t *spooled) @@ -3410,6 +3441,10 @@ spooled_resource_free(spooled_resource_t *spooled) cached_dir_decref(spooled->cached_dir_ref); }
+ if (spooled->consensus_cache_entry) { + consensus_cache_entry_decref(spooled->consensus_cache_entry); + } + tor_free(spooled); }
@@ -3456,6 +3491,9 @@ spooled_resource_estimate_size(const spooled_resource_t *spooled, return bodylen; } else { cached_dir_t *cached; + if (spooled->consensus_cache_entry) { + return spooled->cce_len; + } if (spooled->cached_dir_ref) { cached = spooled->cached_dir_ref; } else { @@ -3505,7 +3543,8 @@ spooled_resource_flush_some(spooled_resource_t *spooled, return SRFS_DONE; } else { cached_dir_t *cached = spooled->cached_dir_ref; - if (cached == NULL) { + consensus_cache_entry_t *cce = spooled->consensus_cache_entry; + if (cached == NULL && cce == NULL) { /* The cached_dir_t hasn't been materialized yet. So let's look it up. */ cached = spooled->cached_dir_ref = spooled_resource_lookup_cached_dir(spooled, NULL); @@ -3517,22 +3556,34 @@ spooled_resource_flush_some(spooled_resource_t *spooled, tor_assert_nonfatal(spooled->cached_dir_offset == 0); }
+ if (BUG(!cached && !cce)) + return SRFS_DONE; + + int64_t total_len; + const char *ptr; + if (cached) { + total_len = cached->dir_z_len; + ptr = cached->dir_z; + } else { + total_len = spooled->cce_len; + ptr = (const char *)spooled->cce_body; + } /* How many bytes left to flush? */ - int64_t remaining = 0; - remaining = cached->dir_z_len - spooled->cached_dir_offset; + int64_t remaining; + remaining = total_len - spooled->cached_dir_offset; if (BUG(remaining < 0)) return SRFS_ERR; ssize_t bytes = (ssize_t) MIN(DIRSERV_CACHED_DIR_CHUNK_SIZE, remaining); if (conn->compress_state) { connection_write_to_buf_compress( - cached->dir_z + spooled->cached_dir_offset, + ptr + spooled->cached_dir_offset, bytes, conn, 0); } else { - connection_write_to_buf(cached->dir_z + spooled->cached_dir_offset, + connection_write_to_buf(ptr + spooled->cached_dir_offset, bytes, TO_CONN(conn)); } spooled->cached_dir_offset += bytes; - if (spooled->cached_dir_offset >= (off_t)cached->dir_z_len) { + if (spooled->cached_dir_offset >= (off_t)total_len) { return SRFS_DONE; } else { return SRFS_MORE; @@ -3608,6 +3659,7 @@ spooled_resource_lookup_body(const spooled_resource_t *spooled, return 0; } case DIR_SPOOL_NETWORKSTATUS: + case DIR_SPOOL_CONSENSUS_CACHE_ENTRY: default: /* LCOV_EXCL_START */ tor_assert_nonfatal_unreached(); diff --git a/src/or/dirserv.h b/src/or/dirserv.h index f707237..4b09f87 100644 --- a/src/or/dirserv.h +++ b/src/or/dirserv.h @@ -38,6 +38,7 @@ typedef enum dir_spool_source_t { DIR_SPOOL_EXTRA_BY_DIGEST, DIR_SPOOL_EXTRA_BY_FP, DIR_SPOOL_MICRODESC, DIR_SPOOL_NETWORKSTATUS, + DIR_SPOOL_CONSENSUS_CACHE_ENTRY, } dir_spool_source_t; #define dir_spool_source_bitfield_t ENUM_BF(dir_spool_source_t)
@@ -74,8 +75,15 @@ typedef struct spooled_resource_t { */ struct cached_dir_t *cached_dir_ref; /** - * The current offset into cached_dir. Only used when spool_eagerly is - * false */ + * A different kind of large object that we might be spooling. Also + * reference-counted. Also only used when spool_eagerly is false. + */ + struct consensus_cache_entry_t *consensus_cache_entry; + const uint8_t *cce_body; + size_t cce_len; + /** + * The current offset into cached_dir or cce_body. Only used when + * spool_eagerly is false */ off_t cached_dir_offset; } spooled_resource_t;
@@ -184,6 +192,8 @@ int dirserv_read_guardfraction_file(const char *fname, spooled_resource_t *spooled_resource_new(dir_spool_source_t source, const uint8_t *digest, size_t digestlen); +spooled_resource_t *spooled_resource_new_from_cache_entry( + struct consensus_cache_entry_t *entry); void spooled_resource_free(spooled_resource_t *spooled); void dirserv_spool_remove_missing_and_guess_size(dir_connection_t *conn, time_t cutoff,