Skip to content

Commit 0073f15

Browse files
authored
refactor: cache/is_dirty impls (#311)
Making more readable and improving tracing. No functional changes.
1 parent e07c391 commit 0073f15

File tree

1 file changed

+85
-71
lines changed

1 file changed

+85
-71
lines changed

crates/compilers/src/cache.rs

Lines changed: 85 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ pub struct CompilerCache<S = Settings> {
5353
}
5454

5555
impl<S> CompilerCache<S> {
56+
/// Creates a new empty cache.
5657
pub fn new(format: String, paths: ProjectPaths, preprocessed: bool) -> Self {
5758
Self {
5859
format,
@@ -118,11 +119,10 @@ impl<S: CompilerSettings> CompilerCache<S> {
118119
/// cache.join_artifacts_files(project.artifacts_path());
119120
/// # Ok::<_, Box<dyn std::error::Error>>(())
120121
/// ```
121-
#[instrument(name = "CompilerCache::read", skip_all)]
122+
#[instrument(name = "CompilerCache::read", err)]
122123
pub fn read(path: &Path) -> Result<Self> {
123-
trace!("reading solfiles cache at {}", path.display());
124124
let cache: Self = utils::read_json_file(path)?;
125-
trace!("read cache \"{}\" with {} entries", cache.format, cache.files.len());
125+
trace!(cache.format, cache.files = cache.files.len(), "read cache");
126126
Ok(cache)
127127
}
128128

@@ -787,43 +787,51 @@ impl<T: ArtifactOutput<CompilerContract = C::CompilerContract>, C: Compiler>
787787
}
788788

789789
/// Returns whether we are missing artifacts for the given file and version.
790-
#[instrument(level = "trace", skip(self))]
791790
fn is_missing_artifacts(&self, file: &Path, version: &Version, profile: &str) -> bool {
791+
self.is_missing_artifacts_impl(file, version, profile).is_err()
792+
}
793+
794+
/// Returns whether we are missing artifacts for the given file and version.
795+
#[instrument(level = "trace", name = "is_missing_artifacts", skip(self), ret)]
796+
fn is_missing_artifacts_impl(
797+
&self,
798+
file: &Path,
799+
version: &Version,
800+
profile: &str,
801+
) -> Result<(), &'static str> {
792802
let Some(entry) = self.cache.entry(file) else {
793-
trace!("missing cache entry");
794-
return true;
803+
return Err("missing cache entry");
795804
};
796805

797806
// only check artifact's existence if the file generated artifacts.
798807
// e.g. a solidity file consisting only of import statements (like interfaces that
799808
// re-export) do not create artifacts
800809
if entry.seen_by_compiler && entry.artifacts.is_empty() {
801-
trace!("no artifacts");
802-
return false;
810+
return Ok(());
803811
}
804812

805813
if !entry.contains(version, profile) {
806-
trace!("missing linked artifacts");
807-
return true;
814+
return Err("missing linked artifacts");
808815
}
809816

810-
if entry.artifacts_for_version(version).any(|artifact| {
811-
let missing_artifact = !self.cached_artifacts.has_artifact(&artifact.path);
812-
if missing_artifact {
813-
trace!("missing artifact \"{}\"", artifact.path.display());
814-
}
815-
missing_artifact
816-
}) {
817-
return true;
817+
if entry
818+
.artifacts_for_version(version)
819+
.any(|artifact| !self.cached_artifacts.has_artifact(&artifact.path))
820+
{
821+
return Err("missing artifact");
818822
}
819823

820824
// If any requested extra files are missing for any artifact, mark source as dirty to
821825
// generate them
822-
self.missing_extra_files()
826+
if self.missing_extra_files() {
827+
return Err("missing extra files");
828+
}
829+
830+
Ok(())
823831
}
824832

825833
// Walks over all cache entries, detects dirty files and removes them from cache.
826-
fn find_and_remove_dirty(&mut self) {
834+
fn remove_dirty_sources(&mut self) {
827835
fn populate_dirty_files<P: SourceParser>(
828836
file: &Path,
829837
dirty_files: &mut HashSet<PathBuf>,
@@ -839,41 +847,7 @@ impl<T: ArtifactOutput<CompilerContract = C::CompilerContract>, C: Compiler>
839847
}
840848
}
841849

842-
let existing_profiles = self.project.settings_profiles().collect::<BTreeMap<_, _>>();
843-
844-
let mut dirty_profiles = HashSet::new();
845-
for (profile, settings) in &self.cache.profiles {
846-
if !existing_profiles.get(profile.as_str()).is_some_and(|p| p.can_use_cached(settings))
847-
{
848-
trace!("dirty profile: {}", profile);
849-
dirty_profiles.insert(profile.clone());
850-
}
851-
}
852-
853-
for profile in &dirty_profiles {
854-
self.cache.profiles.remove(profile);
855-
}
856-
857-
self.cache.files.retain(|_, entry| {
858-
// keep entries which already had no artifacts
859-
if entry.artifacts.is_empty() {
860-
return true;
861-
}
862-
entry.artifacts.retain(|_, artifacts| {
863-
artifacts.retain(|_, artifacts| {
864-
artifacts.retain(|profile, _| !dirty_profiles.contains(profile));
865-
!artifacts.is_empty()
866-
});
867-
!artifacts.is_empty()
868-
});
869-
!entry.artifacts.is_empty()
870-
});
871-
872-
for (profile, settings) in existing_profiles {
873-
if !self.cache.profiles.contains_key(profile) {
874-
self.cache.profiles.insert(profile.to_string(), settings.clone());
875-
}
876-
}
850+
self.update_profiles();
877851

878852
// Iterate over existing cache entries.
879853
let files = self.cache.files.keys().cloned().collect::<HashSet<_>>();
@@ -899,7 +873,7 @@ impl<T: ArtifactOutput<CompilerContract = C::CompilerContract>, C: Compiler>
899873

900874
// Pre-add all sources that are guaranteed to be dirty
901875
for file in sources.keys() {
902-
if self.is_dirty_impl(file, false) {
876+
if self.is_dirty(file, false) {
903877
self.dirty_sources.insert(file.clone());
904878
}
905879
}
@@ -928,7 +902,7 @@ impl<T: ArtifactOutput<CompilerContract = C::CompilerContract>, C: Compiler>
928902
} else if !is_src
929903
&& self.dirty_sources.contains(import)
930904
&& (!self.is_source_file(import)
931-
|| self.is_dirty_impl(import, true)
905+
|| self.is_dirty(import, true)
932906
|| self.cache.mocks.contains(file))
933907
{
934908
if self.cache.mocks.contains(file) {
@@ -953,36 +927,76 @@ impl<T: ArtifactOutput<CompilerContract = C::CompilerContract>, C: Compiler>
953927
}
954928
}
955929

956-
fn is_dirty_impl(&self, file: &Path, use_interface_repr: bool) -> bool {
930+
/// Updates the profiles in the cache, removing those which are dirty alongside their artifacts.
931+
fn update_profiles(&mut self) {
932+
let existing_profiles = self.project.settings_profiles().collect::<BTreeMap<_, _>>();
933+
934+
let mut dirty_profiles = HashSet::new();
935+
for (profile, settings) in &self.cache.profiles {
936+
if !existing_profiles.get(profile.as_str()).is_some_and(|p| p.can_use_cached(settings))
937+
{
938+
dirty_profiles.insert(profile.clone());
939+
}
940+
}
941+
942+
for profile in &dirty_profiles {
943+
trace!(profile, "removing dirty profile and artifacts");
944+
self.cache.profiles.remove(profile);
945+
}
946+
947+
for (profile, settings) in existing_profiles {
948+
if !self.cache.profiles.contains_key(profile) {
949+
trace!(profile, "adding new profile");
950+
self.cache.profiles.insert(profile.to_string(), settings.clone());
951+
}
952+
}
953+
954+
self.cache.files.retain(|_, entry| {
955+
// keep entries which already had no artifacts
956+
if entry.artifacts.is_empty() {
957+
return true;
958+
}
959+
entry.artifacts.retain(|_, artifacts| {
960+
artifacts.retain(|_, artifacts| {
961+
artifacts.retain(|profile, _| !dirty_profiles.contains(profile));
962+
!artifacts.is_empty()
963+
});
964+
!artifacts.is_empty()
965+
});
966+
!entry.artifacts.is_empty()
967+
});
968+
}
969+
970+
fn is_dirty(&self, file: &Path, use_interface_repr: bool) -> bool {
971+
self.is_dirty_impl(file, use_interface_repr).is_err()
972+
}
973+
974+
#[instrument(level = "trace", name = "is_dirty", skip(self), ret)]
975+
fn is_dirty_impl(&self, file: &Path, use_interface_repr: bool) -> Result<(), &'static str> {
957976
let Some(entry) = self.cache.entry(file) else {
958-
trace!("missing cache entry");
959-
return true;
977+
return Err("missing cache entry");
960978
};
961979

962980
if use_interface_repr && self.cache.preprocessed {
963981
let Some(interface_hash) = self.interface_repr_hashes.get(file) else {
964-
trace!("missing interface hash");
965-
return true;
982+
return Err("missing interface hash");
966983
};
967984

968985
if entry.interface_repr_hash.as_ref() != Some(interface_hash) {
969-
trace!("interface hash changed");
970-
return true;
971-
};
986+
return Err("interface hash changed");
987+
}
972988
} else {
973989
let Some(content_hash) = self.content_hashes.get(file) else {
974-
trace!("missing content hash");
975-
return true;
990+
return Err("missing content hash");
976991
};
977992

978993
if entry.content_hash != *content_hash {
979-
trace!("content hash changed");
980-
return true;
994+
return Err("content hash changed");
981995
}
982996
}
983997

984998
// all things match, can be reused
985-
false
999+
Ok(())
9861000
}
9871001

9881002
/// Adds the file's hashes to the set if not set yet
@@ -1155,7 +1169,7 @@ impl<'a, T: ArtifactOutput<CompilerContract = C::CompilerContract>, C: Compiler>
11551169
pub fn remove_dirty_sources(&mut self) {
11561170
match self {
11571171
ArtifactsCache::Ephemeral(..) => {}
1158-
ArtifactsCache::Cached(cache) => cache.find_and_remove_dirty(),
1172+
ArtifactsCache::Cached(cache) => cache.remove_dirty_sources(),
11591173
}
11601174
}
11611175

0 commit comments

Comments
 (0)