commit 7a0964279fafc9912ed5cc4b82abfb81328f5150
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Wed Apr 26 10:42:11 2017 -0400
Functionality to ensure there is space to add files to cache.
---
src/common/storagedir.c | 10 ++++++
src/common/storagedir.h | 1 +
src/or/conscache.c | 13 ++++++++
src/or/conscache.h | 1 +
src/or/consdiffmgr.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 106 insertions(+)
diff --git a/src/common/storagedir.c b/src/common/storagedir.c
index 9d3c32e..309d42d 100644
--- a/src/common/storagedir.c
+++ b/src/common/storagedir.c
@@ -530,3 +530,13 @@ storage_dir_remove_all(storage_dir_t *d)
return storage_dir_shrink(d, 0, d->max_files);
}
+/**
+ * Return the largest number of non-temporary files we're willing to
+ * store in <b>d</b>.
+ */
+int
+storage_dir_get_max_files(storage_dir_t *d)
+{
+ return d->max_files;
+}
+
diff --git a/src/common/storagedir.h b/src/common/storagedir.h
index 7811944..db25057 100644
--- a/src/common/storagedir.h
+++ b/src/common/storagedir.h
@@ -45,6 +45,7 @@ int storage_dir_shrink(storage_dir_t *d,
uint64_t target_size,
int min_to_remove);
int storage_dir_remove_all(storage_dir_t *d);
+int storage_dir_get_max_files(storage_dir_t *d);
#endif
diff --git a/src/or/conscache.c b/src/or/conscache.c
index 7760d13..5ffa129 100644
--- a/src/or/conscache.c
+++ b/src/or/conscache.c
@@ -400,6 +400,19 @@ consensus_cache_unmap_lazy(consensus_cache_t *cache, time_t cutoff)
}
/**
+ * Return the number of currently unused filenames available in this cache.
+ */
+int
+consensus_cache_get_n_filenames_available(consensus_cache_t *cache)
+{
+ tor_assert(cache);
+ int max = storage_dir_get_max_files(cache->dir);
+ int used = smartlist_len(storage_dir_list(cache->dir));
+ tor_assert_nonfatal(max >= used);
+ return max - used;
+}
+
+/**
* Delete every element of <b>cache</b> has been marked with
* consensus_cache_entry_mark_for_removal. If <b>force</b> is false,
* retain those entries which are not in use except by the cache.
diff --git a/src/or/conscache.h b/src/or/conscache.h
index ea27733..aef5420 100644
--- a/src/or/conscache.h
+++ b/src/or/conscache.h
@@ -19,6 +19,7 @@ int consensus_cache_register_with_sandbox(consensus_cache_t *cache,
void consensus_cache_unmap_lazy(consensus_cache_t *cache, time_t cutoff);
void consensus_cache_delete_pending(consensus_cache_t *cache,
int force);
+int consensus_cache_get_n_filenames_available(consensus_cache_t *cache);
consensus_cache_entry_t *consensus_cache_add(consensus_cache_t *cache,
const config_line_t *labels,
const uint8_t *data,
diff --git a/src/or/consdiffmgr.c b/src/or/consdiffmgr.c
index 1f3915f..ba52650 100644
--- a/src/or/consdiffmgr.c
+++ b/src/or/consdiffmgr.c
@@ -107,6 +107,7 @@ static consdiff_cfg_t consdiff_cfg = {
/* .cache_max_num = */ 128
};
+static int consdiffmgr_ensure_space_for_files(int n);
static int consensus_diff_queue_diff_work(consensus_cache_entry_t *diff_from,
consensus_cache_entry_t *diff_to);
static void consdiffmgr_set_cache_flags(void);
@@ -413,6 +414,8 @@ consdiffmgr_add_consensus(const char *consensus,
}
/* We don't have it. Add it to the cache. */
+ consdiffmgr_ensure_space_for_files(1);
+
{
size_t bodylen = strlen(consensus);
config_line_t *labels = NULL;
@@ -853,6 +856,82 @@ consdiffmgr_rescan(void)
}
/**
+ * Helper: compare two files by their from-valid-after and valid-after labels,
+ * trying to sort in ascending order by from-valid-after (when present) and
+ * valid-after (when not). Place everything that has neither label first in
+ * the list.
+ */
+static int
+compare_by_staleness_(const void **a, const void **b)
+{
+ const consensus_cache_entry_t *e1 = *a;
+ const consensus_cache_entry_t *e2 = *b;
+ const char *va1, *fva1, *va2, *fva2;
+ va1 = consensus_cache_entry_get_value(e1, LABEL_VALID_AFTER);
+ va2 = consensus_cache_entry_get_value(e2, LABEL_VALID_AFTER);
+ fva1 = consensus_cache_entry_get_value(e1, LABEL_FROM_VALID_AFTER);
+ fva2 = consensus_cache_entry_get_value(e2, LABEL_FROM_VALID_AFTER);
+
+ if (fva1)
+ va1 = fva1;
+ if (fva2)
+ va2 = fva2;
+
+ /* See note about iso-encoded values in compare_by_valid_after_. Also note
+ * that missing dates will get placed first. */
+ return strcmp_opt(va1, va2);
+}
+
+/** If there are not enough unused filenames to store <b>n</b> files, then
+ * delete old consensuses until there are. (We have to keep track of the
+ * number of filenames because of the way that the seccomp2 cache works.)
+ *
+ * Return 0 on success, -1 on failure.
+ **/
+static int
+consdiffmgr_ensure_space_for_files(int n)
+{
+ consensus_cache_t *cache = cdm_cache_get();
+ if (consensus_cache_get_n_filenames_available(cache) >= n) {
+ // there are already enough unused filenames.
+ return 0;
+ }
+ // Try a cheap deletion of stuff that's waiting to get deleted.
+ consensus_cache_delete_pending(cache, 0);
+ if (consensus_cache_get_n_filenames_available(cache) >= n) {
+ // okay, _that_ made enough filenames available.
+ return 0;
+ }
+ // Let's get more assertive: clean out unused stuff, and force-remove
+ // the files.
+ consdiffmgr_cleanup();
+ consensus_cache_delete_pending(cache, 1);
+ const int n_to_remove = n - consensus_cache_get_n_filenames_available(cache);
+ if (n_to_remove <= 0) {
+ // okay, finally!
+ return 0;
+ }
+
+ // At this point, we're going to have to throw out objects that will be
+ // missed. Too bad!
+ smartlist_t *objects = smartlist_new();
+ consensus_cache_find_all(objects, cache, NULL, NULL);
+ smartlist_sort(objects, compare_by_staleness_);
+ int n_marked = 0;
+ SMARTLIST_FOREACH_BEGIN(objects, consensus_cache_entry_t *, ent) {
+ consensus_cache_entry_mark_for_removal(ent);
+ if (++n_marked >= n_to_remove)
+ break;
+ } SMARTLIST_FOREACH_END(ent);
+
+ consensus_cache_delete_pending(cache, 1);
+ if (BUG(n_marked < n_to_remove))
+ return -1;
+ else
+ return 0;
+}
+
+/**
* Set consensus cache flags on the objects in this consdiffmgr.
*/
static void
@@ -1066,6 +1145,8 @@ consensus_diff_worker_replyfn(void *work_)
/* Success! Store the results */
log_info(LD_DIRSERV, "Adding consensus diff from %s to %s",
lv_from_digest, lv_to_digest);
+
+ consdiffmgr_ensure_space_for_files(1);
consensus_cache_entry_t *ent =
consensus_cache_add(cdm_cache_get(), job->labels_out,
job->body_out,