All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ehcache.clustered.server.ClusterTierManagerActiveEntity Maven / Gradle / Ivy

/*
 * Copyright Terracotta, Inc.
 *
 * 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 org.ehcache.clustered.server;

import org.ehcache.clustered.common.ServerSideConfiguration;
import org.ehcache.clustered.common.internal.ClusterTierManagerConfiguration;
import org.ehcache.clustered.common.internal.exceptions.ClusterException;
import org.ehcache.clustered.common.internal.exceptions.InvalidOperationException;
import org.ehcache.clustered.common.internal.messages.EhcacheEntityMessage;
import org.ehcache.clustered.common.internal.messages.EhcacheEntityResponse;
import org.ehcache.clustered.common.internal.messages.EhcacheMessageType;
import org.ehcache.clustered.common.internal.messages.EhcacheOperationMessage;
import org.ehcache.clustered.common.internal.messages.LifecycleMessage;
import org.ehcache.clustered.server.management.Management;
import org.ehcache.clustered.server.state.EhcacheStateService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terracotta.entity.ActiveInvokeContext;
import org.terracotta.entity.ActiveServerEntity;
import org.terracotta.entity.ClientDescriptor;
import org.terracotta.entity.ConfigurationException;
import org.terracotta.entity.PassiveSynchronizationChannel;
import org.terracotta.entity.StateDumpCollector;

import java.util.concurrent.atomic.AtomicBoolean;

import static org.ehcache.clustered.common.internal.messages.EhcacheEntityResponse.failure;
import static org.ehcache.clustered.common.internal.messages.EhcacheEntityResponse.success;
import static org.ehcache.clustered.common.internal.messages.EhcacheMessageType.isLifecycleMessage;
import static org.ehcache.clustered.common.internal.messages.LifecycleMessage.ValidateStoreManager;

public class ClusterTierManagerActiveEntity implements ActiveServerEntity {

  private static final Logger LOGGER = LoggerFactory.getLogger(ClusterTierManagerActiveEntity.class);

  private final EhcacheStateService ehcacheStateService;
  private final Management management;
  private final AtomicBoolean reconnectComplete = new AtomicBoolean(true);
  private final ServerSideConfiguration configuration;
  private final ClusterTierManagerConfiguration clusterTierManagerConfig;

  /**
   * Only used for subclassing when testing
   */
  protected ClusterTierManagerActiveEntity() {
    ehcacheStateService = null;
    management = null;
    configuration = null;
    clusterTierManagerConfig = null;
  }

  public ClusterTierManagerActiveEntity(ClusterTierManagerConfiguration config,
                                        EhcacheStateService ehcacheStateService, Management management) throws ConfigurationException {
    clusterTierManagerConfig = config;
    if (config == null) {
      throw new ConfigurationException("ClusterTierManagerConfiguration cannot be null");
    }
    this.configuration = config.getConfiguration();
    this.ehcacheStateService = ehcacheStateService;
    if (ehcacheStateService == null) {
      throw new AssertionError("Server failed to retrieve EhcacheStateService.");
    }
    try {
      ehcacheStateService.configure();
      this.management = management;
    } catch (ConfigurationException e) {
      ehcacheStateService.destroy();
      throw e;
    }
  }

  @Override
  public void addStateTo(StateDumpCollector dump) {
    ClusterTierManagerDump.dump(dump, clusterTierManagerConfig);
  }

  @Override
  public void connected(ClientDescriptor clientDescriptor) {
    LOGGER.info("Connecting {}", clientDescriptor);
  }

  @Override
  public void disconnected(ClientDescriptor clientDescriptor) {
    LOGGER.info("Disconnecting {}", clientDescriptor);
  }

  @Override
  public EhcacheEntityResponse invokeActive(ActiveInvokeContext invokeContext, EhcacheEntityMessage message) {
    try {
      if (message instanceof EhcacheOperationMessage) {
        EhcacheOperationMessage operationMessage = (EhcacheOperationMessage) message;
        EhcacheMessageType messageType = operationMessage.getMessageType();
        if (isLifecycleMessage(messageType)) {
          return invokeLifeCycleOperation(invokeContext.getClientDescriptor(), (LifecycleMessage) message);
        }
      }
      throw new AssertionError("Unsupported message : " + message.getClass());
    } catch (ClusterException e) {
      return failure(e);
    } catch (Exception e) {
      LOGGER.error("Unexpected exception raised during operation: " + message, e);
      return failure(new InvalidOperationException(e));
    }
  }

  @Override
  public ReconnectHandler startReconnect() {
    return (clientDescriptor, bytes) -> LOGGER.info("Client '{}' successfully reconnected to newly promoted ACTIVE after failover.", clientDescriptor);
  }

  @Override
  public void synchronizeKeyToPassive(PassiveSynchronizationChannel syncChannel, int concurrencyKey) {
    // Nothing to sync
  }

  @Override
  public void createNew() {
    management.entityCreated();
    management.sharedPoolsConfigured();
  }

  @Override
  public void loadExisting() {
    ehcacheStateService.loadExisting(configuration);
    LOGGER.debug("Preparing for handling Inflight Invalidations and independent Passive Evictions in loadExisting");
    reconnectComplete.set(false);

    management.entityPromotionCompleted();
    management.sharedPoolsConfigured();
  }

  private EhcacheEntityResponse invokeLifeCycleOperation(ClientDescriptor clientDescriptor, LifecycleMessage message) throws ClusterException {
    switch (message.getMessageType()) {
      case VALIDATE:
        validate(clientDescriptor, (ValidateStoreManager) message);
        break;
      case PREPARE_FOR_DESTROY:
        return prepareForDestroy();
      default:
        throw new AssertionError("Unsupported LifeCycle operation " + message);
    }
    return success();
  }

  private EhcacheEntityResponse prepareForDestroy() {
    EhcacheEntityResponse.PrepareForDestroy response = EhcacheEntityResponse.prepareForDestroy(ehcacheStateService.getStores());
    ehcacheStateService.prepareForDestroy();
    return response;
  }

  /**
   * {@inheritDoc}
   * 

* This method is invoked in response to a call to a {@code com.tc.objectserver.api.ServerEntityRequest} * message for a {@code ServerEntityAction.DESTROY_ENTITY} request which is sent via a call to the * {@code ClusteringService.destroyAll} method. This method is expected to be called only when no * clients actively using this entity. */ @Override public void destroy() { ehcacheStateService.destroy(); management.close(); } /** * Handles the {@link ValidateStoreManager ValidateStoreManager} message. This message is used by a client to * connect to an established {@code ClusterTierManagerActiveEntity}. This method validates the client-provided configuration * against the existing configuration to ensure compatibility. * * @param clientDescriptor the client identifier requesting attachment to a configured store manager * @param message the {@code ValidateStoreManager} message carrying the client expected resource pool configuration */ private void validate(ClientDescriptor clientDescriptor, ValidateStoreManager message) throws ClusterException { ehcacheStateService.validate(message.getConfiguration()); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy