Пример #1
0
/** @author i.zaytsev */
public class PoolTransformer implements ClassFileTransformer {

  private static final Log log = LogFactory.getLog(PoolTransformer.class);
  private static final boolean ITF_FALSE = false;
  private static final boolean ITF_TRUE = true;
  private Map<String, ThreadPoolCfg> pools = new ConcurrentHashMap<String, ThreadPoolCfg>();

  public PoolTransformer(Collection<ThreadPoolCfg> pools) {
    for (ThreadPoolCfg p : pools) {
      register(p);
    }
  }

  public PoolTransformer(ThreadPoolCfg p) {
    register(p);
  }

  public boolean register(ThreadPoolCfg p) {
    return this.pools.put(p.className, p) == null;
  }

  @Override
  public byte[] transform(
      ClassLoader cl,
      String className,
      Class<?> classBeingRedefined,
      ProtectionDomain protectionDomain,
      byte[] classfileBuffer) {
    byte[] bytes = null;
    ThreadPoolCfg md = pools.get(className);
    if (md != null) {
      if (className.equals(md.className)) {
        bytes = transformThreadPool(md, classfileBuffer);
        log.info("Transformed [" + className + "]");
      }
    }
    return bytes;
  }

  private byte[] transformThreadPool(ThreadPoolCfg md, byte[] classfileBuffer) {
    ClassWriter w = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
    ClassVisitor a = new PoolClassAdapter(w, md);
    ClassReader r = new ClassReader(classfileBuffer);
    r.accept(a, ClassReader.EXPAND_FRAMES);
    return w.toByteArray();
  }

  /**
   * Transforms ThreadPoolExecutor adding field {@link Stat} and changing constructor and method
   * 'execute'. Class visibility not private for jrockit runtime.
   */
  protected static class PoolClassAdapter extends ClassVisitor {

    private ThreadPoolCfg md;
    private static final String CONSTRUCTOR = "<init>";

    public PoolClassAdapter(ClassVisitor cv, ThreadPoolCfg md) {
      super(Opcodes.ASM4, cv);
      this.md = md;
    }

    @Override
    public MethodVisitor visitMethod(
        int access, String name, String desc, String signature, String[] exceptions) {
      MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
      String className = md.className;
      if (CONSTRUCTOR.equals(name)) {
        mv = new InitAdviceAdapter(mv, access, name, desc, className, md.histogram);
      } else if (md.execName.equals(name) && md.execSign.equals(desc)) {
        mv = new ExecAdviceAdapter(mv, access, name, desc, className);
      }
      return mv;
    }

    @Override
    public void visitEnd() {
      Util.addField(cv, Const.PSTAT_FNAME, Stat.class, false);
      super.visitEnd();
    }
  }

  /** Add ThreadPoolExecutor constructor with registration invocation */
  protected static class InitAdviceAdapter extends AdviceAdapter {

    private String className;
    private boolean histogram;

    public InitAdviceAdapter(
        MethodVisitor mv,
        int access,
        String name,
        String desc,
        String className,
        boolean histogram) {
      super(Opcodes.ASM4, mv, access, name, desc);
      this.className = className;
      this.histogram = histogram;
    }

    @Override
    protected void onMethodExit(int opcode) {
      if (opcode == Opcodes.RETURN) {
        // StatRegistry reg = StatRegistry.instance;
        // int index = reg.registerThreadPool(this, false);
        // this.threadCatPStat = reg.getStatHolder(index);
        mv.visitFieldInsn(GETSTATIC, Const.REG_T, "instance", Const.REG_D);
        int local7 = newLocal(Type.getObjectType(Const.REG_T));
        mv.visitVarInsn(ASTORE, local7);
        mv.visitVarInsn(ALOAD, local7);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitInsn(histogram ? ICONST_1 : ICONST_0);
        // Parameters: opcode, owner, name, desc, itf
        mv.visitMethodInsn(
            INVOKEVIRTUAL, Const.REG_T, "registerThreadPool", "(Ljava/lang/Object;Z)I", ITF_FALSE);
        int local8 = newLocal(Type.INT_TYPE);
        mv.visitVarInsn(ISTORE, local8);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitVarInsn(ALOAD, local7);
        mv.visitVarInsn(ILOAD, local8);
        mv.visitMethodInsn(
            INVOKEVIRTUAL, Const.REG_T, "getStatHolder", "(I)".concat(Const.STAT_D), ITF_FALSE);
        mv.visitFieldInsn(PUTFIELD, className, Const.PSTAT_FNAME, Const.STAT_D);
      }
    }
  }

  /** Modifies method 'execute' of ThreadPoolExecutor */
  protected static class ExecAdviceAdapter extends AdviceAdapter {

    private String className;

    public ExecAdviceAdapter(
        MethodVisitor mv, int access, String name, String desc, String className) {
      super(Opcodes.ASM4, mv, access, name, desc);
      this.className = className;
    }

    @Override
    protected void onMethodEnter() {
      super.onMethodEnter();
      // if(runnable instance of Queuable) {
      mv.visitVarInsn(ALOAD, 1);
      mv.visitTypeInsn(INSTANCEOF, Const.Q_T);
      Label L0 = new Label();
      mv.visitJumpInsn(IFEQ, L0);

      // queuable.setThreadCatExec(System.nanoTime());
      mv.visitVarInsn(ALOAD, 1);
      mv.visitTypeInsn(CHECKCAST, Const.Q_T);
      mv.visitVarInsn(ASTORE, 2);
      mv.visitVarInsn(ALOAD, 2);
      mv.visitMethodInsn(INVOKESTATIC, Const.SYSTEM_T, "nanoTime", "()J", ITF_FALSE);
      mv.visitMethodInsn(INVOKEINTERFACE, Const.Q_T, Const.EXEC_SETTER, "(J)V", ITF_TRUE);

      // queuable.setThreadCatStat(this.threadCatStat);
      mv.visitVarInsn(ALOAD, 2);
      mv.visitVarInsn(ALOAD, 0);
      mv.visitFieldInsn(GETFIELD, className, Const.PSTAT_FNAME, Const.STAT_D);
      mv.visitMethodInsn(
          INVOKEINTERFACE,
          Const.Q_T,
          Const.PSTAT_SETTER,
          "(".concat(Const.STAT_D).concat(")V"),
          ITF_TRUE);

      // }
      mv.visitLabel(L0);
    }
  }
}
Пример #2
0
/**
 * Client-side serializer. Encode commands, decode statistics data.
 *
 * @author i.zaytsev
 */
public class CSerializer {
  private static final Log log = LogFactory.getLog(CSerializer.class);
  private CharBuffer charBuffer = CharBuffer.allocate(10 * 1024);
  private JsonWriteHelper jsonWriter = new JsonWriteHelper(charBuffer);
  private JsonReadHelper jsonReader = new JsonReadHelper(charBuffer);

  public CharBuffer encodeListCmd(Mode mode) {
    charBuffer.clear();
    jsonWriter
        .startObject()
        .writeString(FIELD.type.name(), TYPE.listCmd.name())
        .next()
        .writeString(FIELD.data.name(), mode.name())
        .endObject();
    charBuffer.flip();
    return charBuffer;
  }

  public CharBuffer encodeDescCmd(String template) {
    charBuffer.clear();
    jsonWriter
        .startObject()
        .writeString(FIELD.type.name(), TYPE.descCmd.name())
        .next()
        .writeString(FIELD.data.name(), template)
        .endObject();
    charBuffer.flip();
    return charBuffer;
  }

  public CharBuffer encodeRegCmd(Mode mode, String[] names) {
    charBuffer.clear();
    jsonWriter
        .startObject()
        .writeString(FIELD.type.name(), TYPE.regCmd.name())
        .next()
        .writeFieldName(FIELD.data.name())
        .startObject()
        .writeString(FIELD.mode.name(), mode.name())
        .next()
        .writeFieldName(FIELD.names.name())
        .startArray();
    int i = 0;
    for (String name : names) {
      if (i > 0) jsonWriter.next();
      jsonWriter.writeString(name);
      i++;
    }
    jsonWriter.endArray().endObject().endObject();
    charBuffer.flip();
    return charBuffer;
  }

  public CharBuffer encodeUnregCmd(Mode mode, String[] names) {
    charBuffer.clear();
    jsonWriter
        .startObject()
        .writeString(FIELD.type.name(), TYPE.unregCmd.name())
        .next()
        .writeFieldName(FIELD.data.name())
        .startObject()
        .writeString(FIELD.mode.name(), mode.name())
        .next()
        .writeFieldName(FIELD.names.name())
        .startArray();
    int i = 0;
    for (String name : names) {
      if (i > 0) jsonWriter.next();
      jsonWriter.writeString(name);
      i++;
    }
    jsonWriter.endArray().endObject().endObject();
    charBuffer.flip();
    return charBuffer;
  }

  public CharBuffer encodeStatCmd() {
    charBuffer.clear();
    jsonWriter.startObject().writeString(FIELD.type.name(), TYPE.statCmd.name()).endObject();
    charBuffer.flip();
    return charBuffer;
  }

  public CharBuffer encodeHistCmd(Boolean activate, String[] names) {
    charBuffer.clear();
    jsonWriter.startObject();
    if (activate != null) {
      jsonWriter
          .writeString(FIELD.type.name(), TYPE.histCmd.name())
          .next()
          .writeFieldName(FIELD.data.name())
          .startObject()
          .writeBoolean(FIELD.activate.name(), activate)
          .next()
          .writeFieldName(FIELD.names.name())
          .startArray();
      if (names != null) {
        int i = 0;
        for (String name : names) {
          if (i > 0) jsonWriter.next();
          jsonWriter.writeString(name);
          i++;
        }
      }
      jsonWriter.endArray().endObject();
    } else {
      jsonWriter
          .writeString(FIELD.type.name(), TYPE.statCmd.name())
          .next()
          .writeFieldName(FIELD.data.name())
          .startObject()
          .writeBoolean(FIELD.hist.name(), true)
          .endObject();
    }
    jsonWriter.endObject();
    charBuffer.flip();
    return charBuffer;
  }

  public CharBuffer encodeResetCmd(int[] ids) {
    charBuffer.clear();
    jsonWriter
        .startObject()
        .writeString(FIELD.type.name(), TYPE.resetCmd.name())
        .next()
        .writeFieldName(FIELD.data.name())
        .startArray();
    int i = 0;
    for (int id : ids) {
      if (i > 0) jsonWriter.next();
      jsonWriter.writeDecimal(id, 0);
    }
    jsonWriter.endArray().endObject();
    charBuffer.flip();
    return charBuffer;
  }

  /*------------------------------------------------------------------------*/
  /*                                                                        */
  public ServiceBox decodeBox(String s) {
    ServiceBox box = null;
    charBuffer.clear();
    charBuffer.put(s);
    charBuffer.flip();
    // String typeString = s.replaceAll("\\\":.*$", "").replaceAll("^.*\\\"", "");
    int typeLength = jsonReader.stringLength(FIELD.type.name());
    if (typeLength < 1) {
      log.err("Data type undefined " + s);
      return null;
    }
    String typeString = charBuffer.subSequence(0, typeLength).toString();

    TYPE type = TYPE.valueOf(typeString);
    int statusCode = 0;
    if (type == TYPE.status) {
      statusCode = (int) jsonReader.readDecimal(FIELD.data.name()).getUnscaled();
    } else {
      jsonReader.findField(FIELD.data.name());
    }
    ServiceBox.Type boxType;
    switch (type) {
      case pList:
      case mList:
      case rList:
        box = createStatBox(ServiceBox.Type.REG);
        break;
      case descData:
        box = createStringBox(ServiceBox.Type.DESC);
        break;
      case status:
        box = createStringBox(statusCode);
        break;
      case statData:
        box = createSnapshotBox(ServiceBox.Type.STAT);
        break;
      case cfgData:
        box = createStringBox(ServiceBox.Type.CFG);
        break;
    }
    return box;
  }

  private ServiceBox<String> createStringBox(ServiceBox.Type type) {
    List<String> list = new ArrayList<String>();
    while (jsonReader.next()) {
      int len = jsonReader.stringLength();
      list.add(charBuffer.subSequence(0, len).toString());
      charBuffer.position(charBuffer.position() + len);
    }
    return new ServiceBox<String>(type, list);
  }

  private ServiceBox<String> createStringBox(int statusCode) {
    List<String> list = new ArrayList<String>();
    list.add(statusCode == 0 ? "Ok" : "Error " + statusCode);
    return new ServiceBox<String>(ServiceBox.Type.STATUS, list);
  }

  private ServiceBox<Snapshot> createSnapshotBox(ServiceBox.Type type) {
    List<Snapshot> snapshots = new ArrayList<Snapshot>();
    while (jsonReader.next()) {
      Snapshot sn = decodeSnapshot();
      snapshots.add(sn);
    }
    return new ServiceBox<Snapshot>(type, snapshots);
  }

  private Snapshot decodeSnapshot() {
    long execCount = jsonReader.readDecimal(FIELD.count.name()).getUnscaled();
    long firstTime = jsonReader.readDecimal(FIELD.first.name()).getUnscaled();
    long lastTime = jsonReader.readDecimal(FIELD.last.name()).getUnscaled();
    jsonReader.findField(FIELD.exec.name());
    TimeHolder[] timeHolders = decodeTimeHolders();
    return new SnapshotImpl(firstTime, lastTime, execCount, timeHolders);
  }

  private TimeHolder[] decodeTimeHolders() {
    ArrayList<TimeHolder> list = new ArrayList<TimeHolder>();
    while (jsonReader.next()) {
      long min = jsonReader.readDecimal(FIELD.min.name()).getUnscaled();
      long max = jsonReader.readDecimal(FIELD.max.name()).getUnscaled();
      long accum = jsonReader.readDecimal(FIELD.accum.name()).getUnscaled();
      int[] hist = decodeHistogram();
      TimeHolder holder = new TimeHolder(min, max, accum, hist);
      list.add(holder);
    }
    TimeHolder[] holders = list.toArray(new TimeHolder[] {});
    return holders;
  }

  private int[] decodeHistogram() {
    jsonReader.findField(FIELD.hist.name());
    ArrayList<Integer> list = new ArrayList<Integer>();
    while (jsonReader.next()) {
      list.add((int) jsonReader.readDecimal().getUnscaled());
    }
    int[] hist = new int[list.size()];
    for (int i = 0; i < list.size(); i++) {
      hist[i] = list.get(i);
    }
    return hist;
  }

  private ServiceBox<StatDto> createStatBox(ServiceBox.Type type) {
    List<StatDto> sts = new ArrayList<StatDto>();
    for (int i = 0; jsonReader.next(); i++) {
      StatDto s = decodeStatistics(i);
      sts.add(s);
    }
    return new ServiceBox<StatDto>(type, sts);
  }

  private StatDto decodeStatistics(int ind) {
    JsonHelper.Decimal decimal = jsonReader.readDecimal(FIELD.id.name());
    int id = decimal == null ? ind : (int) decimal.getUnscaled();
    int len = jsonReader.stringLength(FIELD.name.name());
    String name = charBuffer.subSequence(0, len).toString();
    Boolean b = jsonReader.readBoolean(FIELD.hist.name());
    boolean histogram = b != null && b;
    return new StatDto(id, name, histogram);
  }

  /** For client-side only. */
  public static class StatDto {

    public final int id;
    public final String name;
    public final boolean hist;

    public StatDto(int id, String name, boolean hist) {
      this.id = id;
      this.name = name;
      this.hist = hist;
    }

    @Override
    public boolean equals(Object obj) {
      if (StatDto.class.isInstance(obj)) {
        StatDto other = (StatDto) obj;
        return id == other.id && name.equals(other.name) && hist == other.hist;
      }
      return false;
    }

    @Override
    public int hashCode() {
      return (id + name + hist).hashCode();
    }
  }
}