mirror of
https://github.com/fish-shell/fish-shell.git
synced 2024-11-24 19:51:00 +08:00
Reset autoloads in response to variable changes
Prior to this fix, autoloads like function and completion autoloads would check their path variable (like fish_function_path) on every autoload request. Switch to invalidating it in response to the variable changing. This improves time on a microbenchmark: for i in (seq 50000) setenv test_env val$i end from ~11 seconds to ~6.5 seconds.
This commit is contained in:
parent
be13ac353b
commit
9cd952588f
|
@ -65,19 +65,10 @@ int autoload_t::load(const wcstring &cmd, bool reload) {
|
||||||
CHECK_BLOCK(0);
|
CHECK_BLOCK(0);
|
||||||
ASSERT_IS_MAIN_THREAD();
|
ASSERT_IS_MAIN_THREAD();
|
||||||
|
|
||||||
auto path_var = env_get(env_var_name);
|
if (!this->paths) {
|
||||||
|
auto path_var = env_get(env_var_name);
|
||||||
// Do we know where to look?
|
if (path_var.missing_or_empty()) return 0;
|
||||||
if (path_var.missing_or_empty()) return 0;
|
this->paths = path_var->as_list();
|
||||||
|
|
||||||
// Check if the lookup path has changed. If so, drop all loaded files.
|
|
||||||
if (*path_var != this->last_path) {
|
|
||||||
this->last_path = *path_var;
|
|
||||||
this->last_path_tokenized.clear();
|
|
||||||
this->last_path.to_list(this->last_path_tokenized);
|
|
||||||
|
|
||||||
scoped_lock locker(lock);
|
|
||||||
this->evict_all_nodes();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark that we're loading this. Hang onto the iterator for fast erasing later. Note that
|
// Mark that we're loading this. Hang onto the iterator for fast erasing later. Note that
|
||||||
|
@ -98,7 +89,8 @@ int autoload_t::load(const wcstring &cmd, bool reload) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
// Try loading it.
|
// Try loading it.
|
||||||
res = this->locate_file_and_maybe_load_it(cmd, true, reload, this->last_path_tokenized);
|
assert(paths && "Should have paths");
|
||||||
|
res = this->locate_file_and_maybe_load_it(cmd, true, reload, *this->paths);
|
||||||
// Clean up.
|
// Clean up.
|
||||||
is_loading_set.erase(where);
|
is_loading_set.erase(where);
|
||||||
return res;
|
return res;
|
||||||
|
@ -113,6 +105,13 @@ bool autoload_t::can_load(const wcstring &cmd, const env_vars_snapshot_t &vars)
|
||||||
return this->locate_file_and_maybe_load_it(cmd, false, false, path_list);
|
return this->locate_file_and_maybe_load_it(cmd, false, false, path_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void autoload_t::invalidate() {
|
||||||
|
ASSERT_IS_MAIN_THREAD();
|
||||||
|
scoped_lock locker(lock);
|
||||||
|
paths.reset();
|
||||||
|
this->evict_all_nodes();
|
||||||
|
}
|
||||||
|
|
||||||
/// Check whether the given command is loaded.
|
/// Check whether the given command is loaded.
|
||||||
bool autoload_t::has_tried_loading(const wcstring &cmd) {
|
bool autoload_t::has_tried_loading(const wcstring &cmd) {
|
||||||
scoped_lock locker(lock);
|
scoped_lock locker(lock);
|
||||||
|
|
|
@ -49,10 +49,8 @@ class autoload_t : public lru_cache_t<autoload_t, autoload_function_t> {
|
||||||
fish_mutex_t lock;
|
fish_mutex_t lock;
|
||||||
/// The environment variable name.
|
/// The environment variable name.
|
||||||
const wcstring env_var_name;
|
const wcstring env_var_name;
|
||||||
/// The path from which we most recently autoloaded.
|
/// The paths from which to autoload, or missing if none.
|
||||||
env_var_t last_path;
|
maybe_t<wcstring_list_t> paths;
|
||||||
/// the most reecently autoloaded path, tokenized (split on separators).
|
|
||||||
wcstring_list_t last_path_tokenized;
|
|
||||||
/// A table containing all the files that are currently being loaded.
|
/// A table containing all the files that are currently being loaded.
|
||||||
/// This is here to help prevent recursion.
|
/// This is here to help prevent recursion.
|
||||||
std::unordered_set<wcstring> is_loading_set;
|
std::unordered_set<wcstring> is_loading_set;
|
||||||
|
@ -91,5 +89,8 @@ class autoload_t : public lru_cache_t<autoload_t, autoload_function_t> {
|
||||||
|
|
||||||
/// Check whether the given command could be loaded, but do not load it.
|
/// Check whether the given command could be loaded, but do not load it.
|
||||||
bool can_load(const wcstring &cmd, const env_vars_snapshot_t &vars);
|
bool can_load(const wcstring &cmd, const env_vars_snapshot_t &vars);
|
||||||
|
|
||||||
|
/// Invalidates all entries. Uesd when the underlying path variable changes.
|
||||||
|
void invalidate();
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1558,6 +1558,8 @@ wcstring complete_print() {
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void complete_invalidate_path() { completion_autoloader.invalidate(); }
|
||||||
|
|
||||||
/// Completion "wrapper" support. The map goes from wrapping-command to wrapped-command-list.
|
/// Completion "wrapper" support. The map goes from wrapping-command to wrapped-command-list.
|
||||||
static fish_mutex_t wrapper_lock;
|
static fish_mutex_t wrapper_lock;
|
||||||
typedef std::unordered_map<wcstring, wcstring_list_t> wrapper_map_t;
|
typedef std::unordered_map<wcstring, wcstring_list_t> wrapper_map_t;
|
||||||
|
|
|
@ -193,4 +193,7 @@ wcstring_list_t complete_get_wrap_chain(const wcstring &command);
|
||||||
// Wonky interface: returns all wraps. Even-values are the commands, odd values are the targets.
|
// Wonky interface: returns all wraps. Even-values are the commands, odd values are the targets.
|
||||||
wcstring_list_t complete_get_wrap_pairs();
|
wcstring_list_t complete_get_wrap_pairs();
|
||||||
|
|
||||||
|
// Observes that fish_complete_path has changed.
|
||||||
|
void complete_invalidate_path();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
16
src/env.cpp
16
src/env.cpp
|
@ -40,12 +40,14 @@
|
||||||
|
|
||||||
#include "builtin_bind.h"
|
#include "builtin_bind.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "complete.h"
|
||||||
#include "env.h"
|
#include "env.h"
|
||||||
#include "env_universal_common.h"
|
#include "env_universal_common.h"
|
||||||
#include "event.h"
|
#include "event.h"
|
||||||
#include "expand.h"
|
#include "expand.h"
|
||||||
#include "fallback.h" // IWYU pragma: keep
|
#include "fallback.h" // IWYU pragma: keep
|
||||||
#include "fish_version.h"
|
#include "fish_version.h"
|
||||||
|
#include "function.h"
|
||||||
#include "history.h"
|
#include "history.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "input_common.h"
|
#include "input_common.h"
|
||||||
|
@ -814,6 +816,18 @@ static void handle_fish_history_change(const wcstring &op, const wcstring &var_n
|
||||||
reader_change_history(history_session_id().c_str());
|
reader_change_history(history_session_id().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_function_path_change(const wcstring &op, const wcstring &var_name) {
|
||||||
|
UNUSED(op);
|
||||||
|
UNUSED(var_name);
|
||||||
|
function_invalidate_path();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_complete_path_change(const wcstring &op, const wcstring &var_name) {
|
||||||
|
UNUSED(op);
|
||||||
|
UNUSED(var_name);
|
||||||
|
complete_invalidate_path();
|
||||||
|
}
|
||||||
|
|
||||||
static void handle_tz_change(const wcstring &op, const wcstring &var_name) {
|
static void handle_tz_change(const wcstring &op, const wcstring &var_name) {
|
||||||
UNUSED(op);
|
UNUSED(op);
|
||||||
handle_timezone(var_name.c_str());
|
handle_timezone(var_name.c_str());
|
||||||
|
@ -856,6 +870,8 @@ static void setup_var_dispatch_table() {
|
||||||
var_dispatch_table.emplace(L"fish_escape_delay_ms", handle_escape_delay_change);
|
var_dispatch_table.emplace(L"fish_escape_delay_ms", handle_escape_delay_change);
|
||||||
var_dispatch_table.emplace(L"LINES", handle_term_size_change);
|
var_dispatch_table.emplace(L"LINES", handle_term_size_change);
|
||||||
var_dispatch_table.emplace(L"COLUMNS", handle_term_size_change);
|
var_dispatch_table.emplace(L"COLUMNS", handle_term_size_change);
|
||||||
|
var_dispatch_table.emplace(L"fish_complete_path", handle_complete_path_change);
|
||||||
|
var_dispatch_table.emplace(L"fish_function_path", handle_function_path_change);
|
||||||
var_dispatch_table.emplace(L"fish_read_limit", handle_read_limit_change);
|
var_dispatch_table.emplace(L"fish_read_limit", handle_read_limit_change);
|
||||||
var_dispatch_table.emplace(L"fish_history", handle_fish_history_change);
|
var_dispatch_table.emplace(L"fish_history", handle_fish_history_change);
|
||||||
var_dispatch_table.emplace(L"TZ", handle_tz_change);
|
var_dispatch_table.emplace(L"TZ", handle_tz_change);
|
||||||
|
|
|
@ -339,6 +339,8 @@ int function_get_definition_lineno(const wcstring &name) {
|
||||||
return 1 + std::count(source.begin(), source.begin() + func_start, L'\n');
|
return 1 + std::count(source.begin(), source.begin() + func_start, L'\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void function_invalidate_path() { function_autoloader.invalidate(); }
|
||||||
|
|
||||||
// Setup the environment for the function. There are three components of the environment:
|
// Setup the environment for the function. There are three components of the environment:
|
||||||
// 1. argv
|
// 1. argv
|
||||||
// 2. named arguments
|
// 2. named arguments
|
||||||
|
|
|
@ -108,9 +108,11 @@ std::map<wcstring, env_var_t> function_get_inherit_vars(const wcstring &name);
|
||||||
/// is successful.
|
/// is successful.
|
||||||
bool function_copy(const wcstring &name, const wcstring &new_name);
|
bool function_copy(const wcstring &name, const wcstring &new_name);
|
||||||
|
|
||||||
|
|
||||||
/// Prepares the environment for executing a function.
|
/// Prepares the environment for executing a function.
|
||||||
void function_prepare_environment(const wcstring &name, const wchar_t *const *argv,
|
void function_prepare_environment(const wcstring &name, const wchar_t *const *argv,
|
||||||
const std::map<wcstring, env_var_t> &inherited_vars);
|
const std::map<wcstring, env_var_t> &inherited_vars);
|
||||||
|
|
||||||
|
/// Observes that fish_function_path has changed.
|
||||||
|
void function_invalidate_path();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue
Block a user