mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-29 03:41:31 +00:00
libslic3r: append a vendor's presets and sort once
Installing a preset placed it at its position in the sorted collection, which moves every preset after it, so a vendor with 2528 filaments paid an O(n) insertion 2528 times. That is serial work at the end of a load whose per-preset part now runs across threads, so it is what the load waits on. The entries are appended and the collection sorted once they are all in, the way user presets are already loaded. The sort is on a scope guard, so it also runs for an entry that cannot be installed and throws past the end of the loop. A repeated name was caught by find_preset against the half-filled collection, which an unsorted one cannot answer, so the names are kept in a set, seeded with the default presets that are in the collection before the first entry arrives.
This commit is contained in:
@@ -2872,12 +2872,11 @@ std::pair<Preset*, bool> PresetCollection::load_external_preset(
|
|||||||
return std::make_pair(&preset, false);
|
return std::make_pair(&preset, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Preset& PresetCollection::append_preset(const std::string &path, const std::string &name, DynamicPrintConfig &&config)
|
Preset& PresetCollection::append_preset(std::string &&path, const std::string &name, DynamicPrintConfig &&config)
|
||||||
{
|
{
|
||||||
lock();
|
lock();
|
||||||
m_presets.emplace_back(Preset(m_type, name, false));
|
Preset &preset = m_presets.emplace_back(m_type, name, false);
|
||||||
Preset &preset = m_presets.back();
|
preset.file = std::move(path);
|
||||||
preset.file = path;
|
|
||||||
preset.config = std::move(config);
|
preset.config = std::move(config);
|
||||||
preset.loaded = true;
|
preset.loaded = true;
|
||||||
preset.is_dirty = false;
|
preset.is_dirty = false;
|
||||||
|
|||||||
@@ -943,11 +943,9 @@ private:
|
|||||||
return a.name < b.name;
|
return a.name < b.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a preset at the end rather than at its place in the order, which turns one
|
// Append a preset without keeping the collection sorted, for a caller installing
|
||||||
// O(n) insertion per preset into a single sort for a caller installing a whole
|
// many at once; find_preset() is unusable until sort_presets() runs.
|
||||||
// vendor. The collection is unsorted, and find_preset() unusable, until
|
Preset& append_preset(std::string &&path, const std::string &name, DynamicPrintConfig &&config);
|
||||||
// sort_presets() runs.
|
|
||||||
Preset& append_preset(const std::string &path, const std::string &name, DynamicPrintConfig &&config);
|
|
||||||
|
|
||||||
// Sort presets: filament presets use generic-first ordering, others sort alphabetically.
|
// Sort presets: filament presets use generic-first ordering, others sort alphabetically.
|
||||||
void sort_presets() {
|
void sort_presets() {
|
||||||
|
|||||||
@@ -6803,6 +6803,7 @@ std::string PresetBundle::commit_vendor_preset(
|
|||||||
std::map<std::string, DynamicPrintConfig>& config_maps, std::map<std::string, DynamicPrintConfig>& include_maps,
|
std::map<std::string, DynamicPrintConfig>& config_maps, std::map<std::string, DynamicPrintConfig>& include_maps,
|
||||||
std::map<std::string, std::string>& filament_id_maps,
|
std::map<std::string, std::string>& filament_id_maps,
|
||||||
PresetCollection* presets_collection, size_t& count, bool is_from_lib,
|
PresetCollection* presets_collection, size_t& count, bool is_from_lib,
|
||||||
|
std::unordered_set<std::string>& installed_names,
|
||||||
const std::set<std::string>* retain_configs)
|
const std::set<std::string>* retain_configs)
|
||||||
{
|
{
|
||||||
const VendorProfile* current_vendor_profile = &this->vendors.at(vendor_name);
|
const VendorProfile* current_vendor_profile = &this->vendors.at(vendor_name);
|
||||||
@@ -6826,8 +6827,7 @@ std::string PresetBundle::commit_vendor_preset(
|
|||||||
return std::string();
|
return std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Preset *preset_existing = presets_collection->find_preset(preset_name, false);
|
if (! installed_names.insert(preset_name).second) {
|
||||||
if (preset_existing != nullptr) {
|
|
||||||
++m_errors;
|
++m_errors;
|
||||||
BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" <<
|
BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" <<
|
||||||
preset_name << "\" has already been loaded from another Config Bundle.";
|
preset_name << "\" has already been loaded from another Config Bundle.";
|
||||||
@@ -6835,7 +6835,7 @@ std::string PresetBundle::commit_vendor_preset(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load the preset into the list of presets, save it to disk.
|
// Load the preset into the list of presets, save it to disk.
|
||||||
Preset &loaded = presets_collection->load_preset(resolved.file_path, preset_name, std::move(resolved.config), false);
|
Preset &loaded = presets_collection->append_preset(std::move(resolved.file_path), preset_name, std::move(resolved.config));
|
||||||
if (flags.has(LoadConfigBundleAttribute::LoadSystem)) {
|
if (flags.has(LoadConfigBundleAttribute::LoadSystem)) {
|
||||||
loaded.is_system = true;
|
loaded.is_system = true;
|
||||||
loaded.vendor = current_vendor_profile;
|
loaded.vendor = current_vendor_profile;
|
||||||
@@ -6884,6 +6884,16 @@ std::string PresetBundle::commit_vendor_preset(
|
|||||||
return std::string();
|
return std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The names a vendor may not reuse. A preset is installed by appending it, so the
|
||||||
|
// collection cannot be searched for a repeated name while one is in progress, and
|
||||||
|
// the default presets are already in it before the first entry arrives.
|
||||||
|
void PresetBundle::seed_installed_names(std::unordered_set<std::string>& installed_names,
|
||||||
|
const PresetCollection& presets) const
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < presets.m_num_default_presets; ++ i)
|
||||||
|
installed_names.insert(presets.m_presets[i].name);
|
||||||
|
}
|
||||||
|
|
||||||
// Orca: load one source-form preset entry — parsed from its JSON subfile just
|
// Orca: load one source-form preset entry — parsed from its JSON subfile just
|
||||||
// now, or deserialized from the vendor's cache; the code is shared so a
|
// now, or deserialized from the vendor's cache; the code is shared so a
|
||||||
// cache-loaded bundle cannot come out different from a JSON-loaded one.
|
// cache-loaded bundle cannot come out different from a JSON-loaded one.
|
||||||
@@ -6896,13 +6906,14 @@ std::string PresetBundle::load_vendor_preset(
|
|||||||
std::map<std::string, DynamicPrintConfig>& config_maps, std::map<std::string, DynamicPrintConfig>& include_maps,
|
std::map<std::string, DynamicPrintConfig>& config_maps, std::map<std::string, DynamicPrintConfig>& include_maps,
|
||||||
std::map<std::string, std::string>& filament_id_maps,
|
std::map<std::string, std::string>& filament_id_maps,
|
||||||
PresetCollection* presets_collection, size_t& count, bool is_from_lib,
|
PresetCollection* presets_collection, size_t& count, bool is_from_lib,
|
||||||
|
std::unordered_set<std::string>& installed_names,
|
||||||
const std::set<std::string>* retain_configs, const std::set<std::string>* retain_includes)
|
const std::set<std::string>* retain_configs, const std::set<std::string>* retain_includes)
|
||||||
{
|
{
|
||||||
PresetInstall resolved = this->resolve_vendor_preset(entry, path, vendor_name, base_bundle,
|
PresetInstall resolved = this->resolve_vendor_preset(entry, path, vendor_name, base_bundle,
|
||||||
config_maps, include_maps, filament_id_maps, *presets_collection, retain_includes);
|
config_maps, include_maps, filament_id_maps, *presets_collection, retain_includes);
|
||||||
return this->commit_vendor_preset(entry, std::move(resolved), path, vendor_name, flags,
|
return this->commit_vendor_preset(entry, std::move(resolved), path, vendor_name, flags,
|
||||||
substitution_context, substitutions, config_maps, include_maps, filament_id_maps, presets_collection,
|
substitution_context, substitutions, config_maps, include_maps, filament_id_maps, presets_collection,
|
||||||
count, is_from_lib, retain_configs);
|
count, is_from_lib, installed_names, retain_configs);
|
||||||
}
|
}
|
||||||
|
|
||||||
//BBS: Load a config bundle file from json
|
//BBS: Load a config bundle file from json
|
||||||
@@ -7273,6 +7284,16 @@ std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_vendor_configs_
|
|||||||
configs.clear();
|
configs.clear();
|
||||||
include_maps.clear();
|
include_maps.clear();
|
||||||
filament_id_maps.clear();
|
filament_id_maps.clear();
|
||||||
|
std::unordered_set<std::string> installed_names;
|
||||||
|
seed_installed_names(installed_names, *presets);
|
||||||
|
// The presets below are appended, so the collection is out of the order
|
||||||
|
// find_preset() searches until it is sorted. A subfile that cannot be
|
||||||
|
// loaded throws past the end of the loop, and a caller that carries on
|
||||||
|
// from that would be left searching an unsorted collection.
|
||||||
|
struct SortOnExit {
|
||||||
|
PresetCollection* presets;
|
||||||
|
~SortOnExit() { presets->sort_presets(); }
|
||||||
|
} sort_on_exit { presets };
|
||||||
for (auto& subfile : subfiles) {
|
for (auto& subfile : subfiles) {
|
||||||
CachedPreset entry;
|
CachedPreset entry;
|
||||||
std::string reason = parse_subfile(substitution_context, subfile, entry);
|
std::string reason = parse_subfile(substitution_context, subfile, entry);
|
||||||
@@ -7280,7 +7301,7 @@ std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_vendor_configs_
|
|||||||
const int errors_before_install = m_errors;
|
const int errors_before_install = m_errors;
|
||||||
reason = load_vendor_preset(entry, dir, vendor_name, base_bundle, flags,
|
reason = load_vendor_preset(entry, dir, vendor_name, base_bundle, flags,
|
||||||
substitution_context, substitutions, configs, include_maps, filament_id_maps,
|
substitution_context, substitutions, configs, include_maps, filament_id_maps,
|
||||||
presets, presets_loaded, is_from_lib);
|
presets, presets_loaded, is_from_lib, installed_names);
|
||||||
install_errors += m_errors - errors_before_install;
|
install_errors += m_errors - errors_before_install;
|
||||||
}
|
}
|
||||||
if (!reason.empty()) {
|
if (!reason.empty()) {
|
||||||
@@ -8097,10 +8118,19 @@ bool PresetBundle::load_vendor_cache(const std::string& cache_path, const std::s
|
|||||||
}
|
}
|
||||||
const std::set<std::string>* retain_configs = is_from_lib ? nullptr : &inherited;
|
const std::set<std::string>* retain_configs = is_from_lib ? nullptr : &inherited;
|
||||||
|
|
||||||
|
std::unordered_set<std::string> installed_names;
|
||||||
|
seed_installed_names(installed_names, *presets);
|
||||||
|
// The entries below are appended, so the collection is out of the
|
||||||
|
// order find_preset() searches until it is sorted, and an entry that
|
||||||
|
// cannot be installed throws past the end of this lambda.
|
||||||
|
struct SortOnExit {
|
||||||
|
PresetCollection* presets;
|
||||||
|
~SortOnExit() { presets->sort_presets(); }
|
||||||
|
} sort_on_exit { presets };
|
||||||
auto commit = [&](const CachedPreset& entry, PresetInstall&& resolved) {
|
auto commit = [&](const CachedPreset& entry, PresetInstall&& resolved) {
|
||||||
const std::string reason = commit_vendor_preset(entry, std::move(resolved), path, vendor_name,
|
const std::string reason = commit_vendor_preset(entry, std::move(resolved), path, vendor_name,
|
||||||
LoadConfigBundleAttribute::LoadSystem, substitution_context, substitutions,
|
LoadConfigBundleAttribute::LoadSystem, substitution_context, substitutions,
|
||||||
configs, include_maps, filament_id_maps, presets, count, is_from_lib, retain_configs);
|
configs, include_maps, filament_id_maps, presets, count, is_from_lib, installed_names, retain_configs);
|
||||||
if (! reason.empty())
|
if (! reason.empty())
|
||||||
throw std::runtime_error("entry " + entry.name + " failed to install: " + reason);
|
throw std::runtime_error("entry " + entry.name + " failed to install: " + reason);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -651,6 +651,7 @@ private:
|
|||||||
std::map<std::string, DynamicPrintConfig>& config_maps, std::map<std::string, DynamicPrintConfig>& include_maps,
|
std::map<std::string, DynamicPrintConfig>& config_maps, std::map<std::string, DynamicPrintConfig>& include_maps,
|
||||||
std::map<std::string, std::string>& filament_id_maps,
|
std::map<std::string, std::string>& filament_id_maps,
|
||||||
PresetCollection* presets_collection, size_t& count, bool is_from_lib,
|
PresetCollection* presets_collection, size_t& count, bool is_from_lib,
|
||||||
|
std::unordered_set<std::string>& installed_names,
|
||||||
const std::set<std::string>* retain_configs = nullptr, const std::set<std::string>* retain_includes = nullptr);
|
const std::set<std::string>* retain_configs = nullptr, const std::set<std::string>* retain_includes = nullptr);
|
||||||
|
|
||||||
// One entry flattened against the preset it inherits, before anything this
|
// One entry flattened against the preset it inherits, before anything this
|
||||||
@@ -689,6 +690,8 @@ private:
|
|||||||
|
|
||||||
// Install a resolved entry. The collections, the inheritance maps and the
|
// Install a resolved entry. The collections, the inheritance maps and the
|
||||||
// error count are touched here and only here, one entry at a time.
|
// error count are touched here and only here, one entry at a time.
|
||||||
|
// Presets are appended, so a repeated name is caught with `installed_names`,
|
||||||
|
// and the caller sorts the collection once every entry is in.
|
||||||
std::string commit_vendor_preset(const CachedPreset& entry, PresetInstall&& resolved,
|
std::string commit_vendor_preset(const CachedPreset& entry, PresetInstall&& resolved,
|
||||||
const std::string& path, const std::string& vendor_name,
|
const std::string& path, const std::string& vendor_name,
|
||||||
LoadConfigBundleAttributes flags,
|
LoadConfigBundleAttributes flags,
|
||||||
@@ -696,8 +699,15 @@ private:
|
|||||||
std::map<std::string, DynamicPrintConfig>& config_maps, std::map<std::string, DynamicPrintConfig>& include_maps,
|
std::map<std::string, DynamicPrintConfig>& config_maps, std::map<std::string, DynamicPrintConfig>& include_maps,
|
||||||
std::map<std::string, std::string>& filament_id_maps,
|
std::map<std::string, std::string>& filament_id_maps,
|
||||||
PresetCollection* presets_collection, size_t& count, bool is_from_lib,
|
PresetCollection* presets_collection, size_t& count, bool is_from_lib,
|
||||||
|
std::unordered_set<std::string>& installed_names,
|
||||||
const std::set<std::string>* retain_configs = nullptr);
|
const std::set<std::string>* retain_configs = nullptr);
|
||||||
|
|
||||||
|
// The names an install may not give a preset. A preset is installed by
|
||||||
|
// appending it, so the collection is too unsorted to be searched for a
|
||||||
|
// repeated name, and the default presets are in it before the first entry.
|
||||||
|
void seed_installed_names(std::unordered_set<std::string>& installed_names,
|
||||||
|
const PresetCollection& presets) const;
|
||||||
|
|
||||||
// Clear every collection's m_printer_hold_alias, which reset() leaves alone.
|
// Clear every collection's m_printer_hold_alias, which reset() leaves alone.
|
||||||
void clear_printer_hold_aliases();
|
void clear_printer_hold_aliases();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user