Package nginx.clojure.wave

Source Code of nginx.clojure.wave.MethodDatabaseUtil

/**
*  Copyright (C) Zhang,Yuexiang (xfeep)
*
*/
package nginx.clojure.wave;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import nginx.clojure.asm.ClassReader;
import nginx.clojure.asm.tree.analysis.Analyzer;
import nginx.clojure.wave.MethodDatabase.ClassEntry;
import nginx.clojure.wave.MethodDatabase.FuzzyLazyClassEntry;
import nginx.clojure.wave.MethodDatabase.LazyClassEntry;

public class MethodDatabaseUtil {

  public final static Pattern FUZZY_CLASS_PATTERN = Pattern.compile("(\\d+)");

  public MethodDatabaseUtil() {
  }
 
  //eg. load(db, "nginx/clojure/wave/coroutine-method-db.txt")
  public static void load(MethodDatabase db, String resource) throws IOException {
    InputStream in = null;
    try {
      in = Thread.currentThread().getContextClassLoader().getResourceAsStream(resource);
      if (in == null) {
        throw new IOException("can not load resource [" + resource + "] from classpath");
      }
      BufferedReader r = new BufferedReader(new InputStreamReader(in, MethodDatabase.UTF_8));
      db.getUserDefinedWaveConfigFiles().add(resource);
      String l = null;
      ClassEntry ce = null;
      LazyClassEntry lce = null;
      FuzzyLazyClassEntry flce = null;
      int lc = 0;
      String clz = null;
      while ((l = r.readLine()) != null) {
        lc++;
        l = l.trim();
        if (l.startsWith("class:")) {
          lce = null;
          flce = null;
          clz = l.substring("class:".length());
          ce = db.getClasses().get(clz);
          if (ce == null) {
            ce = buildClassEntryFamily(db, clz);
            if (ce == null) {
              db.warn("file %s line %d : not found class: %s", resource , lc,  clz);
              ce = null;
              continue;
            }
          }
        }else if (l.startsWith("lazyclass:")) {
          clz = l.substring("lazyclass:".length());
          ce = null;
          flce = null;
          lce = db.getLazyClasses().get(clz);
          if (lce == null) {
            db.getLazyClasses().put(clz, lce = new LazyClassEntry(resource));
          }
        }else if (l.startsWith("fuzzyclass:")) {
          clz = l.substring("fuzzyclass:".length());
          ce = null;
          lce = null;
          flce = new FuzzyLazyClassEntry(Pattern.compile(clz), resource);
          db.getFuzzlyLazyClasses().add(flce);
        }else if (l.startsWith("retransform:")) {
          db.getRetransformedClasses().add(l.substring("retransform:".length()).trim());
          ce = null;
          lce = null;
          flce = null;
        }else if (l.startsWith("filter:")) {
          db.getFilters().add(l.substring("filter:".length()).trim());
          ce = null;
          lce = null;
          flce = null;
        }else if (l.length() == 0 || (ce == null && lce == null && flce == null) || l.charAt(0) == '#'){
          continue;
        }else {
          String[] ma = l.split(":");
          String m = ma[0];
          Integer st = MethodDatabase.SUSPEND_NORMAL;
          if (ma.length > 1) {
            if (MethodDatabase.SUSPEND_NORMAL_STR.equals(ma[1])) {
              st = MethodDatabase.SUSPEND_NORMAL;
            }else if (MethodDatabase.SUSPEND_NONE_STR.equals(ma[1])) {
              st = MethodDatabase.SUSPEND_NONE;
            }else if (MethodDatabase.SUSPEND_JUST_MARK_STR.equals(ma[1])) {
              st = MethodDatabase.SUSPEND_JUST_MARK;
            }else if (MethodDatabase.SUSPEND_BLOCKING_STR.equals(ma[1])) {
              st = MethodDatabase.SUSPEND_BLOCKING;
            }else if (MethodDatabase.SUSPEND_FAMILY_STR.equals(ma[1])) {
              st = MethodDatabase.SUSPEND_FAMILY;
            }else if (MethodDatabase.SUSPEND_SKIP_STR.equals(ma[1])) {
              st = MethodDatabase.SUSPEND_SKIP;
            }else {
              db.warn("file %s line %d : unknown suspend type: %s , we just set to 'normal'", resource , lc, ma[1]);
              st = MethodDatabase.SUSPEND_NORMAL;
            }
          }
          if (lce != null) {
            Map<String, Integer> methods = lce.getMethods();
            Integer ost = methods.get(m);
            if (ost == null || st.intValue() > ost.intValue()) {
              methods.put(m, st);
            }else {
              st = ost;
            }
            if (db.meetTraceTargetClassMethod(clz, m)) {
              db.info("meet traced method %s.%s, suspend type = %s", clz, m, MethodDatabase.SUSPEND_TYPE_STRS[st]);
            }
            continue;
          }else if (flce != null) {
            Map<String, Integer> methods = flce.getMethods();
            Integer ost = methods.get(m);
            if (ost == null || st.intValue() > ost.intValue()) {
              methods.put(m, st);
            }else {
              st = ost;
            }
            if (db.meetTraceTargetClassMethod(clz, m)) {
              db.info("meet traced method %s.%s, suspend type = %s", clz, m, MethodDatabase.SUSPEND_TYPE_STRS[st]);
            }
            continue;
          }
          if (m.charAt(0) == '/') { // regex pattern
            Pattern p = Pattern.compile(m.substring(1));
            boolean matched = false;
            for (Entry<String, Integer> me : ce.getMethods().entrySet()) {
              if (p.matcher(me.getKey()).find()) {
                me.setValue(st);
                matched = true;
              }
            }
            if (!matched) {
              db.warn("file %s line %d : none of methods matched regex: %s ,ignored", resource , lc, m);
            }
          }else if (ce.getMethods().get(m) == null) {
            db.warn("file %s line %d : unknown method: %s ,ignored", resource , lc, m);
            continue;
          }else {
            Integer ost = ce.getMethods().get(m);
            if (ost == null || st.intValue() > ost.intValue()) {
              ce.set(m, st);
            }else {
              st = ost;
            }
            if (db.meetTraceTargetClassMethod(clz, m)) {
              db.info("meet traced method %s.%s, suspend type = %s", clz, m, MethodDatabase.SUSPEND_TYPE_STRS[st]);
            }
          }
        }
      }
      if (db.isDebugEnabled()) {
        MethodDatabase.getLog().debug("total filters:" + db.getFilters());
      }
    }finally {
      if (in != null) {
        in.close();
      }
    }
   
   
  }
 
  public static String toFuzzyString(Pattern p, String s, String rep) {
    Matcher m = p.matcher(s);
    int start = 0;
    StringBuilder rt = new StringBuilder();
    while (m.find()) {
      rt.append(Matcher.quoteReplacement(s.substring(start, m.start())));
      rt.append(rep);
      start = m.end();
    }
    if (rt.length() == 0){
      return null;
    }
    if (start < s.length()) {
      rt.append(s.substring(start));
    }
    return rt.toString();
  }
 
  public static ClassEntry buildClassEntryFamily(MethodDatabase db, ClassReader r) {
    ClassEntry ce = db.getClasses().get(r.getClassName());
    if (ce == null) {
      CheckInstrumentationVisitor civ = db.checkClass(r);
      return buildClassEntryFamily(db, civ);
    }
    return ce;
  }
 
  public static Analyzer buildAnalyzer(MethodDatabase db) {
     return new TypeAnalyzer(new TypeInterpreter(db));
//    SimpleVerifier sv = new TypeInterpreter(db);//new SimpleVerifier();
//    sv.setClassLoader(Thread.currentThread().getContextClassLoader());
//    return new TypeAnalyzer(sv);
  }
 
  public static void mergeMethodsSuspendTypeFromSuper(ClassEntry ce, ClassEntry sce) {
    if (ce == null || sce == null) {
      return;
    }
    Map<String, Integer> sms = sce.getMethods();
    for (Entry<String, Integer> me : ce.getMethods().entrySet()) {
      Integer st = me.getValue();
      if (st == MethodDatabase.SUSPEND_NONE) {
        Integer sst = sms.get(me.getKey());
        if (sst != null && sst != MethodDatabase.SUSPEND_NONE) {
          me.setValue(sst);
        }
      }
    }
  }
 
  public static ClassEntry buildClassEntryFamily(MethodDatabase db, CheckInstrumentationVisitor civ) {
    ClassEntry ce = civ.getClassEntry();
    String clz = civ.getName();
    LazyClassEntry lce = db.getLazyClasses().get(clz);
   
    if (lce != null) {
      db.debug("rebuild wave info for lazy class %s", clz);
      for (Entry<String, Integer> lme : lce.getMethods().entrySet()) {
        String m = lme.getKey();
        Integer st = lme.getValue();
        if (m.charAt(0) == '/') { // regex pattern
          Pattern p = Pattern.compile(m.substring(1));
          boolean matched = false;
          for (Entry<String, Integer> me : ce.getMethods().entrySet()) {
            if (p.matcher(me.getKey()).find()) {
              me.setValue(st);
              matched = true;
            }
          }
          if (!matched) {
            db.warn("file %s lazy class %s: none of methods matched regex: %s ,ignored", lce.getResource() , clz, m);
          }
        }else if (ce.getMethods().get(m) == null) {
          db.warn("file %s lazy class %s:  : unknown method: %s ,ignored", lce.getResource() , clz, m);
          continue;
        }else {
          Integer ost = ce.getMethods().get(m);
          if (ost == null || st.intValue() > ost.intValue()) {
            ce.set(m, st);
          }
        }
      }
    }
   
    if (FUZZY_CLASS_PATTERN.matcher(clz).find()) {
      for (FuzzyLazyClassEntry flce : db.getFuzzlyLazyClasses()) {
        if (flce.getPattern().matcher(clz).find()) {
          db.debug("rebuild wave info for fuzzylazy class %s, pattern %s", clz, flce.getPattern().toString());
          for (Entry<String, Integer> lme : flce.getMethods().entrySet()) {
            String m = lme.getKey();
            Integer st = lme.getValue();
            if (m.charAt(0) == '/') { // regex pattern
              Pattern p = Pattern.compile(m.substring(1));
              boolean matched = false;
              for (Entry<String, Integer> me : ce.getMethods().entrySet()) {
                if (p.matcher(me.getKey()).find()) {
                  me.setValue(st);
                  matched = true;
                }
              }
              if (!matched) {
                db.warn("file %s fuzzylazy class %s: none of methods matched regex: %s ,ignored", flce.getResource() , clz, m);
              }
            }else if (ce.getMethods().get(m) == null) {
              db.warn("file %s fuzzylazy class %s:  : unknown method: %s ,ignored", flce.getResource() , clz, m);
              continue;
            }else {
              Integer ost = ce.getMethods().get(m);
              if (ost == null || st.intValue() > ost.intValue()) {
                ce.set(m, st);
              }
            }
          }
        }
      }
    }
   
    String superName = ce.getSuperName();
    db.recordSuspendableMethods(clz, ce);
   
    if (superName != null) {
      ClassEntry sce = db.getClasses().get(superName);
      if (sce == null) {
        CheckInstrumentationVisitor sciv = db.checkClass(superName);
        if (sciv == null) {
          db.error("super class %s can not visited", superName);
        }else {
          sce = buildClassEntryFamily(db, sciv);
          db.recordSuspendableMethods(superName, sce);
        }
      }
     
      mergeMethodsSuspendTypeFromSuper(ce, sce);
    }
   
    String[] interfaces = ce.getInterfaces();
    if (interfaces != null) {
      for (String itf : interfaces) {
        ClassEntry sce = db.getClasses().get(itf);
        if (sce == null) {
          CheckInstrumentationVisitor sciv = db.checkClass(itf);
          if (sciv == null) {
            return null;
          }
          sce = buildClassEntryFamily(db, sciv);
          db.recordSuspendableMethods(itf, sce);
        }
        mergeMethodsSuspendTypeFromSuper(ce, sce);
      }
    }
    return ce;
  }
 
  public static ClassEntry buildClassEntryFamily(MethodDatabase db, String name) {
    ClassEntry ce = db.getClasses().get(name);
    if (ce == null) {
      CheckInstrumentationVisitor civ = db.checkClass(name);
      if (civ == null) {
        return null;
      }
      return buildClassEntryFamily(db, civ);
    }
    return ce;
  }


}
TOP

Related Classes of nginx.clojure.wave.MethodDatabaseUtil

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.