All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gemstone.gemfire.internal.cache.partitioned.InvalidateMessage Maven / Gradle / Ivy

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.partitioned;

import com.gemstone.gemfire.DataSerializer;
import com.gemstone.gemfire.i18n.LogWriterI18n;
import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Collections;
import java.util.Set;

import com.gemstone.gemfire.cache.CacheException;
import com.gemstone.gemfire.cache.EntryExistsException;
import com.gemstone.gemfire.cache.EntryNotFoundException;
import com.gemstone.gemfire.distributed.internal.DM;
import com.gemstone.gemfire.distributed.internal.DirectReplyProcessor;
import com.gemstone.gemfire.distributed.internal.DistributionManager;
import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem;
import com.gemstone.gemfire.distributed.internal.ReplyException;
import com.gemstone.gemfire.distributed.internal.ReplyMessage;
import com.gemstone.gemfire.distributed.internal.ReplyProcessor21;
import com.gemstone.gemfire.distributed.internal.ReplySender;
import com.gemstone.gemfire.distributed.internal.membership.InternalDistributedMember;
import com.gemstone.gemfire.internal.Assert;
import com.gemstone.gemfire.internal.NanoTimer;
import com.gemstone.gemfire.internal.cache.DataLocationException;
import com.gemstone.gemfire.internal.cache.EntryEventImpl;
import com.gemstone.gemfire.internal.cache.EnumListenerEvent;
import com.gemstone.gemfire.internal.cache.FilterRoutingInfo;
import com.gemstone.gemfire.internal.cache.KeyWithRegionContext;
import com.gemstone.gemfire.internal.cache.PartitionedRegion;
import com.gemstone.gemfire.internal.cache.ForceReattemptException;
import com.gemstone.gemfire.internal.cache.PartitionedRegionDataStore;
import com.gemstone.gemfire.internal.cache.PartitionedRegionHelper;
import com.gemstone.gemfire.internal.cache.PrimaryBucketException;
import com.gemstone.gemfire.internal.cache.TXStateInterface;
import com.gemstone.gemfire.internal.cache.versions.VersionTag;

public final class InvalidateMessage extends DestroyMessage {

  /**
   * Empty constructor to satisfy {@link com.gemstone.gemfire.DataSerializer}
   * requirements
   */
  public InvalidateMessage() {
  }

  private InvalidateMessage(InternalDistributedMember recipient,
                            boolean notifyOnly,
                            int regionId,
                            DirectReplyProcessor processor,
                            EntryEventImpl event,
                            TXStateInterface tx) {
    super(recipient,
          notifyOnly,
          regionId,
          processor,
          event,
          tx,
          null, // expectedOldValue
          false);
  }

  private InvalidateMessage(Set recipients,
                            boolean notifyOnly,
                            int regionId,
                            DirectReplyProcessor processor,
                            EntryEventImpl event,
                            TXStateInterface tx) {
    super(recipients,
          notifyOnly,
          regionId,
          processor,
          event,
          tx,
          null, // expectedOldValue
          false);
  }

  InvalidateMessage(InvalidateMessage original, EntryEventImpl event) {
    super(original);
    this.versionTag = event.getVersionTag();
  }
  
  /**
   * added for sending old value over the wire to the bridge servers with Cqs
   * @param original invalidateMessage originated at remote vm.
   * @param event EntryEventImpl generated by operation on the bucket region.
   * @param members list of members which needs old value.
   * @since 5.5
   */
  InvalidateMessage(InvalidateMessage original, EntryEventImpl event, Set members) {
    super(original, event, members);
  }


  @Override
  public PartitionMessage getMessageForRelayToListeners(EntryEventImpl event, Set members) {
    if (event.hasOldValue() && ( members != null && !members.isEmpty())){ 
      return new InvalidateMessage(this, event, members);
    }
    return new InvalidateMessage(this, event);
  }
  
  /**
   * send a notification-only message to a set of listeners.  The processor
   * id is passed with the message for reply message processing.  This method
   * does not wait on the processor.
   * 
   * @param cacheOpReceivers receivers of associated bucket CacheOperationMessage
   * @param adjunctRecipients receivers that must get the event
   * @param filterRoutingInfo client routing information
   * @param r the region affected by the event
   * @param event the event that prompted this action
   * @param processor the processor to reply to
   * @return members that could not be notified
   */
  public static Set notifyListeners(Set cacheOpReceivers, Set adjunctRecipients,
      FilterRoutingInfo filterRoutingInfo, 
      PartitionedRegion r, EntryEventImpl event, 
      DirectReplyProcessor processor) {
    InvalidateMessage msg = new InvalidateMessage(Collections.EMPTY_SET, 
        true, r.getPRId(), processor, event, event.getTXState(r));
    msg.versionTag = event.getVersionTag();
    return msg.relayToListeners(cacheOpReceivers, adjunctRecipients,
        filterRoutingInfo, event, r, processor);
  }

  /**
   * Sends an InvalidateMessage
   * {@link com.gemstone.gemfire.cache.Region#invalidate(Object)} to the
   * recipient
   * 
   * @param recipient the recipient of the message
   * @param r
   *          the PartitionedRegion for which the invalidate was performed
   * @param event the event causing this message
   * @return the InvalidateResponse processor used to await the potential
   *         {@link com.gemstone.gemfire.cache.CacheException}
   * @throws ForceReattemptException if the peer is no longer available
   */
  public static InvalidateResponse send(
      final InternalDistributedMember recipient, final PartitionedRegion r,
      final EntryEventImpl event) throws ForceReattemptException {

    final InvalidateMessage m = prepareSend(r.getSystem(), recipient, r, event);
    final Set failures = r.getDistributionManager().putOutgoing(m);
    if (failures != null && failures.size() > 0) {
      throw new ForceReattemptException(LocalizedStrings
          .InvalidateMessage_FAILED_SENDING_0.toLocalizedString(m));
    }
    return (InvalidateResponse)m.processor;
  }

  /**
   * Prepares an InvalidateMessage
   * {@link com.gemstone.gemfire.cache.Region#invalidate(Object)} for send to
   * the recipient.
   * 
   * @param sys
   *          the distributed system
   * @param recipient
   *          the recipient of the message
   * @param r
   *          the PartitionedRegion for which the invalidate was performed
   * @param event
   *          the event causing this message
   * 
   * @return the prepared InvalidateMessage
   */
  public static InvalidateMessage prepareSend(
      final InternalDistributedSystem sys,
      final InternalDistributedMember recipient, final PartitionedRegion r,
      final EntryEventImpl event) {
    //  recipient may be null for remote notifications
    //Assert.assertTrue(recipient != null, "InvalidateMessage NULL recipient");

    final TXStateInterface tx = event.getTXState(r);
    final InvalidateResponse p = new InvalidateResponse(sys, recipient,
        event.getKey(), tx);
    final InvalidateMessage m = new InvalidateMessage(recipient, false,
        r.getPRId(), p, event, tx);
    return m;
  }

  /**
   * Sends an InvalidateMessage
   * {@link com.gemstone.gemfire.cache.Region#invalidate(Object)}message to the
   * recipient
   * 
   * @param recipients the recipients of the message
   * @param r
   *          the PartitionedRegion for which the invalidate was performed
   * @param event the event causing this message
   * @return the InvalidateResponse processor used to await the potential
   *         {@link com.gemstone.gemfire.cache.CacheException}
   * @throws ForceReattemptException if the peer is no longer available
   */
  public static InvalidateResponse send(Set recipients,
      PartitionedRegion r, EntryEventImpl event)
      throws ForceReattemptException
  {
    // recipient may be null for remote notifications
    //Assert.assertTrue(recipient != null, "InvalidateMessage NULL recipient");

    final TXStateInterface tx = event.getTXState(r);
    final InvalidateResponse p = new InvalidateResponse(r.getSystem(),
        recipients, event.getKey(), tx);
    final InvalidateMessage m = new InvalidateMessage(recipients, false,
        r.getPRId(), p, event, tx);
    final Set failures = r.getDistributionManager().putOutgoing(m);
    if (failures != null && failures.size() > 0) {
      throw new ForceReattemptException(LocalizedStrings
          .InvalidateMessage_FAILED_SENDING_0.toLocalizedString(m));
    }
    return p;
  }

  /**
   * This method is called upon receipt and make the desired changes to the
   * PartitionedRegion Note: It is very important that this message does NOT
   * cause any deadlocks as the sender will wait indefinitely for the
   * acknowledgement
   * 
   * @throws EntryExistsException
   * @throws DataLocationException 
   */
  @Override
  protected boolean operateOnPartitionedRegion(DistributionManager dm,
      PartitionedRegion r, long startTime)
      throws EntryExistsException, DataLocationException
  {
    LogWriterI18n l = r.getCache().getLoggerI18n();
//    if (DistributionManager.VERBOSE) {
//      l.fine(getClass().getName() + " operateOnRegion: " + r.getFullPath());
//    }

    InternalDistributedMember eventSender = originalSender;
    if (eventSender == null) {
       eventSender = getSender();
    }
    final Object key = getKey();
    if (r.keyRequiresRegionContext()) {
      ((KeyWithRegionContext)key).setRegionContext(r);
    }
    final EntryEventImpl event = EntryEventImpl.create(
        r,
        getOperation(),
        key,
        null, /*newValue*/
        getCallbackArg(),
        false/*originRemote - false to force distribution in buckets*/,
        eventSender,
        true/*generateCallbacks*/,
        false/*initializeId*/);
    try {
    if (this.versionTag != null) {
      this.versionTag.replaceNullIDs(getSender());
      event.setVersionTag(this.versionTag);
    }
    if (this.bridgeContext != null) {
      event.setContext(this.bridgeContext);
    }
//    Assert.assertTrue(eventId != null);  bug #47235: region invalidation doesn't send event ids
    event.setEventId(eventId);
    event.setPossibleDuplicate(this.posDup);
    event.setLockingPolicy(getLockingPolicy());

    PartitionedRegionDataStore ds = r.getDataStore();
    boolean sendReply = true;
//    boolean failed = false;
    event.setInvokePRCallbacks(!notificationOnly);
    if (!notificationOnly) {
      final TXStateInterface tx = getTXState(r);
      event.setTXState(tx);
      Assert.assertTrue(ds!=null, "This process should have storage for an item in " + this.toString());
      try {
        r.operationStart();
        Integer bucket = Integer.valueOf(PartitionedRegionHelper.getHashKey(event));
        event.setCausedByMessage(this);
        r.getDataView(tx).invalidateOnRemote(event, true/*invokeCallbacks*/,
            false/*forceNewEntry*/);
        this.versionTag = event.getVersionTag();
        if (DistributionManager.VERBOSE) {
          l.info(
              LocalizedStrings.ONE_ARG,
              getClass().getName() + " invalidateLocally in bucket: " + bucket
              + ", key: " + key);
        }
      }
      catch (DataLocationException e) {
        ((ForceReattemptException)e).checkKey(event.getKey());
        throw e;
      }
      catch (EntryNotFoundException eee) {
        //        failed = true;
        if (l.fineEnabled()) {
          l.fine(getClass().getName()
              + ": operateOnRegion caught EntryNotFoundException");
        }
        sendReply(getSender(), getProcessorId(), dm, new ReplyException(eee), r, startTime);
        sendReply = false; // this prevents us from acking later
      }
      catch (PrimaryBucketException pbe) {
        sendReply(getSender(), getProcessorId(), dm, new ReplyException(pbe), r, startTime);
        return false;
      } finally {
        r.operationCompleted();
      }

    }
    else {
      event.setRegion(r);
      event.setOriginRemote(true);
      if (this.versionTag != null) {
        this.versionTag.replaceNullIDs(getSender());
        event.setVersionTag(this.versionTag);
      }
      if (this.filterInfo != null) {
        event.setLocalFilterInfo(this.filterInfo.getFilterInfo(dm.getDistributionManagerId()));
      }
      r.invokeInvalidateCallbacks(EnumListenerEvent.AFTER_INVALIDATE, event, r.isInitialized());
    }
    
    return sendReply;

    } finally {
      event.release();
    }
  }

  // override reply message type from PartitionMessage
  @Override
  protected void sendReply(InternalDistributedMember member, int procId, DM dm, ReplyException ex, PartitionedRegion pr, long startTime) {
    if (pr != null && startTime > 0) {
      pr.getPrStats().endPartitionMessagesProcessing(startTime); 
    }
    InvalidateReplyMessage.send(member, procId, getReplySender(dm), ex, this);
  }

  @Override
  public int getDSFID() {
    return PR_INVALIDATE_MESSAGE;
  }
  
  public static final class InvalidateReplyMessage extends ReplyMessage {
    VersionTag versionTag;

    /**
     * Empty constructor to conform to DataSerializable interface 
     */
    public InvalidateReplyMessage() {
    }

    private InvalidateReplyMessage(int processorId, ReplyException ex,
        InvalidateMessage sourceMessage) {
      super(sourceMessage, true, true);
      setProcessorId(processorId);
      this.versionTag = sourceMessage.versionTag;
      setException(ex);
    }

    /** Send an ack */
    public static void send(InternalDistributedMember recipient,
        int processorId, ReplySender replySender, ReplyException ex,
        InvalidateMessage sourceMessage) {
      Assert.assertTrue(recipient != null, "InvalidateReplyMessage NULL reply message");
      InvalidateReplyMessage m = new InvalidateReplyMessage(processorId, ex,
          sourceMessage);
      m.setRecipient(recipient);
      replySender.putOutgoing(m);
    }
      
    /**
     * Processes this message.  This method is invoked by the receiver
     * of the message.
     * @param dm the distribution manager that is processing the message.
     */
    @Override
    public void process(final DM dm, final ReplyProcessor21 rp) {
      final long startTime = getTimestamp();
      LogWriterI18n l = dm.getLoggerI18n();
      if (DistributionManager.VERBOSE) {
        l.fine("InvalidateReplyMessage process invoking reply processor with processorId:" + this.processorId);
      }
  
      //dm.getLogger().warning("InvalidateResponse processor is " + ReplyProcessor21.getProcessor(this.processorId));
      if (rp == null) {
        if (DistributionManager.VERBOSE) {
          l.fine("InvalidateReplyMessage processor not found");
        }
        return;
      }
      if (rp instanceof InvalidateResponse) {
        InvalidateResponse processor = (InvalidateResponse)rp;
        processor.setResponse(this);
      }
      rp.process(this);
  
      if (DistributionManager.VERBOSE) {
        LogWriterI18n logger = dm.getLoggerI18n();
        logger.info(LocalizedStrings.InvalidateMessage_0__PROCESSED__1, new Object[] {rp, this});
      }

      dm.getStats().incReplyMessageTime(NanoTimer.getTime()-startTime);
    }
    
    @Override
    public int getDSFID() {
      return PR_INVALIDATE_REPLY_MESSAGE;
    }
    
    @Override
    public void toData(DataOutput out) throws IOException {
      super.toData(out);
      DataSerializer.writeObject(this.versionTag, out);
    }
  
    @Override
    public void fromData(DataInput in)
      throws IOException, ClassNotFoundException {
      super.fromData(in);
      this.versionTag = (VersionTag)DataSerializer.readObject(in);
    }
  
    @Override
    public String toString() {
      StringBuilder sb = new StringBuilder();
      sb.append("InvalidateReplyMessage ")
      .append("processorid=").append(this.processorId)
      .append(" exception=").append(getException())
      .append(" versionTag=").append(this.versionTag);
      return sb.toString();
    }
  }

  /**
   * A processor to capture the value returned by {@link InvalidateMessage}
   * @author bruce
   * @since 5.1
   */
  public static final class InvalidateResponse extends PartitionResponse {

    private volatile boolean returnValueReceived;
    final Object key;
    public VersionTag versionTag;

    public InvalidateResponse(final InternalDistributedSystem ds,
        final InternalDistributedMember recipient, final Object key,
        final TXStateInterface tx) {
      super(ds, recipient, false, tx);
      this.key = key;
    }

    public InvalidateResponse(InternalDistributedSystem ds, Set recipients,
        Object key, final TXStateInterface tx) {
      super(ds, recipients, false, tx);
      this.key = key;
    }

    public void setResponse(InvalidateReplyMessage msg) {
      this.returnValueReceived = true;
      this.versionTag = msg.versionTag;
      if (this.versionTag != null) {
        this.versionTag.replaceNullIDs(msg.getSender());
      }
    }

    /**
     * @throws ForceReattemptException if the peer is no longer available
     * @throws CacheException if the peer generates an error
     */
    public final void waitForResult() throws CacheException,
        PrimaryBucketException, ForceReattemptException {
      try {
        waitForCacheException();
      } catch (ForceReattemptException e) {
        e.checkKey(key);
        throw e;
      }
      if (!this.returnValueReceived) {
        throw new ForceReattemptException(
            LocalizedStrings.InvalidateMessage_NO_RESPONSE_CODE_RECEIVED
                .toLocalizedString());
      }
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy