Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

File Based Storage Provider#9537

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Draft
BernhardPollerspoeck wants to merge1 commit intodotnet:main
base:main
Choose a base branch
Loading
fromBernhardPollerspoeck:FileStorageProvider

Conversation

@BernhardPollerspoeck
Copy link

@BernhardPollerspoeckBernhardPollerspoeck commentedJun 2, 2025
edited by dotnet-policy-servicebot
Loading

This pull request introduces a new file-based grain storage provider for Microsoft Orleans. The changes include adding a new project for the provider, implementing its core functionality, and providing documentation and configuration examples.

New File-Based Grain Storage Provider

Project Setup:

  • Added a new projectOrleans.Persistence.FileStorage to the solution with the necessary project references and metadata (Orleans.sln,src/File/Orleans.Persistence.FileStorage/Orleans.Persistence.FileStorage.csproj)[1][2].

Core Implementation:

  • Implemented theFileGrainStorage class, which provides methods for reading, writing, and clearing grain state using a file-based approach (src/File/Orleans.Persistence.FileStorage/FileGrainStorage.cs).
  • Added a factory classFileGrainStorageFactory to create instances ofFileGrainStorage (src/File/Orleans.Persistence.FileStorage/FileGrainStorageFactory.cs).
  • CreatedFileGrainStorageOptions to configure the root directory and serializer for the storage provider (src/File/Orleans.Persistence.FileStorage/FileGrainStorageOptions.cs).
  • Added extension methods inFileSiloBuilderExtensions to simplify the configuration of the file storage provider in Orleans silo builders (src/File/Orleans.Persistence.FileStorage/FileSiloBuilderExtensions.cs).

Documentation and Examples:

  • Added aREADME.md file with an introduction, setup instructions, and examples for configuring and using the file storage provider (src/File/Orleans.Persistence.FileStorage/README.md).
Microsoft Reviewers:Open in CodeFlow

Jaah reacted with thumbs up emoji
@BernhardPollerspoeck
Copy link
Author

@dotnet-policy-service agree

@shacal
Copy link

👍🏻

Directory.CreateDirectory(Path.GetDirectoryName(path)!);
}
var fileInfo = new FileInfo(path);
if (fileInfo.Exists && fileInfo.LastWriteTimeUtc.ToString(CultureInfo.InvariantCulture) != grainState.ETag)

Choose a reason for hiding this comment

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

File date information can be Pita when used by file shares/zfs etc.

Option for sha256 or custom providers would allow sifferent kind of consistency checks.

Some filesystems allow to have hash build in and some have metadata/tags that allows this to be better for production.

BernhardPollerspoeck reacted with thumbs up emoji

public sealed class FileGrainStorageOptions : IStorageProviderSerializerOptions
{
#region properties

Choose a reason for hiding this comment

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

For a love of devs, do not use regions 👏

var storedData = options.GrainStorageSerializer.Serialize(grainState.State);
var fName = GetKeyString(stateName, grainId);
var path = Path.Combine(options.RootDirectory, fName!);
if (!Directory.Exists(path))

Choose a reason for hiding this comment

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

This sync call will destroy some sharing services.
I suggest that try use it, if fails, then try create folder.

This is more ops per write than "normally" needed.

Copy link
Contributor

Choose a reason for hiding this comment

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

I mentioned this in discord, and wanted to note it here for anyone else looking at this PR. We did something similar and
getting the semantics for a file system storage provider is tricky because:

  • File systems are implemented differently, and you have to be sure the subset of functionality you are using is robust across all of them - including when you add NFS or SMB into the mix too, what do they each guarantee in terms of data integrity?
  • Writes are not atomic, if your program or OS crashes midway through overwriting grain state, you are left in a non-deterministic possibly corrupt state.
  • LastWriteTimeUtc may not be accurate - caching, lazy metadata writes could affect it - seehttps://learn.microsoft.com/en-us/dotnet/api/system.io.filesysteminfo.lastwritetimeutc?view=net-9.0#remarks
  • It's possible for two identical grains to be active during a split-brain scenario so you cannot rely on reading last write time then writing because that allows a race-condition.
  • On Linux (as of .NET 9.0) there are no truly asynchronous file operations - all the async ones are implemented as synchronous queued on the threadpool, so you need to be careful not to flood the threadpool with thread stalling sync work during grain activation storage reads.

All these problems can be worked around, and I think it's important to do so because you are dealing with storage and people will trust it to reliably persist their precious data.

We went through several iterations for a log-based storage provider and we settled on was:

  • use exclusive file locking (and we test this works on the base path specified on initialization, because if not all bets are off) - and handle the specific IOException HResult (which is different on Windows and *nix) trying to access a locked file
  • append xxHash to the contents of each file to ensure we can detect partial writes/integrity problems - this could maybe also serve as your etag in this scenario
  • always write replacement contents (with a xxHash) to a new deterministically named file and then overwrite the original file ensuring exclusive access to both for the duration.
  • always look for the above deterministically named new file when opening each original file, and resume the replacement operation if it exists.
  • Add a concurrency gate around the async-over-sync file operations and increase the threadpool size by the concurrency gate limit, to ensure the threadpool has adequate capacity for our file operations.
  • Ensure file handle lifetime is short if the number of concurrent handles might become a problem (some storage stacks have limits)
  • Make sure you are not going to run into inode exhaustion based on how you store your files especially for EXT volumes it seems.

With the above mitigated we have processed a few billion storage operations on the file system now - but we are still only using this for data that can be replaced.

@BernhardPollerspoeck
Copy link
Author

I need to find the time to get more information about your suggested changes. i am not that deep into the details you mention and i dont want to submit changes i dont understand.
@shacal@willg1983

@galvesribeiro
Copy link
Member

Hey! Interesting.

Is this meant to be used in a single silo or by having shared storage like NFS/SMB/EFS? Or do you plan on have some sort of replication/synchronization/distributed locking on the files itself?

I'm interested on what would happen when silos are scaled. Can you elaborate more on that on the PR itself and/or the README you added?

Thanks!

@BernhardPollerspoeck
Copy link
Author

Hey@galvesribeiro,

in the beginning it was meant to be some more single silo or on prem local smaller solution. I got a few great comments for possible improvements, but they maybe just dont match what this storage provider wants to be. Im gonna need to think and have some talks with@ReubenBond and his team on what we really should aim for.
I had some really bad lack of time but i hope in the course of this week its getting easier and then i plan on getting this PR ready for review.

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

Reviewers

Copilot code reviewCopilotAwaiting requested review from CopilotCopilot will automatically review once the pull request is marked ready for review

2 more reviewers

@shacalshacalshacal left review comments

@willg1983willg1983willg1983 left review comments

Reviewers whose approvals may not affect merge requirements

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

4 participants

@BernhardPollerspoeck@shacal@galvesribeiro@willg1983

[8]ページ先頭

©2009-2025 Movatter.jp