Skip to content

Commit 2936695

Browse files
committed
- QoL retry for cache rebuild on file in use errors.
- Wrapped more semaphore releases in finally blocks to help avoid deadlocks with unexpected index read errors.
1 parent fd6e2f8 commit 2936695

File tree

2 files changed

+100
-62
lines changed

2 files changed

+100
-62
lines changed

xivModdingFramework/Cache/XivCache.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,22 @@ private static void CreateCache()
297297
// manually replaces the roots DB. (It takes an hour or more to build)
298298
SQLiteConnection.ClearAllPools();
299299
GC.WaitForPendingFinalizers();
300-
File.Delete(_dbPath.FullName);
300+
301+
302+
try
303+
{
304+
File.Delete(_dbPath.FullName);
305+
} catch
306+
{
307+
// In some select situations sometimes the DB can still be in use
308+
// if we were asyncing other things. Sleep a bit and see if we can succeed after.
309+
310+
// ( The primary case of this happening is a START OVER without Index backups, where we
311+
// transition straight from a full modlist disable into a cache rebuild, without waiting
312+
// on the Cache to finish queueing entries into the DB. )
313+
Thread.Sleep(1000);
314+
File.Delete(_dbPath.FullName);
315+
}
301316

302317
using (var db = new SQLiteConnection(CacheConnectionString))
303318
{

xivModdingFramework/SqPack/FileTypes/Index.cs

Lines changed: 84 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,18 @@ public void UpdateIndexDatCount(XivDataFile dataFile, int datNum)
6060
foreach (var indexPath in indexPaths)
6161
{
6262
_semaphoreSlim.Wait();
63-
using (var bw = new BinaryWriter(File.OpenWrite(indexPath)))
63+
try
6464
{
65-
bw.BaseStream.Seek(1104, SeekOrigin.Begin);
66-
bw.Write(datCount);
65+
using (var bw = new BinaryWriter(File.OpenWrite(indexPath)))
66+
{
67+
bw.BaseStream.Seek(1104, SeekOrigin.Begin);
68+
bw.Write(datCount);
69+
}
70+
}
71+
finally
72+
{
73+
_semaphoreSlim.Release();
6774
}
68-
_semaphoreSlim.Release();
6975
}
7076
}
7177

@@ -261,33 +267,39 @@ public async Task<int> GetDataOffsetIndex2(string fullPath)
261267

262268

263269
await _semaphoreSlim.WaitAsync();
264-
265-
// Dump the index into memory, since we're going to have to inject data.
266-
byte[] originalIndex = File.ReadAllBytes(index2Path);
267-
268-
// Get all the segment header data
269-
for (int i = 0; i < SegmentHeaders.Length; i++)
270+
try
270271
{
271-
SegmentOffsets[i] = BitConverter.ToInt32(originalIndex, SegmentHeaders[i] + 4);
272-
SegmentSizes[i] = BitConverter.ToInt32(originalIndex, SegmentHeaders[i] + 8);
273-
}
274272

275-
int fileCount = SegmentSizes[0] / 8;
273+
// Dump the index into memory, since we're going to have to inject data.
274+
byte[] originalIndex = File.ReadAllBytes(index2Path);
276275

277-
for (int i = 0; i < fileCount; i++)
278-
{
279-
int position = SegmentOffsets[0] + (i * 8);
280-
uint iFullPathHash = BitConverter.ToUInt32(originalIndex, position);
281-
uint iOffset = BitConverter.ToUInt32(originalIndex, position + 4);
276+
// Get all the segment header data
277+
for (int i = 0; i < SegmentHeaders.Length; i++)
278+
{
279+
SegmentOffsets[i] = BitConverter.ToInt32(originalIndex, SegmentHeaders[i] + 4);
280+
SegmentSizes[i] = BitConverter.ToInt32(originalIndex, SegmentHeaders[i] + 8);
281+
}
282+
283+
int fileCount = SegmentSizes[0] / 8;
282284

283-
// Index 2 is just in hash order, so find the spot where we fit in.
284-
if (iFullPathHash == uFullPathHash)
285+
for (int i = 0; i < fileCount; i++)
285286
{
286-
int signedOffset= BitConverter.ToInt32(originalIndex, position + 4);
287-
return signedOffset * 8;
287+
int position = SegmentOffsets[0] + (i * 8);
288+
uint iFullPathHash = BitConverter.ToUInt32(originalIndex, position);
289+
uint iOffset = BitConverter.ToUInt32(originalIndex, position + 4);
290+
291+
// Index 2 is just in hash order, so find the spot where we fit in.
292+
if (iFullPathHash == uFullPathHash)
293+
{
294+
int signedOffset = BitConverter.ToInt32(originalIndex, position + 4);
295+
return signedOffset * 8;
296+
}
288297
}
289298
}
290-
_semaphoreSlim.Release();
299+
finally
300+
{
301+
_semaphoreSlim.Release();
302+
}
291303
return 0;
292304
}
293305

@@ -711,31 +723,36 @@ public async Task<List<int>> GetAllHashedFilesInFolder(int hashedFolder, XivData
711723
var indexPath = Path.Combine(_gameDirectory.FullName, $"{dataFile.GetDataFileName()}{IndexExtension}");
712724

713725
await _semaphoreSlim.WaitAsync();
714-
await Task.Run(() =>
726+
try
715727
{
716-
using (var br = new BinaryReader(File.OpenRead(indexPath)))
728+
await Task.Run(() =>
717729
{
718-
br.BaseStream.Seek(fileCountOffset, SeekOrigin.Begin);
719-
var totalFiles = br.ReadInt32();
720-
721-
br.BaseStream.Seek(dataStartOffset, SeekOrigin.Begin);
722-
for (var i = 0; i < totalFiles; br.ReadBytes(4), i += 16)
730+
using (var br = new BinaryReader(File.OpenRead(indexPath)))
723731
{
724-
var hashedFile = br.ReadInt32();
725-
726-
var folderPathHash = br.ReadInt32();
732+
br.BaseStream.Seek(fileCountOffset, SeekOrigin.Begin);
733+
var totalFiles = br.ReadInt32();
727734

728-
if (folderPathHash == hashedFolder)
735+
br.BaseStream.Seek(dataStartOffset, SeekOrigin.Begin);
736+
for (var i = 0; i < totalFiles; br.ReadBytes(4), i += 16)
729737
{
730-
fileHashesList.Add(hashedFile);
731-
}
738+
var hashedFile = br.ReadInt32();
732739

733-
br.ReadBytes(4);
734-
}
735-
}
736-
});
740+
var folderPathHash = br.ReadInt32();
737741

738-
_semaphoreSlim.Release();
742+
if (folderPathHash == hashedFolder)
743+
{
744+
fileHashesList.Add(hashedFile);
745+
}
746+
747+
br.ReadBytes(4);
748+
}
749+
}
750+
});
751+
}
752+
finally
753+
{
754+
_semaphoreSlim.Release();
755+
}
739756
return fileHashesList;
740757
}
741758

@@ -756,32 +773,38 @@ public async Task<Dictionary<int, int>> GetAllHashedFilesAndOffsetsInFolder(int
756773
var indexPath = Path.Combine(_gameDirectory.FullName, $"{dataFile.GetDataFileName()}{IndexExtension}");
757774

758775
await _semaphoreSlim.WaitAsync();
759-
await Task.Run(() =>
776+
try
760777
{
761-
using (var br = new BinaryReader(File.OpenRead(indexPath)))
778+
await Task.Run(() =>
762779
{
763-
br.BaseStream.Seek(fileCountOffset, SeekOrigin.Begin);
764-
var totalFiles = br.ReadInt32();
765-
766-
br.BaseStream.Seek(dataStartOffset, SeekOrigin.Begin);
767-
for (var i = 0; i < totalFiles; br.ReadBytes(4), i += 16)
780+
using (var br = new BinaryReader(File.OpenRead(indexPath)))
768781
{
769-
var hashedFile = br.ReadInt32();
770-
771-
var folderPathHash = br.ReadInt32();
782+
br.BaseStream.Seek(fileCountOffset, SeekOrigin.Begin);
783+
var totalFiles = br.ReadInt32();
772784

773-
if (folderPathHash == hashedFolder)
774-
{
775-
fileHashesDict.Add(hashedFile, br.ReadInt32() * 8);
776-
}
777-
else
785+
br.BaseStream.Seek(dataStartOffset, SeekOrigin.Begin);
786+
for (var i = 0; i < totalFiles; br.ReadBytes(4), i += 16)
778787
{
779-
br.ReadBytes(4);
788+
var hashedFile = br.ReadInt32();
789+
790+
var folderPathHash = br.ReadInt32();
791+
792+
if (folderPathHash == hashedFolder)
793+
{
794+
fileHashesDict.Add(hashedFile, br.ReadInt32() * 8);
795+
}
796+
else
797+
{
798+
br.ReadBytes(4);
799+
}
780800
}
781801
}
782-
}
783-
});
784-
_semaphoreSlim.Release();
802+
});
803+
}
804+
finally
805+
{
806+
_semaphoreSlim.Release();
807+
}
785808

786809
return fileHashesDict;
787810
}

0 commit comments

Comments
 (0)