[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
|
@ -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 ..
|
|
@ -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…
Reference in New Issue