免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: wlmqgzm
打印 上一主题 下一主题

[C++] 读性能超过Memcached 65%, 单核也超过redis, 支持日志支持掉电保护,欢迎试用 [复制链接]

论坛徽章:
9
程序设计版块每日发帖之星
日期:2015-10-18 06:20:00程序设计版块每日发帖之星
日期:2015-11-01 06:20:00程序设计版块每日发帖之星
日期:2015-11-02 06:20:00每日论坛发贴之星
日期:2015-11-02 06:20:00程序设计版块每日发帖之星
日期:2015-11-03 06:20:00程序设计版块每日发帖之星
日期:2015-11-04 06:20:00程序设计版块每日发帖之星
日期:2015-11-06 06:20:00数据库技术版块每周发帖之星
日期:2015-12-02 15:02:47数据库技术版块每日发帖之星
日期:2015-12-08 06:20:00
71 [报告]
发表于 2016-05-27 09:33 |只看该作者
回复 69# windoze

这里没有memory management thread, 如果有的话, 可能是TCMalloc的. 但是前面也说了, TCMalloc多数情况下, 不需要与TCMalloc其他线程交互, 也不需要锁.

还是以简单的单生产者单消费者Wait_free_queue为例子, 这里永远只有2个线程, 代码中不存在第3个线程, 也不会创建第3个线程, 也没有第3个线程, 永远是单生产者线程负责内存的申请和释放, 只有这一个线程与内存申请释放有关, 消费者线程与内存管理毫无关系, 生产者线程 push代码内部申请本次push需要的小内存后, 有检查确认是否需要释放以前申请的内存; 未来第N次push的时候, 生产者线程在push代码内部检查代码判断符合条件, 释放这次申请的内存.  

Lock_free_queue内存管理设计的原则很简单, 就是: 哪个线程申请的内存, 由哪个线程负责释放, 不与其他线程协调.


   

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
72 [报告]
发表于 2016-05-27 09:54 |只看该作者
回复 70# wlmqgzm

想清楚再下结论,如果producer thread分配了一块内存,传递给了consumer thread去处理,按你“谁分配谁释放”的说法,producer thread什么时候才知道自己需要释放这块内存?无论如何得等到consumer处理完之后才行对不?那么producer怎么才能知道consumer处理完了?你总不能再建一个queue让consumer反过来通知producer吧。

按照你的设计,跨thread的内存管理不但不能避免,甚至还会加剧,TCMalloc根本就帮不上你什么忙。

其实你完全不需要解释的,你自己用strace看一下TCMalloc里加锁解锁的次数统计就知道了。

论坛徽章:
324
射手座
日期:2013-08-23 12:04:38射手座
日期:2013-08-23 16:18:12未羊
日期:2013-08-30 14:33:15水瓶座
日期:2013-09-02 16:44:31摩羯座
日期:2013-09-25 09:33:52双子座
日期:2013-09-26 12:21:10金牛座
日期:2013-10-14 09:08:49申猴
日期:2013-10-16 13:09:43子鼠
日期:2013-10-17 23:23:19射手座
日期:2013-10-18 13:00:27金牛座
日期:2013-10-18 15:47:57午马
日期:2013-10-18 21:43:38
73 [报告]
发表于 2016-05-27 10:07 |只看该作者
对于这种服务器应用,关注的应该是吞吐量而不是每笔响应时间,应在设计上尽量避免锁的竞争,提高并发能力。无锁实现往往会是一个坑,追求无锁意义不大。

论坛徽章:
36
子鼠
日期:2013-08-28 22:23:29黄金圣斗士
日期:2015-12-01 11:37:51程序设计版块每日发帖之星
日期:2015-12-14 06:20:00CU十四周年纪念徽章
日期:2015-12-22 16:50:40IT运维版块每日发帖之星
日期:2016-01-25 06:20:0015-16赛季CBA联赛之深圳
日期:2016-01-27 10:31:172016猴年福章徽章
日期:2016-02-18 15:30:3415-16赛季CBA联赛之福建
日期:2016-04-07 11:25:2215-16赛季CBA联赛之青岛
日期:2016-04-29 18:02:5915-16赛季CBA联赛之北控
日期:2016-06-20 17:38:50技术图书徽章
日期:2016-07-19 13:54:03程序设计版块每日发帖之星
日期:2016-08-21 06:20:00
74 [报告]
发表于 2016-05-27 10:13 |只看该作者
如果可以无锁,那当初锁就不会被设计出来。。

论坛徽章:
9
程序设计版块每日发帖之星
日期:2015-10-18 06:20:00程序设计版块每日发帖之星
日期:2015-11-01 06:20:00程序设计版块每日发帖之星
日期:2015-11-02 06:20:00每日论坛发贴之星
日期:2015-11-02 06:20:00程序设计版块每日发帖之星
日期:2015-11-03 06:20:00程序设计版块每日发帖之星
日期:2015-11-04 06:20:00程序设计版块每日发帖之星
日期:2015-11-06 06:20:00数据库技术版块每周发帖之星
日期:2015-12-02 15:02:47数据库技术版块每日发帖之星
日期:2015-12-08 06:20:00
75 [报告]
发表于 2016-05-27 10:42 |只看该作者
本帖最后由 wlmqgzm 于 2016-05-29 23:52 编辑

回复 72# windoze

producer thread什么时候才知道自己需要释放这块内存?
前面我说了, 一般人都绕不过这个弯子, 总觉得无法实现, 就是有一点点微创新, 以单生产者单消费者为例, 2个计数器就足够了, 为什么是2个, 是为了无等待






   

论坛徽章:
9
程序设计版块每日发帖之星
日期:2015-10-18 06:20:00程序设计版块每日发帖之星
日期:2015-11-01 06:20:00程序设计版块每日发帖之星
日期:2015-11-02 06:20:00每日论坛发贴之星
日期:2015-11-02 06:20:00程序设计版块每日发帖之星
日期:2015-11-03 06:20:00程序设计版块每日发帖之星
日期:2015-11-04 06:20:00程序设计版块每日发帖之星
日期:2015-11-06 06:20:00数据库技术版块每周发帖之星
日期:2015-12-02 15:02:47数据库技术版块每日发帖之星
日期:2015-12-08 06:20:00
76 [报告]
发表于 2016-05-29 23:14 |只看该作者
本帖最后由 wlmqgzm 于 2016-05-30 08:51 编辑

//  本段代码主要是压缩日期和时间为整数, 结合前面给出的整数压缩编码的方案, 可以用更少的字节数,  最终实现更高效率的存储
//  综合考虑,  如果直接使用日期和时间等各C++对象, 效率不高,, 最终还是要自己做代码来提高性能,
//  因此, 干脆直接全部使用自己的代码来实现, 总体上以效率为准

//  方案一: 年9999, 可以用2个字节,最大到65535,  月12用1个字节, 日31用一个字节, 这样总共4个字节, 中间不做转换,效率最高
//   通用代码来实现, 这样1个整数, 4个字节, 头2个字节就是年, 后1个字节就是月, 最后一个字节就是日, 简单的substr操作就可以.
//  方案二:  20160424整体作为整数, 除以10000就是年, 余数0424, 再除以100就是月4, 余数就是日24, 这个方案最大可表示20万年
//  方案三: 2016, 04, 24 整数=2016*12*31+4*31 + 24,   除以12*31=年份,余数部分除以31就是4月,余数就是24日,这个方案表示的年份最大
//  方案四: 直接用离1970/01/01的Unix日子来表示, 这个主要的优点是计算方便,可以不用转换,直接计算, 缺点是输出的时候(这个是最常用的功能), 计算比较繁琐,性能低
//  综合考虑下来, 就采用方案3来存放, 一般的大小比较可以直接比较,  其他的日期计算的就需要转化,

//  这里不得不用如此多的代码来实现的一个原因是: 对现有的代码表示的日期范围不满意
//  将一个字符串表示的日期, "20160120", "2016/1/29", "2016-1-24"这样类似的三种格式统一转化为一个32位的整数
//  最大可以表示11545611年, 即1154万年以后的情况
//  出错返回0, 其他返回一个大于零的整数
//  允许的日期从0000/01/01开始, 到11545611/12/31为止

  1. //  判断是否是闰年
  2. bool year_is_leap( unsigned int int_year )
  3. {
  4.   if( int_year%400==0 )   return true;
  5.   if( int_year%100==0 )   return false;
  6.   if( int_year%4==0 )       return true;
  7.   return false;
  8. }


  9. unsigned int string_to_uint_date( const std::string &str_in, std::string &str_error )
  10. {
  11.   unsigned int  uint_year;
  12.   unsigned int  uint_month;
  13.   unsigned int  uint_day;
  14.   std::string str_tmp;
  15.   std::string str_cmp;
  16.   std::vector<std::string>  vt_str_out;
  17.   std::string str_year;
  18.   std::string str_month;
  19.   std::string str_day;
  20.   std::vector<unsigned int>vt_int_day = {31,29,31,30,31,30,   31,31,30,31,30,31 };
  21.   std::vector<std::string>vt_str_month1 = { "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" };
  22.   std::vector<std::string>vt_str_month2 = { "JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC" };
  23.   bool bool_has_abc ;

  24.   str_error.clear();
  25.   unsigned int n = str_in.length();
  26.   if( n < 6 )  {
  27.     str_error   = str_in;
  28.     str_error += " is too short.";
  29.     return 0;
  30.     }

  31.   //  获得特殊字符, 存放到str_cmp;  可以支持- / _等情况
  32.   for( unsigned int i=0; i<n; ++i )  {
  33.     str_tmp = str_in.substr( i, 1 );
  34.     if( str_tmp>="0" && str_tmp<="9" )  continue;
  35.     str_cmp = str_tmp;
  36.     break;
  37.     }

  38.   //  检查是否存在字母
  39.   bool_has_abc = string_has_abc( str_in );
  40.   if( str_cmp.empty()  )  {  //  表示没有特殊字符隔离, 说明全部是数字
  41.     if( bool_has_abc )  {   //  如果没有特殊字符隔离又有字母, 出错
  42.       str_error   = str_in;
  43.       str_error += " has abc and no find - or /.";
  44.       return 0;
  45.       }
  46.     // 表示没有特殊字符隔离, 没有字母, 说明全部是数字
  47.     str_year = str_in.substr( 0, str_in.length()-4 );  //  保留除最后4位的就是年
  48.     str_month = str_in.substr( str_in.length()-4, 2 );  //  保留最后4位开始的2字节就是月
  49.     str_day = str_in.substr( str_in.length()-2, 2 );  // 最后2位是日
  50.     }
  51.   else  {
  52.     string_to_vector_string(  str_in,  str_cmp, vt_str_out  );
  53.     if(  vt_str_out.size()>3) {
  54.       str_error   = str_in;
  55.       str_error += " has too many data.";
  56.       return 0;
  57.       }
  58.     if( 3==vt_str_out.size() )  {
  59.       str_year = vt_str_out[0];
  60.       str_month = vt_str_out[1];
  61.       str_day = vt_str_out[2];
  62.       if( bool_has_abc )   {  //  如果有字母,  则转换字母月份到数字月份
  63.         for( unsigned int i=0, n=12; i<n; ++i )  {
  64.           if( vt_str_month1[i]  != str_month && vt_str_month2[i]  != str_month )  continue;
  65.           str_month = std::to_string( i+1 );
  66.           continue;
  67.           }
  68.         }
  69.       }
  70.     }

  71. if( str_year.empty() || str_year.length()>8  || !string_is_number( str_year )  )     {
  72.    str_error  = "str_in=";
  73.    str_error += str_in;
  74.    str_error +=  ", str_year=";
  75.    str_error += str_year;
  76.    str_error += ", year is bad.";
  77.    return 0;
  78.    }
  79. if( str_month.empty() || str_month.length()>2  || !string_is_number( str_month ) )     {
  80.    str_error  = "str_in=";
  81.    str_error += str_in;
  82.    str_error +=  ", str_month=";
  83.    str_error += str_month;
  84.    str_error += ", month is bad.";
  85.    return 0;
  86.    }
  87.   if( str_day.empty() || str_month.length()>2  || !string_is_number( str_day ) )     {
  88.    str_error  = "str_in=";
  89.    str_error += str_in;
  90.    str_error +=  ", str_day=";
  91.    str_error += str_day;
  92.    str_error += ", day is bad.";
  93.    return 0;
  94.    }

  95. uint_year = boost::lexical_cast<unsigned int>( str_year );
  96. if( uint_year>256L*256*256*256/12/31 )  {
  97.    str_error   = str_in;
  98.    str_error += ", year is error.";
  99.    return 0;
  100.    }
  101.   uint_month = boost::lexical_cast<unsigned int>( str_month );
  102.   if( uint_month<1 || uint_month>12 )  {
  103.     str_error   = str_in;
  104.     str_error += ", month is error.";
  105.     return 0;
  106.     }
  107.   uint_day = boost::lexical_cast<unsigned int>( str_day );
  108.   if( uint_day<1 || uint_day>31 )  {
  109.     str_error   = str_in;
  110.     str_error += ", day is error.";
  111.     return 0;
  112.     }

  113.   if( 2==uint_month )  {   //  处理特殊的2月
  114.     if( !year_is_leap( uint_year ) &&  uint_day==29 )  {  // 非闰年有29日的报错
  115.       str_error   = str_in;
  116.       str_error += ", day is error. not a leapyear. day can not be 29 in this month.";
  117.       return 0;
  118.       }
  119.     }
  120.   if( uint_day > vt_int_day[uint_month-1] ) {
  121.     str_error   = str_in;
  122.     str_error += ", day is error. max day in this month is ";
  123.     str_error += std::to_string( vt_int_day[uint_month-1] );
  124.     return 0;
  125.     }

  126.   return uint_year*12*31 + uint_month*31 + uint_day;
  127. }


  128. unsigned int ymd_to_uint_date( const unsigned int  uint_year,  const unsigned int  uint_month,  const unsigned int uint_day, std::string &str_error )
  129. {
  130.   std::vector<unsigned int>vt_int_day = {31,29,31,30,31,30,   31,31,30,31,30,31 };

  131.   if( uint_year>256L*256*256*256/12/31 )  {
  132.     str_error = "year is error. year=";
  133.     str_error += std::to_string( uint_year );
  134.     return 0;
  135.     }
  136.   if( uint_month<1 || uint_month>12 )  {
  137.     str_error = "month is error. month=";
  138.     str_error += std::to_string( uint_month );
  139.     return 0;
  140.     }
  141.   if( uint_day<1 || uint_day>31 )  {
  142.     str_error = "day is error. day=";
  143.     str_error += std::to_string( uint_day );
  144.     return 0;
  145.     }

  146.   if( 2==uint_month )  {   //  处理特殊的2月
  147.     if( !year_is_leap( uint_year ) &&  uint_day==29 )  {  // 非闰年有29日的报错
  148.       str_error = "day is error. not a leapyear. year=";
  149.       str_error += std::to_string( uint_year );
  150.       str_error += ", month=";
  151.       str_error += std::to_string( uint_month );
  152.       str_error += ", day=";
  153.       str_error += std::to_string( uint_day );
  154.       return 0;
  155.       }
  156.     }
  157.   if( uint_day > vt_int_day[uint_month-1] ) {
  158.     str_error = "day is error. max day in this month is ";
  159.     str_error += std::to_string( vt_int_day[uint_month-1] );
  160.     str_error += ", month=";
  161.     str_error += std::to_string( uint_month );
  162.     str_error += ", day=";
  163.     str_error += std::to_string( uint_day );
  164.     return 0;
  165.     }

  166.   return uint_year*12*31 + uint_month*31 + uint_day;
  167. }



  168. void uint_date_to_string( const unsigned int uint_date,  std::string &str_date )
  169. {
  170.   unsigned int  uint_year;
  171.   unsigned int  uint_month;
  172.   unsigned int  uint_day;
  173.   unsigned int  uint_excess;  //  余数
  174.   std::string  str_year;
  175.   std::string  str_month;
  176.   std::string  str_day;
  177.   std::string  str_tmp;

  178.   uint_year = uint_date / 372;  // 12*31=372
  179.   uint_excess = uint_date % 372;
  180.   uint_month = uint_excess / 31;
  181.   uint_day = uint_excess % 31;

  182.   str_year = std::to_string( uint_year );
  183.   str_month = std::to_string( uint_month );
  184.   str_day = std::to_string( uint_day );

  185.   /* std::cout << "str_year=" <<  str_year  << std::endl;
  186.   std::cout << "str_month=" <<  str_month  << std::endl;
  187.   std::cout << "str_day=" <<  str_day  << std::endl; */

  188.   while( str_year.length()<4 )  {
  189.     str_tmp = "0";
  190.     str_tmp += str_year;
  191.     str_year = str_tmp;
  192.     }
  193.   if( str_month.length()<2 )  {
  194.     str_tmp = "0";
  195.     str_tmp += str_month;
  196.     str_month = str_tmp;
  197.     }
  198.   if( str_day.length()<2 )  {
  199.     str_tmp = "0";
  200.     str_tmp += str_day;
  201.     str_day = str_tmp;
  202.     }
  203.   str_date = str_year ;
  204.   str_date += "-";
  205.   str_date += str_month;
  206.   str_date += "-";
  207.   str_date += str_day;
  208.   std::cout << str_date << std::endl << std::endl;
  209.   return;
  210. }


  211. void uint_date_to_ymd( const unsigned int uint_date,  unsigned int  &uint_year,  unsigned int  &uint_month,  unsigned int &uint_day  )
  212. {
  213.   unsigned int  uint_excess;  //  余数
  214.   std::string  str_year;
  215.   std::string  str_month;
  216.   std::string  str_day;
  217.   std::string  str_tmp;

  218.   uint_year = uint_date / 372;  // 12*31=372
  219.   uint_excess = uint_date % 372;
  220.   uint_month = uint_excess / 31;
  221.   uint_day = uint_excess % 31;
  222.   return;
  223. }


  224. //  将一个字符串转化为一个整数, 表示从00:00:00过的秒数
  225. unsigned int string_to_uint_time( const std::string &str_in, std::string &str_error )
  226. {
  227.   unsigned int  uint_hour;
  228.   unsigned int  uint_minute;
  229.   unsigned int  uint_second;
  230.   std::string str_tmp;
  231.   std::string str_cmp;
  232.   std::string str_hour;
  233.   std::string str_minute;
  234.   std::string str_second;
  235.   std::vector<std::string>  vt_str_out;

  236.   str_error.clear();
  237.   unsigned int n = str_in.length();
  238.   if( n < 6 )  {
  239.     str_error   = str_in;
  240.     str_error += " is too short.";
  241.     return 0;
  242.     }

  243.   //  获得特殊字符, 存放到str_cmp;  可以支持- / _等情况
  244.   for( unsigned int i=0; i<n; ++i )  {
  245.     str_tmp = str_in.substr( i, 1 );
  246.     if( str_tmp>="0" && str_tmp<="9" )  continue;
  247.     str_cmp = str_tmp;  //  获取第1个非数字的字符
  248.     break;
  249.     }

  250.   if( string_has_abc( str_in ) )  {   //  如果有字母, 出错
  251.     str_error   = str_in;
  252.     str_error += " , time must not have abc.";
  253.     return 0;
  254.     }
  255.   if( str_cmp.empty() )  {  //
  256.     str_hour = str_in.substr( 0, 2 );  //
  257.     str_minute = str_in.substr( 2, 2 );  //
  258.     str_second = str_in.substr( 4, 2 );  //
  259.     }
  260.   else  {
  261.     string_to_vector_string(  str_in,  str_cmp, vt_str_out  );
  262.     if(  vt_str_out.size()>3) {
  263.       str_error   = str_in;
  264.       str_error += " has too many data.";
  265.       return 0;
  266.       }
  267.     if( 3==vt_str_out.size() )  {
  268.       str_hour = vt_str_out[0];
  269.       str_minute = vt_str_out[1];
  270.       str_second = vt_str_out[2];
  271.       }
  272.     }

  273. if(  str_hour.length() != 2  || !string_is_number( str_hour )  )     {
  274.    str_error  = "str_in=";
  275.    str_error += str_in;
  276.    str_error +=  ", str_hour=";
  277.    str_error += str_hour;
  278.    str_error += ", hour is bad.";
  279.    return 0;
  280.    }
  281. if( str_minute.length() != 2  || !string_is_number( str_minute ) )     {
  282.    str_error  = "str_in=";
  283.    str_error += str_in;
  284.    str_error +=  ", str_minute=";
  285.    str_error += str_minute;
  286.    str_error += ", minute is bad.";
  287.    return 0;
  288.    }
  289.   if( str_second.length() != 2  || !string_is_number( str_second ) )     {
  290.    str_error  = "str_in=";
  291.    str_error += str_in;
  292.    str_error +=  ", str_second=";
  293.    str_error += str_second;
  294.    str_error += ", second is bad.";
  295.    return 0;
  296.    }

  297. std::cout << "hour=" << str_hour  << std::endl;
  298. std::cout << "minute=" << str_minute  << std::endl;
  299. std::cout << "second=" << str_second  << std::endl;

  300. uint_hour = boost::lexical_cast<unsigned int>( str_hour );
  301. if( uint_hour>23 )  {
  302.    str_error   = str_in;
  303.    str_error += ", hours must below 24.";
  304.    return 0;
  305.    }
  306.   uint_minute = boost::lexical_cast<unsigned int>( str_minute );
  307.   if( uint_minute>60 )  {
  308.     str_error   = str_in;
  309.     str_error += ", minutes must below 60.";
  310.     return 0;
  311.     }
  312.   uint_second = boost::lexical_cast<unsigned int>( str_second );
  313.   if( uint_second>60 )  {
  314.     str_error   = str_in;
  315.     str_error += ", seconds must below 60.";
  316.     return 0;
  317.     }

  318.   return uint_hour*3600 + uint_minute*60 + uint_second;
  319. }


  320. unsigned long string_to_ulong_datetime( const std::string &str_in, std::string &str_error )
  321. {
  322.   unsigned long ulong_date;
  323.   unsigned long ulong_time;
  324.   std::string  str_date;
  325.   std::string  str_time;
  326.   std::vector<std::string>  vt_str_out;
  327.   std::string str_cmp = " ";
  328.   string_to_vector_string(  str_in,  str_cmp, vt_str_out  );
  329.   if(  vt_str_out.size()>2) {
  330.     str_error   = str_in;
  331.     str_error += " has too many blank.";
  332.     return 0;
  333.     }
  334.   if( 2==vt_str_out.size() )  {
  335.     str_date = vt_str_out[0];
  336.     str_time = vt_str_out[1];
  337.     }
  338.   ulong_date = string_to_uint_date( str_date, str_error );
  339.   if( !str_error.empty() )  return 0;
  340.   ulong_time = string_to_uint_time( str_time, str_error );
  341.   if( !str_error.empty() )  return 0;
  342.   //ulong_ret = ulong_date * 86400L + ulong_time;
  343.   return ulong_date * 86400L + ulong_time;
  344. }


  345. void uint_time_to_string( const unsigned int uint_time,  std::string &str_time )
  346. {
  347.   unsigned int  uint_hour;
  348.   unsigned int  uint_minute;
  349.   unsigned int  uint_second;
  350.   unsigned int  uint_excess;  //  余数
  351.   std::string  str_hour;
  352.   std::string  str_minute;
  353.   std::string  str_second;
  354.   std::string  str_tmp;

  355.   uint_hour = uint_time / 3600;  // 12*31=372
  356.   uint_excess = uint_time % 3600;
  357.   uint_minute = uint_excess / 60;
  358.   uint_second = uint_excess % 60;

  359.   str_hour = std::to_string( uint_hour );
  360.   str_minute = std::to_string( uint_minute );
  361.   str_second = std::to_string( uint_second );

  362.   /* std::cout << "str_hour=" <<  str_hour  << std::endl;
  363.   std::cout << "str_minute=" <<  str_minute  << std::endl;
  364.   std::cout << "str_second=" <<  str_second  << std::endl; */

  365.   if( str_hour.length()<2 )  {
  366.     str_tmp = "0";
  367.     str_tmp += str_hour;
  368.     str_hour = str_tmp;
  369.     }
  370.   if( str_minute.length()<2 )  {
  371.     str_tmp = "0";
  372.     str_tmp += str_minute;
  373.     str_minute = str_tmp;
  374.     }
  375.   if( str_second.length()<2 )  {
  376.     str_tmp = "0";
  377.     str_tmp += str_second;
  378.     str_second = str_tmp;
  379.     }
  380.   str_time = str_hour;
  381.   str_time += ":";
  382.   str_time += str_minute;
  383.   str_time += ":";
  384.   str_time += str_second;
  385.   std::cout << str_time << std::endl << std::endl;
  386.   return;
  387. }


  388. void ulong_datetime_to_string( const unsigned long ulong_datetime,  std::string &str_datetime )
  389. {
  390.   //unsigned long ulong_date;
  391.   //unsigned long ulong_time;
  392.   unsigned int   uint_date;
  393.   unsigned int   uint_time;
  394.   std::string str_date;
  395.   std::string str_time;

  396.   uint_date  = ulong_datetime / 86400L;
  397.   uint_time  = ulong_datetime % 86400L;
  398.   uint_date_to_string( uint_date, str_date );
  399.   uint_time_to_string( uint_time, str_time );
  400.   str_datetime = str_date;
  401.   str_datetime += " ";
  402.   str_datetime += str_time;
  403.   return;
  404. }


  405. void uint_time_to_hms( const unsigned int uint_time,  unsigned int  &uint_hour, unsigned int  &uint_minute,  unsigned int  &uint_second )
  406. {
  407.   unsigned int  uint_excess;  //  余数
  408.   std::string  str_hour;
  409.   std::string  str_minute;
  410.   std::string  str_second;
  411.   std::string  str_tmp;

  412.   uint_hour = uint_time / 3600;  // 12*31=372
  413.   uint_excess = uint_time % 3600;
  414.   uint_minute = uint_excess / 60;
  415.   uint_second = uint_excess % 60;
  416.   return;
  417. }


  418. void ulong_datetime_to_ymdhms( const unsigned long ulong_datetime,
  419.   unsigned int  &uint_year,  unsigned int  &uint_month,  unsigned int &uint_day,
  420.   unsigned int  &uint_hour, unsigned int  &uint_minute,  unsigned int &uint_second )
  421. {
  422.   unsigned int   uint_date;
  423.   unsigned int   uint_time;

  424.   uint_date  = ulong_datetime / 86400L;
  425.   uint_time  = ulong_datetime % 86400L;

  426.   uint_date_to_ymd( uint_date, uint_year, uint_month, uint_day );
  427.   uint_time_to_hms( uint_time, uint_hour, uint_minute, uint_second );
  428.   return;
  429. }
复制代码

论坛徽章:
9
程序设计版块每日发帖之星
日期:2015-10-18 06:20:00程序设计版块每日发帖之星
日期:2015-11-01 06:20:00程序设计版块每日发帖之星
日期:2015-11-02 06:20:00每日论坛发贴之星
日期:2015-11-02 06:20:00程序设计版块每日发帖之星
日期:2015-11-03 06:20:00程序设计版块每日发帖之星
日期:2015-11-04 06:20:00程序设计版块每日发帖之星
日期:2015-11-06 06:20:00数据库技术版块每周发帖之星
日期:2015-12-02 15:02:47数据库技术版块每日发帖之星
日期:2015-12-08 06:20:00
77 [报告]
发表于 2016-05-29 23:46 |只看该作者
本帖最后由 wlmqgzm 于 2016-05-29 23:54 编辑

由于最终的版本将是一个支持大型数据库的存储层, 因此, 存储层的代码做的比较厚,不仅仅是一个KV数据库的存储层, 还是一个通用数据库存储层.
这样预计第一个版本的完成时间, 可能会延期, 但是, 毕竟是自己开发的完整软件, 早一点晚一点都无所谓, 就是希望代码能够尽量重用.

为了有效管理和压缩数据, 在存储层定义和实现了Field type,  支持下列字段类型.

enum field_type{
       field_type_unknow = 0,   
       field_type_bit,
       field_type_bool,  
       field_type_unsigned_tiny_int,
       field_type_tiny_int,
       field_type_enum,
       field_type_unsigned_smallint,
       field_type_smallint,
       field_type_unsigned_int,
       field_type_int,
       field_type_unsigned_bigint,  
       field_type_bigint,  
       field_type_float,
       field_type_double,
       field_type_decimal,
       field_type_chars,
       field_type_varchar,  
       field_type_tiny_txt,
       field_type_txt,
       field_type_medium_txt,
       field_type_big_txt,
       field_type_binary,
       field_type_varbinary,
       field_type_tiny_blob,
       field_type_blob,
       field_type_medium_blob,
       field_type_big_blob,
       field_type_date,   
       field_type_time,
       field_type_timestamp,  
       field_type_timestamp_usecond,  
       field_type_datetime,      
       field_type_datetime_usecond,  
       field_type_set
       };

论坛徽章:
9
程序设计版块每日发帖之星
日期:2015-10-18 06:20:00程序设计版块每日发帖之星
日期:2015-11-01 06:20:00程序设计版块每日发帖之星
日期:2015-11-02 06:20:00每日论坛发贴之星
日期:2015-11-02 06:20:00程序设计版块每日发帖之星
日期:2015-11-03 06:20:00程序设计版块每日发帖之星
日期:2015-11-04 06:20:00程序设计版块每日发帖之星
日期:2015-11-06 06:20:00数据库技术版块每周发帖之星
日期:2015-12-02 15:02:47数据库技术版块每日发帖之星
日期:2015-12-08 06:20:00
78 [报告]
发表于 2016-06-02 15:19 |只看该作者
本帖最后由 wlmqgzm 于 2016-06-02 19:08 编辑

继续做代码中, .......

线程规划情况:
线程数量= io_service 数量= CPU数量
在我的机器上, 网络层使用8个线程, 然后, 提供通用的命令接口层, 命令接口层是一个函数, 转换网络IO到内部函数, 然后指令被转发到 数据层.
网络层是Boost Asio的异步网络接口, 多线程驱动, 高并发设计.

数据层是多io_service 线程驱动的, 我的机器上8 线程(与前面的网络层共享= CPU数量), 默认有256个unordered_map, 每个线程管理8个unordered_map, 之所以分开为256个unordered_map,
主要是为了解决unordered_map的自动扩展时, 会有大量的拷贝, 分开256个以后, 一次扩展拷贝数据的数量就少, 性能抖动小,
其次, 由于每个map都是单线程驱动的, 因此, map的读写不需要加锁
数据层对网络层提供多个io_service 命令和多个 线程间队列,作为接口,  一起驱动数据查询, 数据更新, 数据增加, 数据删除, 操作全部是在unordered_map.
因此, 数据层是高并发的, 并发量=CPU数量  数据层其实是数据索引层,  查询Key得到的只是Global_offset, 还没有得到数据, 后面要进入File_mapping层去存取数据,
数据层的特点是全并发
数据层unordered_map 的的第2个参数是Global Offset, 64bit, 通过计算变换, 得到文件名, 文件offset, 就可以进入file_mapping_read层进行查询. 读查询是直接采用数据层的线程直接读的, 读是全并发的,

File_mapping层主要实现文件数据的缓冲, 分解为read和write这两种对象, 实行读写分离, 读并发无限制, 写不能并发, 其中file_mapping_read是一组多个对象, 每个对象都代表了一个文件, 每个文件都可以同时被所有线程同时并发读,  
file_mapping_write是单对象, 由单线程驱动, 与其他线程之间, 通过Wait_free_mpsc_queue接收写指令, 然后写入后, 其他线程再通过反向的io_service.post调用获得驱动,
File_mapping_write默认是每秒刷新到磁盘一次, 可调可取消, 也可设置为每N个write刷新到磁盘.

以上就是本次设计的主要思路, 都是基于高并发的设计.
个人觉得, 代码中几个设计都是比较好的.
一个是file_mapping层读写分离(写单线程驱动)的设计思路, 堪称经典, 对比mongodb的一把大锁走天下的设计, 并发要好很多.
一个是数据层分开为多个map的设计, 每个map单线程的驱动方式, 对比redis的单线程, 和map扩展, 并发好很多.
一个是file_mapping层的顺序写数据结构设计, 对比monggodb的到处随机写, 更适合SSD.
一个是实现了任意对象的Wait_free_queue的设计代码,可作为Boost库的补充.


论坛徽章:
0
79 [报告]
发表于 2016-06-03 16:52 |只看该作者
mark一下lollol

论坛徽章:
9
程序设计版块每日发帖之星
日期:2015-10-18 06:20:00程序设计版块每日发帖之星
日期:2015-11-01 06:20:00程序设计版块每日发帖之星
日期:2015-11-02 06:20:00每日论坛发贴之星
日期:2015-11-02 06:20:00程序设计版块每日发帖之星
日期:2015-11-03 06:20:00程序设计版块每日发帖之星
日期:2015-11-04 06:20:00程序设计版块每日发帖之星
日期:2015-11-06 06:20:00数据库技术版块每周发帖之星
日期:2015-12-02 15:02:47数据库技术版块每日发帖之星
日期:2015-12-08 06:20:00
80 [报告]
发表于 2016-06-11 17:17 |只看该作者
本帖最后由 wlmqgzm 于 2016-06-11 17:28 编辑

// TODO: field id下推到底的优化: 考虑字段 field_id目前是4字节, 每一行数据都包含, 如果一行数据有32个字段, 那么就是128字节, 这个浪费量也很惊人.
// 每个块如果包含250行, 那么就是32K字节浪费, 因此, 考虑修改底层行编码的格式:
//  就是每1----250行一个块, 每个块的开始要包含数据字段的定义, 主要是Not NULLfield, 这样每行数据将变为2种数据的组合, 一个部分是非空字段的定义, 一个空字段的定义.
//  非空字段在块开头定义了每个字段的id(4字节), 类型1字节, 默认值长度 , 默认值, 字段编号num1字节,   
//  在行中:字段编号num1字节,字段长度为压缩整数1-5字节, 字段内容
//  进一步利用默认值进行压缩: 当压缩整数第1字节表示长度的长度=255时,表示=默认值,无需字段内容,可再压缩. 即  =默认值的字段,  被压缩到2个字节, 无字段内容
//  对于NULL field, 那么还是要下推到底的, 因为这些field是可以不存在的, 对于空字段,实际占用空间=0, 其他情况, 在行中:字段id 4字节,类型1字节,长度的长度1字节, 长度0-4字节,字段内容
//  考虑IO是主要瓶颈, 宁可利用CPU的资源来减少, 因此, 这部分的设计还在继续修改, 以便提供更高的效率.

Not NULL Field高效率存储, 不需要在每行都定义, 等于默认值的field被压缩到2个字节,    NULL Field有数据的情况下,在行中定义, 字段Filed_id下推到底, 无数据的话不占空间.
程序中的块定义越来越复杂了, 但是主要目的是为了尽可能的实现更先进的结构
总之,上面的改进就是结合了innodb和NOSQL的数据结构的优点.
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP