/*
* Copyright 2011 Outerthought bvba
*
* 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.process.test;
import java.util.ArrayList;
import java.util.List;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.MappingJsonFactory;
import org.codehaus.jackson.node.JsonNodeFactory;
import org.codehaus.jackson.node.ObjectNode;
import org.junit.Test;
import org.lilyproject.client.LilyClient;
import org.lilyproject.lilyservertestfw.LilyProxy;
import org.lilyproject.repository.api.FieldType;
import org.lilyproject.repository.api.QName;
import org.lilyproject.repository.api.Record;
import org.lilyproject.repository.api.RecordBuilder;
import org.lilyproject.repository.api.RecordId;
import org.lilyproject.repository.api.RecordTypeBuilder;
import org.lilyproject.repository.api.Repository;
import org.lilyproject.repository.api.Scope;
import org.lilyproject.repository.api.TypeManager;
import org.lilyproject.repository.api.ValueType;
import org.lilyproject.util.json.JsonUtil;
public class RecordValueTypeBenchmark {
private MappingJsonFactory mappingJsonFactory = new MappingJsonFactory();
private Repository repository;
private TypeManager typeManager;
private LilyProxy lilyProxy;
private int nrOfFields = 20;
private int nrOfRecords = 10000;
private int nrOfTimes = 10;
private enum Type {MIXED, SEQ, RVT, JSON}
private Type type = Type.MIXED;
// durations
long rvtBuild = 0;
long rvtCreate = 0;
long rvtRead = 0;
long rvtReadValues = 0;
long jsonBuild = 0;
long jsonCreate = 0;
long jsonRead = 0;
long jsonReadValues = 0;
private List<RecordId> rvtRecordIds;
private List<RecordId> jsonRecordIds;
private String ns;
public static void main(String[] args) throws Exception {
RecordValueTypeBenchmark benchmark = new RecordValueTypeBenchmark();
benchmark.initialize(args);
benchmark.testRecordValueTypePerformance();
benchmark.stop();
}
@Test
public void testBenchmark() throws Exception {
RecordValueTypeBenchmark benchmark = new RecordValueTypeBenchmark();
benchmark.initialize(new String[] { "f=2" });
benchmark.testRecordValueTypePerformance();
benchmark.stop();
}
private void initialize(String[] args) throws Exception {
for (String arg : args) {
if (arg.startsWith("f=")) {
nrOfFields = Integer.valueOf(arg.substring(2));
}
if (arg.startsWith("r=")) {
nrOfRecords = Integer.valueOf(arg.substring(2));
}
if (arg.startsWith("t=")) {
type = Type.valueOf(arg.substring(2));
}
if (arg.startsWith("n=")) {
nrOfTimes = Integer.valueOf(arg.substring(2));
}
}
lilyProxy = new LilyProxy();
lilyProxy.start();
LilyClient lilyClient = lilyProxy.getLilyServerProxy().getClient();
repository = lilyClient.getRepository();
typeManager = repository.getTypeManager();
resetDurations();
}
private void resetDurations() {
// durations
rvtBuild = 0;
rvtCreate = 0;
rvtRead = 0;
rvtReadValues = 0;
jsonBuild = 0;
jsonCreate = 0;
jsonRead = 0;
jsonReadValues = 0;
}
private void stop() throws Exception {
lilyProxy.stop();
}
private void testRecordValueTypePerformance() throws Exception {
System.out.println("===> Starting benchmark with settings: fields=" + nrOfFields + ", records=" + nrOfRecords
+ ", times=" + nrOfTimes + ", type=" + type.toString());
ns = "testRecordValueTypePerformance";
QName rvtRTName = new QName(ns, "rvtRT");
// Create field types and record types for the records containing complex types
RecordTypeBuilder rtBuilder = typeManager.recordTypeBuilder().name(rvtRTName);
for (int i = 0; i < nrOfFields; i++) {
FieldType fieldType = typeManager.createFieldType(typeManager.newFieldType(typeManager
.getValueType("STRING"), new QName(ns, "stringField" + i), Scope.NON_VERSIONED));
rtBuilder.field(fieldType.getId(), false);
}
rtBuilder.create();
ValueType rvt = typeManager.getValueType("RECORD<"+rvtRTName.toString()+">");
FieldType rvtFT = typeManager.createFieldType(typeManager.newFieldType(rvt, new QName(ns, "rvtField"),
Scope.NON_VERSIONED));
typeManager.recordTypeBuilder().name(new QName(ns, "rvtFieldRT")).field(rvtFT.getId(), false).create();
// Create field types and record types for the records containing serialized json
FieldType jsonFT = typeManager.createFieldType(typeManager.newFieldType(typeManager.getValueType("STRING"),
new QName(ns, "jsonField"), Scope.NON_VERSIONED));
typeManager.recordTypeBuilder().name(new QName(ns, "jsonFieldRT")).field(jsonFT.getId(), false).create();
rvtRecordIds = new ArrayList<RecordId>();
jsonRecordIds = new ArrayList<RecordId>();
switch (type) {
case MIXED:
for (int i = 0; i < nrOfTimes; i++) {
resetDurations();
runMixed();
}
break;
case SEQ:
for (int i = 0; i < nrOfTimes; i++) {
resetDurations();
runSequential();
}
break;
case RVT:
for (int i = 0; i < nrOfTimes; i++) {
resetDurations();
runRvt();
}
break;
case JSON:
for (int i = 0; i < nrOfTimes; i++) {
resetDurations();
runJson();
}
break;
default:
break;
}
System.out.println("===> End benchmark");
}
private void runMixed() throws Exception {
// Build and create the records
for (int i = 0; i < nrOfRecords; i++) {
long rvtBuildBefore = System.currentTimeMillis();
Record rvtRecord = buildRvtRecord(ns, nrOfFields);
rvtBuild += (System.currentTimeMillis() - rvtBuildBefore);
long jsonBuildBefore = System.currentTimeMillis();
Record jsonRecord = buildJsonRecord(ns, nrOfFields);
jsonBuild += (System.currentTimeMillis() - jsonBuildBefore);
long rvtCreateBefore = System.currentTimeMillis();
rvtRecordIds.add(repository.create(rvtRecord).getId());
rvtCreate += (System.currentTimeMillis() - rvtCreateBefore);
long jsonCreateBefore = System.currentTimeMillis();
jsonRecordIds.add(repository.create(jsonRecord).getId());
jsonCreate += (System.currentTimeMillis() - jsonCreateBefore);
}
// Read the records and their values
for (int i = 0; i < nrOfRecords; i++) {
long rvtReadBefore = System.currentTimeMillis();
Record rvtRecord = repository.read(rvtRecordIds.get(i));
rvtRead += (System.currentTimeMillis() - rvtReadBefore);
long jsonReadBefore = System.currentTimeMillis();
Record jsonRecord = repository.read(jsonRecordIds.get(i));
jsonRead += (System.currentTimeMillis() - jsonReadBefore);
long rvtReadValuesBefore = System.currentTimeMillis();
readRvtValues(rvtRecord, ns, nrOfFields);
rvtReadValues += (System.currentTimeMillis() - rvtReadValuesBefore);
long jsonReadValuesBefore = System.currentTimeMillis();
readJsonValues(jsonRecord, ns, nrOfFields);
jsonReadValues += (System.currentTimeMillis() - jsonReadValuesBefore);
}
long rvtTotal = rvtBuild + rvtCreate + rvtRead + rvtReadValues;
long rvtAvg = rvtTotal / nrOfRecords;
long jsonTotal = jsonBuild + jsonCreate + jsonRead + jsonReadValues;
long jsonAvg = jsonTotal / nrOfRecords;
System.out.println("===> RVT: total: " + rvtTotal + " avg: " + rvtAvg + " build: " + rvtBuild + " create: "
+ rvtCreate + " read: " + rvtRead + " readValues: " + rvtReadValues);
System.out.println("===> JSON: total: " + jsonTotal + " avg: " + jsonAvg + " build: " + jsonBuild + " create: "
+ jsonCreate + " read: " + jsonRead + " readValues: " + jsonReadValues);
// assertTrue("Complex types encoding is more than 10% slower than json encoding", rvtTotal < (jsonTotal + (jsonTotal / 10)));
}
private void runRvt() throws Exception {
// Build and create the records
for (int i = 0; i < nrOfRecords; i++) {
long rvtBuildBefore = System.currentTimeMillis();
Record rvtRecord = buildRvtRecord(ns, nrOfFields);
rvtBuild += (System.currentTimeMillis() - rvtBuildBefore);
long rvtCreateBefore = System.currentTimeMillis();
rvtRecordIds.add(repository.create(rvtRecord).getId());
rvtCreate += (System.currentTimeMillis() - rvtCreateBefore);
}
// Read the records and their values
for (int i = 0; i < nrOfRecords; i++) {
long rvtReadBefore = System.currentTimeMillis();
Record rvtRecord = repository.read(rvtRecordIds.get(i));
rvtRead += (System.currentTimeMillis() - rvtReadBefore);
long rvtReadValuesBefore = System.currentTimeMillis();
readRvtValues(rvtRecord, ns, nrOfFields);
rvtReadValues += (System.currentTimeMillis() - rvtReadValuesBefore);
}
long rvtTotal = rvtBuild + rvtCreate + rvtRead + rvtReadValues;
long rvtAvg = rvtTotal / nrOfRecords;
System.out.println("RVT: total: " + rvtTotal + " avg: " + rvtAvg + " build: " + rvtBuild + " create: " + rvtCreate + " read: " + rvtRead + " readValues: " + rvtReadValues);
}
private void runJson() throws Exception {
// Build and create the records
for (int i = 0; i < nrOfRecords; i++) {
long jsonBuildBefore = System.currentTimeMillis();
Record jsonRecord = buildJsonRecord(ns, nrOfFields);
jsonBuild += (System.currentTimeMillis() - jsonBuildBefore);
long jsonCreateBefore = System.currentTimeMillis();
jsonRecordIds.add(repository.create(jsonRecord).getId());
jsonCreate += (System.currentTimeMillis() - jsonCreateBefore);
}
// Read the records and their values
for (int i = 0; i < nrOfRecords; i++) {
long jsonReadBefore = System.currentTimeMillis();
Record jsonRecord = repository.read(jsonRecordIds.get(i));
jsonRead += (System.currentTimeMillis() - jsonReadBefore);
long jsonReadValuesBefore = System.currentTimeMillis();
readJsonValues(jsonRecord, ns, nrOfFields);
jsonReadValues += (System.currentTimeMillis() - jsonReadValuesBefore);
}
long jsonTotal = jsonBuild + jsonCreate + jsonRead + jsonReadValues;
long jsonAvg = jsonTotal / nrOfRecords;
System.out.println("JSON: total: " + jsonTotal + " avg: " + jsonAvg + " build: " + jsonBuild + " create: " + jsonCreate + " read: " + jsonRead + " readValues: " + jsonReadValues);
}
private void runSequential() throws Exception {
runJson();
runRvt();
}
private Record buildRvtRecord(String ns, int nrOfFields) throws Exception {
RecordBuilder rvtRecordBuilder = repository.recordBuilder().defaultNamespace(ns);
for (int i = 0; i < nrOfFields; i++) {
rvtRecordBuilder.field("stringField"+i, "value"+i);
}
return repository.recordBuilder().defaultNamespace(ns).recordType("rvtFieldRT").field("rvtField", rvtRecordBuilder.build()).build();
}
private Record buildJsonRecord(String ns, int nrOfFields) throws Exception {
ObjectNode node = JsonNodeFactory.instance.objectNode();
for (int i = 0; i < nrOfFields; i++) {
node.put("stringField"+i, "value"+i);
}
return repository.recordBuilder().defaultNamespace(ns).recordType("jsonFieldRT").field("jsonField", node.toString()).build();
}
private void readRvtValues(Record record, String ns, int nrOfFields) {
Record rvtRecord = record.getField(new QName(ns, "rvtField"));
for (int i = 0; i < nrOfFields; i++) {
rvtRecord.getField(new QName(ns, "stringField"+i));
}
}
private void readJsonValues(Record record, String ns, int nrOfFields) throws Exception {
String jsonString = record.getField(new QName(ns, "jsonField"));
JsonNode jsonNode = mappingJsonFactory.createJsonParser(jsonString).readValueAsTree();
for (int i = 0; i < nrOfFields; i++) {
JsonUtil.getString(jsonNode, "stringField"+i);
}
}
}