关键词搜索

源码搜索 ×
×

漫话Redis源码之三十八

发布2021-12-26浏览689次

详情内容

这里主要就是对象的转换,没啥具体复杂的逻辑。

在看源码时,我们需要掌握这些转换到底做了什么事情,而不需要去看每个转化的细化步骤。

  1. /* Create a string object with EMBSTR encoding if it is smaller than
  2. * OBJ_ENCODING_EMBSTR_SIZE_LIMIT, otherwise the RAW encoding is
  3. * used.
  4. *
  5. * The current limit of 44 is chosen so that the biggest string object
  6. * we allocate as EMBSTR will still fit into the 64 byte arena of jemalloc. */
  7. #define OBJ_ENCODING_EMBSTR_SIZE_LIMIT 44
  8. robj *createStringObject(const char *ptr, size_t len) {
  9. if (len <= OBJ_ENCODING_EMBSTR_SIZE_LIMIT)
  10. return createEmbeddedStringObject(ptr,len);
  11. else
  12. return createRawStringObject(ptr,len);
  13. }
  14. /* Same as CreateRawStringObject, can return NULL if allocation fails */
  15. robj *tryCreateRawStringObject(const char *ptr, size_t len) {
  16. sds str = sdstrynewlen(ptr,len);
  17. if (!str) return NULL;
  18. return createObject(OBJ_STRING, str);
  19. }
  20. /* Same as createStringObject, can return NULL if allocation fails */
  21. robj *tryCreateStringObject(const char *ptr, size_t len) {
  22. if (len <= OBJ_ENCODING_EMBSTR_SIZE_LIMIT)
  23. return createEmbeddedStringObject(ptr,len);
  24. else
  25. return tryCreateRawStringObject(ptr,len);
  26. }
  27. /* Create a string object from a long long value. When possible returns a
  28. * shared integer object, or at least an integer encoded one.
  29. *
  30. * If valueobj is non zero, the function avoids returning a shared
  31. * integer, because the object is going to be used as value in the Redis key
  32. * space (for instance when the INCR command is used), so we want LFU/LRU
  33. * values specific for each key. */
  34. robj *createStringObjectFromLongLongWithOptions(long long value, int valueobj) {
  35. robj *o;
  36. if (server.maxmemory == 0 ||
  37. !(server.maxmemory_policy & MAXMEMORY_FLAG_NO_SHARED_INTEGERS))
  38. {
  39. /* If the maxmemory policy permits, we can still return shared integers
  40. * even if valueobj is true. */
  41. valueobj = 0;
  42. }
  43. if (value >= 0 && value < OBJ_SHARED_INTEGERS && valueobj == 0) {
  44. incrRefCount(shared.integers[value]);
  45. o = shared.integers[value];
  46. } else {
  47. if (value >= LONG_MIN && value <= LONG_MAX) {
  48. o = createObject(OBJ_STRING, NULL);
  49. o->encoding = OBJ_ENCODING_INT;
  50. o->ptr = (void*)((long)value);
  51. } else {
  52. o = createObject(OBJ_STRING,sdsfromlonglong(value));
  53. }
  54. }
  55. return o;
  56. }
  57. /* Wrapper for createStringObjectFromLongLongWithOptions() always demanding
  58. * to create a shared object if possible. */
  59. robj *createStringObjectFromLongLong(long long value) {
  60. return createStringObjectFromLongLongWithOptions(value,0);
  61. }
  62. /* Wrapper for createStringObjectFromLongLongWithOptions() avoiding a shared
  63. * object when LFU/LRU info are needed, that is, when the object is used
  64. * as a value in the key space, and Redis is configured to evict based on
  65. * LFU/LRU. */
  66. robj *createStringObjectFromLongLongForValue(long long value) {
  67. return createStringObjectFromLongLongWithOptions(value,1);
  68. }
  69. /* Create a string object from a long double. If humanfriendly is non-zero
  70. * it does not use exponential format and trims trailing zeroes at the end,
  71. * however this results in loss of precision. Otherwise exp format is used
  72. * and the output of snprintf() is not modified.
  73. *
  74. * The 'humanfriendly' option is used for INCRBYFLOAT and HINCRBYFLOAT. */
  75. robj *createStringObjectFromLongDouble(long double value, int humanfriendly) {
  76. char buf[MAX_LONG_DOUBLE_CHARS];
  77. int len = ld2string(buf,sizeof(buf),value,humanfriendly? LD_STR_HUMAN: LD_STR_AUTO);
  78. return createStringObject(buf,len);
  79. }
  80. /* Duplicate a string object, with the guarantee that the returned object
  81. * has the same encoding as the original one.
  82. *
  83. * This function also guarantees that duplicating a small integer object
  84. * (or a string object that contains a representation of a small integer)
  85. * will always result in a fresh object that is unshared (refcount == 1).
  86. *
  87. * The resulting object always has refcount set to 1. */
  88. robj *dupStringObject(const robj *o) {
  89. robj *d;
  90. serverAssert(o->type == OBJ_STRING);
  91. switch(o->encoding) {
  92. case OBJ_ENCODING_RAW:
  93. return createRawStringObject(o->ptr,sdslen(o->ptr));
  94. case OBJ_ENCODING_EMBSTR:
  95. return createEmbeddedStringObject(o->ptr,sdslen(o->ptr));
  96. case OBJ_ENCODING_INT:
  97. d = createObject(OBJ_STRING, NULL);
  98. d->encoding = OBJ_ENCODING_INT;
  99. d->ptr = o->ptr;
  100. return d;
  101. default:
  102. serverPanic("Wrong encoding.");
  103. break;
  104. }
  105. }
  106. robj *createQuicklistObject(void) {
  107. quicklist *l = quicklistCreate();
  108. robj *o = createObject(OBJ_LIST,l);
  109. o->encoding = OBJ_ENCODING_QUICKLIST;
  110. return o;
  111. }
  112. robj *createZiplistObject(void) {
  113. unsigned char *zl = ziplistNew();
  114. robj *o = createObject(OBJ_LIST,zl);
  115. o->encoding = OBJ_ENCODING_ZIPLIST;
  116. return o;
  117. }
  118. robj *createSetObject(void) {
  119. dict *d = dictCreate(&setDictType,NULL);
  120. robj *o = createObject(OBJ_SET,d);
  121. o->encoding = OBJ_ENCODING_HT;
  122. return o;
  123. }
  124. robj *createIntsetObject(void) {
  125. intset *is = intsetNew();
  126. robj *o = createObject(OBJ_SET,is);
  127. o->encoding = OBJ_ENCODING_INTSET;
  128. return o;
  129. }
  130. robj *createHashObject(void) {
  131. unsigned char *zl = ziplistNew();
  132. robj *o = createObject(OBJ_HASH, zl);
  133. o->encoding = OBJ_ENCODING_ZIPLIST;
  134. return o;
  135. }
  136. robj *createZsetObject(void) {
  137. zset *zs = zmalloc(sizeof(*zs));
  138. robj *o;
  139. zs->dict = dictCreate(&zsetDictType,NULL);
  140. zs->zsl = zslCreate();
  141. o = createObject(OBJ_ZSET,zs);
  142. o->encoding = OBJ_ENCODING_SKIPLIST;
  143. return o;
  144. }
  145. robj *createZsetZiplistObject(void) {
  146. unsigned char *zl = ziplistNew();
  147. robj *o = createObject(OBJ_ZSET,zl);
  148. o->encoding = OBJ_ENCODING_ZIPLIST;
  149. return o;
  150. }
  151. robj *createStreamObject(void) {
  152. stream *s = streamNew();
  153. robj *o = createObject(OBJ_STREAM,s);
  154. o->encoding = OBJ_ENCODING_STREAM;
  155. return o;
  156. }
  157. robj *createModuleObject(moduleType *mt, void *value) {
  158. moduleValue *mv = zmalloc(sizeof(*mv));
  159. mv->type = mt;
  160. mv->value = value;
  161. return createObject(OBJ_MODULE,mv);
  162. }
  163. void freeStringObject(robj *o) {
  164. if (o->encoding == OBJ_ENCODING_RAW) {
  165. sdsfree(o->ptr);
  166. }
  167. }
  168. void freeListObject(robj *o) {
  169. if (o->encoding == OBJ_ENCODING_QUICKLIST) {
  170. quicklistRelease(o->ptr);
  171. } else {
  172. serverPanic("Unknown list encoding type");
  173. }
  174. }
  175. void freeSetObject(robj *o) {
  176. switch (o->encoding) {
  177. case OBJ_ENCODING_HT:
  178. dictRelease((dict*) o->ptr);
  179. break;
  180. case OBJ_ENCODING_INTSET:
  181. zfree(o->ptr);
  182. break;
  183. default:
  184. serverPanic("Unknown set encoding type");
  185. }
  186. }
  187. void freeZsetObject(robj *o) {
  188. zset *zs;
  189. switch (o->encoding) {
  190. case OBJ_ENCODING_SKIPLIST:
  191. zs = o->ptr;
  192. dictRelease(zs->dict);
  193. zslFree(zs->zsl);
  194. zfree(zs);
  195. break;
  196. case OBJ_ENCODING_ZIPLIST:
  197. zfree(o->ptr);
  198. break;
  199. default:
  200. serverPanic("Unknown sorted set encoding");
  201. }
  202. }
  203. void freeHashObject(robj *o) {
  204. switch (o->encoding) {
  205. case OBJ_ENCODING_HT:
  206. dictRelease((dict*) o->ptr);
  207. break;
  208. case OBJ_ENCODING_ZIPLIST:
  209. zfree(o->ptr);
  210. break;
  211. default:
  212. serverPanic("Unknown hash encoding type");
  213. break;
  214. }
  215. }
  216. void freeModuleObject(robj *o) {
  217. moduleValue *mv = o->ptr;
  218. mv->type->free(mv->value);
  219. zfree(mv);
  220. }
  221. void freeStreamObject(robj *o) {
  222. freeStream(o->ptr);
  223. }
  224. void incrRefCount(robj *o) {
  225. if (o->refcount < OBJ_FIRST_SPECIAL_REFCOUNT) {
  226. o->refcount++;
  227. } else {
  228. if (o->refcount == OBJ_SHARED_REFCOUNT) {
  229. /* Nothing to do: this refcount is immutable. */
  230. } else if (o->refcount == OBJ_STATIC_REFCOUNT) {
  231. serverPanic("You tried to retain an object allocated in the stack");
  232. }
  233. }
  234. }
  235. void decrRefCount(robj *o) {
  236. if (o->refcount == 1) {
  237. switch(o->type) {
  238. case OBJ_STRING: freeStringObject(o); break;
  239. case OBJ_LIST: freeListObject(o); break;
  240. case OBJ_SET: freeSetObject(o); break;
  241. case OBJ_ZSET: freeZsetObject(o); break;
  242. case OBJ_HASH: freeHashObject(o); break;
  243. case OBJ_MODULE: freeModuleObject(o); break;
  244. case OBJ_STREAM: freeStreamObject(o); break;
  245. default: serverPanic("Unknown object type"); break;
  246. }
  247. zfree(o);
  248. } else {
  249. if (o->refcount <= 0) serverPanic("decrRefCount against refcount <= 0");
  250. if (o->refcount != OBJ_SHARED_REFCOUNT) o->refcount--;
  251. }
  252. }
  253. /* This variant of decrRefCount() gets its argument as void, and is useful
  254. * as free method in data structures that expect a 'void free_object(void*)'
  255. * prototype for the free method. */
  256. void decrRefCountVoid(void *o) {
  257. decrRefCount(o);
  258. }
  259. int checkType(client *c, robj *o, int type) {
  260. /* A NULL is considered an empty key */
  261. if (o && o->type != type) {
  262. addReplyErrorObject(c,shared.wrongtypeerr);
  263. return 1;
  264. }
  265. return 0;
  266. }
  267. int isSdsRepresentableAsLongLong(sds s, long long *llval) {
  268. return string2ll(s,sdslen(s),llval) ? C_OK : C_ERR;
  269. }
  270. int isObjectRepresentableAsLongLong(robj *o, long long *llval) {
  271. serverAssertWithInfo(NULL,o,o->type == OBJ_STRING);
  272. if (o->encoding == OBJ_ENCODING_INT) {
  273. if (llval) *llval = (long) o->ptr;
  274. return C_OK;
  275. } else {
  276. return isSdsRepresentableAsLongLong(o->ptr,llval);
  277. }
  278. }
  279. /* Optimize the SDS string inside the string object to require little space,
  280. * in case there is more than 10% of free space at the end of the SDS
  281. * string. This happens because SDS strings tend to overallocate to avoid
  282. * wasting too much time in allocations when appending to the string. */
  283. void trimStringObjectIfNeeded(robj *o) {
  284. if (o->encoding == OBJ_ENCODING_RAW &&
  285. sdsavail(o->ptr) > sdslen(o->ptr)/10)
  286. {
  287. o->ptr = sdsRemoveFreeSpace(o->ptr);
  288. }
  289. }
  290. /* Try to encode a string object in order to save space */
  291. robj *tryObjectEncoding(robj *o) {
  292. long value;
  293. sds s = o->ptr;
  294. size_t len;
  295. /* Make sure this is a string object, the only type we encode
  296. * in this function. Other types use encoded memory efficient
  297. * representations but are handled by the commands implementing
  298. * the type. */
  299. serverAssertWithInfo(NULL,o,o->type == OBJ_STRING);
  300. /* We try some specialized encoding only for objects that are
  301. * RAW or EMBSTR encoded, in other words objects that are still
  302. * in represented by an actually array of chars. */
  303. if (!sdsEncodedObject(o)) return o;
  304. /* It's not safe to encode shared objects: shared objects can be shared
  305. * everywhere in the "object space" of Redis and may end in places where
  306. * they are not handled. We handle them only as values in the keyspace. */
  307. if (o->refcount > 1) return o;
  308. /* Check if we can represent this string as a long integer.
  309. * Note that we are sure that a string larger than 20 chars is not
  310. * representable as a 32 nor 64 bit integer. */
  311. len = sdslen(s);
  312. if (len <= 20 && string2l(s,len,&value)) {
  313. /* This object is encodable as a long. Try to use a shared object.
  314. * Note that we avoid using shared integers when maxmemory is used
  315. * because every object needs to have a private LRU field for the LRU
  316. * algorithm to work well. */
  317. if ((server.maxmemory == 0 ||
  318. !(server.maxmemory_policy & MAXMEMORY_FLAG_NO_SHARED_INTEGERS)) &&
  319. value >= 0 &&
  320. value < OBJ_SHARED_INTEGERS)
  321. {
  322. decrRefCount(o);
  323. incrRefCount(shared.integers[value]);
  324. return shared.integers[value];
  325. } else {
  326. if (o->encoding == OBJ_ENCODING_RAW) {
  327. sdsfree(o->ptr);
  328. o->encoding = OBJ_ENCODING_INT;
  329. o->ptr = (void*) value;
  330. return o;
  331. } else if (o->encoding == OBJ_ENCODING_EMBSTR) {
  332. decrRefCount(o);
  333. return createStringObjectFromLongLongForValue(value);
  334. }
  335. }
  336. }
  337. /* If the string is small and is still RAW encoded,
  338. * try the EMBSTR encoding which is more efficient.
  339. * In this representation the object and the SDS string are allocated
  340. * in the same chunk of memory to save space and cache misses. */
  341. if (len <= OBJ_ENCODING_EMBSTR_SIZE_LIMIT) {
  342. robj *emb;
  343. if (o->encoding == OBJ_ENCODING_EMBSTR) return o;
  344. emb = createEmbeddedStringObject(s,sdslen(s));
  345. decrRefCount(o);
  346. return emb;
  347. }
  348. /* We can't encode the object...
  349. *
  350. * Do the last try, and at least optimize the SDS string inside
  351. * the string object to require little space, in case there
  352. * is more than 10% of free space at the end of the SDS string.
  353. *
  354. * We do that only for relatively large strings as this branch
  355. * is only entered if the length of the string is greater than
  356. * OBJ_ENCODING_EMBSTR_SIZE_LIMIT. */
  357. trimStringObjectIfNeeded(o);
  358. /* Return the original object. */
  359. return o;
  360. }

相关技术文章

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

提示信息

×

选择支付方式

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