/*
* 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 org.apache.geode.internal.cache.wan.parallel;
import org.apache.geode.cache.CacheException;
import org.apache.geode.cache.CacheListener;
import org.apache.geode.cache.Region;
import org.apache.geode.internal.cache.Conflatable;
import org.apache.geode.internal.cache.DistributedRegion;
import org.apache.geode.internal.cache.ForceReattemptException;
import org.apache.geode.internal.cache.PartitionedRegion;
import org.apache.geode.internal.cache.RegionQueue;
import org.apache.geode.internal.cache.wan.AbstractGatewaySender;
import org.apache.geode.internal.cache.wan.GatewaySenderEventImpl;
import org.apache.geode.internal.cache.wan.parallel.ParallelGatewaySenderEventProcessor;
import org.apache.geode.internal.cache.wan.parallel.ParallelGatewaySenderQueue;
import java.util.List;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import org.apache.geode.internal.size.SingleObjectSizer;
/**
* Queue built on top of {@link ParallelGatewaySenderQueue} which allows multiple dispatcher to
* register and do peek/remove from the underlying {@link ParallelGatewaySenderQueue}
*
* There is only one queue, but this class co-ordinates access by multiple threads such that we get
* zero contention while peeking or removing.
*
* It implements RegionQueue so that AbstractGatewaySenderEventProcessor can work on it.
*
*
*/
public class ConcurrentParallelGatewaySenderQueue implements RegionQueue {
private final AbstractGatewaySender sender;
private final ParallelGatewaySenderEventProcessor processors[];
public ConcurrentParallelGatewaySenderQueue(AbstractGatewaySender sender,
ParallelGatewaySenderEventProcessor pro[]) {
this.sender = sender;
this.processors = pro;
}
@Override
public boolean put(Object object) throws InterruptedException, CacheException {
throw new UnsupportedOperationException("CPGAQ method(put) is not supported");
}
@Override
public void close() {
/*
* this.commonQueue.close(); // no need to free peekedEvents since they all had makeOffHeap
* called on them. throw new
* UnsupportedOperationException("CPGAQ method(close) is not supported");
*/
}
@Override
public Region getRegion() {
return this.processors[0].getQueue().getRegion();
}
public PartitionedRegion getRegion(String fullpath) {
return processors[0].getRegion(fullpath);
}
public Set<PartitionedRegion> getRegions() {
return ((ParallelGatewaySenderQueue) (processors[0].getQueue())).getRegions();
}
@Override
public Object take() throws CacheException, InterruptedException {
throw new UnsupportedOperationException("This method(take) is not suported");
}
@Override
public List take(int batchSize) throws CacheException, InterruptedException {
throw new UnsupportedOperationException("This method(take) is not suported");
}
@Override
public void remove() throws CacheException {
throw new UnsupportedOperationException("This method(remove) is not suported");
}
@Override
public Object peek() throws InterruptedException, CacheException {
throw new UnsupportedOperationException("This method(peek) is not suported");
}
@Override
public List peek(int batchSize) throws InterruptedException, CacheException {
throw new UnsupportedOperationException("This method(peek) is not suported");
}
@Override
public List peek(int batchSize, int timeToWait) throws InterruptedException, CacheException {
throw new UnsupportedOperationException("This method(peek) is not suported");
}
@Override
public int size() {
// is that fine??
return this.processors[0].getQueue().size();
}
public int localSize() {
return localSize(false);
}
public int localSize(boolean includeSecondary) {
return ((ParallelGatewaySenderQueue) (processors[0].getQueue())).localSize(includeSecondary);
}
@Override
public void addCacheListener(CacheListener listener) {
this.processors[0].getQueue().addCacheListener(listener);
}
@Override
public void removeCacheListener() {
this.processors[0].removeCacheListener();
}
@Override
public void remove(int top) throws CacheException {
throw new UnsupportedOperationException("This method(remove) is not suported");
}
/*
* public void resetLastPeeked(){ this.resetLastPeeked = true; }
*/
public long estimateMemoryFootprint(SingleObjectSizer sizer) {
long size = 0;
for (int i = 0; i < processors.length; i++)
size += ((ParallelGatewaySenderQueue) this.processors[i].getQueue())
.estimateMemoryFootprint(sizer);
return size;
}
/*
* @Override public void release() { for(int i =0; i< processors.length; i++){
* processors[i].getQueue().release(); } }
*/
public void removeShadowPR(String prRegionName) {
for (int i = 0; i < processors.length; i++) {
processors[i].removeShadowPR(prRegionName);
}
}
public void addShadowPartitionedRegionForUserPR(PartitionedRegion pr) {
// Reset enqueuedAllTempQueueEvents if the sender is running
// This is done so that any events received while the shadow PR is added are queued in the
// tmpQueuedEvents
// instead of blocking the distribute call which could cause a deadlock. See GEM-801.
if (this.sender.isRunning()) {
this.sender.setEnqueuedAllTempQueueEvents(false);
}
this.sender.getLifeCycleLock().writeLock().lock();
try {
for (int i = 0; i < processors.length; i++) {
processors[i].addShadowPartitionedRegionForUserPR(pr);
}
} finally {
this.sender.getLifeCycleLock().writeLock().unlock();
}
}
private ParallelGatewaySenderEventProcessor getPGSProcessor(int bucketId) {
int index = bucketId % this.processors.length;
return processors[index];
}
public BlockingQueue<GatewaySenderEventImpl> getBucketTmpQueue(int bucketId) {
return getPGSProcessor(bucketId).getBucketTmpQueue(bucketId);
}
public void notifyEventProcessorIfRequired(int bucketId) {
getPGSProcessor(bucketId).notifyEventProcessorIfRequired(bucketId);
}
public void clear(PartitionedRegion pr, int bucketId) {
getPGSProcessor(bucketId).clear(pr, bucketId);
}
public void cleanUp() {
for (int i = 0; i < processors.length; i++)
((ParallelGatewaySenderQueue) this.processors[i].getQueue()).cleanUp();
}
public void conflateEvent(Conflatable conflatableObject, int bucketId, Long tailKey) {
getPGSProcessor(bucketId).conflateEvent(conflatableObject, bucketId, tailKey);
}
public void addShadowPartitionedRegionForUserRR(DistributedRegion userRegion) {
for (int i = 0; i < processors.length; i++) {
processors[i].addShadowPartitionedRegionForUserRR(userRegion);;
}
}
public long getNumEntriesInVMTestOnly() {
return ((ParallelGatewaySenderQueue) (processors[0].getQueue())).getNumEntriesInVMTestOnly();
}
public long getNumEntriesOverflowOnDiskTestOnly() {
return ((ParallelGatewaySenderQueue) (processors[0].getQueue()))
.getNumEntriesOverflowOnDiskTestOnly();
}
}