Basic C with your handwritten redis adlist

Keywords: C Redis Linux Makefile git

Introduction - Navigation

Some friends may be full of endless thirst for knowledge about redis. Maybe redis belongs to the big play of work, communication (interview),

I have to... But now I just stay at the level of using redis, and I have little involvement in the level of detail. In order to integrate into the big faster

Let's write the simplest data structure in redis, the adlist two-way linked list

We have a preliminary understanding of redis. This article will be interpreted from the following headings.

1. redis adlist analysis
2. redis config.h analysis
3. Redis setproactive. C analysis
4. redis atomicvar.h analysis
5. redis zmalloc analysis
6. redis Makefile analysis

redis is written by C, and C is full of handwriting. OK, let's start the journey of nonsense handwriting:)

Preface - redis adlist

The whole sample code has been written by hand, but for the sake of material normalization, it is directly quoted intact here

Related code in github.com/antirez/redis

1. redis adlist analysis

 1 /* adlist.h - A generic doubly linked list implementation
 2  *
 3  * Copyright (c) 2006-2012, Salvatore Sanfilippo <antirez at gmail dot com>
 4  * All rights reserved.
 5  *
 6  * Redistribution and use in source and binary forms, with or without
 7  * modification, are permitted provided that the following conditions are met:
 8  *
 9  *   * Redistributions of source code must retain the above copyright notice,
10  *     this list of conditions and the following disclaimer.
11  *   * Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  *   * Neither the name of Redis nor the names of its contributors may be used
15  *     to endorse or promote products derived from this software without
16  *     specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #ifndef __ADLIST_H__
32 #define __ADLIST_H__
33 
34 /* Node, List, and Iterator are the only data structures used currently. */
35 
36 typedef struct listNode {
37     struct listNode *prev;
38     struct listNode *next;
39     void *value;
40 } listNode;
41 
42 typedef struct listIter {
43     listNode *next;
44     int direction;
45 } listIter;
46 
47 typedef struct list {
48     listNode *head;
49     listNode *tail;
50     void *(*dup)(void *ptr);
51     void (*free)(void *ptr);
52     int (*match)(void *ptr, void *key);
53     unsigned long len;
54 } list;
55 
56 /* Functions implemented as macros */
57 #define listLength(l) ((l)->len)
58 #define listFirst(l) ((l)->head)
59 #define listLast(l) ((l)->tail)
60 #define listPrevNode(n) ((n)->prev)
61 #define listNextNode(n) ((n)->next)
62 #define listNodeValue(n) ((n)->value)
63 
64 #define listSetDupMethod(l,m) ((l)->dup = (m))
65 #define listSetFreeMethod(l,m) ((l)->free = (m))
66 #define listSetMatchMethod(l,m) ((l)->match = (m))
67 
68 #define listGetDupMethod(l) ((l)->dup)
69 #define listGetFreeMethod(l) ((l)->free)
70 #define listGetMatchMethod(l) ((l)->match)
71 
72 /* Prototypes */
73 list *listCreate(void);
74 void listRelease(list *list);
75 void listEmpty(list *list);
76 list *listAddNodeHead(list *list, void *value);
77 list *listAddNodeTail(list *list, void *value);
78 list *listInsertNode(list *list, listNode *old_node, void *value, int after);
79 void listDelNode(list *list, listNode *node);
80 listIter *listGetIterator(list *list, int direction);
81 listNode *listNext(listIter *iter);
82 void listReleaseIterator(listIter *iter);
83 list *listDup(list *orig);
84 listNode *listSearchKey(list *list, void *key);
85 listNode *listIndex(list *list, long index);
86 void listRewind(list *list, listIter *li);
87 void listRewindTail(list *list, listIter *li);
88 void listRotate(list *list);
89 void listJoin(list *l, list *o);
90 
91 /* Directions for iterators */
92 #define AL_START_HEAD 0
93 #define AL_START_TAIL 1
94 
95 #endif /* __ADLIST_H__ */

The first thing to write is the header file of adlist.h double linked list. There are several points to talk about about this header file

The header file format in 1.1 'redis is not unified at present

#ifndef __ADLIST_H__    #endif
#ifndef __REDIS_HELP_H  #endif
#ifndef __ZMALLOC_H     #endif

Maybe it is. redis has been in maintenance and development for more than ten years. It's normal that the code style is changing

The third way to write is recommended here - > without suffix file name}

Function naming in 1.2 'adlist. H is arbitrary

void listReleaseIterator(listIter *iter);
list *listDup(list *orig);
listNode *listSearchKey(list *list, void *key);
listNode *listIndex(list *list, long index);
void listRewind(list *list, listIter *li);
void listRewindTail(list *list, listIter *li);
void listRotate(list *list);
void listJoin(list *l, list *o);

It's not a good habit to name randomly. It's recommended to distinguish parameter names. For example, the following fixed format

extern void listReleaseIterator(listIter * iter);
extern list * listDup(list * l);
extern listNode * listSearchKey(list * l, void * key);
extern listNode * listIndex(list * l, long index);
extern void listRewind(list * l, listIter * iter);
extern void listRewindTail(list * l, listIter * iter);
extern void listRotate(list * l);
extern void listJoin(list * l, list * o);

After writing the definition part of the adlist.h interface, I believe some people have a rough outline for the implementation of adlist.c:)

  1 /* adlist.c - A generic doubly linked list implementation
  2  *
  3  * Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
  4  * All rights reserved.
  5  *
  6  * Redistribution and use in source and binary forms, with or without
  7  * modification, are permitted provided that the following conditions are met:
  8  *
  9  *   * Redistributions of source code must retain the above copyright notice,
 10  *     this list of conditions and the following disclaimer.
 11  *   * Redistributions in binary form must reproduce the above copyright
 12  *     notice, this list of conditions and the following disclaimer in the
 13  *     documentation and/or other materials provided with the distribution.
 14  *   * Neither the name of Redis nor the names of its contributors may be used
 15  *     to endorse or promote products derived from this software without
 16  *     specific prior written permission.
 17  *
 18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 28  * POSSIBILITY OF SUCH DAMAGE.
 29  */
 30 
 31 
 32 #include <stdlib.h>
 33 #include "adlist.h"
 34 #include "zmalloc.h"
 35 
 36 /* Create a new list. The created list can be freed with
 37  * AlFreeList(), but private value of every node need to be freed
 38  * by the user before to call AlFreeList().
 39  *
 40  * On error, NULL is returned. Otherwise the pointer to the new list. */
 41 list *listCreate(void)
 42 {
 43     struct list *list;
 44 
 45     if ((list = zmalloc(sizeof(*list))) == NULL)
 46         return NULL;
 47     list->head = list->tail = NULL;
 48     list->len = 0;
 49     list->dup = NULL;
 50     list->free = NULL;
 51     list->match = NULL;
 52     return list;
 53 }
 54 
 55 /* Remove all the elements from the list without destroying the list itself. */
 56 void listEmpty(list *list)
 57 {
 58     unsigned long len;
 59     listNode *current, *next;
 60 
 61     current = list->head;
 62     len = list->len;
 63     while(len--) {
 64         next = current->next;
 65         if (list->free) list->free(current->value);
 66         zfree(current);
 67         current = next;
 68     }
 69     list->head = list->tail = NULL;
 70     list->len = 0;
 71 }
 72 
 73 /* Free the whole list.
 74  *
 75  * This function can't fail. */
 76 void listRelease(list *list)
 77 {
 78     listEmpty(list);
 79     zfree(list);
 80 }
 81 
 82 /* Add a new node to the list, to head, containing the specified 'value'
 83  * pointer as value.
 84  *
 85  * On error, NULL is returned and no operation is performed (i.e. the
 86  * list remains unaltered).
 87  * On success the 'list' pointer you pass to the function is returned. */
 88 list *listAddNodeHead(list *list, void *value)
 89 {
 90     listNode *node;
 91 
 92     if ((node = zmalloc(sizeof(*node))) == NULL)
 93         return NULL;
 94     node->value = value;
 95     if (list->len == 0) {
 96         list->head = list->tail = node;
 97         node->prev = node->next = NULL;
 98     } else {
 99         node->prev = NULL;
100         node->next = list->head;
101         list->head->prev = node;
102         list->head = node;
103     }
104     list->len++;
105     return list;
106 }
107 
108 /* Add a new node to the list, to tail, containing the specified 'value'
109  * pointer as value.
110  *
111  * On error, NULL is returned and no operation is performed (i.e. the
112  * list remains unaltered).
113  * On success the 'list' pointer you pass to the function is returned. */
114 list *listAddNodeTail(list *list, void *value)
115 {
116     listNode *node;
117 
118     if ((node = zmalloc(sizeof(*node))) == NULL)
119         return NULL;
120     node->value = value;
121     if (list->len == 0) {
122         list->head = list->tail = node;
123         node->prev = node->next = NULL;
124     } else {
125         node->prev = list->tail;
126         node->next = NULL;
127         list->tail->next = node;
128         list->tail = node;
129     }
130     list->len++;
131     return list;
132 }
133 
134 list *listInsertNode(list *list, listNode *old_node, void *value, int after) {
135     listNode *node;
136 
137     if ((node = zmalloc(sizeof(*node))) == NULL)
138         return NULL;
139     node->value = value;
140     if (after) {
141         node->prev = old_node;
142         node->next = old_node->next;
143         if (list->tail == old_node) {
144             list->tail = node;
145         }
146     } else {
147         node->next = old_node;
148         node->prev = old_node->prev;
149         if (list->head == old_node) {
150             list->head = node;
151         }
152     }
153     if (node->prev != NULL) {
154         node->prev->next = node;
155     }
156     if (node->next != NULL) {
157         node->next->prev = node;
158     }
159     list->len++;
160     return list;
161 }
162 
163 /* Remove the specified node from the specified list.
164  * It's up to the caller to free the private value of the node.
165  *
166  * This function can't fail. */
167 void listDelNode(list *list, listNode *node)
168 {
169     if (node->prev)
170         node->prev->next = node->next;
171     else
172         list->head = node->next;
173     if (node->next)
174         node->next->prev = node->prev;
175     else
176         list->tail = node->prev;
177     if (list->free) list->free(node->value);
178     zfree(node);
179     list->len--;
180 }
181 
182 /* Returns a list iterator 'iter'. After the initialization every
183  * call to listNext() will return the next element of the list.
184  *
185  * This function can't fail. */
186 listIter *listGetIterator(list *list, int direction)
187 {
188     listIter *iter;
189 
190     if ((iter = zmalloc(sizeof(*iter))) == NULL) return NULL;
191     if (direction == AL_START_HEAD)
192         iter->next = list->head;
193     else
194         iter->next = list->tail;
195     iter->direction = direction;
196     return iter;
197 }
198 
199 /* Release the iterator memory */
200 void listReleaseIterator(listIter *iter) {
201     zfree(iter);
202 }
203 
204 /* Create an iterator in the list private iterator structure */
205 void listRewind(list *list, listIter *li) {
206     li->next = list->head;
207     li->direction = AL_START_HEAD;
208 }
209 
210 void listRewindTail(list *list, listIter *li) {
211     li->next = list->tail;
212     li->direction = AL_START_TAIL;
213 }
214 
215 /* Return the next element of an iterator.
216  * It's valid to remove the currently returned element using
217  * listDelNode(), but not to remove other elements.
218  *
219  * The function returns a pointer to the next element of the list,
220  * or NULL if there are no more elements, so the classical usage patter
221  * is:
222  *
223  * iter = listGetIterator(list,<direction>);
224  * while ((node = listNext(iter)) != NULL) {
225  *     doSomethingWith(listNodeValue(node));
226  * }
227  *
228  * */
229 listNode *listNext(listIter *iter)
230 {
231     listNode *current = iter->next;
232 
233     if (current != NULL) {
234         if (iter->direction == AL_START_HEAD)
235             iter->next = current->next;
236         else
237             iter->next = current->prev;
238     }
239     return current;
240 }
241 
242 /* Duplicate the whole list. On out of memory NULL is returned.
243  * On success a copy of the original list is returned.
244  *
245  * The 'Dup' method set with listSetDupMethod() function is used
246  * to copy the node value. Otherwise the same pointer value of
247  * the original node is used as value of the copied node.
248  *
249  * The original list both on success or error is never modified. */
250 list *listDup(list *orig)
251 {
252     list *copy;
253     listIter iter;
254     listNode *node;
255 
256     if ((copy = listCreate()) == NULL)
257         return NULL;
258     copy->dup = orig->dup;
259     copy->free = orig->free;
260     copy->match = orig->match;
261     listRewind(orig, &iter);
262     while((node = listNext(&iter)) != NULL) {
263         void *value;
264 
265         if (copy->dup) {
266             value = copy->dup(node->value);
267             if (value == NULL) {
268                 listRelease(copy);
269                 return NULL;
270             }
271         } else
272             value = node->value;
273         if (listAddNodeTail(copy, value) == NULL) {
274             listRelease(copy);
275             return NULL;
276         }
277     }
278     return copy;
279 }
280 
281 /* Search the list for a node matching a given key.
282  * The match is performed using the 'match' method
283  * set with listSetMatchMethod(). If no 'match' method
284  * is set, the 'value' pointer of every node is directly
285  * compared with the 'key' pointer.
286  *
287  * On success the first matching node pointer is returned
288  * (search starts from head). If no matching node exists
289  * NULL is returned. */
290 listNode *listSearchKey(list *list, void *key)
291 {
292     listIter iter;
293     listNode *node;
294 
295     listRewind(list, &iter);
296     while((node = listNext(&iter)) != NULL) {
297         if (list->match) {
298             if (list->match(node->value, key)) {
299                 return node;
300             }
301         } else {
302             if (key == node->value) {
303                 return node;
304             }
305         }
306     }
307     return NULL;
308 }
309 
310 /* Return the element at the specified zero-based index
311  * where 0 is the head, 1 is the element next to head
312  * and so on. Negative integers are used in order to count
313  * from the tail, -1 is the last element, -2 the penultimate
314  * and so on. If the index is out of range NULL is returned. */
315 listNode *listIndex(list *list, long index) {
316     listNode *n;
317 
318     if (index < 0) {
319         index = (-index)-1;
320         n = list->tail;
321         while(index-- && n) n = n->prev;
322     } else {
323         n = list->head;
324         while(index-- && n) n = n->next;
325     }
326     return n;
327 }
328 
329 /* Rotate the list removing the tail node and inserting it to the head. */
330 void listRotate(list *list) {
331     listNode *tail = list->tail;
332 
333     if (listLength(list) <= 1) return;
334 
335     /* Detach current tail */
336     list->tail = tail->prev;
337     list->tail->next = NULL;
338     /* Move it as head */
339     list->head->prev = tail;
340     tail->prev = NULL;
341     tail->next = list->head;
342     list->head = tail;
343 }
344 
345 /* Add all the elements of the list 'o' at the end of the
346  * list 'l'. The list 'other' remains empty but otherwise valid. */
347 void listJoin(list *l, list *o) {
348     if (o->head)
349         o->head->prev = l->tail;
350 
351     if (l->tail)
352         l->tail->next = o->head;
353     else
354         l->head = o->head;
355 
356     if (o->tail) l->tail = o->tail;
357     l->len += o->len;
358 
359     /* Setup other as an empty list. */
360     o->head = o->tail = NULL;
361     o->len = 0;
362 }

Yes, that's it. That's how simple it is

Let's talk a little bit more about it. In fact, it's simpler for listCreate, isn't it

struct list * listCreate(void) {
    return zcalloc(sizeof(struct list));  
}

OK, let's continue to communicate.

 

1.3 'code bracket {} at random

It's not a good habit, after all, no one likes two sides. Big projects still need to unify styles and constraints in the general direction

 

1.4 'struct listIter::direction is not necessarily a good design

Direction distinguishes the direction of traversal by running time comparison with Al? Start? Head or al? Start? Tail macro

It's a bit wasteful. I prefer to kill run-time comparison. From the beginning, users should know how to traverse better. After all, this is all data structures

The benchmark.

 

❤ congratulations, the most basic and simple data structure of redis adlist has been analyzed by handwriting, and we don't need to see it later

Thank you for joining us

 

Body - adlist perimeter

Behind the simple and pleasant things, there will always be something more unpredictable. Without tittler, we will start from a line of code in adlist.c

Our expedition

#include "zmalloc.h"

2. redis config.h analysis

Also in zmallo.c, we found the following two lines of code, which is one of the main bodies we want to talk about config.h

#include "config.h"
#include "atomicvar.h"

config.h is mainly used to determine the running environment of the program, such as the operating system, byte order, and whether to enable some functions

/*
 * Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *   * Neither the name of Redis nor the names of its contributors may be used
 *     to endorse or promote products derived from this software without
 *     specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef __CONFIG_H
#define __CONFIG_H

#ifdef __APPLE__
#include <AvailabilityMacros.h>
#endif

#ifdef __linux__
#include <linux/version.h>
#include <features.h>
#endif

/* Define redis_fstat to fstat or fstat64() */
#if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
#define redis_fstat fstat64
#define redis_stat stat64
#else
#define redis_fstat fstat
#define redis_stat stat
#endif

/* Test for proc filesystem */
#ifdef __linux__
#define HAVE_PROC_STAT 1
#define HAVE_PROC_MAPS 1
#define HAVE_PROC_SMAPS 1
#define HAVE_PROC_SOMAXCONN 1
#endif

/* Test for task_info() */
#if defined(__APPLE__)
#define HAVE_TASKINFO 1
#endif

/* Test for backtrace() */
#if defined(__APPLE__) || (defined(__linux__) && defined(__GLIBC__)) || \
    defined(__FreeBSD__) || (defined(__OpenBSD__) && defined(USE_BACKTRACE))\
 || defined(__DragonFly__)
#define HAVE_BACKTRACE 1
#endif

/* MSG_NOSIGNAL. */
#ifdef __linux__
#define HAVE_MSG_NOSIGNAL 1
#endif

/* Test for polling API */
#ifdef __linux__
#define HAVE_EPOLL 1
#endif

#if (defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined (__NetBSD__)
#define HAVE_KQUEUE 1
#endif

#ifdef __sun
#include <sys/feature_tests.h>
#ifdef _DTRACE_VERSION
#define HAVE_EVPORT 1
#endif
#endif

/* Define redis_fsync to fdatasync() in Linux and fsync() for all the rest */
#ifdef __linux__
#define redis_fsync fdatasync
#else
#define redis_fsync fsync
#endif

/* Define rdb_fsync_range to sync_file_range() on Linux, otherwise we use
 * the plain fsync() call. */
#ifdef __linux__
#if defined(__GLIBC__) && defined(__GLIBC_PREREQ)
#if (LINUX_VERSION_CODE >= 0x020611 && __GLIBC_PREREQ(2, 6))
#define HAVE_SYNC_FILE_RANGE 1
#endif
#else
#if (LINUX_VERSION_CODE >= 0x020611)
#define HAVE_SYNC_FILE_RANGE 1
#endif
#endif
#endif

#ifdef HAVE_SYNC_FILE_RANGE
#define rdb_fsync_range(fd,off,size) sync_file_range(fd,off,size,SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE)
#else
#define rdb_fsync_range(fd,off,size) fsync(fd)
#endif

/* Check if we can use setproctitle().
 * BSD systems have support for it, we provide an implementation for
 * Linux and osx. */
#if (defined __NetBSD__ || defined __FreeBSD__ || defined __OpenBSD__)
#define USE_SETPROCTITLE
#endif

#if ((defined __linux && defined(__GLIBC__)) || defined __APPLE__)
#define USE_SETPROCTITLE
#define INIT_SETPROCTITLE_REPLACEMENT
void spt_init(int argc, char *argv[]);
void setproctitle(const char *fmt, ...);
#endif

/* Byte ordering detection */
#include <sys/types.h> /* This will likely define BYTE_ORDER */

#ifndef BYTE_ORDER
#if (BSD >= 199103)
# include <machine/endian.h>
#else
#if defined(linux) || defined(__linux__)
# include <endian.h>
#else
#define    LITTLE_ENDIAN    1234    /* least-significant byte first (vax, pc) */
#define    BIG_ENDIAN    4321    /* most-significant byte first (IBM, net) */
#define    PDP_ENDIAN    3412    /* LSB first in word, MSW first in long (pdp)*/

#if defined(__i386__) || defined(__x86_64__) || defined(__amd64__) || \
   defined(vax) || defined(ns32000) || defined(sun386) || \
   defined(MIPSEL) || defined(_MIPSEL) || defined(BIT_ZERO_ON_RIGHT) || \
   defined(__alpha__) || defined(__alpha)
#define BYTE_ORDER    LITTLE_ENDIAN
#endif

#if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \
    defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \
    defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || defined(DGUX) ||\
    defined(apollo) || defined(__convex__) || defined(_CRAY) || \
    defined(__hppa) || defined(__hp9000) || \
    defined(__hp9000s300) || defined(__hp9000s700) || \
    defined (BIT_ZERO_ON_LEFT) || defined(m68k) || defined(__sparc)
#define BYTE_ORDER    BIG_ENDIAN
#endif
#endif /* linux */
#endif /* BSD */
#endif /* BYTE_ORDER */

/* Sometimes after including an OS-specific header that defines the
 * endianess we end with __BYTE_ORDER but not with BYTE_ORDER that is what
 * the Redis code uses. In this case let's define everything without the
 * underscores. */
#ifndef BYTE_ORDER
#ifdef __BYTE_ORDER
#if defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN)
#ifndef LITTLE_ENDIAN
#define LITTLE_ENDIAN __LITTLE_ENDIAN
#endif
#ifndef BIG_ENDIAN
#define BIG_ENDIAN __BIG_ENDIAN
#endif
#if (__BYTE_ORDER == __LITTLE_ENDIAN)
#define BYTE_ORDER LITTLE_ENDIAN
#else
#define BYTE_ORDER BIG_ENDIAN
#endif
#endif
#endif
#endif

#if !defined(BYTE_ORDER) || \
    (BYTE_ORDER != BIG_ENDIAN && BYTE_ORDER != LITTLE_ENDIAN)
    /* you must determine what the correct bit order is for
     * your compiler - the next line is an intentional error
     * which will force your compiles to bomb until you fix
     * the above macros.
     */
#error "Undefined or invalid BYTE_ORDER"
#endif

#if (__i386 || __amd64 || __powerpc__) && __GNUC__
#define GNUC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#if defined(__clang__)
#define HAVE_ATOMIC
#endif
#if (defined(__GLIBC__) && defined(__GLIBC_PREREQ))
#if (GNUC_VERSION >= 40100 && __GLIBC_PREREQ(2, 6))
#define HAVE_ATOMIC
#endif
#endif
#endif

/* Make sure we can test for ARM just checking for __arm__, since sometimes
 * __arm is defined but __arm__ is not. */
#if defined(__arm) && !defined(__arm__)
#define __arm__
#endif
#if defined (__aarch64__) && !defined(__arm64__)
#define __arm64__
#endif

/* Make sure we can test for SPARC just checking for __sparc__. */
#if defined(__sparc) && !defined(__sparc__)
#define __sparc__
#endif

#if defined(__sparc__) || defined(__arm__)
#define USE_ALIGNED_ACCESS
#endif

#endif

It can be seen from the macro definition that redis relies on the linux unix type operating system. If at that time redis only focused on

linux services, the mental burden of development and maintenance is expected to be much smaller (purely intentional). Let's start talking

2.1 'bad comments on macro typesetting

We take byte? Order as an example, which is not typeset, aligned and easy to read

// Sometimes after including an OS-specific header that defines the
// endianess we end with __BYTE_ORDER but not with BYTE_ORDER that is what
// the Redis code uses. In this case let's define everything without the
// underscores. 
#ifndef BYTE_ORDER
#  ifdef __BYTE_ORDER

#    if defined __LITTLE_ENDIAN && defined __BIG_ENDIAN

#      ifndef LITTLE_ENDIAN
#        define LITTLE_ENGIAN __LITTLE_ENDIAN
#      endif

#      ifndef BIG_ENDIAN
#        define BIG_ENGIAN __BIG_ENGIAN
#      endif

#     if __BYTE_ORDER == __LITTLE_ENGIAN
#       define BYTE_ORDER LITTLE_ENGIAN
#     else
#       define BYTE_ORDER BIG_ENGIAN
#     endif

#   endif

#  endif
#endif

Let's see if it's refreshing

For config.h, we will not continue to expand config.c, because the starting point of the project is config. This needs to be further deepened

It's basically redis all in. I'd like to give you a free talk about the topic of setting process title for leftovers

#if (defined __linux && defined __GLIBC__) || (defined __APPLE__)

#define USE_SETPROCTITLE

#define INIT_SETPROCTITLE_REPLACEMENT

extern void spt_init(int argc, char * argv[]);
extern void setproctitle(const char * fmt, ...);

#endif

3. Redis setproactive. C analysis

  1 /* ==========================================================================
  2  * setproctitle.c - Linux/Darwin setproctitle.
  3  * --------------------------------------------------------------------------
  4  * Copyright (C) 2010  William Ahern
  5  * Copyright (C) 2013  Salvatore Sanfilippo
  6  * Copyright (C) 2013  Stam He
  7  *
  8  * Permission is hereby granted, free of charge, to any person obtaining a
  9  * copy of this software and associated documentation files (the
 10  * "Software"), to deal in the Software without restriction, including
 11  * without limitation the rights to use, copy, modify, merge, publish,
 12  * distribute, sublicense, and/or sell copies of the Software, and to permit
 13  * persons to whom the Software is furnished to do so, subject to the
 14  * following conditions:
 15  *
 16  * The above copyright notice and this permission notice shall be included
 17  * in all copies or substantial portions of the Software.
 18  *
 19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
 22  * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 23  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 24  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
 25  * USE OR OTHER DEALINGS IN THE SOFTWARE.
 26  * ==========================================================================
 27  */
 28 #ifndef _GNU_SOURCE
 29 #define _GNU_SOURCE
 30 #endif
 31 
 32 #include <stddef.h>    /* NULL size_t */
 33 #include <stdarg.h>    /* va_list va_start va_end */
 34 #include <stdlib.h>    /* malloc(3) setenv(3) clearenv(3) setproctitle(3) getprogname(3) */
 35 #include <stdio.h>    /* vsnprintf(3) snprintf(3) */
 36 
 37 #include <string.h>    /* strlen(3) strchr(3) strdup(3) memset(3) memcpy(3) */
 38 
 39 #include <errno.h>    /* errno program_invocation_name program_invocation_short_name */
 40 
 41 #if !defined(HAVE_SETPROCTITLE)
 42 #if (defined __NetBSD__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __DragonFly__)
 43 #define HAVE_SETPROCTITLE 1
 44 #else
 45 #define HAVE_SETPROCTITLE 0
 46 #endif
 47 #endif
 48 
 49 
 50 #if !HAVE_SETPROCTITLE
 51 #if (defined __linux || defined __APPLE__)
 52 
 53 extern char **environ;
 54 
 55 static struct {
 56     /* original value */
 57     const char *arg0;
 58 
 59     /* title space available */
 60     char *base, *end;
 61 
 62      /* pointer to original nul character within base */
 63     char *nul;
 64 
 65     _Bool reset;
 66     int error;
 67 } SPT;
 68 
 69 
 70 #ifndef SPT_MIN
 71 #define SPT_MIN(a, b) (((a) < (b))? (a) : (b))
 72 #endif
 73 
 74 static inline size_t spt_min(size_t a, size_t b) {
 75     return SPT_MIN(a, b);
 76 } /* spt_min() */
 77 
 78 
 79 /*
 80  * For discussion on the portability of the various methods, see
 81  * http://lists.freebsd.org/pipermail/freebsd-stable/2008-June/043136.html
 82  */
 83 static int spt_clearenv(void) {
 84 #if __GLIBC__
 85     clearenv();
 86 
 87     return 0;
 88 #else
 89     extern char **environ;
 90     static char **tmp;
 91 
 92     if (!(tmp = malloc(sizeof *tmp)))
 93         return errno;
 94 
 95     tmp[0]  = NULL;
 96     environ = tmp;
 97 
 98     return 0;
 99 #endif
100 } /* spt_clearenv() */
101 
102 
103 static int spt_copyenv(char *oldenv[]) {
104     extern char **environ;
105     char *eq;
106     int i, error;
107 
108     if (environ != oldenv)
109         return 0;
110 
111     if ((error = spt_clearenv()))
112         goto error;
113 
114     for (i = 0; oldenv[i]; i++) {
115         if (!(eq = strchr(oldenv[i], '=')))
116             continue;
117 
118         *eq = '\0';
119         error = (0 != setenv(oldenv[i], eq + 1, 1))? errno : 0;
120         *eq = '=';
121 
122         if (error)
123             goto error;
124     }
125 
126     return 0;
127 error:
128     environ = oldenv;
129 
130     return error;
131 } /* spt_copyenv() */
132 
133 
134 static int spt_copyargs(int argc, char *argv[]) {
135     char *tmp;
136     int i;
137 
138     for (i = 1; i < argc || (i >= argc && argv[i]); i++) {
139         if (!argv[i])
140             continue;
141 
142         if (!(tmp = strdup(argv[i])))
143             return errno;
144 
145         argv[i] = tmp;
146     }
147 
148     return 0;
149 } /* spt_copyargs() */
150 
151 
152 void spt_init(int argc, char *argv[]) {
153         char **envp = environ;
154     char *base, *end, *nul, *tmp;
155     int i, error;
156 
157     if (!(base = argv[0]))
158         return;
159 
160     nul = &base[strlen(base)];
161     end = nul + 1;
162 
163     for (i = 0; i < argc || (i >= argc && argv[i]); i++) {
164         if (!argv[i] || argv[i] < end)
165             continue;
166 
167         end = argv[i] + strlen(argv[i]) + 1;
168     }
169 
170     for (i = 0; envp[i]; i++) {
171         if (envp[i] < end)
172             continue;
173 
174         end = envp[i] + strlen(envp[i]) + 1;
175     }
176 
177     if (!(SPT.arg0 = strdup(argv[0])))
178         goto syerr;
179 
180 #if __GLIBC__
181     if (!(tmp = strdup(program_invocation_name)))
182         goto syerr;
183 
184     program_invocation_name = tmp;
185 
186     if (!(tmp = strdup(program_invocation_short_name)))
187         goto syerr;
188 
189     program_invocation_short_name = tmp;
190 #elif __APPLE__
191     if (!(tmp = strdup(getprogname())))
192         goto syerr;
193 
194     setprogname(tmp);
195 #endif
196 
197 
198     if ((error = spt_copyenv(envp)))
199         goto error;
200 
201     if ((error = spt_copyargs(argc, argv)))
202         goto error;
203 
204     SPT.nul  = nul;
205     SPT.base = base;
206     SPT.end  = end;
207 
208     return;
209 syerr:
210     error = errno;
211 error:
212     SPT.error = error;
213 } /* spt_init() */
214 
215 
216 #ifndef SPT_MAXTITLE
217 #define SPT_MAXTITLE 255
218 #endif
219 
220 void setproctitle(const char *fmt, ...) {
221     char buf[SPT_MAXTITLE + 1]; /* use buffer in case argv[0] is passed */
222     va_list ap;
223     char *nul;
224     int len, error;
225 
226     if (!SPT.base)
227         return;
228 
229     if (fmt) {
230         va_start(ap, fmt);
231         len = vsnprintf(buf, sizeof buf, fmt, ap);
232         va_end(ap);
233     } else {
234         len = snprintf(buf, sizeof buf, "%s", SPT.arg0);
235     }
236 
237     if (len <= 0)
238         { error = errno; goto error; }
239 
240     if (!SPT.reset) {
241         memset(SPT.base, 0, SPT.end - SPT.base);
242         SPT.reset = 1;
243     } else {
244         memset(SPT.base, 0, spt_min(sizeof buf, SPT.end - SPT.base));
245     }
246 
247     len = spt_min(len, spt_min(sizeof buf, SPT.end - SPT.base) - 1);
248     memcpy(SPT.base, buf, len);
249     nul = &SPT.base[len];
250 
251     if (nul < SPT.nul) {
252         *SPT.nul = '.';
253     } else if (nul == SPT.nul && &nul[1] < SPT.end) {
254         *SPT.nul = ' ';
255         *++nul = '\0';
256     }
257 
258     return;
259 error:
260     SPT.error = error;
261 } /* setproctitle() */
262 
263 
264 #endif /* __linux || __APPLE__ */
265 #endif /* !HAVE_SETPROCTITLE */

3.1' spt_clearenv -> spt_copyenv -> setenv -> goto error -> environ = oldenv  memory leak

https://github.com/antirez/redis/pull/6588/commits/ec5405b7ccf809929ff105aeb14d9854896f9d68  

Interested friends can communicate together. For more information, please refer to the interaction between me and this blogger (setting the process name)

https://www.cnblogs.com/imlgc/p/3823990.html#4428962

4. redis atomicvar.h analysis

  1 /* This file implements atomic counters using __atomic or __sync macros if
  2  * available, otherwise synchronizing different threads using a mutex.
  3  *
  4  * The exported interface is composed of three macros:
  5  *
  6  * atomicIncr(var,count) -- Increment the atomic counter
  7  * atomicGetIncr(var,oldvalue_var,count) -- Get and increment the atomic counter
  8  * atomicDecr(var,count) -- Decrement the atomic counter
  9  * atomicGet(var,dstvar) -- Fetch the atomic counter value
 10  * atomicSet(var,value)  -- Set the atomic counter value
 11  *
 12  * The variable 'var' should also have a declared mutex with the same
 13  * name and the "_mutex" postfix, for instance:
 14  *
 15  *  long myvar;
 16  *  pthread_mutex_t myvar_mutex;
 17  *  atomicSet(myvar,12345);
 18  *
 19  * If atomic primitives are available (tested in config.h) the mutex
 20  * is not used.
 21  *
 22  * Never use return value from the macros, instead use the AtomicGetIncr()
 23  * if you need to get the current value and increment it atomically, like
 24  * in the followign example:
 25  *
 26  *  long oldvalue;
 27  *  atomicGetIncr(myvar,oldvalue,1);
 28  *  doSomethingWith(oldvalue);
 29  *
 30  * ----------------------------------------------------------------------------
 31  *
 32  * Copyright (c) 2015, Salvatore Sanfilippo <antirez at gmail dot com>
 33  * All rights reserved.
 34  *
 35  * Redistribution and use in source and binary forms, with or without
 36  * modification, are permitted provided that the following conditions are met:
 37  *
 38  *   * Redistributions of source code must retain the above copyright notice,
 39  *     this list of conditions and the following disclaimer.
 40  *   * Redistributions in binary form must reproduce the above copyright
 41  *     notice, this list of conditions and the following disclaimer in the
 42  *     documentation and/or other materials provided with the distribution.
 43  *   * Neither the name of Redis nor the names of its contributors may be used
 44  *     to endorse or promote products derived from this software without
 45  *     specific prior written permission.
 46  *
 47  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 48  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 49  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 50  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 51  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 52  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 53  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 54  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 55  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 56  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 57  * POSSIBILITY OF SUCH DAMAGE.
 58  */
 59 
 60 #include <pthread.h>
 61 
 62 #ifndef __ATOMIC_VAR_H
 63 #define __ATOMIC_VAR_H
 64 
 65 /* To test Redis with Helgrind (a Valgrind tool) it is useful to define
 66  * the following macro, so that __sync macros are used: those can be detected
 67  * by Helgrind (even if they are less efficient) so that no false positive
 68  * is reported. */
 69 // #define __ATOMIC_VAR_FORCE_SYNC_MACROS
 70 
 71 #if !defined(__ATOMIC_VAR_FORCE_SYNC_MACROS) && defined(__ATOMIC_RELAXED) && !defined(__sun) && (!defined(__clang__) || !defined(__APPLE__) || __apple_build_version__ > 4210057)
 72 /* Implementation using __atomic macros. */
 73 
 74 #define atomicIncr(var,count) __atomic_add_fetch(&var,(count),__ATOMIC_RELAXED)
 75 #define atomicGetIncr(var,oldvalue_var,count) do { \
 76     oldvalue_var = __atomic_fetch_add(&var,(count),__ATOMIC_RELAXED); \
 77 } while(0)
 78 #define atomicDecr(var,count) __atomic_sub_fetch(&var,(count),__ATOMIC_RELAXED)
 79 #define atomicGet(var,dstvar) do { \
 80     dstvar = __atomic_load_n(&var,__ATOMIC_RELAXED); \
 81 } while(0)
 82 #define atomicSet(var,value) __atomic_store_n(&var,value,__ATOMIC_RELAXED)
 83 #define REDIS_ATOMIC_API "atomic-builtin"
 84 
 85 #elif defined(HAVE_ATOMIC)
 86 /* Implementation using __sync macros. */
 87 
 88 #define atomicIncr(var,count) __sync_add_and_fetch(&var,(count))
 89 #define atomicGetIncr(var,oldvalue_var,count) do { \
 90     oldvalue_var = __sync_fetch_and_add(&var,(count)); \
 91 } while(0)
 92 #define atomicDecr(var,count) __sync_sub_and_fetch(&var,(count))
 93 #define atomicGet(var,dstvar) do { \
 94     dstvar = __sync_sub_and_fetch(&var,0); \
 95 } while(0)
 96 #define atomicSet(var,value) do { \
 97     while(!__sync_bool_compare_and_swap(&var,var,value)); \
 98 } while(0)
 99 #define REDIS_ATOMIC_API "sync-builtin"
100 
101 #else
102 /* Implementation using pthread mutex. */
103 
104 #define atomicIncr(var,count) do { \
105     pthread_mutex_lock(&var ## _mutex); \
106     var += (count); \
107     pthread_mutex_unlock(&var ## _mutex); \
108 } while(0)
109 #define atomicGetIncr(var,oldvalue_var,count) do { \
110     pthread_mutex_lock(&var ## _mutex); \
111     oldvalue_var = var; \
112     var += (count); \
113     pthread_mutex_unlock(&var ## _mutex); \
114 } while(0)
115 #define atomicDecr(var,count) do { \
116     pthread_mutex_lock(&var ## _mutex); \
117     var -= (count); \
118     pthread_mutex_unlock(&var ## _mutex); \
119 } while(0)
120 #define atomicGet(var,dstvar) do { \
121     pthread_mutex_lock(&var ## _mutex); \
122     dstvar = var; \
123     pthread_mutex_unlock(&var ## _mutex); \
124 } while(0)
125 #define atomicSet(var,value) do { \
126     pthread_mutex_lock(&var ## _mutex); \
127     var = value; \
128     pthread_mutex_unlock(&var ## _mutex); \
129 } while(0)
130 #define REDIS_ATOMIC_API "pthread-mutex"
131 
132 #endif
133 #endif /* __ATOMIC_VAR_H */

There are three ways to encapsulate atomic library operations: C11 stdatomic.h, GCC sync, and POSIX pthread.h

The "atomic operation" encapsulated by pthread.h is not so universal, because it is strongly bound to the business. It can only be used under the redis project. The reason is that it depends on the definition in advance

Good variable var mutex

pthread_mutex_lock(&var ## _mutex); \

You can find an example. For example, the code in src/lazyfree.c is as follows

#include "server.h"
#include "bio.h"
#include "atomicvar.h"
#include "cluster.h"

static size_t lazyfree_objects = 0;
pthread_mutex_t lazyfree_objects_mutex = PTHREAD_MUTEX_INITIALIZER;

Define "lazyfree" and "lazyfree" objects "in advance to use the atomic operation macro encapsulated by pthread. Additional optimization

You can replace while sync bool compare and swap with sync lock test and set

https://github.com/antirez/redis/pull/6567/commits/dc1e369d6c12df73f128822b7ba30cdc4dd4357a

5. redis zmalloc analysis

  1 /* zmalloc - total amount of allocated memory aware version of malloc()
  2  *
  3  * Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
  4  * All rights reserved.
  5  *
  6  * Redistribution and use in source and binary forms, with or without
  7  * modification, are permitted provided that the following conditions are met:
  8  *
  9  *   * Redistributions of source code must retain the above copyright notice,
 10  *     this list of conditions and the following disclaimer.
 11  *   * Redistributions in binary form must reproduce the above copyright
 12  *     notice, this list of conditions and the following disclaimer in the
 13  *     documentation and/or other materials provided with the distribution.
 14  *   * Neither the name of Redis nor the names of its contributors may be used
 15  *     to endorse or promote products derived from this software without
 16  *     specific prior written permission.
 17  *
 18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 28  * POSSIBILITY OF SUCH DAMAGE.
 29  */
 30 
 31 #ifndef __ZMALLOC_H
 32 #define __ZMALLOC_H
 33 
 34 /* Double expansion needed for stringification of macro values. */
 35 #define __xstr(s) __str(s)
 36 #define __str(s) #s
 37 
 38 #if defined(USE_TCMALLOC)
 39 #define ZMALLOC_LIB ("tcmalloc-" __xstr(TC_VERSION_MAJOR) "." __xstr(TC_VERSION_MINOR))
 40 #include <google/tcmalloc.h>
 41 #if (TC_VERSION_MAJOR == 1 && TC_VERSION_MINOR >= 6) || (TC_VERSION_MAJOR > 1)
 42 #define HAVE_MALLOC_SIZE 1
 43 #define zmalloc_size(p) tc_malloc_size(p)
 44 #else
 45 #error "Newer version of tcmalloc required"
 46 #endif
 47 
 48 #elif defined(USE_JEMALLOC)
 49 #define ZMALLOC_LIB ("jemalloc-" __xstr(JEMALLOC_VERSION_MAJOR) "." __xstr(JEMALLOC_VERSION_MINOR) "." __xstr(JEMALLOC_VERSION_BUGFIX))
 50 #include <jemalloc/jemalloc.h>
 51 #if (JEMALLOC_VERSION_MAJOR == 2 && JEMALLOC_VERSION_MINOR >= 1) || (JEMALLOC_VERSION_MAJOR > 2)
 52 #define HAVE_MALLOC_SIZE 1
 53 #define zmalloc_size(p) je_malloc_usable_size(p)
 54 #else
 55 #error "Newer version of jemalloc required"
 56 #endif
 57 
 58 #elif defined(__APPLE__)
 59 #include <malloc/malloc.h>
 60 #define HAVE_MALLOC_SIZE 1
 61 #define zmalloc_size(p) malloc_size(p)
 62 #endif
 63 
 64 #ifndef ZMALLOC_LIB
 65 #define ZMALLOC_LIB "libc"
 66 #ifdef __GLIBC__
 67 #include <malloc.h>
 68 #define HAVE_MALLOC_SIZE 1
 69 #define zmalloc_size(p) malloc_usable_size(p)
 70 #endif
 71 #endif
 72 
 73 /* We can enable the Redis defrag capabilities only if we are using Jemalloc
 74  * and the version used is our special version modified for Redis having
 75  * the ability to return per-allocation fragmentation hints. */
 76 #if defined(USE_JEMALLOC) && defined(JEMALLOC_FRAG_HINT)
 77 #define HAVE_DEFRAG
 78 #endif
 79 
 80 void *zmalloc(size_t size);
 81 void *zcalloc(size_t size);
 82 void *zrealloc(void *ptr, size_t size);
 83 void zfree(void *ptr);
 84 char *zstrdup(const char *s);
 85 size_t zmalloc_used_memory(void);
 86 void zmalloc_set_oom_handler(void (*oom_handler)(size_t));
 87 size_t zmalloc_get_rss(void);
 88 int zmalloc_get_allocator_info(size_t *allocated, size_t *active, size_t *resident);
 89 void set_jemalloc_bg_thread(int enable);
 90 int jemalloc_purge();
 91 size_t zmalloc_get_private_dirty(long pid);
 92 size_t zmalloc_get_smap_bytes_by_field(char *field, long pid);
 93 size_t zmalloc_get_memory_size(void);
 94 void zlibc_free(void *ptr);
 95 
 96 #ifdef HAVE_DEFRAG
 97 void zfree_no_tcache(void *ptr);
 98 void *zmalloc_no_tcache(size_t size);
 99 #endif
100 
101 #ifndef HAVE_MALLOC_SIZE
102 size_t zmalloc_size(void *ptr);
103 size_t zmalloc_usable(void *ptr);
104 #else
105 #define zmalloc_usable(p) zmalloc_size(p)
106 #endif
107 
108 #ifdef REDIS_TEST
109 int zmalloc_test(int argc, char **argv);
110 #endif
111 
112 #endif /* __ZMALLOC_H */

The memory module supports rich external libraries, so it's a bit wordy to write naturally. Here's a trick. Let's assume that only use jemalloc is used

Then the code goes all the way. Is it convenient to roar

  1 /* zmalloc - total amount of allocated memory aware version of malloc()
  2  *
  3  * Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
  4  * All rights reserved.
  5  *
  6  * Redistribution and use in source and binary forms, with or without
  7  * modification, are permitted provided that the following conditions are met:
  8  *
  9  *   * Redistributions of source code must retain the above copyright notice,
 10  *     this list of conditions and the following disclaimer.
 11  *   * Redistributions in binary form must reproduce the above copyright
 12  *     notice, this list of conditions and the following disclaimer in the
 13  *     documentation and/or other materials provided with the distribution.
 14  *   * Neither the name of Redis nor the names of its contributors may be used
 15  *     to endorse or promote products derived from this software without
 16  *     specific prior written permission.
 17  *
 18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 28  * POSSIBILITY OF SUCH DAMAGE.
 29  */
 30 
 31 #include <stdio.h>
 32 #include <stdlib.h>
 33 #include <stdint.h>
 34 
 35 /* This function provide us access to the original libc free(). This is useful
 36  * for instance to free results obtained by backtrace_symbols(). We need
 37  * to define this function before including zmalloc.h that may shadow the
 38  * free implementation if we use jemalloc or another non standard allocator. */
 39 void zlibc_free(void *ptr) {
 40     free(ptr);
 41 }
 42 
 43 #include <string.h>
 44 #include <pthread.h>
 45 #include "config.h"
 46 #include "zmalloc.h"
 47 #include "atomicvar.h"
 48 
 49 #ifdef HAVE_MALLOC_SIZE
 50 #define PREFIX_SIZE (0)
 51 #else
 52 #if defined(__sun) || defined(__sparc) || defined(__sparc__)
 53 #define PREFIX_SIZE (sizeof(long long))
 54 #else
 55 #define PREFIX_SIZE (sizeof(size_t))
 56 #endif
 57 #endif
 58 
 59 /* Explicitly override malloc/free etc when using tcmalloc. */
 60 #if defined(USE_TCMALLOC)
 61 #define malloc(size) tc_malloc(size)
 62 #define calloc(count,size) tc_calloc(count,size)
 63 #define realloc(ptr,size) tc_realloc(ptr,size)
 64 #define free(ptr) tc_free(ptr)
 65 #elif defined(USE_JEMALLOC)
 66 #define malloc(size) je_malloc(size)
 67 #define calloc(count,size) je_calloc(count,size)
 68 #define realloc(ptr,size) je_realloc(ptr,size)
 69 #define free(ptr) je_free(ptr)
 70 #define mallocx(size,flags) je_mallocx(size,flags)
 71 #define dallocx(ptr,flags) je_dallocx(ptr,flags)
 72 #endif
 73 
 74 #define update_zmalloc_stat_alloc(__n) do { \
 75     size_t _n = (__n); \
 76     if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
 77     atomicIncr(used_memory,__n); \
 78 } while(0)
 79 
 80 #define update_zmalloc_stat_free(__n) do { \
 81     size_t _n = (__n); \
 82     if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
 83     atomicDecr(used_memory,__n); \
 84 } while(0)
 85 
 86 static size_t used_memory = 0;
 87 pthread_mutex_t used_memory_mutex = PTHREAD_MUTEX_INITIALIZER;
 88 
 89 static void zmalloc_default_oom(size_t size) {
 90     fprintf(stderr, "zmalloc: Out of memory trying to allocate %zu bytes\n",
 91         size);
 92     fflush(stderr);
 93     abort();
 94 }
 95 
 96 static void (*zmalloc_oom_handler)(size_t) = zmalloc_default_oom;
 97 
 98 void *zmalloc(size_t size) {
 99     void *ptr = malloc(size+PREFIX_SIZE);
100 
101     if (!ptr) zmalloc_oom_handler(size);
102 #ifdef HAVE_MALLOC_SIZE
103     update_zmalloc_stat_alloc(zmalloc_size(ptr));
104     return ptr;
105 #else
106     *((size_t*)ptr) = size;
107     update_zmalloc_stat_alloc(size+PREFIX_SIZE);
108     return (char*)ptr+PREFIX_SIZE;
109 #endif
110 }
111 
112 /* Allocation and free functions that bypass the thread cache
113  * and go straight to the allocator arena bins.
114  * Currently implemented only for jemalloc. Used for online defragmentation. */
115 #ifdef HAVE_DEFRAG
116 void *zmalloc_no_tcache(size_t size) {
117     void *ptr = mallocx(size+PREFIX_SIZE, MALLOCX_TCACHE_NONE);
118     if (!ptr) zmalloc_oom_handler(size);
119     update_zmalloc_stat_alloc(zmalloc_size(ptr));
120     return ptr;
121 }
122 
123 void zfree_no_tcache(void *ptr) {
124     if (ptr == NULL) return;
125     update_zmalloc_stat_free(zmalloc_size(ptr));
126     dallocx(ptr, MALLOCX_TCACHE_NONE);
127 }
128 #endif
129 
130 void *zcalloc(size_t size) {
131     void *ptr = calloc(1, size+PREFIX_SIZE);
132 
133     if (!ptr) zmalloc_oom_handler(size);
134 #ifdef HAVE_MALLOC_SIZE
135     update_zmalloc_stat_alloc(zmalloc_size(ptr));
136     return ptr;
137 #else
138     *((size_t*)ptr) = size;
139     update_zmalloc_stat_alloc(size+PREFIX_SIZE);
140     return (char*)ptr+PREFIX_SIZE;
141 #endif
142 }
143 
144 void *zrealloc(void *ptr, size_t size) {
145 #ifndef HAVE_MALLOC_SIZE
146     void *realptr;
147 #endif
148     size_t oldsize;
149     void *newptr;
150 
151     if (size == 0 && ptr != NULL) {
152         zfree(ptr);
153         return NULL;
154     }
155     if (ptr == NULL) return zmalloc(size);
156 #ifdef HAVE_MALLOC_SIZE
157     oldsize = zmalloc_size(ptr);
158     newptr = realloc(ptr,size);
159     if (!newptr) zmalloc_oom_handler(size);
160 
161     update_zmalloc_stat_free(oldsize);
162     update_zmalloc_stat_alloc(zmalloc_size(newptr));
163     return newptr;
164 #else
165     realptr = (char*)ptr-PREFIX_SIZE;
166     oldsize = *((size_t*)realptr);
167     newptr = realloc(realptr,size+PREFIX_SIZE);
168     if (!newptr) zmalloc_oom_handler(size);
169 
170     *((size_t*)newptr) = size;
171     update_zmalloc_stat_free(oldsize+PREFIX_SIZE);
172     update_zmalloc_stat_alloc(size+PREFIX_SIZE);
173     return (char*)newptr+PREFIX_SIZE;
174 #endif
175 }
176 
177 /* Provide zmalloc_size() for systems where this function is not provided by
178  * malloc itself, given that in that case we store a header with this
179  * information as the first bytes of every allocation. */
180 #ifndef HAVE_MALLOC_SIZE
181 size_t zmalloc_size(void *ptr) {
182     void *realptr = (char*)ptr-PREFIX_SIZE;
183     size_t size = *((size_t*)realptr);
184     /* Assume at least that all the allocations are padded at sizeof(long) by
185      * the underlying allocator. */
186     if (size&(sizeof(long)-1)) size += sizeof(long)-(size&(sizeof(long)-1));
187     return size+PREFIX_SIZE;
188 }
189 size_t zmalloc_usable(void *ptr) {
190     return zmalloc_size(ptr)-PREFIX_SIZE;
191 }
192 #endif
193 
194 void zfree(void *ptr) {
195 #ifndef HAVE_MALLOC_SIZE
196     void *realptr;
197     size_t oldsize;
198 #endif
199 
200     if (ptr == NULL) return;
201 #ifdef HAVE_MALLOC_SIZE
202     update_zmalloc_stat_free(zmalloc_size(ptr));
203     free(ptr);
204 #else
205     realptr = (char*)ptr-PREFIX_SIZE;
206     oldsize = *((size_t*)realptr);
207     update_zmalloc_stat_free(oldsize+PREFIX_SIZE);
208     free(realptr);
209 #endif
210 }
211 
212 char *zstrdup(const char *s) {
213     size_t l = strlen(s)+1;
214     char *p = zmalloc(l);
215 
216     memcpy(p,s,l);
217     return p;
218 }
219 
220 size_t zmalloc_used_memory(void) {
221     size_t um;
222     atomicGet(used_memory,um);
223     return um;
224 }
225 
226 void zmalloc_set_oom_handler(void (*oom_handler)(size_t)) {
227     zmalloc_oom_handler = oom_handler;
228 }
229 
230 /* Get the RSS information in an OS-specific way.
231  *
232  * WARNING: the function zmalloc_get_rss() is not designed to be fast
233  * and may not be called in the busy loops where Redis tries to release
234  * memory expiring or swapping out objects.
235  *
236  * For this kind of "fast RSS reporting" usages use instead the
237  * function RedisEstimateRSS() that is a much faster (and less precise)
238  * version of the function. */
239 
240 #if defined(HAVE_PROC_STAT)
241 #include <unistd.h>
242 #include <sys/types.h>
243 #include <sys/stat.h>
244 #include <fcntl.h>
245 
246 size_t zmalloc_get_rss(void) {
247     int page = sysconf(_SC_PAGESIZE);
248     size_t rss;
249     char buf[4096];
250     char filename[256];
251     int fd, count;
252     char *p, *x;
253 
254     snprintf(filename,256,"/proc/%d/stat",getpid());
255     if ((fd = open(filename,O_RDONLY)) == -1) return 0;
256     if (read(fd,buf,4096) <= 0) {
257         close(fd);
258         return 0;
259     }
260     close(fd);
261 
262     p = buf;
263     count = 23; /* RSS is the 24th field in /proc/<pid>/stat */
264     while(p && count--) {
265         p = strchr(p,' ');
266         if (p) p++;
267     }
268     if (!p) return 0;
269     x = strchr(p,' ');
270     if (!x) return 0;
271     *x = '\0';
272 
273     rss = strtoll(p,NULL,10);
274     rss *= page;
275     return rss;
276 }
277 #elif defined(HAVE_TASKINFO)
278 #include <unistd.h>
279 #include <stdio.h>
280 #include <stdlib.h>
281 #include <sys/types.h>
282 #include <sys/sysctl.h>
283 #include <mach/task.h>
284 #include <mach/mach_init.h>
285 
286 size_t zmalloc_get_rss(void) {
287     task_t task = MACH_PORT_NULL;
288     struct task_basic_info t_info;
289     mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
290 
291     if (task_for_pid(current_task(), getpid(), &task) != KERN_SUCCESS)
292         return 0;
293     task_info(task, TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count);
294 
295     return t_info.resident_size;
296 }
297 #elif defined(__FreeBSD__)
298 #include <sys/types.h>
299 #include <sys/sysctl.h>
300 #include <sys/user.h>
301 #include <unistd.h>
302 
303 size_t zmalloc_get_rss(void) {
304     struct kinfo_proc info;
305     size_t infolen = sizeof(info);
306     int mib[4];
307     mib[0] = CTL_KERN;
308     mib[1] = KERN_PROC;
309     mib[2] = KERN_PROC_PID;
310     mib[3] = getpid();
311 
312     if (sysctl(mib, 4, &info, &infolen, NULL, 0) == 0)
313         return (size_t)info.ki_rssize;
314 
315     return 0L;
316 }
317 #else
318 size_t zmalloc_get_rss(void) {
319     /* If we can't get the RSS in an OS-specific way for this system just
320      * return the memory usage we estimated in zmalloc()..
321      *
322      * Fragmentation will appear to be always 1 (no fragmentation)
323      * of course... */
324     return zmalloc_used_memory();
325 }
326 #endif
327 
328 #if defined(USE_JEMALLOC)
329 
330 int zmalloc_get_allocator_info(size_t *allocated,
331                                size_t *active,
332                                size_t *resident) {
333     uint64_t epoch = 1;
334     size_t sz;
335     *allocated = *resident = *active = 0;
336     /* Update the statistics cached by mallctl. */
337     sz = sizeof(epoch);
338     je_mallctl("epoch", &epoch, &sz, &epoch, sz);
339     sz = sizeof(size_t);
340     /* Unlike RSS, this does not include RSS from shared libraries and other non
341      * heap mappings. */
342     je_mallctl("stats.resident", resident, &sz, NULL, 0);
343     /* Unlike resident, this doesn't not include the pages jemalloc reserves
344      * for re-use (purge will clean that). */
345     je_mallctl("stats.active", active, &sz, NULL, 0);
346     /* Unlike zmalloc_used_memory, this matches the stats.resident by taking
347      * into account all allocations done by this process (not only zmalloc). */
348     je_mallctl("stats.allocated", allocated, &sz, NULL, 0);
349     return 1;
350 }
351 
352 void set_jemalloc_bg_thread(int enable) {
353     /* let jemalloc do purging asynchronously, required when there's no traffic 
354      * after flushdb */
355     char val = !!enable;
356     je_mallctl("background_thread", NULL, 0, &val, 1);
357 }
358 
359 int jemalloc_purge() {
360     /* return all unused (reserved) pages to the OS */
361     char tmp[32];
362     unsigned narenas = 0;
363     size_t sz = sizeof(unsigned);
364     if (!je_mallctl("arenas.narenas", &narenas, &sz, NULL, 0)) {
365         sprintf(tmp, "arena.%d.purge", narenas);
366         if (!je_mallctl(tmp, NULL, 0, NULL, 0))
367             return 0;
368     }
369     return -1;
370 }
371 
372 #else
373 
374 int zmalloc_get_allocator_info(size_t *allocated,
375                                size_t *active,
376                                size_t *resident) {
377     *allocated = *resident = *active = 0;
378     return 1;
379 }
380 
381 void set_jemalloc_bg_thread(int enable) {
382     ((void)(enable));
383 }
384 
385 int jemalloc_purge() {
386     return 0;
387 }
388 
389 #endif
390 
391 /* Get the sum of the specified field (converted form kb to bytes) in
392  * /proc/self/smaps. The field must be specified with trailing ":" as it
393  * apperas in the smaps output.
394  *
395  * If a pid is specified, the information is extracted for such a pid,
396  * otherwise if pid is -1 the information is reported is about the
397  * current process.
398  *
399  * Example: zmalloc_get_smap_bytes_by_field("Rss:",-1);
400  */
401 #if defined(HAVE_PROC_SMAPS)
402 size_t zmalloc_get_smap_bytes_by_field(char *field, long pid) {
403     char line[1024];
404     size_t bytes = 0;
405     int flen = strlen(field);
406     FILE *fp;
407 
408     if (pid == -1) {
409         fp = fopen("/proc/self/smaps","r");
410     } else {
411         char filename[128];
412         snprintf(filename,sizeof(filename),"/proc/%ld/smaps",pid);
413         fp = fopen(filename,"r");
414     }
415 
416     if (!fp) return 0;
417     while(fgets(line,sizeof(line),fp) != NULL) {
418         if (strncmp(line,field,flen) == 0) {
419             char *p = strchr(line,'k');
420             if (p) {
421                 *p = '\0';
422                 bytes += strtol(line+flen,NULL,10) * 1024;
423             }
424         }
425     }
426     fclose(fp);
427     return bytes;
428 }
429 #else
430 size_t zmalloc_get_smap_bytes_by_field(char *field, long pid) {
431     ((void) field);
432     ((void) pid);
433     return 0;
434 }
435 #endif
436 
437 size_t zmalloc_get_private_dirty(long pid) {
438     return zmalloc_get_smap_bytes_by_field("Private_Dirty:",pid);
439 }
440 
441 /* Returns the size of physical memory (RAM) in bytes.
442  * It looks ugly, but this is the cleanest way to achieve cross platform results.
443  * Cleaned up from:
444  *
445  * http://nadeausoftware.com/articles/2012/09/c_c_tip_how_get_physical_memory_size_system
446  *
447  * Note that this function:
448  * 1) Was released under the following CC attribution license:
449  *    http://creativecommons.org/licenses/by/3.0/deed.en_US.
450  * 2) Was originally implemented by David Robert Nadeau.
451  * 3) Was modified for Redis by Matt Stancliff.
452  * 4) This note exists in order to comply with the original license.
453  */
454 size_t zmalloc_get_memory_size(void) {
455 #if defined(__unix__) || defined(__unix) || defined(unix) || \
456     (defined(__APPLE__) && defined(__MACH__))
457 #if defined(CTL_HW) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM64))
458     int mib[2];
459     mib[0] = CTL_HW;
460 #if defined(HW_MEMSIZE)
461     mib[1] = HW_MEMSIZE;            /* OSX. --------------------- */
462 #elif defined(HW_PHYSMEM64)
463     mib[1] = HW_PHYSMEM64;          /* NetBSD, OpenBSD. --------- */
464 #endif
465     int64_t size = 0;               /* 64-bit */
466     size_t len = sizeof(size);
467     if (sysctl( mib, 2, &size, &len, NULL, 0) == 0)
468         return (size_t)size;
469     return 0L;          /* Failed? */
470 
471 #elif defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
472     /* FreeBSD, Linux, OpenBSD, and Solaris. -------------------- */
473     return (size_t)sysconf(_SC_PHYS_PAGES) * (size_t)sysconf(_SC_PAGESIZE);
474 
475 #elif defined(CTL_HW) && (defined(HW_PHYSMEM) || defined(HW_REALMEM))
476     /* DragonFly BSD, FreeBSD, NetBSD, OpenBSD, and OSX. -------- */
477     int mib[2];
478     mib[0] = CTL_HW;
479 #if defined(HW_REALMEM)
480     mib[1] = HW_REALMEM;        /* FreeBSD. ----------------- */
481 #elif defined(HW_PHYSMEM)
482     mib[1] = HW_PHYSMEM;        /* Others. ------------------ */
483 #endif
484     unsigned int size = 0;      /* 32-bit */
485     size_t len = sizeof(size);
486     if (sysctl(mib, 2, &size, &len, NULL, 0) == 0)
487         return (size_t)size;
488     return 0L;          /* Failed? */
489 #else
490     return 0L;          /* Unknown method to get the data. */
491 #endif
492 #else
493     return 0L;          /* Unknown OS. */
494 #endif
495 }
496 
497 #ifdef REDIS_TEST
498 #define UNUSED(x) ((void)(x))
499 int zmalloc_test(int argc, char **argv) {
500     void *ptr;
501 
502     UNUSED(argc);
503     UNUSED(argv);
504     printf("Initial used memory: %zu\n", zmalloc_used_memory());
505     ptr = zmalloc(123);
506     printf("Allocated 123 bytes; used: %zu\n", zmalloc_used_memory());
507     ptr = zrealloc(ptr, 456);
508     printf("Reallocated to 456 bytes; used: %zu\n", zmalloc_used_memory());
509     zfree(ptr);
510     printf("Freed pointer; used: %zu\n", zmalloc_used_memory());
511     return 0;
512 }
513 #endif

An optimization is proposed here to reduce the invalid operation of code

https://github.com/antirez/redis/pull/6591/commits/ddeece5d690ec41af051a842afe20a3e0ba25d37

The overall code is very simple. Prefix "size is used to record the size of the applied memory block. If it's extra, it's easy to write. Compared with others, it's clear

There are more zmalloc UU test unit tests in the module. You can see src/server.c for the call place

void _serverPanic(const char *file, int line, const char *msg, ...) {
    va_list ap;
    va_start(ap,msg);
    char fmtmsg[256];
    vsnprintf(fmtmsg,sizeof(fmtmsg),msg,ap);
    va_end(ap);

    bugReportStart();
    serverLog(LL_WARNING,"------------------------------------------------");
    serverLog(LL_WARNING,"!!! Software Failure. Press left mouse button to continue");
    serverLog(LL_WARNING,"Guru Meditation: %s #%s:%d",fmtmsg,file,line);
#ifdef HAVE_BACKTRACE
    serverLog(LL_WARNING,"(forcing SIGSEGV in order to print the stack trace)");
#endif
    serverLog(LL_WARNING,"------------------------------------------------");
    *((char*)-1) = 'x';
}

#define serverPanic(...) _serverPanic(__FILE__,__LINE__,__VA_ARGS__),_exit(1)

void redisOutOfMemoryHandler(size_t allocation_size) {
    serverLog(LL_WARNING,"Out Of Memory allocating %zu bytes!",
        allocation_size);
    serverPanic("Redis aborting for OUT OF MEMORY");
}

void redisSetProcTitle(char *title) {
#ifdef USE_SETPROCTITLE
    char *server_mode = "";
    if (server.cluster_enabled) server_mode = " [cluster]";
    else if (server.sentinel_mode) server_mode = " [sentinel]";

    setproctitle("%s %s:%d%s",
        title,
        server.bindaddr_count ? server.bindaddr[0] : "*",
        server.port ? server.port : server.tls_port,
        server_mode);
#else
    UNUSED(title);
#endif
}

int main(int argc, char **argv) {
    struct timeval tv;
    int j;

#ifdef REDIS_TEST
    if (argc == 3 && !strcasecmp(argv[1], "test")) {
        if (!strcasecmp(argv[2], "ziplist")) {
            return ziplistTest(argc, argv);
        } else if (!strcasecmp(argv[2], "quicklist")) {
            quicklistTest(argc, argv);
        } else if (!strcasecmp(argv[2], "intset")) {
            return intsetTest(argc, argv);
        } else if (!strcasecmp(argv[2], "zipmap")) {
            return zipmapTest(argc, argv);
        } else if (!strcasecmp(argv[2], "sha1test")) {
            return sha1Test(argc, argv);
        } else if (!strcasecmp(argv[2], "util")) {
            return utilTest(argc, argv);
        } else if (!strcasecmp(argv[2], "endianconv")) {
            return endianconvTest(argc, argv);
        } else if (!strcasecmp(argv[2], "crc64")) {
            return crc64Test(argc, argv);
        } else if (!strcasecmp(argv[2], "zmalloc")) {
            return zmalloc_test(argc, argv);
        }

        return -1; /* test not found */
    }
#endif

    /* We need to initialize our libraries, and the server configuration. */
#ifdef INIT_SETPROCTITLE_REPLACEMENT
    spt_init(argc, argv);
#endif
    setlocale(LC_COLLATE,"");
    tzset(); /* Populates 'timezone' global. */
    zmalloc_set_oom_handler(redisOutOfMemoryHandler);
    srand(time(NULL)^getpid());
    gettimeofday(&tv,NULL);
...
..
.

You can see the way through these predictions. You should also know about the adlist code. Finally, we enter the practice and compilation phase,

Get through the last kilometer of the corner

6. redis Makefile analysis

With comments, it is convenient for you to read mkreleasehdr.sh and Makefile one by one

 1 #!/bin/sh
 2 
 3 # git log first eight bit hash value
 4 GIT_SHA1=`(git show-ref --head --hash=8 2>/dev/null || echo 00000000) | head -n1`
 5 
 6 # Display submission, Changes between submissions and work trees, etc, Disable external differences driver. System default git diff
 7 GIT_DIRTY=`git diff --no-ext-diff 2>/dev/null | wc -l`
 8 
 9 # {Host name on the network node}-{time stamp}
10 BUILD_ID=`uname -n`"-"`date +%s`
11 # -n judge "$SOURCE_DATE_EPOCH" Is it not an empty string, It's not true.
12 if [ -n "$SOURCE_DATE_EPOCH" ] then
13     # SOURCE_DATE_EPOCH=1574154953 -> date -u -d "@1574154953" +%s -> 1574154953 Or the incoming timestamp
14     # SOURCE_DATE_EPOCH=src -> date -u -r "src" +%s -> 1574153469 Displays the last modified time of the specified file
15     # date -u +%s -> 1574155246 -> Output or set common time for coordination
16     BUILD_ID=$(date -u -d "@$SOURCE_DATE_EPOCH" +%s 2>/dev/null || date -u -r "$SOURCE_DATE_EPOCH" +%s 2>/dev/null || date -u +%s)
17 fi
18 
19 # Test whether the release.h file exists, and create it if not
20 test -f release.h || touch release.h
21 # Judge whether release.h has created OK. If ok, exit
22 (cat release.h | grep SHA1 | grep $GIT_SHA1) && \
23 (cat release.h | grep DIRTY | grep $GIT_DIRTY) && exit 0 # Already up-to-date
24 
25 # release.h write macro configuration redis? Git? SHA1 redis? Git? Dirty redis? Build? ID
26 echo "#define REDIS_GIT_SHA1 \"$GIT_SHA1\"" > release.h
27 echo "#define REDIS_GIT_DIRTY \"$GIT_DIRTY\"" >> release.h
28 echo "#define REDIS_BUILD_ID \"$BUILD_ID\"" >> release.h
29 
30 # touch Update file access time atime File content change time mtime Document status change time ctime
31 touch release.c # Force recompile release.c
  1 # Redis Makefile
  2 # Copyright (C) 2009 Salvatore Sanfilippo <antirez at gmail dot com>
  3 # This file is released under the BSD license, see the COPYING file
  4 #
  5 # The Makefile composes the final FINAL_CFLAGS and FINAL_LDFLAGS using
  6 # what is needed for Redis plus the standard CFLAGS and LDFLAGS passed.
  7 # However when building the dependencies (Jemalloc, Lua, Hiredis, ...)
  8 # CFLAGS and LDFLAGS are propagated to the dependencies, so to pass
  9 # flags only to be used when compiling / linking Redis itself REDIS_CFLAGS
 10 # and REDIS_LDFLAGS are used instead (this is the case of 'make gcov').
 11 #
 12 # Dependencies are stored in the Makefile.dep file. To rebuild this file
 13 # Just use 'make dep', but this is only needed by developers.
 14 
 15 # Makefile run sh ./mkreleasehdr.sh
 16 release_hdr := $(shell sh -c './mkreleasehdr.sh')
 17 # Define direct presentation variables uname_S := Kernel name, for example uname -s -> Linux 
 18 uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
 19 # Define direct presentation variables uname_M := Hardware schema name of the host, for example uname -s -> x86_64
 20 uname_M := $(shell sh -c 'uname -m 2>/dev/null || echo not')
 21 # Defining conditional assignment variables, When OPTIMIZATION Non-existent, There will be OPTIMIZATION :=-O2, Otherwise, it will not change OPTIMIZATION
 22 OPTIMIZATION?=-O2
 23 # Defining recursive expansion variables DEPENDENCY_TARGETS =hiredis linenoise lua
 24 # Makefile Unfolding time = If there is a space after, Will retain.
 25 DEPENDENCY_TARGETS=hiredis linenoise lua
 26 # Define direct presentation variables NODEPS :=clean distclean
 27 NODEPS:=clean distclean
 28 
 29 # Default settings
 30 # -std=c11  Use C11 standard
 31 # -pedantic with ANSI/ISO C All warnings listed in the standard
 32 # -DREDIS_STATIC='' Conduct REDIS_STATIC='' Macro definition
 33 STD=-std=c11 -pedantic -DREDIS_STATIC=''
 34 # ifneq ($1, $2) $1 != $2 To be true 
 35 # $(finding clang, $(CC)) looks up the clang string in $(CC), finds and returns clang, otherwise returns an empty string
 36 # $(findstring FreeBSD,$(uname_S)), find the FreeBSD string in $(uname_S)
 37 # -Wno-c11-extensions delete C11 Extended warning
 38 ifneq (,$(findstring clang,$(CC)))
 39 ifneq (,$(findstring FreeBSD,$(uname_S)))
 40   STD+=-Wno-c11-extensions
 41 endif
 42 endif
 43 # -Wall Show all warnings after compilation
 44 # -W Similar-Wall A warning is displayed, But only the warnings that the compiler thinks there will be errors
 45 # -Wno-missing-field-initializers Disable structure initialization not all field warnings specified
 46 WARN=-Wall -W -Wno-missing-field-initializers
 47 # Defining recursive expansion variables OPT =$(OPTIMIZATION) ?=-O2
 48 OPT=$(OPTIMIZATION)
 49 
 50 # # Defining conditional assignment variables, When PREFIX Non-existent, There will be PREFIX :=/usr/local, Otherwise maintenance PREFIX Variable invariance
 51 PREFIX?=/usr/local
 52 INSTALL_BIN=$(PREFIX)/bin
 53 INSTALL=install
 54 
 55 # Default allocator defaults to Jemalloc if it's not an ARM
 56 MALLOC=libc
 57 # ifneq ($(uname_M),armv6l) $(uname_M) the hardware architecture is not armv6l
 58 # ifneq ($(uname_M),armv7l) $(uname_M) the hardware architecture is not armv7l
 59 # ifeq ($(uname_S),Linux) $(uname_S) the kernel name is Linux
 60 ifneq ($(uname_M),armv6l)
 61 ifneq ($(uname_M),armv7l)
 62 ifeq ($(uname_S),Linux)
 63     MALLOC=jemalloc
 64 endif
 65 endif
 66 endif
 67 
 68 # To get ARM stack traces if Redis crashes we need a special C flag.
 69 # $(filter aarch64 armv,$(uname_M)) $(uname_M) in the hardware architecture, if it is aarch64 or armv, it is reserved
 70 # -funwind-tables Easy to open backtrace
 71 #    unwind table Table records function related information, Starting address of the function, End address of the function, One info block Pointer
 72 ifneq (,$(filter aarch64 armv,$(uname_M)))
 73         CFLAGS+=-funwind-tables
 74 else
 75 ifneq (,$(findstring armv,$(uname_M)))
 76         CFLAGS+=-funwind-tables
 77 endif
 78 endif
 79 
 80 # Backwards compatibility for selecting an allocator
 81 ifeq ($(USE_TCMALLOC),yes)
 82     MALLOC=tcmalloc
 83 endif
 84 
 85 ifeq ($(USE_TCMALLOC_MINIMAL),yes)
 86     MALLOC=tcmalloc_minimal
 87 endif
 88 
 89 # ifeq ($(USE_JEMALLOC),yes) $(USE_JEMALLOC) == yes Will let MALLOC=jemalloc
 90 ifeq ($(USE_JEMALLOC),yes)
 91     MALLOC=jemalloc
 92 endif
 93 
 94 ifeq ($(USE_JEMALLOC),no)
 95     MALLOC=libc
 96 endif
 97 
 98 # Override default settings if possible
 99 # - Ignore mistakes
100 # include .make-settings Import .make-settings Makefile file
101 -include .make-settings
102 
103 # Take Linux jemalloc as an example
104 # FINAL_CFLAGS=-std=c11 -pedantic -DREDIS_STATIC='' -Wall -W -Wno-missing-field-initializers -O2 -g -ggdb 
105 # FINAL_LDFLAGS= -g -ggdb
106 # -g Native format of operating system(native format)Generate debugging information, Other debuggers can also be used
107 # -ggdb send GCC by GDB Generate more specialized debugging information
108 # -lm link math.h Correlation Library
109 FINAL_CFLAGS=$(STD) $(WARN) $(OPT) $(DEBUG) $(CFLAGS) $(REDIS_CFLAGS)
110 FINAL_LDFLAGS=$(LDFLAGS) $(REDIS_LDFLAGS) $(DEBUG)
111 FINAL_LIBS=-lm
112 DEBUG=-g -ggdb
113 
114 ifeq ($(uname_S),SunOS)
115     # SunOS
116         ifneq ($(@@),32bit)
117         CFLAGS+= -m64
118         LDFLAGS+= -m64
119     endif
120     DEBUG=-g
121     DEBUG_FLAGS=-g
122     export CFLAGS LDFLAGS DEBUG DEBUG_FLAGS
123     INSTALL=cp -pf
124     FINAL_CFLAGS+= -D__EXTENSIONS__ -D_XPG6
125     FINAL_LIBS+= -ldl -lnsl -lsocket -lresolv -lpthread -lrt
126 else
127 ifeq ($(uname_S),Darwin)
128     # Darwin
129     FINAL_LIBS+= -ldl
130     OPENSSL_CFLAGS=-I/usr/local/opt/openssl/include
131     OPENSSL_LDFLAGS=-L/usr/local/opt/openssl/lib
132 else
133 ifeq ($(uname_S),AIX)
134         # AIX
135         FINAL_LDFLAGS+= -Wl,-bexpall
136         FINAL_LIBS+=-ldl -pthread -lcrypt -lbsd
137 else
138 ifeq ($(uname_S),OpenBSD)
139     # OpenBSD
140     FINAL_LIBS+= -lpthread
141     ifeq ($(USE_BACKTRACE),yes)
142         FINAL_CFLAGS+= -DUSE_BACKTRACE -I/usr/local/include
143         FINAL_LDFLAGS+= -L/usr/local/lib
144         FINAL_LIBS+= -lexecinfo
145         endif
146 
147 else
148 ifeq ($(uname_S),FreeBSD)
149     # FreeBSD
150     FINAL_LIBS+= -lpthread -lexecinfo
151 else
152 ifeq ($(uname_S),DragonFly)
153     # FreeBSD
154     FINAL_LIBS+= -lpthread -lexecinfo
155 else
156     # All the other OSes (notably Linux)
157     FINAL_LDFLAGS+= -rdynamic
158     FINAL_LIBS+=-ldl -pthread -lrt
159 endif
160 endif
161 endif
162 endif
163 endif
164 endif
165 # Include paths to dependencies
166 FINAL_CFLAGS+= -I../deps/hiredis -I../deps/linenoise -I../deps/lua/src
167 
168 ifeq ($(MALLOC),tcmalloc)
169     FINAL_CFLAGS+= -DUSE_TCMALLOC
170     FINAL_LIBS+= -ltcmalloc
171 endif
172 
173 ifeq ($(MALLOC),tcmalloc_minimal)
174     FINAL_CFLAGS+= -DUSE_TCMALLOC
175     FINAL_LIBS+= -ltcmalloc_minimal
176 endif
177 
178 # ifeq ($(MALLOC),jemalloc) $(MALLOC) == jemalloc Enter the conditional branch for Zhencai
179 # DEPENDENCY_TARGETS += jemalloc -> DEPENDENCY_TARGETS = hiredis linenoise lua jemalloc
180 # FINAL_CFLAGS Continue += -DUSE_JEMALLOC -I../deps/jemalloc/include Introduce USE_JEMALLOC Macro and specify header file path
181 # FINAL_LIBS := ../deps/jemalloc/lib/libjemalloc.a -lm
182 ifeq ($(MALLOC),jemalloc)
183     DEPENDENCY_TARGETS+= jemalloc
184     FINAL_CFLAGS+= -DUSE_JEMALLOC -I../deps/jemalloc/include
185     FINAL_LIBS := ../deps/jemalloc/lib/libjemalloc.a $(FINAL_LIBS)
186 endif
187 
188 # BUILD_TLS -> USE_OPENSSL
189 ifeq ($(BUILD_TLS),yes)
190     FINAL_CFLAGS+=-DUSE_OPENSSL $(OPENSSL_CFLAGS)
191     FINAL_LDFLAGS+=$(OPENSSL_LDFLAGS)
192     FINAL_LIBS += ../deps/hiredis/libhiredis_ssl.a -lssl -lcrypto
193 endif
194 
195 REDIS_CC=$(QUIET_CC)$(CC) $(FINAL_CFLAGS)
196 REDIS_LD=$(QUIET_LINK)$(CC) $(FINAL_LDFLAGS)
197 REDIS_INSTALL=$(QUIET_INSTALL)$(INSTALL)
198 
199 # CCCOLOR="\033[34m"        Blue word
200 # LINKCOLOR="\033[34;1m"    Blue highlight
201 # SRCCOLOR="\033[33m"        Yellow character
202 # BINCOLOR="\033[37;1m"        White highlighted
203 # MAKECOLOR="\033[32;1m"    Green word highlights
204 # ENDCOLOR="\033[0m"        Close all properties
205 CCCOLOR="\033[34m"
206 LINKCOLOR="\033[34;1m"
207 SRCCOLOR="\033[33m"
208 BINCOLOR="\033[37;1m"
209 MAKECOLOR="\033[32;1m"
210 ENDCOLOR="\033[0m"
211 
212 # ifndef doesn't exist, so it's true
213 # @The executed command is no longer echoed on the printf Makefile screen
214 # %b The corresponding parameter is treated as a string containing the escape sequence to be processed
215 # 1>&2 Standard output redirected to standard error
216 # $@ indicates the target in the rule
217 # Query? CC compilation, query? Link, query? Install
218 ifndef V
219 QUIET_CC = @printf '    %b %b\n' $(CCCOLOR)CC$(ENDCOLOR) $(SRCCOLOR)$@$(ENDCOLOR) 1>&2;
220 QUIET_LINK = @printf '    %b %b\n' $(LINKCOLOR)LINK$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR) 1>&2;
221 QUIET_INSTALL = @printf '    %b %b\n' $(LINKCOLOR)INSTALL$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR) 1>&2;
222 endif
223 
224 REDIS_SERVER_NAME=redis-server
225 REDIS_SENTINEL_NAME=redis-sentinel
226 REDIS_SERVER_OBJ=adlist.o quicklist.o ae.o anet.o dict.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o redis-check-aof.o geo.o lazyfree.o module.o evict.o expire.o geohash.o geohash_helper.o childinfo.o defrag.o siphash.o rax.o t_stream.o listpack.o localtime.o lolwut.o lolwut5.o lolwut6.o acl.o gopher.o tracking.o connection.o tls.o sha256.o
227 REDIS_CLI_NAME=redis-cli
228 REDIS_CLI_OBJ=anet.o adlist.o dict.o redis-cli.o zmalloc.o release.o anet.o ae.o crc64.o siphash.o crc16.o
229 REDIS_BENCHMARK_NAME=redis-benchmark
230 REDIS_BENCHMARK_OBJ=ae.o anet.o redis-benchmark.o adlist.o dict.o zmalloc.o siphash.o redis-benchmark.o
231 REDIS_CHECK_RDB_NAME=redis-check-rdb
232 REDIS_CHECK_AOF_NAME=redis-check-aof
233 
234 all: $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_RDB_NAME) $(REDIS_CHECK_AOF_NAME)
235     @echo ""
236     @echo "Hint: It's a good idea to run 'make test' ;)"
237     @echo ""
238 
239 # Build Makefile.dep file
240 # -M  Not as a result of the output precompiling process, Instead, output a make Rules, This rule describes the dependencies of this source file.
241 #     This output of precompiler make Rule contains the target file with the same name as the original file, Colons and all include File name
242 # -MM And -M Be similar, It just doesn't contain the system header file
243 Makefile.dep:
244     -$(REDIS_CC) -MM *.c > Makefile.dep 2> /dev/null || true
245 
246 # $(words <text>) Word count function
247 # Makecmdloads will store a list of the ultimate targets you specify. If you do not specify a target on the command line, then this variable is null
248 # NODEPS:=clean distclean
249 ifeq (0, $(words $(findstring $(MAKECMDGOALS), $(NODEPS))))
250 -include Makefile.dep
251 endif
252 
253 .PHONY: all
254 
255 # structure .make-settings
256 persist-settings: distclean
257     echo STD=$(STD) >> .make-settings
258     echo WARN=$(WARN) >> .make-settings
259     echo OPT=$(OPT) >> .make-settings
260     echo MALLOC=$(MALLOC) >> .make-settings
261     echo CFLAGS=$(CFLAGS) >> .make-settings
262     echo LDFLAGS=$(LDFLAGS) >> .make-settings
263     echo REDIS_CFLAGS=$(REDIS_CFLAGS) >> .make-settings
264     echo REDIS_LDFLAGS=$(REDIS_LDFLAGS) >> .make-settings
265     echo PREV_FINAL_CFLAGS=$(FINAL_CFLAGS) >> .make-settings
266     echo PREV_FINAL_LDFLAGS=$(FINAL_LDFLAGS) >> .make-settings
267     -(cd ../deps && $(MAKE) $(DEPENDENCY_TARGETS))
268 
269 .PHONY: persist-settings
270 
271 # Prerequisites target
272 .make-prerequisites:
273     @touch $@
274 
275 # Clean everything, persist settings and build dependencies if anything changed
276 ifneq ($(strip $(PREV_FINAL_CFLAGS)), $(strip $(FINAL_CFLAGS)))
277 .make-prerequisites: persist-settings
278 endif
279 
280 # $(strip strip strip) space removal function
281 ifneq ($(strip $(PREV_FINAL_LDFLAGS)), $(strip $(FINAL_LDFLAGS)))
282 .make-prerequisites: persist-settings
283 endif
284 
285 # redis-server
286 $(REDIS_SERVER_NAME): $(REDIS_SERVER_OBJ)
287     $(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/lua/src/liblua.a $(FINAL_LIBS)
288 
289 # redis-sentinel
290 $(REDIS_SENTINEL_NAME): $(REDIS_SERVER_NAME)
291     $(REDIS_INSTALL) $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME)
292 
293 # redis-check-rdb
294 $(REDIS_CHECK_RDB_NAME): $(REDIS_SERVER_NAME)
295     $(REDIS_INSTALL) $(REDIS_SERVER_NAME) $(REDIS_CHECK_RDB_NAME)
296 
297 # redis-check-aof
298 $(REDIS_CHECK_AOF_NAME): $(REDIS_SERVER_NAME)
299     $(REDIS_INSTALL) $(REDIS_SERVER_NAME) $(REDIS_CHECK_AOF_NAME)
300 
301 # redis-cli
302 $(REDIS_CLI_NAME): $(REDIS_CLI_OBJ)
303     $(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/linenoise/linenoise.o $(FINAL_LIBS)
304 
305 # redis-benchmark
306 $(REDIS_BENCHMARK_NAME): $(REDIS_BENCHMARK_OBJ)
307     $(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a $(FINAL_LIBS)
308 
309 dict-benchmark: dict.c zmalloc.c sds.c siphash.c
310     $(REDIS_CC) $(FINAL_CFLAGS) $^ -D DICT_BENCHMARK_MAIN -o $@ $(FINAL_LIBS)
311 
312 # Because the jemalloc.h header is generated as a part of the jemalloc build,
313 # building it should complete before building any other object. Instead of
314 # depending on a single artifact, build all dependencies first.
315 %.o: %.c .make-prerequisites
316     $(REDIS_CC) -c $<
317 
318 clean:
319     rm -rf $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_RDB_NAME) $(REDIS_CHECK_AOF_NAME) *.o *.gcda *.gcno *.gcov redis.info lcov-html Makefile.dep dict-benchmark
320 
321 .PHONY: clean
322 
323 distclean: clean
324     -(cd ../deps && $(MAKE) distclean)
325     -(rm -f .make-*)
326 
327 .PHONY: distclean
328 
329 test: $(REDIS_SERVER_NAME) $(REDIS_CHECK_AOF_NAME)
330     @(cd ..; ./runtest)
331 
332 test-sentinel: $(REDIS_SENTINEL_NAME)
333     @(cd ..; ./runtest-sentinel)
334 
335 check: test
336 
337 lcov:
338     $(MAKE) gcov
339     @(set -e; cd ..; ./runtest --clients 1)
340     @geninfo -o redis.info .
341     @genhtml --legend -o lcov-html redis.info
342 
343 test-sds: sds.c sds.h
344     $(REDIS_CC) sds.c zmalloc.c -DSDS_TEST_MAIN $(FINAL_LIBS) -o /tmp/sds_test
345     /tmp/sds_test
346 
347 .PHONY: lcov
348 
349 bench: $(REDIS_BENCHMARK_NAME)
350     ./$(REDIS_BENCHMARK_NAME)
351 
352 32bit:
353     @echo ""
354     @echo "WARNING: if it fails under Linux you probably need to install libc6-dev-i386"
355     @echo ""
356     $(MAKE) CFLAGS="-m32" LDFLAGS="-m32"
357 
358 gcov:
359     $(MAKE) REDIS_CFLAGS="-fprofile-arcs -ftest-coverage -DCOVERAGE_TEST" REDIS_LDFLAGS="-fprofile-arcs -ftest-coverage"
360 
361 noopt:
362     $(MAKE) OPTIMIZATION="-O0"
363 
364 valgrind:
365     $(MAKE) OPTIMIZATION="-O0" MALLOC="libc"
366 
367 helgrind:
368     $(MAKE) OPTIMIZATION="-O0" MALLOC="libc" CFLAGS="-D__ATOMIC_VAR_FORCE_SYNC_MACROS"
369 
370 # generate src/help.h Header file
371 # @../utils/generate-command-help.rb > help.h adopt ruby Script request 
372 # https://raw.githubusercontent.com/antirez/redis-doc/master/commands.json Construction related C Variable information of medium global area
373 src/help.h:
374     @../utils/generate-command-help.rb > help.h
375 
376 install: all
377     @mkdir -p $(INSTALL_BIN)
378     $(REDIS_INSTALL) $(REDIS_SERVER_NAME) $(INSTALL_BIN)
379     $(REDIS_INSTALL) $(REDIS_BENCHMARK_NAME) $(INSTALL_BIN)
380     $(REDIS_INSTALL) $(REDIS_CLI_NAME) $(INSTALL_BIN)
381     $(REDIS_INSTALL) $(REDIS_CHECK_RDB_NAME) $(INSTALL_BIN)
382     $(REDIS_INSTALL) $(REDIS_CHECK_AOF_NAME) $(INSTALL_BIN)
383     @ln -sf $(REDIS_SERVER_NAME) $(INSTALL_BIN)/$(REDIS_SENTINEL_NAME)
384 
385 uninstall:
386     rm -f $(INSTALL_BIN)/{$(REDIS_SERVER_NAME),$(REDIS_BENCHMARK_NAME),$(REDIS_CLI_NAME),$(REDIS_CHECK_RDB_NAME),$(REDIS_CHECK_AOF_NAME),$(REDIS_SENTINEL_NAME)}

Thank you! The simplest data structure of redis, adlist, is here. Goodbye

Postscript - if

Mistakes are inevitable. You are welcome to correct, exchange and improve together~

IF: Rudyard Kipling
  
  If you can keep your head when all about you
  Are losing theirs and blaming it on you;
  If you can trust yourself when all men doubt you,
  But make allowance for their doubting too;
  If you can wait and not be tired by waiting,
  Or, being lied about, don't deal in lies,
  Or, being hated, don't give way to hating,
  And yet don't look too good, nor talk too wise;
If all people lose their heads and curse you,
You can still keep your head clear;
If everyone doubts you,
You can still believe in yourself and let all doubts waver.
If you have to wait, don't get bored,
Be deceived, do not deceive,
Do not hold grudges because they are hated,
Don't be too optimistic, don't be opinionated;
  
  If you can dream - and not make dreams your master;
  If you can think - and not make thoughts your aim;
  If you can meet with triumph and disaster
  And treat those two imposters just the same;
  If you can bear to hear the truth you've spoken
  Twisted by knaves to make a trap for fools,
  Or watch the things you gave your life to broken,
  And stoop and build 'em up with worn-out tools;
If you are a dreamer - don't be dominated by dreams;
If you are a thinker - don't be a thinker;
If you encounter pride and frustration
Treat both as liars;
If you can stand it, you've told the truth
Distorted by villains, used to deceive fools;
Or, watch what you've spent your life caring for be destroyed,
Lean down and mend it with old tools;
  
  If you can make one heap of all your winnings
  And risk it on one turn of pitch-and-toss,
  And lose, and start again at your beginnings
  And never breath a word about your loss;
  If you can force your heart and nerve and sinew
  To serve your turn long after they are gone,
  And so hold on when there is nothing in you
  Except the Will which says to them: "Hold on";
If after you win countless laurels,
And then put all your money in one more fight,
After the failure, we rise again,
Don't complain about your failure;
If you can force yourself,
After others have left, we should stick to our position for a long time,
There is nothing in your heart,
Only will tell you "hold on!" ;
  
  If you can talk with crowds and keep your virtue,
  Or walk with kings - nor lose the common touch;
  If neither foes nor loving friends can hurt you;
  If all men count with you, but none too much;
  If you can fill the unforgiving minute
  With sixty seconds' worth of distance run -
  Yours is the Earth and everything that's in it,
If you talk to people, you can keep your style,
Keep a distance with Wang;
If enemies and friends do not harm you;
If everyone is counting on you, but no one is wholehearted;
If you take 60 seconds to sprint,
Fill that unforgivable minute——
You can have a world,
Everything in this world is yours,
More importantly, child, you are a man of the sky.

Posted by Sanjib Sinha on Fri, 22 Nov 2019 05:49:26 -0800