Skip to content

Commit 784daea

Browse files
authored
Merge pull request #1132 from SteveL-MSFT/discovery-static
Add static memory cache for discovered resources
2 parents 9110c74 + 8ce497c commit 784daea

File tree

2 files changed

+72
-37
lines changed

2 files changed

+72
-37
lines changed

dsc_lib/src/discovery/command_discovery.rs

Lines changed: 40 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
33

4-
use crate::discovery::discovery_trait::{DiscoveryFilter, DiscoveryKind, ResourceDiscovery};
4+
use crate::discovery::{
5+
discovery_trait::{DiscoveryFilter, DiscoveryKind, ResourceDiscovery}
6+
};
7+
use crate::{locked_is_empty, locked_extend, locked_clone, locked_get};
58
use crate::dscresources::dscresource::{Capability, DscResource, ImplementedAs};
69
use crate::dscresources::resource_manifest::{import_manifest, validate_semver, Kind, ResourceManifest, SchemaKind};
710
use crate::dscresources::command_resource::invoke_command;
@@ -15,7 +18,7 @@ use rust_i18n::t;
1518
use semver::{Version, VersionReq};
1619
use schemars::JsonSchema;
1720
use serde::{Deserialize, Serialize};
18-
use std::collections::{BTreeMap, HashSet, HashMap};
21+
use std::{collections::{BTreeMap, HashMap, HashSet}, sync::{LazyLock, RwLock}};
1922
use std::env;
2023
use std::ffi::OsStr;
2124
use std::fs;
@@ -30,19 +33,21 @@ use crate::util::get_exe_path;
3033
const DSC_RESOURCE_EXTENSIONS: [&str; 3] = [".dsc.resource.json", ".dsc.resource.yaml", ".dsc.resource.yml"];
3134
const DSC_EXTENSION_EXTENSIONS: [&str; 3] = [".dsc.extension.json", ".dsc.extension.yaml", ".dsc.extension.yml"];
3235

36+
// use BTreeMap so that the results are sorted by the typename, the Vec is sorted by version
37+
static ADAPTERS: LazyLock<RwLock<BTreeMap<String, Vec<DscResource>>>> = LazyLock::new(|| RwLock::new(BTreeMap::new()));
38+
static RESOURCES: LazyLock<RwLock<BTreeMap<String, Vec<DscResource>>>> = LazyLock::new(|| RwLock::new(BTreeMap::new()));
39+
static EXTENSIONS: LazyLock<RwLock<BTreeMap<String, DscExtension>>> = LazyLock::new(|| RwLock::new(BTreeMap::new()));
40+
static ADAPTED_RESOURCES: LazyLock<RwLock<BTreeMap<String, Vec<DscResource>>>> = LazyLock::new(|| RwLock::new(BTreeMap::new()));
41+
3342
#[derive(Clone, Serialize, Deserialize, JsonSchema)]
3443
pub enum ImportedManifest {
3544
Resource(DscResource),
3645
Extension(DscExtension),
3746
}
3847

48+
3949
#[derive(Clone)]
4050
pub struct CommandDiscovery {
41-
// use BTreeMap so that the results are sorted by the typename, the Vec is sorted by version
42-
adapters: BTreeMap<String, Vec<DscResource>>,
43-
resources: BTreeMap<String, Vec<DscResource>>,
44-
extensions: BTreeMap<String, DscExtension>,
45-
adapted_resources: BTreeMap<String, Vec<DscResource>>,
4651
progress_format: ProgressFormat,
4752
}
4853

@@ -72,18 +77,12 @@ impl CommandDiscovery {
7277
#[must_use]
7378
pub fn new(progress_format: ProgressFormat) -> CommandDiscovery {
7479
CommandDiscovery {
75-
adapters: BTreeMap::new(),
76-
resources: BTreeMap::new(),
77-
extensions: BTreeMap::new(),
78-
adapted_resources: BTreeMap::new(),
7980
progress_format,
8081
}
8182
}
8283

8384
#[must_use]
84-
pub fn get_extensions(&self) -> &BTreeMap<String, DscExtension> {
85-
&self.extensions
86-
}
85+
pub fn get_extensions(&self) -> BTreeMap<String, DscExtension> { locked_clone!(EXTENSIONS) }
8786

8887
fn get_resource_path_setting() -> Result<ResourcePathSetting, DscError>
8988
{
@@ -307,7 +306,7 @@ impl ResourceDiscovery for CommandDiscovery {
307306
match kind {
308307
DiscoveryKind::Resource => {
309308
// Now we need to call discover extensions and add those resource to the list of resources
310-
for extension in self.extensions.values() {
309+
for extension in locked_clone!(EXTENSIONS).values() {
311310
if extension.capabilities.contains(&ExtensionCapability::Discover) {
312311
debug!("{}", t!("discovery.commandDiscovery.callingExtension", extension = extension.type_name));
313312
let discovered_resources = match extension.discover() {
@@ -326,26 +325,27 @@ impl ResourceDiscovery for CommandDiscovery {
326325
}
327326
}
328327
}
329-
self.adapters = adapters;
330-
self.resources = resources;
328+
locked_extend!(ADAPTERS, adapters);
329+
locked_extend!(RESOURCES, resources);
331330
},
332331
DiscoveryKind::Extension => {
333-
self.extensions = extensions;
332+
locked_extend!(EXTENSIONS, extensions);
334333
}
335334
}
336335

337336
Ok(())
338337
}
339338

340339
fn discover_adapted_resources(&mut self, name_filter: &str, adapter_filter: &str) -> Result<(), DscError> {
341-
if self.resources.is_empty() && self.adapters.is_empty() {
340+
if locked_is_empty!(RESOURCES) && locked_is_empty!(ADAPTERS) {
342341
self.discover(&DiscoveryKind::Resource, "*")?;
343342
}
344343

345-
if self.adapters.is_empty() {
344+
if locked_is_empty!(ADAPTERS) {
346345
return Ok(());
347346
}
348347

348+
let adapters = locked_clone!(ADAPTERS);
349349
let regex_str = convert_wildcard_to_regex(adapter_filter);
350350
debug!("Using regex {regex_str} as filter for adapter name");
351351
let mut regex_builder = RegexBuilder::new(&regex_str);
@@ -362,13 +362,13 @@ impl ResourceDiscovery for CommandDiscovery {
362362
return Err(DscError::Operation("Could not build Regex filter for resource name".to_string()));
363363
};
364364

365-
let mut progress = ProgressBar::new(self.adapters.len() as u64, self.progress_format)?;
365+
let mut progress = ProgressBar::new(adapters.len() as u64, self.progress_format)?;
366366
progress.write_activity("Searching for adapted resources");
367367

368368
let mut adapted_resources = BTreeMap::<String, Vec<DscResource>>::new();
369369

370370
let mut found_adapter: bool = false;
371-
for (adapter_name, adapters) in &self.adapters {
371+
for (adapter_name, adapters) in &adapters {
372372
for adapter in adapters {
373373
progress.write_increment(1);
374374

@@ -437,7 +437,7 @@ impl ResourceDiscovery for CommandDiscovery {
437437
return Err(DscError::AdapterNotFound(adapter_filter.to_string()));
438438
}
439439

440-
self.adapted_resources = adapted_resources;
440+
locked_extend!(ADAPTED_RESOURCES, adapted_resources);
441441

442442
Ok(())
443443
}
@@ -447,26 +447,27 @@ impl ResourceDiscovery for CommandDiscovery {
447447
if *kind == DiscoveryKind::Resource {
448448
if adapter_name_filter.is_empty() {
449449
self.discover(kind, type_name_filter)?;
450-
for (resource_name, resources_vec) in &self.resources {
450+
for (resource_name, resources_vec) in &locked_clone!(RESOURCES) {
451451
resources.insert(resource_name.clone(), resources_vec.iter().map(|r| ImportedManifest::Resource(r.clone())).collect());
452452
}
453-
for (adapter_name, adapter_vec) in &self.adapters {
453+
for (adapter_name, adapter_vec) in &locked_clone!(ADAPTERS) {
454454
resources.insert(adapter_name.clone(), adapter_vec.iter().map(|r| ImportedManifest::Resource(r.clone())).collect());
455455
}
456456
} else {
457457
self.discover(kind, "*")?;
458458
self.discover_adapted_resources(type_name_filter, adapter_name_filter)?;
459459

460460
// add/update found adapted resources to the lookup_table
461-
add_resources_to_lookup_table(&self.adapted_resources);
461+
let adapted_resources = locked_clone!(ADAPTED_RESOURCES);
462+
add_resources_to_lookup_table(&adapted_resources);
462463

463-
for (adapted_name, adapted_vec) in &self.adapted_resources {
464+
for (adapted_name, adapted_vec) in &adapted_resources {
464465
resources.insert(adapted_name.clone(), adapted_vec.iter().map(|r| ImportedManifest::Resource(r.clone())).collect());
465466
}
466467
}
467468
} else {
468469
self.discover(kind, type_name_filter)?;
469-
for (extension_name, extension) in &self.extensions {
470+
for (extension_name, extension) in &locked_clone!(EXTENSIONS) {
470471
resources.insert(extension_name.clone(), vec![ImportedManifest::Extension(extension.clone())]);
471472
}
472473
}
@@ -476,16 +477,18 @@ impl ResourceDiscovery for CommandDiscovery {
476477

477478
fn find_resources(&mut self, required_resource_types: &[DiscoveryFilter]) -> Result<BTreeMap<String, Vec<DscResource>>, DscError> {
478479
debug!("{}", t!("discovery.commandDiscovery.searchingForResources", resources = required_resource_types : {:?}));
479-
self.discover( &DiscoveryKind::Resource, "*")?;
480+
if locked_is_empty!(RESOURCES) {
481+
self.discover(&DiscoveryKind::Resource, "*")?;
482+
}
480483
let mut found_resources = BTreeMap::<String, Vec<DscResource>>::new();
481484
let mut required_resources = HashMap::<DiscoveryFilter, bool>::new();
482485
for filter in required_resource_types {
483486
required_resources.insert(filter.clone(), false);
484487
}
485488

486489
for filter in required_resource_types {
487-
if let Some(resources) = self.resources.get(filter.resource_type()) {
488-
filter_resources(&mut found_resources, &mut required_resources, resources, filter);
490+
if let Some(resources) = locked_get!(RESOURCES, filter.resource_type()) {
491+
filter_resources(&mut found_resources, &mut required_resources, &resources, filter);
489492
}
490493
if required_resources.values().all(|&v| v) {
491494
break;
@@ -498,12 +501,12 @@ impl ResourceDiscovery for CommandDiscovery {
498501
}
499502

500503
// now go through the adapters, this is for implicit adapters so version can't be specified so use latest version
501-
for adapter_name in self.adapters.clone().keys() {
504+
for adapter_name in locked_clone!(ADAPTERS).keys() {
502505
self.discover_adapted_resources("*", adapter_name)?;
503-
add_resources_to_lookup_table(&self.adapted_resources);
506+
add_resources_to_lookup_table(&locked_clone!(ADAPTED_RESOURCES));
504507
for filter in required_resource_types {
505-
if let Some(adapted_resources) = self.adapted_resources.get(filter.resource_type()) {
506-
filter_resources(&mut found_resources, &mut required_resources, adapted_resources, filter);
508+
if let Some(adapted_resources) = locked_get!(ADAPTED_RESOURCES, filter.resource_type()) {
509+
filter_resources(&mut found_resources, &mut required_resources, &adapted_resources, filter);
507510
}
508511
if required_resources.values().all(|&v| v) {
509512
break;
@@ -518,10 +521,10 @@ impl ResourceDiscovery for CommandDiscovery {
518521
}
519522

520523
fn get_extensions(&mut self) -> Result<BTreeMap<String, DscExtension>, DscError> {
521-
if self.extensions.is_empty() {
524+
if locked_is_empty!(EXTENSIONS) {
522525
self.discover(&DiscoveryKind::Extension, "*")?;
523526
}
524-
Ok(self.extensions.clone())
527+
Ok(locked_clone!(EXTENSIONS))
525528
}
526529
}
527530

dsc_lib/src/util.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,3 +212,35 @@ fn get_settings_policy_file_path() -> String
212212
// This location is writable only by admins, but readable by all users
213213
Path::new("/etc").join("dsc").join("dsc.settings.json").display().to_string()
214214
}
215+
216+
#[macro_export]
217+
macro_rules! locked_is_empty {
218+
($lockable:expr) => {{
219+
$lockable.read().unwrap().is_empty()
220+
}};
221+
}
222+
223+
#[macro_export]
224+
macro_rules! locked_extend {
225+
($lockable:expr, $items:expr) => {{
226+
$lockable.write().unwrap().extend($items);
227+
}};
228+
}
229+
230+
#[macro_export]
231+
macro_rules! locked_clone {
232+
($lockable:expr) => {{
233+
$lockable.read().unwrap().clone()
234+
}};
235+
}
236+
237+
#[macro_export]
238+
macro_rules! locked_get {
239+
($lockable:expr, $key:expr) => {{
240+
if let Some(v) = $lockable.read().unwrap().get($key) {
241+
Some(v.clone())
242+
} else {
243+
None
244+
}
245+
}};
246+
}

0 commit comments

Comments
 (0)