vfs_mount: bugfix: choose newer version of a file if present in loose dir and archive
vfs_optimizer: add enable/disable logic for trace vfs_tree: add code to determine most recent file This was SVN commit r3562.
This commit is contained in:
parent
2aebdd1894
commit
78a5202e49
@ -94,16 +94,25 @@ char mount_get_type(const Mount* m)
|
||||
}
|
||||
|
||||
|
||||
bool mount_should_replace(const Mount* m_old, const Mount* m_new, bool files_are_identical)
|
||||
bool mount_should_replace(const Mount* m_old, const Mount* m_new,
|
||||
size_t size_old, size_t size_new, time_t mtime_old, time_t mtime_new)
|
||||
{
|
||||
// need to "replace" if not yet associated with a Mount
|
||||
// 1) "replace" if not yet associated with a Mount.
|
||||
if(!m_old)
|
||||
return true;
|
||||
|
||||
// keep old if new priority is lower.
|
||||
// 2) keep old if new priority is lower.
|
||||
if(m_new->pri < m_old->pri)
|
||||
return false;
|
||||
|
||||
// assume they're the same if size and last-modified time match.
|
||||
// note: FAT timestamp only has 2 second resolution
|
||||
const double mtime_diff = difftime(mtime_old, mtime_new);
|
||||
const bool identical = (size_old == size_new) &&
|
||||
fabs(mtime_diff) <= 2.0;
|
||||
|
||||
// 3) go with more efficient source (if files are identical)
|
||||
//
|
||||
// since priority is not less, we really ought to always go with m_new.
|
||||
// however, there is one special case we handle for performance reasons:
|
||||
// if the file contents are the same, prefer the more efficient source.
|
||||
@ -111,7 +120,12 @@ bool mount_should_replace(const Mount* m_old, const Mount* m_new, bool files_are
|
||||
// especially if set incorrectly.
|
||||
//
|
||||
// note: see MountType for explanation of type > type2.
|
||||
if(files_are_identical && m_old->type > m_new->type)
|
||||
if(identical && m_old->type > m_new->type)
|
||||
return false;
|
||||
|
||||
// 4) don't replace "old" file if modified more recently than "new".
|
||||
// (still provide for 2 sec. FAT tolerance - see above)
|
||||
if(mtime_diff > 2.0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -97,8 +97,8 @@ extern LibError x_unmap(XFile* xf);
|
||||
// accessor routines that obviate the need to access Mount fields directly:
|
||||
//
|
||||
|
||||
extern bool mount_should_replace(const Mount* m_old, const Mount* m_new,
|
||||
bool files_are_identical);
|
||||
bool mount_should_replace(const Mount* m_old, const Mount* m_new,
|
||||
size_t size_old, size_t size_new, time_t mtime_old, time_t mtime_new);
|
||||
|
||||
extern char mount_get_type(const Mount* m);
|
||||
|
||||
|
@ -23,11 +23,23 @@ void trace_shutdown()
|
||||
}
|
||||
|
||||
|
||||
static bool trace_enabled;
|
||||
// enabled by default. by the time we can decide whether a trace needs to
|
||||
// be generated (see should_rebuild_main_archive), file accesses will
|
||||
// already have occurred; hence default enabled and disable if not needed.
|
||||
static bool trace_enabled = true;
|
||||
static bool trace_force_enabled = false; // see below
|
||||
|
||||
// note: explicitly enabling trace means the user wants one to be
|
||||
// generated even if an up-to-date version exists.
|
||||
// (mechanism: ignore any attempts to disable)
|
||||
void trace_enable(bool want_enabled)
|
||||
{
|
||||
trace_enabled = want_enabled;
|
||||
|
||||
if(want_enabled)
|
||||
trace_force_enabled = true;
|
||||
if(trace_force_enabled)
|
||||
trace_enabled = true;
|
||||
}
|
||||
|
||||
|
||||
@ -76,6 +88,9 @@ void trace_clear()
|
||||
|
||||
LibError trace_write_to_file(const char* trace_filename)
|
||||
{
|
||||
if(!trace_enabled)
|
||||
return INFO_SKIPPED;
|
||||
|
||||
char N_fn[PATH_MAX];
|
||||
RETURN_ERR(file_make_full_native_path(trace_filename, N_fn));
|
||||
FILE* f = fopen(N_fn, "wt");
|
||||
@ -584,8 +599,6 @@ static void EntCb(const char* path, const DirEnt* ent, void* context)
|
||||
params->files.push_back(file_make_unique_fn_copy(path));
|
||||
}
|
||||
|
||||
|
||||
|
||||
LibError vfs_opt_rebuild_main_archive(const char* P_archive_path, const char* trace_filename)
|
||||
{
|
||||
// get list of all files
|
||||
@ -613,7 +626,6 @@ LibError vfs_opt_rebuild_main_archive(const char* P_archive_path, const char* tr
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -621,11 +633,21 @@ LibError vfs_opt_rebuild_main_archive(const char* P_archive_path, const char* tr
|
||||
// autobuild logic: decides when to (re)build an archive.
|
||||
//
|
||||
|
||||
static const size_t REBUILD_MAIN_ARCHIVE_THRESHOLD = 100;
|
||||
static const size_t BUILD_MINI_ARCHIVE_THRESHOLD = 30;
|
||||
static const size_t REBUILD_MAIN_ARCHIVE_THRESHOLD = 50;
|
||||
static const size_t BUILD_MINI_ARCHIVE_THRESHOLD = 20;
|
||||
|
||||
static bool should_rebuild_main_archive()
|
||||
static bool should_rebuild_main_archive(const char* P_archive_path,
|
||||
const char* trace_filename)
|
||||
{
|
||||
// if there's no trace file, no point in building a main archive.
|
||||
struct stat s;
|
||||
if(file_stat(trace_filename, &s) != ERR_OK)
|
||||
return false;
|
||||
// otherwise, if trace is up-to-date, stop recording a new one.
|
||||
const time_t vfs_mtime = tree_most_recent_mtime();
|
||||
if(s.st_mtime >= vfs_mtime)
|
||||
trace_enable(false);
|
||||
|
||||
if(loose_files.size() >= REBUILD_MAIN_ARCHIVE_THRESHOLD)
|
||||
return true;
|
||||
|
||||
@ -650,11 +672,9 @@ LibError vfs_opt_auto_build_archive(const char* P_dst_path,
|
||||
const char* main_archive_name, const char* trace_filename)
|
||||
{
|
||||
char P_archive_path[PATH_MAX];
|
||||
if(should_rebuild_main_archive())
|
||||
{
|
||||
RETURN_ERR(vfs_path_append(P_archive_path, P_dst_path, main_archive_name));
|
||||
if(should_rebuild_main_archive(P_archive_path, trace_filename))
|
||||
return vfs_opt_rebuild_main_archive(P_archive_path, trace_filename);
|
||||
}
|
||||
else if(should_build_mini_archive())
|
||||
{
|
||||
loose_files.push_back(0);
|
||||
|
@ -32,6 +32,18 @@
|
||||
|
||||
static void* node_alloc();
|
||||
|
||||
|
||||
// remembers which VFS file is the most recently modified.
|
||||
static time_t most_recent_mtime;
|
||||
static void set_most_recent_if_newer(time_t mtime)
|
||||
{
|
||||
most_recent_mtime = MAX(most_recent_mtime, mtime);
|
||||
}
|
||||
time_t tree_most_recent_mtime()
|
||||
{
|
||||
return most_recent_mtime;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// locking
|
||||
// these are exported to protect the vfs_mount list; apart from that, it is
|
||||
@ -459,12 +471,8 @@ LibError tree_add_file(TDir* td, const char* name,
|
||||
RETURN_ERR(ret);
|
||||
if(ret == INFO_ALREADY_PRESENT)
|
||||
{
|
||||
// assume they're the same if size and last-modified time match.
|
||||
// note: FAT timestamp only has 2 second resolution
|
||||
TFile* tf = (TFile*)node;
|
||||
const bool is_same = (tf->size == size) &&
|
||||
fabs(difftime(tf->mtime, mtime)) <= 2.0;
|
||||
if(!mount_should_replace(tf->m, m, is_same))
|
||||
if(!mount_should_replace(tf->m, m, tf->size, size, tf->mtime, mtime))
|
||||
return INFO_ALREADY_PRESENT;
|
||||
|
||||
stats_vfs_file_remove(tf->size);
|
||||
@ -476,6 +484,8 @@ LibError tree_add_file(TDir* td, const char* name,
|
||||
tf->size = size;
|
||||
tf->memento = memento;
|
||||
stats_vfs_file_add(size);
|
||||
|
||||
set_most_recent_if_newer(mtime);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,8 @@ extern void tree_display();
|
||||
// rebuilding VFS and on exit.
|
||||
extern void tree_clear();
|
||||
|
||||
extern time_t tree_most_recent_mtime();
|
||||
|
||||
// attempt to add <fn> to <dir>, storing its attributes.
|
||||
// overrides previously existing files of the same name if the new one
|
||||
// is more important, determined via priority and file location.
|
||||
|
Loading…
Reference in New Issue
Block a user