关键词搜索

源码搜索 ×
×

漫话Redis源码之五十六

发布2022-01-09浏览471次

详情内容

对intset的更新和扩容,不是关键核心的代码:

  1. /* Upgrades the intset to a larger encoding and inserts the given integer. */
  2. static intset *intsetUpgradeAndAdd(intset *is, int64_t value) {
  3. uint8_t curenc = intrev32ifbe(is->encoding);
  4. uint8_t newenc = _intsetValueEncoding(value);
  5. int length = intrev32ifbe(is->length);
  6. int prepend = value < 0 ? 1 : 0;
  7. /* First set new encoding and resize */
  8. is->encoding = intrev32ifbe(newenc);
  9. is = intsetResize(is,intrev32ifbe(is->length)+1);
  10. /* Upgrade back-to-front so we don't overwrite values.
  11. * Note that the "prepend" variable is used to make sure we have an empty
  12. * space at either the beginning or the end of the intset. */
  13. while(length--)
  14. _intsetSet(is,length+prepend,_intsetGetEncoded(is,length,curenc));
  15. /* Set the value at the beginning or the end. */
  16. if (prepend)
  17. _intsetSet(is,0,value);
  18. else
  19. _intsetSet(is,intrev32ifbe(is->length),value);
  20. is->length = intrev32ifbe(intrev32ifbe(is->length)+1);
  21. return is;
  22. }
  23. static void intsetMoveTail(intset *is, uint32_t from, uint32_t to) {
  24. void *src, *dst;
  25. uint32_t bytes = intrev32ifbe(is->length)-from;
  26. uint32_t encoding = intrev32ifbe(is->encoding);
  27. if (encoding == INTSET_ENC_INT64) {
  28. src = (int64_t*)is->contents+from;
  29. dst = (int64_t*)is->contents+to;
  30. bytes *= sizeof(int64_t);
  31. } else if (encoding == INTSET_ENC_INT32) {
  32. src = (int32_t*)is->contents+from;
  33. dst = (int32_t*)is->contents+to;
  34. bytes *= sizeof(int32_t);
  35. } else {
  36. src = (int16_t*)is->contents+from;
  37. dst = (int16_t*)is->contents+to;
  38. bytes *= sizeof(int16_t);
  39. }
  40. memmove(dst,src,bytes);
  41. }
  42. /* Insert an integer in the intset */
  43. intset *intsetAdd(intset *is, int64_t value, uint8_t *success) {
  44. uint8_t valenc = _intsetValueEncoding(value);
  45. uint32_t pos;
  46. if (success) *success = 1;
  47. /* Upgrade encoding if necessary. If we need to upgrade, we know that
  48. * this value should be either appended (if > 0) or prepended (if < 0),
  49. * because it lies outside the range of existing values. */
  50. if (valenc > intrev32ifbe(is->encoding)) {
  51. /* This always succeeds, so we don't need to curry *success. */
  52. return intsetUpgradeAndAdd(is,value);
  53. } else {
  54. /* Abort if the value is already present in the set.
  55. * This call will populate "pos" with the right position to insert
  56. * the value when it cannot be found. */
  57. if (intsetSearch(is,value,&pos)) {
  58. if (success) *success = 0;
  59. return is;
  60. }
  61. is = intsetResize(is,intrev32ifbe(is->length)+1);
  62. if (pos < intrev32ifbe(is->length)) intsetMoveTail(is,pos,pos+1);
  63. }
  64. _intsetSet(is,pos,value);
  65. is->length = intrev32ifbe(intrev32ifbe(is->length)+1);
  66. return is;
  67. }
  68. /* Delete integer from intset */
  69. intset *intsetRemove(intset *is, int64_t value, int *success) {
  70. uint8_t valenc = _intsetValueEncoding(value);
  71. uint32_t pos;
  72. if (success) *success = 0;
  73. if (valenc <= intrev32ifbe(is->encoding) && intsetSearch(is,value,&pos)) {
  74. uint32_t len = intrev32ifbe(is->length);
  75. /* We know we can delete */
  76. if (success) *success = 1;
  77. /* Overwrite value with tail and update length */
  78. if (pos < (len-1)) intsetMoveTail(is,pos+1,pos);
  79. is = intsetResize(is,len-1);
  80. is->length = intrev32ifbe(len-1);
  81. }
  82. return is;
  83. }
  84. /* Determine whether a value belongs to this set */
  85. uint8_t intsetFind(intset *is, int64_t value) {
  86. uint8_t valenc = _intsetValueEncoding(value);
  87. return valenc <= intrev32ifbe(is->encoding) && intsetSearch(is,value,NULL);
  88. }
  89. /* Return random member */
  90. int64_t intsetRandom(intset *is) {
  91. uint32_t len = intrev32ifbe(is->length);
  92. assert(len); /* avoid division by zero on corrupt intset payload. */
  93. return _intsetGet(is,rand()%len);
  94. }
  95. /* Get the value at the given position. When this position is
  96. * out of range the function returns 0, when in range it returns 1. */
  97. uint8_t intsetGet(intset *is, uint32_t pos, int64_t *value) {
  98. if (pos < intrev32ifbe(is->length)) {
  99. *value = _intsetGet(is,pos);
  100. return 1;
  101. }
  102. return 0;
  103. }
  104. /* Return intset length */
  105. uint32_t intsetLen(const intset *is) {
  106. return intrev32ifbe(is->length);
  107. }
  108. /* Return intset blob size in bytes. */
  109. size_t intsetBlobLen(intset *is) {
  110. return sizeof(intset)+(size_t)intrev32ifbe(is->length)*intrev32ifbe(is->encoding);
  111. }
  112. /* Validate the integrity of the data structure.
  113. * when `deep` is 0, only the integrity of the header is validated.
  114. * when `deep` is 1, we make sure there are no duplicate or out of order records. */
  115. int intsetValidateIntegrity(const unsigned char *p, size_t size, int deep) {
  116. intset *is = (intset *)p;
  117. /* check that we can actually read the header. */
  118. if (size < sizeof(*is))
  119. return 0;
  120. uint32_t encoding = intrev32ifbe(is->encoding);
  121. size_t record_size;
  122. if (encoding == INTSET_ENC_INT64) {
  123. record_size = INTSET_ENC_INT64;
  124. } else if (encoding == INTSET_ENC_INT32) {
  125. record_size = INTSET_ENC_INT32;
  126. } else if (encoding == INTSET_ENC_INT16){
  127. record_size = INTSET_ENC_INT16;
  128. } else {
  129. return 0;
  130. }
  131. /* check that the size matchies (all records are inside the buffer). */
  132. uint32_t count = intrev32ifbe(is->length);
  133. if (sizeof(*is) + count*record_size != size)
  134. return 0;
  135. /* check that the set is not empty. */
  136. if (count==0)
  137. return 0;
  138. if (!deep)
  139. return 1;
  140. /* check that there are no dup or out of order records. */
  141. int64_t prev = _intsetGet(is,0);
  142. for (uint32_t i=1; i<count; i++) {
  143. int64_t cur = _intsetGet(is,i);
  144. if (cur <= prev)
  145. return 0;
  146. prev = cur;
  147. }
  148. return 1;
  149. }
  150. #ifdef REDIS_TEST
  151. #include <sys/time.h>
  152. #include <time.h>
  153. #if 0
  154. static void intsetRepr(intset *is) {
  155. for (uint32_t i = 0; i < intrev32ifbe(is->length); i++) {
  156. printf("%lld\n", (uint64_t)_intsetGet(is,i));
  157. }
  158. printf("\n");
  159. }
  160. static void error(char *err) {
  161. printf("%s\n", err);
  162. exit(1);
  163. }
  164. #endif
  165. static void ok(void) {
  166. printf("OK\n");
  167. }
  168. static long long usec(void) {
  169. struct timeval tv;
  170. gettimeofday(&tv,NULL);
  171. return (((long long)tv.tv_sec)*1000000)+tv.tv_usec;
  172. }
  173. static intset *createSet(int bits, int size) {
  174. uint64_t mask = (1<<bits)-1;
  175. uint64_t value;
  176. intset *is = intsetNew();
  177. for (int i = 0; i < size; i++) {
  178. if (bits > 32) {
  179. value = (rand()*rand()) & mask;
  180. } else {
  181. value = rand() & mask;
  182. }
  183. is = intsetAdd(is,value,NULL);
  184. }
  185. return is;
  186. }
  187. static void checkConsistency(intset *is) {
  188. for (uint32_t i = 0; i < (intrev32ifbe(is->length)-1); i++) {
  189. uint32_t encoding = intrev32ifbe(is->encoding);
  190. if (encoding == INTSET_ENC_INT16) {
  191. int16_t *i16 = (int16_t*)is->contents;
  192. assert(i16[i] < i16[i+1]);
  193. } else if (encoding == INTSET_ENC_INT32) {
  194. int32_t *i32 = (int32_t*)is->contents;
  195. assert(i32[i] < i32[i+1]);
  196. } else {
  197. int64_t *i64 = (int64_t*)is->contents;
  198. assert(i64[i] < i64[i+1]);
  199. }
  200. }
  201. }
  202. #define UNUSED(x) (void)(x)
  203. int intsetTest(int argc, char **argv, int accurate) {
  204. uint8_t success;
  205. int i;
  206. intset *is;
  207. srand(time(NULL));
  208. UNUSED(argc);
  209. UNUSED(argv);
  210. UNUSED(accurate);
  211. printf("Value encodings: "); {
  212. assert(_intsetValueEncoding(-32768) == INTSET_ENC_INT16);
  213. assert(_intsetValueEncoding(+32767) == INTSET_ENC_INT16);
  214. assert(_intsetValueEncoding(-32769) == INTSET_ENC_INT32);
  215. assert(_intsetValueEncoding(+32768) == INTSET_ENC_INT32);
  216. assert(_intsetValueEncoding(-2147483648) == INTSET_ENC_INT32);
  217. assert(_intsetValueEncoding(+2147483647) == INTSET_ENC_INT32);
  218. assert(_intsetValueEncoding(-2147483649) == INTSET_ENC_INT64);
  219. assert(_intsetValueEncoding(+2147483648) == INTSET_ENC_INT64);
  220. assert(_intsetValueEncoding(-9223372036854775808ull) ==
  221. INTSET_ENC_INT64);
  222. assert(_intsetValueEncoding(+9223372036854775807ull) ==
  223. INTSET_ENC_INT64);
  224. ok();
  225. }
  226. printf("Basic adding: "); {
  227. is = intsetNew();
  228. is = intsetAdd(is,5,&success); assert(success);
  229. is = intsetAdd(is,6,&success); assert(success);
  230. is = intsetAdd(is,4,&success); assert(success);
  231. is = intsetAdd(is,4,&success); assert(!success);
  232. ok();
  233. zfree(is);
  234. }
  235. printf("Large number of random adds: "); {
  236. uint32_t inserts = 0;
  237. is = intsetNew();
  238. for (i = 0; i < 1024; i++) {
  239. is = intsetAdd(is,rand()%0x800,&success);
  240. if (success) inserts++;
  241. }
  242. assert(intrev32ifbe(is->length) == inserts);
  243. checkConsistency(is);
  244. ok();
  245. zfree(is);
  246. }
  247. printf("Upgrade from int16 to int32: "); {
  248. is = intsetNew();
  249. is = intsetAdd(is,32,NULL);
  250. assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT16);
  251. is = intsetAdd(is,65535,NULL);
  252. assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT32);
  253. assert(intsetFind(is,32));
  254. assert(intsetFind(is,65535));
  255. checkConsistency(is);
  256. zfree(is);
  257. is = intsetNew();
  258. is = intsetAdd(is,32,NULL);
  259. assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT16);
  260. is = intsetAdd(is,-65535,NULL);
  261. assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT32);
  262. assert(intsetFind(is,32));
  263. assert(intsetFind(is,-65535));
  264. checkConsistency(is);
  265. ok();
  266. zfree(is);
  267. }
  268. printf("Upgrade from int16 to int64: "); {
  269. is = intsetNew();
  270. is = intsetAdd(is,32,NULL);
  271. assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT16);
  272. is = intsetAdd(is,4294967295,NULL);
  273. assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT64);
  274. assert(intsetFind(is,32));
  275. assert(intsetFind(is,4294967295));
  276. checkConsistency(is);
  277. zfree(is);
  278. is = intsetNew();
  279. is = intsetAdd(is,32,NULL);
  280. assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT16);
  281. is = intsetAdd(is,-4294967295,NULL);
  282. assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT64);
  283. assert(intsetFind(is,32));
  284. assert(intsetFind(is,-4294967295));
  285. checkConsistency(is);
  286. ok();
  287. zfree(is);
  288. }
  289. printf("Upgrade from int32 to int64: "); {
  290. is = intsetNew();
  291. is = intsetAdd(is,65535,NULL);
  292. assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT32);
  293. is = intsetAdd(is,4294967295,NULL);
  294. assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT64);
  295. assert(intsetFind(is,65535));
  296. assert(intsetFind(is,4294967295));
  297. checkConsistency(is);
  298. zfree(is);
  299. is = intsetNew();
  300. is = intsetAdd(is,65535,NULL);
  301. assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT32);
  302. is = intsetAdd(is,-4294967295,NULL);
  303. assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT64);
  304. assert(intsetFind(is,65535));
  305. assert(intsetFind(is,-4294967295));
  306. checkConsistency(is);
  307. ok();
  308. zfree(is);
  309. }
  310. printf("Stress lookups: "); {
  311. long num = 100000, size = 10000;
  312. int i, bits = 20;
  313. long long start;
  314. is = createSet(bits,size);
  315. checkConsistency(is);
  316. start = usec();
  317. for (i = 0; i < num; i++) intsetSearch(is,rand() % ((1<<bits)-1),NULL);
  318. printf("%ld lookups, %ld element set, %lldusec\n",
  319. num,size,usec()-start);
  320. zfree(is);
  321. }
  322. printf("Stress add+delete: "); {
  323. int i, v1, v2;
  324. is = intsetNew();
  325. for (i = 0; i < 0xffff; i++) {
  326. v1 = rand() % 0xfff;
  327. is = intsetAdd(is,v1,NULL);
  328. assert(intsetFind(is,v1));
  329. v2 = rand() % 0xfff;
  330. is = intsetRemove(is,v2,NULL);
  331. assert(!intsetFind(is,v2));
  332. }
  333. checkConsistency(is);
  334. ok();
  335. zfree(is);
  336. }
  337. return 0;
  338. }
  339. #endif

相关技术文章

点击QQ咨询
开通会员
返回顶部
×
微信扫码支付
微信扫码支付
确定支付下载
请使用微信描二维码支付
×

提示信息

×

选择支付方式

  • 微信支付
  • 支付宝付款
确定支付下载