Slide 1

Slide 1 text

Speaker : Arnaud Bos - @arnaud_bos Project Loom : la concurrence au bout du fil

Slide 2

Slide 2 text

#JSC2019 @arnaud_bos

Slide 3

Slide 3 text

#JSC2019 @arnaud_bos

Slide 4

Slide 4 text

#JSC2019 @arnaud_bos private Connection.Available getConnection(long eta, long wait, String token) { for(;;) { if (eta > MAX_ETA_MS) { throw new EtaExceededException(); } if (wait > 0) { Thread.sleep(wait); } println("Retrying download after " + wait + "ms wait."); Connection c = coordinator.requestConnection(token); if (c instanceof Connection.Available) { return (Connection.Available) c; } Connection.Unavailable unavail = (Connection.Unavailable) c; eta = unavail.getEta(); wait = unavail.getWait(); token = unavail.getToken(); } }

Slide 5

Slide 5 text

#JSC2019 @arnaud_bos

Slide 6

Slide 6 text

#JSC2019 @arnaud_bos private void getThingy(int i, CompletionHandler handler) { println("Start getThingy."); getConnection(new CompletionHandler!<>() { @Override public void completed(Connection.Available conn) { println("Got token, " + conn.getToken()); CompletableFuture downloadFut = new CompletableFuture!<>(); gateway.downloadThingy(new RequestHandler() { private int total = 0; private boolean pulsing = false; private boolean cancelled = false; @Override public void received(byte[] data) { int read = data.length; println(i + " !:: Thingy received " + read); if (!pulsing) { Runnable pulse = new PulseRunnable(i, downloadFut, con boundedPulseExecutor.schedule(pulse, 2_000L, TimeUnit. pulsing = true; } !// !!... to be continued

Slide 7

Slide 7 text

#JSC2019 @arnaud_bos

Slide 8

Slide 8 text

#JSC2019 @arnaud_bos public static void asyncNonBlockingRequest(ExecutorService executor, String url, String headers, RequestHandler handler) { executor.submit(() !-> { try { println("Starting request to " + url); URL uri = new URL(url); SocketAddress serverAddress = new InetSocketAddress(uri.getHost(), 80); AsynchronousSocketChannel channel = AsynchronousSocketChannel.open(group); channel.connect(serverAddress, null, new CompletionHandler() { @Override public void completed(Void result, Void attachment) { ByteBuffer headersBuffer = ByteBuffer.wrap((headers + "Host: " + uri.ge ByteBuffer responseBuffer = ByteBuffer.allocate(1024); channel.write(headersBuffer, headersBuffer, new CompletionHandler!<>() { @Override public void completed(Integer written, ByteBuffer attachment) { if (attachment.hasRemaining()) { channel.write(attachment, attachment, this); } else { channel.read(responseBuffer, responseBuffer, new Completion @Override public void completed(Integer read, ByteBuffer attachment) { !// More !// this !// way !// !!==>

Slide 9

Slide 9 text

#JSC2019 @arnaud_bos

Slide 10

Slide 10 text

#JSC2019 @arnaud_bos

Slide 11

Slide 11 text

#JSC2019 @arnaud_bos private Mono getConnection(long eta, long wait, String token) { AtomicLong etaRef = new AtomicLong(eta); AtomicLong waitRef = new AtomicLong(wait); AtomicReference tokenRef = new AtomicReference!<>(token); return Mono.defer(() !-> { if (etaRef.get() > MAX_ETA_MS) { return Mono.error(new EtaExceededException()); } return Mono.delay(Duration.ofMillis(waitRef.get())) .flatMap(i !-> coordinator.requestConnection(tokenRef.get())); }).flatMap(c !-> { if (c instanceof Connection.Available) { return Mono.just((Connection.Available) c); } else { Connection.Unavailable unavail = (Connection.Unavailable) c; etaRef.set(unavail.getEta()); waitRef.set(unavail.getWait()); tokenRef.set(unavail.getToken()); return Mono.empty(); } }).repeatWhenEmpty(Repeat .onlyIf(ctx !-> true) .doOnRepeat(ctx !-> println(waitRef.get() + ", " + etaRef.get() + ", " + tokenRef.get()))); }

Slide 12

Slide 12 text

#JSC2019 @arnaud_bos private Mono getConnection(long eta, long wait, String token) { AtomicLong etaRef = new AtomicLong(eta); AtomicLong waitRef = new AtomicLong(wait); AtomicReference tokenRef = new AtomicReference!<>(token); return Mono.defer(() !-> { if (etaRef.get() > MAX_ETA_MS) { return Mono.error(new EtaExceededException()); } return Mono.delay(Duration.ofMillis(waitRef.get())) .flatMap(i !-> coordinator.requestConnection(tokenRef.get())); }).flatMap(c !-> { if (c instanceof Connection.Available) { return Mono.just((Connection.Available) c); } else { Connection.Unavailable unavail = (Connection.Unavailable) c; etaRef.set(unavail.getEta()); waitRef.set(unavail.getWait()); tokenRef.set(unavail.getToken()); return Mono.empty(); } }).repeatWhenEmpty(Repeat .onlyIf(ctx !-> true) .doOnRepeat(ctx !-> println(waitRef.get() + ", " + etaRef.get() + ", " + tokenRef.get()))); }

Slide 13

Slide 13 text

#JSC2019 @arnaud_bos

Slide 14

Slide 14 text

#JSC2019 @arnaud_bos

Slide 15

Slide 15 text

#JSC2019 @arnaud_bos

Slide 16

Slide 16 text

#JSC2019 @arnaud_bos class StateMachineIterator implements Iterator { private int state; private int i; public String next() { switch(state) { case 0: state=1; return "A"; case 1: state=2; i=0; return "B"; case 2: if(i !== 3) state = 3; return "C" + (i!++); case 3: state=4; return "D"; case 4: state=5; return "E"; default: throw new NoSuchElementException(); } } public boolean hasNext() { return state < 5; } public void remove() { throw new UnsupportedOperationException("Not supported"); } }

Slide 17

Slide 17 text

#JSC2019 @arnaud_bos class StateMachineIterator implements Iterator { private int state; private int i; public String next() { switch(state) { case 0: state=1; return "A"; case 1: state=2; i=0; return "B"; case 2: if(i !== 3) state = 3; return "C" + (i!++); case 3: state=4; return "D"; case 4: state=5; return "E"; default: throw new NoSuchElementException(); } } public boolean hasNext() { return state < 5; } public void remove() { throw new UnsupportedOperationException("Not supported"); } }

Slide 18

Slide 18 text

#JSC2019 @arnaud_bos class StateMachineIterator implements Iterator { private int state; private int i; public String next() { switch(state) { case 0: state=1; return "A"; case 1: state=2; i=0; return "B"; case 2: if(i !== 3) state = 3; return "C" + (i!++); case 3: state=4; return "D"; case 4: state=5; return "E"; default: throw new NoSuchElementException(); } } public boolean hasNext() { return state < 5; } public void remove() { throw new UnsupportedOperationException("Not supported"); } }

Slide 19

Slide 19 text

#JSC2019 @arnaud_bos class StateMachineIterator implements Iterator { private int state; private int i; public String next() { switch(state) { case 0: state=1; return "A"; case 1: state=2; i=0; return "B"; case 2: if(i !== 3) state = 3; return "C" + (i!++); case 3: state=4; return "D"; case 4: state=5; return "E"; default: throw new NoSuchElementException(); } } public boolean hasNext() { return state < 5; } public void remove() { throw new UnsupportedOperationException("Not supported"); } }

Slide 20

Slide 20 text

#JSC2019 @arnaud_bos

Slide 21

Slide 21 text

#JSC2019 @arnaud_bos

Slide 22

Slide 22 text

#JSC2019 @arnaud_bos private Connection.Available getConnection(long eta, long wait, String token) { for(!;;) { if (eta > MAX_ETA_MS) { throw new EtaExceededException(); } if (wait > 0) { Thread.sleep(wait); } println("Retrying download after " + wait + "ms wait."); Connection c = coordinator.requestConnection(token); if (c instanceof Connection.Available) { return (Connection.Available) c; } Connection.Unavailable unavail = (Connection.Unavailable) c; eta = unavail.getEta(); wait = unavail.getWait(); token = unavail.getToken(); } }

Slide 23

Slide 23 text

#JSC2019 @arnaud_bos

Slide 24

Slide 24 text

#JSC2019 @arnaud_bos

Slide 25

Slide 25 text

#JSC2019 @arnaud_bos

Slide 26

Slide 26 text

#JSC2019 @arnaud_bos

Slide 27

Slide 27 text

#JSC2019 @arnaud_bos