Package freenet.client

Source Code of freenet.client.FailureCodeTracker

/* This code is part of Freenet. It is distributed under the GNU General
* Public License, version 2 (or at your option any later version). See
* http://www.gnu.org/ for further details of the GPL. */
package freenet.client;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import freenet.client.FetchException.FetchExceptionMode;
import freenet.client.InsertException.InsertExceptionMode;
import freenet.support.Logger;
import freenet.support.SimpleFieldSet;
import freenet.support.io.StorageFormatException;

/**
* Essentially a map of integer to incrementible integer.
* FIXME maybe move this to support, give it a better name?
*
* WARNING: Changing non-transient members on classes that are Serializable can result in
* restarting downloads or losing uploads.
*/
public class FailureCodeTracker implements Cloneable, Serializable {

    private static final long serialVersionUID = 1L;
    public final boolean insert;
  private int total;
 
  public FailureCodeTracker(boolean insert) {
    this.insert = insert;
  }
 
  /**
   * Create a FailureCodeTracker from a SimpleFieldSet.
   * @param isInsert Whether this is an insert.
   * @param fs The SimpleFieldSet containing the FieldSet (non-verbose) form of
   * the tracker.
   */
  public FailureCodeTracker(boolean isInsert, SimpleFieldSet fs) {
    this.insert = isInsert;
    Iterator<String> i = fs.directSubsetNameIterator();
    while(i.hasNext()) {
      String name = i.next();
      SimpleFieldSet f = fs.subset(name);
      // We ignore the Description, if there is one; we just want the count
      int num = Integer.parseInt(name);
      int count = Integer.parseInt(f.get("Count"));
      if(count < 0) throw new IllegalArgumentException("Count < 0");
      map.put(Integer.valueOf(num), count);
      total += count;
    }
  }
 
  protected FailureCodeTracker() {
      // For serialization.
      this.insert = false;
  }
 
  private HashMap<Integer, Integer> map;
 
  public void inc(FetchExceptionMode k) {
      if(insert) throw new IllegalStateException();
      inc(k.code);
  }

    public void inc(InsertExceptionMode k) {
        if(!insert) throw new IllegalStateException();
        inc(k.code);
    }

  public synchronized void inc(int k) {
    if(k == 0) {
      Logger.error(this, "Can't increment 0, not a valid failure mode", new Exception("error"));
    }
    if(map == null) map = new HashMap<Integer, Integer>();
    Integer key = k;
    Integer i = map.get(key);
    if(i == null)
      map.put(key, 1);
    else
        map.put(key, i+1);
    total++;
  }

    public void inc(FetchExceptionMode k, int val) {
        if(insert) throw new IllegalStateException();
        inc(k.code, val);
    }

    public void inc(InsertExceptionMode k, int val) {
        if(!insert) throw new IllegalStateException();
        inc(k.code, val);
    }

  public synchronized void inc(Integer k, int val) {
    if(k == 0) {
      Logger.error(this, "Can't increment 0, not a valid failure mode", new Exception("error"));
    }
    if(map == null) map = new HashMap<Integer, Integer>();
    Integer key = k;
    Integer i = map.get(key);
    if(i == null)
      map.put(key, 1);
    else
        map.put(key, i+val);
    total += val;
  }
 
  public synchronized String toVerboseString() {
    if(map == null) return super.toString()+":empty";
    StringBuilder sb = new StringBuilder();
    for (Map.Entry<Integer, Integer> e : map.entrySet()) {
      Integer x = e.getKey();
      Integer val = e.getValue();
      String s = getMessage(x);
      sb.append(val);
      sb.append('\t');
      sb.append(s);
      sb.append('\n');
    }
    return sb.toString();
  }

  public String getMessage(Integer x) {
      return insert ? InsertException.getMessage(InsertExceptionMode.getByCode(x)) :
          FetchException.getMessage(FetchExceptionMode.getByCode(x));
    }

    @Override
  public synchronized String toString() {
    if(map == null) return super.toString()+":empty";
    StringBuilder sb = new StringBuilder(super.toString());
    sb.append(':');
    if(map.size() == 0) sb.append("empty");
    else if(map.size() == 1) {
      sb.append("one:");
      Integer code = (Integer) (map.keySet().toArray())[0];
      sb.append(code);
      sb.append('=');
      sb.append((map.get(code)));
    } else if(map.size() < 10) {
      boolean needComma = false;
      for(Map.Entry<Integer, Integer> entry : map.entrySet()) {
        if(needComma)
          sb.append(',');
        sb.append(entry.getKey()); // code
        sb.append('=');
        sb.append(entry.getValue());
        needComma = true;
      }
    } else {
      sb.append(map.size());
    }
    return sb.toString();
  }
 
  /**
   * Merge codes from another tracker into this one.
   */
  public synchronized FailureCodeTracker merge(FailureCodeTracker source) {
    if(source.map == null) return this;
    if(map == null) map = new HashMap<Integer, Integer>();
    for (Map.Entry<Integer, Integer> e : source.map.entrySet()) {
      Integer k = e.getKey();
      Integer item = e.getValue();
      inc(k, item);
    }
    return this;
  }

  public void merge(FetchException e) {
    if(insert) throw new IllegalStateException("Merging a FetchException in an insert!");
    if(e.errorCodes != null) {
      merge(e.errorCodes);
    }
    // Increment mode anyway, so we get the splitfile error as well.
    inc(e.mode.code);
  }

  public synchronized int totalCount() {
    return total;
  }

  /** Copy verbosely to a SimpleFieldSet */
  public synchronized SimpleFieldSet toFieldSet(boolean verbose) {
    SimpleFieldSet sfs = new SimpleFieldSet(false);
    if(map != null) {
    for (Map.Entry<Integer, Integer> e : map.entrySet()) {
      Integer k = e.getKey();
      Integer item = e.getValue();
      int code = k.intValue();
      // prefix.num.Description=<code description>
      // prefix.num.Count=<count>
      if(verbose)
        sfs.putSingle(Integer.toString(code)+".Description", getMessage(code));
      sfs.put(Integer.toString(code)+".Count", item);
    }
    }
    return sfs;
  }

  public synchronized boolean isOneCodeOnly() {
      if(map == null) return true;
    return map.size() == 1;
  }
 
    public FetchExceptionMode getFirstCodeFetch() {
        if(insert) throw new IllegalStateException();
        return FetchExceptionMode.getByCode(getFirstCode());
    }

    public InsertExceptionMode getFirstCodeInsert() {
        if(!insert) throw new IllegalStateException();
        return InsertExceptionMode.getByCode(getFirstCode());
    }

  public synchronized int getFirstCode() {
    return ((Integer) map.keySet().toArray()[0]).intValue();
  }

  public synchronized boolean isFatal(boolean insert) {
    if(map == null) return false;
    for (Map.Entry<Integer, Integer> e : map.entrySet()) {
      Integer code = e.getKey();
      if(e.getValue() == 0) continue;
      if(insert) {
        if(InsertException.isFatal(InsertExceptionMode.getByCode(code))) return true;
      } else {
        if(FetchException.isFatal(FetchExceptionMode.getByCode(code))) return true;
      }
    }
    return false;
  }

  public void merge(InsertException e) {
    if(!insert) throw new IllegalArgumentException("This is not an insert yet merge("+e+") called!");
    if(e.errorCodes != null)
      merge(e.errorCodes);
    inc(e.getMode());
  }

  public synchronized boolean isEmpty() {
    return map == null || map.isEmpty();
  }

  /** Copy the FailureCodeTracker. We implement Cloneable to shut up findbugs, but Object.clone() won't
   * work because it's a shallow copy, so we implement it with merge(). */
  @Override
  public FailureCodeTracker clone() {
    FailureCodeTracker tracker = new FailureCodeTracker(insert);
    tracker.merge(this);
    return tracker;
  }

  public synchronized boolean isDataFound() {
      if(!insert) throw new IllegalStateException();
    for(Map.Entry<Integer, Integer> entry : map.entrySet()) {
      if(entry.getValue() <= 0) continue;
      if(FetchException.isDataFound(FetchExceptionMode.getByCode(entry.getKey()), null)) return true;
    }
    return false;
  }
 
  private int MAGIC = 0xb605aa08;
  private int VERSION = 1;
 
  /** Get the length of the fixed-size representation produced by writeFixedLengthTo(). */
  public static int getFixedLength(boolean insert) {
        int upperLimit =
            insert ? InsertException.UPPER_LIMIT_ERROR_CODE : FetchException.UPPER_LIMIT_ERROR_CODE;
        return 4 + 4 + 4 + 4 * upperLimit;
  }
 
  /** Write a fixed-size representation to a DataOutputStream. This is important for e.g.
   * splitfiles, where we have a fixed part of the disk file to save it to. */
  public synchronized void writeFixedLengthTo(DataOutputStream dos) throws IOException {
      int upperLimit =
          insert ? InsertException.UPPER_LIMIT_ERROR_CODE : FetchException.UPPER_LIMIT_ERROR_CODE;
      dos.writeInt(MAGIC);
      dos.writeInt(VERSION);
      dos.writeInt(upperLimit);
      for(int i=0;i<upperLimit;i++)
          dos.writeInt(getErrorCount(i));
  }

  /** Get number of errors of count mode */
    public synchronized int getErrorCount(int mode) {
        if(map == null) return 0;
        Integer item = map.get(mode);
        return item == null ? 0 : item;
    }
   
    /** Get number of errors of count mode */
    public synchronized int getErrorCount(InsertExceptionMode mode) {
        if(!insert) throw new IllegalStateException();
        return getErrorCount(mode.code);
    }
   
    /** Get number of errors of count mode */
    public synchronized int getErrorCount(FetchExceptionMode mode) {
        if(insert) throw new IllegalStateException();
        return getErrorCount(mode.code);
    }
   
    public FailureCodeTracker(boolean insert, DataInputStream dis) throws IOException, StorageFormatException {
        this.insert = insert;
        if(dis.readInt() != MAGIC)
            throw new StorageFormatException("Bad magic for FailureCodeTracker");
        if(dis.readInt() != VERSION)
            throw new StorageFormatException("Bad version for FailureCodeTracker");
        int upperLimit =
            insert ? InsertException.UPPER_LIMIT_ERROR_CODE : FetchException.UPPER_LIMIT_ERROR_CODE;
        if(dis.readInt() != upperLimit)
            throw new StorageFormatException("Bad upper limit for FailureCodeTracker");
        for(int i=0;i<upperLimit;i++) {
            int x = dis.readInt();
            if(x < 0) throw new StorageFormatException("Negative error counts");
            if(x == 0) continue;
            if(map == null) map = new HashMap<Integer, Integer>();
            total += x;
            map.put(i, x);
        }
    }
}
TOP

Related Classes of freenet.client.FailureCodeTracker

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.