wabbajack/Wabbajack.Common/Util/DiskSlabAllocator.cs

71 lines
2.1 KiB
C#
Raw Normal View History

using System;
2020-04-03 03:57:59 +00:00
using System.Collections.Generic;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Threading.Tasks;
namespace Wabbajack.Common
{
/// <summary>
/// Memory allocator that stores data via memory mapping to a on-disk file. Disposing of this object
/// deletes the memory mapped file
/// </summary>
public class DiskSlabAllocator : IAsyncDisposable
{
2020-07-20 01:19:56 +00:00
private TempFile? _file;
private MemoryMappedFile? _mmap;
private long _head = 0;
2020-07-20 01:19:56 +00:00
private FileStream? _fileStream;
private List<IAsyncDisposable> _allocated = new List<IAsyncDisposable>();
2020-04-03 03:57:59 +00:00
private long _size;
2020-07-20 01:19:56 +00:00
private DiskSlabAllocator()
{
2020-07-20 01:19:56 +00:00
}
public static async Task<DiskSlabAllocator> Create(long size)
{
var file = new TempFile();
var fileStream = await file.Path.Create();
2020-07-20 01:24:30 +00:00
size = Math.Max(size, 1024);
2020-07-20 01:19:56 +00:00
var self = new DiskSlabAllocator
{
_file = file,
2020-07-20 01:24:30 +00:00
_size = size,
2020-07-20 01:19:56 +00:00
_fileStream = fileStream,
_mmap = MemoryMappedFile.CreateFromFile(fileStream, null, size, MemoryMappedFileAccess.ReadWrite,
HandleInheritability.None, false)
};
return self;
}
public Stream Allocate(long size)
{
lock (this)
{
2020-04-15 11:53:49 +00:00
// This can happen at times due to differences in compression sizes
2020-04-03 03:57:59 +00:00
if (_head + size >= _size)
2020-04-15 11:53:49 +00:00
{
return new MemoryStream();
}
var startAt = _head;
_head += size;
2020-07-20 01:19:56 +00:00
var stream = _mmap!.CreateViewStream(startAt, size, MemoryMappedFileAccess.ReadWrite);
2020-04-03 03:57:59 +00:00
_allocated.Add(stream);
return stream;
}
}
public async ValueTask DisposeAsync()
{
foreach (var allocated in _allocated)
await allocated.DisposeAsync();
2020-07-20 01:19:56 +00:00
_mmap!.Dispose();
await _fileStream!.DisposeAsync();
await _file!.DisposeAsync();
}
}
}