Merge pull request #2316 from schellap/rollfwd

Perform prerelease roll forward for FX and servicing
This commit is contained in:
Senthil 2016-04-06 20:21:15 -07:00
commit 76610c4cd4
11 changed files with 191 additions and 71 deletions

View file

@ -14,7 +14,8 @@ struct probe_config_t
{
pal::string_t probe_dir;
bool match_hash;
bool roll_forward;
bool patch_roll_fwd;
bool prerelease_roll_fwd;
const deps_json_t* probe_deps_json;
bool only_runtime_assets;
@ -22,60 +23,66 @@ struct probe_config_t
void print() const
{
trace::verbose(_X("probe_config_t: probe=[%s] match-hash=[%d] roll-forward=[%d] deps-json=[%p]"),
probe_dir.c_str(), match_hash, roll_forward, probe_deps_json);
trace::verbose(_X("probe_config_t: probe=[%s] match-hash=[%d] patch-roll-forward=[%d] prerelease-roll-forward=[%d] deps-json=[%p]"),
probe_dir.c_str(), match_hash, patch_roll_fwd, prerelease_roll_fwd, probe_deps_json);
}
bool is_roll_fwd_set() const
{
return patch_roll_fwd || prerelease_roll_fwd;
}
probe_config_t(
const pal::string_t& probe_dir,
bool match_hash,
bool roll_forward,
bool patch_roll_fwd,
bool prerelease_roll_fwd,
const deps_json_t* probe_deps_json,
bool only_serviceable_assets,
bool only_runtime_assets)
: probe_dir(probe_dir)
, match_hash(match_hash)
, roll_forward(roll_forward)
, patch_roll_fwd(patch_roll_fwd)
, prerelease_roll_fwd(prerelease_roll_fwd)
, probe_deps_json(probe_deps_json)
, only_serviceable_assets(only_serviceable_assets)
, only_runtime_assets(only_runtime_assets)
{
// Cannot roll forward and also match hash.
assert(!roll_forward || !match_hash);
assert(!is_roll_fwd_set() || !match_hash);
// Will not roll forward within a deps json.
assert(!roll_forward || probe_deps_json == nullptr);
assert(!is_roll_fwd_set() || probe_deps_json == nullptr);
// Will not do hash match when probing a deps json.
assert(!match_hash || probe_deps_json == nullptr);
}
static probe_config_t svc_ni(const pal::string_t dir, bool roll_fwd)
static probe_config_t svc_ni(const pal::string_t dir, bool patch_roll_fwd, bool prerelease_roll_fwd)
{
return probe_config_t(dir, false, roll_fwd, nullptr, true, true);
return probe_config_t(dir, false, patch_roll_fwd, prerelease_roll_fwd, nullptr, true, true);
}
static probe_config_t svc(const pal::string_t dir, bool roll_fwd)
static probe_config_t svc(const pal::string_t dir, bool patch_roll_fwd, bool prerelease_roll_fwd)
{
return probe_config_t(dir, false, roll_fwd, nullptr, true, false);
return probe_config_t(dir, false, patch_roll_fwd, prerelease_roll_fwd, nullptr, true, false);
}
static probe_config_t cache_ni(const pal::string_t dir)
{
return probe_config_t(dir, true, false, nullptr, false, true);
return probe_config_t(dir, true, false, false, nullptr, false, true);
}
static probe_config_t cache(const pal::string_t dir)
{
return probe_config_t(dir, true, false, nullptr, false, false);
return probe_config_t(dir, true, false, false, nullptr, false, false);
}
static probe_config_t fx(const pal::string_t dir, const deps_json_t* deps)
{
return probe_config_t(dir, false, false, deps, false, false);
return probe_config_t(dir, false, false, false, deps, false, false);
}
static probe_config_t additional(const pal::string_t dir, bool roll_fwd)
static probe_config_t additional(const pal::string_t dir, bool patch_roll_fwd, bool prerelease_roll_fwd)
{
return probe_config_t(dir, false, roll_fwd, nullptr, false, false);
return probe_config_t(dir, false, patch_roll_fwd, prerelease_roll_fwd, nullptr, false, false);
}
};

View file

@ -124,6 +124,8 @@ void deps_resolver_t::get_dir_assemblies(
bool deps_resolver_t::try_roll_forward(const deps_entry_t& entry,
const pal::string_t& probe_dir,
bool patch_roll_fwd,
bool prerelease_roll_fwd,
pal::string_t* candidate)
{
trace::verbose(_X("Attempting a roll forward for [%s/%s/%s] in [%s]"), entry.library_name.c_str(), entry.library_version.c_str(), entry.relative_path.c_str(), probe_dir.c_str());
@ -136,29 +138,46 @@ bool deps_resolver_t::try_roll_forward(const deps_entry_t& entry,
trace::verbose(_X("No roll forward as specified version [%s] could not be parsed"), lib_ver.c_str());
return false;
}
// Extract glob string of the form: 1.0.* from the version 1.0.0-prerelease-00001.
size_t pat_start = lib_ver.find(_X('.'), lib_ver.find(_X('.')) + 1);
pal::string_t maj_min_star = lib_ver.substr(0, pat_start + 1) + _X('*');
pal::string_t path = probe_dir;
append_path(&path, entry.library_name.c_str());
pal::string_t cache_key = path;
append_path(&cache_key, maj_min_star.c_str());
pal::string_t max_str;
if (m_roll_forward_cache.count(cache_key))
pal::string_t max_str = lib_ver;
if (cur_ver.is_prerelease() && prerelease_roll_fwd)
{
max_str = m_roll_forward_cache[cache_key];
trace::verbose(_X("Found cached roll forward version [%s] -> [%s]"), lib_ver.c_str(), max_str.c_str());
}
else
{
try_patch_roll_forward_in_dir(path, cur_ver, &max_str, true);
m_roll_forward_cache[cache_key] = max_str;
}
pal::string_t maj_min_pat_star = cur_ver.prerelease_glob();
pal::string_t cache_key = path;
append_path(&cache_key, maj_min_pat_star.c_str());
if (m_prerelease_roll_forward_cache.count(cache_key))
{
max_str = m_prerelease_roll_forward_cache[cache_key];
trace::verbose(_X("Found cached roll forward version [%s] -> [%s]"), lib_ver.c_str(), max_str.c_str());
}
else
{
try_prerelease_roll_forward_in_dir(path, cur_ver, &max_str);
m_prerelease_roll_forward_cache[cache_key] = max_str;
}
}
if (!cur_ver.is_prerelease() && patch_roll_fwd)
{
// Extract glob string of the form: 1.0.* from the version 1.0.0-prerelease-00001.
pal::string_t maj_min_star = cur_ver.patch_glob();
pal::string_t cache_key = path;
append_path(&cache_key, maj_min_star.c_str());
if (m_patch_roll_forward_cache.count(cache_key))
{
max_str = m_patch_roll_forward_cache[cache_key];
trace::verbose(_X("Found cached roll forward version [%s] -> [%s]"), lib_ver.c_str(), max_str.c_str());
}
else
{
try_patch_roll_forward_in_dir(path, cur_ver, &max_str);
m_patch_roll_forward_cache[cache_key] = max_str;
}
}
append_path(&path, max_str.c_str());
return entry.to_rel_path(path, candidate);
@ -176,11 +195,11 @@ void deps_resolver_t::setup_probe_config(
if (pal::directory_exists(ext_ni))
{
// Servicing NI probe.
m_probes.push_back(probe_config_t::svc_ni(ext_ni, config.get_fx_roll_fwd()));
m_probes.push_back(probe_config_t::svc_ni(ext_ni, config.get_patch_roll_fwd(), config.get_prerelease_roll_fwd()));
}
// Servicing normal probe.
m_probes.push_back(probe_config_t::svc(args.dotnet_extensions, config.get_fx_roll_fwd()));
m_probes.push_back(probe_config_t::svc(args.dotnet_extensions, config.get_patch_roll_fwd(), config.get_prerelease_roll_fwd()));
}
if (pal::directory_exists(args.dotnet_packages_cache))
@ -206,8 +225,9 @@ void deps_resolver_t::setup_probe_config(
for (const auto& probe : m_additional_probes)
{
// Additional paths
bool roll_fwd = config.get_fx_roll_fwd();
m_probes.push_back(probe_config_t::additional(probe, roll_fwd));
bool patch_roll_fwd = config.get_patch_roll_fwd();
bool prerelease_roll_fwd = config.get_prerelease_roll_fwd();
m_probes.push_back(probe_config_t::additional(probe, patch_roll_fwd, prerelease_roll_fwd));
}
if (trace::is_enabled())
@ -259,7 +279,7 @@ bool deps_resolver_t::probe_entry_in_configs(const deps_entry_t& entry, pal::str
{
if (entry.to_hash_matched_path(probe_dir, candidate))
{
assert(!config.roll_forward);
assert(!config.is_roll_fwd_set());
trace::verbose(_X(" Matched hash for [%s]"), candidate->c_str());
return true;
}
@ -276,7 +296,7 @@ bool deps_resolver_t::probe_entry_in_configs(const deps_entry_t& entry, pal::str
}
trace::verbose(_X(" Skipping... probe in deps json failed"));
}
else if (!config.roll_forward)
else if (!config.is_roll_fwd_set())
{
if (entry.to_full_path(probe_dir, candidate))
{
@ -285,9 +305,9 @@ bool deps_resolver_t::probe_entry_in_configs(const deps_entry_t& entry, pal::str
}
trace::verbose(_X(" Skipping... not found in probe dir"));
}
else if (config.roll_forward)
else if (config.is_roll_fwd_set())
{
if (try_roll_forward(entry, probe_dir, candidate))
if (try_roll_forward(entry, probe_dir, config.patch_roll_fwd, config.prerelease_roll_fwd, candidate))
{
trace::verbose(_X(" Specified roll forward; matched [%s]"), candidate->c_str());
return true;

View file

@ -117,6 +117,8 @@ private:
bool try_roll_forward(
const deps_entry_t& entry,
const pal::string_t& probe_dir,
bool patch_roll_fwd,
bool prerelease_roll_fwd,
pal::string_t* candidate);
// Framework deps file.
@ -130,7 +132,8 @@ private:
dir_assemblies_t m_local_assemblies;
dir_assemblies_t m_fx_assemblies;
std::unordered_map<pal::string_t, pal::string_t> m_roll_forward_cache;
std::unordered_map<pal::string_t, pal::string_t> m_patch_roll_forward_cache;
std::unordered_map<pal::string_t, pal::string_t> m_prerelease_roll_forward_cache;
pal::string_t m_package_cache;

View file

@ -19,7 +19,7 @@ pal::string_t fx_muxer_t::resolve_fx_dir(const pal::string_t& muxer_dir, runtime
trace::verbose(_X("--- Resolving FX directory from muxer dir [%s]"), muxer_dir.c_str());
const auto fx_name = runtime->get_fx_name();
const auto fx_ver = runtime->get_fx_version();
const auto roll_fwd = runtime->get_fx_roll_fwd();
const auto patch_roll_fwd = runtime->get_patch_roll_fwd();
fx_ver_t specified(-1, -1, -1);
if (!fx_ver_t::parse(fx_ver, &specified, false))
@ -32,16 +32,16 @@ pal::string_t fx_muxer_t::resolve_fx_dir(const pal::string_t& muxer_dir, runtime
append_path(&fx_dir, _X("shared"));
append_path(&fx_dir, fx_name.c_str());
// If not roll forward or if pre-release, just return.
if (!roll_fwd || specified.is_prerelease())
// If production and no roll forward use given version.
// For prerelease, we will always roll forward.
if (!specified.is_prerelease() && !patch_roll_fwd)
{
trace::verbose(_X("Did not roll forward because rollfwd=%d and [%s] is prerelease=%d"),
roll_fwd, fx_ver.c_str(), specified.is_prerelease());
trace::verbose(_X("Did not roll forward because patch_roll_fwd=%d, chose [%s]"), patch_roll_fwd, fx_ver.c_str());
append_path(&fx_dir, fx_ver.c_str());
}
else
{
trace::verbose(_X("Attempting production FX roll forward starting from [%s]"), fx_ver.c_str());
trace::verbose(_X("Attempting FX roll forward starting from [%s]"), fx_ver.c_str());
std::vector<pal::string_t> list;
pal::readdir(fx_dir, &list);
@ -50,11 +50,19 @@ pal::string_t fx_muxer_t::resolve_fx_dir(const pal::string_t& muxer_dir, runtime
{
trace::verbose(_X("Inspecting version... [%s]"), version.c_str());
fx_ver_t ver(-1, -1, -1);
if (fx_ver_t::parse(version, &ver, true) &&
if (!specified.is_prerelease() && fx_ver_t::parse(version, &ver, true) && // true -- only prod. prevents roll forward to prerelease.
ver.get_major() == max_specified.get_major() &&
ver.get_minor() == max_specified.get_minor())
{
max_specified.set_patch(std::max(ver.get_patch(), max_specified.get_patch()));
max_specified = std::max(ver, max_specified);
}
if (specified.is_prerelease() && fx_ver_t::parse(version, &ver, false) && // false -- implies both production and prerelease.
ver.is_prerelease() && // prevent roll forward to production.
ver.get_major() == max_specified.get_major() &&
ver.get_minor() == max_specified.get_minor() &&
ver.get_patch() == max_specified.get_patch())
{
max_specified = std::max(ver, max_specified);
}
}
pal::string_t max_specified_str = max_specified.as_str();

View file

@ -59,6 +59,20 @@ pal::string_t fx_ver_t::as_str() const
return stream.str();
}
pal::string_t fx_ver_t::prerelease_glob() const
{
pal::stringstream_t stream;
stream << m_major << _X(".") << m_minor << _X(".") << m_patch << _X("-*");
return stream.str();
}
pal::string_t fx_ver_t::patch_glob() const
{
pal::stringstream_t stream;
stream << m_major << _X(".") << m_minor << _X(".*");
return stream.str();
}
/* static */
int fx_ver_t::compare(const fx_ver_t&a, const fx_ver_t& b)
{

View file

@ -25,6 +25,8 @@ struct fx_ver_t
bool is_prerelease() const { return !m_pre.empty(); }
pal::string_t as_str() const;
pal::string_t prerelease_glob() const;
pal::string_t patch_glob() const;
bool operator ==(const fx_ver_t& b) const;
bool operator !=(const fx_ver_t& b) const;

View file

@ -105,7 +105,15 @@ bool hostpolicy_exists_in_svc(pal::string_t* resolved_dir)
append_path(&path, _STRINGIFY(HOST_POLICY_PKG_NAME));
pal::string_t max_ver;
try_patch_roll_forward_in_dir(path, lib_ver, &max_ver, false);
if (lib_ver.is_prerelease())
{
try_prerelease_roll_forward_in_dir(path, lib_ver, &max_ver);
}
else
{
try_patch_roll_forward_in_dir(path, lib_ver, &max_ver);
}
append_path(&path, max_ver.c_str());
append_path(&path, rel_dir.c_str());

View file

@ -61,17 +61,17 @@ host_mode_t detect_operating_mode(const int argc, const pal::char_t* argv[], pal
}
}
void try_patch_roll_forward_in_dir(const pal::string_t& cur_dir, const fx_ver_t& start_ver, pal::string_t* max_str, bool only_production)
void try_patch_roll_forward_in_dir(const pal::string_t& cur_dir, const fx_ver_t& start_ver, pal::string_t* max_str)
{
pal::string_t path = cur_dir;
if (trace::is_enabled())
{
pal::string_t start_str = start_ver.as_str();
trace::verbose(_X("Reading roll forward candidates in dir [%s] for version [%s]"), path.c_str(), start_str.c_str());
trace::verbose(_X("Reading patch roll forward candidates in dir [%s] for version [%s]"), path.c_str(), start_str.c_str());
}
pal::string_t maj_min_star = pal::to_string(start_ver.get_major()) + _X(".") + pal::to_string(start_ver.get_minor()) + _X("*");
pal::string_t maj_min_star = start_ver.patch_glob();
std::vector<pal::string_t> list;
pal::readdir(path, maj_min_star, &list);
@ -80,8 +80,8 @@ void try_patch_roll_forward_in_dir(const pal::string_t& cur_dir, const fx_ver_t&
fx_ver_t ver(-1, -1, -1);
for (const auto& str : list)
{
trace::verbose(_X("Considering roll forward candidate version [%s]"), str.c_str());
if (fx_ver_t::parse(str, &ver, only_production))
trace::verbose(_X("Considering patch roll forward candidate version [%s]"), str.c_str());
if (fx_ver_t::parse(str, &ver, true))
{
max_ver = std::max(ver, max_ver);
}
@ -91,6 +91,42 @@ void try_patch_roll_forward_in_dir(const pal::string_t& cur_dir, const fx_ver_t&
if (trace::is_enabled())
{
pal::string_t start_str = start_ver.as_str();
trace::verbose(_X("Roll forwarded [%s] -> [%s] in [%s]"), start_str.c_str(), max_str->c_str(), path.c_str());
trace::verbose(_X("Patch roll forwarded [%s] -> [%s] in [%s]"), start_str.c_str(), max_str->c_str(), path.c_str());
}
}
void try_prerelease_roll_forward_in_dir(const pal::string_t& cur_dir, const fx_ver_t& start_ver, pal::string_t* max_str)
{
pal::string_t path = cur_dir;
if (trace::is_enabled())
{
pal::string_t start_str = start_ver.as_str();
trace::verbose(_X("Reading prerelease roll forward candidates in dir [%s] for version [%s]"), path.c_str(), start_str.c_str());
}
pal::string_t maj_min_pat_star = start_ver.prerelease_glob();
std::vector<pal::string_t> list;
pal::readdir(path, maj_min_pat_star, &list);
fx_ver_t max_ver = start_ver;
fx_ver_t ver(-1, -1, -1);
for (const auto& str : list)
{
trace::verbose(_X("Considering prerelease roll forward candidate version [%s]"), str.c_str());
if (fx_ver_t::parse(str, &ver, false)
&& ver.is_prerelease()) // Pre-release can roll forward to only pre-release
{
max_ver = std::max(ver, max_ver);
}
}
max_str->assign(max_ver.as_str());
if (trace::is_enabled())
{
pal::string_t start_str = start_ver.as_str();
trace::verbose(_X("Prerelease roll forwarded [%s] -> [%s] in [%s]"), start_str.c_str(), max_str->c_str(), path.c_str());
}
}

View file

@ -25,7 +25,7 @@ class corehost_init_t
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
public:
static const int s_version = 0x8002;
static const int s_version = 0x8003;
private:
int m_version;
std::vector<pal::string_t> m_probe_paths;
@ -83,6 +83,7 @@ public:
pal::string_t get_runtime_config_from_file(const pal::string_t& file, pal::string_t* dev_config_file);
host_mode_t detect_operating_mode(const int argc, const pal::char_t* argv[], pal::string_t* own_dir = nullptr);
void try_patch_roll_forward_in_dir(const pal::string_t& cur_dir, const fx_ver_t& start_ver, pal::string_t* max_str, bool only_production);
void try_patch_roll_forward_in_dir(const pal::string_t& cur_dir, const fx_ver_t& start_ver, pal::string_t* max_str);
void try_prerelease_roll_forward_in_dir(const pal::string_t& cur_dir, const fx_ver_t& start_ver, pal::string_t* max_str);
#endif // __LIBHOST_H__
#endif // __LIBHOST_H__

View file

@ -9,7 +9,8 @@
#include <cassert>
runtime_config_t::runtime_config_t(const pal::string_t& path, const pal::string_t& dev_path)
: m_fx_roll_fwd(true)
: m_patch_roll_fwd(true)
, m_prerelease_roll_fwd(false)
, m_path(path)
, m_dev_path(dev_path)
, m_portable(false)
@ -58,10 +59,16 @@ bool runtime_config_t::parse_opts(const json_value& opts)
}
}
auto roll_fwd = opts_obj.find(_X("applyPatches"));
if (roll_fwd != opts_obj.end())
auto patch_roll_fwd = opts_obj.find(_X("applyPatches"));
if (patch_roll_fwd != opts_obj.end())
{
m_fx_roll_fwd = roll_fwd->second.as_bool();
m_patch_roll_fwd = patch_roll_fwd->second.as_bool();
}
auto prerelease_roll_fwd = opts_obj.find(_X("preReleaseRollForward"));
if (prerelease_roll_fwd != opts_obj.end())
{
m_prerelease_roll_fwd = prerelease_roll_fwd->second.as_bool();
}
auto framework = opts_obj.find(_X("framework"));
@ -90,7 +97,7 @@ bool runtime_config_t::ensure_dev_config_parsed()
}
// Set dev mode default values, if the file exists.
m_fx_roll_fwd = false;
m_patch_roll_fwd = false;
pal::ifstream_t file(m_dev_path);
if (!file.good())
@ -120,6 +127,7 @@ bool runtime_config_t::ensure_dev_config_parsed()
trace::error(_X("A JSON parsing exception occurred in [%s]: %s"), m_dev_path.c_str(), jes.c_str());
return false;
}
return true;
}
@ -181,10 +189,16 @@ const pal::string_t& runtime_config_t::get_fx_version() const
return m_fx_ver;
}
bool runtime_config_t::get_fx_roll_fwd() const
bool runtime_config_t::get_patch_roll_fwd() const
{
assert(m_valid);
return m_fx_roll_fwd;
return m_patch_roll_fwd;
}
bool runtime_config_t::get_prerelease_roll_fwd() const
{
assert(m_valid);
return m_prerelease_roll_fwd;
}
bool runtime_config_t::get_portable() const

View file

@ -10,6 +10,11 @@ typedef web::json::value json_value;
class runtime_config_t
{
// // WARNING // WARNING // WARNING // WARNING // WARNING // WARNING //
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// !! If you change this class layout increment the !!
// !! corehost_init_t::s_version field; !!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
public:
runtime_config_t(const pal::string_t& path, const pal::string_t& dev_path);
bool is_valid() { return m_valid; }
@ -19,7 +24,8 @@ public:
const pal::string_t& get_fx_version() const;
const pal::string_t& get_fx_name() const;
const std::list<pal::string_t>& get_probe_paths() const;
bool get_fx_roll_fwd() const;
bool get_patch_roll_fwd() const;
bool get_prerelease_roll_fwd() const;
bool get_portable() const;
bool parse_opts(const json_value& opts);
void config_kv(std::vector<std::string>*, std::vector<std::string>*) const;
@ -34,7 +40,8 @@ private:
std::list<pal::string_t> m_probe_paths;
pal::string_t m_fx_name;
pal::string_t m_fx_ver;
bool m_fx_roll_fwd;
bool m_patch_roll_fwd;
bool m_prerelease_roll_fwd;
pal::string_t m_dev_path;
pal::string_t m_path;