Package org.lilyproject.rest.perftest

Source Code of org.lilyproject.rest.perftest.RestPerfTest$Result

/*
* Copyright 2012 NGDATA nv
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.lilyproject.rest.perftest;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.codehaus.jackson.node.JsonNodeFactory;
import org.codehaus.jackson.node.ObjectNode;
import org.lilyproject.cli.OptionUtil;
import org.lilyproject.testclientfw.BaseTestTool;
import org.lilyproject.testclientfw.Words;
import org.lilyproject.util.Version;
import org.lilyproject.util.json.JsonFormat;

public class RestPerfTest extends BaseTestTool {

    private HttpClient httpclient;

    private String baseUri;

    private int iterations;

    private Option iterationsOption;

    public static void main(String[] args) throws Exception {
        new RestPerfTest().start(args);
    }

    @Override
    protected String getCmdName() {
        return "rest-perftest";
    }

    @Override
    protected String getVersion() {
        return Version.readVersion("org.lilyproject", "lily-rest-perftest");
    }

    @Override
    @SuppressWarnings("static-access")
    public List<Option> getOptions() {
        List<Option> options = super.getOptions();

        iterationsOption = OptionBuilder
                .withArgName("iterations")
                .hasArg()
                .withDescription("Number of iterations")
                .withLongOpt("iterations")
                .create("i");
        options.add(iterationsOption);

        return options;
    }

    @Override
    public int run(CommandLine cmd) throws Exception {
        int result = super.run(cmd);
        if (result != 0) {
            return result;
        }

        iterations = OptionUtil.getIntOption(cmd, iterationsOption, 10000);

        setupMetrics();

        ThreadSafeClientConnManager connMgr = new ThreadSafeClientConnManager();
        httpclient = new DefaultHttpClient(connMgr);

        baseUri = "http://localhost:12060/repository";

//        Logger log = Logger.getLogger("org.apache.http");
//        log.setLevel(Level.DEBUG);

        runTest();

        finishMetrics();

        return 0;
    }

    private void runTest() throws Exception {

        // Create 5 field types
        for (int i = 1; i <= 5; i++) {
            String body = json("{name: 'n$field" + i + "', valueType: 'STRING', " +
                    "scope: 'versioned', namespaces: { 'org.lilyproject.rest-perftest': 'n' } }");
            put("/schema/fieldType/n$field" + i + "?ns.n=org.lilyproject.rest-perftest",
                    body.getBytes(), 200, 201);
        }

        // Create a record type
        {
            String body = json("{name: 'n$recordType', fields: [ {name: 'n$field1'}, {name: 'n$field2'}, " +
                    "{name: 'n$field3'}, {name: 'n$field4'}, {name: 'n$field5'} ]," +
                    "namespaces: { 'org.lilyproject.rest-perftest': 'n' } }");
            put("/schema/recordType/n$recordType?ns.n=org.lilyproject.rest-perftest", body.getBytes(), 200, 201);
        }

        final List<String> recordIds = new ArrayList<String>();

        //
        // Create records using put
        //
        startExecutor();
        final JsonNodeFactory factory = JsonNodeFactory.instance;
        final long now = System.currentTimeMillis();

        for (int i = 0; i < iterations; i++) {
            final int seqnr = i;
            executor.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        ObjectNode recordNode = factory.objectNode();
                        recordNode.put("type", "n$recordType");

                        ObjectNode fieldsNode = recordNode.putObject("fields");
                        for (int f = 1; f <= 5; f++) {
                            fieldsNode.put("n$field" + f, Words.get());
                        }

                        ObjectNode namespaces = recordNode.putObject("namespaces");
                        namespaces.put("org.lilyproject.rest-perftest", "n");

                        byte[] recordBytes = JsonFormat.serializeAsBytes(recordNode);

                        String recordId = "USER." + now + "_" + seqnr;
                        recordIds.add(recordId);

                        long before = System.nanoTime();
                        put("/record/" + recordId, recordBytes, 201);
                        double duration = System.nanoTime() - before;
                        metrics.increment("Create record using put", "C", duration / 1e6d);
                    } catch (Throwable t) {
                        t.printStackTrace();
                    }
                }
            });
        }
        stopExecutor();

        //
        // Create records using post
        //
        startExecutor();
        for (int i = 0; i < iterations; i++) {
            executor.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        ObjectNode actionNode = factory.objectNode();
                        actionNode.put("action", "create");

                        ObjectNode recordNode = actionNode.putObject("record");
                        recordNode.put("type", "n$recordType");

                        ObjectNode fieldsNode = recordNode.putObject("fields");
                        for (int f = 1; f <= 5; f++) {
                            fieldsNode.put("n$field" + f, Words.get());
                        }

                        ObjectNode namespaces = recordNode.putObject("namespaces");
                        namespaces.put("org.lilyproject.rest-perftest", "n");

                        byte[] recordBytes = JsonFormat.serializeAsBytes(actionNode);

                        long before = System.nanoTime();
                        Result result = post("/record", recordBytes, 201);
                        double duration = System.nanoTime() - before;
                        metrics.increment("Create record using post", "E", duration / 1e6d);

                        // ID is assigned by the server, read it out
                        ObjectNode createdRecord = (ObjectNode)JsonFormat.deserialize(result.data);
                        recordIds.add(createdRecord.get("id").getValueAsText());
                    } catch (Throwable t) {
                        t.printStackTrace();
                    }
                }
            });
        }
        stopExecutor();

        //
        // Read records
        //
        startExecutor();
        for (int i = 0; i < recordIds.size(); i++) {
            final int seqnr = i;
            executor.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        long before = System.nanoTime();
                        get("/record/" + recordIds.get(seqnr), 200);
                        double duration = System.nanoTime() - before;
                        metrics.increment("Record read", "R", duration / 1e6d);
                    } catch (Throwable t) {
                        t.printStackTrace();
                    }
                }
            });
        }
        stopExecutor();

        //
        // Read records using vtag
        //
        startExecutor();
        for (int i = 0; i < recordIds.size(); i++) {
            final int seqnr = i;
            executor.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        long before = System.nanoTime();
                        get("/record/" + recordIds.get(seqnr) + "/vtag/last", 200);
                        double duration = System.nanoTime() - before;
                        metrics.increment("Record read via last vtag", "T", duration / 1e6d);
                    } catch (Throwable t) {
                        t.printStackTrace();
                    }
                }
            });
        }
        stopExecutor();

        //
        // Read records using version
        //
        startExecutor();
        for (int i = 0; i < recordIds.size(); i++) {
            final int seqnr = i;
            executor.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        long before = System.nanoTime();
                        get("/record/" + recordIds.get(seqnr) + "/version/1", 200);
                        double duration = System.nanoTime() - before;
                        metrics.increment("Record read specific version", "V", duration / 1e6d);
                    } catch (Throwable t) {
                        t.printStackTrace();
                    }
                }
            });
        }
        stopExecutor();

        //
        // Read list of versions
        //
        startExecutor();
        for (int i = 0; i < recordIds.size(); i++) {
            final int seqnr = i;
            executor.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        long before = System.nanoTime();
                        get("/record/" + recordIds.get(seqnr) + "/version", 200);
                        double duration = System.nanoTime() - before;
                        metrics.increment("Read list of versions", "L", duration / 1e6d);
                    } catch (Throwable t) {
                        t.printStackTrace();
                    }
                }
            });
        }
        stopExecutor();

        //
        // Read list of variants
        //
        startExecutor();
        for (int i = 0; i < recordIds.size(); i++) {
            final int seqnr = i;
            executor.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        long before = System.nanoTime();
                        get("/record/" + recordIds.get(seqnr) + "/variant", 200);
                        double duration = System.nanoTime() - before;
                        metrics.increment("Read list of variants", "M", duration / 1e6d);
                    } catch (Throwable t) {
                        t.printStackTrace();
                    }
                }
            });
        }
        stopExecutor();

        //
        // Update records using PUT
        //
        startExecutor();
        for (int i = 0; i < recordIds.size(); i++) {
            final int seqnr = i;
            executor.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        ObjectNode recordNode = factory.objectNode();

                        ObjectNode fieldsNode = recordNode.putObject("fields");
                        for (int f = 1; f <= 5; f++) {
                            fieldsNode.put("n$field" + f, Words.get());
                        }

                        ObjectNode namespaces = recordNode.putObject("namespaces");
                        namespaces.put("org.lilyproject.rest-perftest", "n");

                        byte[] recordBytes = JsonFormat.serializeAsBytes(recordNode);

                        String recordId = recordIds.get(seqnr);

                        long before = System.nanoTime();
                        put("/record/" + recordId, recordBytes, 200);
                        double duration = System.nanoTime() - before;
                        metrics.increment("Update record using put", "U", duration / 1e6d);
                    } catch (Throwable t) {
                        t.printStackTrace();
                    }
                }
            });
        }
        stopExecutor();

        //
        // Read records using version
        //
        startExecutor();
        for (int i = 0; i < recordIds.size(); i++) {
            final int seqnr = i;
            executor.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        long before = System.nanoTime();
                        get("/record/" + recordIds.get(seqnr) + "/version/2", 200);
                        double duration = System.nanoTime() - before;
                        metrics.increment("Record read specific version (2)", "W", duration / 1e6d);
                    } catch (Throwable t) {
                        t.printStackTrace();
                    }
                }
            });
        }
        stopExecutor();
    }

    private Result get(String path, int... expectedStatus) throws IOException {
        HttpGet get = new HttpGet(baseUri + path);
        HttpResponse response = httpclient.execute(get);

        byte[] data = checkStatusAndReadResponse(path, response, expectedStatus);

        return new Result(response, data);
    }

    private Result put(String path, byte[] body, int... expectedStatus) throws IOException {
        HttpPut put = new HttpPut(baseUri + path);
        put.addHeader("Content-Type", "application/json");
        put.setEntity(new ByteArrayEntity(body));
        HttpResponse response = httpclient.execute(put);

        byte[] data = checkStatusAndReadResponse(path, response, expectedStatus);

        return new Result(response, data);
    }

    private Result post(String path, byte[] body, int... expectedStatus) throws IOException {
        HttpPost post = new HttpPost(baseUri + path);
        post.addHeader("Content-Type", "application/json");
        post.setEntity(new ByteArrayEntity(body));
        HttpResponse response = httpclient.execute(post);

        byte[] data = checkStatusAndReadResponse(path, response, expectedStatus);

        return new Result(response, data);
    }

    private byte[] checkStatusAndReadResponse(String path, HttpResponse response, int... expectedStatus)
            throws IOException {

        // It's important to read out the entity
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        response.getEntity().writeTo(bos);

        int status = response.getStatusLine().getStatusCode();

        Arrays.sort(expectedStatus);
        if (Arrays.binarySearch(expectedStatus, status) < 0) {
            System.out.println(new String(bos.toByteArray()));

            throw new RuntimeException("Unexpected response status. Got " + status + ", expected (one of) " +
                    toString(expectedStatus) + ". Request path: " + path);
        }

        return bos.toByteArray();
    }

    private String json(String input) {
        return input.replaceAll("'", "\"");
    }

    private String toString(int[] numbers) {
        StringBuilder builder = new StringBuilder();
        for (int number : numbers) {
            if (builder.length() > 0) {
                builder.append(", ");
            }
            builder.append(number);
        }
        return builder.toString();
    }

    private static class Result {
        HttpResponse response;
        byte[] data;

        Result(HttpResponse response, byte[] data) {
            this.response = response;
            this.data = data;
        }
    }
}
TOP

Related Classes of org.lilyproject.rest.perftest.RestPerfTest$Result

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.