package com.openkm.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Calendar;
import java.util.InputMismatchException;
import javax.jcr.Node;
import javax.jcr.PropertyType;
import javax.jcr.Session;
import org.apache.jackrabbit.JcrConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.openkm.bean.Document;
import com.openkm.bean.Folder;
import com.openkm.bean.Permission;
import com.openkm.bean.Property;
import com.openkm.core.AccessDeniedException;
import com.openkm.core.Config;
import com.openkm.core.DatabaseException;
import com.openkm.core.FileSizeExceededException;
import com.openkm.core.ItemExistsException;
import com.openkm.core.PathNotFoundException;
import com.openkm.core.RepositoryException;
import com.openkm.core.UnsupportedMimeTypeException;
import com.openkm.core.UserQuotaExceededException;
import com.openkm.core.VirusDetectedException;
import com.openkm.extension.core.ExtensionException;
import com.openkm.module.base.BaseDocumentModule;
import com.openkm.module.base.BaseFolderModule;
import com.openkm.module.direct.DirectDocumentModule;
import com.openkm.module.direct.DirectFolderModule;
import com.openkm.util.markov.Generator;
/**
* Default values generate text files with about 39 pages.
*
* @author pavila
*/
public class Benchmark {
private static Logger log = LoggerFactory.getLogger(Benchmark.class);
private static final String SEED = Config.HOME_DIR + File.separator + "benchmark.txt";
private static final int PARAGRAPH = 250;
private static final int LINE_WIDTH = 80;
private static final int TOTAL_CHARS = 500;
private static final int MAX_DOCUMENTS = 12;
private static final int MAX_FOLDERS = 4;
private static final int MAX_DEPTH = 3;
private Generator gen = null;
private int maxDocuments = 0;
private int maxFolders = 0;
private int maxDepth = 0;
private int totalFolders = 0;
private int totalDocuments = 0;
private long totalSize = 0;
private int row = 0;
/**
* Main method for testing purposes
*/
public static void main(String[] args) {
}
public Benchmark() throws IOException {
this.maxDocuments = MAX_DOCUMENTS;
this.maxFolders = MAX_FOLDERS;
this.maxDepth = MAX_DEPTH;
FileInputStream fis = new FileInputStream(SEED);
gen = new Generator(fis);
fis.close();
}
public Benchmark(int maxDocuments, int maxFolders, int maxDepth) throws IOException {
this.maxDocuments = maxDocuments;
this.maxFolders = maxFolders;
this.maxDepth = maxDepth;
FileInputStream fis = new FileInputStream(SEED);
gen = new Generator(fis);
fis.close();
}
public Benchmark(int maxDocuments, int maxFolders, int maxDepth, InputStream is) throws IOException {
this.maxDocuments = maxDocuments;
this.maxFolders = maxFolders;
this.maxDepth = maxDepth;
gen = new Generator(is);
}
public int getMaxDocuments() {
return maxDocuments;
}
public int getMaxFolders() {
return maxFolders;
}
public int getMaxDepth() {
return maxDepth;
}
public int getTotalFolders() {
return totalFolders;
}
public int getTotalDocuments() {
return totalDocuments;
}
public long getTotalSize() {
return totalSize;
}
/**
* Calculates the number of folder created
*/
public int calculateFolders() {
int nodesAtLevel = 1;
int total = 0;
for (int i=1; i<=maxDepth; i++) {
nodesAtLevel = nodesAtLevel * maxFolders;
total += nodesAtLevel;
}
return total;
}
/**
* Calculates the number of document created
*/
public int calculateDocuments() {
int nodesAtLevel = 1;
int total = 0;
for (int i=1; i<=maxDepth; i++) {
nodesAtLevel = nodesAtLevel * maxFolders;
total += nodesAtLevel;
}
return total * maxDocuments;
}
/**
* Run system calibration
* @throws IOException
* @throws InputMismatchException
*/
public long runCalibration() throws InputMismatchException, IOException {
final int ITERATIONS = 10;
long total = 0;
for (int i=0; i<ITERATIONS; i++) {
long calBegin = System.currentTimeMillis();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
gen.generateText(PARAGRAPH, LINE_WIDTH, TOTAL_CHARS, baos);
baos.close();
long calEnd = System.currentTimeMillis();
total = calEnd - calBegin;
}
log.debug("Calibration: {} ms", total / ITERATIONS);
return total / ITERATIONS;
}
/**
* Run OpenKM text document insertions (API)
*/
public void okmApiHighPopulate(String token, Folder root, PrintWriter out, PrintWriter res) throws IOException,
InputMismatchException, ItemExistsException, PathNotFoundException, UserQuotaExceededException,
AccessDeniedException, UnsupportedMimeTypeException, FileSizeExceededException,
VirusDetectedException, RepositoryException, DatabaseException, ExtensionException {
long begin = System.currentTimeMillis();
okmApiHighPopulateHelper(token, root, out, res, gen, 0);
long end = System.currentTimeMillis();
String elapse = FormatUtil.formatSeconds(end - begin);
log.debug("Total Time: {} - Folders: {}, Documents: {}", new Object[] { elapse, totalFolders, totalDocuments });
}
/**
* Helper
*/
private void okmApiHighPopulateHelper(String token, Folder root, PrintWriter out, PrintWriter res,
Generator gen, int depth) throws
InputMismatchException, IOException, ItemExistsException, PathNotFoundException,
UserQuotaExceededException, AccessDeniedException, UnsupportedMimeTypeException,
FileSizeExceededException, VirusDetectedException, RepositoryException, DatabaseException,
ExtensionException {
log.debug("okmApiHighPopulateHelper({}, {}, {}, {})", new Object[] { token, root, gen, depth });
if (depth < maxDepth) {
for (int i=0; i<maxFolders; i++) {
long begin = System.currentTimeMillis();
Folder fld = new Folder();
fld.setPath(root.getPath() + "/" + System.currentTimeMillis());
fld = new DirectFolderModule().create(token, fld);
totalFolders++;
log.debug("At depth {}, created folder {}", depth, fld.getPath());
for (int j=0; j<maxDocuments; j++) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
gen.generateText(PARAGRAPH, LINE_WIDTH, TOTAL_CHARS, baos);
baos.close();
totalSize += baos.size();
// Repository insertion
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
Document doc = new Document();
doc.setMimeType("text/plain");
doc.setPath(fld.getPath() + "/" + System.currentTimeMillis() + ".txt");
new DirectDocumentModule().create(token, doc, bais);
totalDocuments++;
}
long end = System.currentTimeMillis();
String elapse = FormatUtil.formatSeconds(end - begin);
log.debug("Partial Time: {} - Folders: {}, Documents: {}", new Object[] { elapse, totalFolders, totalDocuments });
out.print("<tr class=\""+(row++%2==0?"even":"odd")+"\">");
out.print("<td>"+FormatUtil.formatDate(Calendar.getInstance())+"</td>");
out.print("<td>"+elapse+"</td>");
out.print("<td>"+(end - begin)+"</td>");
out.print("<td>"+totalFolders+"</td>");
out.print("<td>"+totalDocuments+"</td>");
out.print("<td>"+FormatUtil.formatSize(totalSize)+"</td>");
out.println("</tr>");
out.flush();
res.print("\"" + FormatUtil.formatDate(Calendar.getInstance()) + "\",");
res.print("\"" + elapse + "\",");
res.print("\"" + (end - begin) + "\",");
res.print("\"" + totalFolders + "\",");
res.print("\"" + totalDocuments + "\",");
res.print("\"" + FormatUtil.formatSize(totalSize) + "\"\n");
res.flush();
// Go depth
okmApiHighPopulateHelper(token, fld, out, res, gen, depth+1);
}
} else {
log.debug("Max depth reached: {}", depth);
}
}
/**
* Run OpenKM text document insertions (API)
*/
public void okmApiLowPopulate(Session session, Node root, PrintWriter out, PrintWriter res) throws
javax.jcr.ItemExistsException, javax.jcr.PathNotFoundException,
javax.jcr.nodetype.NoSuchNodeTypeException, javax.jcr.lock.LockException,
javax.jcr.version.VersionException, javax.jcr.nodetype.ConstraintViolationException,
javax.jcr.RepositoryException, InputMismatchException, IOException, DatabaseException,
UserQuotaExceededException {
long begin = System.currentTimeMillis();
okmApiLowPopulateHelper(session, root, out, res, gen, 0);
long end = System.currentTimeMillis();
String elapse = FormatUtil.formatSeconds(end - begin);
log.debug("Total Time: {} - Folders: {}, Documents: {}", new Object[] { elapse, totalFolders, totalDocuments });
}
/**
* Helper
*/
private void okmApiLowPopulateHelper(Session session, Node root, PrintWriter out, PrintWriter res,
Generator gen, int depth) throws
javax.jcr.ItemExistsException, javax.jcr.PathNotFoundException,
javax.jcr.nodetype.NoSuchNodeTypeException, javax.jcr.lock.LockException,
javax.jcr.version.VersionException, javax.jcr.nodetype.ConstraintViolationException,
javax.jcr.RepositoryException, InputMismatchException, IOException, DatabaseException,
UserQuotaExceededException {
log.debug("okmApiLowPopulateHelper({}, {}, {}, {})", new Object[] { session, root, gen, depth });
if (depth < maxDepth) {
for (int i=0; i<maxFolders; i++) {
long begin = System.currentTimeMillis();
Node fld = BaseFolderModule.create(session, root, Long.toString(System.currentTimeMillis()));
totalFolders++;
log.debug("At depth {}, created folder {}", depth, fld.getPath());
for (int j=0; j<maxDocuments; j++) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
gen.generateText(PARAGRAPH, LINE_WIDTH, TOTAL_CHARS, baos);
baos.close();
totalSize += baos.size();
// Repository insertion
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
BaseDocumentModule.create(session, fld, System.currentTimeMillis() + ".txt",
null, "text/plain", new String[]{}, bais);
totalDocuments++;
}
long end = System.currentTimeMillis();
String elapse = FormatUtil.formatSeconds(end - begin);
log.debug("Partial Time: {} - Folders: {}, Documents: {}", new Object[] { elapse, totalFolders, totalDocuments });
out.print("<tr class=\""+(row++%2==0?"even":"odd")+"\">");
out.print("<td>"+FormatUtil.formatDate(Calendar.getInstance())+"</td>");
out.print("<td>"+elapse+"</td>");
out.print("<td>"+(end - begin)+"</td>");
out.print("<td>"+totalFolders+"</td>");
out.print("<td>"+totalDocuments+"</td>");
out.print("<td>"+FormatUtil.formatSize(totalSize)+"</td>");
out.println("</tr>");
out.flush();
res.print("\"" + FormatUtil.formatDate(Calendar.getInstance()) + "\",");
res.print("\"" + elapse + "\",");
res.print("\"" + (end - begin) + "\",");
res.print("\"" + totalFolders + "\",");
res.print("\"" + totalDocuments + "\",");
res.print("\"" + FormatUtil.formatSize(totalSize) + "\"\n");
res.flush();
// Go depth
okmApiLowPopulateHelper(session, fld, out, res, gen, depth+1);
}
} else {
log.debug("Max depth reached: {}", depth);
}
}
/**
* Run OpenKM text document insertions (RAW)
*/
public void okmRawPopulate(Session session, Node root, PrintWriter out, PrintWriter res) throws
javax.jcr.ItemExistsException, javax.jcr.PathNotFoundException,
javax.jcr.nodetype.NoSuchNodeTypeException, javax.jcr.lock.LockException,
javax.jcr.version.VersionException, javax.jcr.nodetype.ConstraintViolationException,
javax.jcr.RepositoryException, InputMismatchException, IOException {
long begin = System.currentTimeMillis();
okmRawPopulateHelper(session, root, out, res, gen, 0);
long end = System.currentTimeMillis();
String elapse = FormatUtil.formatSeconds(end - begin);
log.debug("Total Time: {} - Folders: {}, Documents: {}", new Object[] { elapse, totalFolders, totalDocuments });
}
/**
* Helper
*/
private void okmRawPopulateHelper(Session session, Node root, PrintWriter out, PrintWriter res,
Generator gen, int depth)
throws javax.jcr.ItemExistsException, javax.jcr.PathNotFoundException,
javax.jcr.nodetype.NoSuchNodeTypeException, javax.jcr.lock.LockException,
javax.jcr.version.VersionException, javax.jcr.nodetype.ConstraintViolationException,
javax.jcr.RepositoryException, InputMismatchException, IOException {
log.debug("okmRawPopulateHelper({}, {}, {}, {})", new Object[] { session, root, gen, depth });
if (depth < maxDepth) {
for (int i=0; i<maxFolders; i++) {
long begin = System.currentTimeMillis();
String fldName = Long.toString(System.currentTimeMillis());
Node fldNode = root.addNode(fldName, Folder.TYPE);
fldNode.setProperty(Folder.AUTHOR, session.getUserID());
fldNode.setProperty(Folder.NAME, fldName);
// Set auth info
fldNode.setProperty(Permission.USERS_READ, new String[] { session.getUserID() });
fldNode.setProperty(Permission.USERS_WRITE, new String[] { session.getUserID() });
fldNode.setProperty(Permission.USERS_DELETE, new String[] { session.getUserID() });
fldNode.setProperty(Permission.USERS_SECURITY, new String[] { session.getUserID() });
fldNode.setProperty(Permission.ROLES_READ, new String[] {});
fldNode.setProperty(Permission.ROLES_WRITE, new String[] {});
fldNode.setProperty(Permission.ROLES_DELETE, new String[] {});
fldNode.setProperty(Permission.ROLES_SECURITY, new String[] {});
root.save();
totalFolders++;
log.debug("At depth {}, created folder {}", depth, fldNode.getPath());
for (int j=0; j<maxDocuments; j++) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
gen.generateText(PARAGRAPH, LINE_WIDTH, TOTAL_CHARS, baos);
baos.close();
totalSize += baos.size();
// Repository insertion
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
String docName = System.currentTimeMillis() + ".txt";
Node docNode = fldNode.addNode(docName, Document.TYPE);
docNode.setProperty(Property.KEYWORDS, new String[] {});
docNode.setProperty(Property.CATEGORIES, new String[]{}, PropertyType.REFERENCE);
docNode.setProperty(Document.AUTHOR, session.getUserID());
docNode.setProperty(Document.NAME, docName);
// Set auth info
docNode.setProperty(Permission.USERS_READ, new String[] { session.getUserID() });
docNode.setProperty(Permission.USERS_WRITE, new String[] { session.getUserID() });
docNode.setProperty(Permission.USERS_DELETE, new String[] { session.getUserID() });
docNode.setProperty(Permission.USERS_SECURITY, new String[] { session.getUserID() });
docNode.setProperty(Permission.ROLES_READ, new String[] { session.getUserID() });
docNode.setProperty(Permission.ROLES_WRITE, new String[] { session.getUserID() });
docNode.setProperty(Permission.ROLES_DELETE, new String[] { session.getUserID() });
docNode.setProperty(Permission.ROLES_SECURITY, new String[] { session.getUserID() });
Node contNode = docNode.addNode(Document.CONTENT, Document.CONTENT_TYPE);
contNode.setProperty(Document.SIZE, bais.available());
contNode.setProperty(Document.AUTHOR, session.getUserID());
contNode.setProperty(Document.VERSION_COMMENT, "");
contNode.setProperty(JcrConstants.JCR_MIMETYPE, "text/plain");
contNode.setProperty(JcrConstants.JCR_ENCODING, "UTF-8");
contNode.setProperty(JcrConstants.JCR_DATA, bais);
contNode.setProperty(JcrConstants.JCR_LASTMODIFIED, Calendar.getInstance());
fldNode.save();
contNode.checkin();
totalDocuments++;
}
long end = System.currentTimeMillis();
String elapse = FormatUtil.formatSeconds(end - begin);
log.debug("Partial Time: {} - Folders: {}, Documents: {}", new Object[] { elapse, totalFolders, totalDocuments });
out.print("<tr class=\""+(row++%2==0?"even":"odd")+"\">");
out.print("<td>"+FormatUtil.formatDate(Calendar.getInstance())+"</td>");
out.print("<td>"+elapse+"</td>");
out.print("<td>"+(end - begin)+"</td>");
out.print("<td>"+totalFolders+"</td>");
out.print("<td>"+totalDocuments+"</td>");
out.print("<td>"+FormatUtil.formatSize(totalSize)+"</td>");
out.println("</tr>");
out.flush();
res.print("\"" + FormatUtil.formatDate(Calendar.getInstance()) + "\",");
res.print("\"" + elapse + "\",");
res.print("\"" + (end - begin) + "\",");
res.print("\"" + totalFolders + "\",");
res.print("\"" + totalDocuments + "\",");
res.print("\"" + FormatUtil.formatSize(totalSize) + "\"\n");
res.flush();
// Go depth
okmRawPopulateHelper(session, fldNode, out, res, gen, depth+1);
}
} else {
log.debug("Max depth reached: {}", depth);
}
}
/**
* Run JCR text document insertions
*/
public void jcrPopulate(Session session, Node root, PrintWriter out, PrintWriter res) throws IOException,
javax.jcr.ItemExistsException, javax.jcr.PathNotFoundException,
javax.jcr.nodetype.NoSuchNodeTypeException, javax.jcr.lock.LockException,
javax.jcr.version.VersionException, javax.jcr.nodetype.ConstraintViolationException,
javax.jcr.RepositoryException, InputMismatchException, IOException {
long begin = System.currentTimeMillis();
jcrPopulateHelper(session, root, out, res, gen, 0);
long end = System.currentTimeMillis();
String elapse = FormatUtil.formatSeconds(end - begin);
log.debug("Total Time: {} - Folders: {}, Documents: {}", new Object[] { elapse, totalFolders, totalDocuments });
}
/**
* Helper
*/
private void jcrPopulateHelper(Session session, Node root, PrintWriter out, PrintWriter res,
Generator gen, int depth) throws
javax.jcr.ItemExistsException, javax.jcr.PathNotFoundException,
javax.jcr.nodetype.NoSuchNodeTypeException, javax.jcr.lock.LockException,
javax.jcr.version.VersionException, javax.jcr.nodetype.ConstraintViolationException,
javax.jcr.RepositoryException, InputMismatchException, IOException {
log.debug("jcrPopulateHelper({}, {}, {}, {})", new Object[] { session, root, gen, depth });
if (depth < maxDepth) {
for (int i=0; i<maxFolders; i++) {
long begin = System.currentTimeMillis();
Node fldNode = root.addNode(Long.toString(System.currentTimeMillis()), JcrConstants.NT_FOLDER);
fldNode.addMixin(JcrConstants.MIX_REFERENCEABLE);
root.save();
totalFolders++;
log.debug("At depth {}, created folder {}", depth, fldNode.getPath());
for (int j=0; j<maxDocuments; j++) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
gen.generateText(PARAGRAPH, LINE_WIDTH, TOTAL_CHARS, baos);
baos.close();
totalSize += baos.size();
// Repository insertion
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
Node docNode = fldNode.addNode(System.currentTimeMillis() + ".txt", JcrConstants.NT_FILE);
docNode.addMixin(JcrConstants.MIX_REFERENCEABLE);
Node resNode = docNode.addNode(JcrConstants.JCR_CONTENT, JcrConstants.NT_RESOURCE);
resNode.setProperty(JcrConstants.JCR_MIMETYPE, "text/plain");
resNode.setProperty(JcrConstants.JCR_ENCODING, "UTF-8");
resNode.setProperty(JcrConstants.JCR_DATA, bais);
resNode.setProperty(JcrConstants.JCR_LASTMODIFIED, Calendar.getInstance());
fldNode.save();
totalDocuments++;
}
long end = System.currentTimeMillis();
String elapse = FormatUtil.formatSeconds(end - begin);
log.debug("Partial Time: {} - Folders: {}, Documents: {}", new Object[] { elapse, totalFolders, totalDocuments });
out.print("<tr class=\""+(row++%2==0?"even":"odd")+"\">");
out.print("<td>"+FormatUtil.formatDate(Calendar.getInstance())+"</td>");
out.print("<td>"+elapse+"</td>");
out.print("<td>"+(end - begin)+"</td>");
out.print("<td>"+totalFolders+"</td>");
out.print("<td>"+totalDocuments+"</td>");
out.print("<td>"+FormatUtil.formatSize(totalSize)+"</td>");
out.println("</tr>");
out.flush();
res.print("\"" + FormatUtil.formatDate(Calendar.getInstance()) + "\",");
res.print("\"" + elapse + "\",");
res.print("\"" + (end - begin) + "\",");
res.print("\"" + totalFolders + "\",");
res.print("\"" + totalDocuments + "\",");
res.print("\"" + FormatUtil.formatSize(totalSize) + "\"\n");
res.flush();
// Go depth
jcrPopulateHelper(session, fldNode, out, res, gen, depth+1);
}
} else {
log.debug("Max depth reached: {}", depth);
}
}
}