Skip to content

Commit

Permalink
* rename fields AuthorExpGradeLocks & _savedRevisions and their p…
Browse files Browse the repository at this point in the history
…arams being passed to `GlobalLocks` & `_localLocks`

* remove `.Count != 0` quick exit @ `ReleaseAllLocks()`
@ AuthorRevisionSaver.cs

* rename fields `SignatureLocks` & `_savedSignatures` to `GlobalLocks` & `_localLocks`
* remove `.Count != 0` quick exit @ `SaveReplySignatures()`
@ ReplySaver.cs

* rename fields `UserIdLocks` & `_savedUsersId` to `GlobalLocks` & `_localLocks`
* remove `.Count != 0` quick exit @ `OnPostSave()`
@ UserSaver.cs
@ crawler

* fix `System.Type` cannot be serialized to JSON by default @ `TbmDbContext.LogDbUpdateConcurrencyException()`
@ shared
@ c#
  • Loading branch information
n0099 committed May 13, 2024
1 parent 863c3a2 commit c1d6890
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 32 deletions.
24 changes: 12 additions & 12 deletions c#/crawler/src/Tieba/Crawl/Saver/AuthorRevisionSaver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@ namespace tbm.Crawler.Tieba.Crawl.Saver;

public class AuthorRevisionSaver(PostType triggeredByPostType)
{
// locks only using fid and uid field values from AuthorRevision
// locks only using AuthorRevision.Fid and Uid, ignoring TriggeredBy
// this prevents inserting multiple entities with similar time and other fields with the same values
private static readonly HashSet<(Fid Fid, Uid Uid)> AuthorExpGradeLocks = [];
private readonly List<(Fid Fid, Uid Uid)> _savedRevisions = [];
private static readonly HashSet<(Fid Fid, Uid Uid)> GlobalLocks = [];
private readonly List<(Fid Fid, Uid Uid)> _localLocks = [];

public delegate AuthorRevisionSaver New(PostType triggeredByPostType);

public Action SaveAuthorExpGradeRevisions<TPostWithAuthorExpGrade>
(CrawlerDbContext db, IReadOnlyCollection<TPostWithAuthorExpGrade> posts)
where TPostWithAuthorExpGrade : PostWithAuthorExpGrade
{
SaveAuthorRevisions(db, posts, AuthorExpGradeLocks,
SaveAuthorRevisions(db, posts, GlobalLocks,
db.AuthorExpGradeRevisions,
p => p.AuthorExpGrade,
(a, b) => a != b,
Expand All @@ -34,13 +34,13 @@ public Action SaveAuthorExpGradeRevisions<TPostWithAuthorExpGrade>
TriggeredBy = triggeredByPostType,
AuthorExpGrade = t.Value
});
return () => ReleaseAllLocks(AuthorExpGradeLocks);
return () => ReleaseAllLocks(GlobalLocks);
}

private void SaveAuthorRevisions<TPost, TRevision, TValue>(
CrawlerDbContext db,
IReadOnlyCollection<TPost> posts,
HashSet<(Fid Fid, Uid Uid)> locks,
HashSet<(Fid Fid, Uid Uid)> globalLocks,
IQueryable<TRevision> dbSet,
Func<TPost, TValue?> postAuthorFieldValueSelector,
Func<TValue?, TValue?, bool> isValueChangedPredicate,
Expand Down Expand Up @@ -74,24 +74,24 @@ private void SaveAuthorRevisions<TPost, TRevision, TValue>(
.Where(t => t.Existing.DiscoveredAt != t.NewInPost.DiscoveredAt
&& isValueChangedPredicate(t.Existing.Value, t.NewInPost.Value))
.Select(t => (t.Uid, t.NewInPost.Value, t.NewInPost.DiscoveredAt));
lock (locks)
lock (globalLocks)
{
var newRevisionsExceptLocked = newRevisionOfNewUsers
.Concat(newRevisionOfExistingUsers)
.Select(revisionFactory)
.ExceptBy(locks, rev => (rev.Fid, rev.Uid))
.ExceptBy(globalLocks, rev => (rev.Fid, rev.Uid))
.ToList();
if (newRevisionsExceptLocked.Count == 0) return;

_savedRevisions.AddRange(newRevisionsExceptLocked.Select(rev => (rev.Fid, rev.Uid)));
locks.UnionWith(_savedRevisions);
_localLocks.AddRange(newRevisionsExceptLocked.Select(rev => (rev.Fid, rev.Uid)));
globalLocks.UnionWith(_localLocks);
db.Set<TRevision>().AddRange(newRevisionsExceptLocked);
}
}

private void ReleaseAllLocks(HashSet<(Fid Fid, Uid Uid)> locks)
private void ReleaseAllLocks(HashSet<(Fid Fid, Uid Uid)> globalLocks)
{
lock (locks) locks.ExceptWith(_savedRevisions);
lock (globalLocks) globalLocks.ExceptWith(_localLocks);
}

private sealed class LatestAuthorRevisionProjection<TValue>
Expand Down
15 changes: 7 additions & 8 deletions c#/crawler/src/Tieba/Crawl/Saver/Post/ReplySaver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,8 @@ on existing.UrlFilename equals newInContent.UrlFilename
}
public partial class ReplySaver
{
private static readonly HashSet<UniqueSignature> SignatureLocks = [];
private readonly List<UniqueSignature> _savedSignatures = [];
private static readonly HashSet<UniqueSignature> GlobalLocks = [];
private readonly List<UniqueSignature> _localLocks = [];

private Action SaveReplySignatures(CrawlerDbContext db, IEnumerable<ReplyPost> replies)
{
Expand Down Expand Up @@ -152,23 +152,22 @@ join newInReply in signatures on existing.SignatureId equals newInReply.Signatur
select (existing, newInReply))
.ForEach(t => t.existing.LastSeenAt = t.newInReply.LastSeenAt);

lock (SignatureLocks)
lock (GlobalLocks)
{
var newSignaturesExceptLocked = signatures
.ExceptBy(existingSignatures.Select(s => s.SignatureId), s => s.SignatureId)
.ExceptBy(SignatureLocks, s => new(s.SignatureId, s.XxHash3))
.ExceptBy(GlobalLocks, s => new(s.SignatureId, s.XxHash3))
.ToList();
if (newSignaturesExceptLocked.Count == 0) return () => { };

_savedSignatures.AddRange(newSignaturesExceptLocked
_localLocks.AddRange(newSignaturesExceptLocked
.Select(s => new UniqueSignature(s.SignatureId, s.XxHash3)));
SignatureLocks.UnionWith(_savedSignatures);
GlobalLocks.UnionWith(_localLocks);
db.ReplySignatures.AddRange(newSignaturesExceptLocked);
}
return () =>
{
lock (SignatureLocks)
if (_savedSignatures.Count != 0) SignatureLocks.ExceptWith(_savedSignatures);
lock (GlobalLocks) GlobalLocks.ExceptWith(_localLocks);
};
}

Expand Down
22 changes: 11 additions & 11 deletions c#/crawler/src/Tieba/Crawl/Saver/UserSaver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ protected override Dictionary<Type, AddRevisionDelegate>
public partial class UserSaver(ILogger<UserSaver> logger, ConcurrentDictionary<Uid, User> users)
: BaseSaver<BaseUserRevision>(logger)
{
private static readonly HashSet<Uid> UserIdLocks = [];
private readonly List<Uid> _savedUsersId = [];
private static readonly HashSet<Uid> GlobalLocks = [];
private readonly List<Uid> _localLocks = [];

public delegate UserSaver New(ConcurrentDictionary<Uid, User> users);

Expand All @@ -45,12 +45,12 @@ public void Save(
IFieldChangeIgnorance.FieldChangeIgnoranceDelegates userFieldChangeIgnorance)
{
if (users.IsEmpty) return;
lock (UserIdLocks)
lock (GlobalLocks)
{
var usersExceptLocked = new Dictionary<Uid, User>(users.ExceptBy(UserIdLocks, pair => pair.Key));
var usersExceptLocked = new Dictionary<Uid, User>(users.ExceptBy(GlobalLocks, pair => pair.Key));
if (usersExceptLocked.Count == 0) return;
_savedUsersId.AddRange(usersExceptLocked.Keys);
UserIdLocks.UnionWith(_savedUsersId);
_localLocks.AddRange(usersExceptLocked.Keys);
GlobalLocks.UnionWith(_localLocks);

var existingUsersKeyByUid = (from user in db.Users.AsTracking()
where usersExceptLocked.Keys.Contains(user.Uid)
Expand All @@ -69,18 +69,18 @@ where usersExceptLocked.Keys.Contains(user.Uid)

public IEnumerable<Uid> AcquireUidLocksForSave(IEnumerable<Uid> usersId)
{
lock (UserIdLocks)
lock (GlobalLocks)
{
var exceptLocked = usersId.Except(UserIdLocks).ToList();
var exceptLocked = usersId.Except(GlobalLocks).ToList();
if (exceptLocked.Count == 0) return exceptLocked;
_savedUsersId.AddRange(exceptLocked); // assume all given users are saved
UserIdLocks.UnionWith(exceptLocked);
_localLocks.AddRange(exceptLocked);
GlobalLocks.UnionWith(exceptLocked);
return exceptLocked;
}
}

public void OnPostSave()
{
lock (UserIdLocks) if (_savedUsersId.Count != 0) UserIdLocks.ExceptWith(_savedUsersId);
lock (GlobalLocks) GlobalLocks.ExceptWith(_localLocks);
}
}
2 changes: 1 addition & 1 deletion c#/shared/src/Db/TbmDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public abstract class TbmDbContext(ILogger<TbmDbContext> logger) : DbContext
public void LogDbUpdateConcurrencyException(DbUpdateConcurrencyException e) =>
logger.LogWarning(e, "DbUpdateConcurrencyException: {}",
SharedHelper.UnescapedJsonSerialize(e.Entries
.GroupBy(ee => ee.Entity.GetType())
.GroupBy(ee => ee.Entity.GetType().Name)
.ToDictionary(g => g.Key, g => g.Count())));

public int SaveChangesForUpdate()
Expand Down

0 comments on commit c1d6890

Please sign in to comment.