Browse Source

ASP.Net Core add platform dataupdates (#3802)

* ASP.NET Core, Plat, DataUpdates

* Fix nancy-netcore
Ben Adams 7 years ago
parent
commit
e65cce0c67

+ 61 - 0
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.Fortunes.cs

@@ -0,0 +1,61 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Collections.Generic;
+using System.IO.Pipelines;
+using System.Text.Encodings.Web;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
+
+namespace PlatformBenchmarks
+{
+    public partial class BenchmarkApplication
+    {
+        private async Task Fortunes(PipeWriter pipeWriter)
+        {
+            OutputFortunes(pipeWriter, await Db.LoadFortunesRows());
+        }
+
+        private void OutputFortunes(PipeWriter pipeWriter, List<Fortune> model)
+        {
+            var writer = GetWriter(pipeWriter);
+
+            // HTTP 1.1 OK
+            writer.Write(_http11OK);
+
+            // Server headers
+            writer.Write(_headerServer);
+
+            // Date header
+            writer.Write(DateHeader.HeaderBytes);
+
+            // Content-Type header
+            writer.Write(_headerContentTypeHtml);
+
+            // Content-Length header
+            writer.Write(_headerContentLength);
+
+            var lengthWriter = writer;
+            writer.Write(_contentLengthGap);
+
+            // End of headers
+            writer.Write(_eoh);
+
+            var bodyStart = writer.Buffered;
+            // Body
+            writer.Write(_fortunesTableStart);
+            foreach (var item in model)
+            {
+                writer.Write(_fortunesRowStart);
+                writer.WriteNumeric((uint)item.Id);
+                writer.Write(_fortunesColumn);
+                writer.WriteUtf8String(HtmlEncoder.Encode(item.Message));
+                writer.Write(_fortunesRowEnd);
+            }
+            writer.Write(_fortunesTableEnd);
+            lengthWriter.WriteNumeric((uint)(writer.Buffered - bodyStart));
+
+            writer.Commit();
+        }
+    }
+}

+ 41 - 0
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.Json.cs

@@ -0,0 +1,41 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.IO.Pipelines;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
+using Utf8Json;
+
+namespace PlatformBenchmarks
+{
+    public partial class BenchmarkApplication
+    {
+        private static void Json(PipeWriter pipeWriter)
+        {
+            var writer = GetWriter(pipeWriter);
+
+            // HTTP 1.1 OK
+            writer.Write(_http11OK);
+
+            // Server headers
+            writer.Write(_headerServer);
+
+            // Date header
+            writer.Write(DateHeader.HeaderBytes);
+
+            // Content-Type header
+            writer.Write(_headerContentTypeJson);
+
+            // Content-Length header
+            writer.Write(_headerContentLength);
+            var jsonPayload = JsonSerializer.SerializeUnsafe(new JsonMessage { message = "Hello, World!" });
+            writer.WriteNumeric((uint)jsonPayload.Count);
+
+            // End of headers
+            writer.Write(_eoh);
+
+            // Body
+            writer.Write(jsonPayload);
+            writer.Commit();
+        }
+    }
+}

+ 39 - 0
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.Plaintext.cs

@@ -0,0 +1,39 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.IO.Pipelines;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
+
+namespace PlatformBenchmarks
+{
+    public partial class BenchmarkApplication
+    {
+        private static void PlainText(PipeWriter pipeWriter)
+        {
+            var writer = GetWriter(pipeWriter);
+
+            // HTTP 1.1 OK
+            writer.Write(_http11OK);
+
+            // Server headers
+            writer.Write(_headerServer);
+
+            // Date header
+            writer.Write(DateHeader.HeaderBytes);
+
+            // Content-Type header
+            writer.Write(_headerContentTypeText);
+
+            // Content-Length header
+            writer.Write(_headerContentLength);
+            writer.WriteNumeric((uint)_plainTextBody.Length);
+
+            // End of headers
+            writer.Write(_eoh);
+
+            // Body
+            writer.Write(_plainTextBody);
+            writer.Commit();
+        }
+    }
+}

+ 47 - 0
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.SingleQuery.cs

@@ -0,0 +1,47 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.IO.Pipelines;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
+using Utf8Json;
+
+namespace PlatformBenchmarks
+{
+    public partial class BenchmarkApplication
+    {
+        private async Task SingleQuery(PipeWriter pipeWriter)
+        {
+            OutputSingleQuery(pipeWriter, await Db.LoadSingleQueryRow());
+        }
+
+        private static void OutputSingleQuery(PipeWriter pipeWriter, World row)
+        {
+            var writer = GetWriter(pipeWriter);
+
+            // HTTP 1.1 OK
+            writer.Write(_http11OK);
+
+            // Server headers
+            writer.Write(_headerServer);
+
+            // Date header
+            writer.Write(DateHeader.HeaderBytes);
+
+            // Content-Type header
+            writer.Write(_headerContentTypeJson);
+
+            // Content-Length header
+            writer.Write(_headerContentLength);
+            var jsonPayload = JsonSerializer.SerializeUnsafe(row);
+            writer.WriteNumeric((uint)jsonPayload.Count);
+
+            // End of headers
+            writer.Write(_eoh);
+
+            // Body
+            writer.Write(jsonPayload);
+            writer.Commit();
+        }
+    }
+}

+ 47 - 0
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.Updates.cs

@@ -0,0 +1,47 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.IO.Pipelines;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
+using Utf8Json;
+
+namespace PlatformBenchmarks
+{
+    public partial class BenchmarkApplication
+    {
+        private async Task Updates(PipeWriter pipeWriter, int count)
+        {
+            OutputUpdates(pipeWriter, await Db.LoadMultipleUpdatesRows(count));
+        }
+
+        private static void OutputUpdates(PipeWriter pipeWriter, World[] rows)
+        {
+            var writer = GetWriter(pipeWriter);
+
+            // HTTP 1.1 OK
+            writer.Write(_http11OK);
+
+            // Server headers
+            writer.Write(_headerServer);
+
+            // Date header
+            writer.Write(DateHeader.HeaderBytes);
+
+            // Content-Type header
+            writer.Write(_headerContentTypeJson);
+
+            // Content-Length header
+            writer.Write(_headerContentLength);
+            var jsonPayload = JsonSerializer.SerializeUnsafe(rows);
+            writer.WriteNumeric((uint)jsonPayload.Count);
+
+            // End of headers
+            writer.Write(_eoh);
+
+            // Body
+            writer.Write(jsonPayload);
+            writer.Commit();
+        }
+    }
+}

+ 38 - 150
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.cs

@@ -2,12 +2,10 @@
 // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
 
 using System;
-using System.Collections.Generic;
+using System.Buffers.Text;
 using System.IO.Pipelines;
-using System.Text.Encodings.Web;
 using System.Threading.Tasks;
 using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
-using Utf8Json;
 
 namespace PlatformBenchmarks
 {
@@ -35,7 +33,7 @@ namespace PlatformBenchmarks
         private readonly static AsciiString _fortunesTableEnd = "</table></body></html>";
         private readonly static AsciiString _contentLengthGap = new string(' ', 4);
 
-        public static IDb Db { get; set; }
+        public static RawDb Db { get; set; }
 
         public static class Paths
         {
@@ -43,9 +41,11 @@ namespace PlatformBenchmarks
             public readonly static AsciiString Json = "/json";
             public readonly static AsciiString Fortunes = "/fortunes";
             public readonly static AsciiString Plaintext = "/plaintext";
+            public readonly static AsciiString Updates = "/updates/queries=";
         }
 
         private RequestType _requestType;
+        private int _queries;
 
         public void OnStartLine(HttpMethod method, HttpVersion version, Span<byte> target, Span<byte> path, Span<byte> query, Span<byte> customMethod, bool pathEncoded)
         {
@@ -69,173 +69,60 @@ namespace PlatformBenchmarks
                 {
                     requestType = RequestType.PlainText;
                 }
+                else if (Paths.Updates.Length <= pathLength && path.StartsWith(Paths.Updates))
+                {
+                    _queries = ParseQueries(path);
+                    requestType = RequestType.Updates;
+                }
             }
 
             _requestType = requestType;
         }
 
+        private static int ParseQueries(Span<byte> path)
+        {
+            if (!Utf8Parser.TryParse(path.Slice(Paths.Updates.Length), out int queries, out _) || queries < 1)
+            {
+                queries = 1;
+            }
+            else if (queries > 500)
+            {
+                queries = 500;
+            }
+
+            return queries;
+        }
+
         public Task ProcessRequestAsync()
         {
-            if (_requestType == RequestType.PlainText)
+            var requestType = _requestType;
+            var task = Task.CompletedTask;
+            if (requestType == RequestType.PlainText)
             {
                 PlainText(Writer);
             }
-            else if (_requestType == RequestType.Json)
+            else if (requestType == RequestType.Json)
             {
                 Json(Writer);
             }
-            else if (_requestType == RequestType.Fortunes)
+            else if (requestType == RequestType.Fortunes)
             {
-                return Fortunes(Writer);
+                task = Fortunes(Writer);
             }
-            else if (_requestType == RequestType.SingleQuery)
+            else if (requestType == RequestType.SingleQuery)
             {
-                return SingleQuery(Writer);
+                task = SingleQuery(Writer);
             }
-            else
+            else if (requestType == RequestType.Updates)
             {
-                Default(Writer);
+                task = Updates(Writer, _queries);
             }
-
-            return Task.CompletedTask;
-        }
-
-        private static void PlainText(PipeWriter pipeWriter)
-        {
-            var writer = GetWriter(pipeWriter);
-
-            // HTTP 1.1 OK
-            writer.Write(_http11OK);
-
-            // Server headers
-            writer.Write(_headerServer);
-
-            // Date header
-            writer.Write(DateHeader.HeaderBytes);
-
-            // Content-Type header
-            writer.Write(_headerContentTypeText);
-
-            // Content-Length header
-            writer.Write(_headerContentLength);
-            writer.WriteNumeric((uint)_plainTextBody.Length);
-
-            // End of headers
-            writer.Write(_eoh);
-
-            // Body
-            writer.Write(_plainTextBody);
-            writer.Commit();
-        }
-
-        private static void Json(PipeWriter pipeWriter)
-        {
-            var writer = GetWriter(pipeWriter);
-
-            // HTTP 1.1 OK
-            writer.Write(_http11OK);
-
-            // Server headers
-            writer.Write(_headerServer);
-
-            // Date header
-            writer.Write(DateHeader.HeaderBytes);
-
-            // Content-Type header
-            writer.Write(_headerContentTypeJson);
-
-            // Content-Length header
-            writer.Write(_headerContentLength);
-            var jsonPayload = JsonSerializer.SerializeUnsafe(new { message = "Hello, World!" });
-            writer.WriteNumeric((uint)jsonPayload.Count);
-
-            // End of headers
-            writer.Write(_eoh);
-
-            // Body
-            writer.Write(jsonPayload);
-            writer.Commit();
-        }
-
-        private async Task Fortunes(PipeWriter pipeWriter)
-        {
-            OutputFortunes(pipeWriter, await Db.LoadFortunesRows());
-        }
-
-        private void OutputFortunes(PipeWriter pipeWriter, List<Fortune> model)
-        {
-            var writer = GetWriter(pipeWriter);
-
-            // HTTP 1.1 OK
-            writer.Write(_http11OK);
-
-            // Server headers
-            writer.Write(_headerServer);
-
-            // Date header
-            writer.Write(DateHeader.HeaderBytes);
-
-            // Content-Type header
-            writer.Write(_headerContentTypeHtml);
-
-            // Content-Length header
-            writer.Write(_headerContentLength);
-
-            var lengthWriter = writer;
-            writer.Write(_contentLengthGap);
-
-            // End of headers
-            writer.Write(_eoh);
-
-            var bodyStart = writer.Buffered;
-            // Body
-            writer.Write(_fortunesTableStart);
-            foreach (var item in model)
+            else
             {
-                writer.Write(_fortunesRowStart);
-                writer.WriteNumeric((uint)item.Id);
-                writer.Write(_fortunesColumn);
-                writer.WriteUtf8String(HtmlEncoder.Encode(item.Message));
-                writer.Write(_fortunesRowEnd);
+                Default(Writer);
             }
-            writer.Write(_fortunesTableEnd);
-            lengthWriter.WriteNumeric((uint)(writer.Buffered - bodyStart));
-
-            writer.Commit();
-        }
-
-        private async Task SingleQuery(PipeWriter pipeWriter)
-        {
-            OutputSingleQuery(pipeWriter, await Db.LoadSingleQueryRow());
-        }
-
-        private static void OutputSingleQuery(PipeWriter pipeWriter, World row)
-        {
-            var writer = GetWriter(pipeWriter);
-
-            // HTTP 1.1 OK
-            writer.Write(_http11OK);
-
-            // Server headers
-            writer.Write(_headerServer);
-
-            // Date header
-            writer.Write(DateHeader.HeaderBytes);
-
-            // Content-Type header
-            writer.Write(_headerContentTypeJson);
-
-            // Content-Length header
-            writer.Write(_headerContentLength);
-            var jsonPayload = JsonSerializer.SerializeUnsafe(row);
-            writer.WriteNumeric((uint)jsonPayload.Count);
 
-            // End of headers
-            writer.Write(_eoh);
-
-            // Body
-            writer.Write(jsonPayload);
-            writer.Commit();
+            return task;
         }
 
         private static void Default(PipeWriter pipeWriter)
@@ -265,7 +152,8 @@ namespace PlatformBenchmarks
             PlainText,
             Json,
             Fortunes,
-            SingleQuery
+            SingleQuery,
+            Updates
         }
     }
 }

+ 38 - 5
frameworks/CSharp/aspnetcore/PlatformBenchmarks/Data/BatchUpdateString.cs

@@ -3,22 +3,55 @@
 
 using System.Collections.Generic;
 using System.Linq;
+using System.Runtime.CompilerServices;
 
 namespace PlatformBenchmarks
 {
     internal class BatchUpdateString
     {
-        public static IList<BatchUpdateString> Strings { get;} = 
-            Enumerable.Range(0, 500)
+        private const int MaxBatch = 500;
+        private static string[] _queries = new string[MaxBatch];
+
+        public static IList<BatchUpdateString> Strings { get; } =
+            Enumerable.Range(0, MaxBatch)
                       .Select(i => new BatchUpdateString
                       {
                           Id = $"Id_{i}",
                           Random = $"Random_{i}",
-                          UpdateQuery = $"UPDATE world SET randomnumber = @Random_{i} WHERE id = @Id_{i};"
+                          BatchSize = i
                       }).ToArray();
-                        
+
+        private int BatchSize { get; set; }
         public string Id { get; set; }
         public string Random { get; set; }
-        public string UpdateQuery { get; set; }
+        public string UpdateQuery => _queries[BatchSize] ?? CreateQuery(BatchSize);
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        private string CreateQuery(int batchSize)
+        {
+            var sb = StringBuilderCache.Acquire();
+            foreach (var q in Enumerable.Range(0, batchSize + 1)
+                .Select(i => $"UPDATE world SET randomnumber = @Random_{i} WHERE id = @Id_{i};"))
+            {
+                sb.Append(q);
+            }
+            var query = sb.ToString();
+            _queries[batchSize] = query;
+            return query;
+        }
+
+        public static void Initalize()
+        {
+            Observe(Strings[0].UpdateQuery);
+            Observe(Strings[4].UpdateQuery);
+            Observe(Strings[9].UpdateQuery);
+            Observe(Strings[14].UpdateQuery);
+            Observe(Strings[19].UpdateQuery);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        private static void Observe(string query)
+        {
+        }
     }
 }

+ 0 - 19
frameworks/CSharp/aspnetcore/PlatformBenchmarks/Data/IDb.cs

@@ -1,19 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved. 
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
-
-using System.Collections.Generic;
-using System.Threading.Tasks;
-
-namespace PlatformBenchmarks
-{
-    public interface IDb
-    {
-        Task<World> LoadSingleQueryRow();
-
-        Task<World[]> LoadMultipleQueriesRows(int count);
-
-        Task<World[]> LoadMultipleUpdatesRows(int count);
-
-        Task<List<Fortune>> LoadFortunesRows();
-    }
-}

+ 0 - 10
frameworks/CSharp/aspnetcore/PlatformBenchmarks/Data/IRandom.cs

@@ -1,10 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved. 
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
-
-namespace PlatformBenchmarks
-{
-    public interface IRandom
-    {
-        int Next(int minValue, int maxValue);
-    }
-}

+ 10 - 0
frameworks/CSharp/aspnetcore/PlatformBenchmarks/Data/JsonMessage.cs

@@ -0,0 +1,10 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace PlatformBenchmarks
+{
+    public struct JsonMessage
+    {
+        public string message { get; set; }
+    }
+}

+ 15 - 3
frameworks/CSharp/aspnetcore/PlatformBenchmarks/Data/Random.cs

@@ -2,19 +2,31 @@
 // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
 
 using System;
+using System.Runtime.CompilerServices;
 using System.Threading;
 
 namespace PlatformBenchmarks
 {
-    public class DefaultRandom : IRandom
+    public class ConcurrentRandom
     {
         private static int nextSeed = 0;
+
         // Random isn't thread safe
-        private static readonly ThreadLocal<Random> _random = new ThreadLocal<Random>(() => new Random(Interlocked.Increment(ref nextSeed)));
+        [ThreadStatic]
+        private static Random _random;
+
+        private static Random Random => _random ?? CreateRandom();
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        private static Random CreateRandom()
+        {
+            _random = new Random(Interlocked.Increment(ref nextSeed));
+            return _random;
+        }
 
         public int Next(int minValue, int maxValue)
         {
-            return _random.Value.Next(minValue, maxValue);
+            return Random.Next(minValue, maxValue);
         }
     }
 }

+ 34 - 37
frameworks/CSharp/aspnetcore/PlatformBenchmarks/Data/RawDb.cs

@@ -5,19 +5,19 @@ using System;
 using System.Collections.Generic;
 using System.Data;
 using System.Data.Common;
-using System.Text;
 using System.Threading.Tasks;
-using Microsoft.Extensions.Options;
 
 namespace PlatformBenchmarks
 {
-    public class RawDb : IDb
+    public class RawDb
     {
-        private readonly IRandom _random;
+        private static readonly Comparison<World> WorldSortComparison = (a, b) => a.Id.CompareTo(b.Id);
+
+        private readonly ConcurrentRandom _random;
         private readonly DbProviderFactory _dbProviderFactory;
         private readonly string _connectionString;
 
-        public RawDb(IRandom random, DbProviderFactory dbProviderFactory, AppSettings appSettings)
+        public RawDb(ConcurrentRandom random, DbProviderFactory dbProviderFactory, AppSettings appSettings)
         {
             _random = random;
             _dbProviderFactory = dbProviderFactory;
@@ -65,59 +65,58 @@ namespace PlatformBenchmarks
             return cmd;
         }
 
+
         public async Task<World[]> LoadMultipleQueriesRows(int count)
         {
-            var result = new World[count];
-
             using (var db = _dbProviderFactory.CreateConnection())
             {
                 db.ConnectionString = _connectionString;
                 await db.OpenAsync();
-                using (var cmd = CreateReadCommand(db))
-                {
-                    for (int i = 0; i < count; i++)
-                    {
-                        result[i] = await ReadSingleRow(db, cmd);
-                        cmd.Parameters["@Id"].Value = _random.Next(1, 10001);
-                    }
-                }
+                return await LoadMultipleRows(count, db);
             }
 
-            return result;
         }
 
-        public async Task<World[]> LoadMultipleUpdatesRows(int count)
+        private async Task<World[]> LoadMultipleRows(int count, DbConnection db)
         {
-            var results = new World[count];
+            using (var cmd = CreateReadCommand(db))
+            {
+                cmd.Parameters["@Id"].Value = _random.Next(1, 10001);
 
-            var updateCommand = new StringBuilder(count);
+                var result = new World[count];
+                for (int i = 0; i < result.Length; i++)
+                {
+                    result[i] = await ReadSingleRow(db, cmd);
+                    cmd.Parameters["@Id"].Value = _random.Next(1, 10001);
+                }
+                return result;
+            }
+        }
 
+        public async Task<World[]> LoadMultipleUpdatesRows(int count)
+        {
             using (var db = _dbProviderFactory.CreateConnection())
             {
                 db.ConnectionString = _connectionString;
                 await db.OpenAsync();
 
-                using (var updateCmd = db.CreateCommand())
-                using (var queryCmd = CreateReadCommand(db))
-                {
-                    for (int i = 0; i < count; i++)
-                    {
-                        results[i] = await ReadSingleRow(db, queryCmd);
-                        queryCmd.Parameters["@Id"].Value = _random.Next(1, 10001);
-                    }
+                var results = await LoadMultipleRows(count, db);
 
-                    // Postgres has problems with deadlocks when these aren't sorted
-                    Array.Sort<World>(results, (a, b) => a.Id.CompareTo(b.Id));
+                // Postgres has problems with deadlocks when these aren't sorted
+                Array.Sort<World>(results, WorldSortComparison);
 
-                    for(int i = 0; i < count; i++)
+                using (var updateCmd = db.CreateCommand())
+                {
+                    for (int i = 0; i < results.Length; i++)
                     {
+                        var strings = BatchUpdateString.Strings[i];
                         var id = updateCmd.CreateParameter();
-                        id.ParameterName = BatchUpdateString.Strings[i].Id;
+                        id.ParameterName = strings.Id;
                         id.DbType = DbType.Int32;
                         updateCmd.Parameters.Add(id);
 
                         var random = updateCmd.CreateParameter();
-                        random.ParameterName = BatchUpdateString.Strings[i].Random;
+                        random.ParameterName = strings.Random;
                         random.DbType = DbType.Int32;
                         updateCmd.Parameters.Add(random);
 
@@ -125,16 +124,14 @@ namespace PlatformBenchmarks
                         id.Value = results[i].Id;
                         random.Value = randomNumber;
                         results[i].RandomNumber = randomNumber;
-
-                        updateCommand.Append(BatchUpdateString.Strings[i].UpdateQuery);
                     }
 
-                    updateCmd.CommandText = updateCommand.ToString();
+                    updateCmd.CommandText = BatchUpdateString.Strings[results.Length - 1].UpdateQuery;
                     await updateCmd.ExecuteNonQueryAsync();
+
+                    return results;
                 }
             }
-
-            return results;
         }
 
         public async Task<List<Fortune>> LoadFortunesRows()

+ 3 - 5
frameworks/CSharp/aspnetcore/PlatformBenchmarks/Data/World.cs

@@ -1,17 +1,15 @@
 // Copyright (c) .NET Foundation. All rights reserved.
 // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
 
-using System.ComponentModel.DataAnnotations.Schema;
+using System.Runtime.InteropServices;
 
 namespace PlatformBenchmarks
 {
-    [Table("world")]
-    public class World
+    [StructLayout(LayoutKind.Sequential, Size = 8)]
+    public struct World
     {
-        [Column("id")]
         public int Id { get; set; }
 
-        [Column("randomnumber")]
         public int RandomNumber { get; set; }
     }
 }

+ 4 - 2
frameworks/CSharp/aspnetcore/PlatformBenchmarks/Program.cs

@@ -24,7 +24,9 @@ namespace PlatformBenchmarks
             Console.WriteLine(BenchmarkApplication.Paths.Json);
             Console.WriteLine(BenchmarkApplication.Paths.Fortunes);
             Console.WriteLine(BenchmarkApplication.Paths.SingleQuery);
+            Console.WriteLine(BenchmarkApplication.Paths.Updates);
             DateHeader.SyncDateTimer();
+            BatchUpdateString.Initalize();
 
             BuildWebHost(args).Run();
         }
@@ -42,11 +44,11 @@ namespace PlatformBenchmarks
 
             if (appSettings.Database == DatabaseServer.PostgreSql)
             {
-                BenchmarkApplication.Db = new RawDb(new DefaultRandom(), NpgsqlFactory.Instance, appSettings);
+                BenchmarkApplication.Db = new RawDb(new ConcurrentRandom(), NpgsqlFactory.Instance, appSettings);
             }
             else if (appSettings.Database == DatabaseServer.MySql)
             {
-                BenchmarkApplication.Db = new RawDb(new DefaultRandom(), MySqlClientFactory.Instance, appSettings);
+                BenchmarkApplication.Db = new RawDb(new ConcurrentRandom(), MySqlClientFactory.Instance, appSettings);
             }
 
             var host = new WebHostBuilder()

+ 59 - 0
frameworks/CSharp/aspnetcore/PlatformBenchmarks/Utilities/StringBuilderCache.cs

@@ -0,0 +1,59 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+using System;
+using System.Text;
+
+namespace PlatformBenchmarks
+{
+    internal static class StringBuilderCache
+    {
+        private const int DefaultCapacity = 1386;
+        private const int MaxBuilderSize = DefaultCapacity * 3;
+
+        [ThreadStatic]
+        private static StringBuilder t_cachedInstance;
+
+        /// <summary>Get a StringBuilder for the specified capacity.</summary>
+        /// <remarks>If a StringBuilder of an appropriate size is cached, it will be returned and the cache emptied.</remarks>
+        public static StringBuilder Acquire(int capacity = DefaultCapacity)
+        {
+            if (capacity <= MaxBuilderSize)
+            {
+                StringBuilder sb = t_cachedInstance;
+                if (capacity < DefaultCapacity)
+                {
+                    capacity = DefaultCapacity;
+                }
+
+                if (sb != null)
+                {
+                    // Avoid stringbuilder block fragmentation by getting a new StringBuilder
+                    // when the requested size is larger than the current capacity
+                    if (capacity <= sb.Capacity)
+                    {
+                        t_cachedInstance = null;
+                        sb.Clear();
+                        return sb;
+                    }
+                }
+            }
+            return new StringBuilder(capacity);
+        }
+
+        public static void Release(StringBuilder sb)
+        {
+            if (sb.Capacity <= MaxBuilderSize)
+            {
+                t_cachedInstance = sb;
+            }
+        }
+
+        public static string GetStringAndRelease(StringBuilder sb)
+        {
+            string result = sb.ToString();
+            Release(sb);
+            return result;
+        }
+    }
+}

+ 2 - 0
frameworks/CSharp/aspnetcore/benchmark_config.json

@@ -23,6 +23,7 @@
     "ado-pg": {
       "fortune_url": "/fortunes",
       "db_url": "/db",
+      "update_url": "/updates/queries=",
       "port": 8080,
       "approach": "Realistic",
       "classification": "Platform",
@@ -42,6 +43,7 @@
     "ado-my": {
       "fortune_url": "/fortunes",
       "db_url": "/db",
+      "update_url": "/updates/queries=",
       "port": 8080,
       "approach": "Realistic",
       "classification": "Platform",

+ 13 - 14
frameworks/CSharp/nancy/src/NancyBenchmark.csproj

@@ -26,23 +26,22 @@
   </ItemGroup>
 
   <ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.1' ">
-    <PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.0-rc1-final" />
+    <PackageReference Include="Microsoft.AspNetCore.App" />
   </ItemGroup>
   
   <ItemGroup Condition=" '$(TargetFramework)' == 'net471' ">
-    <PackageReference Include="Microsoft.AspNetCore" Version="2.1.0-rc1-final" />
-    <PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.1.0-rc1-final" />
-    <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.1.0-rc1-final" />
-    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.1.0-rc1-final" />
-    <!-- Fix https://github.com/aspnet/KestrelHttpServer/pull/2562  -->
-    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets" Version="2.1.0-rtm-30793" />
-    <PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.1.0-rc1-final" />
-    <PackageReference Include="Microsoft.Extensions.Configuration" Version="2.1.0-rc1-final" />
-    <PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="2.1.0-rc1-final" />
-    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.1.0-rc1-final" />
-    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.1.0-rc1-final" />
-    <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.1.0-rc1-final" />
-    <PackageReference Include="Microsoft.AspNetCore.Owin" Version="2.1.0-rc1-final" />
+    <PackageReference Include="Microsoft.AspNetCore" Version="2.1.0" />
+    <PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.1.0" />
+    <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.1.0" />
+    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.1.0" />
+    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets" Version="2.1.0" />
+    <PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.1.0" />
+    <PackageReference Include="Microsoft.Extensions.Configuration" Version="2.1.0" />
+    <PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="2.1.0" />
+    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.1.0" />
+    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.1.0" />
+    <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.1.0" />
+    <PackageReference Include="Microsoft.AspNetCore.Owin" Version="2.1.0" />
     <!-- Make .NET 4.7.1 reference assemblies available even on Linux -->
     <PackageReference Include="Microsoft.TargetingPack.NETFramework.v4.7.1" Version="1.0.0" ExcludeAssets="All" PrivateAssets="All" />
     <Reference Include="netstandard" />