crush_do_rule中,用了一个scratch空间来完成item的搜索。

scratch空间总共有3个max_result这么大,并且按照max_result长度划分为三个部分(下图中的a、b、c,其中c只在recursive_to_leaf时用到,本文不涉及)。

a、b两个部分就用来生成result。a、b两个部分分别由o、w两个数组指针来指向,在每完成一个select step后,o、w互换指向的位置,上一次的o将变成本次的w,成为本次step遍历的对象,而上次的w将变成本次的o用于存放本次step的output items。

以Sage Weil论文中的例子来演示此过程:

take(root)   ->root

select(1, row) ->row2   //图例step1

select(3, cabinet)  ->cab21 cab23 cab24   //图例step2

select(1, disk)  ->disk2107 disk2313 disk2437  //图例step3

emit    //图例step4 (从scratch数组中将选中的item拷贝到result数组中)

简化后的骨干代码如下:

1、省略了itemid的合法性校验代码

2、仅考虑firstn的情况(即仅考虑replica策略)

3、不考虑recursive_to_leaf的情况(此为工程优化,非Sage Weil论文的核心内容)

  1. int crush_do_rule(const struct crush_map *map,
  2. int ruleno, int x, int *result, int result_max,
  3. const __u32 *weight, int weight_max,
  4. int *scratch)
  5. {
  6. int osize, wsize = ;
  7. int *w, *o;
  8. w = scratch;
  9. o = scratch + result_max;
  10.  
  11. struct crush_rule *rule = map->rules[ruleno];
  12.  
  13. for (__u32 step = ; step < rule->len; step++) {
  14. struct crush_rule_step *curstep = &rule->steps[step];
  15.  
  16. switch (curstep->op) {
  17. case CRUSH_RULE_TAKE:
  18. w[] = curstep->arg1;
  19. wsize = ;
  20. break;
  21.  
  22. //Elar:
  23. //1. only consider fistn's situation
  24. //2. ignore recurse_to_leaf situation
  25. case CRUSH_RULE_CHOOSELEAF_FIRSTN:
  26. case CRUSH_RULE_CHOOSE_FIRSTN:
  27.  
  28. /* reset output */
  29. osize = ;
  30. for (int i = ; i < wsize; i++) {
  31. int numrep = curstep->arg1;
  32. int outpos = ;
  33.  
  34. int type = curstep->arg2;
  35. int bno = - - w[i];//Elar: get bucketId
  36. struct crush_bucket *bucket = map->buckets[bno];
  37. osize += crush_choose_firstn(map, bucket, weight, weight_max, x, numrep, type, o+osize, outpos);
  38. }
  39.  
  40. /* swap o and w arrays */
  41. int *tmp = o; o = w; w = tmp;
  42. wsize = osize;
  43. break;
  44.  
  45. case CRUSH_RULE_EMIT:
  46. int i = ;
  47. result_len = ;
  48. for (; i < wsize && result_len < result_max; i++) {
  49. result[result_len] = w[i];
  50. result_len++;
  51. }
  52. wsize = ;
  53. break;
  54.  
  55. default:
  56. break;
  57. }
  58. }
  59. return result_len;
  60. }
  61.  
  62. static int crush_choose_firstn(const struct crush_map *map,
  63. struct crush_bucket *bucket,
  64. const __u32 *weight,
  65. int weight_max,
  66. int x,
  67. int numrep,
  68. int type,
  69. int *out)
  70. {
  71. for (int rep = ; rep < numrep; rep++) {
  72. /* keep trying until we get a non-out, non-colliding item */
  73. unsigned int ftotal = ;
  74. bool skip_rep = ;
  75. do {
  76. unsigned int flocal = ;
  77. bool retry_descent = false;
  78. struct crush_bucket *in = bucket;
  79.  
  80. do {
  81. bool retry_bucket = false;
  82. int r = rep + parent_r;
  83. /* r' = r + f_total */
  84. r += ftotal;
  85.  
  86. /* bucket choose */
  87. int item = crush_bucket_choose(in, x, r);
  88.  
  89. int itemtype;
  90. if (item < )//Elar: if item is a bucket, then get its type
  91. itemtype = map->buckets[--item]->type;
  92. else//Elar: if item is a device, then its type=0
  93. itemtype = ;
  94.  
  95. //Elar: if this item's type is not what we expected, then keep going until we get an match one!
  96. if (itemtype != type) {
  97. in = map->buckets[--item];
  98. retry_bucket = ;
  99. continue;
  100. }
  101.  
  102. // Elar: check if item has already been in the output array
  103. bool collide = false;
  104. for (i = ; i < outpos; i++) {
  105. if (out[i] == item) {
  106. collide = true;
  107. break;
  108. }
  109. }
  110.  
  111. bool reject = false;
  112. if (itemtype == ){
  113. //Elar: check if this item has been marked as "out"
  114. reject = is_out(map, weight,weight_max,item, x);
  115. }else{
  116. reject = false;
  117. }
  118.  
  119. reject:
  120. if (reject || collide) {
  121. ftotal++;
  122. flocal++;
  123.  
  124. if still can try locally(with in the same bucket, try other items)
  125. retry_bucket = true;
  126. else if still can try descent(parent's or grandparent's sibling buckets)
  127. /* then retry descent */
  128. retry_descent = true;
  129. else
  130. /* else give up */
  131. skip_rep = true;
  132. }
  133. } while (true == retry_bucket);
  134. } while (true == retry_descent);
  135.  
  136. if (true == skip_rep) {
  137. continue;
  138. }
  139.  
  140. out[outpos] = item;
  141. outpos++;
  142. }
  143. return outpos;
  144. }

完整代码请移步git:

https://github.com/ceph/ceph/blob/master/src/crush/mapper.c

ceph crush 之 crush_do_rule的更多相关文章

  1. ceph crush的问题

    ceph crush的问题看一遍忘一遍,现将<ceph源码分析>一书中相关章节摘抄如下: 4.2.1 层级化的Cluster Map例4-1 Cluster Map定义层级化的Cluste ...

  2. ceph crush算法和crushmap浅析

    1 什么是crushmap crushmap就相当于是ceph集群的一张数据分布地图,crush算法通过该地图可以知道数据应该如何分布:找到数据存放位置从而直接与对应的osd进行数据访问和写入:故障域 ...

  3. ceph 的crush算法 straw

    很多年以前,Sage 在写CRUSH的原始算法的时候,写了不同的Bucket类型,可以选择不同的伪随机选择算法,大部分的模型是基于RJ Honicky写的RUSH algorithms 这个算法,这个 ...

  4. Ceph相关

    Ceph基础知识和基础架构简介 http://www.xuxiaopang.com/2020/10/09/list/#more大话Ceph http://www.xuxiaopang.com/2016 ...

  5. ceph结构详解

    引言 那么问题来了,把一份数据存到一群Server中分几步? Ceph的答案是:两步. 计算PG 计算OSD 计算PG 首先,要明确Ceph的一个规定:在Ceph中,一切皆对象. 不论是视频,文本,照 ...

  6. Ceph常规操作及常见问题梳理

    Ceph集群管理 每次用命令启动.重启.停止Ceph守护进程(或整个集群)时,必须指定至少一个选项和一个命令,还可能要指定守护进程类型或具体例程. **命令格式如 {commandline} [opt ...

  7. ceph笔记(一)

    一.ceph概述本质上是rados:可靠的.自动的.分布式对象存储特性:高效性(大型的网络raid,性能无限接近raid).统一性(支持文件存储.块存储.对象存储).可扩展性数据库的一个弱点:查表ce ...

  8. Ceph 概述和理论

    1.1 Ceph概述 官网地址:https://docs.ceph.com/docs/master/ 1.Ceph简介 概述:Ceph是可靠的.可扩展的.统一的.分布式的存储系统.同时提供对象存储RA ...

  9. Ceph介绍及原理架构分享

    https://www.jianshu.com/p/cc3ece850433 1. Ceph架构简介及使用场景介绍 1.1 Ceph简介 Ceph是一个统一的分布式存储系统,设计初衷是提供较好的性能. ...

随机推荐

  1. Socket进程通信机制

    1.Socket通常称为“套接字”,用于描述IP地址和端口,是一个通信链的句柄. 2.应用程序通过套接字向网络发出请求或者应答网络请求. 3.Socket既不是一个程序,也不是一种协议,其只是操作系统 ...

  2. drupal的node.html.twig说明

    Drupal 8 根据分类不同定义自己的节点模板建议:http://www.thinkindrupal.com/node/5986 *可用变量: * - node:具有有限访问对象属性和方法的节点实体 ...

  3. Python常用模块--base64

    作用:对一些保密性不强的信息进行加密,变为人类不能直接理解的字符串,但是可以反向解密,是一种‘防君子,不防小人’的措施. 例如:在一些项目中,接口的报文是通过base64加密传输的,所以在进行接口自动 ...

  4. 模拟页面获取的php数据(三)

    <?php return array( "aData" => [//通勤方式 "trafficType" => [ 0 => [ &qu ...

  5. 洛谷P2879 [USACO07JAN]区间统计Tallest Cow

    To 洛谷.2879 区间统计 题目描述 FJ's N (1 ≤ N ≤ 10,000) cows conveniently indexed 1..N are standing in a line. ...

  6. iOS for MachineLearning

    链接: 手把手教你在应用里用上iOS机器学习框架Core ML iOS11 新功能开发之 - "高大上"的 CoreML 与 Vision Core ML介绍 (Apple机器学习 ...

  7. B - 可能的路径(gcd变形)

    https://vjudge.net/contest/218366#problem/B 要不是在数学题专题里,我估计就盲目搜索了.10^18范围1s应该过不去. 再细看能感觉到是gcd的变形,但是具体 ...

  8. [原创]PostMan接口测试神器

    [原创]PostMan接口测试神器 1 PostMan是什么?  Postman是一款功能强大的网页调试与发送网页HTTP请求的Chrome插件. 2 Postman工具下载及安装 官方网站: htt ...

  9. The Secret Mixed-Signal Life of PWM Peripherals

    The Secret Mixed-Signal Life of PWM Peripherals Pulse-width modulation (PWM) peripherals have enjoye ...

  10. Linux的cron与%

    这个cron不能执行: * * * * * /bin/echo `/bin/date +"%Y-%m-%d-%T"` >> /home/adminuser/test.t ...