fix: Fixes serialization threading, moves world save to end of loop, and eliminates Parallel.ForEach. (#1530)

This commit is contained in:
Kamron Batman 2023-10-03 00:42:49 -07:00 committed by GitHub
parent e18115dd94
commit 1f0acddc46
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 228 additions and 58 deletions

View file

@ -20,7 +20,6 @@ using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Server.Logging;
namespace Server;
@ -55,13 +54,10 @@ public class GenericEntityPersistence<T> : Persistence, IGenericEntityPersistenc
public override void Serialize()
{
// TODO: Hand off to a scheduler instead
Parallel.ForEach(EntitiesBySerial.Values, SerializeEntity);
}
protected virtual void SerializeEntity(T entity)
{
entity.Serialize(World.SerializedTypes);
foreach (var entity in EntitiesBySerial.Values)
{
World.PushToCache(entity);
}
}
public override void WriteSnapshot(string basePath)
@ -160,6 +156,7 @@ public class GenericEntityPersistence<T> : Persistence, IGenericEntityPersistenc
_pendingAdd[entity.Serial] = entity;
break;
}
case WorldState.PendingSave:
case WorldState.Running:
{
ref var entityEntry = ref CollectionsMarshal.GetValueRefOrAddDefault(EntitiesBySerial, entity.Serial, out bool exists);
@ -216,6 +213,7 @@ public class GenericEntityPersistence<T> : Persistence, IGenericEntityPersistenc
_pendingDelete[entity.Serial] = entity;
break;
}
case WorldState.PendingSave:
case WorldState.Running:
{
EntitiesBySerial.Remove(entity.Serial);
@ -299,6 +297,7 @@ public class GenericEntityPersistence<T> : Persistence, IGenericEntityPersistenc
return null;
}
case WorldState.PendingSave:
case WorldState.Running:
{
return EntitiesBySerial.TryGetValue(serial, out var entity) ? entity as R : null;

View file

@ -14,25 +14,33 @@
*************************************************************************/
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
namespace Server;
public abstract class GenericPersistence : Persistence
public abstract class GenericPersistence : Persistence, IGenericSerializable
{
private BufferWriter _saveBuffer;
public string Name { get; }
public GenericPersistence(string name, int priority) : base(priority) => Name = name;
public override void Serialize()
{
_saveBuffer ??= new BufferWriter(true, World.SerializedTypes);
_saveBuffer.Seek(0, SeekOrigin.Begin);
World.PushToCache(this);
}
Serialize(_saveBuffer);
public long SavePosition { get; set; }
public BufferWriter SaveBuffer { get; set; }
public void Serialize(ConcurrentQueue<Type> types)
{
SaveBuffer ??= new BufferWriter(true, types);
SaveBuffer.Seek(0, SeekOrigin.Begin);
Serialize(SaveBuffer);
}
public abstract void Serialize(IGenericWriter writer);
@ -40,7 +48,7 @@ public abstract class GenericPersistence : Persistence
public override void WriteSnapshot(string basePath)
{
string binPath = Path.Combine(basePath, Name, $"{Name}.bin");
var buffer = _saveBuffer!.Buffer.AsSpan(0, (int)_saveBuffer.Position);
var buffer = SaveBuffer!.Buffer.AsSpan(0, (int)SaveBuffer.Position);
AdhocPersistence.WriteSnapshot(new FileInfo(binPath), buffer);
}

View file

@ -19,7 +19,7 @@ using System.IO;
namespace Server;
public interface ISerializable
public interface ISerializable : IGenericSerializable
{
// Should be serialized/deserialized with the index so it can be referenced by IGenericReader
DateTime Created { get; set; }
@ -48,7 +48,7 @@ public interface ISerializable
}
}
public void Serialize(ConcurrentQueue<Type> types)
void IGenericSerializable.Serialize(ConcurrentQueue<Type> types)
{
SaveBuffer ??= new BufferWriter(true, types);

View file

@ -81,8 +81,10 @@ public abstract class Persistence
internal static void SerializeAll()
{
// TODO: Hand off to a scheduler
Parallel.ForEach(_registry, p => p.Serialize());
foreach (var p in _registry)
{
p.Serialize();
}
}
internal static void PostSerializeAll()