Package com.taobao.top.analysis.node.component

Source Code of com.taobao.top.analysis.node.component.FileJobExporter

/**
*
*/
package com.taobao.top.analysis.node.component;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.taobao.top.analysis.config.MasterConfig;
import com.taobao.top.analysis.node.IJobExporter;
import com.taobao.top.analysis.node.job.Job;
import com.taobao.top.analysis.node.job.JobTask;
import com.taobao.top.analysis.node.job.JobTaskResult;
import com.taobao.top.analysis.node.operation.CreateReportOperation;
import com.taobao.top.analysis.node.operation.JobDataOperation;
import com.taobao.top.analysis.statistics.data.Report;
import com.taobao.top.analysis.statistics.data.Rule;
import com.taobao.top.analysis.util.AnalysisConstants;
import com.taobao.top.analysis.util.NamedThreadFactory;
import com.taobao.top.analysis.util.ReportUtil;


/**
* 默认报表输出实现
*
* @author fangweng
* @Email fangweng@taobao.com
* 2011-11-25
*
*/
public class FileJobExporter implements IJobExporter {

  private static final Log logger = LogFactory.getLog(FileJobExporter.class);
  /**
   * 用于输出报表文件的线程池
   */
  private ThreadPoolExecutor createReportFileThreadPool;
  private MasterConfig config;
  private int maxCreateReportWorker = 8;
  private long lastRuntime=(System.currentTimeMillis() + 8 * 60 * 60 * 1000) / 86400000;

 
  public int getMaxCreateReportWorker() {
    return maxCreateReportWorker;
  }


  public void setMaxCreateReportWorker(int maxCreateReportWorker) {
    this.maxCreateReportWorker = maxCreateReportWorker;
  }

  @Override
  public MasterConfig getConfig() {
    return config;
  }


  @Override
  public void setConfig(MasterConfig config) {
    this.config = config;
  }

  @Override
  public void init() {
   
    if (this.config != null)
      maxCreateReportWorker = this.config.getMaxCreateReportWorker();
   
    if(logger.isInfoEnabled())
      logger.info("filejobExporter init end, maxCreateReportWorker size : " + maxCreateReportWorker);
   
    createReportFileThreadPool = new ThreadPoolExecutor(
        maxCreateReportWorker,
        maxCreateReportWorker, 0,
        TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(),
        new NamedThreadFactory("createReportFile_worker"));
   
  }

 
  @Override
  public void releaseResource() {
    if (createReportFileThreadPool != null)
      createReportFileThreadPool.shutdown();
   
  }

  @Override
    public List<String> exportReport(Job job, boolean needTimeSuffix) {
        try {

            long timer = System.currentTimeMillis();

            List<String> result =
                    exportReport(job.getStatisticsRule(), job.getJobConfig().getOutput(), job.getJobName(),
                        needTimeSuffix, job.getJobResult(), job.getJobConfig().getOutputEncoding());

            job.setJobExportTime(System.currentTimeMillis() - timer);

            return result;
        }
        catch (Throwable e) {
            logger.error(e);
        }
        return null;
    }
 
  @Override
  public List<String> exportReport(JobTask jobTask,JobTaskResult jobTaskResult,boolean needTimeSuffix) {
   
    return exportReport(jobTask.getStatisticsRule(),jobTask.getOutput()
        ,jobTask.getTaskId(),needTimeSuffix,jobTaskResult.getResults(),jobTask.getOutputEncoding());
  }
 
  protected List<String> exportReport(Rule statisticsRule,String reportOutput,String id,boolean needTimeSuffix
      ,Map<String, Map<String, Object>> entryResultPool,String outputEncoding)
  {
    if (logger.isWarnEnabled())
      logger.warn("start exportReport now, id : " + id + ", output : " + reportOutput);
   
    long start = System.currentTimeMillis();
   
    List<String> reports = new CopyOnWriteArrayList<String>();
   
    if (entryResultPool == null || statisticsRule.getReportPool() == null
        || (entryResultPool != null && entryResultPool.size() == 0)
        || (statisticsRule.getReportPool() != null
          && statisticsRule.getReportPool().size() == 0)) {
        logger.info("entryPool " + entryResultPool + "," + entryResultPool.size() + ";reportPool " + statisticsRule.getReportPool() + "," + statisticsRule.getReportPool().size());
      return reports;
    }
    //清理lazy数据
        ReportUtil.cleanLazyData(entryResultPool, statisticsRule.getEntryPool());
    //做一下lazy处理,用于输出
    ReportUtil.lazyMerge(entryResultPool, statisticsRule.getEntryPool());
    if(logger.isInfoEnabled()) {
        logger.info("clean lazyData and lazyMerge export " + id );
    }

    Calendar calendar = Calendar.getInstance();
    String currentTime = new StringBuilder()
        .append(calendar.get(Calendar.YEAR)).append("-")
        .append(calendar.get(Calendar.MONTH) + 1).append("-")
        .append(calendar.get(Calendar.DAY_OF_MONTH)).toString();

    calendar.add(Calendar.DAY_OF_MONTH, -1);
    String statTime = new StringBuilder()
        .append(calendar.get(Calendar.YEAR)).append("-")
        .append(calendar.get(Calendar.MONTH) + 1).append("-")
        .append(calendar.get(Calendar.DAY_OF_MONTH)).toString();

    String rootDir = reportOutput;
   
    //去掉前缀,主要用于协议的前缀
    if (rootDir.indexOf(":") > 0)
      rootDir = rootDir.substring(rootDir.indexOf(":") +1);
   
    if (!rootDir.endsWith(File.separator))
      rootDir = new StringBuilder(rootDir).append(File.separator).toString();
   
    if (config != null && StringUtils.isNotEmpty(config.getMasterName()))
      rootDir = new StringBuilder(rootDir).append(config.getMasterName())
        .append(File.separator).append(id).append(File.separator).toString();
    else
      rootDir = new StringBuilder(rootDir).append(id).append(File.separator).toString();
   
    StringBuilder periodRootDir = new StringBuilder();
    StringBuilder periodDir = new StringBuilder();
    StringBuilder normalDir = new StringBuilder();
   
    //优化,不再先删除日报表再写
    //采用先写临时文件,写完后,重命名的方式
    if (rootDir != null) {
      periodRootDir.append(rootDir).append("period").append(File.separator);
      periodDir.append(periodRootDir).append(currentTime).append(File.separator);
      normalDir = new StringBuilder(rootDir).append(currentTime).append(File.separator);
     
     
      File targetDir = new java.io.File(normalDir.toString());
      File period = new java.io.File(periodDir.toString());

      if (!period.exists() || (period.exists() && !period.isDirectory())) {
        period.mkdirs();
      }

      if (!targetDir.exists()
          || (targetDir.exists() && !targetDir.isDirectory())) {
        targetDir.mkdirs();
      } else {
        // 删除已有的所有的历史文件
        if (targetDir.exists() && targetDir.isDirectory()) {
          File[] deleteFiles = targetDir.listFiles();

          for (File f : deleteFiles) {
              if(f.getAbsolutePath().endsWith(".temp"))
                  f.delete();
          }
        }
      }
    }

    Iterator<Report> iter = statisticsRule.getReportPool()
        .values().iterator();
   
    CountDownLatch countDownLatch = new CountDownLatch(statisticsRule.getReportPool().size());
    List<String> reportFiles = new ArrayList<String>();
   
    while (iter.hasNext()) {
      Report report = iter.next();
     
      if(logger.isInfoEnabled()) {
              logger.info("check report need to generated by this master " + report.getId() );
          }
      //判断是否是自己要输出的报表,在多个master情况下
      if (statisticsRule.getReport2Master() != null
          && statisticsRule.getReport2Master().size() > 0 && config != null)
      {
        String r = statisticsRule.getReport2Master().get(report.getId());
        if (r == null || !r.startsWith(ReportUtil.getIp()) || !r.endsWith(String.valueOf(config.getMasterPort())))
        {
          countDownLatch.countDown();
          continue;
        }
      }
      if(logger.isInfoEnabled()) {
                logger.info("report need to generated by this master " + report.getId() );
            }
     
      String reportFile;
      String reportDir = normalDir.toString();
      if(rootDir==null) reportDir = new StringBuilder(report.getFile()).append(File.separator).toString();

      // 增加对于周期性输出的报表处理,就是根据FileName创建目录,目录中文件是FileName+时间戳.
      if (report.isPeriod()) {
        if(start-report.getLastExportTime()>report.getExportInterval()){
          report.setLastExportTime(start);
        }else{
          countDownLatch.countDown();
          continue;
        }
       
        if(report.isAppend()){
          reportDir = new StringBuilder().append(periodRootDir)
          .append(report.getFile()).append(File.separator)
          .toString();
         
        }else{
          reportDir = new StringBuilder().append(periodDir)
          .append(report.getFile()).append(File.separator)
          .toString();
   
        }
       
        File tmpDir = new java.io.File(reportDir);

        if (!tmpDir.exists()
            || (tmpDir.exists() && !tmpDir.isDirectory())) {
          tmpDir.mkdirs();
        }

      }
     
      if (needTimeSuffix)
        reportFile = new StringBuilder().append(reportDir)
            .append(report.getFile()).append("_")
            .append(statTime).append(".csv").toString();
      else
        reportFile = new StringBuilder().append(reportDir)
            .append(report.getFile()).append(".csv").toString();

     
      // 对周期性输出增加时间戳到文件结尾
      if (report.isPeriod()) {
        if(report.isAppend()){
          long beg=System.currentTimeMillis();
          long currentRuntime = (beg + 8 * 60 * 60 * 1000) / 86400000;
          if(currentRuntime!=lastRuntime){
            lastRuntime=currentRuntime;
            String bakFile=new StringBuilder().append(reportDir)
            .append(report.getFile()).append("_").append(statTime).append(".csv").toString();
            new File(reportFile).renameTo(new File(bakFile));
           
          }
        }else{
          reportFile = new StringBuilder()
          .append(reportFile.substring(0,
              reportFile.indexOf(".csv"))).append("_")
          .append(System.currentTimeMillis()).append(".csv")
          .toString();
        }
 
      } else {
          reportFile = reportFile + ".temp";
      }
     
      createReportFileThreadPool.execute(
          new CreateReportOperation(reportFile,report,entryResultPool,reports,countDownLatch,outputEncoding));
      reportFiles.add(reportFile);
    }
   
    try
    {
      boolean allexport = countDownLatch.await(10, TimeUnit.MINUTES);
     
      if (!allexport)
      {
        logger.error("3 minute use,but not export all reports!");
      }
    }
    catch(Exception ex)
    {
      logger.error("generateReports error.",ex);
    }
   

    createTimeStampFile(normalDir.toString())
   
    //清理lazy数据
    ReportUtil.cleanLazyData(entryResultPool, statisticsRule.getEntryPool());
    //清理period数据
    ReportUtil.cleanPeriodData(entryResultPool, statisticsRule.getEntryPool());
   

    if (logger.isWarnEnabled())
      logger.warn(new StringBuilder("generate report ").append(id).append(" end")
          .append(", time consume: ")
          .append((System.currentTimeMillis() - start) / 1000)
          .toString());
    return reports;
  }
 
 
  protected void createTimeStampFile(String dir) {
    // 创建一个报表输出时间戳文件,用于增量分析
    String timeStampFile = new StringBuilder().append(dir)
        .append(AnalysisConstants.TIMESTAMP_FILE).toString();

    BufferedWriter bwr = null;

    try {
      new File(timeStampFile).createNewFile();

      bwr = new BufferedWriter(new OutputStreamWriter(
          new FileOutputStream(new File(timeStampFile))));

      bwr.write(String.valueOf(System.currentTimeMillis()));
    } catch (Exception ex) {
      logger.error("createTimeStampFile error!", ex);
    } finally {
      if (bwr != null) {
        try {
          bwr.close();
        } catch (IOException e) {
          logger.error(e, e);
        }
      }
    }

  }

  @Override
  public void exportEntryData(Job job) {
    JobDataOperation jobDataOperation = new JobDataOperation(job,AnalysisConstants.JOBMANAGER_EVENT_EXPORTDATA,this.config);
    createReportFileThreadPool.execute(jobDataOperation);
  }


  @Override
  public void loadEntryData(Job job) {
    JobDataOperation jobDataOperation = new JobDataOperation(job,AnalysisConstants.JOBMANAGER_EVENT_LOADDATA,this.config);
    createReportFileThreadPool.submit(jobDataOperation);
  }


  @Override
  public void loadEntryDataToTmp(Job job) {
    JobDataOperation jobDataOperation = new JobDataOperation(job,AnalysisConstants.JOBMANAGER_EVENT_LOADDATA_TO_TMP,this.config);
    createReportFileThreadPool.submit(jobDataOperation);
  }
 
  @Override
  public void loadJobBackupData(Job job,String bckPrefix)
  {
    JobDataOperation jobDataOperation = new JobDataOperation(job,AnalysisConstants.JOBMANAGER_EVENT_LOAD_BACKUPDATA,this.config,bckPrefix);
    createReportFileThreadPool.submit(jobDataOperation);
  }

}
TOP

Related Classes of com.taobao.top.analysis.node.component.FileJobExporter

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.