[BAEL-7044] Shared Memory Between Two JVMs (#15162)
* [BAEL-4849] Article code * [BAEL-4968] Article code * [BAEL-4968] Article code * [BAEL-4968] Article code * [BAEL-4968] Remove extra comments * [BAEL-5258] Article Code * [BAEL-2765] PKCE Support for Secret Clients * [BAEL-5698] Article code * [BAEL-5698] Article code * [BAEL-5905] Initial code * [BAEL-5905] Article code * [BAEL-5905] Relocate article code to new module * [BAEL-6275] PostgreSQL NOTIFY/LISTEN * [BAEL-6275] Minor correction * BAEL-6138 * [BAEL-6138] WIP - LiveTest * [BAEL-6138] Tutorial Code * [BAEL-6138] Tutorial Code * [BAEL-6694] Article Code * [BAEL-7044] Tutorial code --------- Co-authored-by: Philippe Sevestre <psevestre@gmail.com>
This commit is contained in:
parent
499ed4bbbd
commit
0b0db24ebb
8
core-java-modules/core-java-sun/shared-mem-test1.bat
Normal file
8
core-java-modules/core-java-sun/shared-mem-test1.bat
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
@rem This bat file starts the consumer and producer (more or less) at the same time
|
||||||
|
cd target\classes
|
||||||
|
rem start java --add-opens java.base/java.nio=ALL-UNNAMED com.baeldung.sharedmem.ProducerApp c:\lixo\sharedmem.bin 65536
|
||||||
|
rem start java --add-opens java.base/java.nio=ALL-UNNAMED com.baeldung.sharedmem.ConsumerApp c:\lixo\sharedmem.bin 65536
|
||||||
|
start %JAVA_HOME%\bin\java com.baeldung.sharedmem.ProducerApp c:\lixo\sharedmem.bin 65536
|
||||||
|
start %JAVA_HOME%\bin\java com.baeldung.sharedmem.ConsumerApp c:\lixo\sharedmem.bin 65536
|
||||||
|
cd ..
|
||||||
|
cd ..
|
10
core-java-modules/core-java-sun/shared-mem-test2.bat
Normal file
10
core-java-modules/core-java-sun/shared-mem-test2.bat
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
@rem This bat file starts the consumer and producer (more or less) at the same time
|
||||||
|
del target\sharedmem.bin
|
||||||
|
echo "" > target\sharedmem.bin
|
||||||
|
cd target\classes
|
||||||
|
rem start java --add-opens java.base/java.nio=ALL-UNNAMED com.baeldung.sharedmem.ProducerAppWithSpinLock ..\sharedmem.bin 65536
|
||||||
|
rem start java --add-opens java.base/java.nio=ALL-UNNAMED com.baeldung.sharedmem.ConsumerAppWithSpinLock ..\sharedmem.bin 65536
|
||||||
|
start %JAVA_HOME%\bin\java com.baeldung.sharedmem.ProducerAppWithSpinLock ..\sharedmem.bin 65536
|
||||||
|
start %JAVA_HOME%\bin\java com.baeldung.sharedmem.ConsumerAppWithSpinLock ..\sharedmem.bin 65536
|
||||||
|
cd ..
|
||||||
|
cd ..
|
@ -0,0 +1,94 @@
|
|||||||
|
package com.baeldung.sharedmem;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.nio.MappedByteBuffer;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.StandardOpenOption;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
public class ConsumerApp {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
|
||||||
|
MessageDigest digest = MessageDigest.getInstance("SHA1");
|
||||||
|
digest.digest(new byte[256]);
|
||||||
|
byte[] dummy = digest.digest();
|
||||||
|
int hashLen = dummy.length;
|
||||||
|
|
||||||
|
System.out.println("Starting consumer iterations...");
|
||||||
|
|
||||||
|
long size = Long.parseLong(args[1]);
|
||||||
|
MappedByteBuffer shm = createSharedMemory(args[0], size + hashLen);
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
long iterations = 0;
|
||||||
|
int capacity = shm.capacity();
|
||||||
|
|
||||||
|
long matchCount = 0;
|
||||||
|
long mismatchCount = 0;
|
||||||
|
byte[] expectedHash = new byte[hashLen];
|
||||||
|
|
||||||
|
while (System.currentTimeMillis() - start < 30_000) {
|
||||||
|
|
||||||
|
for (int i = 0; i < capacity - hashLen; i++) {
|
||||||
|
byte value = shm.get(i);
|
||||||
|
digest.update(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] hash = digest.digest();
|
||||||
|
shm.position(capacity-hashLen);
|
||||||
|
shm.get(expectedHash);
|
||||||
|
|
||||||
|
if (Arrays.equals(hash, expectedHash)) {
|
||||||
|
matchCount++;
|
||||||
|
} else {
|
||||||
|
mismatchCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterations++;
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.printf("%d iterations run. matches=%d, mismatches=%d\n", iterations, matchCount, mismatchCount);
|
||||||
|
System.out.println("Press <enter> to exit");
|
||||||
|
System.console()
|
||||||
|
.readLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MappedByteBuffer createSharedMemory(String path, long size) {
|
||||||
|
|
||||||
|
try (FileChannel fc = (FileChannel) Files.newByteChannel(
|
||||||
|
new File(path).toPath(),
|
||||||
|
EnumSet.of(
|
||||||
|
StandardOpenOption.CREATE,
|
||||||
|
StandardOpenOption.SPARSE,
|
||||||
|
StandardOpenOption.WRITE,
|
||||||
|
StandardOpenOption.READ))) {
|
||||||
|
return fc.map(FileChannel.MapMode.READ_WRITE, 0, size);
|
||||||
|
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
throw new RuntimeException(ioe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long getBufferAddress(MappedByteBuffer shm) {
|
||||||
|
try {
|
||||||
|
Class<?> cls = shm.getClass();
|
||||||
|
Method maddr = cls.getMethod("address");
|
||||||
|
maddr.setAccessible(true);
|
||||||
|
Long addr = (Long) maddr.invoke(shm);
|
||||||
|
if (addr == null) {
|
||||||
|
throw new RuntimeException("Unable to retrieve buffer's address");
|
||||||
|
}
|
||||||
|
return addr;
|
||||||
|
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,119 @@
|
|||||||
|
package com.baeldung.sharedmem;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.nio.MappedByteBuffer;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.StandardOpenOption;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
public class ConsumerAppWithSpinLock {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
try {
|
||||||
|
// Small wait to ensure the Producer gets the first round. Otherwise the hash will be invalid
|
||||||
|
Thread.sleep(1000);
|
||||||
|
run(args);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
System.console()
|
||||||
|
.printf("Press <enter> to continue");
|
||||||
|
System.console()
|
||||||
|
.readLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void run(String args[]) throws Exception {
|
||||||
|
|
||||||
|
MessageDigest digest = MessageDigest.getInstance("SHA1");
|
||||||
|
digest.digest(new byte[256]);
|
||||||
|
byte[] dummy = digest.digest();
|
||||||
|
int hashLen = dummy.length;
|
||||||
|
|
||||||
|
long size = Long.parseLong(args[1]);
|
||||||
|
MappedByteBuffer shm = createSharedMemory(args[0], size + hashLen);
|
||||||
|
long addr = getBufferAddress(shm);
|
||||||
|
|
||||||
|
System.out.printf("Buffer address: 0x%08x\n", addr);
|
||||||
|
|
||||||
|
Random rnd = new Random();
|
||||||
|
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
long iterations = 0;
|
||||||
|
int capacity = shm.capacity();
|
||||||
|
System.out.println("Starting consumer iterations...");
|
||||||
|
|
||||||
|
long matchCount = 0;
|
||||||
|
long mismatchCount = 0;
|
||||||
|
byte[] expectedHash = new byte[hashLen];
|
||||||
|
SpinLock lock = new SpinLock(addr);
|
||||||
|
|
||||||
|
while (System.currentTimeMillis() - start < 30_000) {
|
||||||
|
|
||||||
|
if (!lock.tryLock(5_000)) {
|
||||||
|
throw new RuntimeException("Unable to acquire lock");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (int i = 4; i < capacity - hashLen; i++) {
|
||||||
|
byte value = shm.get(i);
|
||||||
|
digest.update(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] hash = digest.digest();
|
||||||
|
shm.position(capacity-hashLen);
|
||||||
|
shm.get(expectedHash);
|
||||||
|
|
||||||
|
if (Arrays.equals(hash, expectedHash)) {
|
||||||
|
matchCount++;
|
||||||
|
} else {
|
||||||
|
mismatchCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterations++;
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.printf("%d iteractions run. matches=%d, mismatches=%d\n", iterations, matchCount, mismatchCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MappedByteBuffer createSharedMemory(String path, long size) {
|
||||||
|
|
||||||
|
try (FileChannel fc = (FileChannel) Files.newByteChannel(
|
||||||
|
new File(path).toPath(),
|
||||||
|
EnumSet.of(
|
||||||
|
StandardOpenOption.CREATE,
|
||||||
|
StandardOpenOption.SPARSE,
|
||||||
|
StandardOpenOption.WRITE,
|
||||||
|
StandardOpenOption.READ))) {
|
||||||
|
return fc.map(FileChannel.MapMode.READ_WRITE, 0, size);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
throw new RuntimeException(ioe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long getBufferAddress(MappedByteBuffer shm) {
|
||||||
|
try {
|
||||||
|
Class<?> cls = shm.getClass();
|
||||||
|
Method maddr = cls.getMethod("address");
|
||||||
|
maddr.setAccessible(true);
|
||||||
|
Long addr = (Long) maddr.invoke(shm);
|
||||||
|
if (addr == null) {
|
||||||
|
throw new RuntimeException("Unable to retrieve buffer's address");
|
||||||
|
}
|
||||||
|
return addr;
|
||||||
|
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,89 @@
|
|||||||
|
package com.baeldung.sharedmem;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.nio.MappedByteBuffer;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.StandardOpenOption;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
public class ProducerApp {
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
|
||||||
|
MessageDigest digest = MessageDigest.getInstance("SHA1");
|
||||||
|
digest.digest(new byte[256]);
|
||||||
|
byte[] dummy = digest.digest();
|
||||||
|
int hashLen = dummy.length;
|
||||||
|
|
||||||
|
|
||||||
|
long size = Long.parseLong(args[1]);
|
||||||
|
MappedByteBuffer shm = createSharedMemory(args[0], size + hashLen);
|
||||||
|
|
||||||
|
System.out.println("Starting producer iterations...");
|
||||||
|
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
long iterations = 0;
|
||||||
|
int capacity = shm.capacity();
|
||||||
|
Random rnd = new Random();
|
||||||
|
|
||||||
|
while(System.currentTimeMillis() - start < 30000) {
|
||||||
|
|
||||||
|
for (int i = 0; i < capacity - hashLen; i++) {
|
||||||
|
byte value = (byte) (rnd.nextInt(256) & 0x00ff);
|
||||||
|
digest.update(value);
|
||||||
|
shm.put(i, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write hash at the end
|
||||||
|
byte[] hash = digest.digest();
|
||||||
|
shm.position(capacity - hashLen);
|
||||||
|
shm.put(hash);
|
||||||
|
iterations++;
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.printf("%d iterations run\n", iterations);
|
||||||
|
System.out.println("Press <enter> to exit");
|
||||||
|
System.console().readLine();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long getBufferAddress(MappedByteBuffer shm) {
|
||||||
|
try {
|
||||||
|
Class<?> cls = shm.getClass();
|
||||||
|
Method maddr = cls.getMethod("address");
|
||||||
|
maddr.setAccessible(true);
|
||||||
|
Long addr = (Long) maddr.invoke(shm);
|
||||||
|
if ( addr == null ) {
|
||||||
|
throw new RuntimeException("Unable to retrieve buffer's address");
|
||||||
|
}
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
catch( NoSuchMethodException | InvocationTargetException | IllegalAccessException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MappedByteBuffer createSharedMemory(String path, long size) {
|
||||||
|
|
||||||
|
try (FileChannel fc = (FileChannel)Files.newByteChannel(new File(path).toPath(),
|
||||||
|
EnumSet.of(
|
||||||
|
StandardOpenOption.CREATE,
|
||||||
|
StandardOpenOption.SPARSE,
|
||||||
|
StandardOpenOption.WRITE,
|
||||||
|
StandardOpenOption.READ))) {
|
||||||
|
|
||||||
|
return fc.map(FileChannel.MapMode.READ_WRITE, 0, size);
|
||||||
|
}
|
||||||
|
catch( IOException ioe) {
|
||||||
|
throw new RuntimeException(ioe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,117 @@
|
|||||||
|
package com.baeldung.sharedmem;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.nio.MappedByteBuffer;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.StandardOpenOption;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
public class ProducerAppWithSpinLock {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
try {
|
||||||
|
run(args);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
System.console()
|
||||||
|
.printf("Press <enter> to continue");
|
||||||
|
System.console()
|
||||||
|
.readLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void run(String[] args) throws Exception {
|
||||||
|
|
||||||
|
MessageDigest digest = MessageDigest.getInstance("SHA1");
|
||||||
|
digest.digest(new byte[256]);
|
||||||
|
byte[] dummy = digest.digest();
|
||||||
|
int hashLen = dummy.length;
|
||||||
|
|
||||||
|
|
||||||
|
long size = Long.parseLong(args[1]);
|
||||||
|
MappedByteBuffer shm = createSharedMemory(args[0], size + hashLen);
|
||||||
|
|
||||||
|
// Cleanup lock area
|
||||||
|
shm.putInt(0,0);
|
||||||
|
|
||||||
|
long addr = getBufferAddress(shm);
|
||||||
|
System.out.printf("Buffer address: 0x%08x\n",addr);
|
||||||
|
Random rnd = new Random();
|
||||||
|
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
long iterations = 0;
|
||||||
|
int capacity = shm.capacity();
|
||||||
|
System.out.println("Starting producer iterations...");
|
||||||
|
SpinLock lock = new SpinLock(addr);
|
||||||
|
while(System.currentTimeMillis() - start < 30000) {
|
||||||
|
|
||||||
|
if(!lock.tryLock(5000)) {
|
||||||
|
throw new RuntimeException("Unable to acquire lock");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Skip the first 4 bytes, as they're used by the lock
|
||||||
|
for (int i = 4; i < capacity - hashLen; i++) {
|
||||||
|
byte value = (byte) (rnd.nextInt(256) & 0x00ff);
|
||||||
|
digest.update(value);
|
||||||
|
shm.put(i, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write hash at the end
|
||||||
|
byte[] hash = digest.digest();
|
||||||
|
shm.position(capacity-hashLen);
|
||||||
|
shm.put(hash);
|
||||||
|
iterations++;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.printf("%d iterations run\n", iterations);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long getBufferAddress(MappedByteBuffer shm) {
|
||||||
|
try {
|
||||||
|
Class<?> cls = shm.getClass();
|
||||||
|
Method maddr = cls.getMethod("address");
|
||||||
|
maddr.setAccessible(true);
|
||||||
|
Long addr = (Long) maddr.invoke(shm);
|
||||||
|
if ( addr == null ) {
|
||||||
|
throw new RuntimeException("Unable to retrieve buffer's address");
|
||||||
|
}
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
catch( NoSuchMethodException | InvocationTargetException | IllegalAccessException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MappedByteBuffer createSharedMemory(String path, long size) {
|
||||||
|
|
||||||
|
try (FileChannel fc = (FileChannel)Files.newByteChannel(new File(path).toPath(),
|
||||||
|
EnumSet.of(
|
||||||
|
StandardOpenOption.CREATE,
|
||||||
|
StandardOpenOption.SPARSE,
|
||||||
|
StandardOpenOption.WRITE,
|
||||||
|
StandardOpenOption.READ))) {
|
||||||
|
|
||||||
|
return fc.map(FileChannel.MapMode.READ_WRITE, 0, size);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch( IOException ioe) {
|
||||||
|
throw new RuntimeException(ioe);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
package com.baeldung.sharedmem;
|
||||||
|
|
||||||
|
//import sun.misc.Unsafe;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
|
import sun.misc.Unsafe;
|
||||||
|
|
||||||
|
public class SpinLock {
|
||||||
|
private static final Unsafe unsafe;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
Field f = Unsafe.class.getDeclaredField("theUnsafe");
|
||||||
|
f.setAccessible(true);
|
||||||
|
unsafe = (Unsafe) f.get(null);
|
||||||
|
}
|
||||||
|
catch(NoSuchFieldException | IllegalAccessException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final long addr;
|
||||||
|
|
||||||
|
public SpinLock(long addr) {
|
||||||
|
this.addr = addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean tryLock(long maxWait) {
|
||||||
|
long deadline = System.currentTimeMillis() + maxWait;
|
||||||
|
while(System.currentTimeMillis() < deadline ) {
|
||||||
|
if ( unsafe.compareAndSwapInt(null,addr,0,1)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unlock() {
|
||||||
|
unsafe.putInt(addr,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user