From 6193e487c8806a0962041efc7c24bb6a8a20e553 Mon Sep 17 00:00:00 2001 From: zzz Date: Mon, 12 Feb 2018 18:49:01 +0000 Subject: [PATCH] Util: Add sort methods that catch IAE --- .../org/klomp/snark/web/I2PSnarkServlet.java | 7 +-- .../src/src/i2p/susi/util/Folder.java | 4 +- core/java/src/net/i2p/data/DataHelper.java | 53 +++++++++++++++++++ .../i2p/router/tunnel/pool/BuildExecutor.java | 9 ++-- 4 files changed, 61 insertions(+), 12 deletions(-) diff --git a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java index 258dc7065..c5f1ca00e 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java +++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java @@ -1490,11 +1490,8 @@ public class I2PSnarkServlet extends BasicServlet { Sorters.setPattern(Translate.getLanguage(_manager.util().getContext())); else Sorters.setPattern(null); - try { - Collections.sort(rv, Sorters.getComparator(sort, this)); - } catch (IllegalArgumentException iae) { - // Java 7 TimSort - may be unstable - } + // Java 7 TimSort - may be unstable + DataHelper.sort(rv, Sorters.getComparator(sort, this)); } return rv; } diff --git a/apps/susimail/src/src/i2p/susi/util/Folder.java b/apps/susimail/src/src/i2p/susi/util/Folder.java index 2b87b9271..e874b75bb 100644 --- a/apps/susimail/src/src/i2p/susi/util/Folder.java +++ b/apps/susimail/src/src/i2p/susi/util/Folder.java @@ -34,6 +34,8 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import net.i2p.data.DataHelper; + /** * Folder object manages a array Object[] to support * paging and sorting. @@ -160,7 +162,7 @@ public class Folder { public synchronized void sort() { if (currentSorter != null && elements != null && elements.length > 1) - Arrays.sort( elements, currentSorter ); + DataHelper.sort(elements, currentSorter); } /** diff --git a/core/java/src/net/i2p/data/DataHelper.java b/core/java/src/net/i2p/data/DataHelper.java index 0cf7adbba..15bc0eb7b 100644 --- a/core/java/src/net/i2p/data/DataHelper.java +++ b/core/java/src/net/i2p/data/DataHelper.java @@ -29,9 +29,12 @@ import java.security.MessageDigest; import java.text.DecimalFormat; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Properties; @@ -1997,4 +2000,54 @@ public class DataHelper { cache.release(ba); } } + + /** + * Same as Collections.sort(), but guaranteed not to throw an IllegalArgumentException if the + * sort is unstable. As of Java 7, TimSort will throw an IAE if the underlying sort order + * changes during the sort. + * + * This catches the IAE, retries once, and then returns. + * If an IAE is thrown twice, this method will return, with the list possibly unsorted. + * + * @param list the list to be sorted. + * @param c the comparator to determine the order of the list. A null value indicates that the elements' natural ordering should be used. + * @since 0.9.34 + */ + public static void sort(List list, Comparator c) { + try { + Collections.sort(list, c); + } catch (IllegalArgumentException iae1) { + try { + Thread.sleep(5); + } catch (InterruptedException ie) {} + try { + Collections.sort(list, c); + } catch (IllegalArgumentException iae2) {} + } + } + + /** + * Same as Arrays.sort(), but guaranteed not to throw an IllegalArgumentException if the + * sort is unstable. As of Java 7, TimSort will throw an IAE if the underlying sort order + * changes during the sort. + * + * This catches the IAE, retries once, and then returns. + * If an IAE is thrown twice, this method will return, with the array possibly unsorted. + * + * @param a the array to be sorted. + * @param c the comparator to determine the order of the array. A null value indicates that the elements' natural ordering should be used. + * @since 0.9.34 + */ + public static void sort(T[] a, Comparator c) { + try { + Arrays.sort(a, c); + } catch (IllegalArgumentException iae1) { + try { + Thread.sleep(5); + } catch (InterruptedException ie) {} + try { + Arrays.sort(a, c); + } catch (IllegalArgumentException iae2) {} + } + } } diff --git a/router/java/src/net/i2p/router/tunnel/pool/BuildExecutor.java b/router/java/src/net/i2p/router/tunnel/pool/BuildExecutor.java index 1705bf29b..5f59a8d39 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/BuildExecutor.java +++ b/router/java/src/net/i2p/router/tunnel/pool/BuildExecutor.java @@ -8,6 +8,7 @@ import java.util.Iterator; import java.util.List; import java.util.concurrent.ConcurrentHashMap; +import net.i2p.data.DataHelper; import net.i2p.data.Hash; import net.i2p.data.i2np.I2NPMessage; import net.i2p.data.router.RouterInfo; @@ -382,12 +383,8 @@ class BuildExecutor implements Runnable { // to the front of the line sometimes, to prevent being "locked up" // for several minutes. boolean preferEmpty = _context.random().nextInt(4) != 0; - try { - Collections.sort(wanted, new TunnelPoolComparator(preferEmpty)); - } catch (IllegalArgumentException iae) { - // Java 7 TimSort - see info in TunnelPoolComparator - continue; - } + // Java 7 TimSort - see info in TunnelPoolComparator + DataHelper.sort(wanted, new TunnelPoolComparator(preferEmpty)); } // force the loops to be short, since 3 consecutive tunnel build requests can take