
com.hazelcast.spi.impl.proxyservice.impl.ProxyServiceImpl Maven / Gradle / Ivy
The newest version!
/*
* Copyright (c) 2008-2024, Hazelcast, Inc. All Rights Reserved.
*
* Licensed 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.hazelcast.spi.impl.proxyservice.impl;
import com.hazelcast.cluster.Member;
import com.hazelcast.core.DistributedObject;
import com.hazelcast.core.DistributedObjectListener;
import com.hazelcast.core.HazelcastInstanceNotActiveException;
import com.hazelcast.internal.metrics.MetricsRegistry;
import com.hazelcast.internal.metrics.Probe;
import com.hazelcast.internal.metrics.StaticMetricsProvider;
import com.hazelcast.internal.services.PostJoinAwareService;
import com.hazelcast.internal.services.RemoteService;
import com.hazelcast.internal.util.ConstructorFunction;
import com.hazelcast.internal.util.FutureUtil.ExceptionHandler;
import com.hazelcast.internal.util.UuidUtil;
import com.hazelcast.internal.util.counters.MwCounter;
import com.hazelcast.logging.ILogger;
import com.hazelcast.spi.exception.DistributedObjectDestroyedException;
import com.hazelcast.spi.impl.NodeEngineImpl;
import com.hazelcast.spi.impl.eventservice.EventPublishingService;
import com.hazelcast.spi.impl.operationservice.Operation;
import com.hazelcast.spi.impl.operationservice.OperationService;
import com.hazelcast.spi.impl.proxyservice.InternalProxyService;
import com.hazelcast.spi.impl.proxyservice.ProxyService;
import com.hazelcast.spi.impl.proxyservice.impl.operations.DistributedObjectDestroyOperation;
import com.hazelcast.spi.impl.proxyservice.impl.operations.PostJoinProxyOperation;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import static com.hazelcast.core.DistributedObjectEvent.EventType.CREATED;
import static com.hazelcast.internal.metrics.MetricDescriptorConstants.PROXY_METRIC_CREATED_COUNT;
import static com.hazelcast.internal.metrics.MetricDescriptorConstants.PROXY_METRIC_DESTROYED_COUNT;
import static com.hazelcast.internal.metrics.MetricDescriptorConstants.PROXY_METRIC_PROXY_COUNT;
import static com.hazelcast.internal.metrics.MetricDescriptorConstants.PROXY_PREFIX;
import static com.hazelcast.internal.metrics.ProbeLevel.MANDATORY;
import static com.hazelcast.internal.util.ConcurrencyUtil.getOrPutIfAbsent;
import static com.hazelcast.internal.util.EmptyStatement.ignore;
import static com.hazelcast.internal.util.ExceptionUtil.peel;
import static com.hazelcast.internal.util.FutureUtil.waitWithDeadline;
import static com.hazelcast.internal.util.Preconditions.checkNotNull;
import static com.hazelcast.internal.util.counters.MwCounter.newMwCounter;
import static java.util.logging.Level.FINEST;
import static java.util.logging.Level.WARNING;
public class ProxyServiceImpl
implements InternalProxyService, PostJoinAwareService,
EventPublishingService, StaticMetricsProvider {
public static final String SERVICE_NAME = "hz:core:proxyService";
private static final int TRY_COUNT = 10;
private static final long DESTROY_TIMEOUT_SECONDS = 30;
final NodeEngineImpl nodeEngine;
final ILogger logger;
final ConcurrentMap listeners = new ConcurrentHashMap<>();
private final ConstructorFunction registryConstructor =
serviceName -> new ProxyRegistry(ProxyServiceImpl.this, serviceName);
private final ConcurrentMap registries = new ConcurrentHashMap<>();
@Probe(name = PROXY_METRIC_CREATED_COUNT, level = MANDATORY)
private final MwCounter createdCounter = newMwCounter();
@Probe(name = PROXY_METRIC_DESTROYED_COUNT, level = MANDATORY)
private final MwCounter destroyedCounter = newMwCounter();
private final ExceptionHandler destroyProxyExceptionHandler = new ExceptionHandler() {
@Override
public void handleException(Throwable throwable) {
boolean causedByInactiveInstance = peel(throwable) instanceof HazelcastInstanceNotActiveException;
Level level = causedByInactiveInstance ? FINEST : WARNING;
logger.log(level, "Error while destroying a proxy.", throwable);
}
};
public ProxyServiceImpl(NodeEngineImpl nodeEngine) {
this.nodeEngine = nodeEngine;
this.logger = nodeEngine.getLogger(ProxyService.class.getName());
}
@Override
public void provideStaticMetrics(MetricsRegistry registry) {
registry.registerStaticMetrics(this, PROXY_PREFIX);
}
public void init() {
nodeEngine.getEventService().registerListener(SERVICE_NAME, SERVICE_NAME, new Object());
}
@Probe(name = PROXY_METRIC_PROXY_COUNT)
@Override
public int getProxyCount() {
int count = 0;
for (ProxyRegistry registry : registries.values()) {
count += registry.getProxyCount();
}
return count;
}
public void initializeProxies(boolean publishAfterInitialization) {
for (ProxyRegistry registry : registries.values()) {
registry.initializeProxies(publishAfterInitialization);
}
}
@Override
public void initializeDistributedObject(String serviceName, String name, UUID source) {
checkServiceNameNotNull(serviceName);
checkObjectNameNotNull(name);
ProxyRegistry registry = getOrCreateRegistry(serviceName);
registry.createProxy(name, source, true, false);
createdCounter.inc();
}
public ProxyRegistry getOrCreateRegistry(String serviceName) {
return getOrPutIfAbsent(registries, serviceName, registryConstructor);
}
@Override
public DistributedObject getDistributedObject(String serviceName, String name, UUID source) {
checkServiceNameNotNull(serviceName);
checkObjectNameNotNull(name);
ProxyRegistry registry = getOrCreateRegistry(serviceName);
return registry.getOrCreateProxy(name, source, true);
}
@Override
public void destroyDistributedObject(String serviceName, String name, UUID source) {
checkServiceNameNotNull(serviceName);
checkObjectNameNotNull(name);
OperationService operationService = nodeEngine.getOperationService();
Collection members = nodeEngine.getClusterService().getMembers();
Collection> calls = new ArrayList<>(members.size());
for (Member member : members) {
if (member.localMember()) {
continue;
}
DistributedObjectDestroyOperation operation = new DistributedObjectDestroyOperation(serviceName, name);
operation.setCallerUuid(source);
Future f = operationService.createInvocationBuilder(SERVICE_NAME, operation, member.getAddress())
.setTryCount(TRY_COUNT).invoke();
calls.add(f);
}
try {
destroyLocalDistributedObject(serviceName, name, source, true);
} catch (Throwable e) {
logger.warning("Destroying local DistributedObject failed", e);
throw e;
}
waitWithDeadline(calls, DESTROY_TIMEOUT_SECONDS, TimeUnit.SECONDS, destroyProxyExceptionHandler);
}
@Override
public void destroyLocalDistributedObject(String serviceName, String name, UUID source, boolean fireEvent) {
ProxyRegistry registry = registries.get(serviceName);
if (registry != null) {
registry.destroyProxy(name, source, fireEvent);
destroyedCounter.inc();
}
RemoteService service = nodeEngine.getService(serviceName);
service.destroyDistributedObject(name);
String message = "DistributedObject[" + service + " -> " + name + "] has been destroyed!";
Throwable cause = new DistributedObjectDestroyedException(message);
nodeEngine.getOperationParker().cancelParkedOperations(serviceName, name, cause);
}
@Override
public Collection getDistributedObjects(String serviceName) {
checkServiceNameNotNull(serviceName);
Collection result = new LinkedList<>();
ProxyRegistry registry = registries.get(serviceName);
if (registry != null) {
registry.getDistributedObjects(result);
}
return result;
}
@Override
public Collection getDistributedObjectNames(String serviceName) {
checkServiceNameNotNull(serviceName);
ProxyRegistry registry = registries.get(serviceName);
if (registry == null) {
return Collections.emptySet();
} else {
return Collections.unmodifiableCollection(registry.getDistributedObjectNames());
}
}
@Override
public boolean existsDistributedObject(String serviceName, String objectId) {
checkServiceNameNotNull(serviceName);
ProxyRegistry registry = registries.get(serviceName);
if (registry == null) {
return false;
}
return registry.existsDistributedObject(objectId);
}
@Override
public Collection getAllDistributedObjects() {
Collection result = new LinkedList<>();
for (ProxyRegistry registry : registries.values()) {
registry.getDistributedObjects(result);
}
return result;
}
@Override
public long getCreatedCount(@Nonnull String serviceName) {
ProxyRegistry registry = registries.get(serviceName);
return registry == null ? 0 : registry.getCreatedCount();
}
@Override
public UUID addProxyListener(DistributedObjectListener distributedObjectListener) {
UUID id = UuidUtil.newUnsecureUUID();
listeners.put(id, distributedObjectListener);
return id;
}
@Override
public boolean removeProxyListener(UUID registrationId) {
return listeners.remove(registrationId) != null;
}
@Override
public void dispatchEvent(final DistributedObjectEventPacket eventPacket, Object ignore) {
String serviceName = eventPacket.getServiceName();
if (eventPacket.getEventType() == CREATED) {
try {
final ProxyRegistry registry = getOrCreateRegistry(serviceName);
if (!registry.contains(eventPacket.getName())) {
registry.createProxy(eventPacket.getName(), eventPacket.getSource(), true, true);
// listeners will be called if proxy is created here.
}
} catch (HazelcastInstanceNotActiveException ignored) {
ignore(ignored);
}
} else {
final ProxyRegistry registry = registries.get(serviceName);
if (registry != null) {
registry.destroyProxy(eventPacket.getName(), eventPacket.getSource(), false);
}
}
}
@Override
public Operation getPostJoinOperation() {
Collection proxies = new LinkedList<>();
for (ProxyRegistry registry : registries.values()) {
registry.getProxyInfos(proxies);
}
return proxies.isEmpty() ? null : new PostJoinProxyOperation(proxies);
}
public void shutdown() {
for (ProxyRegistry registry : registries.values()) {
registry.destroy();
}
registries.clear();
listeners.clear();
}
private static void checkServiceNameNotNull(@Nonnull String serviceName) {
checkNotNull(serviceName, "Service name is required");
}
private static void checkObjectNameNotNull(@Nonnull String name) {
checkNotNull(name, "Object name is required");
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy