Package dijjer.io.download

Source Code of dijjer.io.download.Download$BlockPair

/*
* Dijjer - A Peer to Peer HTTP Cache
* Copyright (C) 2004,2005 Change.Tv, Inc
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
package dijjer.io.download;

import java.io.OutputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import dijjer.Dijjer;
import dijjer.io.BlockInfo;
import dijjer.io.comm.DMT;
import dijjer.io.comm.Dispatcher;
import dijjer.io.comm.Peer;
import dijjer.io.comm.RoutingTable;
import dijjer.io.comm.UdpSocketManager;
import dijjer.io.store.Store;
import dijjer.io.xfer.OutputStreamBlockTransmitter;
import dijjer.io.xfer.PartiallyReceivedBlock;
import dijjer.io.xfer.http.HttpBlockReceiver;
import dijjer.util.Misc;
import dijjer.util.TruncatingOutputStream;
import dijjer.util.VeryLongInteger;
import dijjer.util.logging.Logger;

/**
* @author ian
*
* To change the template for this generated type comment go to Window - Preferences - Java - Code Generation - Code and
* Comments
*/
public class Download implements Job {

  boolean _aborted = false;
  OutputStream _os;
  public static final int MAX_PENDING = 8;
  int _firstBlock, _lastBlock, _nextBlockToDownload, _nextHashToDownload, _fromCacheCount = 0;
  LinkedList _pending = new LinkedList();
  HashMap _retrievedHashes = new HashMap();
  URL _url;
  long _length;
  String _lastModified;

  public Download(URL url, long length, String lastModified, int firstBlock, int lastBlock, OutputStream os) {
    _url = url;
    _length = length;
    _lastModified = lastModified;
    _firstBlock = firstBlock;
    _lastBlock = lastBlock;
    _nextBlockToDownload = _nextHashToDownload = _firstBlock;
    _os = os;
  }

  public void start() {
    DownloaderThread.addJob(this);
    abort : for (int block = _firstBlock; block <= _lastBlock; block++) {
      if (_aborted) {
        break abort;
      }
      while (_pending.isEmpty()) {
        if (_aborted) {
          break abort;
        }
        synchronized (this) {
          try {
            this.wait();
          } catch (InterruptedException e) {
          }
        }
      }
      BlockPair bp;
      synchronized (this) {
        Logger.info("Removing block " + block + " from pending queue");
        bp = (BlockPair) _pending.removeFirst();
      }
      OutputStreamBlockTransmitter osbt = new OutputStreamBlockTransmitter(bp.getPartiallyReceivedBlock(), _os);
      try {
        Logger.info("Starting transfer of block " + block);
        osbt.start();
        Logger.info("Completed transfer of block " + block);
        // Confirm that the hash matches
        VeryLongInteger retrievedHash = (VeryLongInteger) _retrievedHashes.get(new Integer(block));
        if (retrievedHash != null) {
          Logger.info("Verifying hash for block "+block);
          VeryLongInteger actualHash = new VeryLongInteger(bp.getPartiallyReceivedBlock().getBlock());
          if (!actualHash.equals(retrievedHash)) {
            Logger.warning("Hash check for block "+block+" failed");
            handleHashVerificationFailure(retrievedHash, actualHash, bp.getBlockInfo());
          }
        }
      } catch (Exception e) {
        Logger.error("Exception writing data to OutputStream, aborting download", e);
        this.abort();
      }
    }
    DownloaderThread.removeJob(this);
  }

  public boolean readyForNextTask() {
    return (!_aborted) && _pending.size() <= MAX_PENDING
        && (_nextBlockToDownload <= _lastBlock || _nextHashToDownload <= _lastBlock);
  }

  public void abort() {
    _aborted = true;
    synchronized (this) {
      this.notify();
    }
  }

  public long getBytesFromCache() {
    return _fromCacheCount * Store.DATA_BLOCK_SIZE;
  }

  public void performNextTask() {
    if (_aborted) {
      return;
    }
    int blockNo;
    if (_nextHashToDownload < _nextBlockToDownload) {
      synchronized (this) {
        blockNo = _nextHashToDownload++;
      }
      Logger.info("Prepairing to retrieve hash " + blockNo);
      int uid = Misc.nextInt();
      Dispatcher.getDispatcher().registerUid(uid);
      VeryLongInteger checkHash = null;
      try {
        checkHash = Dispatcher.getDispatcher().retrieveHash(
            new BlockInfo(_url, _length, _lastModified, blockNo), 10, uid, false);
      } catch (Exception e) {
        Logger.warning("Failed to retrieve hash " + e.getMessage());
      }
      Dispatcher.getDispatcher().unregisterUid(uid);
      if (checkHash != null) {
        _retrievedHashes.put(new Integer(blockNo), checkHash);
      }
      Logger.info("Done with retrieval of hash " + blockNo);
    } else {
      PartiallyReceivedBlock block;
      BlockInfo bi;
      synchronized (this) {
        blockNo = _nextBlockToDownload++;
        bi = new BlockInfo(_url, _length, _lastModified, blockNo);
        block = new PartiallyReceivedBlock(Dijjer.PACKETS_IN_BLOCK, Dijjer.PACKET_SIZE);
        _pending.addLast(new BlockPair(bi, block));
        this.notify();
      }
      try {
        // If the remote transfer fails we don't want the transfer to the client to be aborted, rather
        // we want to rerequest with TTL of 0, so we tell the PartiallyRetrievedBlock to ignore any
        // abort
        block.setIgnoreAbort(true);
        if (Dispatcher.getDispatcher().retrieveData(bi, 15, block, this)) {
          _fromCacheCount++;
        }
        block.setIgnoreAbort(false);
      } catch (Exception e) {
        Logger.warning("Error during download of block " + blockNo + ": " + e.getMessage());
        try {
          Logger.info("Retrying block " + blockNo + " with TTL of 0");
          Dispatcher.getDispatcher().retrieveData(new BlockInfo(_url, _length, _lastModified, blockNo), 0,
              block, this);
        } catch (Exception e1) {
          Logger.error("Error during direct download of block " + blockNo + ", aborting", e1);
          this.abort();
        }
      }
      Logger.info("Done with retrieval of block " + blockNo);
    }
  }

  public String getFileName() {
    return _url.getFile();
  }

  public long getLength() {
    return ((TruncatingOutputStream) _os).getLength();
  }

  public long getSent() {
    return ((TruncatingOutputStream) _os).getBytesTransmitted();
  }

  public long getDownloaded() {
    long ttl = getSent();
    synchronized (this) {
      for (Iterator i = _pending.iterator(); i.hasNext();) {
        BlockPair bp = (BlockPair) i.next();
        ttl += bp.getPartiallyReceivedBlock().numReceived() * Dijjer.PACKET_SIZE;
      }
    }
    return ttl;
  }

  public long getTotalFileLength() {
    return _length;
  }

  private void handleHashVerificationFailure(VeryLongInteger retrievedHash, VeryLongInteger actualHash, BlockInfo bi) {
    // Find out what the hash should be
    PartiallyReceivedBlock prb = new PartiallyReceivedBlock(Dijjer.PACKETS_IN_BLOCK, Dijjer.PACKET_SIZE);
    try {
      (new HttpBlockReceiver(bi, prb)).start();
    } catch (Exception e) {
      Logger.warning("Exception while trying to deal with hash verification failure", e);
    }
    VeryLongInteger confirmHash = new VeryLongInteger(prb.getBlock());
    boolean dataHashFailure = !confirmHash.equals(actualHash);
    boolean hashHashFailure = !confirmHash.equals(retrievedHash);
    Logger.info("Sending corruptionNotification for " + bi + " (" + dataHashFailure + ", " + hashHashFailure + ")");
    for (Iterator i = ((ArrayList) RoutingTable.getRoutingTable().getPeers().clone()).iterator(); i.hasNext();) {
      Peer p = (Peer) i.next();
      if (dataHashFailure) {
        UdpSocketManager.getUdpSocketManager().send(p,
            DMT.createCorruptionNotification(Misc.nextInt(), bi, false));
      }
      if (hashHashFailure) {
        UdpSocketManager.getUdpSocketManager().send(p,
            DMT.createCorruptionNotification(Misc.nextInt(), bi, true));
      }
    }
  }

  protected static class BlockPair {

    BlockInfo _bi;
    PartiallyReceivedBlock _prb;

    public BlockPair(BlockInfo bi, PartiallyReceivedBlock prb) {
      _bi = bi;
      _prb = prb;
    }

    public BlockInfo getBlockInfo() {
      return _bi;
    }

    public PartiallyReceivedBlock getPartiallyReceivedBlock() {
      return _prb;
    }
  }
}
TOP

Related Classes of dijjer.io.download.Download$BlockPair

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.