Skip to content

Commit 5f7e4a9

Browse files
authored
Fix pin and photo subject migration jobs (#1063)
This does a few fixes/adjustments for existing migration jobs: - Deleting entities during a migration job will now cause the job state to be adjusted, fixing an issue where `CorrectWebsitePinProgressPlatformMigration` would never be marked as complete (and possibly also unintentionally skip pins) if there were more than 1000 pins to migrate (the job was also renamed for consistency + to allow it to fully retry on instances where it has already been executed), and to allow similar jobs in the future to also run properly - `MoveSubjectsOutOfGamePhotosMigration` will not try to migrate photos again if they already have associated `GamePhotoSubject`s, avoiding duplicate key insertions - Some migration job-exclusive code was moved from `Refresh.Database` to the jobs' `Migrate()` method, to not keep methods only used by one specific job there
2 parents b19ac23 + 7b045da commit 5f7e4a9

19 files changed

Lines changed: 472 additions & 104 deletions

Refresh.Database/GameDatabaseContext.Photos.cs

Lines changed: 14 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -119,67 +119,20 @@ public GamePhoto UploadPhoto(IPhotoUpload photo, IEnumerable<IPhotoUploadSubject
119119
return newPhoto;
120120
}
121121

122-
/// <remarks>
123-
/// Migration only!!
124-
/// </remarks>
125-
public void MigratePhotoSubjects(GamePhoto photo, bool saveChanges)
122+
public GamePhotoSubject AddSubjectForPhoto(GamePhoto photo, int playerId, string displayName, GameUser? user, List<float> bounds, bool save = true)
126123
{
127-
List<GamePhotoSubject> subjects = [];
128-
129-
#pragma warning disable CS0618 // obsoletion
130-
131-
// If DisplayName is not null, there is a subject in that spot
132-
if (photo.Subject1DisplayName != null)
133-
{
134-
subjects.Add(new()
135-
{
136-
Photo = photo,
137-
PlayerId = 1,
138-
DisplayName = photo.Subject1DisplayName,
139-
User = photo.Subject1User,
140-
Bounds = photo.Subject1Bounds,
141-
});
142-
}
143-
144-
if (photo.Subject2DisplayName != null)
145-
{
146-
subjects.Add(new()
147-
{
148-
Photo = photo,
149-
PlayerId = 2,
150-
DisplayName = photo.Subject2DisplayName,
151-
User = photo.Subject2User,
152-
Bounds = photo.Subject2Bounds,
153-
});
154-
}
155-
156-
if (photo.Subject3DisplayName != null)
157-
{
158-
subjects.Add(new()
159-
{
160-
Photo = photo,
161-
PlayerId = 3,
162-
DisplayName = photo.Subject3DisplayName,
163-
User = photo.Subject3User,
164-
Bounds = photo.Subject3Bounds,
165-
});
166-
}
167-
168-
if (photo.Subject4DisplayName != null)
124+
GamePhotoSubject subject = new()
169125
{
170-
subjects.Add(new()
171-
{
172-
Photo = photo,
173-
PlayerId = 4,
174-
DisplayName = photo.Subject4DisplayName,
175-
User = photo.Subject4User,
176-
Bounds = photo.Subject4Bounds,
177-
});
178-
}
179-
#pragma warning restore CS0618
126+
Photo = photo,
127+
PlayerId = playerId,
128+
DisplayName = displayName,
129+
User = user,
130+
Bounds = bounds,
131+
};
180132

181-
this.GamePhotoSubjects.AddRange(subjects);
182-
if (saveChanges) this.SaveChanges();
133+
this.GamePhotoSubjects.Add(subject);
134+
if (save) this.SaveChanges();
135+
return subject;
183136
}
184137

185138
public void RemovePhoto(GamePhoto photo)
@@ -227,6 +180,9 @@ public IQueryable<GamePhotoSubject> GetSubjectsInPhoto(GamePhoto photo)
227180
.Where(s => s.PhotoId == photo.PhotoId)
228181
.OrderBy(s => s.PlayerId);
229182

183+
public int GetTotalSubjectsInPhoto(GamePhoto photo)
184+
=> this.GamePhotoSubjects.Count(s => s.PhotoId == photo.PhotoId);
185+
230186
public IQueryable<GameUser> GetUsersInPhoto(GamePhoto photo)
231187
=> this.GetSubjectsInPhoto(photo)
232188
.Where(s => s.User != null)

Refresh.Database/GameDatabaseContext.Pins.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -180,20 +180,19 @@ private IEnumerable<ProfilePinRelation> GetProfilePinsByUser(GameUser user, Toke
180180

181181
public DatabaseList<ProfilePinRelation> GetProfilePinsByUser(GameUser user, TokenGame game, TokenPlatform platform, int skip, int count)
182182
=> new(this.GetProfilePinsByUser(user, game, platform), skip, count);
183-
184-
#region Migration Methods
185183

186184
public void AddPinProgress(PinProgressRelation relation, bool save)
187185
{
188186
this.PinProgressRelations.Add(relation);
189187
if (save) this.SaveChanges();
190188
}
191189

192-
public void RemoveAllPinProgressesByIdAndUser(long pinId, ObjectId userId, bool save)
190+
public void RemovePinProgress(PinProgressRelation relation, bool save)
193191
{
194-
this.PinProgressRelations.RemoveRange(p => p.PinId == pinId && p.PublisherId == userId);
192+
this.PinProgressRelations.Remove(relation);
195193
if (save) this.SaveChanges();
196194
}
197195

198-
#endregion
196+
public int GetTotalPinProgresses()
197+
=> this.PinProgressRelations.Count();
199198
}

Refresh.Database/GameDatabaseContext.Relations.cs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -477,20 +477,6 @@ public GameReview UpdateReview(ISubmitReviewRequest updateInfo, GameReview revie
477477
this.SaveChanges();
478478
return review;
479479
}
480-
481-
public void MigrateReviewLabels(IEnumerable<GameReview> reviews)
482-
{
483-
foreach (GameReview review in reviews)
484-
{
485-
#pragma warning disable CS0618 // LabelsString is obsolete
486-
if (string.IsNullOrWhiteSpace(review.LabelsString)) continue;
487-
488-
review.Labels = LabelExtensions.FromLbpCommaList(review.LabelsString).ToList();
489-
#pragma warning restore CS0618
490-
}
491-
492-
this.SaveChanges();
493-
}
494480

495481
public void DeleteReviewsPostedByUser(GameUser user)
496482
{

Refresh.Interfaces.Workers/Migrations/BackfillLevelAttributesMigration.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,14 @@ protected override IQueryable<GameLevel> SortAndFilter(IQueryable<GameLevel> que
1212
.OrderBy(l => l.LevelId);
1313
}
1414

15-
protected override void Migrate(WorkContext context, GameLevel[] batch)
15+
protected override int Migrate(WorkContext context, GameLevel[] batch)
1616
{
1717
foreach (GameLevel level in batch)
1818
{
1919
context.Database.ApplyLevelMetadataFromAttributes(level);
2020
}
2121

2222
context.Database.SaveChanges();
23+
return batch.Length;
2324
}
2425
}

Refresh.Interfaces.Workers/Migrations/BackfillModdedPlanetFlagsMigration.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@ protected override IQueryable<GameUser> SortAndFilter(IQueryable<GameUser> query
1616
|| u.BetaPlanetsHash != "0");
1717
}
1818

19-
protected override void Migrate(WorkContext context, GameUser[] batch)
19+
protected override int Migrate(WorkContext context, GameUser[] batch)
2020
{
2121
foreach (GameUser user in batch)
2222
{
2323
context.Database.UpdatePlanetModdedStatus(user);
2424
}
2525

2626
context.Database.SaveChanges();
27+
return batch.Length;
2728
}
2829
}

Refresh.Interfaces.Workers/Migrations/BackfillReviewLabelsMigration.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,25 @@
1-
using Refresh.Database.Models.Comments;
1+
using Refresh.Database.Models.Comments;
2+
using Refresh.Database.Models.Levels;
23
using Refresh.Workers;
34

45
namespace Refresh.Interfaces.Workers.Migrations;
56

67
public class BackfillReviewLabelsMigration : MigrationJob<GameReview>
78
{
8-
protected override void Migrate(WorkContext context, GameReview[] batch)
9+
protected override int Migrate(WorkContext context, GameReview[] batch)
910
{
10-
context.Database.MigrateReviewLabels(batch);
11+
foreach (GameReview review in batch)
12+
{
13+
#pragma warning disable CS0618 // LabelsString is obsolete
14+
if (string.IsNullOrWhiteSpace(review.LabelsString)) continue;
15+
16+
context.Database.Update(review);
17+
review.Labels = LabelExtensions.FromLbpCommaList(review.LabelsString).ToList();
18+
#pragma warning restore CS0618
19+
}
20+
21+
context.Database.SaveChanges();
22+
return batch.Length;
1123
}
1224

1325
protected override IQueryable<GameReview> SortAndFilter(IQueryable<GameReview> query)

Refresh.Interfaces.Workers/Migrations/BackfillRevisionMigration.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ namespace Refresh.Interfaces.Workers.Migrations;
55

66
public class BackfillRevisionMigration : MigrationJob<GameLevel>
77
{
8-
protected override void Migrate(WorkContext context, GameLevel[] batch)
8+
protected override int Migrate(WorkContext context, GameLevel[] batch)
99
{
1010
foreach (GameLevel level in batch)
1111
{
1212
context.Database.CreateRevisionForLevel(level, null);
1313
}
14+
return batch.Length;
1415
}
1516

1617
protected override IQueryable<GameLevel> SortAndFilter(IQueryable<GameLevel> query)

Refresh.Interfaces.Workers/Migrations/CalculateScoreRanksMigration.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@ protected override IQueryable<GameLevel> SortAndFilter(IQueryable<GameLevel> que
1212
return query.OrderBy(l => l.LevelId);
1313
}
1414

15-
protected override void Migrate(WorkContext context, GameLevel[] batch)
15+
protected override int Migrate(WorkContext context, GameLevel[] batch)
1616
{
1717
foreach (GameLevel level in batch)
1818
{
1919
context.Database.RecalculateScoreStatistics(level);
2020
}
2121
context.Database.SaveChanges();
22+
return batch.Length;
2223
}
2324
}

Refresh.Interfaces.Workers/Migrations/ClampPlayerLimitsMigration.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ protected override IQueryable<GameLevel> SortAndFilter(IQueryable<GameLevel> que
1313
return query.OrderBy(l => l.LevelId);
1414
}
1515

16-
protected override void Migrate(WorkContext context, GameLevel[] batch)
16+
protected override int Migrate(WorkContext context, GameLevel[] batch)
1717
{
1818
foreach (GameLevel level in batch)
1919
{
@@ -26,5 +26,7 @@ protected override void Migrate(WorkContext context, GameLevel[] batch)
2626
level.MinPlayers = Math.Clamp(level.MinPlayers, 1, 4);
2727
level.MaxPlayers = Math.Clamp(level.MaxPlayers, 1, 4);
2828
}
29+
30+
return batch.Length;
2931
}
3032
}

Refresh.Interfaces.Workers/Migrations/CorrectWebsitePinProgressPlatform.cs renamed to Refresh.Interfaces.Workers/Migrations/CorrectWebsitePinProgressPlatformMigration.cs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77

88
namespace Refresh.Interfaces.Workers.Migrations;
99

10-
public class CorrectWebsitePinProgressPlatform : MigrationJob<PinProgressRelation>
10+
public class CorrectWebsitePinProgressPlatformMigration : MigrationJob<PinProgressRelation>
1111
{
12-
private List<long> websitePinIds =
12+
private readonly List<long> WebsitePinIds =
1313
[
1414
(long)ServerPins.HeartPlayerOnWebsite,
1515
(long)ServerPins.QueueLevelOnWebsite,
@@ -19,13 +19,15 @@ public class CorrectWebsitePinProgressPlatform : MigrationJob<PinProgressRelatio
1919
protected override IQueryable<PinProgressRelation> SortAndFilter(IQueryable<PinProgressRelation> query)
2020
{
2121
return query
22-
.Where(p => this.websitePinIds.Contains(p.PinId))
22+
.Where(p => this.WebsitePinIds.Contains(p.PinId))
2323
.OrderBy(p => p.PinId);
2424
}
2525

26-
protected override void Migrate(WorkContext context, PinProgressRelation[] batch)
26+
protected override int Migrate(WorkContext context, PinProgressRelation[] batch)
2727
{
28-
foreach (long pinId in this.websitePinIds)
28+
int pinsLeft = batch.Length;
29+
30+
foreach (long pinId in this.WebsitePinIds)
2931
{
3032
IEnumerable<IGrouping<ObjectId, PinProgressRelation>> pinsByUser = batch
3133
.Where(r => r.PinId == pinId)
@@ -38,12 +40,16 @@ protected override void Migrate(WorkContext context, PinProgressRelation[] batch
3840

3941
// Find best one by the current user
4042
PinProgressRelation relationToMigrate = group.MaxBy(r => r.Progress)!;
43+
List<PinProgressRelation> relationsToRemove = group.ToList();
4144

42-
// Remove all already existing progresses to remove duplicates
43-
context.Database.RemoveAllPinProgressesByIdAndUser(pinId, relationToMigrate.PublisherId, false);
45+
foreach (PinProgressRelation relation in group)
46+
{
47+
context.Database.RemovePinProgress(relation, false);
48+
pinsLeft--;
49+
}
4450

4551
// Now take the best progress we've just got and add it as a website pin, preserving other old metadata
46-
context.Database.AddPinProgress(new()
52+
PinProgressRelation newRelation = new()
4753
{
4854
PinId = relationToMigrate.PinId,
4955
Progress = relationToMigrate.Progress,
@@ -52,10 +58,14 @@ protected override void Migrate(WorkContext context, PinProgressRelation[] batch
5258
LastUpdated = relationToMigrate.LastUpdated,
5359
IsBeta = false, // doesn't matter here
5460
Platform = TokenPlatform.Website,
55-
}, false);
61+
};
62+
63+
context.Database.AddPinProgress(newRelation, false);
64+
pinsLeft++;
5665
}
5766
}
5867

5968
context.Database.SaveChanges();
69+
return pinsLeft;
6070
}
6171
}

0 commit comments

Comments
 (0)