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

#265 Update MemoryMappedPageManager memory mapped initiation #388

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

ssonthal
Copy link
Contributor

#265

Two changes:

  1. Creating the MemoryMappedFile without setting the total file size upfront

_mapped = MemoryMappedFile.CreateFromFile(_file, null, 0, MemoryMappedFileAccess.ReadWrite, HandleInheritability.None, true);

  1. Instead of mapping the whole file, mapping only a portion of it dynamically as needed

_whole = _mapped.CreateViewAccessor(0, historyDepth * Page.PageSize);

@ssonthal
Copy link
Contributor Author

Hi @Scooletz, pls let me know if these changes are in the right direction.

Copy link
Contributor

@Scooletz Scooletz left a comment

Choose a reason for hiding this comment

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

Provided comments. I don't understand how this could work without significant changes or using the NT method mentioned in the referred issue. Maybe we should add some tests for the MemoryMappedPageManager to ensure that it works properly? Also, add some matrix for OS dependent tests?

HandleInheritability.None, true);

_whole = _mapped.CreateViewAccessor();
_whole = _mapped.CreateViewAccessor(0, historyDepth * Page.PageSize);
Copy link
Contributor

Choose a reason for hiding this comment

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

The _whole is used as both, the view to ForceFlush when a synchronization happens and as an accessor that provides the pointer _ptr for the whole file. This is why it was set to cover whole file.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can we introduce a new variable called _viewAccessor for accessing the memory mapped portion as a pointer. And use _whole as it is for ForceFlush?

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not following. ForceFlush semantics should be that all the pages that were allocated are flushed down and then FSYNC is called. I believe we could create a one time use accessor and flush it. This might work.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You mean, inside the ForceFlush method, we can get another accessor for _file that covers the whole file and flush it?

@@ -61,11 +61,9 @@ public unsafe MemoryMappedPageManager(long size, byte historyDepth, string dir,
_file = new FileStream(Path, FileMode.Open, FileAccess.ReadWrite, FileShare.None, 4096,
PaprikaFileOptions);
}
_mapped = MemoryMappedFile.CreateFromFile(_file, null, 0, MemoryMappedFileAccess.ReadWrite, HandleInheritability.None, true);
Copy link
Contributor

Choose a reason for hiding this comment

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

AFAIK, the mapping will get size from the _file, but if the file is just created, it won't work as expected as one will need to set the length. I don't understand how this should work.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

what if we remove this line -

_file.setLength(size);

while creating a new file. We can set it to some safe initial size.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't know how to answer. We may do all the things as long as the file is properly mapped and written and flushed 😅

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Would you recommend -

  1. initialize the _file with an initial size of say, 4 MB.
  2. modifying the write and flush operations in a way it first checks the size of the _file and only if it's large enough to store incoming data, proceed as it is. Otherwise, can double the file size until it can accommodate incoming data.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Would you recommend -

  1. initialize the _file with an initial size of say, 4 MB.
  2. modifying the write and flush operations in a way it first checks the size of the _file and only if it's large enough to store incoming data, proceed as it is. Otherwise, can double the file size until it can accommodate incoming data.

@Scooletz What do you think about this approach?

@ssonthal
Copy link
Contributor Author

ssonthal commented Sep 11, 2024

Provided comments. I don't understand how this could work without significant changes or using the NT method mentioned in the referred issue. Maybe we should add some tests for the MemoryMappedPageManager to ensure that it works properly? Also, add some matrix for OS dependent tests?

I read somewhere that the .NET memory-mapped file API abstracts the complexity of memory management, so we don’t need to use lower-level functions like NtCreateSection in C#.

Might be completely wrong here.

Do you suggest using ntdll.dll and create a custom class like this to get the same behavior as lmdb? -

public static class NativeMethods
{
    [DllImport("ntdll.dll")]
    public static extern NTSTATUS NtCreateSection(
        out IntPtr SectionHandle,
        ACCESS_MASK DesiredAccess,
        ref OBJECT_ATTRIBUTES ObjectAttributes,
        ref LARGE_INTEGER MaximumSize,
        uint SectionPageProtection,
        uint AllocationAttributes,
        IntPtr FileHandle);
}

Although since ntdll.dll is an unmanaged dll, on Linux machines, it will not work.

@Scooletz
Copy link
Contributor

Although since ntdll.dll is an unmanaged dll, on Linux machines, it will not work.

The issue is pure Windows issue (see #265 that you linked). On Linux, mmap behaves nicely not preallocating whole file up front. The only method that I partially investigated was the mentioned NtCreateSection, but it might be the case that there are other ways. One way or the other, the crux is that on Windows it bloats to the file size defined at the beginning.

@Scooletz
Copy link
Contributor

Any comments @shubham-sonthalia ?

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.

2 participants