@Override public void send(Append append) throws ConnectionFailedException { recentMessage.set(true); batchSizeTracker.recordAppend(append.getEventNumber(), append.getData().readableBytes()); Futures.getAndHandleExceptions(getChannel().writeAndFlush(append), ConnectionFailedException::new); }
/** * If there is too much data waiting throttle the producer by stopping consumption from the socket. * If there is room for more data, we resume consuming from the socket. */ private void pauseOrResumeReading() { int bytesWaiting; synchronized (lock) { bytesWaiting = waitingAppends.values() .stream() .mapToInt(a -> a.getData().readableBytes()) .sum(); } if (bytesWaiting > HIGH_WATER_MARK) { log.debug("Pausing writing from connection {}", connection); connection.pauseReading(); } if (bytesWaiting < LOW_WATER_MARK) { log.trace("Resuming writing from connection {}", connection); connection.resumeReading(); } }
toAppend[i] = a.getData(); last = a; eventCount += a.getEventCount();
private CompletableFuture<Void> storeAppend(Append append) { long lastEventNumber; synchronized (lock) { lastEventNumber = latestEventNumbers.get(Pair.of(append.getSegment(), append.getWriterId())); } List<AttributeUpdate> attributes = Arrays.asList( new AttributeUpdate(append.getWriterId(), AttributeUpdateType.ReplaceIfEquals, append.getEventNumber(), lastEventNumber), new AttributeUpdate(EVENT_COUNT, AttributeUpdateType.Accumulate, append.getEventCount())); ByteBuf buf = append.getData().asReadOnly(); byte[] bytes = new byte[buf.readableBytes()]; buf.readBytes(bytes); if (append.isConditional()) { return store.append(append.getSegment(), append.getExpectedLength(), bytes, attributes, TIMEOUT); } else { return store.append(append.getSegment(), bytes, attributes, TIMEOUT); } }
private void verify(List<Object> results, int numValues, int sizeOfEachValue) { int currentValue = -1; int currentCount = sizeOfEachValue; for (Object r : results) { Append append = (Append) r; assertEquals("Append split mid event", sizeOfEachValue, currentCount); while (append.getData().isReadable()) { if (currentCount == sizeOfEachValue) { assertEquals(EVENT.getCode(), append.getData().readInt()); assertEquals(sizeOfEachValue, append.getData().readInt()); currentCount = 0; currentValue++; } byte readByte = append.getData().readByte(); assertEquals((byte) currentValue, readByte); currentCount++; } assertEquals(currentValue, append.getEventNumber()); } assertEquals(numValues - 1, currentValue); assertEquals(currentCount, sizeOfEachValue); }
/** * If there isn't already an append outstanding against the store, write a new one. * Appends are opportunistically batched here. i.e. If many are waiting they are combined into a single append and * that is written. */ private void performNextWrite() { Append append = getNextAppend(); if (append == null) { return; } long traceId = LoggerHelpers.traceEnter(log, "storeAppend", append); Timer timer = new Timer(); storeAppend(append) .whenComplete((v, e) -> { handleAppendResult(append, e); LoggerHelpers.traceLeave(log, "storeAppend", traceId, v, e); if (e == null) { WRITE_STREAM_SEGMENT.reportSuccessEvent(timer.getElapsed()); } else { WRITE_STREAM_SEGMENT.reportFailEvent(timer.getElapsed()); } }) .whenComplete((v, e) -> append.getData().release()); }
@Override public void sendAsync(List<Append> appends, CompletedCallback callback) { recentMessage.set(true); Channel ch; try { ch = getChannel(); } catch (ConnectionFailedException e) { callback.complete(new ConnectionFailedException("Connection to " + connectionName + " is not established.")); return; } PromiseCombiner combiner = new PromiseCombiner(); for (Append append : appends) { batchSizeTracker.recordAppend(append.getEventNumber(), append.getData().readableBytes()); combiner.add(ch.write(append)); } ch.flush(); ChannelPromise promise = ch.newPromise(); promise.addListener(new GenericFutureListener<Future<? super Void>>() { @Override public void operationComplete(Future<? super Void> future) throws Exception { Throwable cause = future.cause(); callback.complete(cause == null ? null : new ConnectionFailedException(cause)); } }); combiner.finish(promise); }
private void testFlush(int size) throws Exception { @Cleanup("release") ByteBuf fakeNetwork = ByteBufAllocator.DEFAULT.buffer(); ArrayList<Object> received = setupAppend(streamName, writerId, fakeNetwork); append(streamName, writerId, size, 0, size, fakeNetwork); read(fakeNetwork, received); KeepAlive keepAlive = new KeepAlive(); encoder.encode(null, keepAlive, fakeNetwork); read(fakeNetwork, received); assertEquals(2, received.size()); Append one = (Append) received.get(0); assertEquals(size + TYPE_PLUS_LENGTH_SIZE, one.getData().readableBytes()); KeepAlive two = (KeepAlive) received.get(1); assertEquals(keepAlive, two); }
@Test public void testAppendAtBlockBound() throws Exception { int size = appendBlockSize; @Cleanup("release") ByteBuf fakeNetwork = ByteBufAllocator.DEFAULT.buffer(); ArrayList<Object> received = setupAppend(streamName, writerId, fakeNetwork); append(streamName, writerId, size, 1, size, fakeNetwork); read(fakeNetwork, received); assertEquals(1, received.size()); append(streamName, writerId, size + size / 2, 2, size / 2, fakeNetwork); read(fakeNetwork, received); assertEquals(1, received.size()); KeepAlive keepAlive = new KeepAlive(); encoder.encode(null, keepAlive, fakeNetwork); read(fakeNetwork, received); assertEquals(3, received.size()); Append one = (Append) received.get(0); Append two = (Append) received.get(1); assertEquals(size + TYPE_PLUS_LENGTH_SIZE, one.getData().readableBytes()); assertEquals(size / 2 + TYPE_PLUS_LENGTH_SIZE, two.getData().readableBytes()); KeepAlive three = (KeepAlive) received.get(2); assertEquals(keepAlive, three); }
ByteBuf data = append.getData().slice(); int msgSize = data.readableBytes();