基于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. return ret;
  239. }
  240. void usage()
  241. {
  242. printf("Usage:  dedup [OPTION...] <target file> <source files ...>/n");
  243. printf("/nPackage files with deduplicaton technique./n");
  244. printf("Mandatory arguments to long options are mandatory for short options too./n");
  245. printf("  -z, --compress   filter the archive through compress/n");
  246. printf("  -b, --block      block size for deduplication, default is 4096/n");
  247. printf("  -t, --hashtable  hashtable backet number, default is 10240/n");
  248. printf("  -d, --debug      print debug messages/n");
  249. printf("  -h, --help       give this help list/n");
  250. printf("/nReport bugs to <[email protected]>./n");
  251. }
  252. int main(int argc, char *argv[])
  253. {
  254. char tmp_file[] = "./.dedup/0";
  255. int bz = 0, bhelp = 0, bdebug = 0;
  256. int ret = -1, c;
  257. struct option longopts[] =
  258. {
  259. {"compress", 0, &bz, ‘z‘},
  260. {"block", 1, 0, ‘b‘},
  261. {"hashtable", 1, 0, ‘t‘},
  262. {"debug", 0, &bdebug, ‘d‘},
  263. {"help", 0, &bhelp, ‘h‘},
  264. {0, 0, 0, 0}
  265. };
  266. /* parse options */
  267. while ((c = getopt_long (argc, argv, "zb:t:dh", longopts, NULL)) != EOF)
  268. {
  269. switch(c)
  270. {
  271. case ‘z‘:
  272. bz = 1;
  273. break;
  274. case ‘b‘:
  275. g_block_size = atoi(optarg);
  276. break;
  277. case ‘t‘:
  278. g_htab_backet_nr = atoi(optarg);
  279. break;
  280. case ‘d‘:
  281. bdebug = 1;
  282. break;
  283. case ‘h‘:
  284. case ‘?‘:
  285. default:
  286. bhelp = 1;
  287. break;
  288. }
  289. }
  290. if (bhelp == 1 || (argc - optind) < 2)
  291. {
  292. usage();
  293. return 0;
  294. }
  295. if (bz)
  296. {
  297. /* dedup and compress */
  298. ret = dedup_package(argc - optind -1 , argv + optind + 1, tmp_file, bdebug);
  299. if (ret == 0)
  300. {
  301. ret = zlib_compress_file(tmp_file, argv[optind]);
  302. unlink(tmp_file);
  303. }
  304. }
  305. else
  306. {
  307. /* dedup only */
  308. ret = dedup_package(argc - optind - 1, argv + optind + 1, argv[optind], bdebug);
  309. }
  310. return ret;
  311. }

/* 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. if (read(fd, &dedup_entry_hdr, DEDUP_ENTRYHDR_SIZE) != DEDUP_ENTRYHDR_SIZE)
  115. {
  116. ret = errno;
  117. break;
  118. }
  119. ret = undedup_regfile(fd, dedup_entry_hdr, dest_dir, debug);
  120. if (ret != 0)
  121. break;
  122. offset += DEDUP_ENTRYHDR_SIZE;
  123. offset += dedup_entry_hdr.path_len;
  124. offset += dedup_entry_hdr.block_num * dedup_entry_hdr.entry_size;
  125. offset += dedup_entry_hdr.last_block_size;
  126. }
  127. _UNDEDUP_PKG_EXIT:
  128. close(fd);
  129. return ret;
  130. }
  131. void usage()
  132. {
  133. printf("Usage:  undedup [OPTION...] <source file>/n");
  134. printf("/nUnpackage files with deduplicaton technique./n");
  135. printf("Mandatory arguments to long options are mandatory for short options too./n");
  136. printf("  -z, --uncompress  filter the archive through uncompress/n");
  137. printf("  -c, --directory   change to directory, default is PWD/n");
  138. printf("  -d, --debug       print debug messages/n");
  139. printf("  -h, --help        give this help list/n");
  140. printf("/nReport bugs to <[email protected]>./n");
  141. }
  142. int main(int argc, char *argv[])
  143. {
  144. char tmp_file[] = "./.dedup/0";
  145. char path[MAX_PATH_LEN] = "./0";
  146. int bz = 0, bhelp = 0, bdebug = 0;
  147. int ret = -1, c;
  148. struct option longopts[] =
  149. {
  150. {"compress", 0, &bz, ‘z‘},
  151. {"directory", 1, 0, ‘c‘},
  152. {"debug", 0, &bdebug, ‘d‘},
  153. {"help", 0, &bhelp, ‘h‘},
  154. {0, 0, 0, 0}
  155. };
  156. while ((c = getopt_long (argc, argv, "zc:dh", longopts, NULL)) != EOF)
  157. {
  158. switch(c)
  159. {
  160. case ‘z‘:
  161. bz = 1;
  162. break;
  163. case ‘c‘:
  164. sprintf(path, "%s", optarg);
  165. break;
  166. case ‘d‘:
  167. bdebug = 1;
  168. break;
  169. case ‘h‘:
  170. case ‘?‘:
  171. default:
  172. bhelp = 1;
  173. break;
  174. }
  175. }
  176. if (bhelp == 1 || (argc - optind) < 1)
  177. {
  178. usage();
  179. return 0;
  180. }
  181. if (bz)
  182. {
  183. /* uncompress and undedup */
  184. ret = zlib_decompress_file(argv[optind], tmp_file);
  185. if (ret == 0)
  186. {
  187. ret = undedup_package(tmp_file, path, bdebug);
  188. unlink(tmp_file);
  189. }
  190. }
  191. else
  192. {
  193. /* only undedup */
  194. ret = undedup_package(argv[optind], path, bdebug);
  195. }
  196. return ret;
  197. }

/* 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

(转)

时间: 2024-08-25 07:24:59

基于Dedup的数据打包技术的相关文章

客户端技术的一点思考(数据存储用SQLite, XMPP通讯用Gloox, Web交互用LibCurl, 数据打包用Protocol Buffer, socket通讯用boost asio)

今天看到CSDN上这么一篇< 彻底放弃没落的MFC,对新人的忠告!>, 作为一个一直在Windows上搞客户端开发的C++程序员,几年前也有过类似的隐忧(参见 落伍的感觉), 现在却有一些不同的想法. 首先,个人职业发展是否成功, 技术只是其中一小块,尤其是在大公司, 更多的是依靠所谓的软实力.作为一个对技术有追求的工匠,我们下面重点说技术相关的. 现在回头看计算机行业的发展,我们看到不同的发展阶段: 1. PC时代,这个时代离我们并不遥远, 也有是2000年前后, 该时代最鲜明的特征是Win

(转)基于RTP的H264视频数据打包解包类

最近考虑使用RTP替换原有的高清视频传输协议,遂上网查找有关H264视频RTP打包.解包的文档和代码.功夫不负有心人,找到不少有价值的文档和代码.参考这些资料,写了H264 RTP打包类.解包类,实现了单个NAL单元包和FU_A分片单元包.对于丢包处理,采用简单的策略:丢弃随后的所有数据包,直到收到关键帧.测试效果还不错,代码贴上来,若能为同道中人借鉴一二,足矣.两个类的使用说明如下(省略了错误处理过程): DWORD H264SSRC ; CH264_RTP_PACK pack ( H264S

基于 request cache 请求缓存技术优化批量商品数据查询接口_一点课堂(多岸学院)

基于 request cache 请求缓存技术优化批量商品数据查询接口 Hystrix command 执行时 8 大步骤第三步,就是检查 Request cache 是否有缓存. 首先,有一个概念,叫做 Request Context 请求上下文,一般来说,在一个 web 应用中,如果我们用到了 Hystrix,我们会在一个 filter 里面,对每一个请求都施加一个请求上下文.就是说,每一次请求,就是一次请求上下文.然后在这次请求上下文中,我们会去执行 N 多代码,调用 N 多依赖服务,有的

NoSQL数据建模技术

原文来自“NoSQL Data Modeling Techniques”,由酷壳网陈皓编译<NoSQL数据建模技术>.这篇文章看完之后,你可能会对NoSQL的数据结构会有些感觉.我的感觉是,关系型数据库想把一致性,完整性,索引,CRUD都干好,NoSQL只干某一种事,但是牺牲了很多别的东西.总体来说,我觉得NoSQL更适合做Cache. 下面是正文: NoSQL数据库经常被用作很多非功能性的地方,如,扩展性,性能和一致性的地方.这些NoSQL的特性在理论和实践中都正在被大众广泛地研究着,研究的

基于SSH2+Maven+EasyUI+MySQL技术实战开发易买网电子商务交易平台【课程分享】

链接:http://pan.baidu.com/share/link?shareid=1334596560&uk=3611155194 密码:ffna 对这个课程有兴趣的朋友可以加我的QQ2059055336和我联系 课程讲师:IT小生 课程分类:Java 适合人群:中级 课时数量:52课时 用到技术:Hibernate.Struts.Spring.Maven.EasyUI 涉及项目:易买网电子商务 更新程度:完毕 一.易买网前台部分讲解: 第一讲: Maven初体验 第二讲:Maven打包测试

NoSQL 数据建模技术(转)

本文转载自:http://coolshell.cn/articles/7270.html ================================================ 全文译自墙外文章"NoSQL Data Modeling Techniques",译得不好,还请见谅.这篇文章看完之后,你可能会对NoSQL的数据结构会有些感觉.我的感觉是,关系型数据库想把一致性,完整性,索引,CRUD都干好,NoSQL只干某一种事,但是牺牲了很多别的东西.总体来说,我觉得NoSQL

一种基于HBase韵海量图片存储技术

针对海量图片存储,已有若干个基于Hadoop的方案被设计出来.这些方案在系统层小文件合并.全局名字空间以及通用性方面存在不足.本文基于HBase提出了一种海量图片存储技术,成功解决了上述问题.本文将介绍基于HBase海量图片存储技术方案,分析其原理及优势,该方案在城市交通监控中得到应用验证. 随着互联网.云计算及大数据等信息技术的发展,越来越多的应用依赖于对海量数据的存储和处理,如智能监控.电子商务.地理信息等,这些应用都需要对海量图片的存储和检索.由于图片大多是小文件(80%大小在数MB以内)

禧云数芯大数据平台技术白皮书

白皮书作者:赵兴申 顾问:郑昀 出品方:禧云集团-基础技术中心-大数据与算法部 数据分析组:谭清勇.王明军.徐蕊.曹寿波 平台开发组:刘永飞.李喜延 数据可视化组:陈少明.董建昌 基础架构组:崔明黎.邱志伟.陈赏 第一章:数芯大数据平台 1.1 禧云大数据发展历程 知名咨询公司麦肯锡称:『数据,已经渗透到当今每一个行业和业务职能领域,成为重要的生产因素.人们对海量数据的挖掘和运用,预示着新一波生产率增长和消费盈余浪潮的到来.』良好的数据管理和处理技术,已经成为企业不可或缺的竞争优势. 禧云集团(

无线传感器网络数据融合技术

http://www.dzsc.com/data/html/2008-11-28/73975.html 由于大多数无线传感器网络应用都是由大量传感器节点构成的,共同完成信息收集.目标监视和感知环境的任务.因此,在信息采集的过程中,采用各个节点单独传输数据到汇聚节点的方法显然是不合适的.因为网络存在大量冗余信息,这样会浪费大量的通信带宽和宝贵的能量资源.此外,还会降低信息的收集效率,影响信息采集的及时性. 为避免上述问题,人们采用了一种称为数据融合(或称为数据汇聚)的技术.所谓数据融合是指将多份数