mirror of
https://github.com/internetarchive/heritrix3.git
synced 2026-09-26 07:35:39 +00:00
Minimize transient garbage creation identified by allocation profiling
* UURIFactory, canonicalize/**, PathologicalPathDecideRule, ExtractorHTML
use recycled matchers via TextUtils
* CrawlURI, KeyedProperties, OverlayContext, SheetOverlaysManager
use ArrayList and indexed access rather than LinkedList and iterator instances
This commit is contained in:
@@ -372,17 +372,20 @@ public class UURIFactory extends URI {
|
||||
// Test for the case of more than two slashes after the http(s) scheme.
|
||||
// Replace with two slashes as mozilla does if found.
|
||||
// See [ 788219 ] URI Syntax Errors stop page parsing.
|
||||
Matcher matcher = HTTP_SCHEME_SLASHES.matcher(uri);
|
||||
// Matcher matcher = HTTP_SCHEME_SLASHES.matcher(uri);
|
||||
Matcher matcher = TextUtils.getMatcher(HTTP_SCHEME_SLASHES.pattern(), uri);
|
||||
if (matcher.matches()) {
|
||||
uri = matcher.group(1) + matcher.group(2);
|
||||
}
|
||||
TextUtils.recycleMatcher(matcher);
|
||||
|
||||
// now, minimally escape any whitespace
|
||||
uri = escapeWhitespace(uri);
|
||||
|
||||
// For further processing, get uri elements. See the RFC2396REGEX
|
||||
// comment above for explanation of group indices used in the below.
|
||||
matcher = RFC2396REGEX.matcher(uri);
|
||||
// matcher = RFC2396REGEX.matcher(uri);
|
||||
matcher = TextUtils.getMatcher(RFC2396REGEX.pattern(), uri);
|
||||
if (!matcher.matches()) {
|
||||
throw new URIException("Failed parse of " + uri);
|
||||
}
|
||||
@@ -392,6 +395,7 @@ public class UURIFactory extends URI {
|
||||
String uriPath = checkUriElement(matcher.group(6));
|
||||
String uriQuery = checkUriElement(matcher.group(8));
|
||||
// UNUSED String uriFragment = checkUriElement(matcher.group(10));
|
||||
TextUtils.recycleMatcher(matcher); matcher = null;
|
||||
|
||||
// Test if relative URI. If so, need a base to resolve against.
|
||||
if (uriScheme == null || uriScheme.length() <= 0) {
|
||||
@@ -701,7 +705,8 @@ public class UURIFactory extends URI {
|
||||
*/
|
||||
private String checkPort(String uriAuthority)
|
||||
throws URIException {
|
||||
Matcher m = PORTREGEX.matcher(uriAuthority);
|
||||
// Matcher m = PORTREGEX.matcher(uriAuthority);
|
||||
Matcher m = TextUtils.getMatcher(PORTREGEX.pattern(), uriAuthority);
|
||||
if (m.matches()) {
|
||||
String no = m.group(2);
|
||||
if (no != null && no.length() > 0) {
|
||||
@@ -726,6 +731,7 @@ public class UURIFactory extends URI {
|
||||
}
|
||||
}
|
||||
}
|
||||
TextUtils.recycleMatcher(m);
|
||||
return uriAuthority;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -56,19 +55,21 @@ public class KeyedProperties extends ConcurrentHashMap<String,Object> {
|
||||
* @return discovered override, or local value
|
||||
*/
|
||||
public Object get(String key) {
|
||||
if(!threadOverrides.get().isEmpty()) {
|
||||
for(OverlayContext ocontext: threadOverrides.get()) {
|
||||
for(String name: ocontext.getOverlayNames()) {
|
||||
Map<String,Object> m = ocontext.getOverlayMap(name);
|
||||
for(String ok : getOverrideKeys(key)) {
|
||||
Object val = m.get(ok);
|
||||
if(val!=null) {
|
||||
return val;
|
||||
}
|
||||
ArrayList<OverlayContext> overlays = threadOverrides.get();
|
||||
for(int i = overlays.size()-1; i>=0; i--) {
|
||||
OverlayContext ocontext = overlays.get(i);
|
||||
for(int j = ocontext.getOverlayNames().size()-1; j>=0; j--) {
|
||||
String name = ocontext.getOverlayNames().get(j);
|
||||
Map<String,Object> m = ocontext.getOverlayMap(name);
|
||||
for(String ok : getOverrideKeys(key)) {
|
||||
Object val = m.get(ok);
|
||||
if(val!=null) {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.get(key);
|
||||
}
|
||||
|
||||
@@ -95,10 +96,10 @@ public class KeyedProperties extends ConcurrentHashMap<String,Object> {
|
||||
/**
|
||||
* ThreadLocal (contextual) collection of pushed override maps
|
||||
*/
|
||||
static ThreadLocal<LinkedList<OverlayContext>> threadOverrides =
|
||||
new ThreadLocal<LinkedList<OverlayContext>>() {
|
||||
protected LinkedList<OverlayContext> initialValue() {
|
||||
return new LinkedList<OverlayContext>();
|
||||
static ThreadLocal<ArrayList<OverlayContext>> threadOverrides =
|
||||
new ThreadLocal<ArrayList<OverlayContext>>() {
|
||||
protected ArrayList<OverlayContext> initialValue() {
|
||||
return new ArrayList<OverlayContext>();
|
||||
}
|
||||
};
|
||||
/**
|
||||
@@ -106,7 +107,7 @@ public class KeyedProperties extends ConcurrentHashMap<String,Object> {
|
||||
* @param m Map to add
|
||||
*/
|
||||
static public void pushOverrideContext(OverlayContext ocontext) {
|
||||
threadOverrides.get().addFirst(ocontext);
|
||||
threadOverrides.get().add(ocontext);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -115,7 +116,7 @@ public class KeyedProperties extends ConcurrentHashMap<String,Object> {
|
||||
*/
|
||||
static public OverlayContext popOverridesContext() {
|
||||
// TODO maybe check that pop is as expected
|
||||
return threadOverrides.get().removeFirst();
|
||||
return threadOverrides.get().remove(threadOverrides.get().size()-1);
|
||||
}
|
||||
|
||||
static public void clearAllOverrideContexts() {
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
package org.archive.spring;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -32,7 +32,7 @@ public interface OverlayContext {
|
||||
* (even if in fact no overlays were added) */
|
||||
public boolean haveOverlayNamesBeenSet();
|
||||
/** return a list of the names of overlay maps to consider */
|
||||
LinkedList<String> getOverlayNames();
|
||||
ArrayList<String> getOverlayNames();
|
||||
/** get the map corresponding to the overlay name */
|
||||
Map<String,Object> getOverlayMap(String name);
|
||||
}
|
||||
|
||||
@@ -315,7 +315,7 @@ BeanFactoryAware, OverlayMapsSource, ApplicationListener {
|
||||
List<String> foundPrefixes = PrefixFinder.findKeys(sheetNamesBySurt, effectiveSurt);
|
||||
for(String prefix : foundPrefixes) {
|
||||
for(String name : sheetNamesBySurt.get(prefix)) {
|
||||
curi.getOverlayNames().push(name);
|
||||
curi.getOverlayNames().add(name);
|
||||
}
|
||||
}
|
||||
// apply deciderule-based overlays
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.util.regex.Matcher;
|
||||
|
||||
import org.archive.spring.HasKeyedProperties;
|
||||
import org.archive.spring.KeyedProperties;
|
||||
import org.archive.util.TextUtils;
|
||||
|
||||
/**
|
||||
* Base of all rules applied canonicalizing a URL that are configurable
|
||||
@@ -36,6 +37,7 @@ import org.archive.spring.KeyedProperties;
|
||||
*/
|
||||
public abstract class BaseRule
|
||||
implements CanonicalizationRule, Serializable, HasKeyedProperties {
|
||||
private static final long serialVersionUID = 1L;
|
||||
protected KeyedProperties kp = new KeyedProperties();
|
||||
public KeyedProperties getKeyedProperties() {
|
||||
return kp;
|
||||
@@ -69,10 +71,13 @@ implements CanonicalizationRule, Serializable, HasKeyedProperties {
|
||||
* @return Original <code>url</code> else concatenization of group 1
|
||||
* and group 2.
|
||||
*/
|
||||
protected String doStripRegexMatch(String url, Matcher matcher) {
|
||||
return (matcher != null && matcher.matches())?
|
||||
protected String doStripRegexMatch(String url, String pat) {
|
||||
Matcher matcher = TextUtils.getMatcher(pat, url);
|
||||
String retVal = (matcher != null && matcher.matches())?
|
||||
checkForNull(matcher.group(1)) + checkForNull(matcher.group(2)):
|
||||
url;
|
||||
TextUtils.recycleMatcher(matcher);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -58,7 +58,7 @@ extends BaseRule {
|
||||
}
|
||||
|
||||
public String canonicalize(String url) {
|
||||
return doStripRegexMatch(url, COLDFUSION_PATTERN.matcher(url));
|
||||
return doStripRegexMatch(url, COLDFUSION_PATTERN.pattern());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -70,9 +70,9 @@ extends BaseRule {
|
||||
}
|
||||
|
||||
public String canonicalize(String url) {
|
||||
url = doStripRegexMatch(url, BASE_PATTERN.matcher(url));
|
||||
url = doStripRegexMatch(url, SID_PATTERN.matcher(url));
|
||||
url = doStripRegexMatch(url, ASPSESSION_PATTERN.matcher(url));
|
||||
url = doStripRegexMatch(url, BASE_PATTERN.pattern());
|
||||
url = doStripRegexMatch(url, SID_PATTERN.pattern());
|
||||
url = doStripRegexMatch(url, ASPSESSION_PATTERN.pattern());
|
||||
return url;
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,6 @@ public class StripUserinfoRule extends BaseRule {
|
||||
}
|
||||
|
||||
public String canonicalize(String url) {
|
||||
return doStripRegexMatch(url, REGEX.matcher(url));
|
||||
return doStripRegexMatch(url, REGEX.pattern());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,6 @@ public class StripWWWNRule extends BaseRule {
|
||||
}
|
||||
|
||||
public String canonicalize(String url) {
|
||||
return doStripRegexMatch(url, REGEX.matcher(url));
|
||||
return doStripRegexMatch(url, REGEX.pattern());
|
||||
}
|
||||
}
|
||||
@@ -49,6 +49,6 @@ public class StripWWWRule extends BaseRule {
|
||||
}
|
||||
|
||||
public String canonicalize(String url) {
|
||||
return doStripRegexMatch(url, REGEX.matcher(url));
|
||||
return doStripRegexMatch(url, REGEX.pattern());
|
||||
}
|
||||
}
|
||||
|
||||
+13
-27
@@ -18,10 +18,10 @@
|
||||
*/
|
||||
package org.archive.modules.deciderules;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
import org.archive.modules.CrawlURI;
|
||||
import org.archive.util.TextUtils;
|
||||
|
||||
|
||||
/**
|
||||
@@ -48,8 +48,6 @@ public class PathologicalPathDecideRule extends DecideRule {
|
||||
public void setMaxRepetitions(int maxRepetitions) {
|
||||
kp.put("maxRepetitions", maxRepetitions);
|
||||
}
|
||||
|
||||
private AtomicReference<Pattern> pattern = new AtomicReference<Pattern>();
|
||||
|
||||
/** Constructs a new PathologicalPathFilter.
|
||||
*
|
||||
@@ -62,31 +60,19 @@ public class PathologicalPathDecideRule extends DecideRule {
|
||||
@Override
|
||||
protected DecideResult innerDecide(CrawlURI uri) {
|
||||
int maxRep = getMaxRepetitions();
|
||||
Pattern p = getPattern(maxRep);
|
||||
if (p.matcher(uri.getUURI().toString()).matches()) {
|
||||
return DecideResult.REJECT;
|
||||
} else {
|
||||
return DecideResult.NONE;
|
||||
// Pattern p = getPattern(maxRep);
|
||||
Matcher m = TextUtils.getMatcher(constructRegex(maxRep), uri.getUURI().toString());
|
||||
try {
|
||||
if (m.matches()) {
|
||||
return DecideResult.REJECT;
|
||||
} else {
|
||||
return DecideResult.NONE;
|
||||
}
|
||||
} finally {
|
||||
TextUtils.recycleMatcher(m);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the regex string to be matched against the URI.
|
||||
* @param o an object to extract a URI from.
|
||||
* @return the regex pattern.
|
||||
*/
|
||||
private Pattern getPattern(int maxRep) {
|
||||
// race no concern: assignment is atomic, happy with any last value
|
||||
Pattern p = pattern.get();
|
||||
if (p != null) {
|
||||
return p;
|
||||
}
|
||||
String regex = constructRegex(maxRep);
|
||||
p = Pattern.compile(regex);
|
||||
pattern.set(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
protected String constructRegex(int rep) {
|
||||
return (rep == 0) ? null : ".*?/(.*?/)\\1{" + rep + ",}.*";
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ import java.util.Iterator;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.httpclient.URIException;
|
||||
import org.archive.io.ReplayCharSequence;
|
||||
@@ -297,8 +296,9 @@ public class ExtractorHTML extends ContentExtractor implements InitializingBean
|
||||
this.metadata = provider;
|
||||
}
|
||||
|
||||
private Pattern relevantTagExtractor;
|
||||
private Pattern eachAttributeExtractor;
|
||||
// TODO: convert to Strings
|
||||
private String relevantTagPattern;
|
||||
private String eachAttributePattern;
|
||||
|
||||
public ExtractorHTML() {
|
||||
}
|
||||
@@ -307,21 +307,21 @@ public class ExtractorHTML extends ContentExtractor implements InitializingBean
|
||||
String regex = RELEVANT_TAG_EXTRACTOR;
|
||||
regex = regex.replace(MAX_ELEMENT_REPLACE,
|
||||
Integer.toString(getMaxElementLength()));
|
||||
this.relevantTagExtractor = Pattern.compile(regex);
|
||||
this.relevantTagPattern = regex;
|
||||
|
||||
regex = EACH_ATTRIBUTE_EXTRACTOR;
|
||||
regex = regex.replace(MAX_ATTR_NAME_REPLACE,
|
||||
Integer.toString(getMaxAttributeNameLength()));
|
||||
regex = regex.replace(MAX_ATTR_VAL_REPLACE,
|
||||
Integer.toString(getMaxAttributeValLength()));
|
||||
this.eachAttributeExtractor = Pattern.compile(regex);
|
||||
this.eachAttributePattern = regex;
|
||||
}
|
||||
|
||||
|
||||
protected void processGeneralTag(CrawlURI curi, CharSequence element,
|
||||
CharSequence cs) {
|
||||
|
||||
Matcher attr = eachAttributeExtractor.matcher(cs);
|
||||
Matcher attr = TextUtils.getMatcher(eachAttributePattern,cs);
|
||||
|
||||
// Just in case it's an OBJECT or APPLET tag
|
||||
String codebase = null;
|
||||
@@ -687,7 +687,7 @@ public class ExtractorHTML extends ContentExtractor implements InitializingBean
|
||||
* of this extractors' lifetime.
|
||||
*/
|
||||
void extract(CrawlURI curi, CharSequence cs) {
|
||||
Matcher tags = relevantTagExtractor.matcher(cs);
|
||||
Matcher tags = TextUtils.getMatcher(relevantTagPattern,cs);
|
||||
while(tags.find()) {
|
||||
if(Thread.interrupted()){
|
||||
break;
|
||||
@@ -801,7 +801,7 @@ public class ExtractorHTML extends ContentExtractor implements InitializingBean
|
||||
* @return True robots exclusion metatag.
|
||||
*/
|
||||
protected boolean processMeta(CrawlURI curi, CharSequence cs) {
|
||||
Matcher attr = eachAttributeExtractor.matcher(cs);
|
||||
Matcher attr = TextUtils.getMatcher(eachAttributePattern,cs);
|
||||
String name = null;
|
||||
String httpEquiv = null;
|
||||
String content = null;
|
||||
|
||||
Reference in New Issue
Block a user