public static void main(String args[]) {
    FileWriter writer = null;
    try {
      OptionParser parser = new OptionParser();
      ArgumentAcceptingOptionSpec<Integer> numberOfIndexesOpt =
          parser.accepts("numberOfIndexes", "The number of indexes to create")
              .withRequiredArg()
              .describedAs("number_of_indexes")
              .ofType(Integer.class);

      ArgumentAcceptingOptionSpec<String> hardwareLayoutOpt =
          parser.accepts("hardwareLayout", "The path of the hardware layout file")
              .withRequiredArg()
              .describedAs("hardware_layout")
              .ofType(String.class);

      ArgumentAcceptingOptionSpec<String> partitionLayoutOpt =
          parser.accepts("partitionLayout", "The path of the partition layout file")
              .withRequiredArg()
              .describedAs("partition_layout")
              .ofType(String.class);

      ArgumentAcceptingOptionSpec<Integer> numberOfWritersOpt =
          parser.accepts("numberOfWriters", "The number of writers that write to a random index concurrently")
              .withRequiredArg()
              .describedAs("The number of writers")
              .ofType(Integer.class)
              .defaultsTo(4);

      ArgumentAcceptingOptionSpec<Integer> writesPerSecondOpt =
          parser.accepts("writesPerSecond", "The rate at which writes need to be performed")
              .withRequiredArg()
              .describedAs("The number of writes per second")
              .ofType(Integer.class)
              .defaultsTo(1000);

      ArgumentAcceptingOptionSpec<Boolean> verboseLoggingOpt =
          parser.accepts("enableVerboseLogging", "Enables verbose logging")
              .withOptionalArg()
              .describedAs("Enable verbose logging")
              .ofType(Boolean.class)
              .defaultsTo(false);

      OptionSet options = parser.parse(args);

      ArrayList<OptionSpec> listOpt = new ArrayList<>();
      listOpt.add(numberOfIndexesOpt);
      listOpt.add(hardwareLayoutOpt);
      listOpt.add(partitionLayoutOpt);

      ToolUtils.ensureOrExit(listOpt, options, parser);

      int numberOfIndexes = options.valueOf(numberOfIndexesOpt);
      int numberOfWriters = options.valueOf(numberOfWritersOpt);
      int writesPerSecond = options.valueOf(writesPerSecondOpt);
      boolean enableVerboseLogging = options.has(verboseLoggingOpt);
      if (enableVerboseLogging) {
        System.out.println("Enabled verbose logging");
      }
      final AtomicLong totalTimeTakenInNs = new AtomicLong(0);
      final AtomicLong totalWrites = new AtomicLong(0);
      String hardwareLayoutPath = options.valueOf(hardwareLayoutOpt);
      String partitionLayoutPath = options.valueOf(partitionLayoutOpt);

      ClusterMapConfig clusterMapConfig = new ClusterMapConfig(new VerifiableProperties(new Properties()));
      ClusterMap map =
          ((ClusterAgentsFactory) Utils.getObj(clusterMapConfig.clusterMapClusterAgentsFactory, clusterMapConfig,
              hardwareLayoutPath, partitionLayoutPath)).getClusterMap();
      StoreKeyFactory factory = new BlobIdFactory(map);

      File logFile = new File(System.getProperty("user.dir"), "writeperflog");
      writer = new FileWriter(logFile);

      MetricRegistry metricRegistry = new MetricRegistry();
      StoreMetrics metrics = new StoreMetrics(metricRegistry);
      DiskSpaceAllocator diskSpaceAllocator =
          new DiskSpaceAllocator(false, null, 0, new StorageManagerMetrics(metricRegistry));
      Properties props = new Properties();
      props.setProperty("store.index.memory.size.bytes", "2097152");
      props.setProperty("store.segment.size.in.bytes", "10");
      StoreConfig config = new StoreConfig(new VerifiableProperties(props));
      Log log = new Log(System.getProperty("user.dir"), 10, diskSpaceAllocator, config, metrics, null);

      ScheduledExecutorService s = Utils.newScheduler(numberOfWriters, "index", false);

      ArrayList<BlobIndexMetrics> indexWithMetrics = new ArrayList<BlobIndexMetrics>(numberOfIndexes);
      for (int i = 0; i < numberOfIndexes; i++) {
        File indexFile = new File(System.getProperty("user.dir"), Integer.toString(i));
        if (indexFile.exists()) {
          for (File c : indexFile.listFiles()) {
            c.delete();
          }
        } else {
          indexFile.mkdir();
        }
        System.out.println("Creating index folder " + indexFile.getAbsolutePath());
        writer.write("logdir-" + indexFile.getAbsolutePath() + "\n");
        indexWithMetrics.add(
            new BlobIndexMetrics(indexFile.getAbsolutePath(), s, log, enableVerboseLogging, totalWrites,
                totalTimeTakenInNs, totalWrites, config, writer, factory));
      }

      final CountDownLatch latch = new CountDownLatch(numberOfWriters);
      final AtomicBoolean shutdown = new AtomicBoolean(false);
      // attach shutdown handler to catch control-c
      Runtime.getRuntime().addShutdownHook(new Thread() {
        public void run() {
          try {
            System.out.println("Shutdown invoked");
            shutdown.set(true);
            latch.await();
            System.out.println(
                "Total writes : " + totalWrites.get() + "  Total time taken : " + totalTimeTakenInNs.get()
                    + " Nano Seconds  Average time taken per write "
                    + ((double) totalWrites.get() / totalTimeTakenInNs.get()) / SystemTime.NsPerSec + " Seconds");
          } catch (Exception e) {
            System.out.println("Error while shutting down " + e);
          }
        }
      });

      Throttler throttler = new Throttler(writesPerSecond, 100, true, SystemTime.getInstance());
      Thread[] threadIndexPerf = new Thread[numberOfWriters];
      for (int i = 0; i < numberOfWriters; i++) {
        threadIndexPerf[i] = new Thread(new IndexWritePerfRun(indexWithMetrics, throttler, shutdown, latch, map));
        threadIndexPerf[i].start();
      }
      for (int i = 0; i < numberOfWriters; i++) {
        threadIndexPerf[i].join();
      }
    } catch (StoreException e) {
      System.err.println("Index creation error on exit " + e.getMessage());
    } catch (Exception e) {
      System.err.println("Error on exit " + e);
    } finally {
      if (writer != null) {
        try {
          writer.close();
        } catch (Exception e) {
          System.out.println("Error when closing the writer");
        }
      }
    }
  }
Tests the memory boundaries and latencies of the index structure
during writes
ambry-tools/src/main/java/com/github/ambry/store/IndexWritePerformance.java