/** * Helios, OpenSource Monitoring * Brought to you by the Helios Development Group * * Copyright 2007, Helios Development Group and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. * */ package org.helios.apmrouter.server.tracing; import java.util.Date; import java.util.Random; import java.util.concurrent.DelayQueue; import java.util.concurrent.Delayed; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; /** * <p>Title: RefreshingExpiryTest</p> * <p>Description: Approach test for a refreshing expiry queue</p> * <p>Company: Helios Development Group LLC</p> * @author Whitehead (nwhitehead AT heliosdev DOT org) * <p><code>org.helios.apmrouter.server.tracing.RefreshingExpiryTest</code></p> */ @SuppressWarnings("javadoc") public class RefreshingExpiryTest { protected static final DelayQueue<Expirer> queue = new DelayQueue<Expirer>(); public static void main(String[] args) { log("RefreshingExpiryTest"); Random random = new Random(System.currentTimeMillis()); for(int i = 0; i < 100; i++) { queue.add(new Expirer(Math.abs(random.nextInt(10000)+3000), "Ex{" + i + "}")); } // queue.add(new Expirer(5000, "Five")); // queue.add(new Expirer(10000, "Ten")); new Thread("ExpiryThread") { int cnt = 0; public void run() { while(queue.size()>0) { try { Expirer ex = queue.take(); cnt++; ex.expire(); log("Queue Removed --->" + ex + "\t\tExpired Count:" + cnt); } catch (InterruptedException e) { e.printStackTrace(); Thread.interrupted(); } } } }.start(); for(int i = 0; i < 10000000; i++) { try { Thread.currentThread().join(Math.abs(random.nextInt(1000))); } catch (Exception ex) {} int queueSize = queue.size(); if(queueSize==0) break; log("Queue Size:" + queue.size()); for(Expirer ex: queue) { ex.touch(); } } } public static void log(Object msg) { System.out.println("[" + Thread.currentThread().getName() + "]:" + msg); } protected static class Expirer implements Delayed { private static final AtomicLong serial = new AtomicLong(); protected final long timeout; protected final long id; protected final long initTime = System.currentTimeMillis(); protected final AtomicLong lastTouch = new AtomicLong(initTime); protected final String name; protected boolean expired = false; public Expirer(long timeout, String name) { super(); this.timeout = timeout; this.name = name; id = serial.incrementAndGet(); } public void touch() { if(expired) throw new IllegalStateException("This expirer is already expired", new Throwable()); lastTouch.set(System.currentTimeMillis()); log("Touched [" + name + "]. New delay:" + getDelay(TimeUnit.MILLISECONDS) + " ms."); } protected void expire() { expired = true; } @Override public int compareTo(Delayed otherDelayed) { long myDelay = getTimeToExpiry(); long hisDelay = otherDelayed.getDelay(TimeUnit.MILLISECONDS); if(myDelay > hisDelay) return 1; if(myDelay < hisDelay) return -1; if(otherDelayed instanceof Expirer) { return ((Expirer)otherDelayed).id > id ? 1 : -1; } return 0; } @Override public long getDelay(TimeUnit unit) { return unit.convert(getTimeToExpiry(), TimeUnit.MILLISECONDS); } public long getTimeToExpiry() { long d = System.currentTimeMillis()-lastTouch.get(); return timeout - d; } /** * {@inheritDoc} * @see java.lang.Object#toString() */ @Override public String toString() { if(!expired) { return String.format( "Expirer [name:%s, id:%s, lastTouch:%s, timeout:%s ms., time-to-expiry:%s ms. ]", name, id, new Date(lastTouch.get()), timeout, getTimeToExpiry()); } return String.format("EXPIRED Expirer [name:%s, id:%s, timeout:%s ms., live-time:%s s.]", name, id, timeout, TimeUnit.SECONDS.convert(System.currentTimeMillis()-initTime, TimeUnit.MILLISECONDS)); } /** * {@inheritDoc} * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (int) (id ^ (id >>> 32)); return result; } /** * {@inheritDoc} * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Expirer other = (Expirer) obj; if (id != other.id) return false; return true; } } }