Package org.springframework.data.mongodb.performance

Source Code of org.springframework.data.mongodb.performance.PerformanceTests

/*
* Copyright 2012 the original author or authors.
*
* 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.springframework.data.mongodb.performance;

import static org.springframework.data.mongodb.core.query.Criteria.*;
import static org.springframework.data.mongodb.core.query.Query.*;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.regex.Pattern;

import org.bson.types.ObjectId;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.Constants;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.MongoConverter;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.support.MongoRepositoryFactoryBean;
import org.springframework.util.Assert;
import org.springframework.util.StopWatch;
import org.springframework.util.StringUtils;

import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import com.mongodb.MongoClient;
import com.mongodb.WriteConcern;

/**
* Test class to execute performance tests for plain MongoDB driver usage, {@link MongoTemplate} and the repositories
* abstraction.
*
* @author Oliver Gierke
*/
public class PerformanceTests {

  private static final String DATABASE_NAME = "performance";
  private static final int NUMBER_OF_PERSONS = 300;
  private static final int ITERATIONS = 50;
  private static final StopWatch watch = new StopWatch();
  private static final Collection<String> IGNORED_WRITE_CONCERNS = Arrays.asList("MAJORITY", "REPLICAS_SAFE",
      "FSYNC_SAFE", "FSYNCED", "JOURNAL_SAFE", "JOURNALED", "REPLICA_ACKNOWLEDGED");
  private static final int COLLECTION_SIZE = 1024 * 1024 * 256; // 256 MB
  private static final Collection<String> COLLECTION_NAMES = Arrays.asList("template", "driver", "person");

  Mongo mongo;
  MongoTemplate operations;
  PersonRepository repository;
  MongoConverter converter;

  @Before
  public void setUp() throws Exception {

    this.mongo = new MongoClient();

    SimpleMongoDbFactory mongoDbFactory = new SimpleMongoDbFactory(this.mongo, DATABASE_NAME);

    MongoMappingContext context = new MongoMappingContext();
    context.setInitialEntitySet(Collections.singleton(Person.class));
    context.afterPropertiesSet();

    this.converter = new MappingMongoConverter(new DefaultDbRefResolver(mongoDbFactory), context);
    this.operations = new MongoTemplate(new SimpleMongoDbFactory(this.mongo, DATABASE_NAME), converter);

    MongoRepositoryFactoryBean<PersonRepository, Person, ObjectId> factory = new MongoRepositoryFactoryBean<PersonRepository, Person, ObjectId>();
    factory.setMongoOperations(operations);
    factory.setRepositoryInterface(PersonRepository.class);
    factory.afterPropertiesSet();

    this.repository = factory.getObject();

  }

  @Test
  public void writeWithWriteConcerns() {
    executeWithWriteConcerns(new WriteConcernCallback() {
      public void doWithWriteConcern(String constantName, WriteConcern concern) {
        writeHeadline("WriteConcern: " + constantName);
        System.out.println(String.format("Writing %s objects using plain driver took %sms", NUMBER_OF_PERSONS,
            writingObjectsUsingPlainDriver(NUMBER_OF_PERSONS)));
        System.out.println(String.format("Writing %s objects using template took %sms", NUMBER_OF_PERSONS,
            writingObjectsUsingMongoTemplate(NUMBER_OF_PERSONS)));
        System.out.println(String.format("Writing %s objects using repository took %sms", NUMBER_OF_PERSONS,
            writingObjectsUsingRepositories(NUMBER_OF_PERSONS)));
        writeFooter();
      }
    });
  }

  @Test
  public void plainConversion() throws InterruptedException {

    Statistics statistics = new Statistics("Plain conversion of " + NUMBER_OF_PERSONS * 100
        + " persons - After %s iterations");

    List<DBObject> dbObjects = getPersonDBObjects(NUMBER_OF_PERSONS * 100);

    for (int i = 0; i < ITERATIONS; i++) {
      statistics.registerTime(Api.DIRECT, Mode.READ, convertDirectly(dbObjects));
      statistics.registerTime(Api.CONVERTER, Mode.READ, convertUsingConverter(dbObjects));
    }

    statistics.printResults(ITERATIONS);
  }

  private long convertDirectly(final List<DBObject> dbObjects) {

    executeWatched(new WatchCallback<List<Person>>() {

      @Override
      public List<Person> doInWatch() {

        List<Person> persons = new ArrayList<PerformanceTests.Person>();

        for (DBObject dbObject : dbObjects) {
          persons.add(Person.from(dbObject));
        }

        return persons;
      }
    });

    return watch.getLastTaskTimeMillis();
  }

  private long convertUsingConverter(final List<DBObject> dbObjects) {

    executeWatched(new WatchCallback<List<Person>>() {

      @Override
      public List<Person> doInWatch() {

        List<Person> persons = new ArrayList<PerformanceTests.Person>();

        for (DBObject dbObject : dbObjects) {
          persons.add(converter.read(Person.class, dbObject));
        }

        return persons;
      }
    });

    return watch.getLastTaskTimeMillis();
  }

  @Test
  public void writeAndRead() throws Exception {

    mongo.setWriteConcern(WriteConcern.SAFE);

    readsAndWrites(NUMBER_OF_PERSONS, ITERATIONS);
  }

  private void readsAndWrites(int numberOfPersons, int iterations) {

    Statistics statistics = new Statistics("Reading " + numberOfPersons + " - After %s iterations");

    for (int i = 0; i < iterations; i++) {

      setupCollections();

      statistics.registerTime(Api.DRIVER, Mode.WRITE, writingObjectsUsingPlainDriver(numberOfPersons));
      statistics.registerTime(Api.TEMPLATE, Mode.WRITE, writingObjectsUsingMongoTemplate(numberOfPersons));
      statistics.registerTime(Api.REPOSITORY, Mode.WRITE, writingObjectsUsingRepositories(numberOfPersons));

      statistics.registerTime(Api.DRIVER, Mode.READ, readingUsingPlainDriver());
      statistics.registerTime(Api.TEMPLATE, Mode.READ, readingUsingTemplate());
      statistics.registerTime(Api.REPOSITORY, Mode.READ, readingUsingRepository());

      statistics.registerTime(Api.DRIVER, Mode.QUERY, queryUsingPlainDriver());
      statistics.registerTime(Api.TEMPLATE, Mode.QUERY, queryUsingTemplate());
      statistics.registerTime(Api.REPOSITORY, Mode.QUERY, queryUsingRepository());

      if (i > 0 && i % (iterations / 10) == 0) {
        statistics.printResults(i);
      }
    }

    statistics.printResults(iterations);
  }

  private void writeHeadline(String headline) {
    System.out.println(headline);
    System.out.println(createUnderline(headline));
  }

  private void writeFooter() {
    System.out.println();
  }

  private long queryUsingTemplate() {
    executeWatched(new WatchCallback<List<Person>>() {
      public List<Person> doInWatch() {
        Query query = query(where("addresses.zipCode").regex(".*1.*"));
        return operations.find(query, Person.class, "template");
      }
    });

    return watch.getLastTaskTimeMillis();
  }

  private long queryUsingRepository() {
    executeWatched(new WatchCallback<List<Person>>() {
      public List<Person> doInWatch() {
        return repository.findByAddressesZipCodeContaining("1");
      }
    });

    return watch.getLastTaskTimeMillis();
  }

  private void executeWithWriteConcerns(WriteConcernCallback callback) {

    Constants constants = new Constants(WriteConcern.class);

    for (String constantName : constants.getNames(null)) {

      if (IGNORED_WRITE_CONCERNS.contains(constantName)) {
        continue;
      }

      WriteConcern writeConcern = (WriteConcern) constants.asObject(constantName);
      mongo.setWriteConcern(writeConcern);

      setupCollections();

      callback.doWithWriteConcern(constantName, writeConcern);
    }
  }

  private void setupCollections() {

    DB db = this.mongo.getDB(DATABASE_NAME);

    for (String collectionName : COLLECTION_NAMES) {
      DBCollection collection = db.getCollection(collectionName);
      collection.drop();
      collection.getDB().command(getCreateCollectionCommand(collectionName));
      collection.ensureIndex(new BasicDBObject("firstname", -1));
      collection.ensureIndex(new BasicDBObject("lastname", -1));
    }
  }

  private DBObject getCreateCollectionCommand(String name) {
    BasicDBObject dbObject = new BasicDBObject();
    dbObject.put("createCollection", name);
    dbObject.put("capped", false);
    dbObject.put("size", COLLECTION_SIZE);
    return dbObject;
  }

  private long writingObjectsUsingPlainDriver(int numberOfPersons) {

    final DBCollection collection = mongo.getDB(DATABASE_NAME).getCollection("driver");
    final List<Person> persons = getPersonObjects(numberOfPersons);

    executeWatched(new WatchCallback<Void>() {
      public Void doInWatch() {
        for (Person person : persons) {
          collection.save(person.toDBObject());
        }
        return null;
      }
    });

    return watch.getLastTaskTimeMillis();
  }

  private long writingObjectsUsingRepositories(int numberOfPersons) {

    final List<Person> persons = getPersonObjects(numberOfPersons);

    executeWatched(new WatchCallback<Void>() {
      public Void doInWatch() {
        repository.save(persons);
        return null;
      }
    });

    return watch.getLastTaskTimeMillis();
  }

  private long writingObjectsUsingMongoTemplate(int numberOfPersons) {

    final List<Person> persons = getPersonObjects(numberOfPersons);

    executeWatched(new WatchCallback<Void>() {
      public Void doInWatch() {
        for (Person person : persons) {
          operations.save(person, "template");
        }
        return null;
      }
    });

    return watch.getLastTaskTimeMillis();
  }

  private long readingUsingPlainDriver() {

    executeWatched(new WatchCallback<List<Person>>() {
      public List<Person> doInWatch() {
        return toPersons(mongo.getDB(DATABASE_NAME).getCollection("driver").find());
      }
    });

    return watch.getLastTaskTimeMillis();
  }

  private long readingUsingTemplate() {
    executeWatched(new WatchCallback<List<Person>>() {
      public List<Person> doInWatch() {
        return operations.findAll(Person.class, "template");
      }
    });

    return watch.getLastTaskTimeMillis();
  }

  private long readingUsingRepository() {
    executeWatched(new WatchCallback<List<Person>>() {
      public List<Person> doInWatch() {
        return repository.findAll();
      }
    });

    return watch.getLastTaskTimeMillis();
  }

  private long queryUsingPlainDriver() {

    executeWatched(new WatchCallback<List<Person>>() {
      public List<Person> doInWatch() {

        DBCollection collection = mongo.getDB(DATABASE_NAME).getCollection("driver");

        DBObject regex = new BasicDBObject("$regex", Pattern.compile(".*1.*"));
        DBObject query = new BasicDBObject("addresses.zipCode", regex);
        return toPersons(collection.find(query));
      }
    });

    return watch.getLastTaskTimeMillis();
  }

  private List<Person> getPersonObjects(int numberOfPersons) {

    List<Person> result = new ArrayList<Person>();

    for (int i = 0; i < numberOfPersons; i++) {

      List<Address> addresses = new ArrayList<Address>();

      for (int a = 0; a < 5; a++) {
        addresses.add(new Address("zip" + a, "city" + a));
      }

      Person person = new Person("Firstname" + i, "Lastname" + i, addresses);

      for (int o = 0; o < 10; o++) {
        person.orders.add(new Order(LineItem.generate()));
      }

      result.add(person);
    }

    return result;
  }

  private List<DBObject> getPersonDBObjects(int numberOfPersons) {

    List<DBObject> dbObjects = new ArrayList<DBObject>(numberOfPersons);

    for (Person person : getPersonObjects(numberOfPersons)) {
      dbObjects.add(person.toDBObject());
    }

    return dbObjects;
  }

  private <T> T executeWatched(WatchCallback<T> callback) {

    watch.start();

    try {
      return callback.doInWatch();
    } finally {
      watch.stop();
    }
  }

  private static List<Person> toPersons(DBCursor cursor) {

    List<Person> persons = new ArrayList<Person>();

    while (cursor.hasNext()) {
      persons.add(Person.from(cursor.next()));
    }

    return persons;
  }

  static class Person {

    ObjectId id;
    String firstname, lastname;
    List<Address> addresses;
    Set<Order> orders;

    public Person(String firstname, String lastname, List<Address> addresses) {
      this.firstname = firstname;
      this.lastname = lastname;
      this.addresses = addresses;
      this.orders = new HashSet<Order>();
    }

    public static Person from(DBObject source) {

      BasicDBList addressesSource = (BasicDBList) source.get("addresses");
      List<Address> addresses = new ArrayList<Address>(addressesSource.size());
      for (Object addressSource : addressesSource) {
        addresses.add(Address.from((DBObject) addressSource));
      }

      BasicDBList ordersSource = (BasicDBList) source.get("orders");
      Set<Order> orders = new HashSet<Order>(ordersSource.size());
      for (Object orderSource : ordersSource) {
        orders.add(Order.from((DBObject) orderSource));
      }

      Person person = new Person((String) source.get("firstname"), (String) source.get("lastname"), addresses);
      person.orders.addAll(orders);
      return person;
    }

    public DBObject toDBObject() {

      DBObject dbObject = new BasicDBObject();
      dbObject.put("firstname", firstname);
      dbObject.put("lastname", lastname);
      dbObject.put("addresses", writeAll(addresses));
      dbObject.put("orders", writeAll(orders));
      return dbObject;
    }
  }

  static class Address implements Convertible {

    final String zipCode;
    final String city;
    final Set<AddressType> types;

    public Address(String zipCode, String city) {
      this(zipCode, city, new HashSet<AddressType>(pickRandomNumerOfItemsFrom(Arrays.asList(AddressType.values()))));
    }

    @PersistenceConstructor
    public Address(String zipCode, String city, Set<AddressType> types) {
      this.zipCode = zipCode;
      this.city = city;
      this.types = types;
    }

    public static Address from(DBObject source) {
      String zipCode = (String) source.get("zipCode");
      String city = (String) source.get("city");
      BasicDBList types = (BasicDBList) source.get("types");

      return new Address(zipCode, city, new HashSet<AddressType>(readFromBasicDBList(types, AddressType.class)));
    }

    public DBObject toDBObject() {
      BasicDBObject dbObject = new BasicDBObject();
      dbObject.put("zipCode", zipCode);
      dbObject.put("city", city);
      dbObject.put("types", toBasicDBList(types));
      return dbObject;
    }
  }

  private static <T extends Enum<T>> List<T> readFromBasicDBList(BasicDBList source, Class<T> type) {

    List<T> result = new ArrayList<T>(source.size());
    for (Object object : source) {
      result.add(Enum.valueOf(type, object.toString()));
    }
    return result;
  }

  private static <T extends Enum<T>> BasicDBList toBasicDBList(Collection<T> enums) {
    BasicDBList result = new BasicDBList();
    for (T element : enums) {
      result.add(element.toString());
    }

    return result;
  }

  static class Order implements Convertible {

    static enum Status {
      ORDERED, PAYED, SHIPPED;
    }

    Date createdAt;
    List<LineItem> lineItems;
    Status status;

    public Order(List<LineItem> lineItems, Date createdAt) {
      this.lineItems = lineItems;
      this.createdAt = createdAt;
      this.status = Status.ORDERED;
    }

    @PersistenceConstructor
    public Order(List<LineItem> lineItems, Date createdAt, Status status) {
      this.lineItems = lineItems;
      this.createdAt = createdAt;
      this.status = status;
    }

    public static Order from(DBObject source) {

      BasicDBList lineItemsSource = (BasicDBList) source.get("lineItems");
      List<LineItem> lineItems = new ArrayList<PerformanceTests.LineItem>(lineItemsSource.size());
      for (Object lineItemSource : lineItemsSource) {
        lineItems.add(LineItem.from((DBObject) lineItemSource));
      }

      Date date = (Date) source.get("createdAt");
      Status status = Status.valueOf((String) source.get("status"));
      return new Order(lineItems, date, status);
    }

    public Order(List<LineItem> lineItems) {
      this(lineItems, new Date());
    }

    public DBObject toDBObject() {
      DBObject result = new BasicDBObject();
      result.put("createdAt", createdAt);
      result.put("lineItems", writeAll(lineItems));
      result.put("status", status.toString());
      return result;
    }
  }

  static class LineItem implements Convertible {

    String description;
    double price;
    int amount;

    public LineItem(String description, int amount, double price) {
      this.description = description;
      this.amount = amount;
      this.price = price;
    }

    public static List<LineItem> generate() {

      LineItem iPad = new LineItem("iPad", 1, 649);
      LineItem iPhone = new LineItem("iPhone", 1, 499);
      LineItem macBook = new LineItem("MacBook", 2, 1299);

      return pickRandomNumerOfItemsFrom(Arrays.asList(iPad, iPhone, macBook));
    }

    public static LineItem from(DBObject source) {

      String description = (String) source.get("description");
      double price = (Double) source.get("price");
      int amount = (Integer) source.get("amount");

      return new LineItem(description, amount, price);
    }

    public DBObject toDBObject() {

      BasicDBObject dbObject = new BasicDBObject();
      dbObject.put("description", description);
      dbObject.put("price", price);
      dbObject.put("amount", amount);
      return dbObject;
    }
  }

  private static <T> List<T> pickRandomNumerOfItemsFrom(List<T> source) {

    Assert.isTrue(!source.isEmpty());

    Random random = new Random();
    int numberOfItems = random.nextInt(source.size());
    numberOfItems = numberOfItems == 0 ? 1 : numberOfItems;

    List<T> result = new ArrayList<T>(numberOfItems);
    while (result.size() < numberOfItems) {
      int index = random.nextInt(source.size());
      T candidate = source.get(index);
      if (!result.contains(candidate)) {
        result.add(candidate);
      }
    }

    return result;
  }

  static enum AddressType {
    SHIPPING, BILLING;
  }

  private interface WriteConcernCallback {
    void doWithWriteConcern(String constantName, WriteConcern concern);
  }

  private interface WatchCallback<T> {
    T doInWatch();
  }

  private interface PersonRepository extends MongoRepository<Person, ObjectId> {

    List<Person> findByAddressesZipCodeContaining(String parameter);
  }

  private interface Convertible {

    DBObject toDBObject();
  }

  private static BasicDBList writeAll(Collection<? extends Convertible> convertibles) {
    BasicDBList result = new BasicDBList();
    for (Convertible convertible : convertibles) {
      result.add(convertible.toDBObject());
    }
    return result;
  }

  static enum Api {
    DRIVER, TEMPLATE, REPOSITORY, DIRECT, CONVERTER;
  }

  static enum Mode {
    WRITE, READ, QUERY;
  }

  private static class Statistics {

    private final String headline;
    private final Map<Mode, ModeTimes> times;

    public Statistics(String headline) {

      this.headline = headline;
      this.times = new HashMap<Mode, ModeTimes>();

      for (Mode mode : Mode.values()) {
        times.put(mode, new ModeTimes(mode));
      }
    }

    public void registerTime(Api api, Mode mode, double time) {
      times.get(mode).add(api, time);
    }

    public void printResults(int iterations) {

      String title = String.format(headline, iterations);

      System.out.println(title);
      System.out.println(createUnderline(title));

      StringBuilder builder = new StringBuilder();
      for (Mode mode : Mode.values()) {
        String print = times.get(mode).print();
        if (!print.isEmpty()) {
          builder.append(print).append('\n');
        }
      }

      System.out.println(builder.toString());
    }

    @Override
    public String toString() {

      StringBuilder builder = new StringBuilder(times.size());

      for (ModeTimes times : this.times.values()) {
        builder.append(times.toString());
      }

      return builder.toString();
    }
  }

  private static String createUnderline(String input) {

    StringBuilder builder = new StringBuilder(input.length());

    for (int i = 0; i < input.length(); i++) {
      builder.append("-");
    }

    return builder.toString();
  }

  static class ApiTimes {

    private static final String TIME_TEMPLATE = "%s %s time -\tAverage: %sms%s,%sMedian: %sms%s";

    private static final DecimalFormat TIME_FORMAT;
    private static final DecimalFormat DEVIATION_FORMAT;

    static {

      TIME_FORMAT = new DecimalFormat("0.00");

      DEVIATION_FORMAT = new DecimalFormat("0.00");
      DEVIATION_FORMAT.setPositivePrefix("+");
    }

    private final Api api;
    private final Mode mode;
    private final List<Double> times;

    public ApiTimes(Api api, Mode mode) {
      this.api = api;
      this.mode = mode;
      this.times = new ArrayList<Double>();
    }

    public void add(double time) {
      this.times.add(time);
    }

    public boolean hasTimes() {
      return !times.isEmpty();
    }

    public double getAverage() {

      double result = 0;

      for (Double time : times) {
        result += time;
      }

      return result == 0.0 ? 0.0 : result / times.size();
    }

    public double getMedian() {

      if (times.isEmpty()) {
        return 0.0;
      }

      ArrayList<Double> list = new ArrayList<Double>(times);
      Collections.sort(list);

      int size = list.size();

      if (size % 2 == 0) {
        return (list.get(size / 2 - 1) + list.get(size / 2)) / 2;
      } else {
        return list.get(size / 2);
      }
    }

    private double getDeviationFrom(double otherAverage) {

      double average = getAverage();
      return average * 100 / otherAverage - 100;
    }

    private double getMediaDeviationFrom(double otherMedian) {
      double median = getMedian();
      return median * 100 / otherMedian - 100;
    }

    public String print() {

      if (times.isEmpty()) {
        return "";
      }

      return basicPrint("", "\t\t", "") + '\n';
    }

    private String basicPrint(String extension, String middle, String foo) {
      return String.format(TIME_TEMPLATE, api, mode, TIME_FORMAT.format(getAverage()), extension, middle,
          TIME_FORMAT.format(getMedian()), foo);
    }

    public String print(double referenceAverage, double referenceMedian) {

      if (times.isEmpty()) {
        return "";
      }

      return basicPrint(String.format(" %s%%", DEVIATION_FORMAT.format(getDeviationFrom(referenceAverage))), "\t",
          String.format(" %s%%", DEVIATION_FORMAT.format(getMediaDeviationFrom(referenceMedian)))) + '\n';
    }

    /*
     * (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
      return times.isEmpty() ? "" : String.format("%s, %s: %s", api, mode,
          StringUtils.collectionToCommaDelimitedString(times)) + '\n';
    }
  }

  static class ModeTimes {

    private final Map<Api, ApiTimes> times;

    public ModeTimes(Mode mode) {

      this.times = new HashMap<Api, ApiTimes>();

      for (Api api : Api.values()) {
        this.times.put(api, new ApiTimes(api, mode));
      }
    }

    public void add(Api api, double time) {
      times.get(api).add(time);
    }

    @SuppressWarnings("null")
    public String print() {

      if (times.isEmpty()) {
        return "";
      }

      Double previousTime = null;
      Double previousMedian = null;
      StringBuilder builder = new StringBuilder();

      for (Api api : Api.values()) {

        ApiTimes apiTimes = times.get(api);

        if (!apiTimes.hasTimes()) {
          continue;
        }

        if (previousTime == null) {
          builder.append(apiTimes.print());
          previousTime = apiTimes.getAverage();
          previousMedian = apiTimes.getMedian();
        } else {
          builder.append(apiTimes.print(previousTime, previousMedian));
        }
      }

      return builder.toString();
    }

    /*
     * (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {

      StringBuilder builder = new StringBuilder(times.size());

      for (ApiTimes times : this.times.values()) {
        builder.append(times.toString());
      }

      return builder.toString();
    }
  }
}
TOP

Related Classes of org.springframework.data.mongodb.performance.PerformanceTests

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.