Package org.radargun.stages.cache

Source Code of org.radargun.stages.cache.WriteSkewCheckStage$Counters

package org.radargun.stages.cache;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

import org.radargun.DistStageAck;
import org.radargun.StageResult;
import org.radargun.config.Property;
import org.radargun.config.Stage;
import org.radargun.state.SlaveState;
import org.radargun.traits.BasicOperations;
import org.radargun.traits.InjectTrait;
import org.radargun.traits.Transactional;
import org.radargun.utils.Projections;
import org.radargun.utils.TimeConverter;

/**
* Stage checking the write skew detection in transactional caches.
*
* @author Radim Vansa <rvansa@redhat.com>
*/
@Stage(doc = "Stage checking the write skew detection in transactional caches.")
public class WriteSkewCheckStage extends CheckStage {
   private static final String WRITE_SKEW_CHECK_KEY = "writeSkewCheckKey";

   @Property(converter = TimeConverter.class, doc = "Duration of the test. Default is 1 minute.")
   private long duration = 60000;

   @Property(doc = "Number of threads overwriting concurrently the entry. Default is 10.")
   private int threads = 10;

   @Property(doc = "Should write skew between null value and first value be tested? Default is false.")
   private boolean testNull = false;

   private volatile boolean finished = false;
   private AtomicLong totalCounter = new AtomicLong(0);
   private AtomicLong skewCounter = new AtomicLong(0);

   @InjectTrait
   private BasicOperations basicOperations;

   @InjectTrait
   private Transactional transactional;

   @Override
   public DistStageAck executeOnSlave() {
      BasicOperations.Cache cache = basicOperations.getCache(null);
      if (!testNull) {
         try {
            cache.put(WRITE_SKEW_CHECK_KEY, new Long(0));
         } catch (Exception e) {
            return errorResponse("Failed to insert initial zero", e);
         }
         try {
            Thread.sleep(30000);
         } catch (InterruptedException e) {
            log.warn("Sleep was interrupted");
         }
      }

      List<ClientThread> threadList = new ArrayList<ClientThread>();
      for (int i = 0; i < threads; ++i) {
         ClientThread t = new WriteSkewThread();
         t.start();
         threadList.add(t);
      }
      try {
         Thread.sleep(duration);
      } catch (InterruptedException e) {
         log.warn("Sleep was interrupted");
      }
      finished = true;
      DistStageAck error = checkThreads(threadList);
      if (error != null) return error;
      try {
         Thread.sleep(30000);
      } catch (InterruptedException e) {
         log.warn("Sleep was interrupted");
      }

      long ispnCounter;
      try {
         Object value = cache.get(WRITE_SKEW_CHECK_KEY);
         if (!(value instanceof Long)) {
            return errorResponse("Counter is not a long: it is " + value);
         } else {
            ispnCounter = (Long) value;
         }
      } catch (Exception e) {
         return errorResponse("Failed to insert first value", e);
      }
      return new Counters(slaveState, totalCounter.get(), skewCounter.get(), ispnCounter);
   }

   @Override
   public StageResult processAckOnMaster(List<DistStageAck> acks) {
      StageResult result = super.processAckOnMaster(acks);
      if (result.isError()) return result;

      long sumIncrements = 0;
      long sumSkews = 0;
      long maxValue = -1;
      for (Counters ack : Projections.instancesOf(acks, Counters.class)) {
         sumIncrements += ack.totalCounter;
         sumSkews += ack.skewCounter;
         maxValue = Math.max(maxValue, ack.ispnCounter);
      }
      log.infof("Total increments: %d, Skews: %d, DB value: %d", sumIncrements, sumSkews, maxValue);
      if (maxValue + sumSkews != sumIncrements) {
         log.errorf("Database contains value %d but slaves report %d successful increments",
               maxValue, sumIncrements - sumSkews);
         return errorResult();
      } else {
         log.infof("Performed %d successful increments in %d ms", sumIncrements - sumSkews, duration);
         return StageResult.SUCCESS;
      }
   }

   private static class Counters extends DistStageAck {
      long totalCounter;
      long skewCounter;
      long ispnCounter;

      private Counters(SlaveState slaveState, long totalCounter, long skewCounter, long ispnCounter) {
         super(slaveState);
         this.totalCounter = totalCounter;
         this.skewCounter = skewCounter;
         this.ispnCounter = ispnCounter;
      }

      @Override
      public String toString() {
         return "Counters{" +
               "totalCounter=" + totalCounter +
               ", skewCounter=" + skewCounter +
               ", ispnCounter=" + ispnCounter +
               "} " + super.toString();
      }
   }

   private class WriteSkewThread extends ClientThread {
      @Override
      public void run() {
         BasicOperations.Cache nonTxCache = basicOperations.getCache(null);
         while (!finished) {
            Transactional.Transaction tx = transactional.getTransaction();
            BasicOperations.Cache txCache = tx.wrap(nonTxCache);
            log.trace("Starting transaction");
            tx.begin();
            Object value = null;
            try {
               value = txCache.get(WRITE_SKEW_CHECK_KEY);
               if (value == null) {
                  value = new Long(0);
               } else if (!(value instanceof Long)) {
                  exception = new IllegalStateException("Counter is not a long: it is " + value);
                  return;
               }
               txCache.put(WRITE_SKEW_CHECK_KEY, ((Long) value) + 1);
            } catch (Exception e) {
               exception = e;
               return;
            }
            boolean skew = false;
            try {
               tx.commit();
            } catch (Exception e) {
               log.trace("Skew detected");
               skewCounter.incrementAndGet();
               skew = true;
            }
            if (!skew && ((Long) value).longValue() == 0l) {
               log.trace("Successfully inserted 1");
            }
            totalCounter.incrementAndGet();
            log.trace("Ended transaction");
         }
      }
   }
}
TOP

Related Classes of org.radargun.stages.cache.WriteSkewCheckStage$Counters

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.