2020-03-05 00:02:16 +00:00
|
|
|
|
using System;
|
2020-04-03 03:57:59 +00:00
|
|
|
|
using System.Collections.Generic;
|
2020-03-05 00:02:16 +00:00
|
|
|
|
using System.IO;
|
|
|
|
|
using System.IO.MemoryMappedFiles;
|
2020-05-28 02:43:57 +00:00
|
|
|
|
using System.Threading.Tasks;
|
2020-03-05 00:02:16 +00:00
|
|
|
|
|
|
|
|
|
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>
|
2020-05-28 02:43:57 +00:00
|
|
|
|
public class DiskSlabAllocator : IAsyncDisposable
|
2020-03-05 00:02:16 +00:00
|
|
|
|
{
|
2020-07-20 01:19:56 +00:00
|
|
|
|
private TempFile? _file;
|
|
|
|
|
private MemoryMappedFile? _mmap;
|
2020-03-05 00:02:16 +00:00
|
|
|
|
private long _head = 0;
|
2020-07-20 01:19:56 +00:00
|
|
|
|
private FileStream? _fileStream;
|
2020-05-28 02:43:57 +00:00
|
|
|
|
private List<IAsyncDisposable> _allocated = new List<IAsyncDisposable>();
|
2020-04-03 03:57:59 +00:00
|
|
|
|
private long _size;
|
2020-03-05 00:02:16 +00:00
|
|
|
|
|
2020-07-20 01:19:56 +00:00
|
|
|
|
private DiskSlabAllocator()
|
2020-03-05 00:02:16 +00:00
|
|
|
|
{
|
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;
|
2020-03-05 00:02:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-05 00:02:16 +00:00
|
|
|
|
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;
|
2020-03-05 00:02:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-28 02:43:57 +00:00
|
|
|
|
public async ValueTask DisposeAsync()
|
2020-03-05 00:02:16 +00:00
|
|
|
|
{
|
2020-05-28 02:43:57 +00:00
|
|
|
|
foreach (var allocated in _allocated)
|
|
|
|
|
await allocated.DisposeAsync();
|
2020-07-20 01:19:56 +00:00
|
|
|
|
_mmap!.Dispose();
|
|
|
|
|
await _fileStream!.DisposeAsync();
|
|
|
|
|
await _file!.DisposeAsync();
|
2020-03-05 00:02:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|