/* * 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; import java.util.*; import java.io.*; import org.apache.geode.*; import org.apache.geode.cache.*; import org.apache.geode.distributed.*; import org.apache.geode.distributed.internal.*; /** * Sends a chunk of queued messages to everyone currently playing a role. * * @since GemFire 5.0 * */ public class SendQueueOperation { // private ReplyProcessor21 processor = null; private DM dm; private DistributedRegion r; private List l; private Role role; SendQueueOperation(DM dm, DistributedRegion r, List l, Role role) { this.dm = dm; this.r = r; this.l = l; this.role = role; } /** * Returns true if distribution successful. Also modifies message list by removing messages sent * to the required role. */ boolean distribute() { CacheDistributionAdvisor advisor = this.r.getCacheDistributionAdvisor(); Set recipients = advisor.adviseCacheOpRole(this.role); if (recipients.isEmpty()) { return false; } ReplyProcessor21 processor = new ReplyProcessor21(this.dm, recipients); // @todo darrel: make this a reliable one SendQueueMessage msg = new SendQueueMessage(); msg.setRecipients(recipients); msg.setRegionPath(this.r.getFullPath()); msg.setProcessorId(processor.getProcessorId()); msg.setOperations(this.l); dm.putOutgoing(msg); try { processor.waitForReplies(); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); // It's OK to keep going, no significant work below. } catch (ReplyException ex) { ex.handleAsUnexpected(); } if (msg.getSuccessfulRecipients().isEmpty()) { return false; } // @todo darrel: now remove sent items from the list this.r.getCachePerfStats().incReliableQueuedOps(-l.size()); this.l.clear(); return true; } /** * A batch of queued messages. Once they are processed on the other side an ack is sent. */ public static final class SendQueueMessage extends SerialDistributionMessage implements MessageWithReply { private int processorId; private String regionPath; /** * List of QueuedOperation instances */ private List ops; @Override public int getProcessorId() { return this.processorId; } public void setProcessorId(int id) { this.processorId = id; } public String getRegionPath() { return this.regionPath; } public void setRegionPath(String rp) { this.regionPath = rp; } public void setOperations(List l) { this.ops = l; } @Override protected void process(DistributionManager dm) { ReplyException rex = null; boolean ignored = false; try { GemFireCacheImpl gfc = (GemFireCacheImpl) CacheFactory.getInstance(dm.getSystem()); final LocalRegion lclRgn = gfc.getRegionByPathForProcessing(this.regionPath); if (lclRgn != null) { lclRgn.waitOnInitialization(); final long lastMod = gfc.cacheTimeMillis(); Iterator it = this.ops.iterator(); while (it.hasNext()) { QueuedOperation op = (QueuedOperation) it.next(); op.process(lclRgn, getSender(), lastMod); } } else { ignored = true; } } catch (RegionDestroyedException e) { ignored = true; } catch (CancelException e) { ignored = true; } finally { ReplyMessage.send(getSender(), this.processorId, rex, dm, ignored, false, false); } } public int getDSFID() { return SEND_QUEUE_MESSAGE; } @Override public void fromData(DataInput in) throws IOException, ClassNotFoundException { super.fromData(in); this.regionPath = DataSerializer.readString(in); this.processorId = in.readInt(); { int opCount = in.readInt(); QueuedOperation[] ops = new QueuedOperation[opCount]; for (int i = 0; i < opCount; i++) { ops[i] = QueuedOperation.createFromData(in); } this.ops = Arrays.asList(ops); } } @Override public void toData(DataOutput out) throws IOException { super.toData(out); DataSerializer.writeString(this.regionPath, out); out.writeInt(this.processorId); { int opCount = this.ops.size(); out.writeInt(opCount); for (int i = 0; i < opCount; i++) { QueuedOperation op = (QueuedOperation) this.ops.get(i); op.toData(out); } } } @Override public String toString() { StringBuffer buff = new StringBuffer(); buff.append(getClass().getName()); buff.append("(region path='"); // make sure this is the first one buff.append(this.regionPath); buff.append("'"); buff.append("; processorId="); buff.append(this.processorId); buff.append("; queuedOps="); buff.append(this.ops.size()); buff.append(")"); return buff.toString(); } } }