コード例 #1
0
  /** Receive a file. */
  public void transfer(RepositoryChannel fileChannel, Role role, Mode mode, Allocator allocator)
      throws Exception {
    /* Initialise transfer parameters.
     */
    _role = role;
    _bytesTransferred = 0;
    _blockLog = new BlockLog(this);
    _fileChannel = fileChannel;
    _allocator = allocator;
    _reservedSpace = 0;
    _spaceUsed = 0;
    _status = "None";
    DigestThread digestThread = null;

    /* Startup the transfer. The transfer is performed on a single
     * thread, no matter the number of streams.
     *
     * Checksum computation is performed on a different
     * thread. The checksum computation thread is not allowed to
     * overtake the transfer thread, but we also ensure that the
     * checksum thread does not fall too far behind. This is to
     * increase the chance that data has not yet been evicted from
     * the cache.
     */
    _multiplexer = new Multiplexer(this);
    try {
      _inProgress = true;

      digestThread = createDigestThread();
      if (digestThread != null) {
        Object o = _cell.getDomainContext().get(READ_AHEAD_KEY);
        if (o != null && ((String) o).length() > 0) {
          try {
            digestThread.setReadAhead(Long.parseLong((String) o));
          } catch (NumberFormatException e) {
            esay("Failed parsing read ahead: " + e.getMessage());
          }
        }

        say("Initiated checksum computation thread");
        digestThread.start();
      }

      _multiplexer.add(mode);

      say("Entering event loop");
      _multiplexer.loop();
    } catch (ClosedByInterruptException e) {
      /* Many NIO operations throw a ClosedByInterruptException
       * rather than InterruptedException. We rethrow this as an
       * InterruptedException and clear the interrupt flag on
       * the thread.
       */
      Thread.interrupted();
      throw new InterruptedException();
    } catch (InterruptedException | FTPException e) {
      throw e;
    } catch (Exception e) {
      esay(e);
      throw e;
    } finally {
      _inProgress = false;

      /* It is important that this is done before joining the
       * digest thread, since otherwise the digest thread would
       * not terminate.
       */
      _blockLog.setEof();

      /* Close all open channels.
       */
      say("Left event loop and closing channels");
      _multiplexer.close();

      /* Wait for checksum computation to finish before
       * returning. Otherwise getActualChecksum() could
       * possibly return an incomplete checksum.
       *
       * REVISIT: If the mover gets killed here, we break out
       * with an InterruptedException. This is as such not a
       * major problem, since everything after this point is not
       * essential for clean up. It is however unfortunate that
       * the job gets killed because we wait for checksum
       * computation (in particular because the checksum
       * computation may be the cause of the timeout if it is
       * very slow).
       */
      if (digestThread != null) {
        digestThread.join();
      }

      /* Log some useful information about the transfer.
       */
      long amount = getBytesTransferred();
      long time = getTransferTime();
      if (time > 0) {
        say(
            String.format(
                "Transfer finished: %d bytes transferred in %.2f seconds = %.3f MB/s",
                amount, time / 1000.0, (1000.0 * amount) / (time * 1024 * 1024)));
      } else {
        say(String.format("Transfer finished: %d bytes transferred in less than 1 ms", amount));
      }
    }

    /* REVISIT: Error reporting from the digest thread is not
     * optimal. In case of errors, they are not detected until
     * here. It would be better if digestThread could shutdown the
     * multiplexer. Maybe we should simply embed the DigestThread
     * class into the Mover.
     */
    if (digestThread != null && digestThread.getLastError() != null) {
      esay(digestThread.getLastError());
      throw digestThread.getLastError();
    }

    /* Check that we receive the whole file.
     */
    if (!_blockLog.isComplete()) {
      throw new CacheException(44, "Incomplete file detected");
    }
  }