optimize guice injector once created
in guice, we always use eager loaded singletons for all modules we create, thus, we can actually optimize the memory used by injectors by reduced the construction information they store per binding resulting in extensive reduction in memory usage for many indices/shards case on a node also because all are eager singletons (and effectively, read only), we can not go through trying to create just in time bindings in the parent injector before trying to craete it in the current injector, resulting in improvement of object creations time and the time it takes to create an index or a shard on a node
This commit is contained in:
parent
09a6907cca
commit
8d9c84f84e
|
@ -16,11 +16,11 @@
|
|||
|
||||
package org.elasticsearch.common.inject;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import org.elasticsearch.common.inject.internal.BindingImpl;
|
||||
import org.elasticsearch.common.inject.internal.Errors;
|
||||
import org.elasticsearch.common.inject.internal.MatcherAndConverter;
|
||||
import org.elasticsearch.common.inject.internal.*;
|
||||
import org.elasticsearch.common.inject.spi.InjectionPoint;
|
||||
import org.elasticsearch.common.inject.spi.TypeListenerBinding;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
@ -131,6 +131,19 @@ class InheritingState implements State {
|
|||
blacklistedKeys = new WeakKeySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void makeAllBindingsToEagerSingletons(Injector injector) {
|
||||
Map<Key<?>, Binding<?>> x = Maps.newLinkedHashMap();
|
||||
for (Map.Entry<Key<?>, Binding<?>> entry : this.explicitBindingsMutable.entrySet()) {
|
||||
Key key = entry.getKey();
|
||||
BindingImpl<?> binding = (BindingImpl<?>) entry.getValue();
|
||||
Object value = binding.getProvider().get();
|
||||
x.put(key, new InstanceBindingImpl<Object>(injector, key, SourceProvider.UNKNOWN_SOURCE, new InternalFactory.Instance(value), ImmutableSet.<InjectionPoint>of(), value));
|
||||
}
|
||||
this.explicitBindingsMutable.clear();
|
||||
this.explicitBindingsMutable.putAll(x);
|
||||
}
|
||||
|
||||
public Object lock() {
|
||||
return lock;
|
||||
}
|
||||
|
|
|
@ -42,7 +42,8 @@ import static org.elasticsearch.common.inject.internal.Annotations.findScopeAnno
|
|||
class InjectorImpl implements Injector, Lookups {
|
||||
final State state;
|
||||
final InjectorImpl parent;
|
||||
final BindingsMultimap bindingsMultimap = new BindingsMultimap();
|
||||
boolean readOnly;
|
||||
BindingsMultimap bindingsMultimap = new BindingsMultimap();
|
||||
final Initializer initializer;
|
||||
|
||||
/**
|
||||
|
@ -564,7 +565,7 @@ class InjectorImpl implements Injector, Lookups {
|
|||
private <T> BindingImpl<T> createJustInTimeBindingRecursive(Key<T> key, Errors errors)
|
||||
throws ErrorsException {
|
||||
// ask the parent to create the JIT binding
|
||||
if (parent != null) {
|
||||
if (parent != null && !parent.readOnly /* ES: don't check on parent if its read only, its already created all the bindings it can*/) {
|
||||
try {
|
||||
return parent.createJustInTimeBindingRecursive(key, new Errors());
|
||||
} catch (ErrorsException ignored) {
|
||||
|
@ -750,8 +751,24 @@ class InjectorImpl implements Injector, Lookups {
|
|||
|
||||
<T> Provider<T> getProviderOrThrow(final Key<T> key, Errors errors) throws ErrorsException {
|
||||
final InternalFactory<? extends T> factory = getInternalFactory(key, errors);
|
||||
final Dependency<T> dependency = Dependency.get(key);
|
||||
// ES: optimize for a common case of read only instance getting from the parent...
|
||||
if (factory instanceof InternalFactory.Instance) {
|
||||
return new Provider<T>() {
|
||||
@Override
|
||||
public T get() {
|
||||
try {
|
||||
return (T) ((InternalFactory.Instance) factory).get(null, null, null);
|
||||
} catch (ErrorsException e) {
|
||||
// ignore
|
||||
}
|
||||
// should never happen...
|
||||
assert false;
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
final Dependency<T> dependency = Dependency.get(key);
|
||||
return new Provider<T>() {
|
||||
public T get() {
|
||||
final Errors errors = new Errors(dependency);
|
||||
|
@ -833,4 +850,13 @@ class InjectorImpl implements Injector, Lookups {
|
|||
membersInjectorStore = new MembersInjectorStore(this, state.getTypeListenerBindings());
|
||||
jitBindings = Maps.newHashMap();
|
||||
}
|
||||
|
||||
// ES_GUICE: make all registered bindings act as eager singletons
|
||||
public void readOnlyAllSingletons() {
|
||||
readOnly = true;
|
||||
state.makeAllBindingsToEagerSingletons(this);
|
||||
bindingsMultimap = new BindingsMultimap();
|
||||
// reindex the bindings
|
||||
index();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,9 @@ public class ModulesBuilder implements Iterable<Module> {
|
|||
Modules.processModules(modules);
|
||||
Injector injector = Guice.createInjector(modules);
|
||||
Injectors.cleanCaches(injector);
|
||||
// in ES, we always create all instances as if they are eager singletons
|
||||
// this allows for considerable memory savings (no need to store construction info) as well as cycles
|
||||
((InjectorImpl) injector).readOnlyAllSingletons();
|
||||
return injector;
|
||||
}
|
||||
|
||||
|
@ -65,6 +68,9 @@ public class ModulesBuilder implements Iterable<Module> {
|
|||
Modules.processModules(modules);
|
||||
Injector childInjector = injector.createChildInjector(modules);
|
||||
Injectors.cleanCaches(childInjector);
|
||||
// in ES, we always create all instances as if they are eager singletons
|
||||
// this allows for considerable memory savings (no need to store construction info) as well as cycles
|
||||
((InjectorImpl) childInjector).readOnlyAllSingletons();
|
||||
return childInjector;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,6 +92,10 @@ interface State {
|
|||
public void clearBlacklisted() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void makeAllBindingsToEagerSingletons(Injector injector) {
|
||||
}
|
||||
|
||||
public Object lock() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
@ -156,4 +160,6 @@ interface State {
|
|||
|
||||
// ES_GUICE: clean blacklist keys
|
||||
void clearBlacklisted();
|
||||
|
||||
void makeAllBindingsToEagerSingletons(Injector injector);
|
||||
}
|
||||
|
|
|
@ -25,6 +25,29 @@ import org.elasticsearch.common.inject.spi.Dependency;
|
|||
*/
|
||||
public interface InternalFactory<T> {
|
||||
|
||||
/**
|
||||
* ES:
|
||||
* An factory that returns a pre created instance.
|
||||
*/
|
||||
public static class Instance<T> implements InternalFactory<T> {
|
||||
|
||||
private final T object;
|
||||
|
||||
public Instance(T object) {
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get(Errors errors, InternalContext context, Dependency<?> dependency) throws ErrorsException {
|
||||
return object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return object.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an object to be injected.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue