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

com.gemstone.gemfire.distributed.internal.locks.DLockReleaseProcessor 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.distributed.internal.locks;
  
import com.gemstone.gemfire.DataSerializer;
import com.gemstone.gemfire.InternalGemFireError;
import com.gemstone.gemfire.SystemFailure;
import com.gemstone.gemfire.i18n.LogWriterI18n;
import com.gemstone.gemfire.internal.Assert;
import com.gemstone.gemfire.distributed.LockServiceDestroyedException;
import com.gemstone.gemfire.distributed.internal.*;
import com.gemstone.gemfire.distributed.internal.membership.*;
import java.io.*;

/**
 * Synchronously releases a lock.
 *
 * @author Kirk Lund
 */
public class DLockReleaseProcessor
extends ReplyProcessor21 {

  private DLockReleaseReplyMessage reply;
  
  protected LogWriterI18n log;
  
  protected Object objectName;
  
  public DLockReleaseProcessor(DM dm,
                               InternalDistributedMember member,
                               String serviceName,
                               Object objectName) {
    super(dm, member);
    this.log = new DLockLogWriter(serviceName, dm.getLoggerI18n());
    this.objectName = objectName;
  }
  
  /** Returns true if release was acknowledged by the grantor; false means
   *  we targeted someone who is not the grantor */
  protected boolean release(InternalDistributedMember grantor,
                            String serviceName, 
                            boolean lockBatch,
                            int lockId) {

    DM dm = getDistributionManager();
    DLockReleaseMessage msg = new DLockReleaseMessage();
    msg.processorId = getProcessorId();
    msg.serviceName = serviceName;
    msg.objectName = this.objectName;
    msg.lockBatch = lockBatch;
    msg.lockId = lockId;
    
    msg.setRecipient(grantor);
    if (grantor.equals(dm.getId())) {
      // local... don't message...
      msg.setSender(grantor);
      msg.processLocally(dm);
    }
    else {
      dm.putOutgoing(msg);
    }

    // keep waiting even if interrupted
    try { 
      waitForRepliesUninterruptibly();
    }
    catch (ReplyException e) {
      e.handleAsUnexpected();
    }
    
    if (this.reply == null) return false;
    return this.reply.replyCode == DLockReleaseReplyMessage.OK;
  }
  
  @Override
  protected boolean allowReplyFromSender() {
    return true;
  }
  
  @Override
  public void process(DistributionMessage msg) {
    try {
      Assert.assertTrue(msg instanceof DLockReleaseReplyMessage, 
          "DLockReleaseProcessor is unable to process message of type " +
          msg.getClass());

      DLockReleaseReplyMessage myReply = (DLockReleaseReplyMessage) msg;
      if (this.log.fineEnabled()) {
        this.log.fine("Handling: " + myReply);
      }
      this.reply = myReply;
      
      // grantor acknowledged release of lock...
      if (myReply.replyCode == DLockReleaseReplyMessage.OK) {
        if (this.log.fineEnabled()) {
          this.log.fine("Successfully released " + this.objectName + 
                        " in " + myReply.serviceName);
        }
      }
      
      // sender denies being the grantor...
      else if (myReply.replyCode == DLockReleaseReplyMessage.NOT_GRANTOR) {
        if (this.log.fineEnabled()) {
          this.log.fine(myReply.getSender() + 
              " has responded DLockReleaseReplyMessage.NOT_GRANTOR for " +
              myReply.serviceName);
        }
      }
    }
    finally {
      super.process(msg);
      /*if (this.log.fineEnabled()) {
        this.log.fine("Finished handling: " + msg);
      }*/
    }
  }
  
  // -------------------------------------------------------------------------
  //   DLockReleaseMessage
  // -------------------------------------------------------------------------
  public static final class DLockReleaseMessage 
  extends HighPriorityDistributionMessage
  implements MessageWithReply {
    
    /** The name of the DistributedLockService */
    protected String serviceName;
  
    /** The object name */
    protected Object objectName;
    
    /** True if objectName identifies a batch of locks */
    protected boolean lockBatch;
    
    /** Id of the processor that will handle replies */
    protected int processorId;
    
    /** Matches up this release with the original lock request */
    protected int lockId;
    
    // set used during processing of this msg...
    protected DLockService svc;
    protected DLockGrantor grantor;
    
    public DLockReleaseMessage() {}
  
    @Override
    public int getProcessorId() {
      return this.processorId;
    }
      
    /**
     * Processes this message - invoked on the node that is the lock grantor.
     */
    @Override
    protected void process(final DistributionManager dm) {
      boolean failed = true;
      ReplyException replyException = null;
      try {
        this.svc = DLockService.getInternalServiceNamed(this.serviceName);
        if (this.svc == null) { 
          failed = false; // basicProcess has it's own finally-block w reply
          basicProcess(dm, false); // don't have a grantor anymore
        }
        else {
          executeBasicProcess(dm); // use executor
        }
        failed = false; // nothing above threw anything
      }
      catch (RuntimeException e) {
        replyException = new ReplyException(e);
        throw e;
      }
      catch (Error e) {
        if (SystemFailure.isJVMFailureError(e)) {
          SystemFailure.initiateFailure(e);
          // If this ever returns, rethrow the error. We're poisoned
          // now, so don't let this thread continue.
          replyException = new ReplyException(e);
          throw e;
        }
        // Whenever you catch Error or Throwable, you must also
        // check for fatal JVM error (see above).  However, there is
        SystemFailure.checkFailure();
        replyException = new ReplyException(e);
        throw e;
      }
      finally {
        if (failed) {
          // above code failed so now ensure reply is sent
          if (DLockLogWriter.fineEnabled(dm)) {
            DLockLogWriter.fine(dm, 
                "DLockReleaseMessage.process failed for <" + this + ">");
          }
          int replyCode = DLockReleaseReplyMessage.NOT_GRANTOR;
          DLockReleaseReplyMessage replyMsg = new DLockReleaseReplyMessage();
          replyMsg.serviceName = this.serviceName;
          replyMsg.replyCode = replyCode;
          replyMsg.setProcessorId(this.processorId);
          replyMsg.setRecipient(getSender());
          replyMsg.setException(replyException);
          
          if (dm.getId().equals(getSender())) {
            replyMsg.setSender(getSender());
            replyMsg.dmProcess(dm);
          }
          else {
            dm.putOutgoing(replyMsg);
          }
        }
      }
    }
    
    /** Process locally without using messaging or executor */
    protected void processLocally(final DM dm) {
      this.svc = DLockService.getInternalServiceNamed(this.serviceName);
      basicProcess(dm, true); // don't use executor
    }

    /** 
     * Execute basicProcess inside Pooled Executor because grantor may not 
     * be initializing which will require us to wait.
     * 

* this.svc and this.grantor must be set before calling this method. */ private void executeBasicProcess(final DM dm) { final DLockReleaseMessage msg = this; dm.getWaitingThreadPool().execute(new Runnable() { public void run() { if (DLockLogWriter.fineEnabled(dm)) { DLockLogWriter.fine(dm, "[executeBasicProcess] waitForGrantor " + msg); } basicProcess(dm, true); } }); } /** * Perform basic processing of this message. *

* this.svc and this.grantor must be set before calling this method. */ protected void basicProcess(final DM dm, final boolean waitForGrantor) { if (DLockLogWriter.fineEnabled(dm)) { DLockLogWriter.fine(dm, "[basicProcess] " + this); } int replyCode = DLockReleaseReplyMessage.NOT_GRANTOR; ReplyException replyException = null; try { if (svc == null || svc.isDestroyed()) return; if (waitForGrantor) { try { this.grantor = DLockGrantor.waitForGrantor(this.svc); } catch (InterruptedException e) { Thread.currentThread().interrupt(); this.grantor = null; } } if (grantor == null || grantor.isDestroyed()) { return; } try { if (lockBatch) { throw new InternalGemFireError("unexpected call"); //grantor.releaseLockBatch(objectName, getSender()); //replyCode = DLockReleaseReplyMessage.OK; } else { grantor.releaseIfLocked(objectName, getSender(), lockId); replyCode = DLockReleaseReplyMessage.OK; } } catch (InterruptedException e) { Thread.currentThread().interrupt(); replyCode = DLockReleaseReplyMessage.NOT_GRANTOR; } } catch (LockGrantorDestroyedException ignore) { } catch (LockServiceDestroyedException ignore) { } catch (RuntimeException e) { replyException = new ReplyException(e); if (DLockLogWriter.fineEnabled(dm)) { DLockLogWriter.fine(dm, "[basicProcess] caught RuntimeException", e); } } catch (Error e) { if (SystemFailure.isJVMFailureError(e)) { SystemFailure.initiateFailure(e); // If this ever returns, rethrow the error. We're poisoned // now, so don't let this thread continue. throw e; } // Whenever you catch Error or Throwable, you must also // check for fatal JVM error (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(); replyException = new ReplyException(e); if (DLockLogWriter.fineEnabled(dm)) { DLockLogWriter.fine(dm, "[basicProcess] caught Error", e); } } finally { DLockReleaseReplyMessage replyMsg = new DLockReleaseReplyMessage(); replyMsg.serviceName = this.serviceName; replyMsg.replyCode = replyCode; replyMsg.setProcessorId(this.processorId); replyMsg.setRecipient(getSender()); replyMsg.setException(replyException); if (dm.getId().equals(getSender())) { replyMsg.setSender(getSender()); replyMsg.dmProcess(dm); } else { dm.putOutgoing(replyMsg); } if (grantor != null && !lockBatch) { // moved what was here into grantor... try { grantor.postRemoteReleaseLock(objectName); } catch (InterruptedException e) { try { dm.getCancelCriterion().checkCancelInProgress(e); } finally { Thread.currentThread().interrupt(); } } } // grantor != null else { if (DLockGrantor.DEBUG_SUSPEND_LOCK) { dm.getLoggerI18n().fine( "DLockReleaseMessage, omitted postRemoteRelease lock on " + objectName + "; grantor = " + grantor + ", lockBatch = " + lockBatch + ", replyMsg = " + replyMsg); } } } } public int getDSFID() { return DLOCK_RELEASE_MESSAGE; } @Override public void toData(DataOutput out) throws IOException { super.toData(out); DataSerializer.writeString(this.serviceName, out); DataSerializer.writeObject(this.objectName, out); out.writeBoolean(this.lockBatch); out.writeInt(this.processorId); out.writeInt(this.lockId); } @Override public void fromData(DataInput in) throws IOException, ClassNotFoundException { super.fromData(in); this.serviceName = DataSerializer.readString(in); this.objectName = DataSerializer.readObject(in); this.lockBatch = in.readBoolean(); this.processorId = in.readInt(); this.lockId = in.readInt(); } @Override public String toString() { return "DLockReleaseMessage for " + this.serviceName + ", " + this.objectName + "; processorId=" + this.processorId + "; lockBatch=" + this.lockBatch + "; lockId=" + this.lockId; } } // DLockReleaseMessage // ------------------------------------------------------------------------- // DLockReleaseReplyMessage // ------------------------------------------------------------------------- public static final class DLockReleaseReplyMessage extends ReplyMessage { static final int NOT_GRANTOR = 0; static final int OK = 1; /** Name of service to release the lock in; for toString only */ protected String serviceName; /** OK or NOT_GRANTOR for the service */ protected int replyCode = NOT_GRANTOR; @Override public int getDSFID() { return DLOCK_RELEASE_REPLY; } @Override public void fromData(DataInput in) throws IOException, ClassNotFoundException { super.fromData(in); this.serviceName = DataSerializer.readString(in); this.replyCode = in.readInt(); } @Override public void toData(DataOutput out) throws IOException { super.toData(out); DataSerializer.writeString(this.serviceName, out); out.writeInt(this.replyCode); } @Override public String toString() { StringBuffer buff = new StringBuffer(); buff.append("DLockReleaseReplyMessage"); buff.append(" (serviceName="); buff.append(this.serviceName); buff.append("; replyCode="); switch (this.replyCode) { case NOT_GRANTOR: buff.append("NOT_GRANTOR"); break; case OK: buff.append("OK"); break; default: buff.append(String.valueOf(this.replyCode)); break; } buff.append("; sender="); buff.append(getSender()); buff.append("; processorId="); buff.append(super.processorId); buff.append(")"); return buff.toString(); } } // DLockReleaseReplyMessage }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy