Browse Source

Merge pull request #1855 from k-r-g/clojure-updates

Compojure and http-kit: Update dependencies and sync implemetations
Nate 9 years ago
parent
commit
741cd6d25b

+ 4 - 17
frameworks/Clojure/compojure/README.md

@@ -14,20 +14,7 @@ This is the Compojure portion of a [benchmarking test suite](../) comparing a va
 The dependencies are documented in [project.clj](hello/project.clj),
 The dependencies are documented in [project.clj](hello/project.clj),
 but the main ones are:
 but the main ones are:
 
 
-* [Clojure 1.5.1](http://clojure.org/)
-* [Compojure 1.1.5](https://github.com/weavejester/compojure)
-* [Ring-JSON 0.2.0](https://github.com/ring-clojure/ring-json), which in turn uses [Cheshire](https://github.com/dakrone/cheshire), which in turn uses [Jackson](http://jackson.codehaus.org/)
-* [Korma 0.3.0-RC5](http://sqlkorma.com/)
-
-## Test URLs
-### JSON Encoding Test
-
-http://localhost/hello-compojure-standalone/json
-
-### Data-Store/Database Mapping Test
-
-http://localhost/hello-compojure-standalone/db
-
-### Variable Query Test
-
-http://localhost/hello-compojure-standalone/db/2
+* [Clojure 1.7.0](http://clojure.org/)
+* [Compojure 1.4.0](https://github.com/weavejester/compojure)
+* [Ring-JSON 0.4.0](https://github.com/ring-clojure/ring-json), which in turn uses [Cheshire](https://github.com/dakrone/cheshire), which in turn uses [Jackson](http://jackson.codehaus.org/)
+* [Korma 0.4.2](http://sqlkorma.com/)

+ 6 - 4
frameworks/Clojure/compojure/benchmark_config.json

@@ -5,9 +5,9 @@
       "setup_file": "setup",
       "setup_file": "setup",
       "json_url": "/compojure/json",
       "json_url": "/compojure/json",
       "db_url": "/compojure/db",
       "db_url": "/compojure/db",
-      "query_url": "/compojure/db/",
+      "query_url": "/compojure/queries/",
       "update_url": "/compojure/updates/",
       "update_url": "/compojure/updates/",
-      "fortune_url": "/compojure/fortune-hiccup",
+      "fortune_url": "/compojure/fortunes",
       "plaintext_url": "/compojure/plaintext",
       "plaintext_url": "/compojure/plaintext",
       "port": 8080,
       "port": 8080,
       "approach": "Realistic",
       "approach": "Realistic",
@@ -26,8 +26,10 @@
     },
     },
     "raw": {
     "raw": {
       "setup_file": "setup",
       "setup_file": "setup",
-      "db_url": "/compojure/dbraw",
-      "query_url": "/compojure/dbraw/",
+      "db_url": "/compojure/raw/db",
+      "query_url": "/compojure/raw/queries/",
+      "update_url": "/compojure/raw/updates/",
+      "fortune_url": "/compojure/raw/fortunes",
       "port": 8080,
       "port": 8080,
       "approach": "Realistic",
       "approach": "Realistic",
       "classification": "Micro",
       "classification": "Micro",

+ 12 - 10
frameworks/Clojure/compojure/hello/project.clj

@@ -1,16 +1,18 @@
 (defproject hello "compojure"
 (defproject hello "compojure"
-  :description "JSON/Database tests"
+  :description "FrameworkBenchmarks test implementations"
   :url "http://localhost:3000/"
   :url "http://localhost:3000/"
-  :dependencies [[org.clojure/clojure "1.5.1"]
-                 [compojure "1.1.6"]
-                 [ring/ring-json "0.2.0"]
-                 [korma "0.3.0-RC6"]
+  :min-lein-version "2.0.0"
+  :dependencies [[org.clojure/clojure "1.7.0"]
+                 [compojure "1.4.0"]
+                 [ring/ring-json "0.4.0"]
+                 [korma "0.4.2"]
                  [log4j "1.2.15" :exclusions [javax.mail/mail javax.jms/jms com.sun.jdmk/jmxtools com.sun.jmx/jmxri]]
                  [log4j "1.2.15" :exclusions [javax.mail/mail javax.jms/jms com.sun.jdmk/jmxtools com.sun.jmx/jmxri]]
-                 [mysql/mysql-connector-java "5.1.6"]
-                 [org.clojure/java.jdbc "0.3.0-alpha1"]
+                 [mysql/mysql-connector-java "5.1.38"]
+                 [org.clojure/java.jdbc "0.3.7"]
                  [c3p0/c3p0 "0.9.1.2"]
                  [c3p0/c3p0 "0.9.1.2"]
-                 [hiccup "1.0.4"]]
-  :plugins [[lein-ring "0.8.10"]]
+                 [hiccup "1.0.5"]]
+  :plugins [[lein-ring "0.9.7"]]
   :ring {:handler hello.handler/app}
   :ring {:handler hello.handler/app}
   :profiles
   :profiles
-  {:dev {:dependencies [[ring-mock "0.1.5"]]}})
+  {:dev {:dependencies [[javax.servlet/servlet-api "2.5"]
+                        [ring/ring-mock "0.3.0"]]}})

+ 132 - 117
frameworks/Clojure/compojure/hello/src/hello/handler.clj

@@ -1,8 +1,8 @@
 (ns hello.handler
 (ns hello.handler
   (:import com.mchange.v2.c3p0.ComboPooledDataSource)
   (:import com.mchange.v2.c3p0.ComboPooledDataSource)
   (:use compojure.core
   (:use compojure.core
+        ring.middleware.content-type
         ring.middleware.json
         ring.middleware.json
-        ring.util.response
         korma.db
         korma.db
         korma.core
         korma.core
         hiccup.core
         hiccup.core
@@ -10,55 +10,41 @@
         hiccup.page)
         hiccup.page)
   (:require [compojure.handler :as handler]
   (:require [compojure.handler :as handler]
             [compojure.route :as route]
             [compojure.route :as route]
-            [clojure.java.jdbc :as jdbc]
-            [clojure.java.jdbc.sql :as sql]))
+            [ring.util.response :as ring-resp]
+            [clojure.java.jdbc :as jdbc]))
 
 
-
-; Database connection
-(defdb db (mysql {:subname "//localhost:3306/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=4096&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=false&maintainTimeStats=false&useServerPrepStmts&cacheRSMetadata=true"
-                  :user "benchmarkdbuser"
-                  :password "benchmarkdbpass"
-                  ;;OPTIONAL KEYS
-                  :delimiters "" ;; remove delimiters
-                  :maximum-pool-size 256
-                  }))
-
-
-; Set up entity World and the database representation
-(defentity world
-  (pk :id)
-  (table :world)
-  (entity-fields :id :randomNumber)
-  (database db))
-
-
-(defn get-world
-  "Query a random World record from the database"
-  []
-  (let [id (inc (rand-int 9999))] ; Num between 1 and 10,000
-    (select world
-            (fields :id :randomNumber)
-            (where {:id id }))))
-
-
-(defn run-queries
-  "Run the specified number of queries, return the results"
+(defn sanitize-queries-param
+  "Sanitizes the `queries` parameter. Clamps the value between 1 and 500.
+  Invalid (string) values become 1."
   [queries]
   [queries]
-  (flatten ; Make it a list of maps
-    (take queries ; Number of queries to run
-          (repeatedly get-world))))
-
+  (let [n (try (Integer/parseInt queries)
+               (catch Exception e 1))] ; default to 1 on parse failure
+    (cond
+      (< n 1) 1
+      (> n 500) 500
+      :else n)))
 
 
-; Database connection for java.jdbc "raw"
-; https://github.com/clojure/java.jdbc/blob/master/doc/clojure/java/jdbc/ConnectionPooling.md
+;; MySQL database connection
+(defdb db-mysql
+  (mysql {
+          :classname "com.mysql.jdbc.Driver"
+          :subprotocol "mysql"
+          :subname "//127.0.0.1:3306/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=4096&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=false&maintainTimeStats=false&useServerPrepStmts&cacheRSMetadata=true"
+          :user "benchmarkdbuser"
+          :password "benchmarkdbpass"
+          ;;OPTIONAL KEYS
+          :delimiters "" ;; remove delimiters
+          :maximum-pool-size 256}))
+
+;; MySQL database connection for java.jdbc "raw"
+;; https://github.com/clojure/java.jdbc/blob/master/doc/clojure/java/jdbc/ConnectionPooling.md
 (def db-spec-mysql-raw
 (def db-spec-mysql-raw
   {:classname "com.mysql.jdbc.Driver"
   {:classname "com.mysql.jdbc.Driver"
    :subprotocol "mysql"
    :subprotocol "mysql"
-   :subname "//localhost:3306/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=4096&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=false&maintainTimeStats=false&useServerPrepStmts&cacheRSMetadata=true"
+   :subname "//127.0.0.1:3306/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=4096&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=false&maintainTimeStats=false&useServerPrepStmts&cacheRSMetadata=true"
    :user "benchmarkdbuser"
    :user "benchmarkdbuser"
    :password "benchmarkdbpass"})
    :password "benchmarkdbpass"})
 
 
-
 (defn pool
 (defn pool
   [spec]
   [spec]
   (let [cpds (doto (ComboPooledDataSource.)
   (let [cpds (doto (ComboPooledDataSource.)
@@ -72,67 +58,70 @@
                (.setMaxIdleTime (* 3 60 60)))]
                (.setMaxIdleTime (* 3 60 60)))]
     {:datasource cpds}))
     {:datasource cpds}))
 
 
-
 (def pooled-db (delay (pool db-spec-mysql-raw)))
 (def pooled-db (delay (pool db-spec-mysql-raw)))
 
 
+(defn db-mysql-raw [] @pooled-db)
 
 
-(defn db-raw [] @pooled-db)
+;; Set up entity World and the database representation
+(defentity world
+  (pk :id)
+  (table :world)
+  (entity-fields :id :randomNumber) ; Default fields for select
+  (database db-mysql))
 
 
+(defn get-random-world-korma
+  "Query a random World record from the database"
+  []
+  (let [id (inc (rand-int 9999))] ; Num between 1 and 10,000
+    (select world
+            (where {:id id }))))
 
 
-(defn get-world-raw
+(defn run-queries
+  "Run query repeatedly, return an array"
+  [queries]
+  (flatten ; Make it a list of maps
+    (take queries ; Number of queries to run
+          (repeatedly get-random-world-korma))))
+
+(defn get-random-world-raw
   "Query a random World record from the database"
   "Query a random World record from the database"
   []
   []
   (let [id (inc (rand-int 9999))]
   (let [id (inc (rand-int 9999))]
-    (jdbc/with-connection (db-raw)
-      ; Set a naming strategy to preserve column name case
-      (jdbc/with-naming-strategy {:keyword identity}
-        (jdbc/with-query-results rs [(str "select * from world where id = ?") id]
-          (doall rs))))))
-
+    (jdbc/query (db-mysql-raw) [(str "select * from world where id = ?") id])))
 
 
 (defn run-queries-raw
 (defn run-queries-raw
-  "Run the specified number of queries, return the results"
+  "Run query repeatedly, return an array"
   [queries]
   [queries]
   (flatten ; Make it a list of maps
   (flatten ; Make it a list of maps
     (take queries
     (take queries
-          (repeatedly get-world-raw))))
+          (repeatedly get-random-world-raw))))
 
 
-
-(defn get-query-count
-  "Parse provided string value of query count, clamping values to between 1 and 500."
-  [queries]
-  (let [n (try (Integer/parseInt queries)
-               (catch Exception e 1))] ; default to 1 on parse failure
-    (cond
-      (< n 1) 1
-      (> n 500) 500
-      :else n)))
-
-
-; Set up entity World and the database representation
+;; Set up entity Fortune and the database representation
 (defentity fortune
 (defentity fortune
   (pk :id)
   (pk :id)
   (table :fortune)
   (table :fortune)
   (entity-fields :id :message)
   (entity-fields :id :message)
-  (database db))
+  (database db-mysql))
 
 
-
-(defn get-all-fortunes
-  "Query all Fortune records from the database."
+(defn get-all-fortunes-korma
+  "Query all Fortune records from the database using Korma."
   []
   []
   (select fortune
   (select fortune
           (fields :id :message)))
           (fields :id :message)))
 
 
+(defn get-all-fortunes-raw
+  "Query all Fortune records from the database using JDBC."
+  []
+  (jdbc/query (db-mysql-raw) [(str "select * from fortune")]))
 
 
 (defn get-fortunes
 (defn get-fortunes
   "Fetch the full list of Fortunes from the database, sort them by the fortune
   "Fetch the full list of Fortunes from the database, sort them by the fortune
   message text, and then return the results."
   message text, and then return the results."
-  []
-  (let [fortunes (conj (get-all-fortunes)
-                       {:id 0
-                        :message "Additional fortune added at request time."})]
-    (sort-by #(:message %) fortunes)))
-
+  [query-function]
+  (sort-by #(:message %)
+    (conj
+      (query-function)
+      { :id 0 :message "Additional fortune added at request time." })))
 
 
 (defn fortunes-hiccup
 (defn fortunes-hiccup
   "Render the given fortunes to simple HTML using Hiccup."
   "Render the given fortunes to simple HTML using Hiccup."
@@ -151,12 +140,11 @@
         [:td (escape-html (:message x))]])
         [:td (escape-html (:message x))]])
      ]]))
      ]]))
 
 
-
-(defn update-and-persist
-  "Changes the :randomNumber of a number of world entities.
+(defn update-and-persist-korma
+  "Using Korma: Changes the :randomNumber of a number of world entities.
   Persists the changes to sql then returns the updated entities"
   Persists the changes to sql then returns the updated entities"
   [queries]
   [queries]
-  (let [results (run-queries queries)]
+(let [results (run-queries queries)]
     (for [w results]
     (for [w results]
       (update-in w [:randomNumber (inc (rand-int 9999))]
       (update-in w [:randomNumber (inc (rand-int 9999))]
         (update world
         (update world
@@ -164,80 +152,107 @@
                 (where {:id [:id w]}))))
                 (where {:id [:id w]}))))
     results))
     results))
 
 
+(defn update-and-persist-raw
+  "Using JDBC: Changes the :randomNumber of a number of world entities.
+  Persists the changes to sql then returns the updated entities"
+  [queries]
+(let [results (run-queries queries)]
+    (for [w results]
+      (update-in w [:randomNumber (inc (rand-int 9999))]
+        (jdbc/update! (db-mysql-raw) :world {:randomNumber (:randomNumber w)} ["id = ?" (:id w)])))
+    results))
 
 
 (def json-serialization
 (def json-serialization
   "Test 1: JSON serialization"
   "Test 1: JSON serialization"
-  (response {:message "Hello, World!"}))
-
+  (ring-resp/response {:message "Hello, World!"}))
 
 
 (def single-query-test
 (def single-query-test
   "Test 2: Single database query"
   "Test 2: Single database query"
-  (-> 1
-      (run-queries)
-      (first)
-      (response)))
-
+  (ring-resp/response (first (run-queries 1))))
 
 
-(defn multiple-query-test
+(defn multiple-queries-test
   "Test 3: Multiple database queries"
   "Test 3: Multiple database queries"
   [queries]
   [queries]
   (-> queries
   (-> queries
-      (get-query-count)
+      (sanitize-queries-param)
       (run-queries)
       (run-queries)
-      (response)))
-
+      (ring-resp/response)))
 
 
 (def single-query-test-raw
 (def single-query-test-raw
   "Test 2: Single database query (raw)"
   "Test 2: Single database query (raw)"
   (-> 1
   (-> 1
       (run-queries-raw)
       (run-queries-raw)
       (first)
       (first)
-      (response)))
-
+      (ring-resp/response)))
 
 
-(defn multiple-query-test-raw
+(defn multiple-queries-test-raw
   "Test 3: Multiple database queries (raw)"
   "Test 3: Multiple database queries (raw)"
   [queries]
   [queries]
   (-> queries
   (-> queries
-      (get-query-count)
+      (sanitize-queries-param)
       (run-queries-raw)
       (run-queries-raw)
-      (response)))
-
+      (ring-resp/response)))
 
 
 (def fortune-test
 (def fortune-test
   "Test 4: Fortunes"
   "Test 4: Fortunes"
-  (response (fortunes-hiccup (get-fortunes))))
-
+  (->
+    (get-fortunes get-all-fortunes-korma)
+    (fortunes-hiccup)
+    (ring-resp/response)
+    (ring-resp/content-type "text/html")
+    (ring-resp/charset "utf-8")))
+
+(def fortune-test-raw
+  "Test 4: Fortunes Raw"
+  (->
+    (get-fortunes get-all-fortunes-raw)
+    (fortunes-hiccup)
+    (ring-resp/response)
+    (ring-resp/content-type "text/html")
+    (ring-resp/charset "utf-8")))
 
 
 (defn db-updates
 (defn db-updates
   "Test 5: Database updates"
   "Test 5: Database updates"
   [queries]
   [queries]
   (-> queries
   (-> queries
-      (get-query-count)
-      (update-and-persist)
-      (response)))
+      (sanitize-queries-param)
+      (update-and-persist-korma)
+      (ring-resp/response)))
+
+(defn db-updates-raw
+  "Test 5: Database updates Raw"
+  [queries]
+  (-> queries
+      (sanitize-queries-param)
+      (update-and-persist-raw)
+      (ring-resp/response)))
 
 
 (def plaintext
 (def plaintext
   "Test 6: Plaintext"
   "Test 6: Plaintext"
-  {:status 200
-   :headers {"Content-Type" "text/plain; charset=utf-8"}
-   :body "Hello, World!"})
-
+  (->
+    (ring-resp/response "Hello, World!")
+    (ring-resp/content-type "text/plain")))
 
 
+;; Define route handlers
 (defroutes app-routes
 (defroutes app-routes
-  (GET "/"                 [] "Hello, World!")
-  (GET "/json"             [] json-serialization)
-  (GET "/db"               [] single-query-test)
-  (GET "/db/:queries"      [queries] (multiple-query-test queries))
-  (GET "/dbraw"            [] single-query-test-raw)
-  (GET "/dbraw/:queries"   [queries] (multiple-query-test-raw queries))
-  (GET "/fortunes"         [] (response (get-fortunes))) ; Raw json of fortunes
-  (GET "/fortune-hiccup"   [] fortune-test)
-  (GET "/updates/:queries" [queries] (db-updates queries))
-  (GET "/plaintext"        [] plaintext)
+  (GET "/"                     [] "Hello, World!")
+  (GET "/plaintext"            [] plaintext)
+  (GET "/json"                 [] json-serialization)
+  (GET "/db"                   [] single-query-test)
+  (GET "/queries/:queries"     [queries] (multiple-queries-test queries))
+  (GET "/queries/"             [] (multiple-queries-test queries)) ; When param is omitted
+  (GET "/fortunes"             [] fortune-test)
+  (GET "/updates/:queries"     [queries] (db-updates queries))
+  (GET "/updates/"             [] (db-updates queries)) ; When param is omitted
+  (GET "/raw/db"               [] single-query-test-raw)
+  (GET "/raw/queries/:queries" [queries] (multiple-queries-test-raw queries))
+  (GET "/raw/queries/"         [] (multiple-queries-test-raw queries)) ; When param is omitted
+  (GET "/raw/fortunes"         [] fortune-test-raw)
+  (GET "/raw/updates/:queries" [queries] (db-updates-raw queries))
+  (GET "/raw/updates/"         [] (db-updates-raw queries)) ; When param is omitted
   (route/not-found "Not Found"))
   (route/not-found "Not Found"))
 
 
-
 (def app
 (def app
   "Format responses as JSON"
   "Format responses as JSON"
-  (wrap-json-response app-routes))
+  (-> app-routes
+      (wrap-json-response)))

+ 1 - 1
frameworks/Clojure/compojure/setup.sh

@@ -1,6 +1,6 @@
 #!/bin/bash
 #!/bin/bash
 
 
-fw_depends java7 resin leiningen
+fw_depends java8 resin leiningen
 
 
 sed -i 's|:subname "//.*:3306|:subname "//'"${DBHOST}"':3306|g' hello/src/hello/handler.clj
 sed -i 's|:subname "//.*:3306|:subname "//'"${DBHOST}"':3306|g' hello/src/hello/handler.clj
 
 

+ 1 - 1
frameworks/Clojure/compojure/source_code

@@ -1,2 +1,2 @@
-./compojure/hello/src/hello/handler.clj
 ./compojure/hello/project.clj
 ./compojure/hello/project.clj
+./compojure/hello/src/hello/handler.clj

+ 3 - 17
frameworks/Clojure/http-kit/README.md

@@ -14,21 +14,7 @@ This is the Compojure (using http-kit) portion of a [benchmarking test suite](..
 The dependencies are documented in [project.clj](hello/project.clj),
 The dependencies are documented in [project.clj](hello/project.clj),
 but the main ones are:
 but the main ones are:
 
 
-* [Clojure 1.5.1](http://clojure.org/)
-* [Compojure 1.1.5](https://github.com/weavejester/compojure)
-* [Ring-JSON 0.2.0](https://github.com/ring-clojure/ring-json), which in turn uses [Cheshire](https://github.com/dakrone/cheshire), which in turn uses [Jackson](http://jackson.codehaus.org/)
+* [Clojure 1.7.0](http://clojure.org/)
 * [http-kit](http://http-kit.org)
 * [http-kit](http://http-kit.org)
-* [dbcp.clj](https://github.com/http-kit/dbcp.clj)
-
-## Test URLs
-### JSON Encoding Test
-
-http://localhost/http-kit/json
-
-### Data-Store/Database Mapping Test
-
-http://localhost/http-kit/db
-
-### Variable Query Test
-
-http://localhost/http-kit/db/2
+* [Ring-JSON 0.4.0](https://github.com/ring-clojure/ring-json), which in turn uses [Cheshire](https://github.com/dakrone/cheshire), which in turn uses [Jackson](http://jackson.codehaus.org/)
+* [Korma 0.4.2](http://sqlkorma.com/)

+ 22 - 1
frameworks/Clojure/http-kit/benchmark_config.json

@@ -6,8 +6,8 @@
       "json_url": "/json",
       "json_url": "/json",
       "db_url": "/db",
       "db_url": "/db",
       "query_url": "/queries/",
       "query_url": "/queries/",
-      "fortune_url": "/fortunes",
       "update_url": "/updates/",
       "update_url": "/updates/",
+      "fortune_url": "/fortunes",
       "plaintext_url": "/plaintext",
       "plaintext_url": "/plaintext",
       "port": 8080,
       "port": 8080,
       "approach": "Realistic",
       "approach": "Realistic",
@@ -15,6 +15,27 @@
       "database": "MySQL",
       "database": "MySQL",
       "framework": "http-kit",
       "framework": "http-kit",
       "language": "Clojure",
       "language": "Clojure",
+      "orm": "Micro",
+      "platform": "http-kit",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "http-kit",
+      "notes": "",
+      "versus": ""
+    },
+    "raw": {
+      "setup_file": "setup",
+      "db_url": "/raw/db",
+      "query_url": "/raw/queries/",
+      "update_url": "/raw/updates/",
+      "fortune_url": "/raw/fortunes",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "MySQL",
+      "framework": "http-kit",
+      "language": "Clojure",
       "orm": "Raw",
       "orm": "Raw",
       "platform": "http-kit",
       "platform": "http-kit",
       "webserver": "None",
       "webserver": "None",

+ 18 - 14
frameworks/Clojure/http-kit/hello/project.clj

@@ -1,23 +1,27 @@
-(defproject hello "compojure"
-  :description "JSON/Database tests"
-  :url "http://example.com/FIXME"
-  :dependencies [[org.clojure/clojure "1.5.1"]
-                 [compojure "1.1.5"]
-                 [ring/ring-json "0.2.0"]
+(defproject hello "http-kit"
+  :description "FrameworkBenchmarks test implementations"
+  :url "http://localhost:8080/"
+  :dependencies [[org.clojure/clojure "1.7.0"]
+                 [compojure "1.4.0"]
+                 [ring/ring-json "0.4.0"]
                  [org.clojure/tools.cli "0.2.1"]
                  [org.clojure/tools.cli "0.2.1"]
-                 [http-kit/dbcp "0.1.0"]
-                 [http-kit "2.1.18"]
+                 [http-kit "2.1.19"]
+                 [korma "0.4.2"]
                  [log4j "1.2.15" :exclusions [javax.mail/mail javax.jms/jms com.sun.jdmk/jmxtools com.sun.jmx/jmxri]]
                  [log4j "1.2.15" :exclusions [javax.mail/mail javax.jms/jms com.sun.jdmk/jmxtools com.sun.jmx/jmxri]]
                  ; [ch.qos.logback/logback-classic "1.1.2" :exclusions [org.slf4j/slf4j-api]]
                  ; [ch.qos.logback/logback-classic "1.1.2" :exclusions [org.slf4j/slf4j-api]]
                  ; [org.slf4j/jul-to-slf4j "1.7.7"]
                  ; [org.slf4j/jul-to-slf4j "1.7.7"]
                  ; [org.slf4j/jcl-over-slf4j "1.7.7"]
                  ; [org.slf4j/jcl-over-slf4j "1.7.7"]
                  ; [org.slf4j/log4j-over-slf4j "1.7.7"]
                  ; [org.slf4j/log4j-over-slf4j "1.7.7"]
-                 [org.clojure/data.json "0.2.5"]
-                 [org.clojure/java.jdbc "0.3.6"]
-                 [korma "0.4.0"]
-                 [mysql/mysql-connector-java "5.1.6"]
-                 [hiccup "1.0.4"]]
+                 [ring/ring-jetty-adapter "1.4.0"]
+                 [mysql/mysql-connector-java "5.1.38"]
+                 [org.clojure/java.jdbc "0.3.7"]
+                 [c3p0/c3p0 "0.9.1.2"]
+                 [hiccup "1.0.5"]]
+  :plugins [[lein-ring "0.9.7"]]
+  :ring {:handler hello.handler/app}
   :main hello.handler
   :main hello.handler
   :aot [hello.handler]
   :aot [hello.handler]
   :uberjar-name "http-kit-standalone.jar"
   :uberjar-name "http-kit-standalone.jar"
-  :profiles {:dev {:dependencies [[ring-mock "0.1.5"]]}})
+  :profiles
+  {:dev {:dependencies [[javax.servlet/servlet-api "2.5"]
+                        [ring/ring-mock "0.3.0"]]}})

+ 137 - 61
frameworks/Clojure/http-kit/hello/src/hello/handler.clj

@@ -13,90 +13,118 @@
   (:require [compojure.handler :as handler]
   (:require [compojure.handler :as handler]
             [compojure.route :as route]
             [compojure.route :as route]
             [ring.util.response :as ring-resp]
             [ring.util.response :as ring-resp]
-            [clojure.data.json :as json]
             [clojure.java.jdbc :as jdbc]))
             [clojure.java.jdbc :as jdbc]))
 
 
+(defn sanitize-queries-param
+  "Sanitizes the `queries` parameter. Clamps the value between 1 and 500.
+  Invalid (string) values become 1."
+  [queries]
+  (let [n (try (Integer/parseInt queries)
+               (catch Exception e 1))] ; default to 1 on parse failure
+    (cond
+      (< n 1) 1
+      (> n 500) 500
+      :else n)))
 
 
-(defn parse-port [s] 
-  "Convert stringy port number int. Defaults to 8080."
-  (cond
-    (string? s) (Integer/parseInt s)
-    (instance? Integer s) s
-    (instance? Long s) (.intValue ^Long s)
-    :else 8080))
-
-
-;; MySQL connection
-(defdb mysql-db
+;; MySQL database connection
+(defdb db-mysql
   (mysql {
   (mysql {
     :classname "com.mysql.jdbc.Driver"
     :classname "com.mysql.jdbc.Driver"
     :subprotocol "mysql"
     :subprotocol "mysql"
-    :subname "//127.0.0.1:3306/hello_world"
+    :subname "//127.0.0.1:3306/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=4096&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=false&maintainTimeStats=false&useServerPrepStmts&cacheRSMetadata=true"
     :user "benchmarkdbuser"
     :user "benchmarkdbuser"
     :password "benchmarkdbpass"
     :password "benchmarkdbpass"
     ;;OPTIONAL KEYS
     ;;OPTIONAL KEYS
     :delimiters "" ;; remove delimiters
     :delimiters "" ;; remove delimiters
     :maximum-pool-size 256}))
     :maximum-pool-size 256}))
 
 
+;; MySQL database connection for java.jdbc "raw"
+;; https://github.com/clojure/java.jdbc/blob/master/doc/clojure/java/jdbc/ConnectionPooling.md
+(def db-spec-mysql-raw
+  {:classname "com.mysql.jdbc.Driver"
+   :subprotocol "mysql"
+   :subname "//127.0.0.1:3306/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=4096&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=false&maintainTimeStats=false&useServerPrepStmts&cacheRSMetadata=true"
+   :user "benchmarkdbuser"
+   :password "benchmarkdbpass"})
+
+(defn pool
+  [spec]
+  (let [cpds (doto (ComboPooledDataSource.)
+               (.setDriverClass (:classname spec))
+               (.setJdbcUrl (str "jdbc:" (:subprotocol spec) ":" (:subname spec)))
+               (.setUser (:user spec))
+               (.setPassword (:password spec))
+               ;; expire excess connections after 30 minutes of inactivity:
+               (.setMaxIdleTimeExcessConnections (* 30 60))
+               ;; expire connections after 3 hours of inactivity:
+               (.setMaxIdleTime (* 3 60 60)))]
+    {:datasource cpds}))
+
+(def pooled-db (delay (pool db-spec-mysql-raw)))
+
+(defn db-mysql-raw [] @pooled-db)
 
 
 ;; Set up entity World and the database representation
 ;; Set up entity World and the database representation
 (defentity world
 (defentity world
   (pk :id)
   (pk :id)
   (table :world)
   (table :world)
-  (entity-fields :id :randomNumber) ;; Default fields for select
-  (database mysql-db))
-
+  (entity-fields :id :randomNumber) ; Default fields for select
+  (database db-mysql))
 
 
-(defn sanitize-queries-param
-  "Sanitizes the `queries` parameter. Caps the value between 1 and 500.
-  Invalid (stringy) values become 1"
-  [queries]
-  (let [n (try (Integer/parseInt queries)
-               (catch Exception e 1))] ; default to 1 on parse failure
-    (cond
-      (< n 1) 1
-      (> n 500) 500
-      :else n)))
-
-
-(defn random-world
+(defn get-random-world-korma
   "Query a random World record from the database"
   "Query a random World record from the database"
   []
   []
   (let [id (inc (rand-int 9999))] ; Num between 1 and 10,000
   (let [id (inc (rand-int 9999))] ; Num between 1 and 10,000
     (select world
     (select world
             (where {:id id }))))
             (where {:id id }))))
 
 
-
 (defn run-queries
 (defn run-queries
-  "Run query repeatedly -- Always returns an array"
+  "Run query repeatedly, return an array"
+  [queries]
+  (flatten ; Make it a list of maps
+    (take queries ; Number of queries to run
+          (repeatedly get-random-world-korma))))
+
+(defn get-random-world-raw
+  "Query a random World record from the database"
+  []
+  (let [id (inc (rand-int 9999))]
+    (jdbc/query (db-mysql-raw) [(str "select * from world where id = ?") id])))
+
+(defn run-queries-raw
+  "Run query repeatedly, return an array"
   [queries]
   [queries]
-  (flatten (take queries (repeatedly random-world))))
+  (flatten ; Make it a list of maps
+    (take queries
+          (repeatedly get-random-world-raw))))
 
 
-; Set up entity Fortune and the database representation
+;; Set up entity Fortune and the database representation
 (defentity fortune
 (defentity fortune
   (pk :id)
   (pk :id)
   (table :fortune)
   (table :fortune)
   (entity-fields :id :message)
   (entity-fields :id :message)
-  (database mysql-db))
-
+  (database db-mysql))
 
 
-(defn get-all-fortunes
-  "Query all Fortune records from the database."
+(defn get-all-fortunes-korma
+  "Query all Fortune records from the database using Korma."
   []
   []
   (select fortune
   (select fortune
           (fields :id :message)))
           (fields :id :message)))
 
 
+(defn get-all-fortunes-raw
+  "Query all Fortune records from the database using JDBC."
+  []
+  (jdbc/query (db-mysql-raw) [(str "select * from fortune")]))
 
 
 (defn get-fortunes
 (defn get-fortunes
   "Fetch the full list of Fortunes from the database, sort them by the fortune
   "Fetch the full list of Fortunes from the database, sort them by the fortune
   message text, and then return the results."
   message text, and then return the results."
-  []
+  [query-function]
   (sort-by #(:message %)
   (sort-by #(:message %)
     (conj
     (conj
-      (get-all-fortunes)
+      (query-function)
       { :id 0 :message "Additional fortune added at request time." })))
       { :id 0 :message "Additional fortune added at request time." })))
 
 
-
 (defn fortunes-hiccup
 (defn fortunes-hiccup
   "Render the given fortunes to simple HTML using Hiccup."
   "Render the given fortunes to simple HTML using Hiccup."
   [fortunes]
   [fortunes]
@@ -114,14 +142,11 @@
         [:td (escape-html (:message x))]])
         [:td (escape-html (:message x))]])
      ]]))
      ]]))
 
 
-
-(defn update-and-persist
-  "Changes the :randomNumber of a number of world entities.
+(defn update-and-persist-korma
+  "Using Korma: Changes the :randomNumber of a number of world entities.
   Persists the changes to sql then returns the updated entities"
   Persists the changes to sql then returns the updated entities"
   [queries]
   [queries]
-  (let [results (-> queries
-                    (sanitize-queries-param)
-                    (run-queries))]
+(let [results (run-queries queries)]
     (for [w results]
     (for [w results]
       (update-in w [:randomNumber (inc (rand-int 9999))]
       (update-in w [:randomNumber (inc (rand-int 9999))]
         (update world
         (update world
@@ -129,43 +154,80 @@
                 (where {:id [:id w]}))))
                 (where {:id [:id w]}))))
     results))
     results))
 
 
+(defn update-and-persist-raw
+  "Using JDBC: Changes the :randomNumber of a number of world entities.
+  Persists the changes to sql then returns the updated entities"
+  [queries]
+(let [results (run-queries queries)]
+    (for [w results]
+      (update-in w [:randomNumber (inc (rand-int 9999))]
+        (jdbc/update! (db-mysql-raw) :world {:randomNumber (:randomNumber w)} ["id = ?" (:id w)])))
+    results))
 
 
 (def json-serialization
 (def json-serialization
   "Test 1: JSON serialization"
   "Test 1: JSON serialization"
   (ring-resp/response {:message "Hello, World!"}))
   (ring-resp/response {:message "Hello, World!"}))
 
 
-
 (def single-query-test
 (def single-query-test
   "Test 2: Single database query"
   "Test 2: Single database query"
   (ring-resp/response (first (run-queries 1))))
   (ring-resp/response (first (run-queries 1))))
 
 
-
 (defn multiple-queries-test
 (defn multiple-queries-test
   "Test 3: Multiple database queries"
   "Test 3: Multiple database queries"
   [queries]
   [queries]
   (-> queries
   (-> queries
       (sanitize-queries-param)
       (sanitize-queries-param)
       (run-queries)
       (run-queries)
-      (ring-resp/response)
-      (ring-resp/content-type "application/json")))
+      (ring-resp/response)))
+
+(def single-query-test-raw
+  "Test 2: Single database query (raw)"
+  (-> 1
+      (run-queries-raw)
+      (first)
+      (ring-resp/response)))
 
 
+(defn multiple-queries-test-raw
+  "Test 3: Multiple database queries (raw)"
+  [queries]
+  (-> queries
+      (sanitize-queries-param)
+      (run-queries-raw)
+      (ring-resp/response)))
 
 
 (def fortune-test
 (def fortune-test
   "Test 4: Fortunes"
   "Test 4: Fortunes"
   (->
   (->
-    (get-fortunes)
+    (get-fortunes get-all-fortunes-korma)
     (fortunes-hiccup)
     (fortunes-hiccup)
     (ring-resp/response)
     (ring-resp/response)
-    (ring-resp/content-type "text/html")))
+    (ring-resp/content-type "text/html")
+    (ring-resp/charset "utf-8")))
 
 
+(def fortune-test-raw
+  "Test 4: Fortunes Raw"
+  (->
+    (get-fortunes get-all-fortunes-raw)
+    (fortunes-hiccup)
+    (ring-resp/response)
+    (ring-resp/content-type "text/html")
+    (ring-resp/charset "utf-8")))
 
 
 (defn db-updates
 (defn db-updates
   "Test 5: Database updates"
   "Test 5: Database updates"
   [queries]
   [queries]
   (-> queries
   (-> queries
-      (update-and-persist)
+      (sanitize-queries-param)
+      (update-and-persist-korma)
       (ring-resp/response)))
       (ring-resp/response)))
 
 
+(defn db-updates-raw
+  "Test 5: Database updates Raw"
+  [queries]
+  (-> queries
+      (sanitize-queries-param)
+      (update-and-persist-raw)
+      (ring-resp/response)))
 
 
 (def plaintext
 (def plaintext
   "Test 6: Plaintext"
   "Test 6: Plaintext"
@@ -173,18 +235,32 @@
     (ring-resp/response "Hello, World!")
     (ring-resp/response "Hello, World!")
     (ring-resp/content-type "text/plain")))
     (ring-resp/content-type "text/plain")))
 
 
-
 ;; Define route handlers
 ;; Define route handlers
 (defroutes app-routes
 (defroutes app-routes
-  (GET "/"                 [] "Hello, World!")
-  (GET "/json"             [] json-serialization)
-  (GET "/db"               [] single-query-test)
-  (GET "/queries/:queries" [queries] (multiple-queries-test queries))
-  (GET "/fortunes"         [] fortune-test)
-  (GET "/updates/:queries" [queries] (db-updates queries))
-  (GET "/plaintext"        [] plaintext)
+  (GET "/"                     [] "Hello, World!")
+  (GET "/plaintext"            [] plaintext)
+  (GET "/json"                 [] json-serialization)
+  (GET "/db"                   [] single-query-test)
+  (GET "/queries/:queries"     [queries] (multiple-queries-test queries))
+  (GET "/queries/"             [] (multiple-queries-test queries)) ; When param is omitted
+  (GET "/fortunes"             [] fortune-test)
+  (GET "/updates/:queries"     [queries] (db-updates queries))
+  (GET "/updates/"             [] (db-updates queries)) ; When param is omitted
+  (GET "/raw/db"               [] single-query-test-raw)
+  (GET "/raw/queries/:queries" [queries] (multiple-queries-test-raw queries))
+  (GET "/raw/queries/"         [] (multiple-queries-test-raw queries)) ; When param is omitted
+  (GET "/raw/fortunes"         [] fortune-test-raw)
+  (GET "/raw/updates/:queries" [queries] (db-updates-raw queries))
+  (GET "/raw/updates/"         [] (db-updates-raw queries)) ; When param is omitted
   (route/not-found "Not Found"))
   (route/not-found "Not Found"))
 
 
+(defn parse-port [s] 
+  "Convert stringy port number int. Defaults to 8080."
+  (cond
+    (string? s) (Integer/parseInt s)
+    (instance? Integer s) s
+    (instance? Long s) (.intValue ^Long s)
+    :else 8080))
 
 
 (defn start-server [{:keys [port]}]
 (defn start-server [{:keys [port]}]
   ;; Format responses as JSON
   ;; Format responses as JSON

+ 1 - 1
frameworks/Clojure/http-kit/setup.sh

@@ -1,6 +1,6 @@
 #!/bin/bash
 #!/bin/bash
 
 
-fw_depends leiningen java7
+fw_depends leiningen java8
 
 
 sed -i 's|:subname "//.*:3306|:subname "//'"${DBHOST}"':3306|g' hello/src/hello/handler.clj
 sed -i 's|:subname "//.*:3306|:subname "//'"${DBHOST}"':3306|g' hello/src/hello/handler.clj
 
 

+ 0 - 3
frameworks/Clojure/http-kit/source_code

@@ -1,5 +1,2 @@
 ./http-kit/hello/project.clj
 ./http-kit/hello/project.clj
-./http-kit/hello/src/
-./http-kit/hello/src/log4j.xml
-./http-kit/hello/src/hello
 ./http-kit/hello/src/hello/handler.clj
 ./http-kit/hello/src/hello/handler.clj