/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
package org.apache.usergrid.count;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.usergrid.ExperimentalTest;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.usergrid.count.common.Count;
import static org.junit.Assert.assertEquals;
/** @author zznate */
@net.jcip.annotations.NotThreadSafe
public class BatchCountParallelismTest {
private static final Logger logger = LoggerFactory.getLogger( BatchCountParallelismTest.class );
private ExecutorService exec = Executors.newFixedThreadPool( 24 );
private SimpleBatcher batcher;
private StubSubmitter submitter = new StubSubmitter();
private AtomicLong submits;
@Before
public void setupLocal() {
submits = new AtomicLong();
batcher = new SimpleBatcher();
batcher.setBatchSize( 10 );
batcher.setBatchSubmitter( submitter );
}
@Test
@Category(ExperimentalTest.class)
// "This test causes the build to hang when all stack tests are run"
public void verifyConcurrentAdd() throws Exception {
final long startCount = batcher.invocationCounter.count();
List<Future<Boolean>> calls = new ArrayList<Future<Boolean>>();
// create 10 tasks
// submit should be invoked 10 times
final CountDownLatch cdl = new CountDownLatch( 10 );
for ( int x = 0; x < 10; x++ ) {
final int c = x;
// each task should increment the counter 10 times
calls.add( exec.submit( new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
// should increment this counter to 10 for this thread, 100 overall
// this is invoked 10 times
for ( int y = 0; y < 10; y++ ) {
Count count = new Count( "Counter", "k1", "counter1", 1 );
batcher.add( count );
}
logger.info( "Task iteration # {} : ", c );
cdl.countDown();
return true;
}
} ) );
}
batcher.add( new Count( "Counter", "k1", "counter1", 1 ) );
logger.info( "size: " + calls.size() );
cdl.await();
// exec.awaitTermination(2,TimeUnit.SECONDS);
exec.shutdown();
while (! exec.awaitTermination( 3, TimeUnit.SECONDS ) ) {
logger.warn("jobs not yet finished, wait again");
}
// we should have 100 total invocations of AbstractBatcher#add
final long currentCount = batcher.invocationCounter.count();
final long delta = currentCount - startCount;
assertEquals( 101, delta );
// we should have submitted 10 batches
// jobs can finished executed, but the batcher may not have flush and so the batchSubmissionCount may not reach the total submitted yet"
//TODO beautify the following hack?
int iteration =0 ;
int total_retry = 10;
while (batcher.getBatchSubmissionCount() != 10 || iteration < total_retry) {
Thread.sleep(3000L);
iteration++;
}
assertEquals( 10, batcher.getBatchSubmissionCount() );
// the first batch should have a size 10 TODO currently 11 though :(
}
class StubSubmitter implements BatchSubmitter {
AtomicLong counted = new AtomicLong();
AtomicLong submit = new AtomicLong();
@Override
public Future<?> submit( Collection<Count> counts ) {
logger.info( "submitted: " + counts.size() );
counted.addAndGet( counts.size() );
submit.incrementAndGet();
return null;
}
@Override
public void shutdown() {
//To change body of implemented methods use File | Settings | File Templates.
}
}
}