Add a cache around CloudConfigProvider
This commit is contained in:
@@ -14,8 +14,9 @@ import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.springframework.ide.vscode.bosh.cloudconfig.CloudConfigModel;
|
||||
import org.springframework.ide.vscode.bosh.cloudconfig.DynamicModelProvider;
|
||||
import org.springframework.ide.vscode.bosh.models.CachingModelProvider;
|
||||
import org.springframework.ide.vscode.bosh.models.CloudConfigModel;
|
||||
import org.springframework.ide.vscode.bosh.models.DynamicModelProvider;
|
||||
import org.springframework.ide.vscode.commons.util.Assert;
|
||||
import org.springframework.ide.vscode.commons.util.Renderable;
|
||||
import org.springframework.ide.vscode.commons.util.Renderables;
|
||||
@@ -83,7 +84,7 @@ public class BoshDeploymentManifestSchema implements YamlSchema {
|
||||
|
||||
public BoshDeploymentManifestSchema(ASTTypeCache astTypes, DynamicModelProvider<CloudConfigModel> cloudConfigProvider) {
|
||||
this.astTypes = astTypes;
|
||||
this.cloudConfigProvider = cloudConfigProvider;
|
||||
this.cloudConfigProvider = new CachingModelProvider<>(cloudConfigProvider);
|
||||
TYPE_UTIL = f.TYPE_UTIL;
|
||||
|
||||
V2_TOPLEVEL_TYPE = createV2Schema();
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.bosh;
|
||||
|
||||
import org.springframework.ide.vscode.bosh.cloudconfig.CloudConfigModel;
|
||||
import org.springframework.ide.vscode.bosh.cloudconfig.DynamicModelProvider;
|
||||
import org.springframework.ide.vscode.bosh.models.CloudConfigModel;
|
||||
import org.springframework.ide.vscode.bosh.models.DynamicModelProvider;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.VscodeCompletionEngineAdapter;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.VscodeCompletionEngineAdapter.LazyCompletionResolver;
|
||||
import org.springframework.ide.vscode.commons.languageserver.hover.HoverInfoProvider;
|
||||
|
||||
@@ -12,7 +12,7 @@ package org.springframework.ide.vscode.bosh;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.ide.vscode.bosh.cloudconfig.BoshCommandCloudConfigProvider;
|
||||
import org.springframework.ide.vscode.bosh.models.BoshCommandCloudConfigProvider;
|
||||
import org.springframework.ide.vscode.commons.languageserver.LaunguageServerApp;
|
||||
|
||||
public class Main {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.bosh.cloudconfig;
|
||||
package org.springframework.ide.vscode.bosh.models;
|
||||
|
||||
import java.io.File;
|
||||
import java.time.Duration;
|
||||
@@ -0,0 +1,73 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.bosh.models;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.DynamicSchemaContext;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
|
||||
/**
|
||||
* Wraps around a {@link DynamicModelProvider} to add a cache.
|
||||
*/
|
||||
public class CachingModelProvider<T> implements DynamicModelProvider<T> {
|
||||
|
||||
/**
|
||||
* Special key to use when the actual key is null (because guava cache doesn't
|
||||
* like null keys).
|
||||
*/
|
||||
private static final Object NULL_KEY = new Object();
|
||||
|
||||
private long timeout = 15;
|
||||
private TimeUnit timeoutUnit = TimeUnit.SECONDS;
|
||||
private Cache<Object, T> cache = createCache();
|
||||
|
||||
private final DynamicModelProvider<T> delegate;
|
||||
|
||||
public CachingModelProvider(DynamicModelProvider<T> delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function used to determine the caching key, given the current {@link DynamicSchemaContext}.
|
||||
* <p>
|
||||
* The default keyGetter ignores the context and just returns the same object all the time. This
|
||||
* results in a cache that only keeps a single value (since there's only a single key ever used
|
||||
* to store / find cache entries.
|
||||
*/
|
||||
private Function<DynamicSchemaContext, Object> keyGetter = (dc) -> "WHATEVER";
|
||||
|
||||
protected Cache<Object, T> createCache() {
|
||||
return CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(timeout, timeoutUnit)
|
||||
.build();
|
||||
}
|
||||
|
||||
public CachingModelProvider<T> setTimeout(long timeout, TimeUnit unit) {
|
||||
this.timeout = timeout;
|
||||
this.timeoutUnit = unit;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getModel(DynamicSchemaContext dc) throws Exception {
|
||||
Object key = keyGetter.apply(dc);
|
||||
if (key==null) {
|
||||
//guava cache doesn't like null key
|
||||
key = NULL_KEY;
|
||||
}
|
||||
return cache.get(key, () -> delegate.getModel(dc));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.bosh.cloudconfig;
|
||||
package org.springframework.ide.vscode.bosh.models;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.springframework.ide.vscode.bosh.cloudconfig;
|
||||
package org.springframework.ide.vscode.bosh.models;
|
||||
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.DynamicSchemaContext;
|
||||
|
||||
@@ -14,9 +14,9 @@ import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.ide.vscode.bosh.cloudconfig.BoshCommandCloudConfigProvider;
|
||||
import org.springframework.ide.vscode.bosh.cloudconfig.CloudConfigModel;
|
||||
import org.springframework.ide.vscode.bosh.mocks.MockCloudConfigProvider;
|
||||
import org.springframework.ide.vscode.bosh.models.BoshCommandCloudConfigProvider;
|
||||
import org.springframework.ide.vscode.bosh.models.CloudConfigModel;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.DynamicSchemaContext;
|
||||
|
||||
import com.google.common.collect.ImmutableMultiset;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.bosh;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.springframework.ide.vscode.languageserver.testharness.Editor.PLAIN_COMPLETION;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -849,5 +850,27 @@ public class BoshEditorTest {
|
||||
"default<*>",
|
||||
"large<*>"
|
||||
);
|
||||
|
||||
//Verify that the cache is working. Shouldn't read the cc provier more than once, evem for multiple CA requests.
|
||||
editor.assertCompletionLabels("default", "large");
|
||||
editor.assertCompletionLabels("default", "large");
|
||||
assertEquals(1, cloudConfigProvider.getReadCount());
|
||||
}
|
||||
|
||||
@Test public void reconcileVMtype() throws Exception {
|
||||
Editor editor = harness.newEditor(
|
||||
"name: foo\n" +
|
||||
"instance_groups: \n" +
|
||||
"- name: some-server\n" +
|
||||
" vm_type: bogus-vm\n" +
|
||||
"- name: other-server\n" +
|
||||
" vm_type: large"
|
||||
);
|
||||
editor.ignoreProblem(YamlSchemaProblems.MISSING_PROPERTY);
|
||||
editor.assertProblems(
|
||||
"bogus-vm|unknown 'VMType'. Valid values are: [default, large]"
|
||||
);
|
||||
assertEquals(1, cloudConfigProvider.getReadCount());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ package org.springframework.ide.vscode.bosh.mocks;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.springframework.ide.vscode.bosh.BoshCommandCloudConfigProviderTest;
|
||||
import org.springframework.ide.vscode.bosh.cloudconfig.BoshCommandCloudConfigProvider;
|
||||
import org.springframework.ide.vscode.bosh.models.BoshCommandCloudConfigProvider;
|
||||
import org.springframework.ide.vscode.commons.util.IOUtil;
|
||||
|
||||
public final class MockCloudConfigProvider extends BoshCommandCloudConfigProvider {
|
||||
@@ -22,12 +22,15 @@ public final class MockCloudConfigProvider extends BoshCommandCloudConfigProvide
|
||||
|
||||
private Callable<String> cloudConfigReader = () -> IOUtil.toString(BoshCommandCloudConfigProviderTest.class.getResourceAsStream(MOCK_DATA_RSRC));
|
||||
|
||||
private int readCount = 0;
|
||||
|
||||
/**
|
||||
* Override with a 'fake' which just returns some mock data. That way we can unit-test
|
||||
* without requiring a real bosh setup.
|
||||
*/
|
||||
@Override
|
||||
protected String executeBoshCloudConfigCommand() throws Exception {
|
||||
readCount++;
|
||||
return cloudConfigReader.call();
|
||||
}
|
||||
|
||||
@@ -35,4 +38,8 @@ public final class MockCloudConfigProvider extends BoshCommandCloudConfigProvide
|
||||
this.cloudConfigReader = reader;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getReadCount() {
|
||||
return readCount;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user