Skip to content

Commit

Permalink
Merge 42f21a6 into 0cf7049
Browse files Browse the repository at this point in the history
  • Loading branch information
tknopp committed Apr 23, 2019
2 parents 0cf7049 + 42f21a6 commit 92dbbf6
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 19 deletions.
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

0 comments on commit 92dbbf6

Please sign in to comment.