mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-06-15 08:23:00 +00:00
Add partial cache generation when only one of the vendros is changed to speed up recalculation time
This commit is contained in:
@@ -2196,45 +2196,59 @@ std::pair<PresetsConfigSubstitutions, std::string> PresetBundle::load_system_pre
|
||||
dir = (boost::filesystem::path(data_dir())).make_preferred();
|
||||
|
||||
// Try loading from binary cache first (skips JSON parsing on cache hit).
|
||||
// partial_dirty_vendors is non-empty when some vendors changed but others are still cached.
|
||||
std::set<std::string> partial_dirty_vendors;
|
||||
if (!validation_mode) {
|
||||
const auto t0 = std::chrono::steady_clock::now();
|
||||
PresetBundleCache::SystemPresetsCache cache;
|
||||
const std::string cache_file = PresetBundleCache::SystemPresetsCache::cache_path();
|
||||
if (cache.load(cache_file) && cache.is_valid(dir.string())) {
|
||||
cache.apply(*this);
|
||||
update_system_maps();
|
||||
const auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now() - t0).count();
|
||||
BOOST_LOG_TRIVIAL(info) << "PresetBundle: system presets loaded from cache in " << ms << " ms";
|
||||
return {PresetsConfigSubstitutions{}, ""};
|
||||
}
|
||||
|
||||
// Try bundled cache shipped with the installer (first launch, before user cache exists).
|
||||
// Validates against resources/profiles/ — the same directory it was generated from in CI.
|
||||
{
|
||||
const std::string bundled_dir =
|
||||
(boost::filesystem::path(resources_dir()) / "profiles").make_preferred().string();
|
||||
PresetBundleCache::SystemPresetsCache bundled;
|
||||
if (bundled.load(PresetBundleCache::SystemPresetsCache::bundled_cache_path()) &&
|
||||
bundled.is_valid(bundled_dir)) {
|
||||
bundled.apply(*this);
|
||||
update_system_maps();
|
||||
// Promote to user cache so subsequent launches skip this check.
|
||||
bundled.save(cache_file);
|
||||
const auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now() - t0).count();
|
||||
BOOST_LOG_TRIVIAL(info) << "PresetBundle: system presets loaded from bundled cache in " << ms << " ms";
|
||||
return {PresetsConfigSubstitutions{}, ""};
|
||||
if (cache.load(cache_file)) {
|
||||
std::set<std::string> dirty;
|
||||
if (cache.get_dirty_vendors(dir.string(), dirty)) {
|
||||
if (dirty.empty()) {
|
||||
// Full hit — every vendor is unchanged.
|
||||
cache.apply(*this);
|
||||
update_system_maps();
|
||||
const auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now() - t0).count();
|
||||
BOOST_LOG_TRIVIAL(info) << "PresetBundle: system presets loaded from cache in " << ms << " ms";
|
||||
return {PresetsConfigSubstitutions{}, ""};
|
||||
}
|
||||
// Partial hit — restore clean vendors from cache, re-parse only dirty ones.
|
||||
BOOST_LOG_TRIVIAL(info) << "PresetBundle: partial cache hit, " << dirty.size()
|
||||
<< " vendor(s) changed — re-parsing those only";
|
||||
cache.apply_partial(*this, dirty);
|
||||
partial_dirty_vendors = std::move(dirty);
|
||||
}
|
||||
// else: structural mismatch (format version or option count changed) → full re-parse.
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " cache miss, falling back to JSON load";
|
||||
if (partial_dirty_vendors.empty()) {
|
||||
// No partial hit — try bundled cache shipped with the installer (first launch).
|
||||
{
|
||||
const std::string bundled_dir =
|
||||
(boost::filesystem::path(resources_dir()) / "profiles").make_preferred().string();
|
||||
PresetBundleCache::SystemPresetsCache bundled;
|
||||
if (bundled.load(PresetBundleCache::SystemPresetsCache::bundled_cache_path()) &&
|
||||
bundled.is_valid(bundled_dir)) {
|
||||
bundled.apply(*this);
|
||||
update_system_maps();
|
||||
// Promote to user cache so subsequent launches skip this check.
|
||||
bundled.save(cache_file);
|
||||
const auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now() - t0).count();
|
||||
BOOST_LOG_TRIVIAL(info) << "PresetBundle: system presets loaded from bundled cache in " << ms << " ms";
|
||||
return {PresetsConfigSubstitutions{}, ""};
|
||||
}
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " cache miss, falling back to JSON load";
|
||||
}
|
||||
}
|
||||
|
||||
const auto json_load_t0 = std::chrono::steady_clock::now();
|
||||
PresetsConfigSubstitutions substitutions;
|
||||
std::string errors_cummulative;
|
||||
bool first = true;
|
||||
bool first = partial_dirty_vendors.empty(); // false in partial mode: clean vendors already applied
|
||||
std::vector<std::string> vendor_names;
|
||||
// store all vendor names in vendor_names
|
||||
for (auto& dir_entry : boost::filesystem::directory_iterator(dir)) {
|
||||
@@ -2256,6 +2270,9 @@ std::pair<PresetsConfigSubstitutions, std::string> PresetBundle::load_system_pre
|
||||
std::vector<std::string> other_vendors;
|
||||
other_vendors.reserve(vendor_names.size());
|
||||
for (auto& vn : vendor_names) {
|
||||
// In partial mode, skip vendors already loaded from cache.
|
||||
if (!partial_dirty_vendors.empty() && !partial_dirty_vendors.count(vn))
|
||||
continue;
|
||||
if (vn == ORCA_FILAMENT_LIBRARY)
|
||||
orca_lib_vendor = vn;
|
||||
else if (!(validation_mode && !vendor_to_validate.empty() && vn != vendor_to_validate))
|
||||
|
||||
@@ -124,9 +124,14 @@ std::string SystemPresetsCache::bundled_cache_path()
|
||||
|
||||
bool SystemPresetsCache::is_valid(const std::string& system_dir) const
|
||||
{
|
||||
if (format_version != FORMAT_VERSION)
|
||||
return false;
|
||||
if (config_options_count != print_config_def.options.size())
|
||||
std::set<std::string> dummy;
|
||||
return get_dirty_vendors(system_dir, dummy) && dummy.empty();
|
||||
}
|
||||
|
||||
bool SystemPresetsCache::get_dirty_vendors(const std::string& system_dir, std::set<std::string>& out_dirty) const
|
||||
{
|
||||
out_dirty.clear();
|
||||
if (format_version != FORMAT_VERSION || config_options_count != print_config_def.options.size())
|
||||
return false;
|
||||
std::map<std::string, std::string> current;
|
||||
try {
|
||||
@@ -143,12 +148,15 @@ bool SystemPresetsCache::is_valid(const std::string& system_dir) const
|
||||
BOOST_LOG_TRIVIAL(warning) << "PresetBundleCache: directory scan failed: " << e.what();
|
||||
return false;
|
||||
}
|
||||
if (current.size() != vendor_versions.size())
|
||||
return false;
|
||||
// A vendor was removed from disk — safest to force a full re-parse.
|
||||
for (const auto& [name, ver] : vendor_versions)
|
||||
if (current.find(name) == current.end())
|
||||
return false;
|
||||
// Collect vendors with changed or new version strings.
|
||||
for (const auto& [name, ver] : current) {
|
||||
auto it = vendor_versions.find(name);
|
||||
if (it == vendor_versions.end() || it->second != ver)
|
||||
return false;
|
||||
out_dirty.insert(name);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -234,9 +242,16 @@ void SystemPresetsCache::capture(const PresetBundle& bundle, const std::string&
|
||||
}
|
||||
|
||||
void SystemPresetsCache::apply(PresetBundle& bundle) const
|
||||
{
|
||||
apply_partial(bundle, {});
|
||||
}
|
||||
|
||||
void SystemPresetsCache::apply_partial(PresetBundle& bundle, const std::set<std::string>& skip_vendor_ids) const
|
||||
{
|
||||
bundle.reset(false);
|
||||
for (const auto& cvp : vendor_profiles) {
|
||||
if (skip_vendor_ids.count(cvp.id))
|
||||
continue;
|
||||
VendorProfile vp(cvp.id);
|
||||
vp.name = cvp.name;
|
||||
vp.config_update_url = cvp.config_update_url;
|
||||
@@ -273,10 +288,12 @@ void SystemPresetsCache::apply(PresetBundle& bundle) const
|
||||
bundle.vendors.emplace(cvp.id, std::move(vp));
|
||||
}
|
||||
|
||||
auto apply_col = [&bundle](const std::vector<CachedPreset>& cached,
|
||||
PresetCollection& coll,
|
||||
bool is_filaments) {
|
||||
auto apply_col = [&](const std::vector<CachedPreset>& cached,
|
||||
PresetCollection& coll,
|
||||
bool is_filaments) {
|
||||
for (const auto& cp : cached) {
|
||||
if (skip_vendor_ids.count(cp.vendor_id))
|
||||
continue;
|
||||
Semver version;
|
||||
if (!cp.version.empty()) {
|
||||
auto v = Semver::parse(cp.version);
|
||||
@@ -284,13 +301,13 @@ void SystemPresetsCache::apply(PresetBundle& bundle) const
|
||||
}
|
||||
DynamicPrintConfig config = cp.config;
|
||||
Preset& p = coll.load_preset(cp.file, cp.name, std::move(config), /*select=*/false, version);
|
||||
p.is_system = true;
|
||||
p.is_visible = cp.is_visible;
|
||||
p.alias = cp.alias;
|
||||
p.renamed_from = cp.renamed_from;
|
||||
p.filament_id = cp.filament_id;
|
||||
p.setting_id = cp.setting_id;
|
||||
p.description = cp.description;
|
||||
p.is_system = true;
|
||||
p.is_visible = cp.is_visible;
|
||||
p.alias = cp.alias;
|
||||
p.renamed_from = cp.renamed_from;
|
||||
p.filament_id = cp.filament_id;
|
||||
p.setting_id = cp.setting_id;
|
||||
p.description = cp.description;
|
||||
p.m_from_orca_filament_lib = cp.m_from_orca_filament_lib;
|
||||
if (!cp.vendor_id.empty()) {
|
||||
auto it = bundle.vendors.find(cp.vendor_id);
|
||||
@@ -307,9 +324,12 @@ void SystemPresetsCache::apply(PresetBundle& bundle) const
|
||||
apply_col(sla_print_presets, bundle.sla_prints, false);
|
||||
apply_col(sla_material_presets, bundle.sla_materials, false);
|
||||
|
||||
// config_maps and filament_id_maps are derived from ORCA_FILAMENT_LIBRARY.
|
||||
// If that vendor is in skip_vendor_ids it will be re-loaded from JSON and will
|
||||
// overwrite these; otherwise the cached values are still valid.
|
||||
bundle.m_config_maps = config_maps;
|
||||
bundle.m_filament_id_maps = filament_id_maps;
|
||||
// Caller must invoke bundle.update_system_maps() after this (it is private to PresetBundle).
|
||||
// Caller must invoke bundle.update_system_maps() after all loading is done.
|
||||
}
|
||||
|
||||
bool SystemPresetsCache::load(const std::string& path)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -121,8 +122,14 @@ struct SystemPresetsCache {
|
||||
static std::string cache_path();
|
||||
static std::string bundled_cache_path();
|
||||
bool is_valid(const std::string& system_dir) const;
|
||||
// Returns false on structural mismatch (full re-parse required).
|
||||
// On true, populates out_dirty with vendor IDs whose version strings changed.
|
||||
// Empty out_dirty means fully valid (cache hit, no re-parse needed).
|
||||
bool get_dirty_vendors(const std::string& system_dir, std::set<std::string>& out_dirty) const;
|
||||
void capture(const PresetBundle& bundle, const std::string& system_dir);
|
||||
void apply(PresetBundle& bundle) const;
|
||||
// Same as apply() but skips vendors listed in skip_vendor_ids and their presets.
|
||||
void apply_partial(PresetBundle& bundle, const std::set<std::string>& skip_vendor_ids) const;
|
||||
bool load(const std::string& path);
|
||||
void save(const std::string& path) const;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user