/*
* 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.
*/
//
// StreamingOperationManyTest.java
//
package org.apache.geode.distributed.internal.streaming;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.apache.geode.LogWriter;
import org.apache.geode.distributed.internal.DistributionMessage;
import org.apache.geode.distributed.internal.InternalDistributedSystem;
import org.apache.geode.distributed.internal.ReplyException;
import org.apache.geode.distributed.internal.ReplyProcessor21;
import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
import org.apache.geode.internal.cache.Token;
import org.apache.geode.test.dunit.Host;
import org.apache.geode.test.dunit.VM;
import org.apache.geode.test.dunit.internal.JUnit4DistributedTestCase;
import org.apache.geode.test.junit.categories.DistributedTest;
@Category(DistributedTest.class)
public class StreamingOperationManyDUnitTest extends JUnit4DistributedTestCase {
@Test
public void testStreamingManyProvidersNoExceptions() throws Exception {
// final String name = this.getUniqueName();
// ask four other VMs to connect to the distributed system
// this will be the data provider
Host host = Host.getHost(0);
HashSet<InternalDistributedMember> otherMemberIds = new HashSet<>();
for (int i = 0; i < 4; i++) {
VM vm = host.getVM(i);
otherMemberIds.add(vm.invoke(() -> getSystem().getDistributedMember()));
}
TestStreamingOperationManyProviderNoExceptions streamOp =
new TestStreamingOperationManyProviderNoExceptions(getSystem());
streamOp.getDataFromAll(otherMemberIds);
assertTrue(streamOp.dataValidated);
}
// about 100 chunks worth of integers?
protected static final int NUM_INTEGERS = 32 * 1024 /* default socket buffer size */ * 100 / 4;
public static class TestStreamingOperationManyProviderNoExceptions extends StreamingOperation {
volatile boolean dataValidated = false;
ConcurrentMap senderMap = new ConcurrentHashMap();
ConcurrentMap senderNumChunksMap = new ConcurrentHashMap();
private int numChunks = -1; // made inst var to fix bug 37421
public TestStreamingOperationManyProviderNoExceptions(InternalDistributedSystem sys) {
super(sys);
}
protected DistributionMessage createRequestMessage(Set recipients, ReplyProcessor21 processor) {
TestRequestStreamingMessageManyProviderNoExceptions msg =
new TestRequestStreamingMessageManyProviderNoExceptions();
msg.setRecipients(recipients);
msg.processorId = processor == null ? 0 : processor.getProcessorId();
return msg;
}
protected synchronized boolean processData(List objects, InternalDistributedMember sender,
int sequenceNum, boolean lastInSequence) {
LogWriter logger = this.sys.getLogWriter();
ConcurrentMap chunkMap = (ConcurrentMap) senderMap.get(sender);
if (chunkMap == null) {
chunkMap = new ConcurrentHashMap();
ConcurrentMap chunkMap2 = (ConcurrentMap) this.senderMap.putIfAbsent(sender, chunkMap);
if (chunkMap2 != null) {
chunkMap = chunkMap2;
}
}
// assert that we haven't gotten this sequence number yet
Object prevValue = chunkMap.putIfAbsent(new Integer(sequenceNum), objects);
if (prevValue != null) {
logger.severe("prevValue != null");
}
if (lastInSequence) {
numChunks = sequenceNum + 1;
prevValue = senderNumChunksMap.putIfAbsent(sender, new Integer(sequenceNum + 1)); // sequenceNum
// is
// 0-based
if (prevValue != null) {
logger.severe("prevValue != null");
}
// assert that we haven't gotten a true for lastInSequence yet
}
// logger.info("DEBUG processData: sender=" + sender
// + " objects.size=" + objects.size()
// + " seqNum=" + sequenceNum
// + " lastInSeq=" + lastInSequence
// + " chunkMap.size=" + chunkMap.size()
// + " numChunks=" + numChunks
// + " senderMap.size=" + senderMap.size());
// are we completely done with all senders ?
if (chunkMap.size() == numChunks && // done with this sender
senderMap.size() == 4) { // we've heard from all 4 senders
// logger.info("completely done (maybe)");
boolean completelyDone = true; // start with true assumption
for (Iterator itr = senderMap.entrySet().iterator(); itr.hasNext();) {
Map.Entry entry = (Map.Entry) itr.next();
InternalDistributedMember senderV = (InternalDistributedMember) entry.getKey();
ConcurrentMap chunkMapV = (ConcurrentMap) entry.getValue();
Integer numChunksV = (Integer) senderNumChunksMap.get(senderV);
if (chunkMapV == null) {
// logger.info("Not completely done senderV=" + senderV
// + " chunkMapV==null");
completelyDone = false;
break;
} else if (numChunksV == null) {
// logger.info("Not completely done senderV=" + senderV
// + " numChunksV==null");
completelyDone = false;
break;
} else if (chunkMapV.size() != numChunksV.intValue()) {
// logger.info("Not completely done senderV=" + senderV
// + " chunkMapV.size=" + chunkMapV.size()
// + " numChunksV=" + numChunksV.intValue());
completelyDone = false;
break;
}
}
if (completelyDone) {
validateData();
}
}
return true;
}
private void validateData() {
LogWriter logger = this.sys.getLogWriter();
for (Iterator senderItr = this.senderMap.entrySet().iterator(); senderItr.hasNext();) {
Map.Entry entry = (Map.Entry) senderItr.next();
ConcurrentMap chunkMap = (ConcurrentMap) entry.getValue();
InternalDistributedMember sender = (InternalDistributedMember) entry.getKey();
List[] arrayOfLists = new ArrayList[chunkMap.size()];
List objList;
int expectedInt = 0;
// sort the input streams
for (Iterator itr = chunkMap.entrySet().iterator(); itr.hasNext();) {
Map.Entry entry2 = (Map.Entry) itr.next();
int seqNum = ((Integer) entry2.getKey()).intValue();
objList = (List) entry2.getValue();
arrayOfLists[seqNum] = objList;
}
int count = 0;
for (int i = 0; i < chunkMap.size(); i++) {
Iterator itr = arrayOfLists[i].iterator();
Integer nextInteger;
while (itr.hasNext()) {
nextInteger = (Integer) itr.next();
if (nextInteger.intValue() != expectedInt) {
logger.severe("nextInteger.intValue() != expectedInt");
return;
}
expectedInt += 10; // the secret number is incremented by 10 each time
count++;
}
}
if (count != NUM_INTEGERS) {
logger.severe(
"found " + count + " integers from " + sender + " , expected " + NUM_INTEGERS);
return;
}
logger.info("Received " + count + " integers from " + sender + " in " + chunkMap.size()
+ " chunks");
}
dataValidated = true;
}
}
public static final class TestRequestStreamingMessageManyProviderNoExceptions
extends StreamingOperation.RequestStreamingMessage {
private int nextInt = -10;
private int count = 0;
protected Object getNextReplyObject() throws ReplyException {
if (++count > NUM_INTEGERS) {
return Token.END_OF_STREAM;
}
nextInt += 10;
return new Integer(nextInt);
}
public int getDSFID() {
return NO_FIXED_ID;
}
}
}