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

com.gemstone.gemfire.internal.cache.wan.serial.ConcurrentSerialGatewaySenderEventProcessor Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2010-2015 Pivotal Software, 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. See accompanying
 * LICENSE file.
 */
/**
 * 
 */
package com.gemstone.gemfire.internal.cache.wan.serial;

import com.gemstone.gemfire.GemFireException;
import com.gemstone.gemfire.InternalGemFireException;
import com.gemstone.gemfire.cache.CacheException;
import com.gemstone.gemfire.cache.partition.PartitionRegionHelper;
import com.gemstone.gemfire.cache.util.Gateway.OrderPolicy;
import com.gemstone.gemfire.internal.LogWriterImpl;
import com.gemstone.gemfire.internal.cache.EntryEventImpl;
import com.gemstone.gemfire.internal.cache.EnumListenerEvent;
import com.gemstone.gemfire.internal.cache.EventID;
import com.gemstone.gemfire.internal.cache.PartitionedRegionHelper;
import com.gemstone.gemfire.internal.cache.RegionQueue;
import com.gemstone.gemfire.internal.cache.ha.ThreadIdentifier;
import com.gemstone.gemfire.internal.cache.wan.AbstractGatewaySenderEventProcessor;
import com.gemstone.gemfire.internal.cache.wan.GatewaySenderException;
import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
import com.gemstone.gemfire.internal.size.SingleObjectSizer;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadFactory;

/**
 * 
 * @author Suranjan Kumar
 * 
 */
public class ConcurrentSerialGatewaySenderEventProcessor extends
    AbstractGatewaySenderEventProcessor {

  private final List processors = new ArrayList();

  private final SerialGatewaySenderImpl sender;

  private GemFireException ex = null;

  private final Set queues;
  /**
   * @param sender
   */
  public ConcurrentSerialGatewaySenderEventProcessor(
      SerialGatewaySenderImpl sender) {
    super(LogWriterImpl.createThreadGroup("Event Processor for GatewaySender_"
        + sender.getId(), sender.getLogger()),
        "Event Processor for GatewaySender_" + sender.getId(), sender);
    this.sender = sender;
    initializeMessageQueue(sender.getId());
    queues = new HashSet();
    for (SerialGatewaySenderEventProcessor processor : processors) {
      queues.add(processor.getQueue());
    }
    setDaemon(true);
  }

  @Override
  protected void initializeMessageQueue(String id) {
    for (int i = 0; i < sender.getDispatcherThreads(); i++) {
      processors.add(new SerialGatewaySenderEventProcessor(this.sender, id
          + "." + i));
      if (this.sender.getLogger().fineEnabled()) {
        this.sender.getLogger()
            .fine(
                "Created the SerialGatewayEventProcessor_"+i+" -> "
                    + processors.get(i));
      }
    }
  }

  //based on the fix for old wan Bug#46992 .revision is 39437  
  @Override
  public void enqueueEvent(EnumListenerEvent operation, EntryEventImpl event)
      throws IOException, CacheException {
    // Get the appropriate index into the gateways
    int index = Math.abs(getHashCode(((EntryEventImpl)event))
        % this.processors.size());
    // Distribute the event to the gateway
    enqueueEvent(operation, event, index);

  }
  
  public void enqueueEvent(EnumListenerEvent operation, EntryEventImpl event,
      int index) throws CacheException, IOException {
    // Get the appropriate gateway
    SerialGatewaySenderEventProcessor serialProcessor = this.processors
        .get(index);

    EntryEventImpl clonedEvent = event;
    if (sender.getOrderPolicy() == OrderPolicy.KEY
        || sender.getOrderPolicy() == OrderPolicy.PARTITION) {
      // Create copy since the event id will be changed, otherwise the same
      // event will be changed for multiple gateways. Fix for bug 44471.
      clonedEvent = new EntryEventImpl(event);
      try {
      EventID originalEventId = clonedEvent.getEventId();
      if (getLogger().fineEnabled()) {
        getLogger().fine("The original EventId is " + originalEventId);
      }
      // PARALLEL_THREAD_BUFFER * (index +1) + originalEventId.getThreadID();
      // generating threadId by the algorithm explained above used to clash with
      // fakeThreadId generated by putAll
      // below is new way to generate threadId so that it doesn't clash with
      // any.
      long newThreadId = ThreadIdentifier.createFakeThreadIDForParallelGateway(
          index, originalEventId.getThreadID());
      EventID newEventId = new EventID(originalEventId.getMembershipID(),
          newThreadId, originalEventId.getSequenceID());
      if (getLogger().fineEnabled()) {
        getLogger().fine(
            this + ": Generated event id for event with key=" + event.getKey()
                + ", index=" + index + ", original event id=" + originalEventId
                + ", new event id=" + newEventId);
      }
      clonedEvent.setEventId(newEventId);
      serialProcessor.enqueueEvent(operation, clonedEvent);
      } finally {
        clonedEvent.release();
      }
    } else {
      serialProcessor.enqueueEvent(operation, event);
    }

  }

  @Override
  public void run() {
    for(int i = 0; i < this.processors.size(); i++){
      if (sender.getLogger().fineEnabled()) {
        sender.getLogger().fine("Starting the serialProcessor " + i);
      }
      this.processors.get(i).start();
    }
    try {
      waitForRunningStatus();
    } catch (GatewaySenderException e) {
      this.ex = e;
    }

    synchronized (this.runningStateLock) {
      if (ex != null) {
        this.setException(ex);
        setIsStopped(true);
      } else {
        setIsStopped(false);
      }
      this.runningStateLock.notifyAll();
    }
    
    for (SerialGatewaySenderEventProcessor serialProcessor : this.processors) {
      try {
        serialProcessor.join();
      } catch (InterruptedException e) {
        if(sender.getLogger().fineEnabled()) {
          sender.getLogger().fine("Got InterruptedException while waiting for child threads to finish.");
          Thread.currentThread().interrupt();
        }  
      }
    }
  }
  
  private void waitForRunningStatus() {
    for (SerialGatewaySenderEventProcessor serialProcessor : this.processors) {
      synchronized (serialProcessor.runningStateLock) {
        while (serialProcessor.getException() == null
            && serialProcessor.isStopped()) {
          try {
            serialProcessor.runningStateLock.wait();
          } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
          }
        }
        Exception ex = serialProcessor.getException();
        if (ex != null) {
          throw new GatewaySenderException(
              LocalizedStrings.Sender_COULD_NOT_START_GATEWAYSENDER_0_BECAUSE_OF_EXCEPTION_1
                  .toLocalizedString(new Object[] { this.getId(),
                      ex.getMessage() }), ex.getCause());
        }
      }
    }
  }
  
  private int getHashCode(EntryEventImpl event) {
    // Get the hash code for the event based on the configured order policy
    int eventHashCode = 0;
    switch (this.sender.getOrderPolicy()) {
    case KEY:
      // key ordering
      eventHashCode = event.getKey().hashCode();
      break;
    case THREAD:
      // member id, thread id ordering
      // requires a lot of threads to achieve parallelism
      EventID eventId = event.getEventId();
      byte[] memberId = eventId.getMembershipID();
      long threadId = eventId.getThreadID();
      int memberIdHashCode = Arrays.hashCode(memberId);
      int threadIdHashCode = (int)(threadId ^ (threadId >>> 32));
      eventHashCode = memberIdHashCode + threadIdHashCode;
      if (getLogger().fineEnabled()) {
        getLogger().fine(
            this + ": Generated hashcode for event with key=" + event.getKey()
                + ", memberId=" + Arrays.toString(memberId) + ", threadId=" + threadId + ": "
                + eventHashCode);
      }
      break;
    case PARTITION:
      eventHashCode = PartitionRegionHelper.isPartitionedRegion(event
          .getRegion()) ? PartitionedRegionHelper.getHashKey(event)
      // Get the partition for the event
          : event.getKey().hashCode();
      // Fall back to key ordering if the region is not partitioned
      if (getLogger().fineEnabled()) {
        getLogger().fine(
            this + ": Generated partition hashcode for event with key="
                + event.getKey() + ": " + eventHashCode);
      }
      break;

    }
    return eventHashCode;
  }
  
  @Override
  public void stopProcessing() {
    if (!this.isAlive()) {
      return;
    }

    final LogWriterImpl.LoggingThreadGroup loggingThreadGroup = LogWriterImpl
        .createThreadGroup(
            "ConcurrentSerialGatewaySenderEventProcessor Logger Group",
            getLogger());

    ThreadFactory threadFactory = new ThreadFactory() {
      public Thread newThread(final Runnable task) {
        final Thread thread = new Thread(loggingThreadGroup, task,
            "ConcurrentSerialGatewaySenderEventProcessor Stopper Thread");
        thread.setDaemon(true);
        return thread;
      }
    };

    List stopperCallables = new ArrayList();
    for (SerialGatewaySenderEventProcessor serialProcessor : this.processors) {
      stopperCallables.add(new SenderStopperCallable(serialProcessor));
    }

    ExecutorService stopperService = Executors.newFixedThreadPool(
        processors.size(), threadFactory);
    try {
      List> futures = stopperService
          .invokeAll(stopperCallables);
      for (Future f : futures) {
        try {
          boolean b = f.get();
          if (getLogger().fineEnabled()) {
            getLogger().fine(
                "ConcurrentSerialGatewaySenderEventProcessor: "
                    + (b ? "Successfully" : "Unsuccesfully")
                    + " Stopped dispatching: " + this);
          }     
        } catch (ExecutionException e) {
          // we don't expect any exception but if caught then eat it and log
          // warning
          getLogger()
              .warning(
                  LocalizedStrings.GatewaySender_0_CAUGHT_EXCEPTION_WHILE_STOPPING_1,
                  sender, e.getCause());
        }
      }
    } catch (InterruptedException e) {
      throw new InternalGemFireException(e.getMessage());
    } catch (RejectedExecutionException rejectedExecutionEx) {
      throw rejectedExecutionEx;
    }
    setIsStopped(true);
    
    closeProcessor();
    
    if (getLogger().fineEnabled()) {
      getLogger().fine(
          "ConcurrentSerialGatewaySenderEventProcessor: Stopped dispatching: "
              + this);
    }
  }
  
  @Override
  public void closeProcessor() {
    for (SerialGatewaySenderEventProcessor processor : processors) {
      processor.closeProcessor();
    }
  }
  
  @Override
  public void pauseDispatching(){
    for (SerialGatewaySenderEventProcessor serialProcessor : this.processors) {
      serialProcessor.pauseDispatching();
    }
    super.pauseDispatching();
    if (getLogger().fineEnabled()) {
      getLogger().fine(
          "ConcurrentSerialGatewaySenderEventProcessor: Paused dispatching: "
              + this);
    }
  }
  
  @Override
  public void resumeDispatching() {
    for (SerialGatewaySenderEventProcessor serialProcessor : this.processors) {
      serialProcessor.resumeDispatching();
    }
    super.resumeDispatching();
    if (getLogger().fineEnabled()) {
      getLogger().fine(
          "ConcurrentSerialGatewaySenderEventProcessor: Resumed dispatching: "
              + this);
    }
  }

  /**
   * @return the queues
   */
  public Set getQueues() {
    return queues;
  }
  
  @Override
  public void removeCacheListener() {
    for(SerialGatewaySenderEventProcessor processor: processors) {
      processor.removeCacheListener();
    }
  }
  
  public long estimateMemoryFootprint(SingleObjectSizer sizer) {
    long size = super.estimateMemoryFootprint(sizer);

    if (queues != null) {
      for (RegionQueue q : queues) {
        size += q.estimateMemoryFootprint(sizer);
      }
    }
    
    for(int i = this.processors.size()-1; i >= 0; i--) {
      if (i >= this.processors.size()) {
        continue;
      }
      size += this.processors.get(i).estimateMemoryFootprint(sizer);
    }
    
    return size;
  }
  

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy