Package com.asakusafw.bulkloader.cache

Source Code of com.asakusafw.bulkloader.cache.GetCacheInfoLocal

/**
* Copyright 2011-2014 Asakusa Framework Team.
*
* 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.
*/
package com.asakusafw.bulkloader.cache;

import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;

import com.asakusafw.bulkloader.bean.ImportBean;
import com.asakusafw.bulkloader.bean.ImportTargetTableBean;
import com.asakusafw.bulkloader.common.ConfigurationLoader;
import com.asakusafw.bulkloader.common.Constants;
import com.asakusafw.bulkloader.exception.BulkLoaderSystemException;
import com.asakusafw.bulkloader.log.Log;
import com.asakusafw.bulkloader.transfer.FileList;
import com.asakusafw.bulkloader.transfer.FileListProvider;
import com.asakusafw.bulkloader.transfer.FileProtocol;
import com.asakusafw.bulkloader.transfer.OpenSshFileListProvider;
import com.asakusafw.runtime.core.context.RuntimeContext;
import com.asakusafw.thundergate.runtime.cache.CacheInfo;

/**
* Retrieves {@link CacheInfo}.
* @since 0.2.3
* @see GetCacheInfoRemote
*/
public class GetCacheInfoLocal {

    static final Log LOG = new Log(GetCacheInfoLocal.class);

    /*
     * This field should not be static because of saving system resources on testing.
     */
    private final ExecutorService executor = Executors.newCachedThreadPool(new ThreadFactory() {
        final AtomicInteger counter = new AtomicInteger();
        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r);
            t.setDaemon(true);
            t.setName(String.format("get-cache-info-%d", counter.incrementAndGet()));
            return t;
        }
    });

    /**
     * Retrieves {@link CacheInfo} from already deployed cache directories.
     * This will return the pairs - {@link ImportTargetTableBean#getDfsFilePath()} and corresponded cache information.
     * If a target table does not use cache feature or related cache did not exist, there will be not in the result.
     * @param bean importer information
     * @return the retrieved information
     * @throws BulkLoaderSystemException if failed to obtain cache information by system exception
     * @throws IllegalArgumentException if some parameters were {@code null}
     */
    public Map<String, CacheInfo> get(ImportBean bean) throws BulkLoaderSystemException {
        if (bean == null) {
            throw new IllegalArgumentException("bean must not be null"); //$NON-NLS-1$
        }
        if (hasCacheUser(bean) == false) {
            return Collections.emptyMap();
        }
        LOG.info("TG-IMPORTER-12001",
                bean.getTargetName(),
                bean.getBatchId(),
                bean.getJobflowId(),
                bean.getExecutionId());
        FileListProvider provider = null;
        try {
            provider = openFileList(
                    bean.getTargetName(), bean.getBatchId(), bean.getJobflowId(), bean.getExecutionId());
            Future<Void> upstream = submitUpstream(bean, provider);
            Future<Map<String, CacheInfo>> downstream = submitDownstream(provider);
            Map<String, CacheInfo> result;
            while (true) {
                try {
                    if (upstream.isDone()) {
                        upstream.get();
                    }
                    result = downstream.get(1, TimeUnit.SECONDS);
                    break;
                } catch (TimeoutException e) {
                    // will retry
                } catch (CancellationException e) {
                    upstream.cancel(true);
                    downstream.cancel(true);
                    throw new IOException("Collecting cache information was cancelled", e);
                } catch (ExecutionException e) {
                    upstream.cancel(true);
                    downstream.cancel(true);
                    Throwable cause = e.getCause();
                    if (cause instanceof Error) {
                        throw (Error) cause;
                    } else if (cause instanceof RuntimeException) {
                        throw (RuntimeException) cause;
                    } else if (cause instanceof IOException) {
                        throw (IOException) cause;
                    } else {
                        throw new AssertionError(cause);
                    }
                }
            }
            provider.waitForComplete();
            LOG.info("TG-IMPORTER-12003",
                    bean.getTargetName(),
                    bean.getBatchId(),
                    bean.getJobflowId(),
                    bean.getExecutionId(),
                    result.size());
            return result;
        } catch (IOException e) {
            throw new BulkLoaderSystemException(e, getClass(), "TG-IMPORTER-12004",
                    bean.getTargetName(),
                    bean.getBatchId(),
                    bean.getJobflowId(),
                    bean.getExecutionId());
        } catch (InterruptedException e) {
            throw new BulkLoaderSystemException(e, getClass(), "TG-IMPORTER-12004",
                    bean.getTargetName(),
                    bean.getBatchId(),
                    bean.getJobflowId(),
                    bean.getExecutionId());
        } finally {
            if (provider != null) {
                try {
                    provider.close();
                } catch (IOException ignored) {
                    ignored.printStackTrace();
                }
            }
        }
    }

    private boolean hasCacheUser(ImportBean bean) {
        assert bean != null;
        for (String tableName : bean.getImportTargetTableList()) {
            ImportTargetTableBean table = bean.getTargetTable(tableName);
            if (table.getCacheId() != null) {
                return true;
            }
        }
        return false;
    }

    private Future<Void> submitUpstream(final ImportBean bean, final FileListProvider provider) {
        return executor.submit(new Callable<Void>() {
            @Override
            public Void call() throws IOException {
                FileList.Writer writer = provider.openWriter(false);
                try {
                    for (String tableName : bean.getImportTargetTableList()) {
                        ImportTargetTableBean table = bean.getTargetTable(tableName);
                        if (table.getCacheId() == null || table.getDfsFilePath() == null) {
                            continue;
                        }
                        FileProtocol protocol = new FileProtocol(
                                FileProtocol.Kind.GET_CACHE_INFO,
                                table.getDfsFilePath(),
                                null);

                        // send only header
                        writer.openNext(protocol).close();
                    }
                } finally {
                    writer.close();
                }
                return null;
            }
        });
    }

    private Future<Map<String, CacheInfo>> submitDownstream(final FileListProvider provider) {
        assert provider != null;
        return executor.submit(new Callable<Map<String, CacheInfo>>() {
            @Override
            public Map<String, CacheInfo> call() throws IOException {
                Map<String, CacheInfo> results = new HashMap<String, CacheInfo>();
                FileList.Reader reader = provider.openReader();
                try {
                    while (reader.next()) {
                        FileProtocol protocol = reader.getCurrentProtocol();

                        // receive only header
                        reader.openContent().close();

                        if (protocol.getKind() == FileProtocol.Kind.RESPONSE_CACHE_INFO) {
                            assert protocol.getInfo() != null;
                            results.put(protocol.getLocation(), protocol.getInfo());
                        } else if (protocol.getKind() != FileProtocol.Kind.RESPONSE_NOT_FOUND
                                && protocol.getKind() != FileProtocol.Kind.RESPONSE_ERROR) {
                            throw new IOException(MessageFormat.format(
                                    "Unknown protocol in response: {0}",
                                    protocol));
                        }
                    }
                } finally {
                    reader.close();
                }
                return results;
            }
        });
    }

    /**
     * Opens a new {@link FileListProvider} for get-cache-info.
     * @param targetName current target name
     * @param batchId current batch ID
     * @param jobflowId current jobflow ID
     * @param executionId current execution ID
     * @return the created provider
     * @throws IOException if failed to open the file list
     * @throws IllegalArgumentException if some parameters were {@code null}
     */
    protected FileListProvider openFileList(
            String targetName,
            String batchId,
            String jobflowId,
            String executionId) throws IOException {
        if (targetName == null) {
            throw new IllegalArgumentException("targetName must not be null"); //$NON-NLS-1$
        }
        if (batchId == null) {
            throw new IllegalArgumentException("batchId must not be null"); //$NON-NLS-1$
        }
        if (jobflowId == null) {
            throw new IllegalArgumentException("jobflowId must not be null"); //$NON-NLS-1$
        }
        if (executionId == null) {
            throw new IllegalArgumentException("executionId must not be null"); //$NON-NLS-1$
        }
        String sshPath = ConfigurationLoader.getProperty(Constants.PROP_KEY_SSH_PATH);
        String hostName = ConfigurationLoader.getProperty(Constants.PROP_KEY_NAMENODE_HOST);
        String userName = ConfigurationLoader.getProperty(Constants.PROP_KEY_NAMENODE_USER);
        String scriptPath = ConfigurationLoader.getRemoteScriptPath(Constants.PATH_REMOTE_CACHE_INFO);
        List<String> command = new ArrayList<String>();
        command.add(scriptPath);
        command.add(targetName);
        command.add(batchId);
        command.add(jobflowId);
        command.add(executionId);

        Map<String, String> env = new HashMap<String, String>();
        env.putAll(ConfigurationLoader.getPropSubMap(Constants.PROP_PREFIX_HC_ENV));
        env.putAll(RuntimeContext.get().unapply());

        LOG.info("TG-IMPORTER-12002",
                sshPath,
                hostName,
                userName,
                scriptPath,
                targetName,
                batchId,
                jobflowId,
                executionId);

        return new OpenSshFileListProvider(sshPath, userName, hostName, command, env);
    }
}
TOP

Related Classes of com.asakusafw.bulkloader.cache.GetCacheInfoLocal

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.