ace/Source/ACE.Server/Command/Handlers/Processors/DatabasePerfTest.cs
Mag-nus 75fc1ce23c
Step 3. Convert ShardDatabase/WorldObjects biota from the ACE.Database model to the new ACE.Entity model (#2731)
* 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.
2020-04-02 22:40:27 -05:00

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);
}
}
}