/** * Licensed to The Apereo Foundation under one or more contributor license * agreements. See the NOTICE file distributed with this work for additional * information regarding copyright ownership. * * * The Apereo Foundation licenses this file to you under the Educational * Community 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://opensource.org/licenses/ecl2.txt * * 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.opencastproject.kernel.http; import org.apache.commons.codec.digest.DigestUtils; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.InputStream; import java.net.URL; public class DigestPerformanceTest { private static final Logger logger = LoggerFactory.getLogger(DigestPerformanceTest.class); /** * Verifying that running an md5 on a classpath resource is quick enough to do on each request. With a mean of around * one millisecond to md5 a large javascript library, this seems like an acceptable cost to support ETags. Testing * concurrent md5 hashing is difficult since it seems to run so quickly, but 100 more-or-less concurrent threads still * seem to perform OK. * * @throws Exception */ @Test public void testSingleThreadedMd5Digest() throws Exception { URL url = getClass().getClassLoader().getResource("InfusionAll.js"); InputStream in = url.openStream(); Statistics stats = new Statistics(); long count = 100; for (int i = 0; i < count; i++) { long start = System.currentTimeMillis(); DigestUtils.md5Hex(in); long elapsed = (System.currentTimeMillis() - start); if (elapsed > stats.getMax()) stats.setMax(elapsed); if (elapsed < stats.getMin()) stats.setMin(elapsed); stats.setTotalElapsed(stats.getTotalElapsed() + elapsed); } logger.info("One thread running {} md5 hashes of InfusionAll.js took min {}ms, max {}ms, mean {}ms", new Long[] { count, stats.getMin(), stats.getMax(), (stats.getTotalElapsed() / count) }); } @Test public void testMultiThreadedMd5Digest() throws Exception { final Statistics stats = new Statistics(); long count = 100; for (int i = 0; i < count; i++) { new Thread(new Runnable() { public void run() { stats.addThread(); try { URL url = getClass().getClassLoader().getResource("InfusionAll.js"); InputStream in = url.openStream(); long start = System.currentTimeMillis(); DigestUtils.md5Hex(in); long elapsed = (System.currentTimeMillis() - start); if (elapsed > stats.getMax()) stats.setMax(elapsed); if (elapsed < stats.getMin()) stats.setMin(elapsed); stats.setTotalElapsed(stats.getTotalElapsed() + elapsed); } catch (Exception e) { throw new RuntimeException(e); } finally { stats.removeThread(); } } }).start(); } logger.info( "{} threads running ({} max concurrent) md5 hashes of InfusionAll.js took min {}ms, max {}ms, mean {}ms", new Long[] { count, stats.getMaxConcurrentThreads(), stats.getMin(), stats.getMax(), (stats.getTotalElapsed() / count) }); } } class Statistics { private long min = Long.MAX_VALUE; private long max = Long.MIN_VALUE; private long totalElapsed = 0; private long maxConcurrentThreads = 0; private long concurrentThreads = 0; long getMin() { return min; } long getMax() { return max; } long getTotalElapsed() { return totalElapsed; } void setMin(long min) { this.min = min; } void setMax(long max) { this.max = max; } void setTotalElapsed(long total) { this.totalElapsed = total; } long getMaxConcurrentThreads() { return maxConcurrentThreads; } void addThread() { this.concurrentThreads++; if (this.concurrentThreads > maxConcurrentThreads) maxConcurrentThreads = concurrentThreads; } void removeThread() { this.concurrentThreads--; } }