The JIRA <https://issues.apache.org/jira/browse/TRINIDAD-2013> has the complete story, but the basic issue is that operations that create keys representing the ancestors of TreeModel keys can currently only get those keys by essentially recursively calling TreeModel.getContainerRowKey(). For list-based keys, this creates deeply nested subLists. When these keys are used as keys into a HashMap, the resulting behavior is n^3. For example, adding each of the keys in a 374 element-deep path to a HashSet resulted in over 800 million calls to ListIterator.next().

The two api parts to the solution are to add another method to TreeModel that subclasses can override for greater efficiency:

And also allow immutable lists to cache their hash codes with:

  /**
* Returns the nth ancestor rowKey or <code>null</code> if no such ancestor exists. * This is more efficient than calling <code>getContainerRowKey(Object)</code>
   * on each rowKey in turn.
   * <p>
   * If generationFromChild is 0, the childRowKey will be returned.
   * <p>
* While for backwards compatibility, <code>getAncestorRowKey</code> is implemented in terms * of <code>getContainerRowKey</code>, Path-based subclasses should implement * <code>getContainerRowKey</code> in terms of <code>getAncestorRowKey</code> to avoid
   * creating deeply nested sublists of keys.
   * @param childRowKey
   * @param generationFromChild
* @return the nth ancestor rowKey or <code>null</code> if no such ancestor exists
   * @throws NullPointerException if childRowKey is <code>null</code>
   * @throws IllegalArgumentException if generationFromChild is less than 0
   * @see #getContainerRowKey
   */
public Object getAncestorRowKey(Object childRowKey, int generationFromChild)

in TreeModel


 /**
* Returns a new immutable wrapper list based on an existing list <code>l</code>.
   * <p>
   * Once an immutable wrapper has been created on <code>l</code>, neither
   * <code>l</code> nor the contents of List <code>l</code> may be changed.
   * <p>
   * In return for this restriction, the immutable List offers much faster
   * implementations of operations such as <code>hashCode</code> and
* <code>subList</code>. This makes the instances returned for use as keys into * Sets or Maps, especially since the immutability restrictions are identical.
   * @param l The List to create an immutable wrapper on
   * @return A new immutable list on <code>l</code>
   * @throws NullPointerException if <code>l</code> is null.
   */
  public static <T> List<? extends T> newImmutableList(List<? extends T> l)

in org.apache.myfaces.trinidad.util.CollectionUtils

-- Blake Sullivan

Reply via email to