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

org.apache.geode.internal.cache.tier.sockets.ClientProxyMembershipID 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.internal.cache.tier.sockets;

import org.apache.geode.DataSerializer;
import org.apache.geode.InternalGemFireException;
import org.apache.geode.distributed.DistributedMember;
import org.apache.geode.distributed.DistributedSystem;
import org.apache.geode.distributed.DurableClientAttributes;
import org.apache.geode.distributed.internal.DistributionConfig;
import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
import org.apache.geode.internal.*;
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.logging.log4j.Logger;

import java.io.*;
import java.util.Arrays;

import static org.apache.geode.distributed.ConfigurationProperties.*;

/**
 * This class represents a ConnectionProxy of the CacheClient
 * 
 * 
 * 
 */
public final class ClientProxyMembershipID
    implements DataSerializableFixedID, Serializable, Externalizable {

  private static final Logger logger = LogService.getLogger();

  private static ThreadLocal POOL_NAME = new ThreadLocal();

  public static void setPoolName(String poolName) {
    POOL_NAME.set(poolName);
  }

  public static String getPoolName() {
    return POOL_NAME.get();
  }

  private static final int BYTES_32KB = 32768;

  public volatile static DistributedSystem system = null;

  /**
   * the membershpi id of the distributed system in this client (if running in a client)
   */
  public static DistributedMember systemMemberId;

  // durable_synch_counter=1 is reserved for durable clients
  // so that when pools are being created and deleted the same client
  // session is selected on the serverside by always using the
  // same uniqueID value which is set via the synch_counter
  private static final int durable_synch_counter = 1;
  private static int synch_counter = 0;

  // private byte[] proxyID ;
  protected byte[] identity;

  /** cached membership identifier */
  private transient DistributedMember memberId;

  /** cached tostring of the memberID */
  private transient String memberIdString;

  protected int uniqueId;

  // private final String proxyIDStr;
  // private final String clientIdStr ;

  @Override
  public int hashCode() {
    int result = 17;
    final int mult = 37;
    if (isDurable()) {
      result = mult * result + getDurableId().hashCode();
    } else {
      if (this.identity != null && this.identity.length > 0) {
        for (int i = 0; i < this.identity.length; i++) {
          result = mult * result + this.identity[i];
        }
      }
    }
    // we can't use unique_id in hashCode
    // because of HandShake's hashCode using our HashCode but
    // its equals using our isSameDSMember which ignores unique_id
    // result = mult * result + this.unique_id;
    return result;
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }
    if ((obj == null) || !(obj instanceof ClientProxyMembershipID)) {
      return false;
    }
    ClientProxyMembershipID that = (ClientProxyMembershipID) obj;
    if (this.uniqueId != that.uniqueId) {
      return false;
    }
    boolean isDurable = this.isDurable();
    if (isDurable && !that.isDurable()) {
      return false;
    }
    if (isDurable) {
      return this.getDurableId().equals(that.getDurableId());
    }
    return Arrays.equals(this.identity, that.identity);
  }

  /**
   * Return true if "that" can be used in place of "this" when canonicalizing.
   */
  private boolean isCanonicalEquals(ClientProxyMembershipID that) {
    if (this == that) {
      return true;
    }
    if (this.uniqueId != that.uniqueId) {
      return false;
    }
    return Arrays.equals(this.identity, that.identity);
  }

  boolean isSameDSMember(ClientProxyMembershipID that) {
    if (that != null) {
      // Test whether:
      // - the durable ids are equal (if durable) or
      // - the identities are equal (if non-durable)
      return isDurable() ? this.getDurableId().equals(that.getDurableId())
          : Arrays.equals(this.identity, that.identity);
    } else {
      return false;
    }
  }

  /** method to obtain ClientProxyMembership for client side */
  public static synchronized ClientProxyMembershipID getNewProxyMembership(DistributedSystem sys) {
    byte[] ba = initializeAndGetDSIdentity(sys);
    return new ClientProxyMembershipID(++synch_counter, ba);
  }

  public static ClientProxyMembershipID getClientId(DistributedMember member) {
    return new ClientProxyMembershipID(member);
  }

  public static byte[] initializeAndGetDSIdentity(DistributedSystem sys) {
    byte[] client_side_identity = null;
    if (sys == null) {
      // DistributedSystem is required now before handshaking -Kirk
      throw new IllegalStateException(
          LocalizedStrings.ClientProxyMembershipID_ATTEMPTING_TO_HANDSHAKE_WITH_CACHESERVER_BEFORE_CREATING_DISTRIBUTEDSYSTEM_AND_CACHE
              .toLocalizedString());
    }
    // if (system != sys)
    {
      // DS already exists... make sure it's for current DS connection
      systemMemberId = sys.getDistributedMember();
      try {
        HeapDataOutputStream hdos = new HeapDataOutputStream(256, Version.CURRENT);
        DataSerializer.writeObject(systemMemberId, hdos);
        client_side_identity = hdos.toByteArray();
      } catch (IOException ioe) {
        throw new InternalGemFireException(
            LocalizedStrings.ClientProxyMembershipID_UNABLE_TO_SERIALIZE_IDENTITY
                .toLocalizedString(),
            ioe);
      }

      system = sys;
    }
    return client_side_identity;

  }

  private ClientProxyMembershipID(int id, byte[] clientSideIdentity) {
    Boolean specialCase = Boolean.getBoolean(DistributionConfig.GEMFIRE_PREFIX + "SPECIAL_DURABLE");
    String durableID = this.system.getProperties().getProperty(DURABLE_CLIENT_ID);
    if (specialCase.booleanValue() && durableID != null && (!durableID.equals(""))) {
      this.uniqueId = durable_synch_counter;
    } else {
      this.uniqueId = id;
    }
    this.identity = clientSideIdentity;
    this.memberId = systemMemberId;
  }

  public ClientProxyMembershipID() {}

  public ClientProxyMembershipID(DistributedMember member) {
    this.uniqueId = 1;
    this.memberId = member;
    updateID(member);
  }


  private transient String _toString;

  // private transient int transientPort; // variable for debugging member ID issues

  @Override
  public String toString() {
    if (this.identity != null
        && ((InternalDistributedMember) getDistributedMember()).getPort() == 0) {
      return this.toStringNoCache();
    }
    if (this._toString == null) {
      this._toString = this.toStringNoCache();
    }
    return this._toString;
  }

  /**
   * returns a string representation of this identifier, ignoring the toString cache
   */
  public String toStringNoCache() {
    StringBuffer sb = new StringBuffer("identity(").append(getDSMembership()).append(",connection=")
        .append(uniqueId);
    if (identity != null) {
      DurableClientAttributes dca = getDurableAttributes();
      if (dca.getId().length() > 0) {
        sb.append(",durableAttributes=").append(getDurableAttributes()).append(')').toString();
      }
    }
    return sb.toString();
  }

  /**
   * For Externalizable
   * 
   * @see Externalizable
   */
  public void writeExternal(ObjectOutput out) throws IOException {
    // if (this.transientPort == 0) {
    // InternalDistributedSystem.getLoggerI18n().warning(
    // LocalizedStrings.DEBUG,
    // "externalizing a client ID with zero port: " + this.toString(),
    // new Exception("Stack trace"));
    // }
    Assert.assertTrue(this.identity.length <= BYTES_32KB);
    out.writeShort(this.identity.length);
    out.write(this.identity);
    out.writeInt(this.uniqueId);

  }

  /** returns the externalized size of this object */
  public int getSerializedSize() {
    return 4 + identity.length + 4;
  }

  /**
   * For Externalizable
   * 
   * @see Externalizable
   */
  public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
    int identityLength = in.readShort();
    if (identityLength > BYTES_32KB) {
      throw new IOException(
          LocalizedStrings.ClientProxyMembershipID_HANDSHAKE_IDENTITY_LENGTH_IS_TOO_BIG
              .toLocalizedString());
    }
    this.identity = new byte[identityLength];
    read(in, this.identity);
    this.uniqueId = in.readInt();
    if (this.uniqueId == -1) {
      throw new IOException(
          LocalizedStrings.ClientProxyMembershipID_UNEXPECTED_EOF_REACHED_UNIQUE_ID_COULD_NOT_BE_READ
              .toLocalizedString());
    }
    // {toString(); this.transientPort = ((InternalDistributedMember)this.memberId).getPort();}
  }

  private void read(ObjectInput dis, byte[] toFill) throws IOException {

    int idBytes = 0;
    int toFillLength = toFill.length;
    while (idBytes < toFillLength) {
      // idBytes += dis.read(toFill, idBytes, (toFillLength - idBytes));
      int dataRead = dis.read(toFill, idBytes, (toFillLength - idBytes));
      if (dataRead == -1) {
        throw new IOException(
            LocalizedStrings.ClientProxyMembershipID_UNEXPECTED_EOF_REACHED_DISTRIBUTED_MEMBERSHIPID_COULD_NOT_BE_READ
                .toLocalizedString());
      }
      idBytes += dataRead;
    }
  }

  public int getDSFID() {
    return CLIENT_PROXY_MEMBERSHIPID;
  }

  public void toData(DataOutput out) throws IOException {
    // if (this.transientPort == 0) {
    // InternalDistributedSystem.getLoggerI18n().warning(
    // LocalizedStrings.DEBUG,
    // "serializing a client ID with zero port: " + this.toString(),
    // new Exception("Stack trace"));
    // }
    DataSerializer.writeByteArray(this.identity, out);
    out.writeInt(this.uniqueId);
  }

  public void fromData(DataInput in) throws IOException, ClassNotFoundException {
    this.identity = DataSerializer.readByteArray(in);
    this.uniqueId = in.readInt();
    // {toString(); this.transientPort = ((InternalDistributedMember)this.memberId).getPort();}
  }

  public Version getClientVersion() {
    return ((InternalDistributedMember) getDistributedMember()).getVersionObject();
  }

  public String getDSMembership() {
    if (identity == null) {
      // some unit tests create IDs that have no real identity, so return null
      return "null";
    }
    // don't cache if we haven't connected to the server yet
    if (((InternalDistributedMember) getDistributedMember()).getPort() == 0) {
      return getDistributedMember().toString();
    }
    if (memberIdString == null) {
      memberIdString = getDistributedMember().toString();
    }
    return memberIdString;
  }

  /**
   * this method uses CacheClientNotifier to try to obtain an ID that is equal to this one. This is
   * used during deserialization to reduce storage overhead.
   */
  private ClientProxyMembershipID canonicalReference() {
    CacheClientNotifier ccn = CacheClientNotifier.getInstance();
    if (ccn != null) {
      CacheClientProxy cp = ccn.getClientProxy(this, true);
      if (cp != null) {
        if (this.isCanonicalEquals(cp.getProxyID())) {
          return cp.getProxyID();
        }
      }
    }
    return this;
  }

  /**
   * deserializes the membership id, if necessary, and returns it. All access to membershipId should
   * be through this method
   */

  public DistributedMember getDistributedMember() {
    if (memberId == null) {
      ByteArrayInputStream bais = new ByteArrayInputStream(identity);
      DataInputStream dis = new VersionedDataInputStream(bais, Version.CURRENT);
      try {
        memberId = (DistributedMember) DataSerializer.readObject(dis);
      } catch (Exception e) {
        logger.error(LocalizedMessage.create(
            LocalizedStrings.ClientProxyMembershipID_UNABLE_TO_DESERIALIZE_MEMBERSHIP_ID), e);
      }
    }
    return memberId;
  }

  /** Returns the byte-array for membership identity */
  byte[] getMembershipByteArray() {
    return this.identity;
  }

  /**
   * Returns whether this ClientProxyMembershipID is durable.
   * 
   * @return whether this ClientProxyMembershipID is durable
   * 
   * @since GemFire 5.5
   */
  public boolean isDurable() {
    String durableClientId = getDistributedMember().getDurableClientAttributes().getId();
    return durableClientId != null && !(durableClientId.length() == 0);
  }

  /**
   * Returns this ClientProxyMembershipID's durable attributes.
   * 
   * @return this ClientProxyMembershipID's durable attributes
   * 
   * @since GemFire 5.5
   */
  protected DurableClientAttributes getDurableAttributes() {
    return getDistributedMember().getDurableClientAttributes();
  }

  /**
   * Returns this ClientProxyMembershipID's durable id.
   * 
   * @return this ClientProxyMembershipID's durable id
   * 
   * @since GemFire 5.5
   */
  public String getDurableId() {
    DurableClientAttributes dca = getDurableAttributes();
    return dca == null ? "" : dca.getId();
  }

  /**
   * Returns this ClientProxyMembershipID's durable timeout.
   * 
   * @return this ClientProxyMembershipID's durable timeout
   * 
   * @since GemFire 5.5
   */
  protected int getDurableTimeout() {
    DurableClientAttributes dca = getDurableAttributes();
    return dca == null ? 0 : dca.getTimeout();
  }

  /**
   * Used to update the timeout when a durable client comes back to a server
   */
  public void updateDurableTimeout(int newValue) {
    DurableClientAttributes dca = getDurableAttributes();
    if (dca != null) {
      dca.updateTimeout(newValue);
    }
  }

  /**
   * call this when the distributed system ID has been modified
   */
  @edu.umd.cs.findbugs.annotations.SuppressWarnings(
      value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD",
      justification = "Only applicable in client DS and in that case too multiple instances do not modify it at the same time.")
  public void updateID(DistributedMember idm) {
    // this.transientPort = ((InternalDistributedMember)this.memberId).getPort();
    // if (this.transientPort == 0) {
    // InternalDistributedSystem.getLoggerI18n().warning(
    // LocalizedStrings.DEBUG,
    // "updating client ID when member port is zero: " + this.memberId,
    // new Exception("stack trace")
    // );
    // }
    HeapDataOutputStream hdos = new HeapDataOutputStream(256, Version.CURRENT);
    try {
      DataSerializer.writeObject(idm, hdos);
    } catch (IOException e) {
      throw new InternalGemFireException("Unable to serialize member: " + this.memberId, e);
    }
    this.identity = hdos.toByteArray();
    if (this.memberId != null && this.memberId == systemMemberId) {
      systemMemberId = idm;
      // client_side_identity = this.identity;
    }
    this.memberId = idm;
    this._toString = null; // make sure we don't retain the old ID representation in toString
  }


  /**
   * Return the name of the HARegion queueing this proxy's messages. This is name is
   * generated based on whether or not this proxy id is durable. If this proxy id is durable, then
   * the durable client id is used. If this proxy id is not durable, then
   * theDistributedMember string is used.
   * 
   * @return the name of the HARegion queueing this proxy's messages.
   * 
   * @since GemFire 5.5
   */
  protected String getHARegionName() {
    return getBaseRegionName() + "_queue";
  }

  /**
   * Return the name of the region used for communicating interest changes between servers.
   * 
   * @return the name of the region used for communicating interest changes between servers
   * 
   * @since GemFire 5.6
   */
  protected String getInterestRegionName() {
    return getBaseRegionName() + "_interest";
  }

  private String getBaseRegionName() {
    String id = isDurable() ? getDurableId() : getDSMembership();
    if (id.indexOf('/') >= 0) {
      id = id.replace('/', ':');
    }
    StringBuffer buffer = new StringBuffer().append("_gfe_").append(isDurable() ? "" : "non_")
        .append("durable_client_").append("with_id_" + id).append("_").append(this.uniqueId);
    return buffer.toString();
  }

  /**
   * Resets the unique id counter. This is done for durable clients that stops/starts its cache.
   * When it restarts its cache, it needs to maintain the same unique id
   * 
   * @since GemFire 5.5
   */
  public static synchronized void resetUniqueIdCounter() {
    synch_counter = 0;
  }

  public Identity getIdentity() {
    return new Identity();
  }

  /**
   * Used to represent a unique identity of this ClientProxyMembershipID. It does this by ignoring
   * the durable id and only respecting the unique_id and identity.
   * 

* This class is used to clean up resources associated with a particular client and thus does not * want to limit itself to the durable id. * * @since GemFire 5.7 */ public class Identity { public int getUniqueId() { return uniqueId; } public byte[] getMemberIdBytes() { return identity; } @Override public int hashCode() { int result = 17; final int mult = 37; byte[] idBytes = getMemberIdBytes(); if (idBytes != null && idBytes.length > 0) { for (int i = 0; i < idBytes.length; i++) { result = mult * result + idBytes[i]; } } result = mult * result + uniqueId; return result; } @Override public boolean equals(Object obj) { if ((obj == null) || !(obj instanceof ClientProxyMembershipID.Identity)) { return false; } ClientProxyMembershipID.Identity that = (ClientProxyMembershipID.Identity) obj; return (getUniqueId() == that.getUniqueId() && Arrays.equals(getMemberIdBytes(), that.getMemberIdBytes())); } public ClientProxyMembershipID getClientProxyID() { return ClientProxyMembershipID.this; } } @Override public Version[] getSerializationVersions() { return null; } public static ClientProxyMembershipID readCanonicalized(DataInput in) throws IOException, ClassNotFoundException { ClientProxyMembershipID result = DataSerializer.readObject(in); // We can't canonicalize if we have no identity. // I only saw this happen in unit tests that serialize "new ClientProxyMembershipID()". if (result == null || result.identity == null) { return result; } return result.canonicalReference(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy