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.sync! for array mapped from an offset #14885

Merged
merged 1 commit into from
Feb 7, 2016

Conversation

tanmaykm
Copy link
Member

@tanmaykm tanmaykm commented Feb 1, 2016

This fixes error when calling Mmap.sync! on an array that is not memory mapped from a pagesized offset of a file.

julia> using Base.Mmap

julia> f = open("arrayfile", "r+");

julia> A = Mmap.mmap(f, Vector{Int64}, (200,), 0);

julia> Mmap.sync!(A) #works

julia> B = Mmap.mmap(f, Vector{Int64}, (200,), 8);

julia> Mmap.sync!(B) #fails
ERROR: SystemError: msync: Invalid argument
 [inlined code] from ./int.jl:33
 in sync!(Base.Mmap.#sync!, Array{Int64,1}, Int64) at ./mmap.jl:207 (repeats 2 times)
 in eval at ./boot.jl:267

Since Mmap.mmap maps from the beginning of a page boundary, pointer(B) may not be at the page boundary when an offset is provided.

But since the pointer returned from mmap is also aligned at page boundary, sync! now recalculates the offset before calling msync!.

@yuyichao
Copy link
Contributor

yuyichao commented Feb 1, 2016

If you are going to add a test, make sure the offset is properly aligned (to the alignment of the element type) Ref #14551.

@tanmaykm
Copy link
Member Author

tanmaykm commented Feb 1, 2016

Ah Ok. Updated the code snippet above. Will include a test also in a bit.

@tkelman
Copy link
Contributor

tkelman commented Feb 1, 2016

IIRC the page size and allocation granularity are different on windows (edit: line 5)

definitely needs a test

Mmap.sync!(A)
A = Mmap.mmap(s, Vector{UInt8}, (10,), 1);
Mmap.sync!(A)
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clean it up when finished

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done now

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... yes, needed on Windows. Should have noticed it use elsewhere in the tests.
Done now. Thanks!

This fixes error when calling `Mmap.sync!` on an array that is not memory mapped from a pagesized offset of a file.

````
julia> using Base.Mmap

julia> f = open("arrayfile", "r+");

julia> A = Mmap.mmap(f, Vector{Int64}, (200,), 0);

julia> Mmap.sync!(A)

julia> B = Mmap.mmap(f, Vector{Int64}, (200,), 8);

julia> Mmap.sync!(B)
ERROR: SystemError: msync: Invalid argument
 [inlined code] from ./int.jl:33
 in sync!(Base.Mmap.#sync!, Array{Int64,1}, Int64) at ./mmap.jl:207 (repeats 2 times)
 in eval at ./boot.jl:267
````

Since `Mmap.mmap` maps from the beginning of a page boundary, `pointer(A)` is not at the page boundary when an offset is provided.
But since the pointer returned from `mmap` is aligned at page boundary, `sync!` now recalculates the offset before calling `msync!`.

````
julia> using Base.Mmap

julia> f = open("arrayfile", "r+");

julia> B = Mmap.mmap(f, Vector{Int64}, (200,), 8);

julia> Mmap.sync!(B)
````
@tanmaykm
Copy link
Member Author

tanmaykm commented Feb 1, 2016

AppVeyor tests failed.
Tests passed for mmap, but a subsequent test failed on the same worker.
@tkelman could this be causing some memory corruption on Windows as you suspected?

@tanmaykm
Copy link
Member Author

tanmaykm commented Feb 2, 2016

No failures after a retry.
I don't have access to windows resources to do any further checks.
@tkelman ?

@tkelman
Copy link
Contributor

tkelman commented Feb 2, 2016

I'll run this branch locally several times tomorrow and merge if I don't see any trouble. I think the limited memory on appveyor has been triggering all sorts of intermittent issues, especially since the llvm 3.7 and functions merges.

@quinnj
Copy link
Member

quinnj commented Feb 5, 2016

Yeah, I think as long as you force GC after doing Mmap.mmap, that should be all that's necessary on windows. Windows holds some kind of reference to the file when it is mmapped, so we get in trouble if it doesn't get finalized before the file is removed or re-opened.

I'm a little confused on why this is needed; the pointer returned by mmap should be page-aligned, so I don't see how it would need to be page aligned later (see the code here: https://github.com/tanmaykm/julia/blob/fc9fd22181664b4c61c52dfcf973ab919529bf49/base/mmap.jl#L111). Obviously there was something you were hitting, so I'm not doubting there's a fix needed, I'm just not quite following what the issue is here.

@tanmaykm
Copy link
Member Author

tanmaykm commented Feb 6, 2016

@quinnj when the array is being read from an offset that's not page aligned, the pointer to the array is not exactly the pointer that mmap returned. Therefore sync! needs to recalculate the right pointer value to call msync! with.

@tanmaykm
Copy link
Member Author

tanmaykm commented Feb 6, 2016

Also, when the page is dirty, simple unmapping (which happens with gc) doesn't guarantee flushing and invalidation.

@tanmaykm
Copy link
Member Author

tanmaykm commented Feb 7, 2016

I was able to get a Windows machine and test this locally.
It ran fine multiple times without errors or signs of memory corruption.
Will merge this in a while.

@quinnj
Copy link
Member

quinnj commented Feb 7, 2016

Thanks for the response @tanmaykm, that makes sense. LGTM

@tanmaykm
Copy link
Member Author

tanmaykm commented Feb 7, 2016

Thanks for validating @quinnj

tanmaykm added a commit that referenced this pull request Feb 7, 2016
fix Mmap.sync! for array mapped from an offset
@tanmaykm tanmaykm merged commit 350e4da into JuliaLang:master Feb 7, 2016
tkelman pushed a commit that referenced this pull request Sep 13, 2016
This fixes error when calling `Mmap.sync!` on an array that is not memory mapped from a pagesized offset of a file.

````
julia> using Base.Mmap

julia> f = open("arrayfile", "r+");

julia> A = Mmap.mmap(f, Vector{Int64}, (200,), 0);

julia> Mmap.sync!(A)

julia> B = Mmap.mmap(f, Vector{Int64}, (200,), 8);

julia> Mmap.sync!(B)
ERROR: SystemError: msync: Invalid argument
 [inlined code] from ./int.jl:33
 in sync!(Base.Mmap.#sync!, Array{Int64,1}, Int64) at ./mmap.jl:207 (repeats 2 times)
 in eval at ./boot.jl:267
````

Since `Mmap.mmap` maps from the beginning of a page boundary, `pointer(A)` is not at the page boundary when an offset is provided.
But since the pointer returned from `mmap` is aligned at page boundary, `sync!` now recalculates the offset before calling `msync!`.

````
julia> using Base.Mmap

julia> f = open("arrayfile", "r+");

julia> B = Mmap.mmap(f, Vector{Int64}, (200,), 8);

julia> Mmap.sync!(B)
````

(cherry picked from commit fc9fd22)
ref #14885
tanmaykm added a commit to tanmaykm/Blobs.jl that referenced this pull request Sep 22, 2016
JuliaLang/julia#14885 is now backported on to Julia v0.4.7
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants