Make BSA Construction async

This commit is contained in:
Timothy Baldridge 2020-07-19 19:19:56 -06:00
parent 7bc1bcb861
commit 91ae3a716e
10 changed files with 54 additions and 36 deletions

View File

@ -119,7 +119,7 @@ namespace Compression.BSA.Test
TestContext.WriteLine($"Building {bsa}"); TestContext.WriteLine($"Building {bsa}");
await using (var w = ViaJson(a.State).MakeBuilder(size)) await using (var w = await ViaJson(a.State).MakeBuilder(size))
{ {
var streams = await a.Files.PMap(Queue, async file => var streams = await a.Files.PMap(Queue, async file =>
{ {

View File

@ -29,10 +29,10 @@ namespace Compression.BSA
private List<IFileBuilder> _entries = new List<IFileBuilder>(); private List<IFileBuilder> _entries = new List<IFileBuilder>();
private DiskSlabAllocator _slab; private DiskSlabAllocator _slab;
public BA2Builder(BA2StateObject state, long size) public static async Task<BA2Builder> Create(BA2StateObject state, long size)
{ {
_state = state; var self = new BA2Builder {_state = state, _slab = await DiskSlabAllocator.Create(size)};
_slab = new DiskSlabAllocator(size); return self;
} }
public async ValueTask DisposeAsync() public async ValueTask DisposeAsync()

View File

@ -144,9 +144,9 @@ namespace Compression.BSA
public EntryType Type { get; set; } public EntryType Type { get; set; }
public string HeaderMagic { get; set; } public string HeaderMagic { get; set; }
public uint Version { get; set; } public uint Version { get; set; }
public override IBSABuilder MakeBuilder(long size) public override async Task<IBSABuilder> MakeBuilder(long size)
{ {
return new BA2Builder(this, size); return await BA2Builder.Create(this, size);
} }
} }

View File

@ -26,18 +26,24 @@ namespace Compression.BSA
internal uint _version; internal uint _version;
internal DiskSlabAllocator _slab; internal DiskSlabAllocator _slab;
public BSABuilder(long size) public static async Task<BSABuilder> Create(long size)
{ {
_fileId = Encoding.ASCII.GetBytes("BSA\0"); var self = new BSABuilder
_offset = 0x24; {
_slab = new DiskSlabAllocator(size); _fileId = Encoding.ASCII.GetBytes("BSA\0"),
_offset = 0x24,
_slab = await DiskSlabAllocator.Create(size)
};
return self;
} }
public BSABuilder(BSAStateObject bsaStateObject, long size) : this(size) public static async Task<BSABuilder> Create(BSAStateObject bsaStateObject, long size)
{ {
_version = bsaStateObject.Version; var self = await Create(size);
_fileFlags = bsaStateObject.FileFlags; self._version = bsaStateObject.Version;
_archiveFlags = bsaStateObject.ArchiveFlags; self._fileFlags = bsaStateObject.FileFlags;
self._archiveFlags = bsaStateObject.ArchiveFlags;
return self;
} }
public IEnumerable<FileEntry> Files => _files; public IEnumerable<FileEntry> Files => _files;

View File

@ -179,9 +179,9 @@ namespace Compression.BSA
} }
public override IBSABuilder MakeBuilder(long size) public override async Task<IBSABuilder> MakeBuilder(long size)
{ {
return new BSABuilder(this, size); return await BSABuilder.Create(this, size);
} }
public string Magic { get; set; } public string Magic { get; set; }

View File

@ -26,7 +26,7 @@ namespace Compression.BSA
public class ArchiveStateObject public class ArchiveStateObject
{ {
public virtual IBSABuilder MakeBuilder(long size) public virtual async Task<IBSABuilder> MakeBuilder(long size)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }

View File

@ -100,7 +100,7 @@ namespace Compression.BSA
public uint HashOffset { get; set; } public uint HashOffset { get; set; }
public uint VersionNumber { get; set; } public uint VersionNumber { get; set; }
public override IBSABuilder MakeBuilder(long size) public override async Task<IBSABuilder> MakeBuilder(long size)
{ {
return new TES3Builder(this); return new TES3Builder(this);
} }

View File

@ -12,19 +12,31 @@ namespace Wabbajack.Common
/// </summary> /// </summary>
public class DiskSlabAllocator : IAsyncDisposable public class DiskSlabAllocator : IAsyncDisposable
{ {
private readonly TempFile _file; private TempFile? _file;
private readonly MemoryMappedFile _mmap; private MemoryMappedFile? _mmap;
private long _head = 0; private long _head = 0;
private readonly FileStream _fileStream; private FileStream? _fileStream;
private List<IAsyncDisposable> _allocated = new List<IAsyncDisposable>(); private List<IAsyncDisposable> _allocated = new List<IAsyncDisposable>();
private long _size; private long _size;
public DiskSlabAllocator(long size) private DiskSlabAllocator()
{ {
_file = new TempFile();
_fileStream = _file.File.Open(FileMode.Create, FileAccess.ReadWrite); }
_size = Math.Max(size, 1024);
_mmap = MemoryMappedFile.CreateFromFile(_fileStream, null, size, MemoryMappedFileAccess.ReadWrite, HandleInheritability.None, false); public static async Task<DiskSlabAllocator> Create(long size)
{
var file = new TempFile();
var fileStream = await file.Path.Create();
var self = new DiskSlabAllocator
{
_file = file,
_size = Math.Max(size, 1024),
_fileStream = fileStream,
_mmap = MemoryMappedFile.CreateFromFile(fileStream, null, size, MemoryMappedFileAccess.ReadWrite,
HandleInheritability.None, false)
};
return self;
} }
public Stream Allocate(long size) public Stream Allocate(long size)
@ -39,7 +51,7 @@ namespace Wabbajack.Common
var startAt = _head; var startAt = _head;
_head += size; _head += size;
var stream = _mmap.CreateViewStream(startAt, size, MemoryMappedFileAccess.ReadWrite); var stream = _mmap!.CreateViewStream(startAt, size, MemoryMappedFileAccess.ReadWrite);
_allocated.Add(stream); _allocated.Add(stream);
return stream; return stream;
} }
@ -49,9 +61,9 @@ namespace Wabbajack.Common
{ {
foreach (var allocated in _allocated) foreach (var allocated in _allocated)
await allocated.DisposeAsync(); await allocated.DisposeAsync();
_mmap.Dispose(); _mmap!.Dispose();
await _fileStream.DisposeAsync(); await _fileStream!.DisposeAsync();
await _file.DisposeAsync(); await _file!.DisposeAsync();
} }
} }
} }

View File

@ -266,7 +266,7 @@ namespace Wabbajack.Lib
var bsaSize = bsa.FileStates.Select(state => sourceDir.Combine(state.Path).Size).Sum(); var bsaSize = bsa.FileStates.Select(state => sourceDir.Combine(state.Path).Size).Sum();
await using var a = bsa.State.MakeBuilder(bsaSize); await using var a = await bsa.State.MakeBuilder(bsaSize);
var streams = await bsa.FileStates.PMap(Queue, async state => var streams = await bsa.FileStates.PMap(Queue, async state =>
{ {
Status($"Adding {state.Path} to BSA"); Status($"Adding {state.Path} to BSA");

View File

@ -302,7 +302,7 @@ namespace Wabbajack.Test
Magic = "BSA\0", Version = 0x69, ArchiveFlags = 0x107, FileFlags = 0x0, Magic = "BSA\0", Version = 0x69, ArchiveFlags = 0x107, FileFlags = 0x0,
}; };
await using (var bsa = bsaState.MakeBuilder(1024 * 1024)) await using (var bsa = await bsaState.MakeBuilder(1024 * 1024))
{ {
await bsa.AddFile(new BSAFileStateObject await bsa.AddFile(new BSAFileStateObject
{ {
@ -344,7 +344,7 @@ namespace Wabbajack.Test
var tempFileData = utils.RandomData(1024); var tempFileData = utils.RandomData(1024);
await using (var bsa = bsaState.MakeBuilder(1024 * 1024)) await using (var bsa = await bsaState.MakeBuilder(1024 * 1024))
{ {
await bsa.AddFile(new BSAFileStateObject await bsa.AddFile(new BSAFileStateObject
{ {
@ -382,7 +382,7 @@ namespace Wabbajack.Test
Magic = "BSA\0", Version = 0x69, ArchiveFlags = 0x107, FileFlags = 0x0, Magic = "BSA\0", Version = 0x69, ArchiveFlags = 0x107, FileFlags = 0x0,
}; };
await using (var bsa = bsaState.MakeBuilder(1024 * 1024)) await using (var bsa = await bsaState.MakeBuilder(1024 * 1024))
{ {
await bsa.AddFile(new BSAFileStateObject await bsa.AddFile(new BSAFileStateObject
{ {
@ -418,7 +418,7 @@ namespace Wabbajack.Test
// Create the download // Create the download
await using var tempFile = new TempFile(); await using var tempFile = new TempFile();
await using (var bsa = bsaState.MakeBuilder(1024 * 1024)) await using (var bsa = await bsaState.MakeBuilder(1024 * 1024))
{ {
await bsa.AddFile(new BSAFileStateObject await bsa.AddFile(new BSAFileStateObject
{ {
@ -431,7 +431,7 @@ namespace Wabbajack.Test
// Create the result // Create the result
await using (var bsa = bsaState.MakeBuilder(1024 * 1024)) await using (var bsa = await bsaState.MakeBuilder(1024 * 1024))
{ {
await bsa.AddFile(new BSAFileStateObject await bsa.AddFile(new BSAFileStateObject
{ {