Compare commits

...

4 Commits

Author SHA1 Message Date
Spirtix
1a6db72d7a downgrade ef to 7
There's a performance regression for synchronous insert/update in npgsql
ef adapter, we'll have to switch to asynchronous db calls before
updating
2025-07-02 21:28:53 +02:00
Spirtix
0923b80cdf lock CreatePet and SetImage 2025-07-01 16:40:56 +02:00
Spirtix
1b22c9c3dd remove async query 2025-06-30 22:21:10 +02:00
Spirtix
7dbcc456b9 async locking for VikingSession 2025-06-30 19:33:49 +02:00
4 changed files with 35 additions and 16 deletions

View File

@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using sodoff.Model;
namespace sodoff.Attributes;
@ -12,6 +13,9 @@ public class VikingSession : Attribute, IAsyncActionFilter {
public Modes Mode { get; set; } = Modes.VIKING;
public bool UseLock = false;
private static Dictionary<string, SemaphoreSlim> semaphores = new();
private static SemaphoreSlim dictSemaphore = new(1, 1);
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) {
DBContext ctx = context.HttpContext.RequestServices.GetService(typeof(DBContext)) as DBContext;
@ -44,15 +48,16 @@ public class VikingSession : Attribute, IAsyncActionFilter {
// NOTE: we can't refer to session.User / session.Viking here,
// because it may cause to ignore modifications from the threads we are waiting for
// we can use its only after vikingMutex.WaitOne()
Mutex vikingMutex = new Mutex(false, "SoDOffViking:" + userVikingId);
string semKey = "SoDOffViking:" + userVikingId;
SemaphoreSlim semaphore = await GetSemaphore(semKey);
try {
vikingMutex.WaitOne();
await semaphore.WaitAsync();
context.ActionArguments["user"] = session.User;
context.ActionArguments["viking"] = session.Viking;
await next();
} finally {
vikingMutex.ReleaseMutex();
semaphore.Release();
await RemoveSemaphore(semKey, semaphore);
}
} else {
context.ActionArguments["user"] = session.User;
@ -60,4 +65,22 @@ public class VikingSession : Attribute, IAsyncActionFilter {
await next();
}
}
private static async Task<SemaphoreSlim> GetSemaphore(string key) {
await dictSemaphore.WaitAsync();
if (!semaphores.TryGetValue(key, out SemaphoreSlim semaphore)) {
semaphore = new SemaphoreSlim(1, 1);
semaphores.Add(key, semaphore);
}
dictSemaphore.Release();
return semaphore;
}
private static async Task RemoveSemaphore(string key, SemaphoreSlim sem) {
await dictSemaphore.WaitAsync();
if (sem.CurrentCount == 1) {
semaphores.Remove(key);
}
dictSemaphore.Release();
}
}

View File

@ -570,7 +570,7 @@ public class ContentController : Controller {
[HttpPost]
[Produces("application/xml")]
[Route("V2/ContentWebService.asmx/CreatePet")]
[VikingSession]
[VikingSession(UseLock = true)]
public IActionResult CreatePet(Viking viking, [FromForm] string request) {
RaisedPetRequest raisedPetRequest = XmlUtil.DeserializeXml<RaisedPetRequest>(request);
// TODO: Investigate SetAsSelectedPet and UnSelectOtherPets - they don't seem to do anything
@ -602,7 +602,6 @@ public class ContentController : Controller {
if (raisedPetRequest.SetAsSelectedPet == true) {
viking.SelectedDragon = dragon;
ctx.Update(viking);
}
ctx.Dragons.Add(dragon);
ctx.Images.Add(image);
@ -905,7 +904,7 @@ public class ContentController : Controller {
[HttpPost]
[Produces("application/xml")]
[Route("ContentWebService.asmx/SetImage")]
[VikingSession]
[VikingSession(UseLock = true)]
public bool SetImage(Viking viking, [FromForm] string ImageType, [FromForm] int ImageSlot, [FromForm] string contentXML, [FromForm] string imageFile) {
// TODO: the other properties of contentXML
ImageData data = XmlUtil.DeserializeXml<ImageData>(contentXML);
@ -925,11 +924,8 @@ public class ContentController : Controller {
image.ImageData = imageFile;
image.TemplateName = data.TemplateName;
if (newImage) {
if (newImage)
ctx.Images.Add(image);
} else {
ctx.Images.Update(image);
}
ctx.SaveChanges();
return true;

View File

@ -74,7 +74,7 @@
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
"Microsoft.AspNetCore": "Information"
}
},
"AllowedHosts": "*"

View File

@ -11,26 +11,26 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="9.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="7.0.20" />
</ItemGroup>
<Choose>
<When Condition="$(DefineConstants.Contains('USE_SQLITE'))">
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.20" />
</ItemGroup>
</When>
</Choose>
<Choose>
<When Condition="$(DefineConstants.Contains('USE_POSTGRESQL'))">
<ItemGroup>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.18" />
</ItemGroup>
</When>
</Choose>
<Choose>
<When Condition="$(DefineConstants.Contains('USE_MYSQL'))">
<ItemGroup>
<PackageReference Include="MySql.EntityFrameworkCore" Version="9.0.3" />
<PackageReference Include="MySql.EntityFrameworkCore" Version="7.0.16" />
</ItemGroup>
</When>
</Choose>