All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.infinispan.server.resp.logging.AccessLoggerManager Maven / Gradle / Ivy

There is a newer version: 15.1.4.Final
Show newest version
package org.infinispan.server.resp.logging;

import java.util.List;
import java.util.concurrent.CompletionStage;
import java.util.function.IntConsumer;

import org.infinispan.commons.time.TimeService;
import org.infinispan.server.resp.RespCommand;
import org.infinispan.commons.util.concurrent.CompletionStages;

import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelProgressiveFuture;
import io.netty.channel.ChannelProgressiveFutureListener;
import io.netty.channel.ChannelProgressivePromise;

/**
 * Handle the access log.
 * 

* Keeps track of pending operations and pushes them to the access log. Some operations are not flushed directly * because of the pipelining, so the manager keeps them with {@link ChannelProgressivePromise}. Once the buffer is * flushed, the {@link ChannelProgressivePromise} advances the indexes and flushes the pending operations to the * access log. *

* The manager tracks data of only one active operation at a time. The current active operation is then flushed or * registered to do so later. This approach fits with the way we handle the commands on the * {@link org.infinispan.server.resp.RespHandler}. *

* Thread safety: This implementation is not thread-safe. It assumes all invocations come from the same * thread to track, register, and flush operations. * * @since 15.0 */ public class AccessLoggerManager implements IntConsumer { private final ChannelProgressivePromise promise; private final Tracker tracker; private long start; private long end; public AccessLoggerManager(ChannelHandlerContext ctx, TimeService timeService) { this.promise = ctx.newProgressivePromise(); this.tracker = new Tracker(ctx, timeService); } public void track(RespCommand req, List arguments) { // Unknown command. if (req == null) req = UnknownCommand.UNKNOWN_COMMAND; tracker.track(req, arguments); } public void flush(ChannelHandlerContext ctx, ChannelFuture future, CompletionStage pending) { assert ctx.channel().eventLoop().inEventLoop() : "Flush must happen from event loop"; if (end > start) { final long s = start; final long e = end; future.addListener(ignore -> { promise.tryProgress(s, e); }); start = end; } if (pending != null) logCompleted(future, pending); } public void register(CompletionStage res) { if (CompletionStages.isCompletedSuccessfully(res)) { registerFinishedOperation(null); return; } res.whenComplete((ignore, t) -> registerFinishedOperation(t)); } public void close() { promise.setSuccess(); } private void logCompleted(ChannelFuture future, CompletionStage pending) { if (CompletionStages.isCompletedSuccessfully(pending)) { AccessData data = tracker.done(null); if (data != null) data.log(future); return; } pending.whenComplete((ignore, t) -> { AccessData data = tracker.done(t); if (data != null) data.log(future); }); } private void registerFinishedOperation(Throwable t) { AccessData data = tracker.done(t); if (data == null) throw new IllegalStateException("No operation tracked!"); promise.addListener(new LogProgressiveListener(data, end++)); } @Override public void accept(int value) { // Bytes requested to buffer allocator. tracker.increaseBytesRequested(value); } private static class LogProgressiveListener implements ChannelProgressiveFutureListener { private final AccessData data; private final long offset; private LogProgressiveListener(AccessData data, long offset) { this.data = data; this.offset = offset; } @Override public void operationProgressed(ChannelProgressiveFuture future, long progress, long total) { if (offset >= progress && offset <= total) { data.log(future.channel().newSucceededFuture()); future.removeListener(this); } } @Override public void operationComplete(ChannelProgressiveFuture future) { data.log(future); } } private static final class UnknownCommand extends RespCommand { private static final UnknownCommand UNKNOWN_COMMAND = new UnknownCommand(); private UnknownCommand() { super("UNKNOWN_COMMAND", 0, 0, 0, 0); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy