The process of OutOfCoreCallable

Constructor of ServerData

At the constructor of ServerData, if USE_OUT_OF_CORE_GRAPH is set true. oocEngine is created, and partitionStore is wrapped using DiskBackedPartitionStore.

PartitionStore<I, V, E> inMemoryPartitionStore =
        new SimplePartitionStore<I, V, E>(conf, context);
    if (GiraphConstants.USE_OUT_OF_CORE_GRAPH.get(conf)) {
      oocEngine = new OutOfCoreEngine(conf, service, workerServer);
      partitionStore =
          new DiskBackedPartitionStore<I, V, E>(inMemoryPartitionStore,
              conf, context, oocEngine);
      edgeStore =
          new DiskBackedEdgeStore<I, V, E>(inMemoryEdgeStore, conf, oocEngine);
    }

Constructor of OutOfCoreEngine

public OutOfCoreEngine(ImmutableClassesGiraphConfiguration<?, ?, ?> conf,
                         CentralizedServiceWorker<?, ?, ?> service,
                         NetworkMetrics networkMetrics) {

dataAccessor in OutOfCoreEngine

dataAccessor is instance of LocalDiskDataAccessor.
dataAccessor set numIOThreads by PARTITIONS_DIRECTORY.

  StrConfOption PARTITIONS_DIRECTORY =
      new StrConfOption("giraph.partitionsDirectory", "_bsp/_partitions",
          "Comma-separated list of directories in the local filesystem for " +
          "out-of-core partitions.");
Class<? extends OutOfCoreDataAccessor> accessorClass =
        GiraphConstants.OUT_OF_CORE_DATA_ACCESSOR.get(conf);
    try {
      Constructor<?> constructor = accessorClass.getConstructor(
          ImmutableClassesGiraphConfiguration.class);
      this.dataAccessor = (OutOfCoreDataAccessor) constructor.newInstance(conf);
    } catch (NoSuchMethodException | InstantiationException |
        InvocationTargetException | IllegalAccessException e) {
      throw new IllegalStateException("OutOfCoreEngine: caught exception " +
          "while creating the data accessor instance!", e);
    }

create OutOfCoreIOCallableFactory

this.oocIOCallableFactory =
        new OutOfCoreIOCallableFactory(this, numIOThreads,
            service.getGraphTaskManager().createUncaughtExceptionHandler());

OutOfCoreEngine.initialize

OutOfCoreEngine.initialize call oocIOCallableFactory.createCallable();

public void initialize() {
    oocIOCallableFactory.createCallable();
  }

OutOfCoreIOCallableFactory.createCallable

OutOfCoreIOCallableFactory uses a ThreadPoolExecutor to submit Call

public void createCallable() {
    CallableFactory<Void> outOfCoreIOCallableFactory =
      new CallableFactory<Void>() {
        @Override
        public Callable<Void> newCallable(int callableId) {
          return new OutOfCoreIOCallable(oocEngine, callableId);
        }
      };
    outOfCoreIOExecutor = new ThreadPoolExecutor(numIOThreads, numIOThreads, 0L,
        TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(),
        ThreadUtils.createThreadFactory("ooc-io-%d"));

    for (int i = 0; i < numIOThreads; ++i) {
      Future<Void> future = ThreadUtils.submitToExecutor(outOfCoreIOExecutor,
          outOfCoreIOCallableFactory.newCallable(i), uncaughtExceptionHandler);
      results.add(future);
    }
    // Notify executor to not accept any more tasks
    outOfCoreIOExecutor.shutdown();
  }

OutOfCoreIOCallable.call

OutOfCoreIOCallable.call acqure IOCommand from occEngine.OSScheduler

public Void call() throws Exception {
    while (true) {

      IOCommand command = oocEngine.getIOScheduler().getNextIOCommand(diskId);
        boolean commandExecuted = false;
       commandExecuted = command.execute();
      oocEngine.getIOScheduler().ioCommandCompleted(command);
  }
  return null;
  }

OutOfCoreIOScheduler.getNextIOCommand

  public IOCommand getNextIOCommand(int threadId) {
              IOCommand command = null;
              OutOfCoreOracle.IOAction[] actions =
          oocEngine.getOracle().getNextIOActions();

There are several type of OutOfCoreOracle, includes MemoryEstimatorOracle, ThresholdBasedOracle. FixedPartitionsOracle, SimpleGCMonitoringOracle

   int numPartitionsInMemory =
        oocEngine.getMetaPartitionManager().getNumInMemoryPartitions();
    int numPartialPartitionsInMemory =
        oocEngine.getMetaPartitionManager().getNumPartiallyInMemoryPartitions();
int numPartitions =
        numPartitionsInMemory + deltaNumPartitionsInMemory.get();
 if (numPartitions < maxPartitionsInMemory) {
      return new IOAction[]{
        IOAction.LOAD_PARTITION,
        IOAction.STORE_MESSAGES_AND_BUFFERS};
    } else if (numPartitions > maxPartitionsInMemory) {
      return new IOAction[]{
        IOAction.STORE_PARTITION,
        IOAction.STORE_MESSAGES_AND_BUFFERS};
    } else {
      return new IOAction[]{
        IOAction.STORE_MESSAGES_AND_BUFFERS,
        IOAction.LOAD_TO_SWAP_PARTITION};
    }

Continue OutOfCoreIOScheduler.getNextIOCommand

 // Check whether there are any urgent outstanding load requests
   if (!threadLoadCommandQueue.get(threadId).isEmpty()) {
        boolean canLoad = false;
        for (OutOfCoreOracle.IOAction action : actions) {
          if (action == OutOfCoreOracle.IOAction.LOAD_PARTITION ||
              action == OutOfCoreOracle.IOAction.LOAD_UNPROCESSED_PARTITION ||
              action == OutOfCoreOracle.IOAction.LOAD_TO_SWAP_PARTITION ||
              action == OutOfCoreOracle.IOAction.URGENT_LOAD_PARTITION) {
            canLoad = true;
            break;
          }
        }
        if (canLoad) {
          command = threadLoadCommandQueue.get(threadId).poll();
          checkNotNull(command);
          if (oocEngine.getOracle().approve(command)) {
            return command;
          } else {
            // Loading is not viable at this moment. We should put the command
            // back in the load queue and wait until loading becomes viable.
            threadLoadCommandQueue.get(threadId).offer(command);
          }
        }
      }

the element in threadLoadCommandQueue is added by OutOfCoreIOScheduler.addIOCommand

public void addIOCommand(IOCommand ioCommand) {
    if (ioCommand instanceof LoadPartitionIOCommand) {
      int ownerThread = oocEngine.getMetaPartitionManager()
          .getOwnerThreadId(ioCommand.getPartitionId());
      threadLoadCommandQueue.get(ownerThread).offer(ioCommand);
    } else {
      throw new IllegalStateException("addIOCommand: IO command type is not " +
          "supported for addition");
    }
  }

OutOfCoreEngine.retrievePartition

For example,OutOfCoreEngine.retrievePartition will wait until partition in memory.

/**
   * Retrieve a particular partition. After this method is complete the
   * requested partition should be in memory.
   *
   * @param partitionId id of the partition to retrieve
   */
  public void retrievePartition(int partitionId) {
    if (metaPartitionManager.isPartitionOnDisk(partitionId)) {
      ioScheduler.addIOCommand(new LoadPartitionIOCommand(this, partitionId,
          superstep));
      synchronized (partitionAvailable) {
        while (metaPartitionManager.isPartitionOnDisk(partitionId)) {
          try {  
            partitionAvailable.wait();
          } catch (InterruptedException e) {
           //
        }
      }
    }
  }

Continue OutOfCoreIOScheduler.getNextIOCommand

then it will try every type of action, to setup correspond command and return the command.

  command = null;
      for (OutOfCoreOracle.IOAction action : actions) {
        Integer partitionId;
        switch (action) {
        case STORE_MESSAGES_AND_BUFFERS:
          partitionId = oocEngine.getMetaPartitionManager()
              .getOffloadPartitionBufferId(threadId);
          if (partitionId != null) {
            command = new StoreDataBufferIOCommand(oocEngine, partitionId,
                StoreDataBufferIOCommand.DataBufferType.PARTITION);
          } else {
            partitionId = oocEngine.getMetaPartitionManager()
                .getOffloadMessageBufferId(threadId);
            if (partitionId != null) {
              command = new StoreDataBufferIOCommand(oocEngine, partitionId,
                  StoreDataBufferIOCommand.DataBufferType.MESSAGE);
            } else {
              partitionId = oocEngine.getMetaPartitionManager()
                  .getOffloadMessageId(threadId);
              if (partitionId != null) {
                command = new StoreIncomingMessageIOCommand(oocEngine,
                    partitionId);
              }
            }
          }
          break;
        case STORE_PROCESSED_PARTITION:
          partitionId = oocEngine.getMetaPartitionManager()
              .getOffloadPartitionId(threadId);
          if (partitionId != null &&
              oocEngine.getMetaPartitionManager()
                  .isPartitionProcessed(partitionId)) {
            command = new StorePartitionIOCommand(oocEngine, partitionId);
          }
          break;
        case STORE_PARTITION:
          partitionId = oocEngine.getMetaPartitionManager()
              .getOffloadPartitionId(threadId);
          if (partitionId != null) {
            command = new StorePartitionIOCommand(oocEngine, partitionId);
          }
          break;
        case LOAD_UNPROCESSED_PARTITION:
          partitionId = oocEngine.getMetaPartitionManager()
              .getLoadPartitionId(threadId);
          if (partitionId != null &&
              !oocEngine.getMetaPartitionManager()
                  .isPartitionProcessed(partitionId)) {
            command = new LoadPartitionIOCommand(oocEngine, partitionId,
                oocEngine.getSuperstep());
          }
          break;
        case LOAD_TO_SWAP_PARTITION:
          partitionId = oocEngine.getMetaPartitionManager()
              .getLoadPartitionId(threadId);
          if (partitionId != null &&
              !oocEngine.getMetaPartitionManager()
                  .isPartitionProcessed(partitionId) &&
              oocEngine.getMetaPartitionManager().hasProcessedOnMemory()) {
            command = new LoadPartitionIOCommand(oocEngine, partitionId,
                oocEngine.getSuperstep());
          }
          break;
        case LOAD_PARTITION:
          partitionId = oocEngine.getMetaPartitionManager()
              .getLoadPartitionId(threadId);
          if (partitionId != null) {
            if (oocEngine.getMetaPartitionManager()
                .isPartitionProcessed(partitionId)) {
              command = new LoadPartitionIOCommand(oocEngine, partitionId,
                  oocEngine.getSuperstep() + 1);
            } else {
              command = new LoadPartitionIOCommand(oocEngine, partitionId,
                  oocEngine.getSuperstep());
            }
          }
          break;
        case URGENT_LOAD_PARTITION:
          // Do nothing
          break;
        default:
          throw new IllegalStateException("getNextIOCommand: the IO action " +
              "is not defined!");
        }
        if (command != null) {
          break;
        }
      }
      if (command == null) {
        command = new WaitIOCommand(oocEngine, waitInterval);
      }
    } while (!oocEngine.getOracle().approve(command));
    return command;

For example, FixedPartitionsOracle.getNextIOActions.

 if (numPartitions > maxPartitionsInMemory) {
    
      return new IOAction[]{
        IOAction.STORE_PARTITION,
        IOAction.STORE_MESSAGES_AND_BUFFERS};
  }

numPartitons is determined by numPartitionsInMemory. int numPartitionsInMemory = oocEngine.getMetaPartitionManager().getNumInMemoryPartitions();

MetaPartitionManager.addPartition

MetaPartitionManager.numInMemoryPartitions is updated at addPartition and updateCounters.

public void addPartition(int partitionId) {
    MetaPartition meta = new MetaPartition(partitionId);
    MetaPartition temp = partitions.putIfAbsent(partitionId, meta);
    // Check if the given partition is new
    if (temp == null) {
      int index = indexCounter.getAndIncrement();
      checkState(partitionIndex.putIfAbsent(partitionId, index) == null);
      int ownerThread = getOwnerThreadId(partitionId);
      perThreadPartitionDictionary.get(ownerThread).addPartition(meta);
      numInMemoryPartitions.getAndIncrement();
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值