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

com.gemstone.gemfire.internal.cache.DistributedClearOperation 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;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import com.gemstone.gemfire.DataSerializer;
import com.gemstone.gemfire.cache.CacheEvent;
import com.gemstone.gemfire.cache.EntryNotFoundException;
import com.gemstone.gemfire.distributed.internal.DistributionManager;
import com.gemstone.gemfire.distributed.internal.membership.InternalDistributedMember;
import com.gemstone.gemfire.internal.cache.tier.sockets.ClientProxyMembershipID;
import com.gemstone.gemfire.internal.cache.versions.RegionVersionVector;
import com.gemstone.gemfire.internal.cache.versions.VersionTag;

/**
 * 
 * @author Asif
 * 
 */
public class DistributedClearOperation extends DistributedCacheOperation {
  public static enum OperationType {
    OP_LOCK_FOR_CLEAR, OP_CLEAR,
  }

  private final RegionVersionVector rvv;
  private final OperationType operation;
  private final Set recipients;
  private VersionTag operationTag;

  /**
   * A map of all the regions that are currently locked for a clear in this VM
   */
  private static final ConcurrentHashMap lockedRegions = new ConcurrentHashMap();
  
  public static void regionLocked(InternalDistributedMember locker, String regionPath, DistributedRegion region) {
    lockedRegions.put(new LockKey(locker, regionPath), region);
  }
  
  public static DistributedRegion regionUnlocked(InternalDistributedMember locker, String regionPath) {
    return lockedRegions.remove(new LockKey(locker, regionPath));
  }
  

  /** distribute a clear() to other members 
   **/
  public static void clear(RegionEventImpl regionEvent, RegionVersionVector rvv, Set recipients) {
    new DistributedClearOperation(
        DistributedClearOperation.OperationType.OP_CLEAR,
        regionEvent, rvv, recipients).distribute();
  }
  
  /** obtain locks on version generation in other members have them do a state-flush back to this member 
   * @param recipients */
  public static void lockAndFlushToOthers(RegionEventImpl regionEvent, Set recipients) {
    DistributedClearOperation dco = new DistributedClearOperation(
        DistributedClearOperation.OperationType.OP_LOCK_FOR_CLEAR,
        regionEvent, null, recipients);
    dco.distribute();
  }

  @Override
  public String toString() {
    String cname = getClass().getName().substring(
        getClass().getPackage().getName().length() + 1);
    return cname + "(op=" + this.operation + ", tag=" + this.operationTag + "event=" + this.event + ")";
  }

  /** release locks in other members obtained for an RVV clear */
  public static void releaseLocks(RegionEventImpl regionEvent, Set recipients) {
    DistributedRegion region =  (DistributedRegion) regionEvent.getRegion();
    ReleaseClearLockMessage.send(recipients, region.getDistributionManager(), region.getFullPath());
  }

  
  // clear must receive responses when versioning is enabled
  @Override
  protected boolean shouldAck() {
    return true;
  }

  @Override
  public boolean containsRegionContentChange() {
    return this.operation == OperationType.OP_CLEAR;
  }
  
  /** Creates new instance of DistributedClearOperation 
   * @param recipients */
  private DistributedClearOperation(OperationType op, RegionEventImpl event, RegionVersionVector rvv, Set recipients) {
    super(event);
    this.rvv = rvv;
    this.operation = op;
    this.recipients = recipients;
    if (event != null) {
      this.operationTag = event.getVersionTag();
    }
  }

  @Override
  protected void initProcessor(CacheOperationReplyProcessor p,
      CacheOperationMessage msg) {
    super.initProcessor(p, msg);
  }

  @Override
  protected boolean supportsAdjunctMessaging() {
    return false;
  }
 
  @Override
  public boolean supportsMulticast() {
    return false;
  }
 
  @Override
  protected CacheOperationMessage createMessage()
  {
    ClearRegionMessage mssg;
    if (this.event instanceof BridgeRegionEventImpl) {
      mssg = new ClearRegionWithContextMessage();
      ((ClearRegionWithContextMessage)mssg).context = ((BridgeRegionEventImpl)this.event)
          .getContext();

    }
    else {
      mssg = new ClearRegionMessage();
    }
    mssg.clearOp = this.operation;
    mssg.eventID = this.event.getEventId();
    mssg.rvv = this.rvv;
    mssg.owner = this;
    mssg.operationTag = this.operationTag;
    return mssg;
  }
  
  @Override
  protected Set getRecipients()
  {
    return recipients;
  }
  
  
  public static class ClearRegionMessage extends CacheOperationMessage
  {

    protected EventID eventID;
    protected RegionVersionVector rvv;
    protected OperationType clearOp;
    protected VersionTag operationTag;
    protected transient DistributedClearOperation owner;
    
    @Override
    public boolean containsRegionContentChange() {
      return this.clearOp == OperationType.OP_CLEAR;
    }

    @Override
    protected int getMessageProcessorType() {
      /* since clear() can block for a while we don't want to run it in a reader
       * thread.  It is also okay to run this in a non-ordered executor since
       * the operation contains its own ordering information.
       */
      return DistributionManager.HIGH_PRIORITY_EXECUTOR;
    }

    @Override
    protected InternalCacheEvent createEvent(DistributedRegion rgn)
        throws EntryNotFoundException
    {
      RegionEventImpl event = createRegionEvent(rgn);
      event.setEventID(this.eventID);
      if (this.filterRouting != null) {
        event.setLocalFilterInfo(this.filterRouting
            .getFilterInfo(rgn.getMyId()));
      }
      return event;
    }
    
    protected RegionEventImpl createRegionEvent(DistributedRegion rgn)
    {     
      RegionEventImpl event = new RegionEventImpl(rgn, getOperation(),
          this.callbackArg, true /* originRemote */, getSender());
      event.setVersionTag(this.operationTag);
      return event;
    }
    
    @Override
    protected boolean operateOnRegion(CacheEvent event, DistributionManager dm)
        throws EntryNotFoundException
    {
      
      DistributedRegion region = (DistributedRegion)event.getRegion();
      switch (this.clearOp) {
      case OP_CLEAR:
        region.clearRegionLocally((RegionEventImpl)event, false, this.rvv);
        region.notifyBridgeClients(event);
        this.appliedOperation = true;
        break;
      case OP_LOCK_FOR_CLEAR:
        if (region.getDataPolicy().withStorage()) {
          DistributedClearOperation.regionLocked(this.getSender(), region.getFullPath(), region);
          region.lockLocallyForClear(dm, this.getSender());
        }
        this.appliedOperation = true;
        break;
      }
      return true;
    }

    public int getDSFID() {
      return CLEAR_REGION_MESSAGE;
    }
    

    @Override
    public void fromData(DataInput in)
        throws IOException, ClassNotFoundException {
      super.fromData(in);
      this.clearOp = OperationType.values()[in.readByte()];
      this.eventID = (EventID)DataSerializer.readObject(in);
      this.rvv = (RegionVersionVector)DataSerializer.readObject(in);
      this.operationTag = (VersionTag)DataSerializer.readObject(in);
    }

    @Override
    public void toData(DataOutput out)
        throws IOException {
      super.toData(out);
      out.writeByte(this.clearOp.ordinal());
      DataSerializer.writeObject(this.eventID, out);
      DataSerializer.writeObject(this.rvv, out);
      DataSerializer.writeObject(this.operationTag, out);
    }

    @Override
    protected void appendFields(StringBuilder buff)
    {
      super.appendFields(buff);
      buff.append("; op=").append(this.clearOp);
      buff.append("; eventID=").append(this.eventID);
      buff.append("; tag=").append(this.operationTag);
      buff.append("; rvv=").append(this.rvv);
    }

  }

  public static final class ClearRegionWithContextMessage extends ClearRegionMessage
  {
    protected transient Object context;
    protected RegionVersionVector rvv;

    
    @Override
    final public RegionEventImpl createRegionEvent(DistributedRegion rgn)
    {
      
      BridgeRegionEventImpl event = new BridgeRegionEventImpl(rgn,
          getOperation(), this.callbackArg, true /* originRemote */,
          getSender(), (ClientProxyMembershipID)this.context);
      return event;
    }

    @Override
    protected void appendFields(StringBuilder buff)
    {
      super.appendFields(buff);
      buff.append("; context=").append(this.context);
    }

    @Override
    public int getDSFID() {
      return CLEAR_REGION_MESSAGE_WITH_CONTEXT;
    }

    @Override
    public void fromData(DataInput in)
        throws IOException, ClassNotFoundException {
      super.fromData(in);
      this.context = DataSerializer.readObject(in);
    }

    @Override
    public void toData(DataOutput out)
        throws IOException {
      super.toData(out);
      DataSerializer.writeObject(this.context, out);
    }
  }
  
  public static class LockKey {

    private final InternalDistributedMember locker;
    private final String regionPath;

    public LockKey(InternalDistributedMember locker, String regionPath) {
      this.locker = locker;
      this.regionPath = regionPath;
    }

    @Override
    public int hashCode() {
      final int prime = 31;
      int result = 1;
      result = prime * result + ((locker == null) ? 0 : locker.hashCode());
      result = prime * result
          + ((regionPath == null) ? 0 : regionPath.hashCode());
      return result;
    }

    @Override
    public boolean equals(Object obj) {
      if (this == obj)
        return true;
      if (obj == null)
        return false;
      if (getClass() != obj.getClass())
        return false;
      LockKey other = (LockKey) obj;
      if (locker == null) {
        if (other.locker != null)
          return false;
      } else if (!locker.equals(other.locker))
        return false;
      if (regionPath == null) {
        if (other.regionPath != null)
          return false;
      } else if (!regionPath.equals(other.regionPath))
        return false;
      return true;
    }
    
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy