Skip to content

Commit

Permalink
2514: Add row version to packages table to detect concurrency conflic…
Browse files Browse the repository at this point in the history
…ts when updating IsLatest
  • Loading branch information
chenriksson committed Dec 9, 2016
1 parent b31a5dd commit 2b8d0c9
Show file tree
Hide file tree
Showing 6 changed files with 199 additions and 3 deletions.
6 changes: 6 additions & 0 deletions src/NuGetGallery.Core/Entities/Package.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,12 @@ public Package()

public bool RequiresLicenseAcceptance { get; set; }

/// <summary>
/// Timestamp for optimistic concurrency checks to prevent conflicting IsLatest updates from multiple uploads
/// </summary>
[Timestamp]
public byte[] RowVersion { get; set; }

/// <remarks>
/// Has a max length of 4000. Is not indexed and not used for searches. Db column is nvarchar(max).
/// </remarks>
Expand Down
16 changes: 13 additions & 3 deletions src/NuGetGallery/Controllers/PackagesController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity.Infrastructure;
using System.Diagnostics;
using System.Globalization;
using System.IO;
Expand Down Expand Up @@ -1178,9 +1179,18 @@ public virtual async Task<ActionResult> VerifyPackage(VerifyPackageRequest formD
// save package to blob storage
uploadFile.Position = 0;
await _packageFileService.SavePackageFileAsync(package, uploadFile.AsSeekableStream());

// commit all changes to database as an atomic transaction
await _entitiesContext.SaveChangesAsync();

try
{
// commit all changes to database as an atomic transaction
await _entitiesContext.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
// another package upload modified IsLatest state for packages in this registration
TempData["Message"] = "Your attempt to verify the package submission failed, because of a conflict with another upload. Please try again.";
return new RedirectResult(Url.VerifyPackage());
}

// tell Lucene to update index for the new package
_indexingService.UpdateIndex();
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 18 additions & 0 deletions src/NuGetGallery/Migrations/201612091849195_PackagesRowVersion.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace NuGetGallery.Migrations
{
using System;
using System.Data.Entity.Migrations;

public partial class PackagesRowVersion : DbMigration
{
public override void Up()
{
AddColumn("dbo.Packages", "RowVersion", c => c.Binary(nullable: false, fixedLength: true, timestamp: true, storeType: "rowversion"));
}

public override void Down()
{
DropColumn("dbo.Packages", "RowVersion");
}
}
}
Loading

0 comments on commit 2b8d0c9

Please sign in to comment.