Skip to content

Commit

Permalink
Add dynamic JVM service invoking cache (#876)
Browse files Browse the repository at this point in the history
  • Loading branch information
alaneuler authored Oct 21, 2021
1 parent c070d92 commit b3770f2
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 3 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
<description>SOFABoot Build</description>

<properties>
<revision>3.9.0</revision>
<revision>3.9.1-SNAPSHOT</revision>
<sofa.boot.version>${revision}</sofa.boot.version>
<!--maven plugin-->
<maven.staging.plugin>1.6.7</maven.staging.plugin>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.alipay.sofa.ark.spi.model.Biz;
import com.alipay.sofa.ark.spi.service.PriorityOrdered;
import com.alipay.sofa.ark.spi.service.event.EventHandler;
import com.alipay.sofa.runtime.invoke.DynamicJvmServiceProxyFinder;
import com.alipay.sofa.runtime.spi.component.SofaRuntimeManager;

/**
Expand All @@ -34,6 +35,9 @@ public void handleEvent(BeforeBizStopEvent event) {
}

private void doUninstallBiz(Biz biz) {
// Remove dynamic JVM service cache
DynamicJvmServiceProxyFinder.getDynamicJvmServiceProxyFinder().afterBizUninstall(biz);

SofaRuntimeProperties.unRegisterProperties(biz.getBizClassLoader());
SofaRuntimeManager sofaRuntimeManager = getSofaRuntimeManager(biz);
SofaFramework.unRegisterSofaRuntimeManager(sofaRuntimeManager);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ public class SofaRuntimeProperties {
private static boolean jvmFilterEnable = false;
private static boolean serviceInterfaceTypeCheck = false;

private static boolean dynamicJvmServiceCacheEnable = false;

public static boolean isManualReadinessCallback(ClassLoader classLoader) {
return manualReadinessCallbackMap.get(classLoader) != null
&& manualReadinessCallbackMap.get(classLoader);
Expand All @@ -54,6 +56,14 @@ public static void setJvmFilterEnable(boolean jvmFilterEnable) {
SofaRuntimeProperties.jvmFilterEnable = jvmFilterEnable;
}

public static boolean isDynamicJvmServiceCacheEnable() {
return dynamicJvmServiceCacheEnable;
}

public static void setDynamicJvmServiceCacheEnable(boolean dynamicJvmServiceCacheEnable) {
SofaRuntimeProperties.dynamicJvmServiceCacheEnable = dynamicJvmServiceCacheEnable;
}

public static boolean isServiceInterfaceTypeCheck() {
return serviceInterfaceTypeCheck;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ public void setJvmFilterEnable(boolean jvmFilterEnable) {
SofaRuntimeProperties.setJvmFilterEnable(jvmFilterEnable);
}

public boolean isDynamicJvmServiceCacheEnable() {
return SofaRuntimeProperties.isDynamicJvmServiceCacheEnable();
}

public void setDynamicJvmServiceCacheEnable(boolean dynamicJvmServiceCacheEnable) {
SofaRuntimeProperties.setDynamicJvmServiceCacheEnable(dynamicJvmServiceCacheEnable);
}

public void setSkipJvmReferenceHealthCheck(boolean skipJvmReferenceHealthCheck) {
SofaRuntimeProperties.setSkipJvmReferenceHealthCheck(Thread.currentThread()
.getContextClassLoader(), skipJvmReferenceHealthCheck);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.alipay.sofa.ark.spi.replay.ReplayContext;
import com.alipay.sofa.common.utils.StringUtil;
import com.alipay.sofa.runtime.SofaRuntimeProperties;
import org.aopalliance.intercept.MethodInvocation;

Expand All @@ -50,7 +53,9 @@
*/
public class DynamicJvmServiceProxyFinder {

private static DynamicJvmServiceProxyFinder dynamicJvmServiceProxyFinder = new DynamicJvmServiceProxyFinder();
private static DynamicJvmServiceProxyFinder dynamicJvmServiceProxyFinder = new DynamicJvmServiceProxyFinder();

private static Map<String, JvmServiceTargetHabitat> jvmServiceTargetHabitats = new ConcurrentHashMap<>();

private DynamicJvmServiceProxyFinder() {
}
Expand All @@ -65,6 +70,14 @@ public static DynamicJvmServiceProxyFinder getDynamicJvmServiceProxyFinder() {
}

public ServiceComponent findServiceComponent(ClassLoader clientClassloader, Contract contract) {
ServiceComponent serviceComponent = null;
if (hasFinishStartup && SofaRuntimeProperties.isDynamicJvmServiceCacheEnable()) {
serviceComponent = cacheSearching(contract);
if (serviceComponent != null) {
return serviceComponent;
}
}

String interfaceType = contract.getInterfaceType().getCanonicalName();
String uniqueId = contract.getUniqueId();
for (SofaRuntimeManager sofaRuntimeManager : SofaFramework.getRuntimeSet()) {
Expand Down Expand Up @@ -103,7 +116,7 @@ public ServiceComponent findServiceComponent(ClassLoader clientClassloader, Cont
}

// match biz
ServiceComponent serviceComponent = findServiceComponent(uniqueId, interfaceType,
serviceComponent = findServiceComponent(uniqueId, interfaceType,
sofaRuntimeManager.getComponentManager());
if (serviceComponent != null) {
return serviceComponent;
Expand All @@ -112,6 +125,79 @@ public ServiceComponent findServiceComponent(ClassLoader clientClassloader, Cont
return null;
}

public void afterBizStartup(Biz biz) {
if (!SofaRuntimeProperties.isDynamicJvmServiceCacheEnable()) {
return;
}

// Currently, there is no way to get SOFA Runtime Manager from biz
// The overhead is acceptable as this only happens after biz's successful installation
for (SofaRuntimeManager runtimeManager: SofaFramework.getRuntimeSet()) {
if (runtimeManager.getAppClassLoader().equals(biz.getBizClassLoader())) {
for (ComponentInfo componentInfo: runtimeManager.getComponentManager().getComponents()) {
if (componentInfo instanceof ServiceComponent) {
ServiceComponent serviceComponent = (ServiceComponent) componentInfo;
String uniqueName = getUniqueName(serviceComponent.getService());
jvmServiceTargetHabitats.computeIfAbsent(uniqueName, e -> new JvmServiceTargetHabitat(biz.getBizName()));
JvmServiceTargetHabitat jvmServiceTargetHabitat = jvmServiceTargetHabitats.get(uniqueName);
jvmServiceTargetHabitat.addServiceComponent(biz.getBizVersion(), serviceComponent);
}
}
}
}
}

public void afterBizUninstall(Biz biz) {
if (!SofaRuntimeProperties.isDynamicJvmServiceCacheEnable()) {
return;
}

for (SofaRuntimeManager runtimeManager : SofaFramework.getRuntimeSet()) {
if (runtimeManager.getAppClassLoader().equals(biz.getBizClassLoader())) {
for (ComponentInfo componentInfo : runtimeManager.getComponentManager()
.getComponents()) {
if (componentInfo instanceof ServiceComponent) {
ServiceComponent serviceComponent = (ServiceComponent) componentInfo;
String uniqueName = getUniqueName(serviceComponent.getService());
JvmServiceTargetHabitat jvmServiceTargetHabitat = jvmServiceTargetHabitats
.get(uniqueName);
if (jvmServiceTargetHabitat != null) {
jvmServiceTargetHabitat.removeServiceComponent(biz.getBizVersion());
}
}
}
}
}
}

private ServiceComponent cacheSearching(Contract contract) {
// Master Biz is in starting phase, cache isn't ready
if (!hasFinishStartup) {
return null;
}

String uniqueName = getUniqueName(contract);
JvmServiceTargetHabitat jvmServiceTargetHabitat = jvmServiceTargetHabitats.get(uniqueName);
if (jvmServiceTargetHabitat == null) {
return null;
}

String version = ReplayContext.get();
version = ReplayContext.PLACEHOLDER.equals(version) ? null : version;
if (StringUtil.isNotBlank(version)) {
return jvmServiceTargetHabitat.getServiceComponent(version);
}
return jvmServiceTargetHabitat.getDefaultServiceComponent();
}

private String getUniqueName(Contract contract) {
String uniqueName = contract.getInterfaceType().getName();
if (StringUtil.isNotBlank(contract.getUniqueId())) {
uniqueName += ":" + contract.getUniqueId();
}
return uniqueName;
}

public ServiceProxy findServiceProxy(ClassLoader clientClassloader, Contract contract) {
ServiceComponent serviceComponent = findServiceComponent(clientClassloader, contract);
if (serviceComponent == null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* 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 com.alipay.sofa.runtime.invoke;

import com.alipay.sofa.ark.api.ArkClient;
import com.alipay.sofa.runtime.service.component.ServiceComponent;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
* @author <a href="mailto:guaner.zzx@alipay.com">Alaneuler</a>
* Created on 03/09/2021
*/
public class JvmServiceTargetHabitat {
private String bizName;

/**
* Key as version
* Value as target bean
*/
private Map<String, ServiceComponent> habitat = new ConcurrentHashMap<>();

public JvmServiceTargetHabitat(String bizName) {
this.bizName = bizName;
}

public void addServiceComponent(String bizVersion, ServiceComponent serviceComponent) {
habitat.put(bizVersion, serviceComponent);
}

public void removeServiceComponent(String bizVersion) {
habitat.remove(bizVersion);
}

public ServiceComponent getServiceComponent(String version) {
return habitat.get(version);
}

public ServiceComponent getDefaultServiceComponent() {
for (String bizVersion : habitat.keySet()) {
if (ArkClient.getBizManagerService().isActiveBiz(bizName, bizVersion)) {
return habitat.get(bizVersion);
}
}
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* 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 com.alipay.sofa.runtime.spring;

import com.alipay.sofa.ark.spi.event.biz.AfterBizStartupEvent;
import com.alipay.sofa.ark.spi.model.Biz;
import com.alipay.sofa.ark.spi.service.PriorityOrdered;
import com.alipay.sofa.ark.spi.service.event.EventHandler;
import com.alipay.sofa.runtime.invoke.DynamicJvmServiceProxyFinder;

/**
* @author <a href="mailto:guaner.zzx@alipay.com">Alaneuler</a>
* Created on 03/09/2021
*/
public class AfterBizStartupEventHandler implements EventHandler<AfterBizStartupEvent> {
@Override
public void handleEvent(AfterBizStartupEvent event) {
Biz biz = event.getSource();
DynamicJvmServiceProxyFinder.getDynamicJvmServiceProxyFinder().afterBizStartup(biz);
}

@Override
public int getPriority() {
return PriorityOrdered.DEFAULT_PRECEDENCE;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.alipay.sofa.runtime.SofaBizHealthCheckEventHandler;
import com.alipay.sofa.runtime.SofaBizUninstallEventHandler;
import com.alipay.sofa.runtime.invoke.DynamicJvmServiceProxyFinder;
import com.alipay.sofa.runtime.spring.AfterBizStartupEventHandler;
import com.alipay.sofa.runtime.spring.FinishStartupEventHandler;

/**
Expand All @@ -42,6 +43,7 @@ private void registerEventHandler(final PluginContext context) {
eventAdminService.register(new SofaBizUninstallEventHandler());
eventAdminService.register(new SofaBizHealthCheckEventHandler());
eventAdminService.register(new FinishStartupEventHandler());
eventAdminService.register(new AfterBizStartupEventHandler());
}

@Override
Expand Down

0 comments on commit b3770f2

Please sign in to comment.