/*
*
* * Copyright 2014 Orient Technologies LTD (info(at)orientechnologies.com)
* *
* * 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.
* *
* * For more information: http://www.orientechnologies.com
*
*/
package com.orientechnologies.orient.stresstest;
import com.orientechnologies.common.io.OIOUtils;
import com.orientechnologies.common.log.OLogManager;
import com.orientechnologies.orient.client.remote.OStorageRemote;
import com.orientechnologies.orient.core.OConstants;
import com.orientechnologies.orient.core.db.ODatabase;
import com.orientechnologies.orient.core.sql.OCommandSQL;
import com.orientechnologies.orient.stresstest.workload.OCheckWorkload;
import com.orientechnologies.orient.stresstest.workload.OWorkload;
import com.orientechnologies.orient.stresstest.workload.OWorkloadFactory;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* The main class of the OStressTester. It is instantiated from the OStressTesterCommandLineParser and takes care of launching the
* needed threads (OOperationsExecutor) for executing the operations of the test.
*
* @author Andrea Iacono
*/
public class OStressTester {
/**
* The access mode to the database
*/
public enum OMode {
PLOCAL, MEMORY, REMOTE, DISTRIBUTED
}
private final ODatabaseIdentifier databaseIdentifier;
private OConsoleProgressWriter consoleProgressWriter;
private final OStressTesterSettings settings;
private static final OWorkloadFactory workloadFactory = new OWorkloadFactory();
private List<OWorkload> workloads = new ArrayList<OWorkload>();
public OStressTester(final List<OWorkload> workloads, ODatabaseIdentifier databaseIdentifier,
final OStressTesterSettings settings) throws Exception {
this.workloads = workloads;
this.databaseIdentifier = databaseIdentifier;
this.settings = settings;
}
public static void main(String[] args) {
System.out.println(String.format("OrientDB Stress Tool v.%s - %s", OConstants.getVersion(), OConstants.COPYRIGHT));
int returnValue = 1;
try {
final OStressTester stressTester = OStressTesterCommandLineParser.getStressTester(args);
returnValue = stressTester.execute();
} catch (Exception ex) {
System.err.println(ex.getMessage());
}
System.exit(returnValue);
}
@SuppressWarnings("unchecked")
public int execute() throws Exception {
int returnCode = 0;
// we don't want logs from DB
OLogManager.instance().setConsoleLevel("SEVERE");
// creates the temporary DB where to execute the test
ODatabaseUtils.createDatabase(databaseIdentifier);
System.out.println(String.format("Created database [%s].", databaseIdentifier.getUrl()));
try {
for (OWorkload workload : workloads) {
consoleProgressWriter = new OConsoleProgressWriter(workload);
consoleProgressWriter.start();
consoleProgressWriter.printMessage(
String.format("\nStarting workload %s (concurrencyLevel=%d)...", workload.getName(), settings.concurrencyLevel));
final long startTime = System.currentTimeMillis();
workload.execute(settings, databaseIdentifier);
final long endTime = System.currentTimeMillis();
consoleProgressWriter.sendShutdown();
System.out.println(String.format("\n- Total execution time: %.3f secs", ((float) (endTime - startTime) / 1000f)));
System.out.println(workload.getFinalResult());
dumpHaMetrics();
if (settings.checkDatabase && workload instanceof OCheckWorkload) {
System.out.println(String.format("- Checking database..."));
((OCheckWorkload) workload).check(databaseIdentifier);
System.out.println(String.format("- Check completed"));
}
}
if (settings.resultOutputFile != null)
writeFile();
} catch (Exception ex) {
System.err.println("\nAn error has occurred while running the stress test: " + ex.getMessage());
returnCode = 1;
} finally {
// we don't need to drop the in-memory DB
if (settings.keepDatabaseAfterTest || databaseIdentifier.getMode() == OMode.MEMORY)
consoleProgressWriter.printMessage(String.format("\nDatabase is available on [%s].", databaseIdentifier.getUrl()));
else {
ODatabaseUtils.dropDatabase(databaseIdentifier);
consoleProgressWriter.printMessage(String.format("\nDropped database [%s].", databaseIdentifier.getUrl()));
}
}
return returnCode;
}
private void dumpHaMetrics() {
if (settings.haMetrics) {
final ODatabase db = ODatabaseUtils.openDatabase(databaseIdentifier, OStorageRemote.CONNECTION_STRATEGY.STICKY);
try {
final String output = db.command(new OCommandSQL("ha status -latency -messages -output=text")).execute();
System.out.println("HA METRICS");
System.out.println(output);
} catch (Exception e) {
// IGNORE IT
} finally {
db.close();
}
}
}
private void writeFile() {
try {
final StringBuilder output = new StringBuilder();
output.append("{\"result\":[");
int i = 0;
for (OWorkload workload : workloads) {
if (i++ > 0)
output.append(",");
output.append(workload.getFinalResultAsJson());
}
output.append("]}");
OIOUtils.writeFile(new File(settings.resultOutputFile), output.toString());
} catch (IOException e) {
System.err.println("\nError on writing the result file : " + e.getMessage());
}
}
public int getThreadsNumber() {
return settings.concurrencyLevel;
}
public OMode getMode() {
return databaseIdentifier.getMode();
}
public ODatabaseIdentifier getDatabaseIdentifier() {
return databaseIdentifier;
}
public String getPassword() {
return databaseIdentifier.getPassword();
}
public int getTransactionsNumber() {
return settings.operationsPerTransaction;
}
public static OWorkloadFactory getWorkloadFactory() {
return workloadFactory;
}
}