com.gemstone.gemfire.internal.cache.ha.ThreadIdentifier Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gemfire-core Show documentation
Show all versions of gemfire-core Show documentation
SnappyData store based off Pivotal GemFireXD
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.ha;
import java.io.ByteArrayInputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Arrays;
import com.gemstone.gemfire.DataSerializable;
import com.gemstone.gemfire.DataSerializer;
import com.gemstone.gemfire.distributed.internal.membership.InternalDistributedMember;
import com.gemstone.gemfire.internal.cache.EventID;
/**
* Class identifying a Thread uniquely across the distributed system. It is
* composed of two fields 1) A byte array uniquely identifying the distributed
* system 2) A long value unqiuely identifying the thread in the distributed
* system
*
* The application thread while operating on the Region gets an EventID object (
* contained in EntryEventImpl) This EventID object contains a ThreadLocal field
* which uniquely identifies the thread by storing the Object of this class.
*
* @see EventID
* @author Asif
*
*
*/
public class ThreadIdentifier implements DataSerializable {
private static final long serialVersionUID = 3366884860834823186L;
private byte[] membershipID;
private long threadID;
public static final long MAX_THREAD_PER_CLIENT = 1000000L;
public static final int MAX_BUCKET_PER_PR = 1000;
public static final long WAN_BITS_MASK = 0xFFFFFFFF00000000L;
/**
* Generates thread ids for parallel wan usage.
*/
public enum WanType {
RESERVED, // original thread id incl putAll (or old format)
PRIMARY, // parallel new wan
SECONDARY, // parallel new wan
PARALLEL; // parallel old wan
/**
* Generates a new thread id for usage in a parallel wan context.
* @param threadId the original thread id
* @param offset the thread offset
* @return the new thread id
*/
public long generateWanId(long threadId, long offset) {
assert this != RESERVED;
return Bits.WAN_TYPE.shift(ordinal())
| Bits.WAN.shift(offset)
| threadId;
}
/**
* Returns true if the supplied value is a wan thread identifier.
* @param tid the thread
* @return true if the thread id is one of the wan types
*/
public static boolean matches(long tid) {
return Bits.WAN_TYPE.extract(tid) > 0;
}
}
/**
* Provides type-safe bitwise access to the threadID when dealing with generated
* values for wan id generation.
*/
protected enum Bits {
THREAD_ID (0, 32), // bits 0-31 thread id (including fake putAll bits)
WAN (32, 16), // bits 32-47 wan thread index (or bucket for new wan)
WAN_TYPE (48, 8), // bits 48-55 thread id type
RESERVED (56, 8); // bits 56-63 unused
/** the beginning bit position */
private final int position;
/** the field width */
private final int width;
private Bits(int position, int width) {
this.position = position;
this.width = width;
}
/**
* Returns the field bitmask.
* @return the mask
*/
public long mask() {
return (1L << width) - 1;
}
/**
* Returns the value shifted into the field position.
* @param val the value to shift
* @return the shifted value
*/
public long shift(long val) {
assert val <= mask();
return val << position;
}
/**
* Extracts the field bits from the value.
* @param val the value
* @return the field
*/
public long extract(long val) {
return (val >> position) & mask();
}
}
public ThreadIdentifier() {
}
public ThreadIdentifier(final byte[] mid, long threadId) {
this.membershipID = mid;
this.threadID = threadId;
}
@Override
public boolean equals(Object obj)
{
if ((obj == null) || !(obj instanceof ThreadIdentifier)) {
return false;
}
return (this.threadID == ((ThreadIdentifier)obj).threadID && Arrays.equals(
this.membershipID, ((ThreadIdentifier)obj).membershipID));
}
// TODO: Asif : Check this implementation
@Override
public int hashCode()
{
int result = 17;
final int mult = 37;
if (this.membershipID != null && this.membershipID.length > 0) {
for (int i = 0; i < this.membershipID.length; i++) {
result = mult * result + this.membershipID[i];
}
}
result = mult* result + (int) this.threadID;
result = mult* result + (int) (this.threadID >>> 32);
return result;
}
public byte[] getMembershipID()
{
return membershipID;
}
public long getThreadID()
{
return threadID;
}
public static String toDisplayString(long tid) {
StringBuilder sb = new StringBuilder();
long lower = Bits.THREAD_ID.extract(tid);
if (lower != tid) {
sb.append("0x");
sb.append(Long.toHexString(tid >> Bits.THREAD_ID.width));
sb.append("|");
}
sb.append(lower);
return sb.toString();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("ThreadId[");
sb.append(toDisplayString(threadID));
sb.append("]");
return sb.toString();
}
public String expensiveToString() {
Object mbr;
try {
mbr = InternalDistributedMember.readEssentialData(
new DataInputStream(new ByteArrayInputStream(membershipID)));
}
catch (Exception e) {
mbr = membershipID; // punt and use the bytes
}
return "ThreadId[" + mbr + "; thread " + toDisplayString(threadID) + "]";
}
/**
* convert fake thread id into real thread id
*
* @param tid thread id
* @return real thread id
*/
public static long getRealThreadID(long tid) {
return Bits.THREAD_ID.extract(tid) % MAX_THREAD_PER_CLIENT;
}
/**
* convert fake thread id into real thread id including WAN id
*
* @param tid thread id
* @return real thread id
*/
public static long getRealThreadIDIncludingWan(long tid) {
return getRealThreadID(tid) | (tid & WAN_BITS_MASK);
}
/**
* check if current thread id is a fake thread id for putAll
*
* @param tid thread id
* @return whether the thread id is fake
*/
public static boolean isPutAllFakeThreadID(long tid) {
return Bits.THREAD_ID.extract(tid) / MAX_THREAD_PER_CLIENT > 0;
}
/**
* check if current thread id is generated by ParallelWAN
*
* @param tid thread id
* @return whether the thread id is generated by ParallelGatewaySender
*/
public static boolean isParallelWANThreadID(long tid) {
return WanType.matches(tid) ? true
: tid / MAX_THREAD_PER_CLIENT > (MAX_BUCKET_PER_PR + 2);
}
/**
* create a fake id for an operation on the given bucket
* @return the fake id
*/
public static long createFakeThreadIDForPutAll(int bucketNumber,
long originatingThreadId) {
return (MAX_THREAD_PER_CLIENT * (bucketNumber + 1) + originatingThreadId);
}
/**
* create a fake id for an operation on the given bucket
* @return the fake id
*/
public static long createFakeThreadIDForParallelGSPrimaryBucket(int bucketId,
long originatingThreadId) {
return WanType.PRIMARY.generateWanId(originatingThreadId, bucketId);
}
/**
* create a fake id for an operation on the given bucket
* @return the fake id
*/
public static long createFakeThreadIDForParallelGSSecondaryBucket(
int bucketId, long originatingThreadId) {
return WanType.SECONDARY.generateWanId(originatingThreadId, bucketId);
}
/**
* create a fake id for an operation on the given bucket
* @return the fake id
*/
public static long createFakeThreadIDForParallelGateway(int index,
long originatingThreadId) {
return WanType.PARALLEL.generateWanId(originatingThreadId, index);
}
/**
* checks to see if the membership id of this identifier is the same
* as in the argument
* @param other
* @return whether the two IDs are from the same member
*/
public boolean isSameMember(ThreadIdentifier other) {
return Arrays.equals(this.membershipID, other.membershipID);
}
public void fromData(DataInput in) throws IOException, ClassNotFoundException {
membershipID = DataSerializer.readByteArray(in);
threadID = in.readLong();
}
public void toData(DataOutput out) throws IOException {
DataSerializer.writeByteArray(membershipID, out);
out.writeLong(threadID);
}
}