Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use a simple cache based on futures to avoid redownloading on concurrent usage #1384

Merged
merged 3 commits into from
Jun 4, 2019

Conversation

jrudolph
Copy link
Contributor

No description provided.

}
} match {
case Right(fut) =>
/*fut.value match {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left the printlns in for now but can remove them if required.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I normally don't leave printlns in the code but I don't have a strong preference against them. Let's remove it here for consistency with the rest of the codebase

@tanishiking
Copy link
Member

Though CI failed (test for Scala 2.11, and scalafmtCheck), it looks nice at a glance.
I'll review this in a couple of days.

Copy link
Member

@olafurpg olafurpg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for this contribution! This is a good idea. @jrudolph Only blocking comment is to remove the comments, we can keep ReentrantCache if you think that is a better solution than synchronized maps.

To fix the CI

./scalafmt --diff

Also, to fix the compile error on 2.11 we can add -Xexperimental to build or remove the following SAM type

foreach is not a member of org.scalafmt.dynamic.ScalafmtDynamic.FormatEval[org.scalafmt.dynamic.ScalafmtReflect]
[error]     formatCache.clear().foreach(_.foreach(_.foreach(_.classLoader.close()))(ExecutionContext.global))
[error]                                             ^
[error] /home/travis/build/scalameta/scalafmt/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtDynamic.scala:109:50: value exists is not a member of org.scalafmt.dynamic.ScalafmtDynamic.FormatEval[(org.scalafmt.dynamic.ScalafmtReflectConfig, java.nio.file.attribute.FileTime)]
[error]       configsCache.getOrAddToCache(configPath, _.exists(_._2.compareTo(currentTimestamp) != 0)) { () =>
[error]                                                  ^

}
} match {
case Right(fut) =>
/*fut.value match {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I normally don't leave printlns in the code but I don't have a strong preference against them. Let's remove it here for consistency with the rest of the codebase

import scala.concurrent.duration._
import scala.util.Try

class ReentrantCache[K, V] {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a simple explanation of this data structure? For example "This is like a map except ..."

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we use Collections.synchronizedMap(...) and computeIfAbsent instead of ReentrantCache? To limit synchronization we could have another HashMap cache in front of that where we first try with get()

Copy link
Member

@tanishiking tanishiking Mar 17, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found that ReentrantCache is a helpful abstraction of the series of operations (check the result of download and then cache or not)) 👍
Therefore I think it isn't necessarily required to replacing this data structure with built-in data structures (synchronized or concurrent HashMap) as long as the performance doesn't matter.

It would be better to replace this with synchronizedMap or something while keeping the ScalafmtDynamic.scala simple, but I don't have any ideas now...

case None =>
//println(s"Previous calculation for $key still ongoing")
}*/
val result = Await.result(fut, 1.minute) // get or wait for other thread to finish download
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a 1 minute timeout limit to complete the download? If so, I think we need to increase the timeout since we can't expect everybody to have the same internet connection speed. I would go with a large value like 10 minutes, users see the download progress in the console output and can cancel the process with ctrl-c.

@tanishiking
Copy link
Member

@olafurpg FYI @jrudolph I tweaked this PR a bit so that it passes compilation on 2.11 and scalafmtCheck. What do you think about merging it and release the latest version (as a pre-release version)?
And if this fixes #1399, it would be a time to release scalafmt 2.0.0, isn't it?

Copy link
Member

@olafurpg olafurpg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tanishiking LGTM 👍 thank you for looking into this. I'm still concerned about the 1 minute timeout for downloads since people have varying internet connections, I think it might be better to use Collections.synchronizedMap with no timeout limit.

@tanishiking
Copy link
Member

Thanks :)

I'm still concerned about the 1 minute timeout

That's right... I'll merge this PR after modifying the timeout to 10 minutes for now. (Maybe we want to refactor it to use synchronizedMap later). After that, I'm going to release the new version in a few days.

@tanishiking tanishiking merged commit 954753b into scalameta:master Jun 4, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants