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

Fix mmap support for windows #545

Merged
merged 3 commits into from
Apr 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 44 additions & 11 deletions src/HDF5.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1598,26 +1598,58 @@ function readmmap(obj::HDF5Dataset, ::Type{Array{T}}) where {T}
if isempty(dims)
return T[]
end
local fd
prop = h5d_get_access_plist(checkvalid(obj).id)
try
ret = Ptr{Cint}[0]
h5f_get_vfd_handle(obj.file.id, prop, ret)
fd = unsafe_load(ret[1])
finally
HDF5.h5p_close(prop)
if !Sys.iswindows()
local fdint
prop = h5d_get_access_plist(checkvalid(obj).id)
try
ret = Ptr{Cint}[0]
h5f_get_vfd_handle(obj.file.id, prop, ret)
fdint = unsafe_load(ret[1])
finally
HDF5.h5p_close(prop)
end
fd = fdio(fdint)
else
# This is a workaround since the regular code path does not work on windows
# (see #89 for background). The error is that "Mmap.mmap(fd, ...)" cannot
# create create a valid file mapping. The question is if the handler
# returned by "h5f_get_vfd_handle" has
# the correct format as required by the "fdio" function. The former
# calls
# https://gitlabext.iag.uni-stuttgart.de/libs/hdf5/blob/develop/src/H5FDcore.c#L1209
#
# The workaround is to create a new file handle, which should actually
# not make any problems. Since we need to know the permissions of the
# original file handle, we first retrieve them using the "h5f_get_intend"
# function

# Check permissions
intent = Ref{Cuint}()
h5f_get_intend(obj.file, intent)
if intent[] == HDF5.H5F_ACC_RDONLY || intent[] == HDF5.H5F_ACC_RDONLY
flag = "r"
else
flag = "r+"
end
fd = open(obj.file.filename, flag)
end

offset = h5d_get_offset(obj.id)
if offset == reinterpret(Hsize, convert(Hssize, -1))
error("Error mmapping array")
end
if offset % Base.datatype_alignment(T) == 0
return Mmap.mmap(fdio(fd), Array{T,length(dims)}, dims, offset)
A = Mmap.mmap(fd, Array{T,length(dims)}, dims, offset)
else
A = Mmap.mmap(fdio(fd), Array{UInt8,1}, prod(dims)*sizeof(T), offset)
return reshape(reinterpret(T,A),dims)
Aflat = Mmap.mmap(fd, Array{UInt8,1}, prod(dims)*sizeof(T), offset)
A = reshape(reinterpret(T, Aflat), dims)
end

if Sys.iswindows()
close(fd)
end

return A
end

function readmmap(obj::HDF5Dataset)
Expand Down Expand Up @@ -2098,6 +2130,7 @@ for (jlname, h5name, outtype, argtypes, argsyms, msg) in
(:h5f_flush, :H5Fflush, Herr, (Hid, Cint), (:object_id, :scope,), "Error flushing object to file"),
(:hf5start_swmr_write, :H5Fstart_swmr_write, Herr, (Hid,), (:id,), "Error starting SWMR write"),
(:h5f_get_vfd_handle, :H5Fget_vfd_handle, Herr, (Hid, Hid, Ptr{Ptr{Cint}}), (:file_id, :fapl_id, :file_handle), "Error getting VFD handle"),
(:h5f_get_intend, :H5Fget_intent, Herr, (Hid, Ptr{Cuint}), (:file_id, :intent), "Error getting file intent"),
(:h5g_close, :H5Gclose, Herr, (Hid,), (:group_id,), "Error closing group"),
(:h5g_get_info, :H5Gget_info, Herr, (Hid, Ptr{H5Ginfo}), (:group_id, :buf), "Error getting group info"),
(:h5o_get_info, :H5Oget_info1, Herr, (Hid, Ptr{H5Oinfo}), (:object_id, :buf), "Error getting object info"),
Expand Down
17 changes: 12 additions & 5 deletions test/mmap.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,19 @@ f = h5open(fn, "w")
hdf5_A = d_create(f,"A",datatype(Int64),dataspace(3,3));
A = rand(Int64,3,3)
hdf5_A[:,:] = A
flush(f);
close(f);
flush(f)
close(f)
# Read HDF5 file & MMAP
f = h5open(fn,"r");
A_mmaped = readmmap(f["A"]);

f = h5open(fn,"r")
A_mmaped = readmmap(f["A"])
@test all(A .== A_mmaped)
# Check that it is read only
@test_throws ReadOnlyMemoryError A_mmaped[1,1] = 33
close(f)
# Now check if we can write
f = h5open(fn,"r+")
A_mmaped = readmmap(f["A"])
A_mmaped[1,1] = 33
close(f)

end
4 changes: 1 addition & 3 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ include("extend_test.jl")
include("gc.jl")
include("external.jl")
include("swmr.jl")
if !Sys.iswindows() # Mmap needs to be fixed on windows
include("mmap.jl")
end
include("mmap.jl")
if get(Pkg.installed(), "MPI", nothing) !== nothing
# basic MPI tests, for actual parallel tests we need to run in MPI mode
include("mpio.jl")
Expand Down