-
Notifications
You must be signed in to change notification settings - Fork 84
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
SDK-321: Optimizing SDK Cache Management #255
Conversation
Add the enableDataSaving parameter to the setup-sdk plugin. This parameter enables the data-saving mode. When using this mode, the SDK will reuse the existing cache folder rather than creating a new one. In normal mode, SDK will remove the cache folder after running the setup.
9e2a1dd
to
7ac1f6b
Compare
Add the enableDataSaving parameter to the setup-sdk plugin. This parameter enables the data-saving mode. When using this mode, the SDK will reuse the existing cache folder rather than creating a new one. In normal mode, SDK will remove the cache folder after running the setup.
05f3b84
to
703adaf
Compare
|
||
@Mojo(name = "setup-sdk", requiresProject = false) | ||
public class SetupSDK extends AbstractTask { | ||
|
||
@Parameter(defaultValue = "false", property = "enableDataSaving") | ||
private boolean enableDataSaving; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like we should change the above name to something that reflects what exactly the effects of this flag will be on the actual implementation.
boolean isDataSavingMode = Boolean.parseBoolean(sdkProperties.getProperty("enableDataSaving")); | ||
String cacheName = "openmrs-sdk-node"; | ||
if (isDataSavingMode) { | ||
logger.info("OpenMRS SDK is running on data saving mode"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would not call this a data saving mode because it may be used for other reasons like performance instead of just saving data.
703adaf
to
da1a394
Compare
|
||
@Mojo(name = "setup-sdk", requiresProject = false) | ||
public class SetupSDK extends AbstractTask { | ||
|
||
@Parameter(defaultValue = "true", property = "removeCacheAfterSetup") | ||
private boolean removeCacheAfterSetup; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add some documentation to this parameter?
File tempDir = new File(tempDirPath); | ||
if(tempDir.exists() && tempDir.isDirectory()) { | ||
File[] cache = tempDir.listFiles(file -> file.isDirectory() && file.getName().startsWith("openmrs-sdk-node")); | ||
if(cache == null) return null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
boolean isRemoveCacheAfterSetup = Boolean.parseBoolean(sdkProperties.getProperty("removeCacheAfterSetup")); | ||
String cacheName = "openmrs-sdk-node"; | ||
if (!isRemoveCacheAfterSetup) { | ||
logger.info("OpenMRS SDK will reuse the NPM cache. Run openmrs-sdk:setup-sdk -DremoveCacheAfterSetup=true to disable it."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we be consistent? The description says reuse npm cache
but the method name says remove cache
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we rename the parameter as "ReuseNpmCache" ??
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think is better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think logger info is consistent with implementation. If isRemoveCacheAfterSetup is false the NPM will reuse NPM caches without deleting them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about something along the lines of reuseNodeCache
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sounds good
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed the parameter name
da1a394
to
c6bdbbd
Compare
if (cache == null) { | ||
return null; | ||
} | ||
if (cache.length > 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens to the rest of the caches?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we delete them??
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If they are more than one, will the first one (at index 0) be consistently the same for subsequent calls?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dkayiwa what do you suggest we should do here? We could delete the other caches.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes
This actually isn't guaranteed. We're operating on files in the order returned from listFiles()
which has this caveat:
"There is no guarantee that the name strings in the resulting array will appear in any specific order; they are not, in particular, guaranteed to appear in alphabetical order. "
Similarly, createTempDirectory()
says:
"The details as to how the name of the directory is constructed is implementation dependent and therefore not specified."
In order to guarantee that this always returns the same folder, we'd need a guarantee that listFiles()
returned files in a consistent order and that createTempDirectory()
generates files in a defined order that will fit the order returned by listFiles()
, but those details are specifically disclaimed.
(On Windows, the default JVM does indeed use the tick count as the source of randomness for createTempDirectory()
and listFiles()
likely returns in a consistent order, which would likely result in this appearing to work; however, Linux, the underlying mkstemp()
implementation will try to use a RNG, falling back to ticks if not available on that device. I haven't looked into the details of macOS.)
Probably the thing to do is to make the tempDir
a class variable instead of an instance variable so it's only set once per JVM, which would guarantee consistent results across multiple invocations of the NodeHelper within a single invocation of the SDK.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On reflection, actually, I think a better strategy is: if the user wants to use a consistent NPM cache directory, use a named folder in the directory the SDK "servers directory" (defined here). Just name it something unlikely to be a server name, e.g., _openmrs_sdk_node_cache
. That's cleaner, easier for end-users to understand and nobody has to go poking around for the right "openmrs-sdk-node.1234567" folder.
* By default, this is set to 'true' to save storage space. | ||
* If set to 'false', the SDK will reuse the existing NPM cache | ||
*/ | ||
@Parameter(defaultValue = "true", property = "removeCacheAfterSetup") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't the default be what it was before these changes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed the default value and the code to reflect the property name.
c6bdbbd
to
64b2faf
Compare
|
||
private static final Logger logger = LoggerFactory.getLogger(NodeHelper.class); | ||
|
||
public Path getTempDir() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need to be public? Also, coding style, accessor properties should always come after constructors.
this.mavenProject = mavenProject; | ||
this.mavenSession = mavenSession; | ||
this.pluginManager = pluginManager; | ||
try { | ||
this.tempDir = Files.createTempDirectory("openmrs-sdk-node"); | ||
this.tempDir.toFile().deleteOnExit(); | ||
Properties sdkProperties = getSdkProperties(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's preferrable, I think to move this code into getTempDir()
that way we can defer creating a temporary directory until we actually need it.
this.tempDir.toFile().deleteOnExit(); | ||
Properties sdkProperties = getSdkProperties(); | ||
boolean reuseNodeCache = Boolean.parseBoolean(sdkProperties.getProperty("reuseNodeCache")); | ||
String cacheName = "openmrs-sdk-node"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like this should just be a class constant, no?
if (cache == null) { | ||
return null; | ||
} | ||
if (cache.length > 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes
This actually isn't guaranteed. We're operating on files in the order returned from listFiles()
which has this caveat:
"There is no guarantee that the name strings in the resulting array will appear in any specific order; they are not, in particular, guaranteed to appear in alphabetical order. "
Similarly, createTempDirectory()
says:
"The details as to how the name of the directory is constructed is implementation dependent and therefore not specified."
In order to guarantee that this always returns the same folder, we'd need a guarantee that listFiles()
returned files in a consistent order and that createTempDirectory()
generates files in a defined order that will fit the order returned by listFiles()
, but those details are specifically disclaimed.
(On Windows, the default JVM does indeed use the tick count as the source of randomness for createTempDirectory()
and listFiles()
likely returns in a consistent order, which would likely result in this appearing to work; however, Linux, the underlying mkstemp()
implementation will try to use a RNG, falling back to ticks if not available on that device. I haven't looked into the details of macOS.)
Probably the thing to do is to make the tempDir
a class variable instead of an instance variable so it's only set once per JVM, which would guarantee consistent results across multiple invocations of the NodeHelper within a single invocation of the SDK.
64b2faf
to
6ad7585
Compare
@ibacher I made the changes you requested. |
@wikumChamith I think what I actually asked for was this:
Also, even if we have a global option for this (which is fine), it would be nice to have a local option to override the global option without needing to run |
Add the enableDataSaving parameter to the setup-sdk plugin. This parameter enables the data-saving mode. When using this mode, the SDK will reuse the existing cache folder rather than creating a new one. In normal mode, SDK will remove the cache folder after running the setup.
@ibacher I made the changes you suggested. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @wikumChamith! There are two more places we should be able to override the node cache value:
- BuildDistro
- ServerUpgrader
Then I think this will be all set. Thanks for the work on this!
7f1f3a0
to
96fef6d
Compare
@ibacher I integrated the cache management to build-distro and server upgrader. |
S3yg
…On Wed, 20 Sep 2023, 12:09 Wikum Weerakutti, ***@***.***> wrote:
Description of what I changed
-
Add the enableDataSaving parameter to the setup-sdk plugin. This
parameter enables the data-saving mode. When using this mode, the SDK will
reuse the existing cache folder rather than creating a new one.
-
In normal mode, SDK will remove the cache folder after running the
setup.
Issue I worked on
see https://issues.openmrs.org/browse/SDK-321
Checklist: I completed these to help reviewers :)
-
My IDE is configured to follow the *code style*
<https://wiki.openmrs.org/display/docs/Java+Conventions> of this
project.
No? Unsure? -> configure your IDE
<https://wiki.openmrs.org/display/docs/How-To+Setup+And+Use+Your+IDE>,
format the code and add the changes with git add . && git commit
--amend
-
I have *added tests* to cover my changes. (If you refactored
existing code that was well tested you do not have to add tests)
No? -> write tests and add them to this commit git add . && git commit
--amend
-
I ran mvn clean install right before creating this pull request and
added all formatting changes to my commit.
No? -> execute the above command
-
All new and existing *tests passed*.
No? -> figure out why and add the fix to your commit. It is your
responsibility to make sure your code works.
-
My pull request is *based on the latest changes* of the master branch.
No? Unsure? -> execute command git pull --rebase upstream master
------------------------------
You can view, comment on, or merge this pull request online at:
#255
Commit Summary
- 9e2a1dd
<9e2a1dd>
SDK-321: Optimizing SDK Cache Management
File Changes
(5 files <https://github.com/openmrs/openmrs-sdk/pull/255/files>)
- *M*
maven-plugin/src/main/java/org/openmrs/maven/plugins/SetupSDK.java
<https://github.com/openmrs/openmrs-sdk/pull/255/files#diff-20401bf5b076fe51b23973f37b44022b5acff19d4cde389befa6e56c7e68a81a>
(12)
- *M*
maven-plugin/src/main/java/org/openmrs/maven/plugins/utility/NodeHelper.java
<https://github.com/openmrs/openmrs-sdk/pull/255/files#diff-5d26fc863281dda12d77af873dc4e40e83ad5f98daf37ce8ef292da97dabc3dc>
(48)
- *M*
maven-plugin/src/main/java/org/openmrs/maven/plugins/utility/SpaInstaller.java
<https://github.com/openmrs/openmrs-sdk/pull/255/files#diff-e90c9e5e322d90165e0236bb5ea86ea79a8fdc53a9d374c4291418bc95982fb8>
(19)
- *M* pom.xml
<https://github.com/openmrs/openmrs-sdk/pull/255/files#diff-9c5fb3d1b7e3b0f54bc5c4182965c4fe1f9023d449017cece3005d3f90e8e4d8>
(7)
- *M*
sdk-commons/src/main/java/org/openmrs/maven/plugins/utility/PropertiesUtils.java
<https://github.com/openmrs/openmrs-sdk/pull/255/files#diff-1521ea06c40e43b7e609c6a2f57bb03e2fdbba3264bcb9550475eea60f29d11a>
(39)
Patch Links:
- https://github.com/openmrs/openmrs-sdk/pull/255.patch
- https://github.com/openmrs/openmrs-sdk/pull/255.diff
—
Reply to this email directly, view it on GitHub
<#255>, or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ABB2CWVNLCSLULXFNPRGJPDX3KXF5ANCNFSM6AAAAAA47SIGLQ>
.
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
|
@@ -33,6 +36,7 @@ | |||
public class PropertiesUtils { | |||
|
|||
private static final Logger log = LoggerFactory.getLogger(PropertiesUtils.class); | |||
private static final String SDK_PROPERTIES_FILE = "SDK Properties file"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this just be something like sdk.properties
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When writing the SDK properties to the files using Properties#store(java.io.OutputStream, java.lang.String) we have to pass a comment. This comment is used as the heading of the file. I renamed the variable name to eliminate any confusion. The actual file name of the properties file is "sdk.properties".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then the constant name would be less confusing if it reflected that in one way or another like SDK_PROPERTIES_FILE_HEADER. Or just get rid of the constant because after all, you use it in only one place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public static void savePropertiesChangesToFile(Properties properties, File file) | ||
throws MojoExecutionException { | ||
try (OutputStream fos = new FileOutputStream(file)) { | ||
properties.store(fos, SDK_PROPERTIES_FILE + ":"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the use of the full colon at the end of this comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed the colon.
Description of what I changed
Add the enableDataSaving parameter to the setup-sdk plugin. This parameter enables the data-saving mode. When using this mode, the SDK will reuse the existing cache folder rather than creating a new one.
In normal mode, SDK will remove the cache folder after running the setup.
Issue I worked on
see https://issues.openmrs.org/browse/SDK-321
Checklist: I completed these to help reviewers :)
My IDE is configured to follow the code style of this project.
No? Unsure? -> configure your IDE, format the code and add the changes with
git add . && git commit --amend
I have added tests to cover my changes. (If you refactored
existing code that was well tested you do not have to add tests)
No? -> write tests and add them to this commit
git add . && git commit --amend
I ran
mvn clean install
right before creating this pull request andadded all formatting changes to my commit.
No? -> execute the above command
All new and existing tests passed.
No? -> figure out why and add the fix to your commit. It is your responsibility to make sure your code works.
My pull request is based on the latest changes of the master branch.
No? Unsure? -> execute command
git pull --rebase upstream master