Darren
Darren

Reputation: 577

MemoryMappedFiles.MemoryMappedFile.CreateFromFile won't extend a file under linux/mono

Under windows, this F# code will extend a file from say 12 bytes out to 655346 bytes when the capacity argument (last argument) is set to a larger size than the underlying file. This seems to be the cleanest way to extend a memory mapped file. Under mono / linux it throws an ArgumentException: capacity unless the file is as long as the mapped capacity. Is there a clean way to get mono to extend the file or do I have to preextend the file before I can map?

let Main () =
    let path = "parts.pash"
    let l = 65536L
    let mm =    MemoryMappedFiles.MemoryMappedFile.CreateFromFile(path,FileMode.OpenOrCreate,"pashmap",l)

    ()

Main()

Error message

Unhandled Exception: System.ArgumentException: capacity at System.IO.MemoryMappedFiles.MemoryMappedFile.CreateFromFile (System.String path, FileMode mode, System.String mapName, Int64 capacity, MemoryMappedFileAccess access) [0x00000] in :0 at System.IO.MemoryMappedFiles.MemoryMappedFile.CreateFromFile (System.String path, FileMode mode, System.String mapName, Int64 capacity) [0x00000] in :0 at Program.Main () [0x00000] in :0 at .$Program.main@ () [0x00000] in :0

Version of mono:

[daz@clowder pash]$ mono --version
Mono JIT compiler version 2.10.1 (tarball Mon Apr  4 10:40:52 PDT 2011)
Copyright (C) 2002-2011 Novell, Inc and Contributors. www.mono-project.com
        TLS:           __thread
        SIGSEGV:       altstack
        Notifications: epoll
        Architecture:  x86
        Disabled:      none
        Misc:          softdebug
        LLVM:          supported, not enabled.
        GC:            Included Boehm (with typed GC and Parallel Mark)

EDIT: it appears that the different underlying behaviour of memory mapping is exposed in the API so you need to extend the file yourself to the right length to be platform neutral

let f = File.Open(path,FileMode.Append,FileAccess.Write)
let pad = l- FileInfo(path).Length
let padding = Array.create (int32 pad) 0uy
f.Write(padding,0,int pad)
f.Close()

Upvotes: 6

Views: 872

Answers (2)

Andrew McKinlay
Andrew McKinlay

Reputation: 2631

Rather than allocating a potentially large array, and then writing it, it's probably more efficient to seek. I'm not sure of the F# code, but in C# you'd do something like:

 filestream.Seek(length - 1, SeekOrigin.Begin);
 filestream.WriteByte(0);

With Mono 2.10.8 on Mac OS X seeking by itself was not sufficient, I had to write at least one byte, despite the MSDN documentation for FileStream.Seek saying that it will extend the file.

It seems like Mono could do something similar in their MemoryMappedFile implementation to make it more compatible with .Net on Windows.

Upvotes: 0

Guvante
Guvante

Reputation: 19203

Looking at the .NET implementation of CreateFromFile there is no implementation of that functionality. Other than argument checking, it is a slim wrapper around the Windows API call from what I can tell.

For this reason the ability to create a larger file is more of a happy coincidence from the .NET land, so it is no surprise that Mono removed that ability if the underlying operating system does not allow similar functionality.

Put more simply, not likely, since the .NET version doesn't technically extend the file either, the Windows API does.

Upvotes: 4

Related Questions