content: /*
   * The Alluxio Open Foundation licenses this work under the Apache License, version 2.0
   * (the "License"). You may not use this work except in compliance with the License, which is
   * available at www.apache.org/licenses/LICENSE-2.0
   *
   * This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
   * either express or implied, as more fully set forth in the License.
   *
   * See the NOTICE file distributed with this work for information regarding copyright ownership.
   */
  
  package alluxio.inode;
  
  import static alluxio.master.file.meta.InodeTreeTest.TEST_DIR_MODE;
  import static alluxio.master.file.meta.InodeTreeTest.TEST_GROUP;
  import static alluxio.master.file.meta.InodeTreeTest.TEST_OWNER;
  import static org.mockito.Mockito.mock;
  
  import alluxio.AlluxioTestDirectory;
  import alluxio.AlluxioURI;
  import alluxio.conf.Configuration;
  import alluxio.exception.BlockInfoException;
  import alluxio.exception.FileAlreadyExistsException;
  import alluxio.exception.FileDoesNotExistException;
  import alluxio.exception.InvalidPathException;
  import alluxio.grpc.CreateDirectoryPOptions;
  import alluxio.master.CoreMasterContext;
  import alluxio.master.MasterRegistry;
  import alluxio.master.MasterTestUtils;
  import alluxio.master.block.BlockMaster;
  import alluxio.master.block.BlockMasterFactory;
  import alluxio.master.file.RpcContext;
  import alluxio.master.file.contexts.CreateDirectoryContext;
  import alluxio.master.file.meta.Inode;
  import alluxio.master.file.meta.InodeDirectoryIdGenerator;
  import alluxio.master.file.meta.InodeLockManager;
  import alluxio.master.file.meta.InodeTree;
  import alluxio.master.file.meta.LockedInodePath;
  import alluxio.master.file.meta.MountTable;
  import alluxio.master.file.meta.options.MountInfo;
  import alluxio.master.journal.NoopJournalContext;
  import alluxio.master.metastore.InodeStore;
  import alluxio.master.metastore.caching.CachingInodeStore;
  import alluxio.master.metastore.heap.HeapInodeStore;
  import alluxio.master.metastore.rocks.RocksInodeStore;
  import alluxio.master.metrics.MetricsMaster;
  import alluxio.master.metrics.MetricsMasterFactory;
  import alluxio.underfs.UfsManager;
  
  import com.google.common.base.Preconditions;
  import org.apache.log4j.Level;
  import org.apache.log4j.Logger;
  
  import java.io.IOException;
  import java.time.Clock;
  import java.util.ArrayList;
  import java.util.function.Consumer;
  
  class InodeBenchBase {
    public static final String HEAP = "heap";
    public static final String ROCKS = "rocks";
    public static final String ROCKSCACHE = "rocksCache";
    private static final CreateDirectoryContext DIRECTORY_CONTEXT = CreateDirectoryContext
        .mergeFrom(CreateDirectoryPOptions.newBuilder().setMode(TEST_DIR_MODE.toProto()))
        .setOwner(TEST_OWNER).setGroup(TEST_GROUP);
  
    private ArrayList<String> mBasePath;
    private final InodeStore mInodeStore;
    private final InodeTree mTree;
    private final MasterRegistry mRegistry;
    private final BlockMaster mBlockMaster;
    private final InodeLockManager mInodeLockManager = new InodeLockManager();
  
    InodeBenchBase(String inodeStoreType, String rocksConfig) throws Exception {
      Logger.getRootLogger().setLevel(Level.ERROR);
      mRegistry = new MasterRegistry();
      CoreMasterContext context = MasterTestUtils.testMasterContext();
      MetricsMaster metricsMaster = new MetricsMasterFactory().create(mRegistry, context);
      mRegistry.add(MetricsMaster.class, metricsMaster);
      mBlockMaster = new BlockMasterFactory().create(mRegistry, context);
      InodeDirectoryIdGenerator inodeDirectoryIdGenerator =
          new InodeDirectoryIdGenerator(mBlockMaster);
      UfsManager ufsManager = mock(UfsManager.class);
      MountTable mountTable = new MountTable(ufsManager, mock(MountInfo.class), Clock.systemUTC());
      mInodeStore = getInodeStore(inodeStoreType, rocksConfig, mInodeLockManager);
      mTree = new InodeTree(mInodeStore, mBlockMaster, inodeDirectoryIdGenerator,
          mountTable, mInodeLockManager);
      mRegistry.start(true);
      mTree.initializeRoot(TEST_OWNER, TEST_GROUP, TEST_DIR_MODE, NoopJournalContext.INSTANCE);
    }
  
    public void after() throws Exception {
      mRegistry.stop();
      mBlockMaster.close();
      mInodeLockManager.close();
      mInodeStore.clear();
      mInodeStore.close();
    }
  
    static InodeStore getInodeStore(
        String inodeStoreType, String rocksConfig,
        InodeLockManager lockManager) throws IOException {
      switch (inodeStoreType) {
        case HEAP:
          Preconditions.checkArgument(rocksConfig.equals(RocksBenchConfig.JAVA_CONFIG),
              String.format("Heap inode store does not expect a configuration for rocksDB,"
                  + " instead should be %s", RocksBenchConfig.JAVA_CONFIG));
          return new HeapInodeStore();
        case ROCKS:
          String dir =
              AlluxioTestDirectory.createTemporaryDirectory("inode-store-bench").getAbsolutePath();
          RocksBenchConfig.setRocksConfig(rocksConfig, dir, Configuration.modifiableGlobal());
          return new RocksInodeStore(dir);
        case ROCKSCACHE:
          dir =
              AlluxioTestDirectory.createTemporaryDirectory("inode-store-bench").getAbsolutePath();
          return new CachingInodeStore(new RocksInodeStore(dir), lockManager);
        default:
          throw new IllegalStateException("Invalid type: " + inodeStoreType);
      }
    }
  
    // Helper to create a path.
    private void createPath(InodeTree root, AlluxioURI path)
        throws FileAlreadyExistsException, BlockInfoException, InvalidPathException, IOException,
        FileDoesNotExistException {
      try (LockedInodePath inodePath = root.lockInodePath(
          path, InodeTree.LockPattern.WRITE_EDGE, NoopJournalContext.INSTANCE)
      ) {
        root.createPath(RpcContext.NOOP, inodePath, InodeBenchBase.DIRECTORY_CONTEXT);
      }
    }
  
    void createBasePath(int depth) throws Exception {
      mBasePath = new ArrayList<>(depth + 1);
      String prevBasePath = "/";
      mBasePath.add(prevBasePath);
      for (int i = 0; i < depth; i++) {
        prevBasePath += "nxt/";
        mBasePath.add(prevBasePath);
        createPath(mTree, new AlluxioURI(prevBasePath));
      }
    }
  
    AlluxioURI getPath(int myId, int depth, long nxtFileId) {
      return new AlluxioURI(String.format("%s%dthread%d",
          mBasePath.get(depth), nxtFileId, myId));
    }
  
    Inode getFile(int depth, long nxtFileId) throws Exception {
      try (LockedInodePath path = mTree.lockFullInodePath(
          getPath(0, depth, nxtFileId), InodeTree.LockPattern.READ, NoopJournalContext.INSTANCE)) {
        return path.getInode();
      }
    }
  
    void writeFile(int myId, int depth, long nxtFileId) throws Exception {
      createPath(mTree, getPath(myId, depth, nxtFileId));
    }
  
    void listDir(int depth, Consumer<Inode> consumeFun) throws Exception {
      try (LockedInodePath path = mTree.lockInodePath(
          new AlluxioURI(mBasePath.get(depth)),
          InodeTree.LockPattern.READ, NoopJournalContext.INSTANCE)) {
        mInodeStore.getChildren(path.getInode().asDirectory()).forEachRemaining(
            consumeFun);
      }
    }
  }
  