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

com.huaweicloud.dis.util.cache.CacheResenderThread Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2002-2010 the original author or authors.
 *
 * 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.huaweicloud.dis.util.cache;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.huaweicloud.dis.Constants;
import com.huaweicloud.dis.DIS;
import com.huaweicloud.dis.DISClientBuilder;
import com.huaweicloud.dis.DISConfig;
import com.huaweicloud.dis.iface.data.request.PutRecordRequest;
import com.huaweicloud.dis.iface.data.request.PutRecordsRequest;
import com.huaweicloud.dis.util.IOUtils;
import com.huaweicloud.dis.util.JsonUtils;

/**
 * 缓存重发线程
 *
 */
public class CacheResenderThread extends Thread
{
    private static final Logger LOGGER = LoggerFactory.getLogger(CacheUtils.class); 
    
    private DISConfig disConfig;
    
    private static final int BUFFER_SIZE = 5 * 1024 * 1024; // 缓存读取大小:5M
    
    public CacheResenderThread(String name, DISConfig disConfig)
    {
        setDaemon(true);
        setName("Cache-ResenderThread-" + name);
        
        this.disConfig = disConfig;
    }
    
    @Override
    public void run()
    {
        
        // 归档缓存数据重传
        while (true)
        {
            LOGGER.info("BEGIN resend cache data.");
            
            // 重发缓存数据文件之前,先执行归档操作
            CacheManager cacheManager = CacheManager.getInstance(disConfig);
            cacheManager.archive();
            
            try
            {
                resend();
            }
            catch (IOException ioException)
            {
                LOGGER.error("Failed to resend cache data.", ioException);
            }
            
            LOGGER.info("END resend cache data.");
            
            try
            {
                // 10分钟一次数据重发
//                Thread.sleep(10 * 60 * 1000);
                Thread.sleep(2 * 60 * 1000);
            }
            catch (InterruptedException e)
            {
                LOGGER.error("Thread interrupt.", e);
            }
        }
    }
    
    private void resend() throws IOException
    {
        String dataCacheDir = this.disConfig.getDataCacheDir();
        File dataCacheDirFile = new File(dataCacheDir);
        if (!dataCacheDirFile.exists() || !dataCacheDirFile.isDirectory())
        {
            LOGGER.debug("Data Cache dir doesn't exist, continue.");
            return ;
        }
        
        File[] files = dataCacheDirFile.listFiles();
        for (int i = 0; i < files.length; i++)
        {
            if (isArchiveFile(files[i]))
            {
                doResend(files[i], getIndexFile(files[i]));
            }
        }
    }
    
    /**
     * 重发缓存数据
     * 
     * @param dataFile 缓存数据文件
     * @param indexFile 缓存索引文件
     * @throws IOException
     */
    private void doResend(File dataFile, File indexFile) throws IOException
    {
        DIS dic = DISClientBuilder.standard()
            .withEndpoint(disConfig.getEndpoint())
            .withAk(disConfig.getAK())
            .withSk(disConfig.getSK())
            .withProjectId(disConfig.getProjectId())
            .withRegion(disConfig.getRegion())
            .build();
        
        String indexFileContents = getIndexFileContents(indexFile);
        String[] indexArray = indexFileContents.split(",");
        int resendIndex = Integer.parseInt(indexArray[0]);
        int totalIndex = Integer.parseInt(indexArray[1]);
        if (resendIndex == totalIndex)
        {
            // 该缓存文件已完成重发,清理归档文件
            clearArchiveFile(dataFile, indexFile);
        }
        else
        {
            InputStreamReader read = null;
            BufferedReader bufferedReader = null;
            
            try
            {
                read = new InputStreamReader(new FileInputStream(dataFile), "UTF-8"); // 考虑到编码格式
                bufferedReader = new BufferedReader(read, BUFFER_SIZE);
                String lineTxt = null;
                
                while ((lineTxt = bufferedReader.readLine()) != null)
                {
                    // 重发成功,则更新索引文件;重发失败,则认为网络未恢复,终止本次重发。
                    LOGGER.info("lineTxt: {}", lineTxt);
                    PutRecordsRequest putRecordsRequest = JsonUtils.jsonToObj(lineTxt, PutRecordsRequest.class);
                    try
                    {
                        dic.putRecords(putRecordsRequest);
                    }
                    catch (Exception e)
                    {
                        LOGGER.error("Failed to resend records, archive data filename: {}, break.", dataFile.getName(), e);
                        break;
                    }
                    
                    // 更新索引文件
                    resendIndex++;
                    updateIndexFile(resendIndex, totalIndex, indexFile);
                }
            }
            catch (IOException e)
            {
                throw e;
            }
            finally
            {
                bufferedReader.close();
                read.close();
            }
            
            if (resendIndex == totalIndex)
            {
                // 该缓存文件已完成重发,清理归档文件
                clearArchiveFile(dataFile, indexFile);
            }
        }
        
    }
    
    /**
     * 该文件是否为归档的缓存数据文件
     * @param file 缓存目录下的文件对象
     * @return {@code true} 是归档的缓存数据文件
     *          {@code false} 不是归档的缓存数据文件
     */
    private boolean isArchiveFile(File file)
    {
        String fileName = file.getName();
        if (fileName.contains(Constants.CACHE_ARCHIVE_DATA_FILE_SUFFIX))
        {
            return true;
        }
        return false;
    }
    
    private File getIndexFile(File dataFile) throws IOException
    {
        String dataFilePath = dataFile.getCanonicalPath();
        String indexFilePath = dataFilePath.replace(Constants.CACHE_ARCHIVE_DATA_FILE_SUFFIX, Constants.CACHE_ARCHIVE_INDEX_FILE_SUFFIX);
        
        return new File(indexFilePath);
    }
    
    private String getIndexFileContents(File indexFile) throws IOException
    {
        String lineTxt = null;
        InputStreamReader read = null;
        BufferedReader bufferedReader = null;
        
        try
        {
            read = new InputStreamReader(new FileInputStream(indexFile), "UTF-8"); // 考虑到编码格式
            bufferedReader = new BufferedReader(read);
            
            while ((lineTxt = bufferedReader.readLine()) != null)
            {
                break;
            }
        }
        catch (IOException e)
        {
            throw e;
        }
        finally 
        {
            read.close();
            bufferedReader.close();
        }
        
        return lineTxt;
    }
    
    private void updateIndexFile(int resendIndex, int totalIndex, File indexFile) throws IOException
    {
        String newIndex = resendIndex + "," + totalIndex;
        IOUtils.writeToFile(newIndex, indexFile.getCanonicalPath());
    }
    
    private void clearArchiveFile(File dataFile, File indexFile)
    {
        dataFile.delete();
        indexFile.delete();
        LOGGER.debug("Clean-up work has been completed, archive data filename: {}.", dataFile.getName());
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy