-
Notifications
You must be signed in to change notification settings - Fork 22
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
provide a scratchspace for AtlasRep data if necessary #1026
provide a scratchspace for AtlasRep data if necessary #1026
Conversation
If AtlasRep does not know a writable directory for downloaded data, i.e., if the value of its user preference AtlasRepDataDirectory is an empty string, provide a scratchspace and adjust the user preference. For that, we check for the empty string when GAP has been started (which may trigger that AtlasRep gets loaded) and in `GAP.Packages.load` calls. Thus this mechanism will fail if one starts GAP without packages and then loads GAP packages only via the GAP function `LoadPackage`.
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1026 +/- ##
==========================================
+ Coverage 75.77% 75.83% +0.05%
==========================================
Files 51 51
Lines 4182 4204 +22
==========================================
+ Hits 3169 3188 +19
- Misses 1013 1016 +3
|
The feature proposed here is relevant if the computed default for (In my installation, the directories in question are in fact writable, thus the problem of an empty computed default for The proposed change means that we may ignore the user's intention not to store downloaded files, by setting |
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.
Thank you!
# and AtlasRep. | ||
|
||
# The path to the scratchspace, will be filled by `init_atlasrep()` | ||
atlasrep_download_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.
This is type unstable. Better is something like this:
const atlasrep_download_cache = Ref{String}()
...
!isassigned(atlasrep_download_cache) || return
...
atlasrep_download_cache[] = String(val)
and so on.
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.
O.k.
(I had just copied the code from the example in Scratch.jl.)
atlasrep = GapObj("atlasrep") | ||
AtlasRepDataDirectory = GapObj("AtlasRepDataDirectory") | ||
val = Wrappers.UserPreference(atlasrep, AtlasRepDataDirectory) | ||
if Wrappers.IsString(val) |
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 it is not a string, then I think the only other value (baring a mistake in gap.ini
) is fail
, which means AtlasRep is not loaded yet and the user did not set a preference.
So isn't that a situation in which we should provide a path, too?
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.
Ideally, if AtlasRep does not get loaded at all then GAP.jl need not create a scratchspace at all.
As long as the preference AtlasRepDataDirectory
is not set (value fail
), we need not provide a default for 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.
But creating a scratch space is super cheap. If the price for avoiding it is complicated and error-prone logic to detect whether the scratch space is really needed, I would just forget about that and always create the scratch space.
val = Wrappers.UserPreference(atlasrep, AtlasRepDataDirectory) | ||
if Wrappers.IsString(val) | ||
# A default is set. | ||
if length(val) == 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.
I did some tests with plain GAP locally: if I have no AtlasRepDataDirectory
user pref set, and start a regular GAP session which auto-loads atlasrep, then AtlasRepDataDirectory
is set to a default value (a path inside the atlasrep package directory).
So if I read it right, then with atlasrep autoloaded (which is the case right now with GAP.jl), this code would be never triggered?!
Can we perhaps instead somehow distinguish between "the user set a value (so honor that)" and "some kind of default value that we should override". E.g. perhaps one way to do that would be to perform just that check in gap/systemfile.g
(so that it is run before any packages are loaded), i.e. basically: check if UserPreference("atlasrep", "AtlasRepDataDirectory")
returns a value different from fail
or not.
Anyway, another potential issue: What if we set a path to a scratch dir, but then the user calls WriteGapIniFile
. Then the scratch path is put into the resulting gap.ini
-- but it may be invalid the next time we run (and load gap.ini
). So perhaps we need some logic that detects if the AtlasRepDataDirectory
value "looks like a Julia scratch space path", and in that case, update it anyway?
In closing, I think for 99.9% of all users, they are not aware of this setting and don't care about it and with that in mind the simples solution would be to just call SetUserPreference
unconditionally... but I realize this is annoying for a handful of power users (such as yourself), so I guess we can't really do that.
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.
- The computed default for
AtlasRepDataDirectory
is a path inside the package directory if this is writable, and in this case I want to keep this default. - Also in the case that the
gap.ini
file sets a path (such that no computed default gets set), I want to keep this path because the user wants it. - If the path is not writable (which will happen if the artifact in question is read-only --currently it seems to be writable) then the computed default is an empty string (meaning that downloaded data are not cached), and then the idea is that GAP.jl can provide a scratchspace as a way to enable caching.
Accidentally storing the path to the scratchspace in a gap.ini
file is an issue, good point.
More generally, we can override any value of AtlasRepDataDirectory
that is not a valid (writable) directory path.
What I had mentioned already is that the currently proposed code ignores that a user may set an empty string in order to disable caching. One solution would be to check in the case of an empty string whether the package directory is writable, and if yes to conclude that the empty string is intentional, and to keep it.
Concerning the fact that the replacement of the default does not get triggered if one starts GAP without packages and later on loads GAP packages only on the GAP side, we could argue that the situation is not worse as it was before, and if one does not use the features from the Julia side than one does not get its advantages.
(I had thought whether a clean solution would be to put the relevant Julia code into the function for the default computation in AtlasRep's PackageInfo.g
file. This would remove the problem that one might load all packages only with GAP's LoadPackage
. The problem with the scratchspace path stored in gap.ini
cannot be solved then, but it could be documented in AtlasRep that storing the computed value is not a good idea.)
# If the AtlasRep package is loaded afterwards (perhaps indirectly) | ||
# then provide its scratchspace if necessary. | ||
if atlasrep_download_cache == "" && Wrappers.IsPackageLoaded(GapObj("AtlasRep")) | ||
init_atlasrep() |
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.
This will not catch the cases were a user calls GAP code that does LoadPackage("atlasrep")
.
I don't think we need this if we call SetUserPreference
earlier and in more cases, see below.
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 we set the value of the preference before AtlasRep gets loaded then we have to set it unconditionally, and create the scratchspace even if the package will not be loaded.
I am not sure how to deal with several available package versions: As long as the package is not loaded, we do not know which version will be loaded, and there is only one path which we can set.
Coming back to the idea to move the code to the GAP side, here is GAP code for the function()
local val, dir, julia, subdir, file;
# In general, the default of a user preference gets computed
# also if a value is already stored.
# (This can be regarded as a bug in the handling of user preferences.)
# Here we return a stored value without running the computation.
val:= UserPreference( "AtlasRep", "AtlasRepDataDirectory" );
if val <> fail then
return val;
fi;
dir:= DirectoriesPackageLibrary( "atlasrep", "" );
if ForAll( [ "dataext", "datagens", "dataword" ],
subdir -> IsWritableFile( Filename( dir, subdir ) ) ) then
# The package directory is the first default.
return Filename( dir, "" );
elif IsPackageLoaded( "JuliaInterface" ) then
# Create/fetch a Julia scratchspace.
ValueGlobal( "JuliaImportPackage" )( "Scratch" );
julia:= ValueGlobal( "Julia" );
val:= julia.Scratch.( "get_scratch!" )( julia.GAP,
julia.String( "atlasrep_cache" ) );
val:= julia.GAP.GapObj( val );
if not IsDirectoryPath( val ) then
# Something went wrong.
return "";
fi;
# Create writable subdirectories if necessary.
dir:= Directory( val );
for subdir in [ "datagens", "dataword", "dataext" ] do
file:= Filename( dir, subdir );
if not IsDirectoryPath( file ) then
CreateDir( file );
fi;
od;
return val;
else
return "";
fi;
end; This changed function makes the current pull request obsolete. |
One more thought: |
I think However we could change GAP.jl to do |
Of course that doesn't solve the immediate problem of supporting this without a new GAP.jl release. I note the following trick:
resp. from GAP:
|
@fingolfin thank you for your comments. Concerning the remark
I do not catch the point.
from your proposal is essentially what Note that the current pull request and the change of the default function in AtlasRep are independent.
|
What you are missing is the issue of scope / of different Julia environments. The fact that GAP.jl's But if you start up The difference between |
@fingolfin Thanks. I have fixed the proposed From this point of view, the current pull request is obsolete: The only improvement that remains for GAP.jl may be the idea to provide a small helper function for simplifying the Julia code in GAP functions that create/fetch Julia scratchspaces, but this can be done in a new pull request. |
With the changed default for the user preference |
If AtlasRep does not know a writable directory for downloaded data, i.e., if the value of its user preference AtlasRepDataDirectory is an empty string, provide a scratchspace and adjust the user preference.
For that, we check for the empty string when GAP has been started (which may trigger that AtlasRep gets loaded)
and in
GAP.Packages.load
calls.Thus this mechanism will fail if one starts GAP without packages and then loads GAP packages only via the GAP function
LoadPackage
.