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

com.gemstone.gemfire.distributed.internal.locks.DLockQueryProcessor 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.LogWriter;
import com.gemstone.gemfire.SystemFailure;
import com.gemstone.gemfire.distributed.DistributedMember;
import com.gemstone.gemfire.distributed.LockServiceDestroyedException;
import com.gemstone.gemfire.distributed.internal.DM;
import com.gemstone.gemfire.distributed.internal.DistributionManager;
import com.gemstone.gemfire.distributed.internal.DistributionMessage;
import com.gemstone.gemfire.distributed.internal.MessageWithReply;
import com.gemstone.gemfire.distributed.internal.PooledDistributionMessage;
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.locks.DLockGrantor.DLockGrantToken;
import com.gemstone.gemfire.distributed.internal.membership.InternalDistributedMember;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

/**
 * Queries the grantor for current leasing information of a lock.
 * 
 * @author Kirk Lund
 */
public class DLockQueryProcessor extends ReplyProcessor21 {

  /** DLockLogWriter wrapped logger */
  private final LogWriter log;
  
  /** The reply to the query or null */
  private volatile DLockQueryReplyMessage reply;
  
  /**
   * Query the grantor for current leasing information of a lock.
   * 
   * @param grantor the member that is the grantor
   * @param serviceName the name of the lock service
   * @param objectName the named lock
   * @param lockBatch true if the named lock is a TX lock batch
   * @param dm distribution manager to use for logging and messaging
   * @return the query reply or null if there was no reply due to membership
   * change
   */
  static DLockQueryReplyMessage query(final InternalDistributedMember grantor,
                                      final String serviceName, 
                                      final Object objectName,
                                      final boolean lockBatch,
                                      final DM dm) {
    DLockQueryProcessor processor = new DLockQueryProcessor(
        dm, grantor, serviceName);

    DLockQueryMessage msg = new DLockQueryMessage();
    msg.processorId = processor.getProcessorId();
    msg.serviceName = serviceName;
    msg.objectName = objectName;
    msg.lockBatch = lockBatch;
    
    msg.setRecipient(grantor);
    if (grantor.equals(dm.getId())) {
      // local... don't actually send message
      msg.setSender(grantor);
      msg.processLocally(dm);
    }
    else {
      dm.putOutgoing(msg);
    }

    // keep waiting even if interrupted
    try { 
      processor.waitForRepliesUninterruptibly();
    }
    catch (ReplyException e) {
      e.handleAsUnexpected();
    }
    
    if (processor.reply == null) {
      return null;
    }
    else {
      return processor.reply;
    }
  }
  
  /**
   * Instantiates a new DLockQueryProcessor.
   * 
   * @param dm the distribution manager to use for logging and messaging
   * @param grantor the member to query for lock leasing info
   * @param serviceName the name of the lock service
   */
  private DLockQueryProcessor(DM dm,
                              InternalDistributedMember grantor,
                              String serviceName) {
    super(dm, grantor);
    this.log = new DLockLogWriter(serviceName, dm.getLoggerI18n());
  }
  
  @Override
  protected boolean allowReplyFromSender() {
    return true;
  }
  
  @Override
  public void process(DistributionMessage msg) {
    try {
      DLockQueryReplyMessage myReply = (DLockQueryReplyMessage) msg;
      if (this.log.fineEnabled()) {
        this.log.fine("Handling: " + myReply);
      }
      this.reply = myReply;
    }
    finally {
      super.process(msg);
    }
  }
  
  // -------------------------------------------------------------------------
  //   DLockQueryMessage
  // -------------------------------------------------------------------------
  public static final class DLockQueryMessage 
  extends PooledDistributionMessage
  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;
    
    // set used during processing of this msg...
    protected transient DLockService svc;
    protected transient DLockGrantor grantor;
    
    public DLockQueryMessage() {
    }
  
    @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;
        }
        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, 
                "DLockQueryMessage.process failed for <" + this + ">");
          }
          DLockQueryReplyMessage replyMsg = new DLockQueryReplyMessage();
          replyMsg.setProcessorId(this.processorId);
          replyMsg.setRecipient(getSender());
          replyMsg.setException(replyException); // might be null
          
          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 DLockQueryMessage msg = this; dm.getWaitingThreadPool().execute(new Runnable() { public void run() { if (DLockLogWriter.fineEnabled(dm)) { DLockLogWriter.fine(dm, "[executeBasicProcess] " + 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); } final DLockQueryReplyMessage replyMsg = new DLockQueryReplyMessage(); replyMsg.setProcessorId(this.processorId); replyMsg.setRecipient(getSender()); replyMsg.replyCode = DLockQueryReplyMessage.NOT_GRANTOR; replyMsg.lesseeThread = null; replyMsg.leaseId = DLockService.INVALID_LEASE_ID; replyMsg.leaseExpireTime = 0; 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; } if (lockBatch) { throw new UnsupportedOperationException( "DLockQueryProcessor does not support lock batches"); } else { DLockGrantToken grantToken; try { grantToken = grantor.handleLockQuery(this); } catch (InterruptedException e) { Thread.currentThread().interrupt(); grantToken = null; } if (grantToken != null) { synchronized (grantToken) { if (!grantToken.isDestroyed()) { replyMsg.lesseeThread = grantToken.getRemoteThread(); replyMsg.leaseId = grantToken.getLockId(); replyMsg.leaseExpireTime = grantToken.getLeaseExpireTime(); } } } } replyMsg.replyCode = DLockQueryReplyMessage.OK; } catch (LockGrantorDestroyedException ignore) { } catch (LockServiceDestroyedException ignore) { } catch (RuntimeException e) { replyMsg.setException(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(); replyMsg.setException(new ReplyException(e)); if (DLockLogWriter.fineEnabled(dm)) { DLockLogWriter.fine(dm, "[basicProcess] caught Error", e); } } finally { if (dm.getId().equals(getSender())) { replyMsg.setSender(getSender()); replyMsg.dmProcess(dm); } else { dm.putOutgoing(replyMsg); } } } public int getDSFID() { return DLOCK_QUERY_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); } @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(); } @Override public String toString() { StringBuffer sb = new StringBuffer("DLockQueryMessage@"); sb.append(Integer.toHexString(hashCode())); sb.append(", serviceName: ").append(this.serviceName); sb.append(", objectName: ").append(this.objectName); sb.append(", lockBatch: ").append(this.lockBatch); sb.append(", processorId: ").append(this.processorId); return sb.toString(); } } // DLockQueryMessage // ------------------------------------------------------------------------- // DLockQueryReplyMessage // ------------------------------------------------------------------------- public static final class DLockQueryReplyMessage extends ReplyMessage { static final int NOT_GRANTOR = 0; static final int OK = 1; /** OK or NOT_GRANTOR for the service */ protected int replyCode = NOT_GRANTOR; /** Member and thread holding lease on the lock */ protected RemoteThread lesseeThread; /** Lease id used to hold a lease on the lock */ protected int leaseId; /** Absolute time in millis when lease will expire */ protected long leaseExpireTime; public DLockQueryReplyMessage() { } /** * Returns true if the queried grantor replied with the current lease info * for the named lock. * * @return true if the queried grantor replied with the current lease info */ boolean repliedOK() { return this.replyCode == DLockQueryReplyMessage.OK; } /** * Returns true if the queried grantor replied NOT_GRANTOR. * * @return true if the queried grantor replied NOT_GRANTOR */ boolean repliedNotGrantor() { return this.replyCode == DLockQueryReplyMessage.NOT_GRANTOR; } /** * Returns the member holding the lease or null if there was no lease. * * @return the member holding the lease or null */ DistributedMember getLessee() { if (this.lesseeThread != null) { return this.lesseeThread.getDistributedMember(); } else { return null; } } /** * Returns the query reply's lesseeThread or null if there was no lease. * * @return the query reply's lesseeThread or null */ RemoteThread getLesseeThread() { return this.lesseeThread; } /** * Return the query reply's leaseId or -1 if there was no lease. * * @return the query reply's leaseId or -1 */ int getLeaseId() { return this.leaseId; } /** * Return the query reply's leaseExpireTime or 0 if there was no lease. * * @return the query reply's leaseExpireTime or 0 */ long getLeaseExpireTime() { return this.leaseExpireTime; } @Override public int getDSFID() { return DLOCK_QUERY_REPLY; } @Override public void fromData(DataInput in) throws IOException, ClassNotFoundException { super.fromData(in); this.replyCode = in.readInt(); if (this.replyCode == OK) { InternalDistributedMember lessee = (InternalDistributedMember) DataSerializer.readObject(in); if (lessee != null) { this.lesseeThread = new RemoteThread(lessee, in.readInt()); } this.leaseId = in.readInt(); this.leaseExpireTime = in.readLong(); } } @Override public void toData(DataOutput out) throws IOException { super.toData(out); out.writeInt(this.replyCode); if (this.replyCode == OK) { if (this.lesseeThread == null) { DataSerializer.writeObject(null, out); } else { DataSerializer.writeObject(this.lesseeThread.getDistributedMember(), out); out.writeInt(this.lesseeThread.getThreadId()); } out.writeInt(this.leaseId); out.writeLong(this.leaseExpireTime); } } @Override public String toString() { StringBuffer sb = new StringBuffer("DLockQueryReplyMessage@"); sb.append(Integer.toHexString(hashCode())); sb.append(", replyCode: "); switch (this.replyCode) { case NOT_GRANTOR: sb.append("NOT_GRANTOR"); break; case OK: sb.append("OK"); break; default: sb.append(String.valueOf(this.replyCode)); break; } sb.append(", lesseeThread: ").append(this.lesseeThread); sb.append(", leaseId: ").append(this.leaseId); sb.append(", leaseExpireTime: ").append(this.leaseExpireTime); sb.append(", processorId: ").append(this.processorId); return sb.toString(); } } // DLockQueryReplyMessage }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy