package org.jgroups.tests; import org.jgroups.util.Table; import org.jgroups.util.Util; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; /** * Test which uses 1 or more adder threads to add numbers to a table, and 1 remover thread to remove all of them. Test * concurrency: when all threads are done, exactly N numbers have to have been added and the remover needs to * ensure that it gets the numbers in the correct sequence, that there are no gaps and every number has been * received only once. */ public class TableStressTest { static int NUM_THREADS=10; static int NUM=1000000; static final AtomicInteger added=new AtomicInteger(0); static final AtomicInteger removed=new AtomicInteger(0); public static void main(String[] args) throws InterruptedException { for(int i=0; i < args.length; i++) { if(args[i].startsWith("-h")) { System.out.println("TableStressTest [-num numbers] [-adders <number of adder threads>]"); return; } if(args[i].equals("-num")) { NUM=Integer.parseInt(args[++i]); continue; } if(args[i].equals("-adders")) { NUM_THREADS=Integer.parseInt(args[++i]); } } Table<Integer> buf=new Table<Integer>(10000, 10000, 0); final CountDownLatch latch=new CountDownLatch(1); Remover remover=new Remover(buf,latch); remover.start(); Adder[] adders=new Adder[NUM_THREADS]; for(int i=0; i < adders.length; i++) { adders[i]=new Adder(buf,latch, added); adders[i].start(); } long start=System.currentTimeMillis(); latch.countDown(); while(remover.isAlive()) { System.out.println("added messages: " + added + ", removed messages: " + removed); remover.join(2000); } long diff=System.currentTimeMillis() - start; System.out.println("added messages: " + added + ", removed messages: " + removed); System.out.println("took " + diff + " ms to insert and remove " + NUM + " messages"); } protected static class Adder extends Thread { protected final Table<Integer> buf; protected final AtomicInteger num; protected final CountDownLatch latch; public Adder(Table<Integer> buf, CountDownLatch latch, AtomicInteger num) { this.buf=buf; this.num=num; this.latch=latch; setName("Adder"); } public void run() { try { latch.await(); } catch(InterruptedException e) { e.printStackTrace(); } while(true) { int seqno=num.incrementAndGet(); if(seqno > NUM) { num.decrementAndGet(); break; } buf.add(seqno, seqno); } } } protected static class Remover extends Thread { protected final Table<Integer> buf; protected final CountDownLatch latch; public Remover(Table<Integer> buf, CountDownLatch latch) { this.buf=buf; this.latch=latch; setName("Remover"); } public void run() { try { latch.await(); } catch(InterruptedException e) { e.printStackTrace(); } int cnt=0; int expected=1, unexpected=0; for(;;) { List<Integer> nums=buf.removeMany(true, 100); if(nums != null) { for(Integer num: nums) { cnt++; removed.incrementAndGet(); if(num.intValue() != expected) { unexpected++; System.err.println("***** expected " + expected + ", but got " + num); } expected++; } continue; } if(cnt >= NUM) break; Util.sleep(500); } System.out.println("-- removed " + cnt + " numbers"); if(unexpected > 0) System.err.println("****** got " + unexpected + " numbers ! *******"); } } }