网络数据同步开发库libsync

本文介绍了一种改进的数据同步算法,并将其封装为libsync动态函数库,用于文件切分、差异编码与同步操作。提供了三种文件切分算法:定长切分、内容定义切分和滑动块切分,以及差异编码与文件同步功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

"数据同步算法研究"一文提出了一种改进的数据同步算法,我在实现的原型系统基础上,将文件切分、差异编码、文件同步等关键算法抽取出来封装成动态开发库libsync,方便自己的开发应用。在本人开发的deduputil,WSIO, wsync等软件中,均使用了libsync动态函数库,现已将libsync发布至google code。libsync函数库由提供三个API,原型描述如下:

1、int file_chunk(char *src_filename, char *chunk_filename, int chunk_algo)
功能:对件进行切分生成分块描述文件。
参数:src_filename为切分文件,chunk_filename为生成的块信息描述文件,chunk_algo为文件切分算法,目前支持定长FSP切分(Ffixed-size partition)、CDC切分(content-defined chunking)和滑动块(sliding block)切分三种。

2、int file_delta(char *src_filename, char *chunk_filename, char *delta_filename, int chunk_algo)
功能:使用生成的块描述信息对文件进行差异编码。
参数:src_filename为待编码文件,chunk_filename为通过函数file_chunk生成的块描述文件,chunk_algo为文件切分算法。

3、int file_sync(char *src_filename, char *delta_filename)
功能:使用差异编码文件将源文件同步至目标文件。
参数:src_filename为基本文件,delta_filename为通过函数file_delta生成的差异编码文件。

  1. /* 
  2.   Copyright (C) 2010, Aigui Liu 
  3.                                                                                                     
  4.   Filename: sync.h 
  5.   Author: Aigui.Liu@gmail.com 
  6.  */  
  7. #ifndef _SYNC_H  
  8. #define _SYNC_H  
  9. #include <stdint.h>  
  10. #define BLOCK_SZ        2048  
  11. #define BLOCK_MIN_SZ    1024  
  12. #define BLOCK_MAX_SZ    4096  
  13. #define BLOCK_WIN_SZ    48  
  14. #define NAME_MAX_SZ     256  
  15. #define BUF_MAX_SZ      32768  
  16. #define HASHTABLE_BUCKET_SZ 1024  
  17. #define CHUNK_CDC_D     BLOCK_SZ  
  18. #define CHUNK_CDC_R     13  
  19. enum chunk_algo {  
  20.     CHUNK_FSP = 0,  /* fixed-size partition */  
  21.     CHUNK_CDC,      /* content-define chunking */  
  22.     CHUNK_SBC       /* slide block chunking */  
  23. };  
  24. /* define chunk file header and block entry */  
  25. typedef struct _chunk_file_header {  
  26.     uint32_t block_sz;  
  27.     uint32_t block_nr;  
  28. } chunk_file_header;  
  29. #define CHUNK_FILE_HEADER_SZ    (sizeof(chunk_file_header))  
  30. typedef struct _chunk_block_entry {  
  31.     uint64_t offset;  
  32.     uint32_t len;  
  33.     uint8_t  md5[16 + 1];  
  34.     uint8_t  csum[10 + 1];  
  35. } chunk_block_entry;  
  36. #define CHUNK_BLOCK_ENTRY_SZ    (sizeof(chunk_block_entry))  
  37. /* define delta file header and block entry */  
  38. typedef struct _delta_file_header {  
  39.     uint32_t block_nr;  
  40.     uint32_t last_block_sz;  
  41.     uint64_t last_block_offset;  /* offset in delta file */  
  42. } delta_file_header;  
  43. #define DELTA_FILE_HEADER_SZ    (sizeof(delta_file_header))  
  44. typedef struct _delta_block_entry {  
  45.     uint64_t offset;  
  46.     uint32_t len;  
  47.     uint8_t  embeded; /* 1, block in delta file; 0, block in source file. */  
  48. } delta_block_entry;  
  49. #define DELTA_BLOCK_ENTRY_SZ    (sizeof(delta_block_entry))  
  50. int file_chunk(char *src_filename, char *chunk_filename, int chunk_algo);  
  51. int file_delta(char *src_filename, char *chunk_filename, char *delta_filename, int chunk_algo);  
  52. int file_sync(char *src_filename, char *delta_filename);  
  53. #endif  

数据同步有PULL和PUSH两种应用模式,PULL是将远程数据同步到本地,而PUSH是将本地数据同步到远程。对应到同步算法,主要区别在于数据分块和差异编码位置不同。PULL和PUSH同步模式步骤分别如下所述。

PULL同步模式流程:
1、本地对文件A进行数据切分,生成数据块描述文件chunk;
2、上传chunk文件至远程服务器;
3、远程服务器对文件B进行差异编码,生成差异编码文件delta;
4、下载delta文件至本地;
5、本地同步文件A至文件B,相当于下载文件B到本地文件A。

例子程序:

  1. /* 
  2.   Copyright (c) 2010, Aigui Liu 
  3.   All rights reserved. 
  4.   
  5.   Filename: wspull.c  
  6.   Author: Aigui.Liu@gmail.com 
  7. */  
  8. #include <stdio.h>  
  9. #include <stdlib.h>  
  10. #include <string.h>  
  11. #include <fcntl.h>  
  12. #include <unistd.h>  
  13. #include "wsioclient.h"  
  14. #include "wsio_api.h"  
  15. #include "sync.h"  
  16. /* main function */  
  17. int main(int argc, char **argv)  
  18. {   
  19.     char fap[32] = {0};  
  20.     char server[256] = {0};  
  21.     char *local_filename = NULL;  
  22.     char remote_filename[256] = {0};  
  23.     char local_chunkname[256] = {0};  
  24.     char remote_chunkname[256] = {0};  
  25.     char local_deltaname[256] = {0};  
  26.     char remote_deltaname[256] = {0};  
  27.     int ret = 0;  
  28.     if (argc < 3) {   
  29.         fprintf(stderr, "Usage: wspull remote_filename local_filename/n");  
  30.         exit(0);  
  31.     }  
  32.     
  33.     if(argv[1]) {  
  34.         if(parseURL(argv[1], fap, server, remote_filename) == -1) {  
  35.             fprintf(stderr, "wsio address is illegal/n");  
  36.             exit(1);  
  37.         }  
  38.     }  
  39.     wsio_init(fap, server);  
  40.     local_filename = argv[2];  
  41.     if (0 == access(local_filename, F_OK)) {  
  42.         sprintf(local_chunkname, "%s_%d", tmpnam(NULL), getpid());  
  43.         sprintf(remote_chunkname, "%s_%d", tmpnam(NULL), getpid());  
  44.         sprintf(local_deltaname, "%s_%d", tmpnam(NULL), getpid());  
  45.         sprintf(remote_deltaname, "%s_%d", tmpnam(NULL), getpid());  
  46.         ret = file_chunk(local_filename, local_chunkname, CHUNK_CDC);  
  47.         if (ret == -1) {  
  48.             fprintf(stderr, "local file chunking failed/n");  
  49.             return -1;  
  50.         }  
  51.         ret = wsio_putfile(local_chunkname, remote_chunkname);  
  52.         if (ret == -1) {  
  53.             fprintf(stderr, "upload chunking file failed/n");  
  54.             return -1;  
  55.         }  
  56.         ret = wsio_deltafile(remote_filename, remote_chunkname, remote_deltaname, CHUNK_CDC);  
  57.         if (ret == -1) {  
  58.             fprintf(stderr, "remote file delta coding failed/n");  
  59.             return -1;  
  60.         }  
  61.         ret = wsio_getfile(remote_deltaname, local_deltaname);  
  62.         if (ret == -1) {  
  63.             fprintf(stderr, "download delta file failed/n");  
  64.         }  
  65.         ret = file_sync(local_filename, local_deltaname);  
  66.         if (ret == -1) {  
  67.             fprintf(stderr, "local file sync failed/n");  
  68.             return -1;  
  69.         }  
  70.     } else {  
  71.         ret = wsio_getfile(remote_filename, local_filename);  
  72.         if (ret == -1) {  
  73.             fprintf(stderr, "download file failed/n");  
  74.             return -1;  
  75.         }  
  76.     }  
  77.     wsio_unlink(remote_chunkname);  
  78.     wsio_unlink(remote_deltaname);  
  79.     unlink(local_chunkname);  
  80.     unlink(local_deltaname);  
  81.     wsio_destroy();  
  82.     fprintf(stderr, "pull %s to %s %s/n", argv[1], local_filename, (ret == 0)? "sucessfully" : "failed");  
  83.     return 0;  
  84. }  
 

PUSH同步模式流程:
1、远程服务器对文件B进行数据切分,生成数据块描述文件chunk;
2、下载chunk文件至本地;
3、本地对文件A进行差异编码,生成差异编码文件delta;
4、上传delta文件至远程服务器;
5、远程同步文件B到A,相当于上传文件A到远程文件B。

例子程序:

  1. /* 
  2.   Copyright (c) 2010, Aigui Liu 
  3.   All rights reserved. 
  4.   
  5.   Filename: wspush.c  
  6.   Author: Aigui.Liu@gmail.com 
  7. */  
  8. #include <stdio.h>  
  9. #include <stdlib.h>  
  10. #include <string.h>  
  11. #include <fcntl.h>  
  12. #include <unistd.h>  
  13. #include "wsioclient.h"  
  14. #include "wsio_api.h"  
  15. #include "sync.h"  
  16. /* main function */  
  17. int main(int argc, char **argv)  
  18. {   
  19.     char fap[32] = {0};  
  20.     char server[256] = {0};  
  21.     char remote_filename[256] = {0};  
  22.     char *local_filename = NULL;  
  23.     char local_chunkname[256] = {0};  
  24.     char remote_chunkname[256] = {0};  
  25.     char local_deltaname[256] = {0};  
  26.     char remote_deltaname[256] = {0};  
  27.     int ret = 0;  
  28.     if (argc < 3) {   
  29.         fprintf(stderr, "Usage: wspush local_filename remote_filename/n");  
  30.         exit(0);  
  31.     }  
  32.     
  33.     if(argv[2]) {  
  34.         if(parseURL(argv[2], fap, server, remote_filename) == -1) {  
  35.             fprintf(stderr, "wsio address is illegal/n");  
  36.             exit(1);  
  37.         }  
  38.     }  
  39.     wsio_init(fap, server);  
  40.     local_filename = argv[1];  
  41.     if (0 == wsio_access(remote_filename, F_OK)) {  
  42.         sprintf(local_chunkname, "%s_%d", tmpnam(NULL), getpid());  
  43.         sprintf(remote_chunkname, "%s_%d", tmpnam(NULL), getpid());  
  44.         sprintf(local_deltaname, "%s_%d", tmpnam(NULL), getpid());  
  45.         sprintf(remote_deltaname, "%s_%d", tmpnam(NULL), getpid());  
  46.         ret = wsio_chunkfile(remote_filename, remote_chunkname, CHUNK_CDC);  
  47.         if (ret == -1) {  
  48.             fprintf(stderr, "remote file chunking failed/n");  
  49.             return -1;  
  50.         }  
  51.         ret = wsio_getfile(remote_chunkname, local_chunkname);  
  52.         if (ret == -1) {  
  53.             fprintf(stderr, "download chunking file failed/n");  
  54.             return -1;  
  55.         }  
  56.         ret = file_delta(local_filename, local_chunkname, local_deltaname, CHUNK_CDC);  
  57.         if (ret == -1) {  
  58.             fprintf(stderr, "local file delta coding failed/n");  
  59.             return -1;  
  60.         }  
  61.         ret = wsio_putfile(local_deltaname, remote_deltaname);  
  62.         if (ret == -1) {  
  63.             fprintf(stderr, "upload delta file failed/n");  
  64.         }  
  65.         ret = wsio_syncfile(remote_filename, remote_deltaname);  
  66.         if (ret == -1) {  
  67.             fprintf(stderr, "remote file sync failed/n");  
  68.             return -1;  
  69.         }  
  70.     } else {  
  71.         ret = wsio_putfile(local_filename, remote_filename);  
  72.         if (ret == -1) {  
  73.             fprintf(stderr, "upload file failed/n");  
  74.             return -1;  
  75.         }  
  76.     }  
  77.     wsio_unlink(remote_chunkname);  
  78.     wsio_unlink(remote_deltaname);  
  79.     unlink(local_chunkname);  
  80.     unlink(local_deltaname);  
  81.     wsio_destroy();  
  82.     fprintf(stderr, "push %s to %s %s/n", local_filename, remote_filename, (ret == 0)? "sucessfully" : "failed");  
  83.     return 0;  
  84. }  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值