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

org.apache.geode.distributed.internal.locks.ElderState Maven / Gradle / Ivy

Go to download

Apache Geode provides a database-like consistency model, reliable transaction processing and a shared-nothing architecture to maintain very low latency performance with high concurrency processing

There is a newer version: 1.15.1
Show newest version
/*
 * 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.distributed.internal.locks;

import java.util.HashMap;
import java.util.Iterator;

import org.apache.logging.log4j.Logger;

import org.apache.geode.InternalGemFireError;
import org.apache.geode.distributed.internal.DM;
import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
import org.apache.geode.internal.Assert;
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;

/**
 * Keeps track of all the information kept by the elder.
 *
 * @since GemFire 4.0
 */
public class ElderState {
  private static final Logger logger = LogService.getLogger();

  /**
   * Maps service name keys to GrantorInfo values.
   */
  private final HashMap nameToInfo;
  private final DM dm;

  /**
   * Constructs the EdlerState for the given dm. Note that this constructor does not complete until
   * elder recovery is complete.
   */
  public ElderState(DM dm) {
    Assert.assertTrue(dm != null);
    this.dm = dm;
    this.nameToInfo = new HashMap();
    try {
      this.dm.getStats().incElders(1);
      ElderInitProcessor.init(this.dm, this.nameToInfo);
    } catch (NullPointerException e) {
      try {
        checkForProblem(dm);
      } finally {
        if (true)
          throw e; // conditional prevents eclipse warning
      }
    } catch (InternalGemFireError e) {
      try {
        checkForProblem(dm);
      } finally {
        if (true)
          throw e; // conditional prevents eclipse warning
      }
    } finally {
      if (logger.isTraceEnabled(LogMarker.DLS)) {
        StringBuffer sb = new StringBuffer("ElderState initialized with:");
        for (Iterator grantors = this.nameToInfo.keySet().iterator(); grantors.hasNext();) {
          Object key = grantors.next();
          // key=dlock svc name, value=GrantorInfo object
          sb.append("\n\t" + key + ": " + this.nameToInfo.get(key));
        }
        logger.trace(LogMarker.DLS, sb.toString());
      }
    }
  }

  private void checkForProblem(DM checkDM) {
    if (checkDM.getSystem() == null) {
      logger.warn(LogMarker.DLS, LocalizedMessage
          .create(LocalizedStrings.ElderState_ELDERSTATE_PROBLEM_SYSTEM_0, checkDM.getSystem()));
      return;
    }
    if (checkDM.getSystem().getDistributionManager() == null) {
      logger.warn(LogMarker.DLS,
          LocalizedMessage.create(
              LocalizedStrings.ElderState_ELDERSTATE_PROBLEM_SYSTEM_DISTRIBUTIONMANAGER_0,
              checkDM.getSystem().getDistributionManager()));
    }
    if (checkDM != checkDM.getSystem().getDistributionManager()) {
      logger.warn(LogMarker.DLS,
          LocalizedMessage.create(
              LocalizedStrings.ElderState_ELDERSTATE_PROBLEM_DM_0_BUT_SYSTEM_DISTRIBUTIONMANAGER_1,
              new Object[] {checkDM, checkDM.getSystem().getDistributionManager()}));
    }
  }

  /**
   * Atomically determine who is the current grantor of the given service. If no current grantor
   * exists then the caller is made the grantor.
   * 
   * @param serviceName the name of the lock service we want the grantor of
   * @param requestor the id of the member who is making this request
   * @return the current grantor of serviceName and recoveryNeeded will be true if
   *         requestor has become the grantor and needs to recover lock info.
   */
  public GrantorInfo getGrantor(String serviceName, InternalDistributedMember requestor,
      int dlsSerialNumberRequestor) {
    synchronized (this) {
      GrantorInfo gi = (GrantorInfo) this.nameToInfo.get(serviceName);
      if (gi != null) {
        waitWhileInitiatingTransfer(gi);
        InternalDistributedMember currentGrantor = gi.getId();
        // Note that elder recovery may put GrantorInfo instances in
        // the map whose id is null and whose needRecovery is true
        if (currentGrantor != null
            && this.dm.getDistributionManagerIds().contains(currentGrantor)) {
          return gi;
        } else {
          if (logger.isTraceEnabled(LogMarker.DLS)) {
            logger.trace(LogMarker.DLS, "Elder setting grantor for {} to {} because {} ",
                serviceName, requestor, (currentGrantor != null ? "current grantor crashed"
                    : "of unclean grantor shutdown"));
          }
          // current grantor crashed; make new guy grantor and force recovery
          long myVersion = gi.getVersionId() + 1;
          this.nameToInfo.put(serviceName,
              new GrantorInfo(requestor, myVersion, dlsSerialNumberRequestor, false));
          return new GrantorInfo(requestor, myVersion, dlsSerialNumberRequestor, true);
        }
      } else {
        if (logger.isTraceEnabled(LogMarker.DLS)) {
          logger.trace(LogMarker.DLS,
              "Elder setting grantor for {} to {} because of clean grantor shutdown", serviceName,
              requestor);
        }
        gi = new GrantorInfo(requestor, 1, dlsSerialNumberRequestor, false);
        this.nameToInfo.put(serviceName, gi);
        return gi;
      }
    }
  }

  /**
   * Atomically determine who is the current grantor of the given service.
   * 
   * @param serviceName the name of the lock service we want the grantor of
   * @return the current grantor of serviceName and recoveryNeeded will be true if
   *         requestor has become the grantor and needs to recover lock info.
   */
  public GrantorInfo peekGrantor(String serviceName) {
    synchronized (this) {
      GrantorInfo gi = (GrantorInfo) this.nameToInfo.get(serviceName);
      if (gi != null) {
        waitWhileInitiatingTransfer(gi);
        InternalDistributedMember currentGrantor = gi.getId();
        // Note that elder recovery may put GrantorInfo instances in
        // the map whose id is null and whose needRecovery is true
        if (currentGrantor != null
            && this.dm.getDistributionManagerIds().contains(currentGrantor)) {
          return gi;
        } else {
          return new GrantorInfo(null, 0, 0, true);
        }
      } else {
        return new GrantorInfo(null, 0, 0, false);
      }
    }
  }

  /**
   * Atomically sets the current grantor of the given service to newGrantor.
   * 
   * @param serviceName the name of the lock service we want the grantor of
   * @param newGrantor the id of the member who is making this request
   * @param oldTurk if non-null then only do the become if the current grantor is the oldTurk
   * @return the previous grantor, which may be null, of serviceName and recoveryNeeded
   *         will be true if new grantor needs to recover lock info
   */
  public GrantorInfo becomeGrantor(String serviceName, InternalDistributedMember newGrantor,
      int newGrantorSerialNumber, InternalDistributedMember oldTurk) {
    GrantorInfo newInfo = null;
    InternalDistributedMember previousGrantor = null;
    long newGrantorVersion = -1;
    try {
      synchronized (this) {
        GrantorInfo gi = (GrantorInfo) this.nameToInfo.get(serviceName);
        while (gi != null && gi.isInitiatingTransfer()) {
          waitWhileInitiatingTransfer(gi);
          gi = (GrantorInfo) this.nameToInfo.get(serviceName);
        }
        if (gi != null) {
          previousGrantor = gi.getId();
          // Note that elder recovery may put GrantorInfo instances in
          // the map whose id is null and whose needRecovery is true

          // if previousGrantor still exists...
          if (previousGrantor != null
              && this.dm.getDistributionManagerIds().contains(previousGrantor)) {

            // if newGrantor is not previousGrantor...
            if (!newGrantor.equals(previousGrantor)) {

              // problem: specified oldTurk is not previousGrantor...
              if (oldTurk != null && !oldTurk.equals(previousGrantor)) {
                if (logger.isTraceEnabled(LogMarker.DLS)) {
                  logger.trace(LogMarker.DLS,
                      "Elder did not become grantor for {} to {} because oldT was {} and the current grantor is {}",
                      serviceName, newGrantor, oldTurk, previousGrantor);
                }
              }

              // no oldTurk or oldTurk matches previousGrantor... transfer might occur
              else {
                // install new grantor
                if (logger.isTraceEnabled(LogMarker.DLS)) {
                  logger.trace(LogMarker.DLS, "Elder forced to set grantor for {} to {}",
                      serviceName, newGrantor);
                }
                long myVersion = gi.getVersionId() + 1;
                newGrantorVersion = myVersion;
                newInfo = new GrantorInfo(newGrantor, myVersion, newGrantorSerialNumber, false);
                this.nameToInfo.put(serviceName, newInfo);

                if (gi.getId() != null && (oldTurk == null || gi.getId().equals(oldTurk))
                    && !gi.getId().equals(newGrantor)) {
                  beginInitiatingTransfer(newInfo);
                }

              }
            }
            // return previous grantor
            return new GrantorInfo(gi.getId(), gi.getVersionId(), gi.getSerialNumber(), true);
          }

          // no previousGrantor in existence...
          else {
            long myVersion = gi.getVersionId() + 1;

            // problem: oldTurk was specified but there is no previousGrantor...
            if (oldTurk != null) {
              if (logger.isTraceEnabled(LogMarker.DLS)) {
                logger.trace(LogMarker.DLS,
                    "Elder did not become grantor for {} to {} because oldT was {} and the current grantor {} had crashed",
                    serviceName, newGrantor, oldTurk, previousGrantor);
              }
            }

            // no oldTurk was specified...
            else {
              if (logger.isTraceEnabled(LogMarker.DLS)) {
                logger.trace(LogMarker.DLS,
                    "Elder forced to set grantor for {} to {} and noticed previous grantor had crashed",
                    serviceName, newGrantor);
              }
              // current grantor crashed; make new guy grantor and force recovery
              this.nameToInfo.put(serviceName,
                  new GrantorInfo(newGrantor, myVersion, newGrantorSerialNumber, false));
            }

            return new GrantorInfo(null, myVersion - 1, gi.getSerialNumber(), true);
          }
        }

        // GrantorInfo was null...
        else {
          // problem: no oldTurk was specified
          if (oldTurk != null) {
            if (logger.isTraceEnabled(LogMarker.DLS)) {
              logger.trace(LogMarker.DLS,
                  "Elder did not become grantor for {} to {} because oldT was {} and elder had no current grantor",
                  serviceName, newGrantor, oldTurk);
            }
          }

          // no oldTurk was specified
          else {
            if (logger.isTraceEnabled(LogMarker.DLS)) {
              logger.trace(LogMarker.DLS,
                  "Elder forced to set grantor for {} to {} because of clean grantor shutdown",
                  serviceName, newGrantor);
            }
            // no current grantor; last one shutdown cleanly
            gi = new GrantorInfo(newGrantor, 1, newGrantorSerialNumber, false);
            this.nameToInfo.put(serviceName, gi);
          }
          return new GrantorInfo(null, 0, 0, false);
        }
      }
    } finally {
      if (isInitiatingTransfer(newInfo)) {
        Assert.assertTrue(newGrantorVersion > -1);
        DeposeGrantorProcessor.send(serviceName, previousGrantor, newGrantor, newGrantorVersion,
            newGrantorSerialNumber, dm);
        finishInitiatingTransfer(newInfo);
      }
    }
  }

  /**
   * Atomically clears the current grantor of the given service if the current grantor is
   * oldGrantor. The next grantor for this service will not need to recover unless
   * locksHeld is true.
   * 
   * @param locksHeld true if old grantor had held locks
   */
  public void clearGrantor(long grantorVersion, String serviceName, int dlsSerialNumber,
      InternalDistributedMember oldGrantor, boolean locksHeld) {
    synchronized (this) {
      if (grantorVersion == -1) {
        // not possible to clear grantor of non-initialized grantorVersion
        return;
      }

      GrantorInfo currentGI = (GrantorInfo) this.nameToInfo.get(serviceName);
      if (currentGI == null) {
        return; // KIRK added this null check because becomeGrantor may not have talked to elder
                // before destroy dls
      }
      if (currentGI.getVersionId() != grantorVersion
          || currentGI.getSerialNumber() != dlsSerialNumber) {
        // not possible to clear mismatched grantorVersion
        return;
      }

      GrantorInfo gi;
      if (locksHeld) {
        gi = (GrantorInfo) this.nameToInfo.put(serviceName,
            new GrantorInfo(null, currentGI.getVersionId(), 0, true));
      } else {
        gi = (GrantorInfo) this.nameToInfo.remove(serviceName);
      }
      if (gi != null) {
        InternalDistributedMember currentGrantor = gi.getId();
        if (!oldGrantor.equals(currentGrantor)) { // fix for 32603
          this.nameToInfo.put(serviceName, gi);
          if (logger.isTraceEnabled(LogMarker.DLS)) {
            logger.trace(LogMarker.DLS,
                "Elder not making {} grantor shutdown for {} by {} because the current grantor is {}",
                (locksHeld ? "unclean" : "clean"), serviceName, oldGrantor, currentGrantor);
          }
        } else {
          if (logger.isTraceEnabled(LogMarker.DLS)) {
            logger.trace(LogMarker.DLS, "Elder making {} grantor shutdown for {} by {}",
                (locksHeld ? "unclean" : "clean"), serviceName, oldGrantor);
          }
        }
      }
    }
  }

  private final boolean isInitiatingTransfer(GrantorInfo gi) {
    if (gi == null)
      return false;
    synchronized (this) {
      return gi.isInitiatingTransfer();
    }
  }

  private final void beginInitiatingTransfer(GrantorInfo gi) {
    synchronized (this) {
      gi.setInitiatingTransfer(true);
    }
  }

  private final void finishInitiatingTransfer(GrantorInfo gi) {
    synchronized (this) {
      gi.setInitiatingTransfer(false);
      notifyAll();
    }
  }

  private final void waitWhileInitiatingTransfer(GrantorInfo gi) {
    synchronized (this) {
      boolean interrupted = false;
      try {
        while (gi.isInitiatingTransfer()) {
          try {
            wait();
          } catch (InterruptedException e) {
            interrupted = true;
            dm.getCancelCriterion().checkCancelInProgress(e);
          }
        }
      } finally {
        if (interrupted)
          Thread.currentThread().interrupt();
      }
    }
  }

  /** Testing method to force grantor recovery state for named service */
  public void forceGrantorRecovery(String serviceName) {
    synchronized (this) {
      GrantorInfo gi = (GrantorInfo) this.nameToInfo.get(serviceName);
      if (gi.isInitiatingTransfer()) {
        throw new IllegalStateException(
            LocalizedStrings.ElderState_CANNOT_FORCE_GRANTOR_RECOVERY_FOR_GRANTOR_THAT_IS_TRANSFERRING
                .toLocalizedString());
      }
      this.nameToInfo.put(serviceName,
          new GrantorInfo(gi.getId(), gi.getVersionId(), gi.getSerialNumber(), true));
    }
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy