mirror of
https://github.com/ACEmulator/ACE
synced 2026-08-17 12:26:06 -04:00
* Step 1. Add new adapter classes and models All classes and objects added are in new namespaces. This add has 0 interraction on existing ACE code. This sets the groundwork for Step 2. Moving World DB caching to the new models * first part of the world entity usage * almost there * final part * update WeenieExtensions * fix * merge fixes and improvements * ACE.Database new code * it compiles * InitializePropertyDictionaries * WOrldDatabaseWithEntityCache cleanup * ShardDatabaseWithCaching * ShardDatabase Cleanup * todo * cache counts reported in serverstatus * House InitializePropertyDictionaries * improve ServerStatus * BiotaModel change HousePermissions to Dictionary<uint, bool> * PropertiesAllegiance to dictionary * BiotaUpdater improvements * Shard Database Cache Reporting * More code ported from Step 3 * Remove stub CharacterCache * Update WorldDatabaseWithEntityCache.cs * build fixes * code audit * Remove non-callback functions from SerializedShardDatabase * BiotaUpdater progress.. only emote left * Emotes done... now need to test * fix * Burden/Value fix for containers * fat fingered EncumbranceVal * add some safety * Don't cache player biotas for initial PlayerManager load * fix null spellbook * Add another null check This is redundant as the check is also upstream. This is to prevent an exception in the future if this function is called from another source.
355 lines
14 KiB
C#
355 lines
14 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
using ACE.Database;
|
|
using ACE.Database.Models.Shard;
|
|
using ACE.Entity.Enum;
|
|
using ACE.Server.Factories;
|
|
using ACE.Server.Network;
|
|
|
|
namespace ACE.Server.Command.Handlers.Processors
|
|
{
|
|
class DatabasePerfTest
|
|
{
|
|
public const int DefaultBiotasTestCount = 1000;
|
|
|
|
private readonly List<uint> testWeenies = new List<uint>
|
|
{
|
|
1, // Clay
|
|
9035, // Exarch Plate Girth
|
|
9034, // Exarch Plate Coat
|
|
27361, // Palenqual's Ukira of the Vortex
|
|
29947, // Bracelet of Creature Enchantments
|
|
};
|
|
|
|
private static bool SessionIsStillInWorld(Session session)
|
|
{
|
|
return session.State == Network.Enum.SessionState.WorldConnected && session.Player != null;
|
|
}
|
|
|
|
public void RunAsync(Session session, int biotasPerTest = DefaultBiotasTestCount)
|
|
{
|
|
Task.Run(() => Run(session, biotasPerTest));
|
|
}
|
|
|
|
private void Run(Session session, int biotasPerTest)
|
|
{
|
|
CommandHandlerHelper.WriteOutputInfo(session, $"Starting Shard Database Performance Tests.\nBiotas per test: {biotasPerTest}\nThis may take several minutes to complete...\nCurrent database queue count: {DatabaseManager.Shard.QueueCount}");
|
|
|
|
|
|
// Get the current queue wait time
|
|
bool responseReceived = false;
|
|
|
|
DatabaseManager.Shard.GetCurrentQueueWaitTime(result =>
|
|
{
|
|
CommandHandlerHelper.WriteOutputInfo(session, $"Current database queue wait time: {result.TotalMilliseconds:N0} ms");
|
|
responseReceived = true;
|
|
});
|
|
|
|
while (!responseReceived)
|
|
Thread.Sleep(1);
|
|
|
|
|
|
// Generate Individual WorldObjects
|
|
var biotas = new Collection<(Biota biota, ReaderWriterLockSlim rwLock)>();
|
|
|
|
for (int i = 0; i < biotasPerTest; i++)
|
|
{
|
|
var worldObject = WorldObjectFactory.CreateNewWorldObject(testWeenies[i % testWeenies.Count]);
|
|
// TODO fix this
|
|
//biotas.Add((worldObject.Biota, worldObject.BiotaDatabaseLock));
|
|
}
|
|
|
|
|
|
// Add biotasPerTest biotas individually
|
|
long trueResults = 0;
|
|
long falseResults = 0;
|
|
var startTime = DateTime.UtcNow;
|
|
var initialQueueWaitTime = TimeSpan.Zero;
|
|
var totalQueryExecutionTime = TimeSpan.Zero;
|
|
foreach (var biota in biotas)
|
|
{
|
|
/* todo
|
|
DatabaseManager.Shard.SaveBiota(biota.biota, biota.rwLock, result =>
|
|
{
|
|
if (result)
|
|
Interlocked.Increment(ref trueResults);
|
|
else
|
|
Interlocked.Increment(ref falseResults);
|
|
}, (queueWaitTime, queryExecutionTime) =>
|
|
{
|
|
if (initialQueueWaitTime == TimeSpan.Zero)
|
|
initialQueueWaitTime = queueWaitTime;
|
|
|
|
totalQueryExecutionTime += queryExecutionTime;
|
|
});*/
|
|
}
|
|
|
|
while (Interlocked.Read(ref trueResults) + Interlocked.Read(ref falseResults) < biotas.Count)
|
|
Thread.Sleep(1);
|
|
|
|
var endTime = DateTime.UtcNow;
|
|
ReportResult(session, "individual add", biotasPerTest, (endTime - startTime), initialQueueWaitTime, totalQueryExecutionTime, trueResults, falseResults);
|
|
|
|
|
|
// Update biotasPerTest biotas individually
|
|
if (session == null || SessionIsStillInWorld(session))
|
|
{
|
|
ModifyBiotas(biotas);
|
|
|
|
trueResults = 0;
|
|
falseResults = 0;
|
|
startTime = DateTime.UtcNow;
|
|
initialQueueWaitTime = TimeSpan.Zero;
|
|
totalQueryExecutionTime = TimeSpan.Zero;
|
|
|
|
foreach (var biota in biotas)
|
|
{
|
|
/* todo
|
|
DatabaseManager.Shard.SaveBiota(biota.biota, biota.rwLock, result =>
|
|
{
|
|
if (result)
|
|
Interlocked.Increment(ref trueResults);
|
|
else
|
|
Interlocked.Increment(ref falseResults);
|
|
}, (queueWaitTime, queryExecutionTime) =>
|
|
{
|
|
if (initialQueueWaitTime == TimeSpan.Zero)
|
|
initialQueueWaitTime = queueWaitTime;
|
|
|
|
totalQueryExecutionTime += queryExecutionTime;
|
|
});*/
|
|
}
|
|
|
|
while (Interlocked.Read(ref trueResults) + Interlocked.Read(ref falseResults) < biotas.Count)
|
|
Thread.Sleep(1);
|
|
|
|
endTime = DateTime.UtcNow;
|
|
ReportResult(session, "individual save", biotasPerTest, (endTime - startTime), initialQueueWaitTime, totalQueryExecutionTime, trueResults, falseResults);
|
|
}
|
|
|
|
|
|
// Delete biotasPerTest biotas individually
|
|
trueResults = 0;
|
|
falseResults = 0;
|
|
startTime = DateTime.UtcNow;
|
|
initialQueueWaitTime = TimeSpan.Zero;
|
|
totalQueryExecutionTime = TimeSpan.Zero;
|
|
|
|
foreach (var biota in biotas)
|
|
{
|
|
DatabaseManager.Shard.RemoveBiota(biota.biota.Id, result =>
|
|
{
|
|
if (result)
|
|
Interlocked.Increment(ref trueResults);
|
|
else
|
|
Interlocked.Increment(ref falseResults);
|
|
}, (queueWaitTime, queryExecutionTime) =>
|
|
{
|
|
if (initialQueueWaitTime == TimeSpan.Zero)
|
|
initialQueueWaitTime = queueWaitTime;
|
|
|
|
totalQueryExecutionTime += queryExecutionTime;
|
|
});
|
|
}
|
|
|
|
while (Interlocked.Read(ref trueResults) + Interlocked.Read(ref falseResults) < biotas.Count)
|
|
Thread.Sleep(1);
|
|
|
|
endTime = DateTime.UtcNow;
|
|
ReportResult(session, "individual remove", biotasPerTest, (endTime - startTime), initialQueueWaitTime, totalQueryExecutionTime, trueResults, falseResults);
|
|
|
|
|
|
if (session != null && !SessionIsStillInWorld(session))
|
|
return;
|
|
|
|
// Generate Bulk WorldObjects
|
|
biotas.Clear();
|
|
|
|
for (int i = 0; i < biotasPerTest; i++)
|
|
{
|
|
var worldObject = WorldObjectFactory.CreateNewWorldObject(testWeenies[i % testWeenies.Count]);
|
|
// TODO fix this
|
|
//biotas.Add((worldObject.Biota, worldObject.BiotaDatabaseLock));
|
|
}
|
|
|
|
|
|
// Add biotasPerTest biotas in bulk
|
|
trueResults = 0;
|
|
falseResults = 0;
|
|
startTime = DateTime.UtcNow;
|
|
initialQueueWaitTime = TimeSpan.Zero;
|
|
totalQueryExecutionTime = TimeSpan.Zero;
|
|
/* todo
|
|
DatabaseManager.Shard.SaveBiotasInParallel(biotas, result =>
|
|
{
|
|
if (result)
|
|
Interlocked.Increment(ref trueResults);
|
|
else
|
|
Interlocked.Increment(ref falseResults);
|
|
}, (queueWaitTime, queryExecutionTime) =>
|
|
{
|
|
if (initialQueueWaitTime == TimeSpan.Zero)
|
|
initialQueueWaitTime = queueWaitTime;
|
|
|
|
totalQueryExecutionTime += queryExecutionTime;
|
|
});*/
|
|
|
|
while (Interlocked.Read(ref trueResults) + Interlocked.Read(ref falseResults) < 1)
|
|
Thread.Sleep(1);
|
|
|
|
endTime = DateTime.UtcNow;
|
|
ReportResult(session, "bulk add", biotasPerTest, (endTime - startTime), initialQueueWaitTime, totalQueryExecutionTime, trueResults, falseResults);
|
|
|
|
|
|
// Update biotasPerTest biotas in bulk
|
|
if (session == null || SessionIsStillInWorld(session))
|
|
{
|
|
ModifyBiotas(biotas);
|
|
|
|
trueResults = 0;
|
|
falseResults = 0;
|
|
startTime = DateTime.UtcNow;
|
|
initialQueueWaitTime = TimeSpan.Zero;
|
|
totalQueryExecutionTime = TimeSpan.Zero;
|
|
/* todo
|
|
DatabaseManager.Shard.SaveBiotasInParallel(biotas, result =>
|
|
{
|
|
if (result)
|
|
Interlocked.Increment(ref trueResults);
|
|
else
|
|
Interlocked.Increment(ref falseResults);
|
|
}, (queueWaitTime, queryExecutionTime) =>
|
|
{
|
|
if (initialQueueWaitTime == TimeSpan.Zero)
|
|
initialQueueWaitTime = queueWaitTime;
|
|
|
|
totalQueryExecutionTime += queryExecutionTime;
|
|
});*/
|
|
|
|
while (Interlocked.Read(ref trueResults) + Interlocked.Read(ref falseResults) < 1)
|
|
Thread.Sleep(1);
|
|
|
|
endTime = DateTime.UtcNow;
|
|
ReportResult(session, "bulk save", biotasPerTest, (endTime - startTime), initialQueueWaitTime, totalQueryExecutionTime, trueResults, falseResults);
|
|
}
|
|
|
|
|
|
// Delete biotasPerTest biotas in bulk
|
|
trueResults = 0;
|
|
falseResults = 0;
|
|
startTime = DateTime.UtcNow;
|
|
initialQueueWaitTime = TimeSpan.Zero;
|
|
totalQueryExecutionTime = TimeSpan.Zero;
|
|
|
|
var ids = biotas.Select(r => r.biota.Id).ToList();
|
|
|
|
DatabaseManager.Shard.RemoveBiotasInParallel(ids, result =>
|
|
{
|
|
if (result)
|
|
Interlocked.Increment(ref trueResults);
|
|
else
|
|
Interlocked.Increment(ref falseResults);
|
|
}, (queueWaitTime, queryExecutionTime) =>
|
|
{
|
|
if (initialQueueWaitTime == TimeSpan.Zero)
|
|
initialQueueWaitTime = queueWaitTime;
|
|
|
|
totalQueryExecutionTime += queryExecutionTime;
|
|
});
|
|
|
|
while (Interlocked.Read(ref trueResults) + Interlocked.Read(ref falseResults) < 1)
|
|
Thread.Sleep(1);
|
|
|
|
endTime = DateTime.UtcNow;
|
|
ReportResult(session, "bulk remove", biotasPerTest, (endTime - startTime), initialQueueWaitTime, totalQueryExecutionTime, trueResults, falseResults);
|
|
|
|
|
|
if (session != null && !SessionIsStillInWorld(session))
|
|
return;
|
|
|
|
CommandHandlerHelper.WriteOutputInfo(session, "Database Performance Tests Completed");
|
|
}
|
|
|
|
private static void ModifyBiotas(ICollection<(Biota biota, ReaderWriterLockSlim rwLock)> biotas)
|
|
{
|
|
foreach (var entry in biotas)
|
|
{
|
|
var biota = entry.biota;
|
|
|
|
// Change the first record
|
|
if (biota.BiotaPropertiesInt.Count > 0)
|
|
biota.BiotaPropertiesInt.First().Value++;
|
|
|
|
if (biota.BiotaPropertiesInt64.Count > 0)
|
|
biota.BiotaPropertiesInt64.First().Value++;
|
|
|
|
if (biota.BiotaPropertiesIID.Count > 0)
|
|
biota.BiotaPropertiesIID.First().Value++;
|
|
|
|
if (biota.BiotaPropertiesDID.Count > 0)
|
|
biota.BiotaPropertiesDID.First().Value++;
|
|
|
|
if (biota.BiotaPropertiesFloat.Count > 0)
|
|
biota.BiotaPropertiesFloat.First().Value++;
|
|
|
|
if (biota.BiotaPropertiesBool.Count > 0)
|
|
biota.BiotaPropertiesBool.First().Value = !biota.BiotaPropertiesBool.First().Value;
|
|
|
|
if (biota.BiotaPropertiesString.Count > 0)
|
|
biota.BiotaPropertiesString.First().Value += " test";
|
|
|
|
|
|
// Remove the last record
|
|
if (biota.BiotaPropertiesInt.Count > 0)
|
|
biota.BiotaPropertiesInt.Remove(biota.BiotaPropertiesInt.Last());
|
|
|
|
if (biota.BiotaPropertiesInt64.Count > 0)
|
|
biota.BiotaPropertiesInt64.Remove(biota.BiotaPropertiesInt64.Last());
|
|
|
|
if (biota.BiotaPropertiesIID.Count > 0)
|
|
biota.BiotaPropertiesIID.Remove(biota.BiotaPropertiesIID.Last());
|
|
|
|
if (biota.BiotaPropertiesDID.Count > 0)
|
|
biota.BiotaPropertiesDID.Remove(biota.BiotaPropertiesDID.Last());
|
|
|
|
if (biota.BiotaPropertiesFloat.Count > 0)
|
|
biota.BiotaPropertiesFloat.Remove(biota.BiotaPropertiesFloat.Last());
|
|
|
|
if (biota.BiotaPropertiesBool.Count > 0)
|
|
biota.BiotaPropertiesBool.Remove(biota.BiotaPropertiesBool.Last());
|
|
|
|
if (biota.BiotaPropertiesString.Count > 0)
|
|
biota.BiotaPropertiesString.Remove(biota.BiotaPropertiesString.Last());
|
|
|
|
|
|
// Add a new record
|
|
biota.BiotaPropertiesInt.Add(new BiotaPropertiesInt { ObjectId = biota.Id, Type = ushort.MaxValue, Value = 0, Object = biota });
|
|
|
|
biota.BiotaPropertiesInt64.Add(new BiotaPropertiesInt64 { ObjectId = biota.Id, Type = ushort.MaxValue, Value = 0, Object = biota });
|
|
|
|
biota.BiotaPropertiesIID.Add(new BiotaPropertiesIID { ObjectId = biota.Id, Type = ushort.MaxValue, Value = 0, Object = biota });
|
|
|
|
biota.BiotaPropertiesDID.Add(new BiotaPropertiesDID { ObjectId = biota.Id, Type = ushort.MaxValue, Value = 0, Object = biota });
|
|
|
|
biota.BiotaPropertiesFloat.Add(new BiotaPropertiesFloat { ObjectId = biota.Id, Type = ushort.MaxValue, Value = 0, Object = biota });
|
|
|
|
biota.BiotaPropertiesBool.Add(new BiotaPropertiesBool { ObjectId = biota.Id, Type = ushort.MaxValue, Value = false, Object = biota });
|
|
|
|
biota.BiotaPropertiesString.Add(new BiotaPropertiesString { ObjectId = biota.Id, Type = ushort.MaxValue, Value = "", Object = biota });
|
|
}
|
|
}
|
|
|
|
private static void ReportResult(Session session, string testDescription, int biotasPerTest, TimeSpan duration, TimeSpan queueWaitTime, TimeSpan totalQueryExecutionTime, long trueResults, long falseResults)
|
|
{
|
|
if (session != null && !SessionIsStillInWorld(session))
|
|
return;
|
|
|
|
CommandHandlerHelper.WriteOutputInfo(session, $"{biotasPerTest} {testDescription.PadRight(17)} Duration: {duration.TotalSeconds.ToString("N1").PadLeft(5)} s. Queue Wait Time: {queueWaitTime.TotalMilliseconds.ToString("N0").PadLeft(3)} ms. Average Execution Time: {(totalQueryExecutionTime.TotalMilliseconds / biotasPerTest).ToString("N0").PadLeft(3)} ms. Success/Fail: {trueResults}/{falseResults}.", ChatMessageType.System);
|
|
}
|
|
}
|
|
}
|