Add configurable limit to ensure a minimum amount of free space is preserved

- default to 100MB of free space
- currently disabled on android due to missing sys/statvfs.h
This commit is contained in:
Jeremy Lakeman 2014-06-23 11:08:01 +09:30
parent 533c0be445
commit 2ef73884a1
4 changed files with 80 additions and 11 deletions

View File

@ -429,7 +429,8 @@ ATOM(bool_t, fetch, 1, boolean,, "If false, no new bundl
ATOM(bool_t, clean_on_open, 0, boolean,, "If true, Rhizome database is cleaned at start of every command")
ATOM(bool_t, clean_on_start, 1, boolean,, "If true, Rhizome database is cleaned at start of daemon")
STRING(256, datastore_path, "", str_nonempty,, "Path of rhizome storage directory, absolute or relative to instance directory")
ATOM(uint64_t, database_size, 0, uint64_scaled,, "Maximum size of database in bytes")
ATOM(uint64_t, database_size, UINT64_MAX, uint64_scaled,, "Maximum size of database in bytes")
ATOM(uint64_t, min_free_space, 100*1024*1024, uint64_scaled,, "Minimum free space to preserve on the disk")
ATOM(uint32_t, max_blob_size, 128 * 1024, uint32_scaled,, "Store payloads larger than this in files not SQLite blobs")
ATOM(uint64_t, rhizome_mdp_block_size, 512, uint64_scaled,, "Rhizome MDP block size.")

View File

@ -92,6 +92,8 @@ AC_CHECK_HEADERS(
sys/mman.h \
sys/time.h \
sys/ucred.h \
sys/statvfs.h \
sys/vfs.h \
poll.h \
netdb.h \
linux/ioctl.h \

View File

@ -19,6 +19,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <assert.h>
#ifdef HAVE_SYS_STATVFS_H
# include <sys/statvfs.h>
#endif
#include "serval.h"
#include "rhizome.h"
#include "conf.h"
@ -150,6 +153,43 @@ int rhizome_delete_file(const rhizome_filehash_t *hashp)
return rhizome_delete_file_id(alloca_tohex_rhizome_filehash_t(*hashp));
}
static uint64_t store_get_free_space()
{
const char *fake_space = getenv("SERVALD_FREE_SPACE");
if (fake_space)
return atol(fake_space);
#ifdef HAVE_SYS_STATVFS_H
char store_path[1024];
if (!FORMF_RHIZOME_STORE_PATH(store_path, "rhizome.db"))
return UINT64_MAX;
struct statvfs stats;
if (statvfs(store_path, &stats)==-1){
WARNF_perror("statvfs(%s)", store_path);
return UINT64_MAX;
}
return stats.f_bsize * stats.f_bfree;
#else
return UINT64_MAX;
#endif
}
static uint64_t store_space_limit(uint64_t current_size)
{
uint64_t limit = config.rhizome.database_size;
if (config.rhizome.min_free_space!=0){
uint64_t free_space = store_get_free_space();
if (free_space < config.rhizome.min_free_space){
if (current_size + free_space < config.rhizome.min_free_space)
limit = 0;
else
limit = current_size + free_space - config.rhizome.min_free_space;
}
}
return limit;
}
// TODO readonly version?
static enum rhizome_payload_status store_make_space(uint64_t bytes, struct rhizome_cleanup_report *report)
{
@ -157,12 +197,11 @@ static enum rhizome_payload_status store_make_space(uint64_t bytes, struct rhizo
uint64_t db_page_size;
uint64_t db_page_count;
uint64_t db_free_page_count;
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
// TODO limit based on free space?
// No limit?
if (config.rhizome.database_size==0)
if (config.rhizome.database_size==UINT64_MAX && config.rhizome.min_free_space==0)
return RHIZOME_PAYLOAD_STATUS_NEW;
// TODO index external_bytes calculation and/or cache result
@ -181,13 +220,10 @@ static enum rhizome_payload_status store_make_space(uint64_t bytes, struct rhizo
)
return WHY("Cannot measure database used bytes");
if (config.rhizome.database_size < db_page_size*10)
return WHYF("rhizome.database_size is too small to store anything");
const uint64_t limit = config.rhizome.database_size - db_page_size*4;
uint64_t db_used = external_bytes + db_page_size * (db_page_count - db_free_page_count);
const uint64_t limit = store_space_limit(db_used);
if (bytes >= limit){
if (bytes && bytes >= limit){
if (config.debug.rhizome)
DEBUGF("Not enough space for %"PRIu64". Used; %"PRIu64" = %"PRIu64" + %"PRIu64" * (%"PRIu64" - %"PRIu64"), Limit; %"PRIu64,
bytes, db_used, external_bytes, db_page_size, db_page_count, db_free_page_count, limit);
@ -223,7 +259,7 @@ static enum rhizome_payload_status store_make_space(uint64_t bytes, struct rhizo
DEBUGF("Considering dropping file %s, size %"PRId64" cost %"PRId64" vs %"PRId64" to add %"PRId64" new bytes",
id, length, cost, cost_existing, bytes);
// don't allow the new file, we've got more important things to store
if (cost < cost_existing)
if (bytes && cost < cost_existing)
break;
// drop the existing content and recalculate used space

View File

@ -1291,8 +1291,30 @@ setup_evictUninteresting() {
setup_rhizome
set_instance +A
executeOk_servald config set rhizome.database_size 1M
create_file file1 512K
create_file file2 256K
create_file file3 128K
create_file file4 128K
}
test_evictUninteresting(){
executeOk_servald rhizome add file $SIDA file1 file1.manifest
executeOk_servald rhizome add file $SIDA file2 file2.manifest
executeOk_servald rhizome add file $SIDA file3 file3.manifest
executeOk_servald rhizome add file $SIDA file4 file4.manifest
tfw_cat --stderr
rhizome_clean
assert [ $deleted_files = 0 ]
assert [ $deleted_fileblobs = 0 ]
assert [ $deleted_manifests = 1 ]
executeOk_servald rhizome list
assert_rhizome_list file{2,3,4}
}
doc_evictFreeSpace="Reduce database size due to insufficient free space"
setup_evictFreeSpace() {
setup_servald
setup_rhizome
set_instance +A
create_file file1 512K
create_file file2 256K
create_file file3 128K
@ -1301,9 +1323,17 @@ test_evictUninteresting(){
executeOk_servald rhizome add file $SIDA file2 file2.manifest
executeOk_servald rhizome add file $SIDA file3 file3.manifest
executeOk_servald rhizome add file $SIDA file4 file4.manifest
}
test_evictFreeSpace() {
executeOk_servald config \
set rhizome.min_free_space 1M
# only 640K free...
export SERVALD_FREE_SPACE=655360
rhizome_clean
assert [ $deleted_files = 0 ]
assert [ $deleted_fileblobs = 0 ]
assert [ $deleted_manifests = 1 ]
executeOk_servald rhizome list
assert_rhizome_list file{2,3,4}
}
runTests "$@"