Explorar o código

[ci fw-only Java/act] Optimize SQL datasource configuration; Add act-jdbc tests (db tests with raw jdbc access) (#2709)

* make beetlsql dbservice share the datasource with pgsql dbservice

* add act-jdbc tests; optimize datasource configuration

* rename test set name in benchmark_config.json
Green Luo %!s(int64=8) %!d(string=hai) anos
pai
achega
30e27d758e

+ 17 - 6
frameworks/Java/act/README.md

@@ -2,7 +2,7 @@
 
 This is the ActFramework portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
 
-This is using [ActFramework R1.0.2](http://actframework.org) to build an application.
+This is using [ActFramework R1.1.2](http://actframework.org) to build an application.
 
 ## How to run this app locally
 
@@ -16,7 +16,7 @@ unzip *.zip
 ./start
 ```
 
-Or simply run `run.sh`
+Or simply run `./run.sh`
     
 
 ## Application Endpoints
@@ -30,24 +30,32 @@ Or simply run `run.sh`
 * `mongo`: http://localhost:8080/mongo/db
 * `mysql`: http://localhost:8080/mysql/db
 * `pgsql`: http://localhost:8080/pgsql/db
+* `beetlsql-pgsql`: http://localhost:8080/beetsql/db
+* `jdbc-pgsql`: http://localhost:8080/beetsql/db
 
 ### Multiple queries
 
 * `mongo`: http://localhost:8080/mongo/queries?quries=20
 * `mysql`: http://localhost:8080/mysql/queries?quries=20
 * `pgsql`: http://localhost:8080/pgsql/queries?quries=20
+* `beetlsql-pgsql`: http://localhost:8080/beetsql/queries?quries=20
+* `jdbc-pgsql`: http://localhost:8080/beetsql/queries?quries=20
 
 ### Fortunes
 
 * `mongo`: http://localhost:8080/mongo/fortunes
 * `mysql`: http://localhost:8080/mysql/fortunes
 * `pgsql`: http://localhost:8080/pgsql/fortunes
+* `beetlsql-pgsql`: http://localhost:8080/beetsql/db
+* `jdbc-pgsql`: http://localhost:8080/beetsql/db
 
 ### DB updates
 
 * `mongo`: http://localhost:8080/mongo/updates?quries=20
 * `mysql`: http://localhost:8080/mysql/updates?quries=20
 * `pgsql`: http://localhost:8080/pgsql/updates?quries=20
+* `beetlsql-pgsql`: http://localhost:8080/beetsql/updates?quries=20
+* `jdbc-pgsql`: http://localhost:8080/beetsql/updates?quries=20
 
 ### Plain text
 
@@ -132,17 +140,20 @@ The common base classes for mysql and pgsql classes
 * [World controller](src/main/java/com/techempower/act/pgsql/controller/WorldController.java) - for `/pgsql/db`, `/pgsql/queries` and `/pgsql/updates` endpoint
 
 
-
 ## Infrastructure Software Versions
 The tests were run with:
 
-* [ActFramework 1.0.4](http://actframework.org/)
-* [act-ebean plugin 1.0.3](https://github.com/actframework/act-ebean)
-* [act-morphia plugin 1.0.2](https://github.com/actframework/act-morphia)
+* [ActFramework 1.1.2](http://actframework.org/)
+* [act-ebean2 plugin 1.04](https://github.com/actframework/act-ebean2)
+* [act-morphia plugin 1.1.0](https://github.com/actframework/act-morphia)
+* [act-beetlsql plugin 1.1.0](https://github.com/actframework/act-beetlsql)
+* [act-mustache plugin 1.0.0](https://github.com/actframework/act-mustache)
 * [Undertow 1.4.8.Final](http://undertow.io/)
 
 ## Local Test Result
 
+**Note** the data below is outdated
+
 |            Test            | Throughput |  Latency  | Timeout/Error |
 | -------------------------- | ---------: | --------: | ------: |
 | json                       | 1026530.41 |    3.31ms |         |

+ 27 - 5
frameworks/Java/act/benchmark_config.json

@@ -21,7 +21,7 @@
       "notes": "",
       "versus": "undertow"
     },
-    "pgsql": {
+    "ebean-pg": {
       "setup_file": "setup",
       "db_url": "/pgsql/db",
       "query_url": "/pgsql/queries?queries=",
@@ -43,7 +43,7 @@
       "notes": "",
       "versus": "undertow"
     },
-    "mysql": {
+    "ebean-my": {
       "setup_file": "setup",
       "db_url": "/mysql/db",
       "query_url": "/mysql/queries?queries=",
@@ -65,7 +65,7 @@
       "notes": "",
       "versus": "undertow"
     },
-    "mongodb": {
+    "morphia-mo": {
       "setup_file": "setup",
       "db_url": "/mongo/db",
       "query_url": "/mongo/queries?queries=",
@@ -87,7 +87,7 @@
       "notes": "",
       "versus": "undertow"
     },
-    "beetlsql": {
+    "beetlsql-pg": {
       "setup_file": "setup",
       "db_url": "/beetlsql/db",
       "query_url": "/beetlsql/queries?queries=",
@@ -105,7 +105,29 @@
       "webserver": "None",
       "os": "Linux",
       "database_os": "Linux",
-      "display_name": "act-beetlsql",
+      "display_name": "act-beetlsql-pgsql",
+      "notes": "",
+      "versus": "undertow"
+    },
+    "jdbc-pg": {
+      "setup_file": "setup",
+      "db_url": "/jdbc/db",
+      "query_url": "/jdbc/queries?queries=",
+      "fortune_url": "/jdbc/fortunes",
+      "update_url": "/jdbc/updates?queries=",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Fullstack",
+      "database": "Postgres",
+      "framework": "actframework",
+      "language": "Java",
+      "flavor": "None",
+      "orm": "Raw",
+      "platform": "Undertow",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "act-jdbc-pgsql",
       "notes": "",
       "versus": "undertow"
     }

+ 15 - 25
frameworks/Java/act/src/main/java/com/techempower/act/beetlsql/BeetlSqlController.java

@@ -1,11 +1,8 @@
 package com.techempower.act.beetlsql;
 
-import act.app.conf.AutoConfig;
 import act.controller.Controller;
-import org.osgl.$;
 import org.osgl.mvc.annotation.GetAction;
 import org.osgl.mvc.result.Result;
-import org.osgl.util.Const;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -18,64 +15,57 @@ import static com.techempower.act.controller.WorldControllerBase.regulateQueries
  * Testing for Act on BeetlSQL
  */
 @Controller("beetlsql")
-@AutoConfig
 @SuppressWarnings("unused")
 public class BeetlSqlController extends Controller.Util {
 
-    /**
-     * This constant will get populated with the value set in
-     * `app.world.max_row` configuration item
-     */
-    public static final Const<Integer> WORLD_MAX_ROW = $.constant();
-
     @GetAction("db")
-    public final void singleQuery(World.Mapper worldDao) {
-        json(findOne(worldDao));
+    public final void singleQuery(World.Mapper worldMapper) {
+        json(findOne(worldMapper));
     }
 
     @GetAction("queries")
-    public final Result multipleQueries(String queries, World.Mapper worldDao) {
+    public final Result multipleQueries(String queries, World.Mapper worldMapper) {
         int q = regulateQueries(queries);
 
         World[] worlds = new World[q];
         for (int i = 0; i < q; ++i) {
-            worlds[i] = findOne(worldDao);
+            worlds[i] = findOne(worldMapper);
         }
         return json(worlds);
     }
 
     @GetAction("updates")
-    public final void updateQueries(String queries, World.Mapper worldDao) {
+    public final void updateQueries(String queries, World.Mapper worldMapper) {
         int q = regulateQueries(queries);
-        List<World> retVal = doUpdate(q, worldDao);
+        List<World> retVal = doUpdate(q, worldMapper);
         json(retVal);
     }
 
     @GetAction("fortunes")
-    public void fortunes(Fortune.Mapper fortuneDao) {
-        List<Fortune> fortunes = fortuneDao.all();
+    public void fortunes(Fortune.Mapper fortuneMapper) {
+        List<Fortune> fortunes = fortuneMapper.all();
         fortunes.add(new Fortune(0, "Additional fortune added at request time."));
         Collections.sort(fortunes);
         template("fortunes.mustache", fortunes);
     }
 
-    protected List<World> doUpdate(int q, World.Mapper worldDao) {
+    protected List<World> doUpdate(int q, World.Mapper worldMapper) {
         List<World> retVal = new ArrayList<>(q);
         for (int i = 0; i < q; ++i) {
-            retVal.add(findAndModifyOne(worldDao));
+            retVal.add(findAndModifyOne(worldMapper));
         }
         return retVal;
     }
 
-    private World findOne(World.Mapper worldDao) {
-        return worldDao.single(randomWorldNumber());
+    private World findOne(World.Mapper worldMapper) {
+        return worldMapper.single(randomWorldNumber());
     }
 
-    private World findAndModifyOne(World.Mapper worldDao) {
-        World world = findOne(worldDao);
+    private World findAndModifyOne(World.Mapper worldMapper) {
+        World world = findOne(worldMapper);
         notFoundIfNull(world);
         world.setRandomNumber(randomWorldNumber());
-        worldDao.updateById(world);
+        worldMapper.updateById(world);
         return world;
     }
 

+ 114 - 0
frameworks/Java/act/src/main/java/com/techempower/act/jdbc/JdbcController.java

@@ -0,0 +1,114 @@
+package com.techempower.act.jdbc;
+
+import act.app.DbServiceManager;
+import act.controller.Controller;
+import act.db.sql.SqlDbService;
+import com.techempower.act.beetlsql.Fortune;
+import com.techempower.act.beetlsql.World;
+import org.osgl.mvc.annotation.GetAction;
+import org.osgl.mvc.result.Result;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import static com.techempower.act.controller.WorldControllerBase.randomWorldNumber;
+import static com.techempower.act.controller.WorldControllerBase.regulateQueries;
+
+/**
+ * Testing for Act on raw JDBC
+ */
+@Controller("jdbc")
+@SuppressWarnings("unused")
+public class JdbcController extends Controller.Util {
+
+    private Connection conn(DbServiceManager dsm) throws SQLException {
+        SqlDbService pgsql = dsm.dbService("pgsql");
+        return pgsql.dataSource().getConnection();
+    }
+
+    @GetAction("db")
+    public final void singleQuery(DbServiceManager dsm) throws SQLException {
+        try (Connection conn = conn(dsm)) {
+            throw json(findOne(query(conn)));
+        }
+    }
+
+    @GetAction("queries")
+    public final Result multipleQueries(String queries, DbServiceManager dsm) throws SQLException {
+        int q = regulateQueries(queries);
+
+        World[] worlds = new World[q];
+        try (Connection conn = conn(dsm)) {
+            PreparedStatement query = query(conn);
+            for (int i = 0; i < q; ++i) {
+                worlds[i] = findOne(query);
+            }
+        }
+        return json(worlds);
+    }
+
+    @GetAction("updates")
+    public final Result updateQueries(String queries, DbServiceManager dsm) throws SQLException {
+        int count = regulateQueries(queries);
+        World[] worlds = new World[count];
+        try (Connection conn = conn(dsm)) {
+            try (PreparedStatement query = query(conn);
+                 PreparedStatement update = update(conn)) {
+                for (int i = 0; i < count; i++) {
+                    final int id = randomWorldNumber();
+                    query.setInt(1, id);
+
+                    try (ResultSet results = query.executeQuery()) {
+                        if (results.next()) {
+                            worlds[i] = new World(id, results.getInt("randomNumber"));
+                            worlds[i].setRandomNumber(randomWorldNumber());
+                            update.setInt(1, worlds[i].getRandomNumber());
+                            update.setInt(2, id);
+                            update.execute();
+                        }
+                    }
+                }
+            }
+        }
+        return json(worlds);
+    }
+
+    @GetAction("fortunes")
+    public void fortunes(DbServiceManager dsm) throws SQLException {
+        List<Fortune> fortunes = new ArrayList<>();
+        try (Connection conn = conn(dsm)) {
+            ResultSet set = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)
+                    .executeQuery("SELECT id, message FROM Fortune");
+            while (set.next()) {
+                fortunes.add(new Fortune(set.getInt(1), set.getString(2)));
+            }
+        }
+        fortunes.add(new Fortune(0, "Additional fortune added at request time."));
+        Collections.sort(fortunes);
+        template("fortunes.mustache", fortunes);
+    }
+
+    private World findOne(PreparedStatement statement) throws SQLException {
+        World world;
+        statement.setInt(1, randomWorldNumber());
+        try (ResultSet resultSet = statement.executeQuery()) {
+            resultSet.next();
+            return new World(resultSet.getInt("id"), resultSet.getInt("randomNumber"));
+        }
+    }
+
+    private PreparedStatement query(Connection conn) throws SQLException {
+        return conn.prepareStatement("SELECT * FROM world WHERE id = ?", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
+    }
+
+    private PreparedStatement update(Connection conn) throws SQLException {
+        return conn.prepareStatement("UPDATE World SET randomNumber = ? WHERE id= ?");
+    }
+
+
+}

+ 2 - 0
frameworks/Java/act/src/main/resources/conf/common/app.properties

@@ -13,3 +13,5 @@ metric=false
 # World max row is 10,000
 app.world.max_row=10000
 
+xio.worker_threads.max=256
+

+ 32 - 3
frameworks/Java/act/src/main/resources/conf/common/db.properties

@@ -13,17 +13,46 @@ db.mysql.username=benchmarkdbuser
 db.mysql.password=benchmarkdbpass
 db.mysql.maxConnections=256
 db.mysql.minConnections=128
-db.mysql.useServerPrepStmts=true
+db.mysql.poolServerPrepStmts=true
+db.mysql.autoCommit=true
+db.mysql.prepStmtCacheSqlLimit=2048
+db.mysql.prepStmtCacheSize=4096
+db.mysql.alwaysSendSetIsolation=false
+db.mysql.cacheCallableStmts=true
+db.mysql.cachePrepStmts=true
+db.mysql.useLocalSessionState=true
+db.mysql.jdbcCompliantTruncation=false
+db.mysql.elideSetAutoCommits=true
+db.mysql.zeroDateTimeBehavior=convertToNull
+db.mysql.traceProtocol=false
+db.mysql.useUnbufferedInput=false
+db.mysql.useReadAheadInput=false
+db.mysql.maintainTimeStats=false
+db.mysql.cacheRSMetadata=true
 
 pgsql.host=localhost
 
 db.pgsql.impl=act.db.ebean2.EbeanPlugin
-db.pgsql.url=jdbc:postgresql://${pgsql.host}:5432/hello_world
+db.pgsql.url=jdbc:postgresql://${pgsql.host}:5432/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
 db.pgsql.username=benchmarkdbuser
 db.pgsql.password=benchmarkdbpass
 db.pgsql.maxConnections=256
 db.pgsql.minConnections=128
-db.pgsql.useServerPrepStmts=true
+db.pgsql.autoCommit=true
+db.pgsql.prepStmtCacheSqlLimit=2048
+db.pgsql.prepStmtCacheSize=4096
+db.pgsql.alwaysSendSetIsolation=false
+db.pgsql.cacheCallableStmts=true
+db.pgsql.cachePrepStmts=true
+db.pgsql.useLocalSessionState=true
+db.pgsql.jdbcCompliantTruncation=false
+db.pgsql.elideSetAutoCommits=true
+db.pgsql.zeroDateTimeBehavior=convertToNull
+db.pgsql.traceProtocol=false
+db.pgsql.useUnbufferedInput=false
+db.pgsql.useReadAheadInput=false
+db.pgsql.maintainTimeStats=false
+db.pgsql.cacheRSMetadata=true
 
 db.beetl.impl=act.db.beetlsql.BeetlSqlPlugin
 db.beetl.datasource.provider=shared:pgsql

+ 2 - 2
frameworks/Java/act/src/main/resources/conf/local/db.properties

@@ -1,2 +1,2 @@
-db.mysql.maxConnections=40
-db.pgsql.maxConnections=40
+db.mysql.maxConnections=128
+db.pgsql.maxConnections=128