mirror of
https://github.com/2dust/v2rayN.git
synced 2026-10-23 21:55:00 +03:00
fix(profile-ex): make ProfileExItem creation atomic per IndexId (#10420)
ConcurrentBag only makes individual operations safe. GetProfileExItem performed FirstOrDefault and AddProfileEx as separate operations, so concurrent speed tests could both miss and create duplicate entries for the same IndexId. Recheck under a dedicated lock before creating, and replace the bag under the same lock in InitData/ClearAll so creation cannot target a bag that is being swapped. Existing reads and item updates stay lock-free.
This commit is contained in:
@@ -5,6 +5,7 @@ public class ProfileExManager
|
||||
private static readonly Lazy<ProfileExManager> _instance = new(() => new());
|
||||
private ConcurrentBag<ProfileExItem> _lstProfileEx = [];
|
||||
private readonly ConcurrentQueue<string> _queIndexIds = new();
|
||||
private readonly Lock _profileExLock = new();
|
||||
public static ProfileExManager Instance => _instance.Value;
|
||||
private static readonly string _tag = "ProfileExHandler";
|
||||
|
||||
@@ -27,7 +28,11 @@ public class ProfileExManager
|
||||
{
|
||||
await SQLiteHelper.Instance.ExecuteAsync($"delete from ProfileExItem where indexId not in ( select indexId from ProfileItem )");
|
||||
|
||||
_lstProfileEx = new(await SQLiteHelper.Instance.TableAsync<ProfileExItem>().ToListAsync());
|
||||
var lstProfileEx = new ConcurrentBag<ProfileExItem>(await SQLiteHelper.Instance.TableAsync<ProfileExItem>().ToListAsync());
|
||||
lock (_profileExLock)
|
||||
{
|
||||
_lstProfileEx = lstProfileEx;
|
||||
}
|
||||
}
|
||||
|
||||
private void IndexIdEnqueue(string indexId)
|
||||
@@ -109,13 +114,26 @@ public class ProfileExManager
|
||||
|
||||
private ProfileExItem GetProfileExItem(string? indexId)
|
||||
{
|
||||
return _lstProfileEx.FirstOrDefault(t => t.IndexId == indexId) ?? AddProfileEx(indexId);
|
||||
var profileEx = _lstProfileEx.FirstOrDefault(t => t.IndexId == indexId);
|
||||
if (profileEx is not null)
|
||||
{
|
||||
return profileEx;
|
||||
}
|
||||
|
||||
lock (_profileExLock)
|
||||
{
|
||||
profileEx = _lstProfileEx.FirstOrDefault(t => t.IndexId == indexId);
|
||||
return profileEx ?? AddProfileEx(indexId);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task ClearAll()
|
||||
{
|
||||
await SQLiteHelper.Instance.ExecuteAsync($"delete from ProfileExItem ");
|
||||
_lstProfileEx = [];
|
||||
lock (_profileExLock)
|
||||
{
|
||||
_lstProfileEx = [];
|
||||
}
|
||||
}
|
||||
|
||||
public async Task SaveTo()
|
||||
|
||||
Reference in New Issue
Block a user