Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions frameworks/FSharp/oxpecker/src/App/App.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
</ItemGroup>

<ItemGroup>
<PackageReference Update="FSharp.Core" Version="8.0.400" />
<PackageReference Include="Oxpecker" Version="0.14.1" />
<PackageReference Include="Oxpecker.ViewEngine" Version="0.14.0" />
<PackageReference Include="Npgsql" Version="8.0.3" />
<PackageReference Include="SpanJson" Version="4.2.0" />
<PackageReference Update="FSharp.Core" Version="9.0.100" />
<PackageReference Include="Oxpecker" Version="1.0.0" />
<PackageReference Include="Oxpecker.ViewEngine" Version="1.0.0" />
<PackageReference Include="Npgsql" Version="9.0.1" />
<PackageReference Include="SpanJson" Version="4.2.1" />
</ItemGroup>
</Project>
6 changes: 4 additions & 2 deletions frameworks/FSharp/oxpecker/src/App/Common.fs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ module Common =
[<Struct>]
[<CLIMutable>]
type JsonMessage = {
message : string
message: string
}

[<CLIMutable>]
Expand All @@ -26,7 +26,9 @@ module Common =
}

[<Literal>]
let ConnectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=1024;NoResetOnClose=true;Enlist=false;Max Auto Prepare=3"
let ConnectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=1024;NoResetOnClose=true;Enlist=false"
[<Literal>]
let MultiplexedConnectionString = ConnectionString + ";Max Auto Prepare=3;Multiplexing=true"

let FortuneComparer = {
new IComparer<Fortune> with
Expand Down
31 changes: 18 additions & 13 deletions frameworks/FSharp/oxpecker/src/App/Db.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ namespace App

open System
open System.Data
open System.Data.Common
open System.Text
open Microsoft.Extensions.ObjectPool
open Npgsql


Expand All @@ -15,6 +14,7 @@ module Db =
use db = new NpgsqlConnection(ConnectionString)
use cmd = db.CreateCommand(CommandText = "SELECT id, message FROM fortune")
do! db.OpenAsync()
do! cmd.PrepareAsync()
use! rdr = cmd.ExecuteReaderAsync(CommandBehavior.CloseConnection)
while! rdr.ReadAsync() do
result.Add { id = rdr.GetInt32(0); message = rdr.GetString(1) }
Expand All @@ -31,7 +31,7 @@ module Db =
TypedValue = Random.Shared.Next(1, 10001)
)
cmd.Parameters.Add(id) |> ignore
cmd
struct(cmd, id)

let private readSingleRow (cmd: NpgsqlCommand) =
task {
Expand All @@ -43,41 +43,46 @@ module Db =
let loadSingleRow () =
task {
use db = new NpgsqlConnection(ConnectionString)
let struct(cmd', _) = createReadCommand db
use cmd = cmd'
do! db.OpenAsync()
use cmd = createReadCommand db
do! cmd.PrepareAsync()
return! readSingleRow cmd
}

let private readMultipleRows (count: int) (conn: NpgsqlConnection) =
let result = Array.zeroCreate count
task {
use cmd = createReadCommand conn
let struct(cmd', idParam) = createReadCommand conn
use cmd = cmd'
for i in 0..result.Length-1 do
cmd.Parameters["@Id"].Value <- Random.Shared.Next(1, 10001)
let! row = readSingleRow cmd
result[i] <- row
idParam.TypedValue <- Random.Shared.Next(1, 10001)
return result
}

let loadMultipleRows (count: int) =
task {
use db = new NpgsqlConnection(ConnectionString)
use db = new NpgsqlConnection(MultiplexedConnectionString)
do! db.OpenAsync()
return! readMultipleRows count db
}

let private maxBatch = 500
let private queries = Array.zeroCreate (maxBatch + 1)
let private stringBuilderPool = DefaultObjectPoolProvider().CreateStringBuilderPool()
let private batchUpdateString batchSize =
match queries[batchSize] with
| null ->
let lastIndex = batchSize - 1
let sb = StringBuilder()
let sb = stringBuilderPool.Get()
sb.Append("UPDATE world SET randomNumber = temp.randomNumber FROM (VALUES ") |> ignore
for i in 0..lastIndex-1 do
sb.AppendFormat("(@Id_{0}, @Rn_{0}), ", i) |> ignore
sb.AppendFormat("(@Id_{0}, @Rn_{0}) ORDER BY 1) AS temp(id, randomNumber) WHERE temp.id = world.id", lastIndex) |> ignore
let result = sb.ToString()
stringBuilderPool.Return(sb)
queries[batchSize] <- result
result
| q ->
Expand All @@ -95,15 +100,15 @@ module Db =
for i in 0..results.Length-1 do
let randomNumber = Random.Shared.Next(1, 10001)
let struct(rnParamName, idParamName) = paramNames[i]
let random = NpgsqlParameter<int>(ParameterName = rnParamName, DbType = DbType.Int32, TypedValue = randomNumber)
command.Parameters.Add(random) |> ignore
let id = NpgsqlParameter<int>(ParameterName = idParamName, DbType = DbType.Int32, TypedValue = results[i].id)
command.Parameters.Add(id) |> ignore
command.Parameters.Add(NpgsqlParameter<int>(
ParameterName = rnParamName, DbType = DbType.Int32, TypedValue = randomNumber)) |> ignore
command.Parameters.Add(NpgsqlParameter<int>(
ParameterName = idParamName, DbType = DbType.Int32, TypedValue = results[i].id)) |> ignore
results[i] <- { results[i] with randomnumber = randomNumber }

let doMultipleUpdates (count: int) =
task {
use conn = new NpgsqlConnection(ConnectionString)
use conn = new NpgsqlConnection(MultiplexedConnectionString)
do! conn.OpenAsync()
let! results = readMultipleRows count conn
use cmd = conn.CreateCommand(CommandText = batchUpdateString count)
Expand Down
39 changes: 13 additions & 26 deletions frameworks/FSharp/oxpecker/src/App/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,21 @@ namespace App

open System
open Oxpecker
open System.Runtime.InteropServices

[<RequireQualifiedAccess>]
module HtmlViews =
module HttpHandlers =
open System.Text
open Microsoft.AspNetCore.Http
open SpanJson
open Oxpecker.ViewEngine

let private head, tail =
let private extra =
{
id = 0
message = "Additional fortune added at request time."
}

let private fortunesHeadAndTail =
(fun (content: HtmlElement) ->
html() {
head() {
Expand All @@ -26,32 +34,11 @@ module HtmlViews =
} :> HtmlElement
) |> RenderHelpers.prerender

let fortunes (fortunesData: ResizeArray<Fortune>) =
let fragment = __()
for fortune in CollectionsMarshal.AsSpan fortunesData do
tr() {
td() { raw <| string fortune.id }
td() { fortune.message }
}
|> fragment.AddChild
RenderHelpers.combine head tail fragment

[<RequireQualifiedAccess>]
module HttpHandlers =
open System.Text
open Microsoft.AspNetCore.Http
open SpanJson

let private extra =
{
id = 0
message = "Additional fortune added at request time."
}

let rec private renderFortunes (ctx: HttpContext) (data: ResizeArray<Fortune>) =
data.Add extra
data.Sort FortuneComparer
data |> HtmlViews.fortunes |> ctx.WriteHtmlViewChunked
RenderHelpers.CombinedElement(fortunesHeadAndTail, data)
|> ctx.WriteHtmlViewChunked

let fortunes : EndpointHandler =
fun ctx ->
Expand Down
29 changes: 20 additions & 9 deletions frameworks/FSharp/oxpecker/src/App/RenderHelpers.fs
Original file line number Diff line number Diff line change
@@ -1,8 +1,27 @@
module RenderHelpers

open System.Text
open App
open Oxpecker.ViewEngine

type HeadAndTail =
{
Head: string
Tail: string
}

[<Struct>]
type CombinedElement(ht: HeadAndTail, fortunesData: ResizeArray<Fortune>) =
interface HtmlElement with
member this.Render(sb) =
sb.Append(ht.Head) |> ignore
for fortune in fortunesData do
(tr() {
td() { raw <| string fortune.id }
td() { fortune.message }
}).Render(sb)
sb.Append(ht.Tail) |> ignore

let prerender (view: HtmlElement -> HtmlElement) =
let sb = StringBuilder()
let mutable head = ""
Expand All @@ -13,12 +32,4 @@
sb.Clear() |> ignore }
let readyView = view fakeHole
readyView.Render(sb)
(head, sb.ToString())

let inline combine (head: string) (tail: string) (hole: HtmlElement) =
{ new HtmlElement with
member this.Render(sb) =
sb.Append(head) |> ignore
hole.Render(sb)
sb.Append(tail) |> ignore
}
{ Head = head; Tail = sb.ToString() }
Loading