SOLR-9657: Use cache for templates

This commit is contained in:
Noble Paul 2016-10-20 20:06:21 +05:30
parent 14b6d93db4
commit 127bf9f772
5 changed files with 92 additions and 60 deletions

View File

@ -25,6 +25,8 @@ import java.util.function.Function;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.apache.solr.common.util.Cache;
import org.apache.solr.common.util.MapBackedCache;
import org.apache.solr.update.processor.TemplateUpdateProcessorFactory; import org.apache.solr.update.processor.TemplateUpdateProcessorFactory;
import static org.apache.solr.update.processor.TemplateUpdateProcessorFactory.Resolved; import static org.apache.solr.update.processor.TemplateUpdateProcessorFactory.Resolved;
@ -55,7 +57,7 @@ public class VariableResolver {
.compile("^(\\w*?)\\((.*?)\\)$"); .compile("^(\\w*?)\\((.*?)\\)$");
private Map<String,Object> rootNamespace; private Map<String,Object> rootNamespace;
private Map<String,Evaluator> evaluators; private Map<String,Evaluator> evaluators;
private Map<String,Resolved> cache = new WeakHashMap<>(); private Cache<String,Resolved> cache = new MapBackedCache<>(new WeakHashMap<>());
private Function<String,Object> fun = this::resolve; private Function<String,Object> fun = this::resolve;
public static final String FUNCTIONS_NAMESPACE = "dataimporter.functions."; public static final String FUNCTIONS_NAMESPACE = "dataimporter.functions.";

View File

@ -20,18 +20,21 @@ package org.apache.solr.update.processor;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.apache.solr.common.SolrInputDocument; import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.util.Cache;
import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.update.AddUpdateCommand; import org.apache.solr.update.AddUpdateCommand;
import org.apache.solr.util.ConcurrentLRUCache;
//Adds new fields to documents based on a template pattern specified via Template.field //Adds new fields to documents based on a template pattern specified via Template.field
// request parameters (multi-valued) or 'field' value specified in initArgs // request parameters (multi-valued) or 'field' value specified in initArgs
public class TemplateUpdateProcessorFactory extends SimpleUpdateProcessorFactory { public class TemplateUpdateProcessorFactory extends SimpleUpdateProcessorFactory {
private Cache<String, Resolved> templateCache = new ConcurrentLRUCache<>(1000, 800, 900, 10, false, false, null);
@Override @Override
protected void process(AddUpdateCommand cmd, SolrQueryRequest req, SolrQueryResponse rsp) { protected void process(AddUpdateCommand cmd, SolrQueryRequest req, SolrQueryResponse rsp) {
String[] vals = getParams("field"); String[] vals = getParams("field");
@ -45,7 +48,7 @@ public class TemplateUpdateProcessorFactory extends SimpleUpdateProcessorFactory
String fName = val.substring(0, idx); String fName = val.substring(0, idx);
String template = val.substring(idx + 1); String template = val.substring(idx + 1);
doc.addField(fName, replaceTokens(template, null, s -> { doc.addField(fName, replaceTokens(template, templateCache, s -> {
Object v = doc.getFieldValue(s); Object v = doc.getFieldValue(s);
return v == null ? "" : v; return v == null ? "" : v;
})); }));
@ -55,7 +58,7 @@ public class TemplateUpdateProcessorFactory extends SimpleUpdateProcessorFactory
} }
public static Resolved getResolved(String template, Map<String, Resolved> cache) { public static Resolved getResolved(String template, Cache<String, Resolved> cache) {
Resolved r = cache == null ? null : cache.get(template); Resolved r = cache == null ? null : cache.get(template);
if (r == null) { if (r == null) {
r = new Resolved(); r = new Resolved();
@ -74,7 +77,7 @@ public class TemplateUpdateProcessorFactory extends SimpleUpdateProcessorFactory
/** /**
* Get a list of variables embedded in the template string. * Get a list of variables embedded in the template string.
*/ */
public static List<String> getVariables(String template, Map<String, Resolved> cache) { public static List<String> getVariables(String template, Cache<String, Resolved> cache) {
Resolved r = getResolved(template, cache); Resolved r = getResolved(template, cache);
if (r == null) { if (r == null) {
return Collections.emptyList(); return Collections.emptyList();
@ -82,7 +85,7 @@ public class TemplateUpdateProcessorFactory extends SimpleUpdateProcessorFactory
return new ArrayList<>(r.variables); return new ArrayList<>(r.variables);
} }
public static String replaceTokens(String template, Map<String, Resolved> cache, Function<String, Object> fun) { public static String replaceTokens(String template, Cache<String, Resolved> cache, Function<String, Object> fun) {
if (template == null) { if (template == null) {
return null; return null;
} }

View File

@ -16,13 +16,31 @@
*/ */
package org.apache.solr.common.util; package org.apache.solr.common.util;
import java.util.Objects;
import java.util.function.Function;
public interface Cache<K, V> { public interface Cache<K, V> {
public V put(K key, V val); V put(K key, V val);
public V get(K key); V get(K key);
public V remove(K key); V remove(K key);
public void clear(); void clear();
default V computeIfAbsent(K key,
Function<? super K, ? extends V> mappingFunction) {
Objects.requireNonNull(mappingFunction);
V v;
if ((v = get(key)) == null) {
V newValue;
if ((newValue = mappingFunction.apply(key)) != null) {
put(key, newValue);
return newValue;
}
}
return v;
}
} }

View File

@ -0,0 +1,57 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.solr.common.util;
import java.util.Map;
import java.util.function.Function;
// A cache backed by a map
public class MapBackedCache<K, V> implements Cache<K, V> {
private final Map<K, V> map;
public MapBackedCache(Map<K, V> map) {
this.map = map;
}
@Override
public V put(K key, V val) {
return map.put(key, val);
}
@Override
public V get(K key) {
return map.get(key);
}
@Override
public V remove(K key) {
return map.remove(key);
}
@Override
public void clear() {
map.clear();
}
@Override
public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
return map.computeIfAbsent(key, mappingFunction);
}
}

View File

@ -340,30 +340,7 @@ public class TestJavaBinCodec extends SolrTestCaseJ4 {
assertTrue(l1.get(1).equals(l2.get(1))); assertTrue(l1.get(1).equals(l2.get(1)));
assertFalse(l1.get(1) == l2.get(1)); assertFalse(l1.get(1) == l2.get(1));
JavaBinCodec.StringCache stringCache = new JavaBinCodec.StringCache(new Cache<JavaBinCodec.StringBytes, String>() { JavaBinCodec.StringCache stringCache = new JavaBinCodec.StringCache(new MapBackedCache<>(new HashMap<>()));
private HashMap<JavaBinCodec.StringBytes, String> cache = new HashMap<>();
@Override
public String put(JavaBinCodec.StringBytes key, String val) {
return cache.put(key, val);
}
@Override
public String get(JavaBinCodec.StringBytes key) {
return cache.get(key);
}
@Override
public String remove(JavaBinCodec.StringBytes key) {
return cache.remove(key);
}
@Override
public void clear() {
cache.clear();
}
});
m1 = (Map) new JavaBinCodec(null, stringCache).unmarshal(new ByteArrayInputStream(b1)); m1 = (Map) new JavaBinCodec(null, stringCache).unmarshal(new ByteArrayInputStream(b1));
@ -409,32 +386,7 @@ public class TestJavaBinCodec extends SolrTestCaseJ4 {
Runtime.getRuntime().gc(); Runtime.getRuntime().gc();
printMem("before cache init"); printMem("before cache init");
Cache<JavaBinCodec.StringBytes, String> cache1 = new Cache<JavaBinCodec.StringBytes, String>() { Cache<JavaBinCodec.StringBytes, String> cache1 = new MapBackedCache<>(new HashMap<>()) ;
private HashMap<JavaBinCodec.StringBytes, String> cache = new HashMap<>();
@Override
public String put(JavaBinCodec.StringBytes key, String val) {
l.add(key);
return cache.put(key, val);
}
@Override
public String get(JavaBinCodec.StringBytes key) {
return cache.get(key);
}
@Override
public String remove(JavaBinCodec.StringBytes key) {
return cache.remove(key);
}
@Override
public void clear() {
cache.clear();
}
};
final JavaBinCodec.StringCache STRING_CACHE = new JavaBinCodec.StringCache(cache1); final JavaBinCodec.StringCache STRING_CACHE = new JavaBinCodec.StringCache(cache1);
// STRING_CACHE = new JavaBinCodec.StringCache(cache); // STRING_CACHE = new JavaBinCodec.StringCache(cache);