@Override
 public void init(Stressor stressor) {
   this.numNodes = stressor.getNumNodes();
   keysLoaded.compareAndSet(0, stressor.getNodeIndex());
   double averageSize = 0;
   Map<Integer, Double> probabilityMap = stage.entrySize.getProbabilityMap();
   long entries;
   if (stage.numBytes > 0) {
     for (Map.Entry<Integer, Double> entry : probabilityMap.entrySet()) {
       averageSize += entry.getValue() * entry.getKey();
     }
     entries = (long) (stage.numBytes / averageSize);
   } else {
     entries = stage.numEntries;
   }
   long expectedMax = 0;
   for (Map.Entry<Integer, Double> entry : probabilityMap.entrySet()) {
     long valuesForSize = (long) (entries * entry.getValue());
     expectedMax += valuesForSize * entry.getKey();
     loadForSize.put(entry.getKey(), new Load(valuesForSize));
   }
   log.info("Expecting maximal load of " + new SizeConverter().convertToString(expectedMax));
 }
 @Override
 public Object run(Stressor stressor) throws RequestException {
   Random r = ThreadLocalRandom.current();
   KeyWithRemovalTime pair;
   long timestamp = System.currentTimeMillis();
   if (minRemoveTimestamp <= timestamp) {
     Load load = loadForSize.get(minRemoveSize);
     pair = load.scheduledKeys.pollFirst();
     Boolean value;
     try {
       value = (Boolean) stressor.makeRequest(BasicOperations.REMOVE, pair.key);
     } catch (RequestException e) {
       load.scheduledKeys.add(pair);
       return null;
     }
     updateMin();
     if (!value && !stage.expectLostKeys) {
       log.error("REMOVE: Entry for key " + pair.key + " was not found!");
     }
     return value;
   } else if (r.nextInt(100) >= stage.writePercentage && minRemoveTimestamp < Long.MAX_VALUE) {
     // we cannot get random access to PriorityQueue and there is no SortedList or another
     // appropriate structure
     Load load = null;
     for (int attempt = 0; attempt < 100; ++attempt) {
       load = loadForSize.get(stage.entrySize.next(r));
       if (!load.scheduledKeys.isEmpty()) break;
     }
     if (load.scheduledKeys.isEmpty()) {
       log.error("Current load seems to be null but timestamp is " + minRemoveTimestamp);
       return null;
     }
     pair = getRandomPair(load.scheduledKeys, timestamp, r);
     Object value = stressor.makeRequest(BasicOperations.GET, pair.key);
     if (value == null) {
       if (stage.expectLostKeys) {
         load.scheduledKeys.remove(pair);
         updateMin();
       } else {
         log.error("GET: Value for key " + pair.key + " is null!");
       }
     }
     return value;
   } else {
     Object value = stage.generateValue(null, Integer.MAX_VALUE, stressor.getRandom());
     int size = stage.getValueGenerator().sizeOf(value);
     Load load = loadForSize.get(size);
     if (load.scheduledKeys.size() < load.max) {
       long keyIndex = keysLoaded.getAndAdd(numNodes);
       pair =
           new KeyWithRemovalTime(
               stage.getKeyGenerator().generateKey(keyIndex), getRandomTimestamp(timestamp, r));
       load.scheduledKeys.add(pair);
       updateMin();
     } else {
       pair = getRandomPair(load.scheduledKeys, timestamp, r);
     }
     try {
       return stressor.makeRequest(BasicOperations.PUT, pair.key, value);
     } catch (RequestException e) {
       load.scheduledKeys.remove(pair);
       for (; ; ) {
         try {
           return stressor.makeRequest(BasicOperations.REMOVE, pair.key);
         } catch (RequestException e1) {
         }
       }
     }
   }
 }