Просмотр исходного кода

updated wizzardo-http dependencies and implementation (#3785)

* updated dependency

* updated dependency and improved db-handlers

* cleanup

* cleanup
Mikhail Bobrutskov 7 лет назад
Родитель
Сommit
a65f24afe8

+ 2 - 1
frameworks/Java/wizzardo-http/build.gradle

@@ -14,7 +14,8 @@ repositories {
 }
 
 dependencies {
-    compile 'com.wizzardo:http:0.2.1'
+    compile 'com.wizzardo:http:0.2.2'
+
     compile 'org.postgresql:postgresql:9.4.1212'
     compile 'com.zaxxer:HikariCP:2.7.3'
 }

+ 10 - 9
frameworks/Java/wizzardo-http/src/main/java/com/wizzardo/techempower/App.java

@@ -31,15 +31,16 @@ public class App {
         };
 
         webApplication.onSetup(app -> {
-                app.getUrlMapping()
-                        .append("/plaintext", (request, response) -> response.setBody(HELLO_WORLD)
-                                .appendHeader(Header.KV_CONTENT_TYPE_TEXT_PLAIN))
-                        .append("/json", (request, response) -> response
-                                .setBody(JsonTools.serializeToBytes(new Message("Hello, World!")))
-                                .appendHeader(Header.KV_CONTENT_TYPE_APPLICATION_JSON))
-                        .append("/db", DBController.class, "world")
-                        .append("/queries", DBController.class, "queries")
-                        .append("/updates", DBController.class, "updates");
+                    app.getUrlMapping()
+                            .append("/plaintext", (request, response) -> response.setBody(HELLO_WORLD)
+                                    .appendHeader(Header.KV_CONTENT_TYPE_TEXT_PLAIN))
+                            .append("/json", (request, response) -> response
+                                    .setBody(JsonTools.serializeToBytes(new Message("Hello, World!")))
+                                    .appendHeader(Header.KV_CONTENT_TYPE_APPLICATION_JSON))
+                            .append("/db", DBController.class, "world")
+                            .append("/queries", DBController.class, "queries")
+                            .append("/updates", DBController.class, "updates")
+                    ;
                 }
         );
 

+ 110 - 42
frameworks/Java/wizzardo-http/src/main/java/com/wizzardo/techempower/DBController.java

@@ -1,23 +1,31 @@
 package com.wizzardo.techempower;
 
+import com.wizzardo.epoll.ByteBufferProvider;
+import com.wizzardo.epoll.ByteBufferWrapper;
+import com.wizzardo.http.HttpConnection;
 import com.wizzardo.http.framework.Controller;
-import com.wizzardo.http.framework.parameters.Parameter;
 import com.wizzardo.http.framework.template.Renderer;
 import com.wizzardo.http.request.Header;
+import com.wizzardo.http.response.Status;
+import com.wizzardo.tools.json.JsonTools;
 
-import java.nio.charset.StandardCharsets;
-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 java.sql.*;
+import java.util.Arrays;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
 
 public class DBController extends Controller {
 
     DBService dbService;
+    static ThreadLocal<ByteBufferProvider> byteBufferProviderThreadLocal = ThreadLocal.<ByteBufferProvider>withInitial(() -> {
+        ByteBufferWrapper wrapper = new ByteBufferWrapper(64 * 1024);
+        return () -> wrapper;
+    });
+
+    static ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
 
     public Renderer world() throws SQLException {
         World world;
@@ -36,52 +44,112 @@ public class DBController extends Controller {
         return renderJson(world);
     }
 
-    public Renderer queries() throws SQLException {
+    public void queries() {
         int queries = Math.min(Math.max(params().getInt("queries", 1), 1), 500);
+        response.async();
+        AtomicInteger counter = new AtomicInteger(0);
+        AtomicBoolean failed = new AtomicBoolean(false);
 
         World[] worlds = new World[queries];
-        try (Connection connection = dbService.getConnection();
-             PreparedStatement statement = connection.prepareStatement("SELECT id,randomNumber FROM World WHERE id = ?")
-        ) {
-            for (int i = 0; i < worlds.length; i++) {
-                statement.setInt(1, getRandomNumber());
-                try (ResultSet resultSet = statement.executeQuery()) {
-                    resultSet.next();
-                    int id = resultSet.getInt(1);
-                    int randomNumber = resultSet.getInt(2);
-                    worlds[i] = new World(id, randomNumber);
-                }
-            }
-        }
-
-        return renderJson(worlds);
-    }
+        for (int i = 0; i < queries; i++) {
+            int index = i;
 
-    public Renderer updates() throws SQLException {
-        int queries = Math.min(Math.max(params().getInt("queries", 1), 1), 500);
-        World[] worlds = new World[queries];
-        try (Connection connection = dbService.getConnection()) {
-            try (PreparedStatement statement = connection.prepareStatement("SELECT id,randomNumber FROM World WHERE id = ?")) {
-                for (int i = 0; i < worlds.length; i++) {
+            executorService.submit(() -> {
+                try (Connection connection = dbService.getConnection();
+                     PreparedStatement statement = connection.prepareStatement("SELECT id,randomNumber FROM World WHERE id = ?")
+                ) {
                     statement.setInt(1, getRandomNumber());
                     try (ResultSet resultSet = statement.executeQuery()) {
                         resultSet.next();
                         int id = resultSet.getInt(1);
                         int randomNumber = resultSet.getInt(2);
-                        worlds[i] = new World(id, randomNumber);
+                        worlds[index] = new World(id, randomNumber);
+                    }
+                } catch (SQLException e) {
+                    if (failed.compareAndSet(false, true)) {
+                        response.status(Status._500).body(e.getMessage());
+                        commitAsyncResponse();
                     }
+                    return;
                 }
-            }
-            try (PreparedStatement statement = connection.prepareStatement("UPDATE World SET randomNumber = ? WHERE id = ?")) {
-                for (World world : worlds) {
-                    world.randomNumber = getRandomNumber();
-                    statement.setInt(1, world.randomNumber);
-                    statement.setInt(2, world.id);
-                    statement.executeUpdate();
+
+                if (counter.incrementAndGet() == queries && !failed.get()) {
+                    response.appendHeader(Header.KV_CONTENT_TYPE_APPLICATION_JSON);
+                    response.body(JsonTools.serializeToBytes(worlds));
+
+                    commitAsyncResponse();
                 }
-            }
+            });
         }
-        return renderJson(worlds);
+    }
+
+    public void updates() {
+        int queries = Math.min(Math.max(params().getInt("queries", 1), 1), 500);
+        response.async();
+        AtomicInteger counter = new AtomicInteger(0);
+        AtomicBoolean failed = new AtomicBoolean(false);
+
+        World[] worlds = new World[queries];
+        for (int i = 0; i < queries; i++) {
+            int index = i;
+            executorService.submit(() -> {
+                try (Connection connection = dbService.getConnection()) {
+                    try (PreparedStatement statement = connection.prepareStatement("SELECT id,randomNumber FROM World WHERE id = ?")) {
+                        statement.setInt(1, getRandomNumber());
+                        try (ResultSet resultSet = statement.executeQuery()) {
+                            resultSet.next();
+                            int id = resultSet.getInt(1);
+                            int randomNumber = resultSet.getInt(2);
+                            worlds[index] = new World(id, randomNumber);
+                        }
+                    }
+                } catch (Exception e) {
+                    if (failed.compareAndSet(false, true)) {
+                        response.status(Status._500).body(e.getMessage());
+                        commitAsyncResponse();
+                    }
+                }
+
+
+                if (counter.incrementAndGet() == queries && !failed.get()) {
+                    executorService.submit(() -> {
+                        try (Connection connection = dbService.getConnection()) {
+                            try (PreparedStatement statement = connection.prepareStatement("UPDATE World SET randomNumber = ? WHERE id = ?")) {
+                                Arrays.sort(worlds, (o1, o2) -> Integer.compare(o2.id, o1.id));
+                                for (int j = queries - 1; j >= 0; j--) {
+                                    World world = worlds[j];
+                                    world.randomNumber = getRandomNumber();
+                                    statement.setInt(1, world.randomNumber);
+                                    statement.setInt(2, world.id);
+                                    if (j > 0)
+                                        statement.addBatch();
+                                    else
+                                        statement.executeBatch();
+                                }
+                            }
+
+                            response.appendHeader(Header.KV_CONTENT_TYPE_APPLICATION_JSON);
+                            response.body(JsonTools.serializeToBytes(worlds));
+
+                            commitAsyncResponse();
+                        } catch (Exception e) {
+                            if (failed.compareAndSet(false, true)) {
+                                response.status(Status._500).body(e.getMessage());
+                                commitAsyncResponse();
+                            }
+                        }
+                    });
+                }
+            });
+        }
+    }
+
+    protected void commitAsyncResponse() {
+        ByteBufferProvider bufferProvider = byteBufferProviderThreadLocal.get();
+        HttpConnection connection = request.connection();
+        response.commit(connection, bufferProvider);
+        connection.flush(bufferProvider);
+        response.reset();
     }
 
     protected int getRandomNumber() {

+ 15 - 1
frameworks/Java/wizzardo-http/src/main/java/com/wizzardo/techempower/DBService.java

@@ -3,6 +3,7 @@ package com.wizzardo.techempower;
 import com.wizzardo.http.framework.Configuration;
 import com.wizzardo.http.framework.di.PostConstruct;
 import com.wizzardo.http.framework.di.Service;
+
 import com.zaxxer.hikari.HikariConfig;
 import com.zaxxer.hikari.HikariDataSource;
 import org.postgresql.ds.PGSimpleDataSource;
@@ -13,8 +14,8 @@ import java.sql.SQLException;
 
 public class DBService implements Service, PostConstruct {
 
-    protected DataSource dataSource;
     protected DBConfig config;
+    protected DataSource dataSource;
 
     @Override
     public void init() {
@@ -59,5 +60,18 @@ public class DBService implements Service, PostConstruct {
         public String prefix() {
             return "db";
         }
+
+        @Override
+        public String toString() {
+            return "DBConfig{" +
+                    "dbname='" + dbname + '\'' +
+                    ", host='" + host + '\'' +
+                    ", port=" + port +
+                    ", username='" + username + '\'' +
+                    ", password='" + password + '\'' +
+                    ", maximumPoolSize=" + maximumPoolSize +
+                    ", minimumIdle=" + minimumIdle +
+                    '}';
+        }
     }
 }