Package com.taobao.metamorphosis.client.extension.producer

Source Code of com.taobao.metamorphosis.client.extension.producer.AsyncMetaMessageProducer

/*
* (C) 2007-2012 Alibaba Group Holding Limited.
*
* Licensed 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.
* Authors:
*   wuhua <wq163@163.com> , boyan <killme2008@gmail.com>
*/
package com.taobao.metamorphosis.client.extension.producer;

import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.taobao.gecko.core.command.ResponseCommand;
import com.taobao.gecko.core.command.ResponseStatus;
import com.taobao.gecko.core.command.kernel.BooleanAckCommand;
import com.taobao.gecko.service.Connection;
import com.taobao.gecko.service.SingleRequestCallBackListener;
import com.taobao.gecko.service.exception.NotifyRemotingException;
import com.taobao.metamorphosis.Message;
import com.taobao.metamorphosis.client.MetaMessageSessionFactory;
import com.taobao.metamorphosis.client.RemotingClientWrapper;
import com.taobao.metamorphosis.client.extension.producer.MessageRecoverManager.MessageRecoverer;
import com.taobao.metamorphosis.client.producer.PartitionSelector;
import com.taobao.metamorphosis.client.producer.ProducerZooKeeper;
import com.taobao.metamorphosis.client.producer.SimpleMessageProducer;
import com.taobao.metamorphosis.cluster.Partition;
import com.taobao.metamorphosis.exception.InvalidMessageException;
import com.taobao.metamorphosis.exception.MetaClientException;
import com.taobao.metamorphosis.network.BooleanCommand;
import com.taobao.metamorphosis.network.HttpStatus;
import com.taobao.metamorphosis.network.PutCommand;


/**
* <pre>
* �첽��������Ϣ����������������ʵ��.
*
* ʹ�ó���:
*      ���ڷ��Ϳɿ���Ҫ����ô��,��Ҫ����߷���Ч�ʺͽ��Ͷ�����Ӧ�õ�Ӱ�죬�������Ӧ�õ��ȶ���.
*      ����,�ռ���־���û���Ϊ��Ϣ�ȳ���.
* ע��:
*      ������Ϣ�󷵻صĽ���в�����׼ȷ��messageId��offset,��Щֵ����-1
*
* @author �޻�
* @since 2011-10-21 ����1:42:55
* </pre>
*/

public class AsyncMetaMessageProducer extends SimpleMessageProducer implements AsyncMessageProducer, MessageRecoverer {
    private static final Log log = LogFactory.getLog(AsyncMetaMessageProducer.class);
    private static final int DEFAULT_PERMITS = 20000;

    private final SlidingWindow slidingWindow;

    private IgnoreMessageProcessor ignoreMessageProcessor;


    public AsyncMetaMessageProducer(final MetaMessageSessionFactory messageSessionFactory,
            final RemotingClientWrapper remotingClient, final PartitionSelector partitionSelector,
            final ProducerZooKeeper producerZooKeeper, final String sessionId, final int slidingWindowSize0,
            final IgnoreMessageProcessor processor) {

        super(messageSessionFactory, remotingClient, partitionSelector, producerZooKeeper, sessionId);
        this.slidingWindow = new SlidingWindow(slidingWindowSize0 > 0 ? slidingWindowSize0 : DEFAULT_PERMITS);
        this.ignoreMessageProcessor =
                processor != null ? processor : new AsyncIgnoreMessageProcessor(
                    messageSessionFactory.getMetaClientConfig(), this);
    }


    /*
     * (non-Javadoc)
     *
     * @see
     * com.taobao.metamorphosis.client.extension.producer.AsyncMessageProducer
     * #asyncSendMessage(com.taobao.metamorphosis.Message)
     */
    @Override
    public void asyncSendMessage(final Message message) {
        this.asyncSendMessage(message, DEFAULT_OP_TIMEOUT, TimeUnit.MILLISECONDS);
    }


    /*
     * (non-Javadoc)
     *
     * @see
     * com.taobao.metamorphosis.client.extension.producer.AsyncMessageProducer
     * #asyncSendMessage(com.taobao.metamorphosis.Message, long,
     * java.util.concurrent.TimeUnit)
     */
    @Override
    public void asyncSendMessage(final Message message, final long timeout, final TimeUnit unit) {
        try {
            super.sendMessage(message, timeout, unit);
        }
        catch (final IllegalStateException e) {
            // ������producer�ѹر�
            log.warn(e);
        }
        catch (final InvalidMessageException e) {
            // �Ƿ�����Ϣ,������Ϣֱ���ӵ�,���ڱ��ػ���Զ��recover����ȥ
            log.warn(e);
        }
        catch (final MetaClientException e) {
            // ������ʧ�ܵ���Ϣ
            if (log.isDebugEnabled()) {
                log.debug("save to local strage,and waitting for recover. cause:" + e.getMessage());
            }
            this.handleSendFailMessage(message);
        }
        catch (final InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        catch (final Throwable e) {
            // ����û��Ԥ�ϵ������
            if (log.isDebugEnabled()) {
                log.debug("save to local strage,and waitting for recover. cause:", e);
            }
            this.handleSendFailMessage(message);
        }
    }


    /*
     * (non-Javadoc)
     *
     * @see
     * com.taobao.metamorphosis.client.extension.producer.AsyncMessageProducer
     * #setIgnoreMessageProcessor
     * (com.taobao.metamorphosis.client.extension.producer
     * .AsyncMessageProducer.IgnoreMessageProcessor)
     */
    @Override
    public void setIgnoreMessageProcessor(final IgnoreMessageProcessor ignoreMessageProcessor) {
        this.ignoreMessageProcessor = ignoreMessageProcessor;
    }


    @Override
    protected BooleanCommand invokeToGroup(final String serverUrl, final Partition partition,
            final PutCommand putCommand, final Message message, final long timeout, final TimeUnit unit)
            throws InterruptedException, TimeoutException, NotifyRemotingException {

        try {
            return this.trySend(serverUrl, putCommand, timeout, unit);
        }
        catch (final MetaMessageOverflowException e) {
            if (log.isDebugEnabled()) {
                log.debug("save to local strage,and waitting for recover. cause:" + e.getMessage());
            }
            return this.processOverMessage(partition, putCommand, message, e);
        }

    }


    // ���ϲ�����������,����������ݰ����remoting�����OOM
    private BooleanCommand trySend(final String serverUrl, final PutCommand putCommand, final long timeout,
            final TimeUnit unit) throws NotifyRemotingException, InterruptedException {
        final int dataLength = putCommand.getData() != null ? putCommand.getData().length : 0;
        if (this.slidingWindow.tryAcquireByLength(dataLength)) {// , timeout,
                                                                // unit
            try {
                super.remotingClient.sendToGroup(serverUrl, putCommand, new MessageSendCallBackListener(putCommand),
                    timeout, unit);
                return new BooleanCommand(HttpStatus.Success, "-1 " + putCommand.getPartition()
                        + " -1", putCommand.getOpaque());
            }
            catch (final NotifyRemotingException e) {
                this.slidingWindow.releaseByLenth(dataLength);
                if (e.getMessage().contains("������������") || e.getMessage().contains("������������CallBack����")) {
                    throw new MetaMessageOverflowException(e);
                }
                else {
                    throw e;
                }
            }
        }
        else {
            throw new MetaMessageOverflowException("������Ϣ���������������ڵ�λ������" + this.slidingWindow.getWindowsSize());
        }
    }


    private BooleanCommand processOverMessage(final Partition partition, final PutCommand putCommand,
            final Message message, final MetaMessageOverflowException e2) throws MetaMessageOverflowException {
        if (this.ignoreMessageProcessor != null) {
            // ���ܴ��������������سɹ�
            this.handleSendFailMessage(message);
            return new BooleanCommand(HttpStatus.Success, "-1 " + putCommand.getPartition()
                    + " -1", putCommand.getOpaque());
        }
        else {
            throw e2;
        }
    }


    private void handleSendFailMessage(final Message message) {
        try {
            this.ignoreMessageProcessor.handle(message);
        }
        catch (final Exception e1) {
            log.warn(e1);
        }
    }

    /**
     * ��ʾ��Ϣ�������ص��쳣
     *
     * @author wuhua
     *
     */
    public static class MetaMessageOverflowException extends NotifyRemotingException {

        private static final long serialVersionUID = -1842231102008256662L;


        public MetaMessageOverflowException(final String string) {
            super(string);
        }


        public MetaMessageOverflowException(final Throwable e) {
            super(e);
        }

    }

    private class MessageSendCallBackListener implements SingleRequestCallBackListener {

        int dataLenth;
        AtomicBoolean released = new AtomicBoolean(false);


        MessageSendCallBackListener(final PutCommand putCommand) {
            final byte[] data = putCommand.getData();
            this.dataLenth = data != null ? data.length : 0;
        }


        @Override
        public void onResponse(final ResponseCommand responseCommand, final Connection conn) {
            this.release();

            if (responseCommand.getResponseStatus() != ResponseStatus.NO_ERROR) {
                final StringBuilder sb = new StringBuilder();
                sb.append("onResponse. Status:").append(responseCommand.getResponseStatus());
                if (responseCommand instanceof BooleanCommand) {
                    sb.append(",Code:").append(((BooleanCommand) responseCommand).getCode());
                }
                if (responseCommand instanceof BooleanAckCommand) {
                    sb.append(",ErrorMsg:").append(((BooleanAckCommand) responseCommand).getErrorMsg());
                    sb.append(",ResponseHost:").append(((BooleanAckCommand) responseCommand).getResponseHost());
                }
                log.warn(sb.toString());
            }
        }


        @Override
        public void onException(final Exception e) {
            this.release();
            log.warn(e);
        }


        private void release() {
            if (this.released.compareAndSet(false, true)) {
                AsyncMetaMessageProducer.this.slidingWindow.releaseByLenth(this.dataLenth);
            }
        }


        @Override
        public ThreadPoolExecutor getExecutor() {
            return null;
        }

    }


    @Override
    public void handle(final Message msg) throws Exception {
        this.asyncSendMessage(msg);
    }


    // for test
    IgnoreMessageProcessor getIgnoreMessageProcessor() {
        return ignoreMessageProcessor;
    }

}
TOP

Related Classes of com.taobao.metamorphosis.client.extension.producer.AsyncMetaMessageProducer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.