Skip to content

Commit e98c7ab

Browse files
committedJul 11, 2021
initial commit
0 parents  commit e98c7ab

23 files changed

+828
-0
lines changed
 

‎.gitignore

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
target
2+
*vault.exe*
3+
dist
4+
datademo
5+
.scannerwork
6+
7+
8+
HELP.md
9+
target/
10+
!.mvn/wrapper/maven-wrapper.jar
11+
!**/src/main/**
12+
!**/src/test/**
13+
14+
### STS ###
15+
.apt_generated
16+
.classpath
17+
.factorypath
18+
.project
19+
.settings
20+
.springBeans
21+
.sts4-cache
22+
23+
### IntelliJ IDEA ###
24+
.idea
25+
*.iws
26+
*.iml
27+
*.ipr
28+
29+
### NetBeans ###
30+
/nbproject/private/
31+
/nbbuild/
32+
/dist/
33+
/nbdist/
34+
/.nb-gradle/
35+
build/
36+
37+
### VS Code ###
38+
.vscode/

‎README.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Phantom

‎pom.xml

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<groupId>com.tuannh</groupId>
8+
<artifactId>phantom</artifactId>
9+
<version>1.0-SNAPSHOT</version>
10+
<build>
11+
<plugins>
12+
<plugin>
13+
<groupId>org.apache.maven.plugins</groupId>
14+
<artifactId>maven-compiler-plugin</artifactId>
15+
<configuration>
16+
<source>8</source>
17+
<target>8</target>
18+
</configuration>
19+
</plugin>
20+
</plugins>
21+
</build>
22+
23+
<dependencies>
24+
<dependency>
25+
<groupId>org.projectlombok</groupId>
26+
<artifactId>lombok</artifactId>
27+
<version>1.18.16</version>
28+
<scope>provided</scope>
29+
</dependency>
30+
</dependencies>
31+
</project>
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.tuannh.phantom;
2+
3+
public class Test {
4+
static int bitNum(long val) {
5+
int bit = 0;
6+
for (; val != 0L; bit++) {
7+
val >>>= 1;
8+
}
9+
return bit;
10+
}
11+
12+
public static void main(String[] args) {
13+
System.out.println(bitNum(126));
14+
long x = (1 << 31);
15+
System.out.println((int)(x & 0xffffffffL));
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.tuannh.phantom.commons.concurrent;
2+
3+
import lombok.NoArgsConstructor;
4+
5+
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
6+
7+
// simple version of re-entrance lock
8+
@NoArgsConstructor
9+
public class RLock {
10+
private static final AtomicLongFieldUpdater<RLock> UPDATER = AtomicLongFieldUpdater.newUpdater(RLock.class, "holder");
11+
12+
private volatile long holder;
13+
14+
public boolean lock() {
15+
long threadId = Thread.currentThread().getId();
16+
if (threadId == UPDATER.get(this)) {
17+
return false; // already locked on current thread
18+
}
19+
while (true) {
20+
if (UPDATER.compareAndSet(this, 0, threadId)) {
21+
return true;
22+
}
23+
Thread.yield();
24+
}
25+
}
26+
27+
public void release(boolean lockResult) { // result of latest lock() command
28+
if (lockResult) {
29+
long threadId = Thread.currentThread().getId();
30+
if (!UPDATER.compareAndSet(this, threadId, 0)) {
31+
throw new AssertionError("Something wrong"); // FIXME change assertion message
32+
}
33+
}
34+
}
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.tuannh.phantom.commons.io;
2+
3+
import lombok.AccessLevel;
4+
import lombok.NoArgsConstructor;
5+
6+
import java.io.File;
7+
import java.io.IOException;
8+
import java.nio.file.Files;
9+
import java.util.regex.Pattern;
10+
11+
@NoArgsConstructor(access = AccessLevel.PRIVATE)
12+
public class FileUtils {
13+
public static void mkdir(File dir) throws IOException {
14+
if (dir.exists()) {
15+
if (!dir.isDirectory()) {
16+
throw new IOException(dir.getName() + " is not a directory");
17+
} else {
18+
return;
19+
}
20+
}
21+
boolean b = dir.mkdirs();
22+
if (!b) {
23+
throw new IOException("could not create directory " + dir.getName());
24+
}
25+
}
26+
27+
public static void del(File f) throws IOException {
28+
if (f.isDirectory()) {
29+
File[] files = f.listFiles();
30+
if (files != null) {
31+
for (File file: files) {
32+
del(file);
33+
}
34+
}
35+
} else {
36+
Files.delete(f.toPath());
37+
}
38+
}
39+
40+
public static File[] ls(File dir, Pattern fileNamePattern) throws IOException {
41+
if (dir.isDirectory()) {
42+
if (fileNamePattern == null) {
43+
return dir.listFiles();
44+
} else {
45+
return dir.listFiles(file -> fileNamePattern.matcher(file.getName()).matches());
46+
}
47+
} else {
48+
throw new IOException(dir.getName() + " is not a directory");
49+
}
50+
}
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.tuannh.phantom.commons.number;
2+
3+
import lombok.AccessLevel;
4+
import lombok.NoArgsConstructor;
5+
6+
@NoArgsConstructor(access = AccessLevel.PRIVATE)
7+
public class NumberUtils {
8+
public static long toUInt32(int x) {
9+
return x & 0xffffffffL;
10+
}
11+
12+
public static int fromUInt32(long x) {
13+
return (int)(x & 0xffffffffL);
14+
}
15+
16+
public static byte toUInt8(int x) {
17+
return (byte)(x & 0xff);
18+
}
19+
20+
public static int fromUInt8(byte x) {
21+
return x & 0xff;
22+
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package com.tuannh.phantom.commons.unsafe;
2+
3+
import lombok.AccessLevel;
4+
import lombok.NoArgsConstructor;
5+
6+
import java.lang.reflect.Field;
7+
import java.nio.Buffer;
8+
import java.nio.ByteBuffer;
9+
import java.nio.ByteOrder;
10+
11+
@SuppressWarnings({"java:S1191", "java:S3011"})
12+
@NoArgsConstructor(access = AccessLevel.PRIVATE)
13+
public class UnsafeWrapper {
14+
private static final sun.misc.Unsafe UNSAFE;
15+
private static final Class<?> DIRECT_BYTE_BUFFER_CLASS;
16+
private static final Class<?> DIRECT_BYTE_BUFFER_R_CLASS;
17+
private static final long DIRECT_BYTE_BUFFER_ADDRESS_OFFSET;
18+
private static final long DIRECT_BYTE_BUFFER_CAPACITY_OFFSET;
19+
private static final long DIRECT_BYTE_BUFFER_LIMIT_OFFSET;
20+
21+
static {
22+
try {
23+
// get unsafe instance
24+
Field field = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
25+
field.setAccessible(true);
26+
UNSAFE = (sun.misc.Unsafe) field.get(null);
27+
// checks
28+
if (UNSAFE.addressSize() != 8) {
29+
throw new IllegalStateException("only support 8 bytes address size");
30+
}
31+
// init direct buffer
32+
ByteBuffer directByteBuffer = ByteBuffer.allocateDirect(0);
33+
ByteBuffer readOnlyDirectByteBuffer = directByteBuffer.asReadOnlyBuffer();
34+
DIRECT_BYTE_BUFFER_CLASS = directByteBuffer.getClass();
35+
DIRECT_BYTE_BUFFER_R_CLASS = readOnlyDirectByteBuffer.getClass();
36+
DIRECT_BYTE_BUFFER_ADDRESS_OFFSET = UNSAFE.objectFieldOffset(Buffer.class.getDeclaredField("address"));
37+
DIRECT_BYTE_BUFFER_CAPACITY_OFFSET = UNSAFE.objectFieldOffset(Buffer.class.getDeclaredField("capacity"));
38+
DIRECT_BYTE_BUFFER_LIMIT_OFFSET = UNSAFE.objectFieldOffset(Buffer.class.getDeclaredField("limit"));
39+
} catch (Exception e) {
40+
throw new AssertionError(e);
41+
}
42+
}
43+
44+
// byte buffer
45+
46+
public static ByteBuffer directBuffer(long address, long offset, int len, boolean readOnly) {
47+
ByteBuffer byteBuffer;
48+
try {
49+
if (readOnly) {
50+
byteBuffer = (ByteBuffer) UNSAFE.allocateInstance(DIRECT_BYTE_BUFFER_R_CLASS);
51+
} else {
52+
byteBuffer = (ByteBuffer) UNSAFE.allocateInstance(DIRECT_BYTE_BUFFER_CLASS);
53+
}
54+
UNSAFE.putLong(byteBuffer, DIRECT_BYTE_BUFFER_ADDRESS_OFFSET, address + offset);
55+
UNSAFE.putInt(byteBuffer, DIRECT_BYTE_BUFFER_CAPACITY_OFFSET, len);
56+
UNSAFE.putInt(byteBuffer, DIRECT_BYTE_BUFFER_LIMIT_OFFSET, len);
57+
byteBuffer.order(ByteOrder.BIG_ENDIAN);
58+
return byteBuffer;
59+
} catch (Exception e) {
60+
throw new AssertionError(e);
61+
}
62+
}
63+
64+
// memory
65+
66+
public static long malloc(long size) {
67+
long address = UNSAFE.allocateMemory(size);
68+
if (address == 0) {
69+
throw new OutOfMemoryError("Could not allocate " + size + " bytes");
70+
}
71+
return address;
72+
}
73+
74+
public static void free(long address) {
75+
if (address != 0) {
76+
UNSAFE.freeMemory(address);
77+
}
78+
}
79+
80+
public static void memset(long address, long offset, int len, byte value) {
81+
UNSAFE.setMemory(address + offset, len, value);
82+
}
83+
84+
public static void memcpy(long from, long fromOffset, long to, long toOffset, long len) {
85+
UNSAFE.copyMemory(null, from + fromOffset, null, to + toOffset, len);
86+
}
87+
88+
// special copy
89+
public static void memcpy(byte[] arr, long offset, long to, long toOffset, long len) {
90+
UNSAFE.copyMemory(arr, sun.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET + offset, null, to + toOffset, len);
91+
}
92+
93+
// manipulate
94+
95+
public static void putLong(long address, long offset, long value) {
96+
UNSAFE.putLong(null, address + offset, value);
97+
}
98+
99+
public static long getLong(long address, long offset) {
100+
return UNSAFE.getLong(null, address + offset);
101+
}
102+
103+
public static void putInt(long address, long offset, int value) {
104+
UNSAFE.putInt(null, address + offset, value);
105+
}
106+
107+
public static int getInt(long address, long offset) {
108+
return UNSAFE.getInt(null, address + offset);
109+
}
110+
111+
public static short getShort(long address, long offset) {
112+
return UNSAFE.getShort(null, address + offset);
113+
}
114+
115+
public static void putByte(long address, long offset, byte value) {
116+
UNSAFE.putByte(null, address + offset, value);
117+
}
118+
119+
public static byte getByte(long address, long offset) {
120+
return UNSAFE.getByte(null, address + offset);
121+
}
122+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.tuannh.phantom.db;
2+
3+
import java.io.Closeable;
4+
5+
public interface DB extends Closeable {
6+
byte[] get(byte[] key) throws DBException;
7+
boolean put(byte[] key, byte[] value) throws DBException;
8+
boolean delete(byte[] key) throws DBException;
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.tuannh.phantom.db;
2+
3+
public class DBException extends Exception {
4+
public DBException() { }
5+
public DBException(String message) { super(message); }
6+
public DBException(String message, Throwable cause) { super(message, cause); }
7+
public DBException(Throwable cause) { super(cause); }
8+
public DBException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
9+
super(message, cause, enableSuppression, writableStackTrace);
10+
}
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package com.tuannh.phantom.db.index;
2+
3+
public class InMemoryIndex {
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.tuannh.phantom.db.internal;
2+
3+
import com.tuannh.phantom.db.DB;
4+
import com.tuannh.phantom.db.DBException;
5+
6+
import java.io.File;
7+
import java.io.IOException;
8+
9+
public class PhantomDB implements DB {
10+
private final PhantomDBInternal internal;
11+
12+
public PhantomDB(File dir, PhantomDBOptions options) {
13+
if (!dir.isDirectory()) {
14+
throw new AssertionError(dir.getName() + " is not a directory");
15+
}
16+
internal = new PhantomDBInternal(dir, options);
17+
}
18+
19+
@Override
20+
public byte[] get(byte[] key) throws DBException {
21+
return internal.get(key);
22+
}
23+
24+
@Override
25+
public boolean put(byte[] key, byte[] value) throws DBException {
26+
return internal.put(key, value);
27+
}
28+
29+
@Override
30+
public boolean delete(byte[] key) throws DBException {
31+
return internal.delete(key);
32+
}
33+
34+
@Override
35+
public void close() throws IOException {
36+
internal.close();
37+
}
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package com.tuannh.phantom.db.internal;
2+
3+
import com.tuannh.phantom.commons.io.FileUtils;
4+
5+
import java.io.Closeable;
6+
import java.io.File;
7+
import java.io.IOException;
8+
import java.nio.channels.FileChannel;
9+
import java.nio.file.Path;
10+
import java.nio.file.StandardOpenOption;
11+
12+
public class PhantomDBDirectory implements Closeable {
13+
private final File dir;
14+
private final FileChannel dirChannel;
15+
private final Path path;
16+
17+
public PhantomDBDirectory(File dir) throws IOException {
18+
FileUtils.mkdir(dir);
19+
this.dir = dir;
20+
FileChannel channel = null;
21+
try {
22+
channel = FileChannel.open(dir.toPath(), StandardOpenOption.READ);
23+
} catch (Exception ignored) {
24+
// unnecessary to initiate directory channel
25+
}
26+
this.dirChannel = channel;
27+
this.path = dir.toPath();
28+
}
29+
30+
public File[] dataFiles() {
31+
// TODO
32+
return null;
33+
}
34+
35+
public File[] indexFiles() {
36+
// TODO
37+
return null;
38+
}
39+
40+
public File[] tombstoneFiles() {
41+
// TODO
42+
return null;
43+
}
44+
45+
public Path path() {
46+
return path;
47+
}
48+
49+
public File file() {
50+
return dir;
51+
}
52+
53+
public void sync() throws IOException {
54+
if (dirChannel != null) {
55+
dirChannel.force(true);
56+
}
57+
}
58+
59+
@Override
60+
public void close() throws IOException {
61+
if (dirChannel != null) {
62+
dirChannel.close();
63+
}
64+
}
65+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.tuannh.phantom.db.internal;
2+
3+
import com.tuannh.phantom.db.DBException;
4+
import com.tuannh.phantom.offheap.hashtable.KeyBuffer;
5+
import com.tuannh.phantom.offheap.hashtable.hash.Hasher;
6+
7+
import java.io.Closeable;
8+
import java.io.File;
9+
import java.io.IOException;
10+
11+
public class PhantomDBInternal implements Closeable {
12+
private final Hasher hasher;
13+
14+
public PhantomDBInternal(File dir, PhantomDBOptions options) {
15+
hasher = options.getHasher();
16+
}
17+
18+
public byte[] get(byte[] key) throws DBException {
19+
KeyBuffer keyBuffer = new KeyBuffer(key, hasher.hash(key));
20+
return new byte[0]; // TODO
21+
}
22+
23+
public boolean put(byte[] key, byte[] value) throws DBException {
24+
KeyBuffer keyBuffer = new KeyBuffer(key, hasher.hash(key));
25+
return false; // TODO
26+
}
27+
28+
public boolean delete(byte[] key) throws DBException {
29+
KeyBuffer keyBuffer = new KeyBuffer(key, hasher.hash(key));
30+
return false; // TODO
31+
}
32+
33+
public void close() throws IOException {
34+
// TODO
35+
}
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.tuannh.phantom.db.internal;
2+
3+
public class PhantomDBMetadata {
4+
/**
5+
* checksum(4), version(1), is_open(1), io_error(1), max_file_size(4)
6+
*/
7+
private static final int METADATA_SIZE = 4 + 1 + 1 + 1 + 4;
8+
9+
private long checksum;
10+
private byte version;
11+
private boolean open;
12+
private boolean ioError;
13+
private int maxFileSize;
14+
15+
// TODO
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.tuannh.phantom.db.internal;
2+
3+
import com.tuannh.phantom.offheap.hashtable.hash.Hasher;
4+
import com.tuannh.phantom.offheap.hashtable.hash.Murmur3;
5+
import lombok.Builder;
6+
import lombok.Getter;
7+
8+
@Getter
9+
@Builder
10+
public class PhantomDBOptions {
11+
private int fixedKeySize;
12+
private final Hasher hasher = new Murmur3();
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.tuannh.phantom.offheap.hashtable;
2+
3+
import java.io.Closeable;
4+
5+
public interface HashTable<V> extends Closeable {
6+
boolean putIfAbsent(KeyBuffer keyBuffer, V value);
7+
boolean replace(KeyBuffer keyBuffer, V value);
8+
boolean delete(KeyBuffer keyBuffer);
9+
V get(KeyBuffer keyBuffer);
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.tuannh.phantom.offheap.hashtable;
2+
3+
import lombok.Builder;
4+
import lombok.Getter;
5+
6+
@Getter
7+
@Builder
8+
public class HashTableOptions<V> {
9+
private int numberOfSegments;
10+
private int segmentSize;
11+
private int memoryChunkSize;
12+
private int fixedKeySize;
13+
private int fixedValueSize;
14+
private ValueSerializer<V> valueSerializer;
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.tuannh.phantom.offheap.hashtable;
2+
3+
import lombok.AllArgsConstructor;
4+
5+
// raw value buffer
6+
@AllArgsConstructor
7+
public class KeyBuffer {
8+
private final byte[] buffer;
9+
private final long hash;
10+
11+
public byte[] buffer() {
12+
return buffer;
13+
}
14+
15+
public long hash() {
16+
return hash;
17+
}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package com.tuannh.phantom.offheap.hashtable;
2+
3+
public class OffHeapHashTable<V> {
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.tuannh.phantom.offheap.hashtable;
2+
3+
import java.nio.ByteBuffer;
4+
5+
public interface ValueSerializer<V> {
6+
void serialize(V value, ByteBuffer buffer);
7+
V deserialize(ByteBuffer buffer);
8+
int serializedSize();
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.tuannh.phantom.offheap.hashtable.hash;
2+
3+
import java.nio.ByteBuffer;
4+
5+
public interface Hasher {
6+
long hash(byte[] buffer);
7+
long hash(ByteBuffer buffer);
8+
long hash(long address, long offset, int len); // unsafe hash
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
package com.tuannh.phantom.offheap.hashtable.hash;
2+
3+
import com.tuannh.phantom.commons.unsafe.UnsafeWrapper;
4+
5+
import java.nio.ByteBuffer;
6+
7+
@SuppressWarnings("all")
8+
// from HaloDB
9+
public class Murmur3 implements Hasher {
10+
@Override
11+
public long hash(byte[] array) {
12+
int o = 0;
13+
int r = array.length;
14+
15+
long h1 = 0L;
16+
long h2 = 0L;
17+
long k1, k2;
18+
19+
for (; r >= 16; r -= 16) {
20+
k1 = getLong(array, o);
21+
o += 8;
22+
k2 = getLong(array, o);
23+
o += 8;
24+
25+
// bmix64()
26+
27+
h1 ^= mixK1(k1);
28+
29+
h1 = Long.rotateLeft(h1, 27);
30+
h1 += h2;
31+
h1 = h1 * 5 + 0x52dce729;
32+
33+
h2 ^= mixK2(k2);
34+
35+
h2 = Long.rotateLeft(h2, 31);
36+
h2 += h1;
37+
h2 = h2 * 5 + 0x38495ab5;
38+
}
39+
40+
if (r > 0) {
41+
k1 = 0;
42+
k2 = 0;
43+
switch (r) {
44+
case 15:
45+
k2 ^= toLong(array[o + 14]) << 48; // fall through
46+
case 14:
47+
k2 ^= toLong(array[o + 13]) << 40; // fall through
48+
case 13:
49+
k2 ^= toLong(array[o + 12]) << 32; // fall through
50+
case 12:
51+
k2 ^= toLong(array[o + 11]) << 24; // fall through
52+
case 11:
53+
k2 ^= toLong(array[o + 10]) << 16; // fall through
54+
case 10:
55+
k2 ^= toLong(array[o + 9]) << 8; // fall through
56+
case 9:
57+
k2 ^= toLong(array[o + 8]); // fall through
58+
case 8:
59+
k1 ^= getLong(array, o);
60+
break;
61+
case 7:
62+
k1 ^= toLong(array[o + 6]) << 48; // fall through
63+
case 6:
64+
k1 ^= toLong(array[o + 5]) << 40; // fall through
65+
case 5:
66+
k1 ^= toLong(array[o + 4]) << 32; // fall through
67+
case 4:
68+
k1 ^= toLong(array[o + 3]) << 24; // fall through
69+
case 3:
70+
k1 ^= toLong(array[o + 2]) << 16; // fall through
71+
case 2:
72+
k1 ^= toLong(array[o + 1]) << 8; // fall through
73+
case 1:
74+
k1 ^= toLong(array[o]);
75+
break;
76+
default:
77+
throw new AssertionError("Should never get here.");
78+
}
79+
80+
h1 ^= mixK1(k1);
81+
h2 ^= mixK2(k2);
82+
}
83+
84+
// makeHash()
85+
86+
h1 ^= array.length;
87+
h2 ^= array.length;
88+
89+
h1 += h2;
90+
h2 += h1;
91+
92+
h1 = fmix64(h1);
93+
h2 = fmix64(h2);
94+
95+
h1 += h2;
96+
//h2 += h1;
97+
98+
// padToLong()
99+
return h1;
100+
}
101+
102+
@Override
103+
public long hash(ByteBuffer buffer) {
104+
return hash(buffer.array());
105+
}
106+
107+
@Override
108+
public long hash(long adr, long offset, int length) {
109+
long o = offset;
110+
long r = length;
111+
112+
long h1 = 0L;
113+
long h2 = 0L;
114+
long k1, k2;
115+
116+
for (; r >= 16; r -= 16) {
117+
k1 = getLong(adr, o);
118+
o += 8;
119+
k2 = getLong(adr, o);
120+
o += 8;
121+
122+
// bmix64()
123+
124+
h1 ^= mixK1(k1);
125+
126+
h1 = Long.rotateLeft(h1, 27);
127+
h1 += h2;
128+
h1 = h1 * 5 + 0x52dce729;
129+
130+
h2 ^= mixK2(k2);
131+
132+
h2 = Long.rotateLeft(h2, 31);
133+
h2 += h1;
134+
h2 = h2 * 5 + 0x38495ab5;
135+
}
136+
137+
if (r > 0) {
138+
k1 = 0;
139+
k2 = 0;
140+
switch ((int) r) {
141+
case 15:
142+
k2 ^= toLong(UnsafeWrapper.getByte(adr, o + 14)) << 48; // fall through
143+
case 14:
144+
k2 ^= toLong(UnsafeWrapper.getByte(adr, o + 13)) << 40; // fall through
145+
case 13:
146+
k2 ^= toLong(UnsafeWrapper.getByte(adr, o + 12)) << 32; // fall through
147+
case 12:
148+
k2 ^= toLong(UnsafeWrapper.getByte(adr, o + 11)) << 24; // fall through
149+
case 11:
150+
k2 ^= toLong(UnsafeWrapper.getByte(adr, o + 10)) << 16; // fall through
151+
case 10:
152+
k2 ^= toLong(UnsafeWrapper.getByte(adr, o + 9)) << 8; // fall through
153+
case 9:
154+
k2 ^= toLong(UnsafeWrapper.getByte(adr, o + 8)); // fall through
155+
case 8:
156+
k1 ^= getLong(adr, o);
157+
break;
158+
case 7:
159+
k1 ^= toLong(UnsafeWrapper.getByte(adr, o + 6)) << 48; // fall through
160+
case 6:
161+
k1 ^= toLong(UnsafeWrapper.getByte(adr, o + 5)) << 40; // fall through
162+
case 5:
163+
k1 ^= toLong(UnsafeWrapper.getByte(adr, o + 4)) << 32; // fall through
164+
case 4:
165+
k1 ^= toLong(UnsafeWrapper.getByte(adr, o + 3)) << 24; // fall through
166+
case 3:
167+
k1 ^= toLong(UnsafeWrapper.getByte(adr, o + 2)) << 16; // fall through
168+
case 2:
169+
k1 ^= toLong(UnsafeWrapper.getByte(adr, o + 1)) << 8; // fall through
170+
case 1:
171+
k1 ^= toLong(UnsafeWrapper.getByte(adr, o));
172+
break;
173+
default:
174+
throw new AssertionError("Should never get here.");
175+
}
176+
177+
h1 ^= mixK1(k1);
178+
h2 ^= mixK2(k2);
179+
}
180+
181+
// makeHash()
182+
183+
h1 ^= length;
184+
h2 ^= length;
185+
186+
h1 += h2;
187+
h2 += h1;
188+
189+
h1 = fmix64(h1);
190+
h2 = fmix64(h2);
191+
192+
h1 += h2;
193+
//h2 += h1;
194+
195+
// padToLong()
196+
197+
return h1;
198+
}
199+
200+
private static long getLong(byte[] array, int o) {
201+
long l = toLong(array[o + 7]) << 56;
202+
l |= toLong(array[o + 6]) << 48;
203+
l |= toLong(array[o + 5]) << 40;
204+
l |= toLong(array[o + 4]) << 32;
205+
l |= toLong(array[o + 3]) << 24;
206+
l |= toLong(array[o + 2]) << 16;
207+
l |= toLong(array[o + 1]) << 8;
208+
l |= toLong(array[o]);
209+
return l;
210+
}
211+
212+
private static long getLong(long adr, long o) {
213+
long l = toLong(UnsafeWrapper.getByte(adr, o + 7)) << 56;
214+
l |= toLong(UnsafeWrapper.getByte(adr, o + 6)) << 48;
215+
l |= toLong(UnsafeWrapper.getByte(adr, o + 5)) << 40;
216+
l |= toLong(UnsafeWrapper.getByte(adr, o + 4)) << 32;
217+
l |= toLong(UnsafeWrapper.getByte(adr, o + 3)) << 24;
218+
l |= toLong(UnsafeWrapper.getByte(adr, o + 2)) << 16;
219+
l |= toLong(UnsafeWrapper.getByte(adr, o + 1)) << 8;
220+
l |= toLong(UnsafeWrapper.getByte(adr, o));
221+
return l;
222+
}
223+
224+
static final long C1 = 0x87c37b91114253d5L;
225+
static final long C2 = 0x4cf5ad432745937fL;
226+
227+
static long fmix64(long k) {
228+
k ^= k >>> 33;
229+
k *= 0xff51afd7ed558ccdL;
230+
k ^= k >>> 33;
231+
k *= 0xc4ceb9fe1a85ec53L;
232+
k ^= k >>> 33;
233+
return k;
234+
}
235+
236+
static long mixK1(long k1) {
237+
k1 *= C1;
238+
k1 = Long.rotateLeft(k1, 31);
239+
k1 *= C2;
240+
return k1;
241+
}
242+
243+
static long mixK2(long k2) {
244+
k2 *= C2;
245+
k2 = Long.rotateLeft(k2, 33);
246+
k2 *= C1;
247+
return k2;
248+
}
249+
250+
static long toLong(byte value) {
251+
return value & 0xff;
252+
}
253+
}

0 commit comments

Comments
 (0)
Please sign in to comment.