/* * 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.partitioned; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.util.HashSet; import java.util.Set; import org.apache.logging.log4j.Logger; import org.apache.geode.SystemFailure; import org.apache.geode.cache.CacheException; import org.apache.geode.cache.RegionDestroyedException; import org.apache.geode.cache.query.Index; import org.apache.geode.cache.query.QueryException; import org.apache.geode.distributed.internal.DM; import org.apache.geode.distributed.internal.DistributionManager; import org.apache.geode.distributed.internal.InternalDistributedSystem; import org.apache.geode.distributed.internal.ReplyException; import org.apache.geode.distributed.internal.ReplyMessage; import org.apache.geode.distributed.internal.ReplyProcessor21; import org.apache.geode.distributed.internal.membership.InternalDistributedMember; import org.apache.geode.internal.cache.ForceReattemptException; import org.apache.geode.internal.cache.PartitionedRegion; import org.apache.geode.internal.cache.PartitionedRegionException; import org.apache.geode.internal.i18n.LocalizedStrings; import org.apache.geode.internal.logging.LogService; import org.apache.geode.internal.logging.log4j.LocalizedMessage; import org.apache.geode.internal.logging.log4j.LogMarker; /** * This class represents a partition message for removing indexes. An instance of this class is send * over the wire to remove indexes on remote vms. This class extends PartitionMessage * {@link org.apache.geode.internal.cache.partitioned.PartitionMessage} * * */ public final class RemoveIndexesMessage extends PartitionMessage { private static final Logger logger = LogService.getLogger(); /** * Represents how many buckets had indexes and got removed. */ // private int bucketIndexesRemoved; /** * Name of the index to be removed. */ private String indexName; /** * Boolean indicating only a single index has to be removed. */ private boolean removeSingleIndex; /** * Constructor. */ public RemoveIndexesMessage() { } /** * Constructor for remove indexes to be sent over the wire. * * @param recipients members to which this message has to be sent * @param regionId partitioned region id * @param processor the processor to reply to */ public RemoveIndexesMessage(Set recipients, int regionId, ReplyProcessor21 processor) { super(recipients, regionId, processor); } /** * Constructor to remove a particular index which will be sent over the wire. * * @param recipients members to which this message has to be sent * @param regionId partitioned region id * @param processor the processor to reply to * @param removeSingleIndex boolean indicating to remove a partitular index * * @param indexName name of the index to be removed. * */ public RemoveIndexesMessage(Set recipients, int regionId, ReplyProcessor21 processor, boolean removeSingleIndex, String indexName) { super(recipients, regionId, processor); this.removeSingleIndex = removeSingleIndex; this.indexName = indexName; } /** * This message may be sent to nodes before the PartitionedRegion is completely initialized due to * the RegionAdvisor(s) knowing about the existance of a partitioned region at a very early part * of the initialization */ @Override protected final boolean failIfRegionMissing() { return false; } /** * This method is responsible to remove index on the given partitioned region. * * @param dm Distribution maanger for the system * @param pr Partitioned region to remove indexes on. * * @throws CacheException indicates a cache level error * @throws ForceReattemptException if the peer is no longer available * @throws InterruptedException if the thread is interrupted in the operation for example during * shutdown. */ @Override protected boolean operateOnPartitionedRegion(DistributionManager dm, PartitionedRegion pr, long startTime) throws CacheException, QueryException, ForceReattemptException, InterruptedException { // TODO Auto-generated method stub ReplyException replyEx = null; boolean result = true; int bucketIndexRemoved = 0; // invalid int numIndexesRemoved = 0; logger.info(LocalizedMessage .create(LocalizedStrings.RemoveIndexesMessage_WILL_REMOVE_THE_INDEXES_ON_THIS_PR___0, pr)); try { if (this.removeSingleIndex) { bucketIndexRemoved = pr.removeIndex(this.indexName); } else { bucketIndexRemoved = pr.removeIndexes(true); // remotely orignated } numIndexesRemoved = pr.getDataStore().getAllLocalBuckets().size(); } catch (Exception ex) { result = false; replyEx = new ReplyException(ex); } // send back the reply. sendReply(getSender(), getProcessorId(), dm, replyEx, result, bucketIndexRemoved, numIndexesRemoved); return false; } /** * Send a reply for remove indexes message. * * @param member representing the actual index creatro in the system * @param procId waiting processor * @param dm distirbution manager to send the message * @param ex any exceptions * @param result represents remove index worked properly. * @param bucketIndexesRemoved number of bucket indexes removed properly. */ void sendReply(InternalDistributedMember member, int procId, DM dm, ReplyException ex, boolean result, int bucketIndexesRemoved, int totalNumBuckets) { RemoveIndexesReplyMessage.send(member, processorId, dm, ex, result, bucketIndexesRemoved, totalNumBuckets); } /** * Sends this RemoveIndexesMessage to all the participating members in the system. * * @param pr prartitioned region to remove the index on. * @return PartitionResponse indicating sucessful remove index * */ public static PartitionResponse send(PartitionedRegion pr, Index ind, boolean removeAllIndex) { RemoveIndexesResponse processor = null; // PartitionResponse processor = null; RegionAdvisor advisor = (RegionAdvisor) (pr.getDistributionAdvisor()); final Set recipients = new HashSet(advisor.adviseDataStore()); // removing the originator for remove index command. recipients.remove(pr.getDistributionManager().getDistributionManagerId()); // RemoveIndexesResponse processor = null; // RemoveIndexesMessage removeIndexesMsg = new RemoveIndexesMessage(); if (recipients.size() > 0) { processor = (RemoveIndexesResponse) (new RemoveIndexesMessage()).createReplyProcessor(pr, recipients); } if (removeAllIndex) { RemoveIndexesMessage rm = new RemoveIndexesMessage(recipients, pr.getPRId(), processor); /* Set failures = */ pr.getDistributionManager().putOutgoing(rm); } else { // remove a single index. RemoveIndexesMessage rm = new RemoveIndexesMessage(recipients, pr.getPRId(), processor, true, ind.getName()); /* Set failures = */ pr.getDistributionManager().putOutgoing(rm); } return processor; } @Override PartitionResponse createReplyProcessor(PartitionedRegion r, Set recipients) { return new RemoveIndexesResponse(r.getSystem(), recipients); } public int getDSFID() { return PR_REMOVE_INDEXES_MESSAGE; } @Override public final void fromData(DataInput in) throws IOException, ClassNotFoundException { super.fromData(in); this.removeSingleIndex = in.readBoolean(); if (this.removeSingleIndex) this.indexName = in.readUTF(); } @Override public final void toData(DataOutput out) throws IOException { super.toData(out); out.writeBoolean(this.removeSingleIndex); if (this.removeSingleIndex) out.writeUTF(this.indexName); } /** * Processes remove index on the receiver. */ @Override public final void process(final DistributionManager dm) { Throwable thr = null; boolean sendReply = true; PartitionedRegion pr = null; try { logger.info(LocalizedMessage.create( LocalizedStrings.RemoveIndexesMessage_TRYING_TO_GET_PR_WITH_ID___0, this.regionId)); pr = PartitionedRegion.getPRFromId(this.regionId); logger.info(LocalizedMessage .create(LocalizedStrings.RemoveIndexesMessage_REMOVE_INDEXES_MESSAGE_GOT_THE_PR__0, pr)); if (pr == null /* && failIfRegionMissing() */ ) { throw new PartitionedRegionException( LocalizedStrings.RemoveIndexesMessage_COULD_NOT_GET_PARTITIONED_REGION_FROM_ID_0_FOR_MESSAGE_1_RECEIVED_ON_MEMBER_2_MAP_3 .toLocalizedString(new Object[] {Integer.valueOf(this.regionId), this, dm.getId(), PartitionedRegion.dumpPRId()})); } // remove the indexes on the pr. sendReply = operateOnPartitionedRegion(dm, pr, 0); } catch (PRLocallyDestroyedException pde) { if (logger.isDebugEnabled()) { logger.debug("Region is locally Destroyed "); } thr = pde; } catch (VirtualMachineError err) { SystemFailure.initiateFailure(err); // If this ever returns, rethrow the error. We're poisoned // now, so don't let this thread continue. throw err; } catch (Throwable t) { // Whenever you catch Error or Throwable, you must also // catch VirtualMachineError (see above). However, there is // _still_ a possibility that you are dealing with a cascading // error condition, so you also need to check to see if the JVM // is still usable: SystemFailure.checkFailure(); // log the exception at fine level if there is no reply to the message if (this.processorId == 0) { logger.debug("{} exception while processing message: {}", this, t.getMessage(), t); } else if (logger.isTraceEnabled(LogMarker.DM) && (t instanceof RuntimeException)) { logger.debug("Exception caught while processing message: {}", t.getMessage(), t); } if (t instanceof RegionDestroyedException && pr != null) { if (pr.isClosed) { logger.info(LocalizedMessage.create( LocalizedStrings.RemoveIndexesMessage_REGION_IS_LOCALLY_DESTROYED_THROWING_REGIONDESTROYEDEXCEPTION_FOR__0, pr)); thr = new RegionDestroyedException( LocalizedStrings.RemoveIndexesMessage_REGION_IS_LOCALLY_DESTROYED_ON_0 .toLocalizedString(dm.getId()), pr.getFullPath()); } } else { thr = t; } } finally { if (sendReply && this.processorId != 0) { ReplyException rex = null; if (thr != null) { rex = new ReplyException(thr); } sendReply(getSender(), this.processorId, dm, rex, pr, 0); } } } /** * Class representing remove index response. This class has all the information for successful or * unsucessful remove index on the member of the partitioned region. * * */ public static class RemoveIndexesResponse extends PartitionResponse { /** * Result of remove index. */ // boolean result; /** * Number of buckets index removed. */ private int numBucketIndexRemoved; /** * Total number of buckets in the sytem. */ private int numTotalRemoteBuckets; /** * Constructor. */ public RemoveIndexesResponse(InternalDistributedSystem ds, Set recipients) { super(ds, recipients); } /** * Waits for the response from the members for remove indexes call on this system. * * @throws ForceReattemptException */ public RemoveIndexesResult waitForResults() throws CacheException, ForceReattemptException { waitForCacheException(); return new RemoveIndexesResult(0); } /** * Sets the relevant information in the response. * * @param result true if index removed properly * @param numBucketsIndexesRemoved number of buckets indexes removed remotely for a memeber. * @param numTotalBuckets number of total buckets in the member. */ public void setResponse(boolean result, int numBucketsIndexesRemoved, int numTotalBuckets) { // this.result = result; this.numBucketIndexRemoved += numBucketsIndexesRemoved; this.numTotalRemoteBuckets += numTotalBuckets; } /** * Returns number of remotely removed indexes. */ public int getRemoteRemovedIndexes() { return this.numBucketIndexRemoved; } /** * Returns the total number of remote buckets. */ public int getTotalRemoteBuckets() { return this.numTotalRemoteBuckets; } }// RemoveIndexResponse /** * Class representing remove index results on pr. * */ public static class RemoveIndexesResult { /** * Int representing number of total bucket indexes removed. */ // private int numBucketIndexRemoved; /** * Constructor. * * @param numBucketIndexRemoved number of total bucket indexes removed. * */ public RemoveIndexesResult(int numBucketIndexRemoved) { // this.numBucketIndexRemoved = numBucketIndexRemoved; } } // RemoveIndexesResult /** * Class for index creation reply. This class has the information about sucessful or unsucessful * index creation. * */ public static final class RemoveIndexesReplyMessage extends ReplyMessage { /** Indexes removed or not. */ private boolean result; /** * Number of buckets locally remove indexes */ private int numBucketsIndexesRemoved; /** Number of total bukets in this vm. */ private int numTotalBuckets; /** * Default constructor. * */ public RemoveIndexesReplyMessage() { } /** * Constructor for index creation reply message. * * @param processorId processor id of the waiting processor * @param ex any exceptions * @param result ture if indexes removed properly else false * @param numBucketsIndexesRemoved number of buckets indexed. * @param numTotalBuckets number of total buckets. */ RemoveIndexesReplyMessage(int processorId, ReplyException ex, boolean result, int numBucketsIndexesRemoved, int numTotalBuckets) { super(); super.setException(ex); this.result = result; this.numBucketsIndexesRemoved = numBucketsIndexesRemoved; this.numTotalBuckets = numTotalBuckets; setProcessorId(processorId); } @Override public int getDSFID() { return PR_REMOVE_INDEXES_REPLY_MESSAGE; } @Override public void fromData(DataInput in) throws IOException, ClassNotFoundException { super.fromData(in); this.result = in.readBoolean(); this.numBucketsIndexesRemoved = in.readInt(); this.numTotalBuckets = in.readInt(); } @Override public void toData(DataOutput out) throws IOException { super.toData(out); out.writeBoolean(this.result); out.writeInt(this.numBucketsIndexesRemoved); out.writeInt(this.numTotalBuckets); } /** * Actual method sending the index creation reply message. * * @param recipient the originator of index creation message * @param processorId waiting processor id * @param dm distribution manager * @param ex any exceptions * @param result true is indexes removed sucessfully * @param numBucketsIndexesRemoved number of buckets indexed * @param numTotalBuckets total number of buckets */ public static void send(InternalDistributedMember recipient, int processorId, DM dm, ReplyException ex, boolean result, int numBucketsIndexesRemoved, int numTotalBuckets) { RemoveIndexesReplyMessage rmIndMsg = new RemoveIndexesReplyMessage(processorId, ex, result, numBucketsIndexesRemoved, numTotalBuckets); rmIndMsg.setRecipient(recipient); dm.putOutgoing(rmIndMsg); } /** * Processes this RemoveIndexesReplyMessge on the receiver. * * @param dm distribution manager */ @Override public final void process(final DM dm, final ReplyProcessor21 p) { RemoveIndexesResponse processor = (RemoveIndexesResponse) p; if (processor != null) { processor.setResponse(this.result, this.numBucketsIndexesRemoved, this.numTotalBuckets); processor.process(this); } } } // RemvoeIndexReplyMessage }