zoukankan      html  css  js  c++  java
  • 基于Dedup的数据打包技术

    基于Dedup的数据打包技术

    0、引言
        Tar, winrar, winzip是最为常见的数据打包工具软件,它们把文件集体封装成一个单独的数据包,从而方便数据的分布、传输、归档以及持久保存等目的。这类工具通常都支持数据压缩技术,从而有效减少数据的存储空间,常用压缩算法有Huffman编码、Z77/z78、LZW等。压缩算法的原理是通过对数据的重新编码,高频率数据片段采用较短的编码,低频率数据片段采用较长的编码,从而获得全局的上数据量较小的文件表示。

    1、Dedup原理
       Deduplication,即重复数据删除,它是一种非常新的且流行度很高的存储技术,可以大大减少数据的数量。重复数据删除技术,通过数据集中重复的数据,从而消除冗余数据。借助dedup技术,可以提高存储系统的效率,有效节约成本、减少传输过程中的网络带宽。同时它也是一种绿色存储技术,能有效降低能耗(存储空间小了,所需要存储系统磁盘也就少了,自然所需要电能就减少了)。
       dedup按照消重的粒度可以分为文件级和数据块级。文件级的dedup技术也称为单一实例存储(SIS, Single Instance Store),数据块级的重复数据删除,其消重粒度更小,可以达到4-24KB之间。显然,数据块级的可以提供更高的数据消重率,因此目前主流的dedup产品都是数据块级的。重复数据删除原理如下图所示。将文件都分割成数据块(可以是定长或变长的数据块),采用MD5或SHA1等Hash算法(可以同时使用两种或以上hash算法,或CRC校验等,以获得非常小概率的数据碰撞发生)为数据块计算FingerPrint。具有相同FP指纹的数据块即可认为是相同的数据块,存储系统中仅需要保留一份。这样,一个物理文件在存储系统中就对应一个逻辑表示,由一组FP组成的元数据。当进行读取文件时,先读取逻辑文件,然后根据FP序列,从存储系统中取出相应数据块,还原物理文件副本。
       重复数据删除目前主要应用于数据备份,因此对数据进行多次备份后,存在大量重复数据,非常适合dedup技术。事实上,dedup技术可以用于很多场合,包括在线数据、近线数据、离线数据存储系统,甚至可以在文件系统、卷管理器、NAS、SAN中实施。还可以用于网络数据传输,当然也可以应用于数据打包技术。dedup技术可以帮助众多应用降低数据存储量,节省网络带宽,提高存储效率、减小备份窗口,绿色节能。这里,基于dedup实现一种数据打包技术。



    2、基于Dedup的数据打包模型

      数据包文件的数据布局:

    Header

    Unique block data

    File metadata

     数据包由三部分组成:文件头(header)、唯一数据块集(unique block data)和逻辑文件元数据(file metadata)。其中,header为一个结构体,定义了数据块大小、唯一数据块数量、数据块ID大小、包中文件数量、元数据在包中的位置等元信息。文件头后紧接就存储着所有唯一的数据块,大小和数量由文件头中元信息指示。在数据块之后,就是数据包中文件的逻辑表示元数据,由多个实体组成,结构如下所示,一个实体表示一个文件。解包时根据文件的元数据,逐一提取数据块,还原出当初的物理文件。
     
      逻辑文件的元数据表示:

    Entry header

    pathname

    Entry data

    Last block data

      逻辑文件的实体头中记录着文件名长度、数据块数量、数据块ID大小和最后一个数据块大小等信息。紧接着是文件名数据,长度在实体头中定义。文件名数据之后,存储着一组唯一数据块的编号,编号与唯一数据块集中的数据块一一对应。最后存储着文件最后一个数据块,由于这个数据块大小通常比正常数据块小,重复概率非常小,因此单独保存。


    3、原型实现
    基于上面的数据布局,就可以实现支持重复数据删除的数据打包方法。本人在Linux系统上实现了一个原型,实现中使用了hashtable来记录和查询唯一数据块信息,使用MD5算法计算数据块指纹,并使用zlib中的z77压缩算法对删除了重复数据后的数据包进行压缩。hashtable, MD5, z77算法和实现,这里不作介绍,有兴趣的读者可以参考相关资源。下面给出dedup.h, dedup.c undedup.c源码文件。目前实现的原型还相对比较粗糙。

    /* dedup.h */

    [cpp] view plain copy
     
     print?
    1. #ifndef _DEDUP_H  
    2. #define _DEDUP_H  
    3. #include "md5.h"  
    4. #include "hash.h"  
    5. #include "hashtable.h"  
    6. #include "libz.h"  
    7. #ifdef __cplusplus  
    8. extern "C" {  
    9. #endif  
    10. /*  
    11.  * deduplication file data layout 
    12.  * -------------------------------------------------- 
    13.  * |  header  |  unique block data |  file metadata | 
    14.  * -------------------------------------------------- 
    15.  * 
    16.  * file metedata entry layout 
    17.  * ----------------------------------------------------------------- 
    18.  * |  entry header  |  pathname  |  entry data  |  last block data | 
    19.  * ----------------------------------------------------------------- 
    20.  */  
    21. typedef unsigned int block_id_t;  
    22. #define BLOCK_SIZE  4096     /* 4K Bytes */  
    23. #define BACKET_SIZE     10240  
    24. #define MAX_PATH_LEN    255  
    25. #define BLOCK_ID_SIZE   (sizeof(block_id_t))  
    26. /* deduplication package header */  
    27. #define DEDUP_MAGIC_NUM 0x1329149  
    28. typedef struct _dedup_package_header {  
    29.     unsigned int block_size;  
    30.     unsigned int block_num;  
    31.     unsigned int blockid_size;  
    32.     unsigned int magic_num;  
    33.     unsigned int file_num;  
    34.     unsigned long long metadata_offset;  
    35. } dedup_package_header;  
    36. #define DEDUP_PKGHDR_SIZE   (sizeof(dedup_package_header))  
    37. /* deduplication metadata entry header */  
    38. typedef struct _dedup_entry_header {  
    39.     unsigned int path_len;  
    40.     unsigned int block_num;  
    41.     unsigned int entry_size;  
    42.     unsigned int last_block_size;  
    43.     int mode;  
    44. } dedup_entry_header;  
    45. #define DEDUP_ENTRYHDR_SIZE (sizeof(dedup_entry_header))  
    46. #ifdef __cplusplus  
    47. }  
    48. #endif  
    49. #endif  


    /* dedup.c */

    [cpp] view plain copy
     
     print?
    1. #include <stdio.h>  
    2. #include <stdlib.h>  
    3. #include <sys/types.h>  
    4. #include <sys/stat.h>  
    5. #include <dirent.h>  
    6. #include <unistd.h>  
    7. #include <getopt.h>  
    8. #include <fcntl.h>  
    9. #include <dirent.h>  
    10. #include <errno.h>  
    11. #include "dedup.h"  
    12. /* unique block number in package */  
    13. static unsigned int g_unique_block_nr = 0;  
    14. /* regular file number in package */  
    15. static unsigned int g_regular_file_nr = 0;  
    16. /* block length */  
    17. static unsigned int g_block_size = BLOCK_SIZE;  
    18. /* hashtable backet number */  
    19. static unsigned int g_htab_backet_nr = BACKET_SIZE;  
    20. void show_md5(unsigned char md5_checksum[16])  
    21. {  
    22.     int i;  
    23.     for (i = 0; i < 16; i++)  
    24.     {  
    25.             printf("%02x", md5_checksum[i]);  
    26.     }  
    27. }  
    28. void show_pkg_header(dedup_package_header dedup_pkg_hdr)  
    29. {  
    30.         printf("block_size = %d/n", dedup_pkg_hdr.block_size);  
    31.         printf("block_num = %d/n", dedup_pkg_hdr.block_num);  
    32.     printf("blockid_size = %d/n", dedup_pkg_hdr.blockid_size);  
    33.     printf("magic_num = 0x%x/n", dedup_pkg_hdr.magic_num);  
    34.     printf("file_num = %d/n", dedup_pkg_hdr.file_num);  
    35.     printf("metadata_offset = %lld/n", dedup_pkg_hdr.metadata_offset);  
    36. }  
    37. int dedup_regfile(char *fullpath, int prepos, int fd_bdata, int fd_mdata, hashtable *htable, int debug)  
    38. {  
    39.     int fd;  
    40.     char *buf = NULL;  
    41.     unsigned int rwsize, pos;  
    42.     unsigned char md5_checksum[16 + 1] = {0};  
    43.     unsigned int *metadata = NULL;  
    44.     unsigned int block_num = 0;  
    45.     struct stat statbuf;  
    46.     dedup_entry_header dedup_entry_hdr;  
    47.     if (-1 == (fd = open(fullpath, O_RDONLY)))  
    48.     {  
    49.         perror("open regulae file");  
    50.         return errno;  
    51.     }  
    52.     if (-1 == fstat(fd, &statbuf))  
    53.     {  
    54.         perror("fstat regular file");  
    55.         goto _DEDUP_REGFILE_EXIT;  
    56.     }  
    57.     block_num = statbuf.st_size / g_block_size;  
    58.     metadata = (unsigned int *)malloc(BLOCK_ID_SIZE * block_num);  
    59.     if (metadata == NULL)  
    60.     {  
    61.         perror("malloc metadata for regfile");  
    62.         goto _DEDUP_REGFILE_EXIT;  
    63.     }  
    64.     buf = (char *)malloc(g_block_size);  
    65.     if (buf == NULL)  
    66.     {  
    67.         perror("malloc buf for regfile");  
    68.         goto _DEDUP_REGFILE_EXIT;  
    69.     }  
    70.     pos = 0;  
    71.     while (rwsize = read(fd, buf, g_block_size))   
    72.     {  
    73.         /* if the last block */  
    74.         if (rwsize != g_block_size)  
    75.             break;  
    76.         /* calculate md5 */  
    77.         md5(buf, rwsize, md5_checksum);  
    78.         /* check hashtable with hashkey */  
    79.         unsigned int *bindex = (block_id_t *)hash_value((void *)md5_checksum, htable);  
    80.         if (bindex == NULL)  
    81.         {  
    82.             bindex = (unsigned int *)malloc(BLOCK_ID_SIZE);  
    83.             if (NULL == bindex)  
    84.             {  
    85.                 perror("malloc in dedup_regfile");  
    86.                 break;  
    87.             }  
    88.             /* insert hash entry and write unique block into bdata*/  
    89.             *bindex = g_unique_block_nr;  
    90.             hash_insert((void *)strdup(md5_checksum), (void *)bindex, htable);  
    91.             write(fd_bdata, buf, rwsize);  
    92.             g_unique_block_nr++;  
    93.         }  
    94.         metadata[pos] = *bindex;  
    95.         memset(buf, 0, g_block_size);  
    96.         memset(md5_checksum, 0, 16 + 1);  
    97.         pos++;  
    98.     }  
    99.     /* write metadata into mdata */  
    100.     dedup_entry_hdr.path_len = strlen(fullpath) - prepos;  
    101.     dedup_entry_hdr.block_num = block_num;  
    102.     dedup_entry_hdr.entry_size = BLOCK_ID_SIZE;  
    103.     dedup_entry_hdr.last_block_size = rwsize;  
    104.     dedup_entry_hdr.mode = statbuf.st_mode;  
    105.     write(fd_mdata, &dedup_entry_hdr, sizeof(dedup_entry_header));  
    106.     write(fd_mdata, fullpath + prepos, dedup_entry_hdr.path_len);  
    107.     write(fd_mdata, metadata, BLOCK_ID_SIZE * block_num);  
    108.     write(fd_mdata, buf, rwsize);  
    109.     g_regular_file_nr++;  
    110. _DEDUP_REGFILE_EXIT:  
    111.     close(fd);  
    112.     if (metadata) free(metadata);  
    113.     if (buf) free(buf);  
    114.     return 0;  
    115. }  
    116. int dedup_dir(char *fullpath, int prepos, int fd_bdata, int fd_mdata, hashtable *htable, int debug)  
    117. {  
    118.     DIR *dp;  
    119.     struct dirent *dirp;  
    120.     struct stat statbuf;  
    121.     char subpath[MAX_PATH_LEN] = {0};  
    122.     if (NULL == (dp = opendir(fullpath)))  
    123.     {  
    124.         return errno;  
    125.     }  
    126.     while ((dirp = readdir(dp)) != NULL)  
    127.     {  
    128.         if (strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0)  
    129.             continue;  
    130.         sprintf(subpath, "%s/%s", fullpath, dirp->d_name);  
    131.         if (0 == lstat(subpath, &statbuf))  
    132.         {  
    133.             if (debug)  
    134.                 printf("%s/n", subpath);  
    135.             if (S_ISREG(statbuf.st_mode))   
    136.                 dedup_regfile(subpath, prepos, fd_bdata, fd_mdata, htable,debug);  
    137.             else if (S_ISDIR(statbuf.st_mode))  
    138.                 dedup_dir(subpath, prepos, fd_bdata, fd_mdata, htable, debug);  
    139.         }  
    140.     }  
    141.     closedir(dp);  
    142.     return 0;  
    143. }  
    144. int dedup_package(int path_nr, char **src_paths, char *dest_file, int debug)  
    145. {  
    146.     int fd, fd_bdata, fd_mdata, ret = 0;  
    147.     struct stat statbuf;  
    148.     hashtable *htable = NULL;  
    149.     dedup_package_header dedup_pkg_hdr;  
    150.     char **paths = src_paths;  
    151.     int i, rwsize, prepos;  
    152.     char buf[1024 * 1024] = {0};  
    153.     if (-1 == (fd = open(dest_file, O_WRONLY | O_CREAT, 0755)))  
    154.     {  
    155.         perror("open dest file");  
    156.         ret = errno;  
    157.         goto _DEDUP_PKG_EXIT;  
    158.     }  
    159.     htable = create_hashtable(g_htab_backet_nr);  
    160.     if (NULL == htable)  
    161.     {  
    162.         perror("create_hashtable");  
    163.         ret = errno;  
    164.         goto _DEDUP_PKG_EXIT;  
    165.     }  
    166.     fd_bdata = open("./.bdata", O_RDWR | O_CREAT, 0777);  
    167.     fd_mdata = open("./.mdata", O_RDWR | O_CREAT, 0777);  
    168.     if (-1 == fd_bdata || -1 == fd_mdata)  
    169.     {  
    170.         perror("open bdata or mdata");  
    171.         ret = errno;  
    172.         goto _DEDUP_PKG_EXIT;  
    173.     }  
    174.     g_unique_block_nr = 0;  
    175.     g_regular_file_nr = 0;  
    176.     for (i = 0; i < path_nr; i++)  
    177.     {  
    178.         if (lstat(paths[i], &statbuf) < 0)  
    179.         {  
    180.             perror("lstat source path");  
    181.             ret = errno;  
    182.             goto _DEDUP_PKG_EXIT;  
    183.         }  
    184.         if (S_ISREG(statbuf.st_mode) || S_ISDIR(statbuf.st_mode))  
    185.         {  
    186.             if (debug)  
    187.                 printf("%s/n", paths[i]);  
    188.             /* get filename position in pathname */   
    189.             prepos = strlen(paths[i]) - 1;  
    190.             if (strcmp(paths[i], "/") != 0 && *(paths[i] + prepos) == '/')  
    191.             {  
    192.                 *(paths[i] + prepos--) = '/0';  
    193.             }  
    194.             while(*(paths[i] + prepos) != '/' && prepos >= 0) prepos--;  
    195.             prepos++;  
    196.             if (S_ISREG(statbuf.st_mode))  
    197.                 dedup_regfile(paths[i], prepos, fd_bdata, fd_mdata, htable, debug);  
    198.             else  
    199.                 dedup_dir(paths[i], prepos, fd_bdata, fd_mdata, htable, debug);  
    200.         }     
    201.         else   
    202.         {  
    203.             if (debug)  
    204.                 printf("%s is not regular file or directory./n", paths[i]);  
    205.         }  
    206.     }  
    207.     /* fill up dedup package header */  
    208.     dedup_pkg_hdr.block_size = g_block_size;  
    209.     dedup_pkg_hdr.block_num = g_unique_block_nr;  
    210.     dedup_pkg_hdr.blockid_size = BLOCK_ID_SIZE;  
    211.     dedup_pkg_hdr.magic_num = DEDUP_MAGIC_NUM;  
    212.     dedup_pkg_hdr.file_num = g_regular_file_nr;   
    213.     dedup_pkg_hdr.metadata_offset = DEDUP_PKGHDR_SIZE + g_block_size * g_unique_block_nr;  
    214.     write(fd, &dedup_pkg_hdr, DEDUP_PKGHDR_SIZE);  
    215.     /* fill up dedup package unique blocks*/  
    216.     lseek(fd_bdata, 0, SEEK_SET);  
    217.     while(rwsize = read(fd_bdata, buf, 1024 * 1024))  
    218.     {  
    219.         write(fd, buf, rwsize);  
    220.         memset(buf, 0, 1024 * 1024);  
    221.     }  
    222.     /* fill up dedup package metadata */  
    223.     lseek(fd_mdata, 0, SEEK_SET);  
    224.     while(rwsize = read(fd_mdata, buf, 1024 * 1024))  
    225.     {  
    226.         write(fd, buf, rwsize);  
    227.         memset(buf, 0, 1024 * 1024);  
    228.     }  
    229.     if (debug)  
    230.         show_pkg_header(dedup_pkg_hdr);  
    231. _DEDUP_PKG_EXIT:  
    232.     close(fd);  
    233.     close(fd_bdata);  
    234.     close(fd_mdata);  
    235.     unlink("./.bdata");  
    236.     unlink("./.mdata");  
    237.     hash_free(htable);  
    238.       
    239.     return ret;  
    240. }  
    241. void usage()  
    242. {  
    243.     printf("Usage:  dedup [OPTION...] <target file> <source files ...>/n");  
    244.     printf("/nPackage files with deduplicaton technique./n");  
    245.     printf("Mandatory arguments to long options are mandatory for short options too./n");  
    246.     printf("  -z, --compress   filter the archive through compress/n");  
    247.     printf("  -b, --block      block size for deduplication, default is 4096/n");  
    248.     printf("  -t, --hashtable  hashtable backet number, default is 10240/n");  
    249.     printf("  -d, --debug      print debug messages/n");  
    250.     printf("  -h, --help       give this help list/n");  
    251.     printf("/nReport bugs to <Aigui.Liu@gmail.com>./n");  
    252. }  
    253. int main(int argc, char *argv[])  
    254. {  
    255.     char tmp_file[] = "./.dedup/0";  
    256.     int bz = 0, bhelp = 0, bdebug = 0;  
    257.     int ret = -1, c;  
    258.     struct option longopts[] =  
    259.     {  
    260.         {"compress", 0, &bz, 'z'},  
    261.         {"block", 1, 0, 'b'},  
    262.         {"hashtable", 1, 0, 't'},  
    263.         {"debug", 0, &bdebug, 'd'},  
    264.         {"help", 0, &bhelp, 'h'},  
    265.         {0, 0, 0, 0}  
    266.     };  
    267.     /* parse options */  
    268.     while ((c = getopt_long (argc, argv, "zb:t:dh", longopts, NULL)) != EOF)  
    269.     {  
    270.         switch(c)   
    271.         {  
    272.         case 'z':  
    273.             bz = 1;  
    274.             break;  
    275.         case 'b':  
    276.             g_block_size = atoi(optarg);  
    277.             break;  
    278.         case 't':  
    279.             g_htab_backet_nr = atoi(optarg);  
    280.             break;  
    281.         case 'd':  
    282.             bdebug = 1;  
    283.             break;  
    284.         case 'h':  
    285.         case '?':  
    286.         default:  
    287.             bhelp = 1;  
    288.             break;  
    289.         }  
    290.     }  
    291.     if (bhelp == 1 || (argc - optind) < 2)  
    292.     {  
    293.         usage();  
    294.         return 0;  
    295.     }  
    296.     if (bz)  
    297.     {  
    298.         /* dedup and compress */  
    299.         ret = dedup_package(argc - optind -1 , argv + optind + 1, tmp_file, bdebug);  
    300.         if (ret == 0)  
    301.         {  
    302.             ret = zlib_compress_file(tmp_file, argv[optind]);  
    303.             unlink(tmp_file);  
    304.         }  
    305.     }   
    306.     else   
    307.     {  
    308.         /* dedup only */  
    309.         ret = dedup_package(argc - optind - 1, argv + optind + 1, argv[optind], bdebug);  
    310.     }  
    311.     return ret;  
    312. }   

    /* undedup.c */

    [cpp] view plain copy
     
     print?
    1. #include <stdio.h>  
    2. #include <stdlib.h>  
    3. #include <sys/types.h>  
    4. #include <sys/stat.h>  
    5. #include <unistd.h>  
    6. #include <getopt.h>  
    7. #include <fcntl.h>  
    8. #include <errno.h>  
    9. #include "dedup.h"  
    10. /* block length */  
    11. static unsigned int g_block_size = BLOCK_SIZE;  
    12. void show_pkg_header(dedup_package_header dedup_pkg_hdr)  
    13. {  
    14.         printf("block_size = %d/n", dedup_pkg_hdr.block_size);  
    15.         printf("block_num = %d/n", dedup_pkg_hdr.block_num);  
    16.         printf("blockid_size = %d/n", dedup_pkg_hdr.blockid_size);  
    17.         printf("magic_num = 0x%x/n", dedup_pkg_hdr.magic_num);  
    18.         printf("file_num = %d/n", dedup_pkg_hdr.file_num);  
    19.         printf("metadata_offset = %lld/n", dedup_pkg_hdr.metadata_offset);  
    20. }  
    21. int prepare_target_file(char *pathname, char *basepath, int mode)  
    22. {  
    23.     char fullpath[MAX_PATH_LEN] = {0};  
    24.     char path[MAX_PATH_LEN] = {0};  
    25.     char *p = NULL;  
    26.     int pos = 0, fd;  
    27.     sprintf(fullpath, "%s/%s", basepath, pathname);  
    28.     p = fullpath;  
    29.     while (*p != '/0')  
    30.     {  
    31.         path[pos++] = *p;  
    32.         if (*p == '/')  
    33.             mkdir(path, 0755);  
    34.         p++;  
    35.     }   
    36.     fd = open(fullpath, O_WRONLY | O_CREAT, mode);  
    37.     return fd;  
    38. }  
    39. int undedup_regfile(int fd, dedup_entry_header dedup_entry_hdr, char *dest_dir, int debug)  
    40. {  
    41.     char pathname[MAX_PATH_LEN] = {0};  
    42.     block_id_t *metadata = NULL;  
    43.     unsigned int block_num = 0;  
    44.     char *buf = NULL;  
    45.     char *last_block_buf = NULL;  
    46.     long long offset, i;  
    47.     int fd_dest, ret = 0;  
    48.     metadata = (block_id_t *) malloc(BLOCK_ID_SIZE * dedup_entry_hdr.block_num);  
    49.     if (NULL == metadata)  
    50.         return errno;  
    51.     buf = (char *)malloc(g_block_size);  
    52.     last_block_buf = (char *)malloc(g_block_size);  
    53.     if (NULL == buf || NULL == last_block_buf)  
    54.     {  
    55.         ret = errno;  
    56.         goto _UNDEDUP_REGFILE_EXIT;  
    57.     }  
    58.     read(fd, pathname, dedup_entry_hdr.path_len);  
    59.     read(fd, metadata, BLOCK_ID_SIZE * dedup_entry_hdr.block_num);  
    60.     read(fd, last_block_buf, dedup_entry_hdr.last_block_size);  
    61.     fd_dest = prepare_target_file(pathname, dest_dir, dedup_entry_hdr.mode);  
    62.     if (fd_dest == -1)  
    63.     {  
    64.         ret = errno;  
    65.         goto _UNDEDUP_REGFILE_EXIT;  
    66.     }  
    67.     if (debug)  
    68.         printf("%s/%s/n", dest_dir, pathname);  
    69.     /* write regular block */  
    70.     block_num = dedup_entry_hdr.block_num;  
    71.     for(i = 0; i < block_num; ++i)  
    72.     {  
    73.         offset = DEDUP_PKGHDR_SIZE + metadata[i] * g_block_size;  
    74.         lseek(fd, offset, SEEK_SET);  
    75.         read(fd, buf, g_block_size);  
    76.         write(fd_dest, buf, g_block_size);  
    77.     }  
    78.     /* write last block */  
    79.     write(fd_dest, last_block_buf, dedup_entry_hdr.last_block_size);  
    80.     close(fd_dest);  
    81. _UNDEDUP_REGFILE_EXIT:  
    82.     if (metadata) free(metadata);  
    83.     if (buf) free(buf);  
    84.     if (last_block_buf) free(last_block_buf);  
    85.     return ret;  
    86. }  
    87. int undedup_package(char *src_file, char *dest_dir, int debug)  
    88. {  
    89.     int fd, i, ret = 0;  
    90.     dedup_package_header dedup_pkg_hdr;  
    91.     dedup_entry_header dedup_entry_hdr;  
    92.     unsigned long long offset;  
    93.         if (-1 == (fd = open(src_file, O_RDONLY)))  
    94.         {  
    95.                 perror("open source file");  
    96.                 return errno;  
    97.         }  
    98.     if (read(fd, &dedup_pkg_hdr, DEDUP_PKGHDR_SIZE) != DEDUP_PKGHDR_SIZE)  
    99.     {  
    100.         perror("read dedup_package_header");  
    101.         ret = errno;  
    102.         goto _UNDEDUP_PKG_EXIT;  
    103.     }  
    104.     if (debug)  
    105.         show_pkg_header(dedup_pkg_hdr);  
    106.     offset = dedup_pkg_hdr.metadata_offset;  
    107.     for (i = 0; i < dedup_pkg_hdr.file_num; ++i)  
    108.     {  
    109.         if (lseek(fd, offset, SEEK_SET) == -1)  
    110.         {  
    111.             ret = errno;  
    112.             break;  
    113.         }  
    114.               
    115.         if (read(fd, &dedup_entry_hdr, DEDUP_ENTRYHDR_SIZE) != DEDUP_ENTRYHDR_SIZE)  
    116.         {  
    117.             ret = errno;  
    118.             break;  
    119.         }  
    120.         ret = undedup_regfile(fd, dedup_entry_hdr, dest_dir, debug);  
    121.         if (ret != 0)  
    122.             break;  
    123.         offset += DEDUP_ENTRYHDR_SIZE;  
    124.         offset += dedup_entry_hdr.path_len;  
    125.         offset += dedup_entry_hdr.block_num * dedup_entry_hdr.entry_size;  
    126.         offset += dedup_entry_hdr.last_block_size;  
    127.     }  
    128. _UNDEDUP_PKG_EXIT:  
    129.     close(fd);  
    130.     return ret;  
    131. }  
    132. void usage()  
    133. {  
    134.         printf("Usage:  undedup [OPTION...] <source file>/n");  
    135.     printf("/nUnpackage files with deduplicaton technique./n");  
    136.     printf("Mandatory arguments to long options are mandatory for short options too./n");  
    137.     printf("  -z, --uncompress  filter the archive through uncompress/n");  
    138.     printf("  -c, --directory   change to directory, default is PWD/n");  
    139.     printf("  -d, --debug       print debug messages/n");  
    140.     printf("  -h, --help        give this help list/n");  
    141.     printf("/nReport bugs to <Aigui.Liu@gmail.com>./n");  
    142. }  
    143. int main(int argc, char *argv[])  
    144. {  
    145.     char tmp_file[] = "./.dedup/0";  
    146.     char path[MAX_PATH_LEN] = "./0";  
    147.     int bz = 0, bhelp = 0, bdebug = 0;  
    148.     int ret = -1, c;  
    149.     struct option longopts[] =  
    150.     {  
    151.         {"compress", 0, &bz, 'z'},  
    152.         {"directory", 1, 0, 'c'},  
    153.         {"debug", 0, &bdebug, 'd'},  
    154.         {"help", 0, &bhelp, 'h'},  
    155.         {0, 0, 0, 0}  
    156.     };  
    157.     while ((c = getopt_long (argc, argv, "zc:dh", longopts, NULL)) != EOF)  
    158.     {  
    159.         switch(c)  
    160.         {  
    161.         case 'z':  
    162.             bz = 1;  
    163.             break;  
    164.         case 'c':  
    165.             sprintf(path, "%s", optarg);  
    166.             break;  
    167.         case 'd':  
    168.             bdebug = 1;  
    169.             break;  
    170.         case 'h':  
    171.         case '?':  
    172.         default:  
    173.             bhelp = 1;  
    174.             break;  
    175.         }  
    176.     }  
    177.     if (bhelp == 1 || (argc - optind) < 1)  
    178.     {  
    179.         usage();  
    180.         return 0;  
    181.     }  
    182.     if (bz)  
    183.     {  
    184.         /* uncompress and undedup */  
    185.         ret = zlib_decompress_file(argv[optind], tmp_file);  
    186.         if (ret == 0)  
    187.         {  
    188.             ret = undedup_package(tmp_file, path, bdebug);  
    189.             unlink(tmp_file);  
    190.         }  
    191.     }  
    192.     else  
    193.     {  
    194.         /* only undedup */  
    195.         ret = undedup_package(argv[optind], path, bdebug);  
    196.     }  
    197.     return ret;  
    198. }  


    /* dedup usage */
    Usage:  dedup [OPTION...] <target file> <source files ...>

    Package files with deduplicaton technique.

      -z, --compress   filter the archive through compress
      -b, --block      block size for deduplication, default is 4096
      -t, --hashtable  hashtable backet number, default is 10240
      -d, --debug      print debug messages
      -h, --help       give this help list

    /* undedup usage */
    Usage:  undedup [OPTION...] <source file>

    Unpackage files with deduplicaton technique.


      -z, --uncompress  filter the archive through uncompress
      -c, --directory   change to directory, default is PWD
      -d, --debug       print debug messages
      -h, --help        give this help list


    4、初步测试
      这里使用linux最新的kernel源码进行测试,并与tar工具进行比较。从www.kernel.org 下载linux-2.6.32.tar.gz文件,并解压出源文件,然后分别使用tar和dedup工具进行打包,分别得到以下几个文件。

    Filename

    File size

    commands

    linux-2.6.32.tar

    382392320 (365MB)

    tar cvf linux-2.6.32.tar linux-2.6.32/

    linux-2.6.32.tar.dd 

    380381944 (363M)

    dedup linux-2.6.32.tar.dd linux-2.6.32.tar

    linux-2.6.32.dd

    357325910 (341MB)

    dedup linux-2.6.32.dd linux-2.6.32/

    linux-2.6.32.tar.gz

    84322110 (81MB)

    gzip -c linux-2.6.32.tar > linux-2.6.32.tar.gz

    linux-2.6.32.tar.dd.gz

    83978234 (81MB)

    gzip -c linux-2.6.32.tar.dd > linux-2.6.32.tar.dd.gz

    linux-2.6.32.dd.gz

    83674306 (80MB)

    gzip -c linux-2.6.32.dd > linux-2.6.32.dd.gz 

        linux-2.6.32.tar.gz解压出来的kernel源码文件数据很多,使用这个文件来测试应该具有普遍的意义。通过初步的测试结果,我们可以看出,即使在这样不明确数据是否具备较高重复率的情况下,dedup技术也能较明显地减少数据包的数据量。在数据重复率很高的测试用例下,比如全0或全1的大文件,dedup要远远优于tar。比如,全0的64MB文件,tar+gzip的结果为65KB,而dedup的结果才有286字节。

    5、TODO
      1、变长数据块。目前是定长数据块的实现,技术上较为简单,变长数据块可能会获得更高的数据压缩率。
      2、相似文件识别。如果两个文件只有很小的差别,比如在某处插入了若干字节,找出这些数据块并单独处理,可能会提高数据压缩率。

    原文博客地址:

    http://blog.csdn.net/liuaigui/article/details/5166538

    (转)

  • 相关阅读:
    从网络得到图片数据保存到手机中,
    jni 写一个简单的photoshop
    rman catalog配置简要笔记
    如何利用c中的指针实现两个8bit的数合并为16bit
    使用eclipse远程调试weblogic
    迁移11g Rac中OCR和VOTEDISK
    SQL SERVER导入数据到ORACLE的方法总结
    SQL SERVER如何通过SQL语句获服务器硬件和系统信息
    ORACLE SQL Developer日期显示格式设置
    mysqldump:Couldn't execute 'show create table `tablename`': Table tablename' doesn't exist (1146)
  • 原文地址:https://www.cnblogs.com/qiaoyanlin/p/6820243.html
Copyright © 2011-2022 走看看