Package com.taobao.metamorphosis.client.consumer

Source Code of com.taobao.metamorphosis.client.consumer.RecoverStorageManager

/*
* (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.consumer;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

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

import com.taobao.common.store.Store;
import com.taobao.gecko.core.util.ConcurrentHashSet;
import com.taobao.metamorphosis.Message;
import com.taobao.metamorphosis.client.MetaClientConfig;
import com.taobao.metamorphosis.client.extension.storage.MessageStore;
import com.taobao.metamorphosis.exception.GetRecoverStorageErrorException;
import com.taobao.metamorphosis.utils.NamedThreadFactory;


/**
* Recover�洢������
*
* @author boyan
* @Date 2011-5-12
*
*/
public class RecoverStorageManager extends AbstractRecoverManager {
    private static final String SPLIT = "@";
    private final ConcurrentHashMap<String/* topic */, FutureTask<Store>> topicStoreMap =
            new ConcurrentHashMap<String, FutureTask<Store>>();
    static final Log log = LogFactory.getLog(RecoverStorageManager.class);
    public static final String META_RECOVER_STORE_PATH = System.getProperty("meta.recover.path",
        System.getProperty("user.home") + File.separator + ".meta_recover");

    private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();

    private final SubscribeInfoManager subscribeInfoManager;

    private final ThreadPoolExecutor threadPoolExecutor;

    private final AtomicLong count = new AtomicLong(0);

    private boolean started;


    public RecoverStorageManager(final MetaClientConfig metaClientConfig,
            final SubscribeInfoManager subscribeInfoManager) {
        super();

        // ǿ��ʹ��caller run����
        this.threadPoolExecutor =
                new ThreadPoolExecutor(metaClientConfig.getRecoverThreadCount(),
                    metaClientConfig.getRecoverThreadCount(), 60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(
                            100), new NamedThreadFactory("Recover-thread"), new ThreadPoolExecutor.CallerRunsPolicy());
        // this.startRecover(metaClientConfig);
        this.makeDataDir();
        this.subscribeInfoManager = subscribeInfoManager;
        this.loadStores();
    }


    @Override
    public synchronized boolean isStarted() {
        return this.started;
    }


    @Override
    public synchronized void start(final MetaClientConfig metaClientConfig) {
        if (this.started) {
            return;
        }
        this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                RecoverStorageManager.this.recover();

            }
        }, 5000, metaClientConfig.getRecoverMessageIntervalInMills(), TimeUnit.MILLISECONDS);
        this.started = true;
    }


    private void loadStores() {
        final File dataPath = new File(META_RECOVER_STORE_PATH);
        final File[] files = dataPath.listFiles();
        for (final File subFile : files) {
            if (subFile.isDirectory()) {

                final String name = subFile.getName();
                final String[] tmps = name.split(SPLIT);
                if (tmps.length != 2) {
                    continue;
                }
                log.info("����recover storage " + name + " ...");
                this.getOrCreateStore(tmps[0], tmps[1]);
            }
        }
    }


    private void makeDataDir() {
        final File file = new File(META_RECOVER_STORE_PATH);
        if (!file.exists()) {
            file.mkdir();
        }
    }


    private void recover() {
        for (final Map.Entry<String, FutureTask<Store>> entry : this.topicStoreMap.entrySet()) {
            this.threadPoolExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    final String name = entry.getKey();
                    final String[] tmps = name.split(SPLIT);
                    final String topic = tmps[0];
                    final String group = tmps[1];
                    final FutureTask<Store> task = entry.getValue();
                    final Store store = RecoverStorageManager.this.getStore(topic, task);
                    try {
                        final MessageListener listener =
                                RecoverStorageManager.this.subscribeInfoManager.getMessageListener(topic, group);
                        final Iterator<byte[]> it = store.iterator();
                        int count = 0;
                        while (it.hasNext()) {
                            final byte[] key = it.next();
                            final Message msg =
                                    (Message) RecoverStorageManager.this.deserializer.decodeObject(store.get(key));
                            if (msg != null) {
                                RecoverStorageManager.this.receiveMessage(store, key, msg, listener);
                            }
                            count++;
                        }
                        log.info("Recover topic=" + topic + "�ָ���Ϣ" + count + "��");
                    }
                    catch (InterruptedException e) {
                        // receive messages is interrupted,we have to interrupt
                        // all executors threads
                        if (Thread.currentThread().isInterrupted()) {
                            for (Thread thread : RecoverStorageManager.this.executorThreads) {
                                thread.interrupt();
                            }
                        }
                    }
                    catch (final Exception e) {
                        log.error("Recover message failed,topic=" + topic, e);
                    }
                }
            });

        }
    }

    boolean wasFirst = true;

    private final ConcurrentHashSet<Thread> executorThreads = new ConcurrentHashSet<Thread>();


    private void receiveMessage(final Store store, final byte[] key, final Message msg,
            final MessageListener messageListener) throws InterruptedException {
        if (messageListener == null) {
            // throw new
            // IllegalStateException("messageListenerΪnull,�����������߻�δ����,����ǵ�һ�α�������û�����������");
            if (this.wasFirst) {
                log.warn("messageListenerΪnull,�����������߻�δ����");
                this.wasFirst = false;
            }
            return;
        }
        if (messageListener.getExecutor() != null) {
            try {
                messageListener.getExecutor().execute(new Runnable() {

                    @Override
                    public void run() {
                        Thread currentThread = Thread.currentThread();
                        RecoverStorageManager.this.executorThreads.add(currentThread);
                        try {
                            try {
                                RecoverStorageManager.this.notifyListener(store, key, msg, messageListener);
                            }
                            catch (InterruptedException e) {
                                // Receive messages is interrrupted.
                            }
                        }
                        finally {
                            RecoverStorageManager.this.executorThreads.remove(currentThread);
                        }
                    }

                });
            }
            catch (final RejectedExecutionException e) {

            }
        }
        else {
            this.notifyListener(store, key, msg, messageListener);
        }
    }


    private void notifyListener(final Store store, final byte[] key, final Message msg,
            final MessageListener messageListener) throws InterruptedException {
        messageListener.recieveMessages(msg);
        try {
            store.remove(key);
        }
        catch (final IOException e) {
            log.error("Remove message failed", e);
        }
    }


    @Override
    public void shutdown() {
        for (final Map.Entry<String, FutureTask<Store>> entry : this.topicStoreMap.entrySet()) {
            final String name = entry.getKey();
            final String[] tmps = name.split(SPLIT);
            final String topic = tmps[0];
            final FutureTask<Store> task = entry.getValue();
            final Store store = this.getStore(topic, task);
            try {
                store.close();
            }
            catch (final IOException e) {
                // ignore
            }
        }
        this.threadPoolExecutor.shutdown();
        for (Thread thread : this.executorThreads) {
            thread.interrupt();
        }
        this.scheduledExecutorService.shutdown();
    }


    @Override
    public void append(final String group, final Message message) throws IOException {
        final Store store = this.getOrCreateStore(message.getTopic(), group);
        long key = message.getId();
        IOException error = null;
        for (int i = 0; i < 5; i++) {
            try {
                final ByteBuffer buf = ByteBuffer.allocate(16);
                buf.putLong(key);
                store.add(buf.array(), this.serializer.encodeObject(message));
                return;
            }
            catch (final IOException e) {
                final String msg = e.getMessage();
                // key�ظ�
                if (msg.contains("�ظ�")) {
                    error = e;
                    log.warn("д��recover store����,key=" + key + "," + e.getMessage() + ",retry...");
                    key += this.count.incrementAndGet();
                }
                else {
                    throw e;
                }
            }
        }

        if (error != null) {
            throw error;
        }

    }


    public Store getOrCreateStore(final String topic, final String group) {
        final String name = this.generateKey(topic, group);
        FutureTask<Store> task = this.topicStoreMap.get(name);
        if (task != null) {
            return this.getStore(topic, task);
        }
        else {
            task = new FutureTask<Store>(new Callable<Store>() {

                @Override
                public Store call() throws Exception {
                    final File file = new File(META_RECOVER_STORE_PATH + File.separator + name);
                    if (!file.exists()) {
                        file.mkdir();
                    }
                    return new MessageStore(META_RECOVER_STORE_PATH + File.separator + name, name);
                }

            });
            FutureTask<Store> existsTask = this.topicStoreMap.putIfAbsent(name, task);
            if (existsTask == null) {
                task.run();
                existsTask = task;
            }
            return this.getStore(name, existsTask);
        }

    }


    private String generateKey(final String topic, final String group) {
        return topic + SPLIT + group;
    }


    private Store getStore(final String name, final FutureTask<Store> task) {
        try {
            return task.get();
        }
        catch (final Throwable t) {
            log.error("��ȡname=" + name + "��Ӧ��storeʧ��", t);
            throw new GetRecoverStorageErrorException("��ȡtopic=" + name + "��Ӧ��storeʧ��", t);
        }

    }
}
TOP

Related Classes of com.taobao.metamorphosis.client.consumer.RecoverStorageManager

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.