com.gemstone.gemfire.internal.cache.wan.serial.ConcurrentSerialGatewaySenderEventProcessor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gemfire-core Show documentation
Show all versions of gemfire-core Show documentation
SnappyData store based off Pivotal GemFireXD
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;
}
}