public static AccessDistribution loadAccessDistribution(
      Properties props, long minid, long maxid, DistributionType kind) throws LinkBenchConfigError {
    Logger logger = Logger.getLogger(ConfigUtil.LINKBENCH_LOGGER);
    String keyPrefix;
    switch (kind) {
      case LINK_READS:
        keyPrefix = LinkBenchConstants.READ_CONFIG_PREFIX;
        break;
      case LINK_READS_UNCORR:
        keyPrefix = LinkBenchConstants.READ_UNCORR_CONFIG_PREFIX;
        break;
      case LINK_WRITES:
        keyPrefix = LinkBenchConstants.WRITE_CONFIG_PREFIX;
        break;
      case LINK_WRITES_UNCORR:
        keyPrefix = LinkBenchConstants.WRITE_UNCORR_CONFIG_PREFIX;
        break;
      case NODE_READS:
        keyPrefix = LinkBenchConstants.NODE_READ_CONFIG_PREFIX;
        break;
      case NODE_UPDATES:
        keyPrefix = LinkBenchConstants.NODE_UPDATE_CONFIG_PREFIX;
        break;
      case NODE_DELETES:
        keyPrefix = LinkBenchConstants.NODE_DELETE_CONFIG_PREFIX;
        break;
      default:
        throw new RuntimeException("Bad kind " + kind);
    }

    String func_key = keyPrefix + LinkBenchConstants.ACCESS_FUNCTION_SUFFIX;
    String access_func = ConfigUtil.getPropertyRequired(props, func_key);

    try {
      AccessDistMode mode = AccessDistMode.valueOf(access_func.toUpperCase());

      if (mode == AccessDistMode.REAL) {
        RealDistribution realDist = new RealDistribution();
        realDist.init(props, minid, maxid, kind);
        InvertibleShuffler shuffler = RealDistribution.getShuffler(kind, maxid - minid);
        logger.debug("Using real access distribution" + " for " + kind.toString().toLowerCase());
        return new ProbAccessDistribution(realDist, shuffler);
      } else {
        String config_key = keyPrefix + LinkBenchConstants.ACCESS_CONFIG_SUFFIX;
        long config_val = ConfigUtil.getLong(props, config_key);
        logger.debug(
            "Using built-in access distribution "
                + mode
                + " with config param "
                + config_val
                + " for "
                + kind.toString().toLowerCase());
        return new BuiltinAccessDistribution(mode, minid, maxid, config_val);
      }
    } catch (IllegalArgumentException e) {
      return tryDynamicLoad(access_func, props, keyPrefix, minid, maxid, kind);
    }
  }
 /**
  * @param className ProbabilityDistribution class name
  * @param props
  * @param keyPrefix prefix to use for looking up keys in props
  * @param minid
  * @param maxid
  * @return
  */
 private static AccessDistribution tryDynamicLoad(
     String className,
     Properties props,
     String keyPrefix,
     long minid,
     long maxid,
     DistributionType kind) {
   try {
     Logger logger = Logger.getLogger(ConfigUtil.LINKBENCH_LOGGER);
     logger.debug(
         "Using ProbabilityDistribution class "
             + className
             + " for "
             + kind.toString().toLowerCase());
     ProbabilityDistribution pDist =
         ClassUtil.newInstance(className, ProbabilityDistribution.class);
     pDist.init(minid, maxid, props, keyPrefix);
     InvertibleShuffler shuffler = RealDistribution.getShuffler(kind, maxid - minid);
     return new ProbAccessDistribution(pDist, shuffler);
   } catch (ClassNotFoundException e) {
     throw new LinkBenchConfigError(
         "Access distribution class " + className + " not successfully loaded: " + e.getMessage());
   }
 }