# following https://support.hdfgroup.org/HDF5/doc/RM/RM_H5F.html#File-StartSwmrWrite # and https://support.hdfgroup.org/HDF5/docNewFeatures/SWMR/HDF5_SWMR_Users_Guide.pdf using HDF5 using Test using Distributed if nprocs() == 1 procs = addprocs(1) else procs = Int64[] end @everywhere using HDF5 @testset "swmr" begin fname = tempname() @testset "swmr modes" begin h5open(fname, "w"; swmr=true) do h5 h5["foo"] = collect(1:10) end h5open(fname, "r"; swmr=true) do h5 @test read(h5["foo"]) == collect(1:10) end h5open(fname, "r+"; swmr=true) do h5 @test read(h5["foo"]) == collect(1:10) end end @testset "h5d_oappend" begin h5open(fname, "w") do h5 g = create_group(h5, "shoe") d = create_dataset(g, "bar", datatype(Float64), ((1,), (-1,)); chunk=(100,)) dxpl_id = HDF5.get_create_properties(d) v = [1.0, 2.0] memtype = datatype(Float64) # @test HDF5.h5d_oappend(d, dxpl_id, 0, length(v), memtype, v) end end function dataset_write(d, ch_written, ch_read) for i in 1:10 @assert take!(ch_read) == true HDF5.set_extent_dims(d, (i * 10,)) inds::UnitRange{Int} = (1:10) .+ (i - 1) * 10 d[inds] = inds flush(d) # flush the dataset put!(ch_written, i) end end @everywhere function dataset_read(d, ch_written, ch_read) n = nlast = length(d) nbigger = 0 i = 0 put!(ch_read, true) while n < 100 i = take!(ch_written) for j in 1:1000 # wait for new data to be available to avoid CI failures HDF5.refresh(d) nlast, n = n, length(d) n > nlast && break sleep(0.001) end vals = read(d) @assert vals == collect(1:n) n > nlast && (nbigger += 1) put!(ch_read, true) end return nbigger end @everywhere function swmr_reader(fname, ch_written, ch_read) h5open(fname, "r"; swmr=true) do h5 d = h5["foo"] dataset_read(d, ch_written, ch_read) end end # Spawn a reader function in a 2nd process, provide two channels for synchronization. # Run a writing function in this process. The writing function writes, # then notifies `ch_read`, then the reading function reads, and notifies `ch_read`. So read # attempts should always follow writes, though there may be a delay before the data is available # so there is a step that sleeps until data is available. function remote_test(h5) ch_written, ch_read = RemoteChannel(1), RemoteChannel(1) a = @spawn(swmr_reader(fname, ch_written, ch_read)) dataset_write(h5["foo"], ch_written, ch_read) nbigger = fetch(a) @test nbigger == 10 end # create datasets and attributes before staring swmr writing function prep_h5_file(h5) d = create_dataset(h5, "foo", datatype(Int), ((1,), (100,)); chunk=(1,)) attributes(h5)["bar"] = "bar" g = create_group(h5, "group") end @testset "create by libver, then start_swmr_write" begin #test this h5open method with keyword arg h5open(fname, "w"; libver_bounds=(:latest, :latest), swmr=false) do h5 prep_h5_file(h5) HDF5.start_swmr_write(h5) # after creating datasets remote_test(h5) end end @testset "create by swmr mode, then close and open again" begin h5open(fname, "w"; swmr=true) do h5 prep_h5_file(h5) end # close the file after creating datasets, open again with swmr write access but not truncate h5open(fname, "r+"; swmr=true) do h5 remote_test(h5) end end rm(fname) # cleanup file created by swmr tests if nprocs() > 1 rmprocs(procs) end end # testset swmr