2 Replies Latest reply on May 22, 2008 7:38 AM by Ales Justin

    JBVFS-26 - Optimizing the VFS PathTokenizer

    Adrian Brock Master

      It looks to me that the problem with the PathTokenizer
      (and the related findChild() is all the string comparisons.

       public static String[] getTokens(String path)
       {
       if (path == null)
       throw new IllegalArgumentException("Null path");
      
       StringTokenizer tokenizer = new StringTokenizer(path, "/");
       int count = tokenizer.countTokens();
       if (count == 0)
       return null;
      
       String[] tokens = new String[count];
       int i = 0;
       while (tokenizer.hasMoreTokens())
       {
       String token = tokenizer.nextToken();
      
       if ("".equals(token))
       throw new IllegalArgumentException("A path element is empty: " + path);
      
       tokens[i++] = token;
       }
       return tokens;
       }
      
       /**
       * Is current token.
       *
       * @param token the token to check
       * @return true if token matches current path token
       */
       public static boolean isCurrentToken(String token)
       {
       return CURRENT_PATH.equals(token);
       }
      
       /**
       * Is reverse token.
       *
       * @param token the token to check
       * @return true if token matches reverse path token
       */
       public static boolean isReverseToken(String token)
       {
       return REVERSE_PATH.equals(token);
       }
      


      1) If StringTokenizer was replaced with an optimized lexer
      (e.g. like the one used to parse system property references from strings in common-core)
      then the check for an empty token could be done inline instead of string
      comparison.

      2) Similarly the usage of "." and ".." as tokens could be optimized to
      return the singleton reference of these strings in the token array.
      The code then check for object equality, e.g.

       public static boolean isCurrentToken(String token)
       {
      -- return CURRENT_PATH.equals(token);
      ++ return CURRENT_PATH == token;
       }
      


      It's worth while optimizing this code since it is showing up as a hotspot.
      It will be hotspot at runtime as well (not just boot time) since this code
      gets invoked on every classloading request (that isn't to a previously cached
      or blacklisted class) - since the classloader uses the VFS.

        • 1. Re: JBVFS-26 - Optimizing the VFS PathTokenizer
          Ales Justin Master

          OK, I'll look into both, 1) and 2).
          Should be included in the next VFS version.

          • 2. Re: JBVFS-26 - Optimizing the VFS PathTokenizer
            Ales Justin Master

             

            "adrian@jboss.org" wrote:

            1) If StringTokenizer was replaced with an optimized lexer
            (e.g. like the one used to parse system property references from strings in common-core)
            then the check for an empty token could be done inline instead of string
            comparison.

            This is now rewritten into this:
             public static String[] getTokens(String path)
             {
             if (path == null)
             throw new IllegalArgumentException("Null path");
            
             char[] chars = path.toCharArray();
             StringBuilder buffer = new StringBuilder();
             List<String> list = new ArrayList<String>();
             String specialToken = null;
            
             for (int index=0; index < chars.length; index++)
             {
             char ch = chars[index];
            
             if (ch == '/')
             {
             if (index > 0)
             {
             if (buffer.length() == 0 && specialToken == null)
             throw new IllegalArgumentException("A path element is empty: " + path);
            
             if (specialToken != null)
             list.add(specialToken);
             else
             list.add(buffer.toString());
            
             // reset
             buffer.setLength(0);
             specialToken = null;
             }
             }
             else if (ch == '.')
             {
             if (specialToken == null && buffer.length() == 0)
             specialToken = CURRENT_PATH;
             else if (specialToken == CURRENT_PATH && buffer.length() == 0)
             specialToken = REVERSE_PATH;
             else if (specialToken != null && buffer.length() == 0)
             throw new IllegalArgumentException("Illegal token in path: " + path);
             else
             buffer.append(ch);
             }
             else
             {
             // token starts with '.' or '..', but also has some path after that
             if (specialToken != null)
             throw new IllegalArgumentException("Illegal token in path: " + path);
            
             buffer.append(ch);
             }
             }
            
             // add last token
             if (specialToken != null)
             list.add(specialToken);
             else if (buffer.length() > 0)
             list.add(buffer.toString());
            
             return list.toArray(new String[list.size()]);
             }
            

            and we do '==' check on special tokens. ;-)