Skip to content

Instantly share code, notes, and snippets.

@BFalkner
Forked from nkallen/MODULARITY_OLYMPICS.markdown
Created February 17, 2010 21:50
Show Gist options
  • Select an option

  • Save BFalkner/307052 to your computer and use it in GitHub Desktop.

Select an option

Save BFalkner/307052 to your computer and use it in GitHub Desktop.

Notes

The original subs actually making a query with printing the query, so no real queries here either.

The 'transaction' from the original doesn't appear to do anything except close over the connection argument. I didn't implement any transactional functionality because the original didn't appear to have any.

It doesn't make sense to memoize the non-query stuff and always run the query which is going to be your slowest thing. It also doesn't make sense to memoize inserts which always need to run.

Output

Forward:
Instantiating Query Object
Selecting SELECT ... FROM ... FOR UPDATE ... on Connection String
Measured select at 1.026 seconds
Did not timeout! Yay fast database!
Result: Some([1; 2; 3])
Measured select at 0.000 seconds
Did not timeout! Yay fast database!
Result: Some([1; 2; 3])
Executing INSERT ... on Connection String
Measured execute at 1.013 seconds
Did not timeout! Yay fast database!
Result: Some(True)

Backward:
Instantiating Query Object
Selecting SELECT ... FROM ... FOR UPDATE ... on Connection String
Did not timeout! Yay fast database!
Measured select at 1.012 seconds
Result: Some([1; 2; 3])
Result: Some([1; 2; 3])
Executing INSERT ... on Connection String
Did not timeout! Yay fast database!
Measured execute at 1.010 seconds
Result: Some(True)
let select connection query =
async {
do! Async.Sleep(1000)
ignore <| printfn "Selecting %s on %s" query connection
return [1; 2; 3]
}
let execute connection query =
async {
do! Async.Sleep(1000)
ignore <| printfn "Executing %s on %s" query connection
return true
}
let statistics name op =
let stopwatch = System.Diagnostics.Stopwatch.StartNew()
let result = op()
stopwatch.Stop()
ignore <| printfn "Measured %s at %.3f seconds" name (float stopwatch.ElapsedMilliseconds / 1000.0)
result
let statisticsAsync name op =
async {
let stopwatch = System.Diagnostics.Stopwatch.StartNew()
let! result = op
stopwatch.Stop()
ignore <| printfn "Measured %s at %.3f seconds" name (float stopwatch.ElapsedMilliseconds / 1000.0)
return result
}
let memoize (cache:Map<'a,'b> ref) key f =
match cache.Value.TryFind key with
| Some(result) -> result
| None ->
printfn "Instantiating Query Object"
let result = f()
cache.Value <- cache.Value.Add(key, result)
result
let memoizeAsync (cache:Map<'a,'b> ref) key f =
match cache.Value.TryFind key with
| Some(result) -> async { return result }
| None ->
printfn "Instantiating Query Object"
async {
let! result = f()
cache.Value <- cache.Value.Add(key, result)
return result
}
let runWithTimeout timeout op =
try
let result = Async.RunSynchronously(op, timeout)
printfn "Did not timeout! Yay fast database!"
Some(result)
with
| :? System.TimeoutException -> printfn "Timed out after %d milliseconds" timeout; None
type IEvaluator =
abstract member Select : string -> int list option
abstract member Execute : string -> bool option
abstract member Name : string
let createEvaluator connection =
let cache = ref Map.empty
{ new IEvaluator with
member x.Select(query) = (fun () -> select connection query)
|> memoizeAsync cache query
|> statisticsAsync "select"
|> runWithTimeout 2000
member x.Execute(query) = execute connection query
|> statisticsAsync "execute"
|> runWithTimeout 2000
member x.Name = "Forward" }
let createReversedEvaluator connection =
let cache = ref Map.empty
{ new IEvaluator with
member x.Select(query) = (fun () ->
(fun () ->
select connection query
|> runWithTimeout 2000)
|> statistics "select")
|> memoize cache query
member x.Execute(query) = (fun () -> execute connection query
|> runWithTimeout 2000)
|> statistics "execute"
member x.Name = "Backward" }
let evaluators = List.map (fun evaluator -> evaluator "Connection String") [createEvaluator; createReversedEvaluator]
for evaluator in evaluators do
printfn "%s:" evaluator.Name
printfn "Result: %O" <| evaluator.Select "SELECT ... FROM ... FOR UPDATE ..."
printfn "Result: %O" <| evaluator.Select "SELECT ... FROM ... FOR UPDATE ..."
printfn "Result: %O" <| evaluator.Execute "INSERT ..."
printfn ""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment