improve locks
All checks were successful
Server Build / publish (push) Successful in 29s
Voice Build / publish (push) Successful in 26s

This commit is contained in:
olcxja 2026-05-29 12:01:13 +02:00
commit cd581593bb
3 changed files with 130 additions and 142 deletions

View file

@ -65,9 +65,7 @@ public class Requests
return;
}
await createLock.WaitAsync();
try
{
switch (step)
{
case "init":
@ -178,6 +176,9 @@ public class Requests
string lowerName = entry.name.ToLowerInvariant();
await createLock.WaitAsync();
try
{
if (Fs.Exists($"{ACCOUNTS_NAME_DIR}/{lowerName}"))
{
await context.Response.WriteAsync("error:username.taken");
@ -229,7 +230,6 @@ public class Requests
await Fs.WriteFile($"{ACCOUNTS_DIR}/registration", Encoding.UTF8.GetBytes("0;"));
}
ulong id = ulong.Parse(await Fs.ReadFile($"{ACCOUNTS_DIR}/last"));
id++;
var freeid = Path.GetFileName(Directory.EnumerateFiles(ACCOUNTS_FREEID_DIR).FirstOrDefault());
@ -270,15 +270,17 @@ public class Requests
await context.Response.WriteAsync("success:account.created");
return;
}
}
await next();
}
finally
{
createLock.Release();
}
}
}
await next();
}
public static async Task Auth(HttpContext context, Func<Task> next, IQueryCollection query, StreamReader bodyReader)
{

View file

@ -3,6 +3,7 @@ using System.Numerics;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading;
using LarpixServer.Filesystem;
using LarpixServer.Utils.Jsons;
using static LarpixServer.Utils.Utils;
@ -15,46 +16,20 @@ public class Utils
public static string LOGIN_SUCCESS = "success:login.successful";
public static ConcurrentDictionary<string, SemaphoreSlim> userLocks = new();
public static ConcurrentQueue<string> keyQueue = new();
private static SemaphoreSlim[]? _userLocksArray = null;
public static SemaphoreSlim GetUserLock(string id)
{
while (userLocks.Count >= LOCK_SIZE)
if (_userLocksArray == null)
{
if (!keyQueue.TryDequeue(out var firstKey)) break;
if (userLocks.TryGetValue(firstKey, out var sem))
{
if (sem.Wait(0))
{
try
{
userLocks.TryRemove(firstKey, out _);
}
finally { sem.Release(); }
}
else
{
keyQueue.Enqueue(firstKey);
break;
}
}
int size = LOCK_SIZE > 0 ? LOCK_SIZE : 65536;
var newArray = Enumerable.Range(0, size).Select(_ => new SemaphoreSlim(1, 1)).ToArray();
Interlocked.CompareExchange(ref _userLocksArray, newArray, null);
}
if (!userLocks.TryGetValue(id, out var semLock))
{
semLock = new SemaphoreSlim(1, 1);
if (userLocks.TryAdd(id, semLock))
{
keyQueue.Enqueue(id);
}
else
{
semLock = userLocks[id];
}
}
return semLock;
int hash = id.GetHashCode();
if (hash < 0) hash = -hash; // Or use Math.Abs, but hash < 0 logic avoids OverflowException on int.MinValue
return _userLocksArray[hash % _userLocksArray.Length];
}
public static string GetIdFromUsernameWD(string usernameWD)
@ -174,16 +149,23 @@ public class Utils
public static async Task<string> NonceDecryptBody(string id, string password, string body, bool delEntry = true)
{
if (!Requests.nonceHolder.TryGetValue(id, out (string, DateTimeOffset) nonce))
(string, DateTimeOffset) nonce;
if (delEntry)
{
if (!Requests.nonceHolder.TryRemove(id, out nonce))
{
return "error:invalid.nonce";
}
string decBody = Encryption.Encryption.PacketDecPass(body, password, nonce.Item1);
if (delEntry)
}
else
{
Requests.nonceHolder.TryRemove(id, out _);
if (!Requests.nonceHolder.TryGetValue(id, out nonce))
{
return "error:invalid.nonce";
}
}
string decBody = Encryption.Encryption.PacketDecPass(body, password, nonce.Item1);
return decBody;
}

View file

@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System.Threading;
using static LarpixServer.Utils.Utils;
namespace LarpixServer.Filesystem;
@ -9,8 +10,7 @@ public class Fs
public static ConcurrentDictionary<string, bool> existCache = new ConcurrentDictionary<string, bool>();
public static ConcurrentDictionary<string, string[]> dirCache = new ConcurrentDictionary<string, string[]>();
private static ConcurrentDictionary<string, SemaphoreSlim> fileLocks = new();
private static SemaphoreSlim[]? _fileLocksArray = null;
private static void InvalidateDirCacheFor(string path)
{
@ -23,7 +23,16 @@ public class Fs
private static SemaphoreSlim GetFileLock(string path)
{
return fileLocks.GetOrAdd(path, _ => new SemaphoreSlim(1, 1));
if (_fileLocksArray == null)
{
int size = LOCK_SIZE > 0 ? LOCK_SIZE : 65536;
var newArray = Enumerable.Range(0, size).Select(_ => new SemaphoreSlim(1, 1)).ToArray();
Interlocked.CompareExchange(ref _fileLocksArray, newArray, null);
}
int hash = path.GetHashCode();
if (hash < 0) hash = -hash; // Or use Math.Abs, but hash < 0 logic avoids OverflowException on int.MinValue
return _fileLocksArray[hash % _fileLocksArray.Length];
}
public static void ProcessCacheSpace()
@ -46,11 +55,6 @@ public class Fs
if (firstKey != null) dirCache.TryRemove(firstKey, out _);
}
while (fileLocks.Count >= LOCK_SIZE)
{
var firstKey = fileLocks.Keys.FirstOrDefault();
if (firstKey != null) fileLocks.TryRemove(firstKey, out _);
}
}
public static ulong ClearCache(string pattern)