Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 83 additions & 42 deletions ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/Uid.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,15 @@
*/
package com.arjuna.ats.arjuna.common;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.io.Serializable;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.nio.ByteOrder;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

import com.arjuna.ats.arjuna.exceptions.FatalError;
import com.arjuna.ats.arjuna.logging.tsLogger;
Expand Down Expand Up @@ -89,14 +88,22 @@ public Uid (byte[] byteForm)

try
{
ByteArrayInputStream ba = new ByteArrayInputStream(byteForm);
DataInputStream ds = new DataInputStream(ba);

hostAddr[0] = ds.readLong();
hostAddr[1] = ds.readLong();
process = ds.readInt();
sec = ds.readInt();
other = ds.readInt();

if (byteForm.length < UID_SIZE) {
throw new IllegalArgumentException("byteForm too small: " + byteForm.length);
}
long hostAddr0 = (long) BE_LONG_ARRAY_VIEW.get(byteForm, 0);
long hostAddr1 = (long) BE_LONG_ARRAY_VIEW.get(byteForm, 8);
int process = (int) BE_INT_ARRAY_VIEW.get(byteForm, 16);
int sec = (int) BE_INT_ARRAY_VIEW.get(byteForm, 20);
int other = (int) BE_INT_ARRAY_VIEW.get(byteForm, 24);

long[] hostAddr = this.hostAddr;
hostAddr[0] = hostAddr0;
hostAddr[1] = hostAddr1;
this.process = process;
this.sec = sec;
this.other = other;

_valid = true;
}
Expand Down Expand Up @@ -292,18 +299,44 @@ public void print (PrintStream strm)
strm.print("<Uid:" + this.toString() + ">");
}

public String stringForm ()
{
// no need to synchronize since object is immutable
public String stringForm () {
// no need to synchronize since object is immutable

if (_stringForm == null)
_stringForm = Utility.longToHexString(hostAddr[0]) + Uid.breakChar
+ Utility.longToHexString(hostAddr[1]) + Uid.breakChar
+ Utility.intToHexString(process) + Uid.breakChar
+ Utility.intToHexString(sec) + Uid.breakChar
+ Utility.intToHexString(other);
if (_stringForm == null) {
_stringForm = stringForm(breakChar);
}
return _stringForm;
}

return _stringForm;
public String stringForm(byte breakChar) {
long[] hostAddr = this.hostAddr;
long hostAddr0 = hostAddr[0];
long hostAddr1 = hostAddr[1];
int process = this.process;
int sec = this.sec;
int other = this.other;
int hostAddr0Chars = Utility.hexCharsOf(hostAddr0);
int hostAddr1Chars = Utility.hexCharsOf(hostAddr1);
int processChars = Utility.hexCharsOf(process);
int secChars = Utility.hexCharsOf(sec);
int otherChars = Utility.hexCharsOf(other);
int totalChars = hostAddr0Chars + hostAddr1Chars + processChars + secChars + otherChars + 4; // 4 break chars
byte[] asciiBytes = new byte[totalChars];
int pos = 0;
Utility.toHexChars(hostAddr0, asciiBytes, pos, hostAddr0Chars);
pos += hostAddr0Chars;
asciiBytes[pos++] = breakChar;
Utility.toHexChars(hostAddr1, asciiBytes, pos, hostAddr1Chars);
pos += hostAddr1Chars;
asciiBytes[pos++] = breakChar;
Utility.toHexChars(process, asciiBytes, pos, processChars);
pos += processChars;
asciiBytes[pos++] = breakChar;
Utility.toHexChars(sec, asciiBytes, pos, secChars);
pos += secChars;
asciiBytes[pos++] = breakChar;
Utility.toHexChars(other, asciiBytes, pos, otherChars);
return new String(asciiBytes, 0, 0, totalChars);
}

/**
Expand All @@ -313,11 +346,7 @@ public String stringForm ()

public String fileStringForm ()
{
return Utility.longToHexString(hostAddr[0]) + Uid.fileBreakChar
+ Utility.longToHexString(hostAddr[1]) + Uid.fileBreakChar
+ Utility.intToHexString(process) + Uid.fileBreakChar
+ Utility.intToHexString(sec) + Uid.fileBreakChar
+ Utility.intToHexString(other);
return stringForm(fileBreakChar);
}

/**
Expand All @@ -336,19 +365,24 @@ public byte[] getBytes ()

if (_byteForm == null)
{
ByteArrayOutputStream ba = new ByteArrayOutputStream(UID_SIZE);
DataOutputStream ds = new DataOutputStream(ba);

try


long[] hostAddr = this.hostAddr;
int process = this.process;
int sec = this.sec;
int other = this.other;
try
{
ds.writeLong(hostAddr[0]);
ds.writeLong(hostAddr[1]);
ds.writeInt(process);
ds.writeInt(sec);
ds.writeInt(other);
//_byteForm = stringForm().getBytes(StandardCharsets.UTF_8);

_byteForm = ba.toByteArray();

long hostAddr0 = hostAddr[0];
long hostAddr1 = hostAddr[1];
byte[] newByteForm = new byte[UID_SIZE];
BE_LONG_ARRAY_VIEW.set(newByteForm, 0, hostAddr0);
BE_LONG_ARRAY_VIEW.set(newByteForm, 8, hostAddr1);
BE_INT_ARRAY_VIEW.set(newByteForm, 16, process);
BE_INT_ARRAY_VIEW.set(newByteForm, 20, sec);
BE_INT_ARRAY_VIEW.set(newByteForm, 24, other);
BYTE_FORM_UPDATER.lazySet(this, newByteForm);
}
catch (final Throwable ex) {
tsLogger.i18NLogger.warn_common_Uid_getbytes(ex);
Expand Down Expand Up @@ -722,9 +756,16 @@ private static final char getBreakChar (String uidString)

private static volatile int initTime;

private static final char breakChar = ':';
private static final VarHandle BE_LONG_ARRAY_VIEW = MethodHandles.byteArrayViewVarHandle(long[].class, ByteOrder.BIG_ENDIAN);

private static final VarHandle BE_INT_ARRAY_VIEW = MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.BIG_ENDIAN);

private static final AtomicReferenceFieldUpdater<Uid, byte[]> BYTE_FORM_UPDATER =
AtomicReferenceFieldUpdater.newUpdater(Uid.class, byte[].class, "_byteForm");

private static final byte breakChar = ':';

private static final char fileBreakChar = '_';
private static final byte fileBreakChar = '_';

private static final Uid NIL_UID = new Uid("0:0:0:0:0");

Expand Down
116 changes: 108 additions & 8 deletions ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/utils/Utility.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,115 @@ public static int hexStringToInt (String s) throws NumberFormatException
return val;
}

/**
* Convert a long to a hex String.
*/
private static final byte[] HEX_DIGITS;

static {
// each byte contains 2 hex digits
HEX_DIGITS = new byte[16];
HEX_DIGITS[0] = (byte) '0';
HEX_DIGITS[1] = (byte) '1';
HEX_DIGITS[2] = (byte) '2';
HEX_DIGITS[3] = (byte) '3';
HEX_DIGITS[4] = (byte) '4';
HEX_DIGITS[5] = (byte) '5';
HEX_DIGITS[6] = (byte) '6';
HEX_DIGITS[7] = (byte) '7';
HEX_DIGITS[8] = (byte) '8';
HEX_DIGITS[9] = (byte) '9';
HEX_DIGITS[10] = (byte) 'a';
HEX_DIGITS[11] = (byte) 'b';
HEX_DIGITS[12] = (byte) 'c';
HEX_DIGITS[13] = (byte) 'd';
HEX_DIGITS[14] = (byte) 'e';
HEX_DIGITS[15] = (byte) 'f';
}

/**
* Determine the number of hex chars needed to represent the given int
* value. This is at least 1.
*
* @param value the int value
* @return the number of hex chars needed to represent the value
*/
public static int hexCharsOf(int value) {
int signLen = 0;
if (value < 0) {
value = -value;
signLen = 1;
}
int nonZeroBits = Integer.SIZE - Integer.numberOfLeadingZeros(value);
// each hex char represents 4 bits: align the non-zero bits to the next multiple of 4 and divide by 4
return signLen + Math.max(((nonZeroBits + 3) >> 2), 1);
}

/**
* Convert a int to hex chars. The byte array must be big enough to hold
* the expected number of hex chars. See {@link #hexCharsOf(int)} to determine
* the number of hex chars needed.
*
* @param value the int value to convert
* @param ascii the byte array to hold the hex chars
* @param offset the offset into the byte array to start writing
* @param expectedHexChars the expected number of hex chars to write
*/
public static void toHexChars(int value, byte[] ascii, int offset, int expectedHexChars) {
int numHexChars = expectedHexChars;
if (value < 0) {
value = -value;
ascii[offset++] = (byte) '-';
numHexChars--;
}
// write the hex digits in reverse order
for (int i = numHexChars - 1; i >= 0; i--) {
int digit = value & 0xF;
ascii[offset + i] = HEX_DIGITS[digit];
value >>>= 4;
}
}

/**
* Determine the number of hex chars needed to represent the given long
* value. This is at least 1.
*
* @param value the long value
* @return the number of hex chars needed to represent the value
*/
public static int hexCharsOf(long value) {
int signLen = 0;
if (value < 0) {
value = -value;
signLen = 1;
}
int nonZeroBits = Long.SIZE - Long.numberOfLeadingZeros(value);
// each hex char represents 4 bits: align the non-zero bits to the next multiple of 4 and divide by 4
return signLen + Math.max(((nonZeroBits + 3) >> 2), 1);
}

/**
* Convert a long to hex chars. The byte array must be big enough to hold
* the expected number of hex chars. See {@link #hexCharsOf(long)} to determine
* the number of hex chars needed.
*
* @param value the long value to convert
* @param ascii the byte array to hold the hex chars
* @param offset the offset into the byte array to start writing
* @param expectedHexChars the expected number of hex chars to write
*/
public static void toHexChars(long value, byte[] ascii, int offset, int expectedHexChars) {
int numHexChars = expectedHexChars;
if (value < 0) {
value = -value;
ascii[offset++] = (byte) '-';
numHexChars--;
}
// write the hex digits in reverse order
for (int i = numHexChars - 1; i >= 0; i--) {
int digit = (int) (value & 0xF);
ascii[offset + i] = HEX_DIGITS[digit];
value >>>= 4;
}
}

public static String longToHexString (long number)
throws NumberFormatException
{
return Long.toString(number, 16);
}

/**
* Convert a hex String to a long
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,5 +133,12 @@ public void testMaxMinUid () throws Exception
assertTrue(uid.greaterThan(minUid));
assertTrue(maxUid.greaterThan(minUid));
assertTrue(maxUid.greaterThan(uid));

// check the min/max string and file string forms

assertEquals("-8000000000000000:-8000000000000000:-80000000:-80000000:-80000000", minUid.stringForm());
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added these since relevant for the hex encoding @marcosgopen

assertEquals("7fffffffffffffff:7fffffffffffffff:7fffffff:7fffffff:7fffffff", maxUid.stringForm());
assertEquals("-8000000000000000_-8000000000000000_-80000000_-80000000_-80000000", minUid.fileStringForm());
assertEquals("7fffffffffffffff_7fffffffffffffff_7fffffff_7fffffff_7fffffff", maxUid.fileStringForm());
}
}