3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-02-07 06:44:16 +00:00

Patch 10 from Steves lazy parsing patchset.

Customize Sha256Hash.hashCode() method to only use first n bytes of the backing array.  This provides uniqueness to 256^n combinations.  As hashcode is not required to be guaranteed unique this fulfills the contract and reduces hashing time.

Use case is for applications that do a lot of mapping by Sha256Hash.  Each put and get require several hashcode operations.  Cached hashcode is already implemented in 8.patch.

Similar changes to this yielded huge performance benefits in poolserverj.

There is no point implementing a FastEquals version of equals given the bytes are essentially random and no byte is any more likely unique than another.
This commit is contained in:
Mike Hearn 2011-10-14 12:39:11 +00:00
parent ee083d6fac
commit f336a89984
2 changed files with 45 additions and 3 deletions

View File

@ -33,13 +33,42 @@ public class Sha256Hash implements Serializable {
private byte[] bytes;
private int hash = -1;
/**
* @see setHashcodeByteLength(int hashcodeByteLength)
*/
private static int HASHCODE_BYTES_TO_CHECK = 5;
private static boolean HASHCODE_BYTES_TO_CHECK_CHANGED = false;
public static final Sha256Hash ZERO_HASH = new Sha256Hash(new byte[32]);
/**
* Alters the number of bytes from the backing array to use when generating java hashCodes.
* <br/><br/>
* The default value of 5 gives approximately 1 trillion possible unique combinations.
* Given that an int hashcode only has 4 billion possible values it should be more than enough.
* <br/><br/>
* Changing this value after Sha256Hashes have been stored in hashed collections breaks the
* hashCode contract and will result in unpredictable behaviour. If this
* needs to be set to a different value it should be done once and only once
* and before any calls to hashCode() are made on any instance of Sha256Hash instances.
* <br/>
* @param hashcodeByteLength the number of bytes in the hash to use for generating the hashcode.
* @throws IllegalStateException if called more than once.
*/
public static void setHashcodeByteLength(int hashcodeByteLength) {
if (HASHCODE_BYTES_TO_CHECK_CHANGED)
throw new IllegalStateException("setHashcodeByteLength can only be called once and should be called before any instances of Sha256Hash are constructed");
HASHCODE_BYTES_TO_CHECK = hashcodeByteLength;
HASHCODE_BYTES_TO_CHECK_CHANGED = true;
}
/** Creates a Sha256Hash by wrapping the given byte array. It must be 32 bytes long. */
public Sha256Hash(byte[] bytes) {
assert bytes.length == 32;
this.bytes = bytes;
}
private Sha256Hash(byte[] bytes, int hash) {
@ -78,8 +107,11 @@ public class Sha256Hash implements Serializable {
*/
@Override
public int hashCode() {
if (hash == -1)
hash = Arrays.hashCode(bytes);
if (hash == -1) {
hash = 1;
for (int i = 0; i < HASHCODE_BYTES_TO_CHECK; i++)
hash = 31 * hash + bytes[i];
}
return hash;
}

View File

@ -155,12 +155,18 @@ public class SpeedTest {
float total = 0;
float r224total = 0;
float totalTime = 0;
float totalr224Time = 0;
int rcount = 0;
for (Float[] f: gains) {
total += f[0];
if (f[1] != -1) {
rcount++;
r224total += f[1];
totalTime += f[2];
totalr224Time += f[3];
}
}
NumberFormat nf = NumberFormat.getInstance();
@ -169,6 +175,10 @@ public class SpeedTest {
float avg = total / gains.size();
float r224Avg = r224total / rcount;
System.out.println("\n Average performance gain across all main run tests [" + gains.size() + "]: " + nf.format(avg) + "% - against r224 client: [" + rcount + "]: " + nf.format(r224Avg) + "%");
float perc = ((float) totalr224Time / totalTime - 1) * 100;
System.out.println("Total time to run main run tests: [Lazy]" + totalTime + "ms, [r224] " + totalr224Time + "ms. Diff: " + (totalr224Time - totalTime) + "ms - " + nf.format(perc) + "% gain");
}
private void resetBlockStore() {
@ -1002,7 +1012,7 @@ public class SpeedTest {
if (man.timeForR224Test() == -1)
r224Perc = -1;
if (gains != null)
gains.add(new Float[] {perc, r224Perc});
gains.add(new Float[] {perc, r224Perc, (float) bestTime, (float) man.timeForR224Test()});
}
public static void pause(int millis) {