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

org.finos.legend.engine.postgres.DelayableWriteChannel Maven / Gradle / Ivy

There is a newer version: 4.66.0
Show newest version
/*
 * Licensed to Crate.io GmbH ("Crate") under one or more contributor
 * license agreements.  See the NOTICE file distributed with this work for
 * additional information regarding copyright ownership.  Crate licenses
 * this file to you under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the specific language governing permissions and limitations
 * under the License.
 *
 * However, if you have executed another commercial license agreement
 * with Crate these terms will supersede the license and you may use the
 * software solely pursuant to the terms of the relevant commercial agreement.
 */

package org.finos.legend.engine.postgres;

import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelConfig;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelId;
import io.netty.channel.ChannelMetadata;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelProgressivePromise;
import io.netty.channel.ChannelPromise;
import io.netty.channel.EventLoop;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import io.netty.util.ReferenceCountUtil;
import java.net.SocketAddress;
import java.util.ArrayDeque;
import java.util.concurrent.atomic.AtomicReference;

/**
 * Channel implementation that allows to delay writes with `blockWritesUntil`
 **/
public class DelayableWriteChannel implements Channel
{

    private final Channel delegate;
    private final AtomicReference delay = new AtomicReference<>(null);

    public DelayableWriteChannel(Channel channel)
    {
        this.delegate = channel;
        channel.closeFuture().addListener(f ->
        {
            discardDelayedWrites();
        });
    }

    @Override
    public  Attribute attr(AttributeKey key)
    {
        return delegate.attr(key);
    }

    @Override
    public  boolean hasAttr(AttributeKey key)
    {
        return delegate.hasAttr(key);
    }

    @Override
    public ChannelFuture bind(SocketAddress localAddress)
    {
        return delegate.bind(localAddress);
    }

    @Override
    public ChannelFuture connect(SocketAddress remoteAddress)
    {
        return delegate.connect(remoteAddress);
    }

    @Override
    public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress)
    {
        return delegate.connect(remoteAddress, localAddress);
    }

    @Override
    public ChannelFuture disconnect()
    {
        return delegate.disconnect();
    }

    @Override
    public ChannelFuture close()
    {
        return delegate.close();
    }

    @Override
    public ChannelFuture deregister()
    {
        return delegate.deregister();
    }

    @Override
    public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise)
    {
        return delegate.bind(localAddress, promise);
    }

    @Override
    public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise)
    {
        return delegate.connect(remoteAddress, promise);
    }

    @Override
    public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress,
                                 ChannelPromise promise)
    {
        return delegate.connect(remoteAddress, localAddress, promise);
    }

    @Override
    public ChannelFuture disconnect(ChannelPromise promise)
    {
        return delegate.disconnect(promise);
    }

    @Override
    public ChannelFuture close(ChannelPromise promise)
    {
        return delegate.close(promise);
    }

    @Override
    public ChannelFuture deregister(ChannelPromise promise)
    {
        return delegate.deregister(promise);
    }

    @Override
    public ChannelFuture write(Object msg)
    {
        return this.write(msg, newPromise());
    }

    @Override
    public ChannelFuture write(Object msg, ChannelPromise promise)
    {
        DelayedWrites currentDelay = delay.get();
        if (currentDelay != null)
        {
            currentDelay.add(msg, () -> delegate.write(msg, promise));
            return promise;
        }
        return delegate.write(msg, promise);
    }

    @Override
    public ChannelFuture writeAndFlush(Object msg, ChannelPromise promise)
    {
        DelayedWrites currentDelay = delay.get();
        if (currentDelay != null)
        {
            currentDelay.add(msg, () -> delegate.writeAndFlush(msg, promise));
            return promise;
        }
        return delegate.writeAndFlush(msg, promise);
    }

    @Override
    public ChannelFuture writeAndFlush(Object msg)
    {
        return this.writeAndFlush(msg, newPromise());
    }

    @Override
    public ChannelPromise newPromise()
    {
        return delegate.newPromise();
    }

    @Override
    public ChannelProgressivePromise newProgressivePromise()
    {
        return delegate.newProgressivePromise();
    }

    @Override
    public ChannelFuture newSucceededFuture()
    {
        return delegate.newSucceededFuture();
    }

    @Override
    public ChannelFuture newFailedFuture(Throwable cause)
    {
        return delegate.newFailedFuture(cause);
    }

    @Override
    public ChannelPromise voidPromise()
    {
        return delegate.voidPromise();
    }

    @Override
    public int compareTo(Channel o)
    {
        return delegate.compareTo(o);
    }

    @Override
    public ChannelId id()
    {
        return delegate.id();
    }

    @Override
    public EventLoop eventLoop()
    {
        return delegate.eventLoop();
    }

    @Override
    public Channel parent()
    {
        return delegate.parent();
    }

    @Override
    public ChannelConfig config()
    {
        return delegate.config();
    }

    @Override
    public boolean isOpen()
    {
        return delegate.isOpen();
    }

    @Override
    public boolean isRegistered()
    {
        return delegate.isRegistered();
    }

    @Override
    public boolean isActive()
    {
        return delegate.isActive();
    }

    @Override
    public ChannelMetadata metadata()
    {
        return delegate.metadata();
    }

    @Override
    public SocketAddress localAddress()
    {
        return delegate.localAddress();
    }

    @Override
    public SocketAddress remoteAddress()
    {
        return delegate.remoteAddress();
    }

    @Override
    public ChannelFuture closeFuture()
    {
        return delegate.closeFuture();
    }

    @Override
    public boolean isWritable()
    {
        return delegate.isWritable();
    }

    @Override
    public long bytesBeforeUnwritable()
    {
        return delegate.bytesBeforeUnwritable();
    }

    @Override
    public long bytesBeforeWritable()
    {
        return delegate.bytesBeforeWritable();
    }

    @Override
    public Unsafe unsafe()
    {
        return delegate.unsafe();
    }

    @Override
    public ChannelPipeline pipeline()
    {
        return delegate.pipeline();
    }

    @Override
    public ByteBufAllocator alloc()
    {
        return delegate.alloc();
    }

    @Override
    public Channel read()
    {
        return delegate.read();
    }

    @Override
    public Channel flush()
    {
        return delegate.flush();
    }

    public Channel bypassDelay()
    {
        return delegate;
    }

    public void discardDelayedWrites()
    {
        DelayedWrites currentDelay = delay.getAndSet(null);
        if (currentDelay != null)
        {
            DelayedWrites parent = currentDelay.parent;
            while (parent != null)
            {
                parent.discard();
                parent = parent.parent;
            }
            currentDelay.discard();
        }
    }

    public void writePendingMessages(DelayedWrites delayedWrites)
    {
        delay.compareAndSet(delayedWrites, null);
        delayedWrites.writeDelayed();
    }

    public void writePendingMessages()
    {
        DelayedWrites currentDelay = delay.getAndSet(null);
        if (currentDelay != null)
        {
            DelayedWrites parent = currentDelay.parent;
            while (parent != null)
            {
                parent.writeDelayed();
                parent = parent.parent;
            }
            currentDelay.writeDelayed();
        }
    }

    public DelayedWrites delayWrites()
    {
        return delay.updateAndGet(DelayedWrites::new);
    }

    static class DelayedMsg
    {

        final Runnable runnable;
        final Object msg;

        public DelayedMsg(Object msg, Runnable runnable)
        {
            this.runnable = runnable;
            this.msg = msg;
        }
    }

    static class DelayedWrites
    {

        private final ArrayDeque delayed = new ArrayDeque<>();
        private final DelayedWrites parent;

        public DelayedWrites(DelayedWrites parent)
        {
            this.parent = parent;
        }

        public void discard()
        {
            DelayedMsg delayedMsg;
            synchronized (delayed)
            {
                while ((delayedMsg = delayed.poll()) != null)
                {
                    ReferenceCountUtil.safeRelease(delayedMsg.msg);
                }
            }
        }

        public void add(Object msg, Runnable runnable)
        {
            synchronized (delayed)
            {
                delayed.add(new DelayedMsg(msg, runnable));
            }
        }

        private void writeDelayed()
        {
            DelayedMsg delayedMsg;
            synchronized (delayed)
            {
                while ((delayedMsg = delayed.poll()) != null)
                {
                    delayedMsg.runnable.run();
                }
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy