Fixes bugs in world save (#297)

- [X] Fixes bugs in the buffer writer
- [X] Removes background save commands
- [X] Avoids calling Serialize() on deserialization
    - In a future optimization I will copy the entire object to a buffer, deserialize using a SpanReader, then use that buffer for the SaveBuffer
- [X] Fixes issue with decay queue.

Bumps release version
This commit is contained in:
Kamron Batman 2020-11-01 17:22:18 -08:00 committed by GitHub
parent daf48ebdf2
commit 55935d30b4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 122 additions and 153 deletions

View file

@ -137,7 +137,7 @@ namespace Server
m_DiskWriteHandle.WaitOne();
}
public static void EnqueueForDecay(Item item)
private static void EnqueueForDecay(Item item)
{
if (WorldState != WorldState.Saving)
{
@ -338,6 +338,11 @@ namespace Server
}
t.Delete();
}
reader.Seek(entry.Position, SeekOrigin.Begin);
t.SaveBuffer = new BufferWriter(new byte[entry.Length], true);
reader.Read(t.SaveBuffer.Data);
}
reader.Close();
@ -381,8 +386,6 @@ namespace Server
ProcessSafetyQueues();
var now = DateTime.UtcNow;
foreach (var item in Items.Values)
{
if (item.Parent == null)
@ -391,7 +394,6 @@ namespace Server
}
item.ClearProperties();
item.Serialize(now);
}
foreach (var m in Mobiles.Values)
@ -400,12 +402,6 @@ namespace Server
m.UpdateTotals();
m.ClearProperties();
m.Serialize(now);
}
foreach (var g in Guilds.Values)
{
g.Serialize(now);
}
watch.Stop();
@ -466,6 +462,9 @@ namespace Server
public static void WriteFiles(object state)
{
Console.Write("Closing Save Files...");
var watch = Stopwatch.StartNew();
IIndexInfo<Serial> itemIndexInfo = new EntityTypeIndex("Items");
IIndexInfo<Serial> mobileIndexInfo = new EntityTypeIndex("Mobiles");
IIndexInfo<Serial> guildIndexInfo = new EntityTypeIndex("Guilds");
@ -474,10 +473,11 @@ namespace Server
WriteEntities(mobileIndexInfo, Mobiles, MobileTypes);
WriteEntities(guildIndexInfo, Guilds, GuildTypes);
if (m_DiskWriteHandle.Set())
{
Console.WriteLine("Closing Save Files.");
}
watch.Stop();
m_DiskWriteHandle.Set();
Console.WriteLine("done {0:F1} seconds.", watch.Elapsed.TotalSeconds);
Timer.DelayCall(FinishWorldSave);
}
@ -525,8 +525,13 @@ namespace Server
private static void SaveEntities<T>(IEnumerable<T> list, DateTime serializeStart) where T : class, ISerializable
{
Parallel.ForEach(list, (t, now) => {
t.Serialize(serializeStart);
Parallel.ForEach(list, t => {
if (t is Item item && item.CanDecay() && item.LastMoved + item.DecayTime <= serializeStart)
{
EnqueueForDecay(item);
}
t.Serialize();
});
}
@ -551,13 +556,13 @@ namespace Server
return;
}
WaitForWriteCompletion(); // Blocks Save until current disk flush is done.s
++_Saves;
NetState.FlushAll();
NetState.Pause();
WaitForWriteCompletion(); // Blocks Save until current disk flush is done.
WorldState = WorldState.Saving;
m_DiskWriteHandle.Reset();
@ -593,12 +598,11 @@ namespace Server
Console.WriteLine("Save done in {0:F2} seconds.", duration);
Broadcast(
0x35,
true,
"World save complete. The entire process took {0:F2} seconds.",
duration
);
// Only broadcast if it took at least 150ms
if (duration >= 0.15)
{
Broadcast(0x35, true, $"World save completed in {duration:F2} seconds.");
}
NetState.Resume();
}