Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to understand the source code of Redis code base

2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article is to share with you about how to understand the source code of Redis code base, the editor thinks it is very practical, so I share it with you to learn. I hope you can get something after reading this article.

Redis is an open source data structure server written in ANSI C. "data structure server" is just another term for smart key-value storage services. You can store not only simple strings, but also hash (or map, or even dicts), list,set,sorted set. We have made extensive use of Redis in Top10, mostly to index based on the date of the user's search and the availability and price of the hotel. I find the Redis code very easy to read, even for beginners like me. The code is neatly written, and the amount of code is relatively small (about 45000 lines), most of it is single-threaded, and there is little dependency. All the dependencies are included with the source code, which makes compiling it very simple: clone its library, and then type make.

I decided to drill down into the code by adding a command to it. This simple thing lets me know how Redis handles a command and dispatches responses to it. The command rand receives an integer value as max and randomly returns an integer between 0 and max (excluding max). This is not the idea of using key-value storage, but implementing it will be instructive. And I certainly won't submit a pull request.

Disclaimer: as I said before, I am definitely not an expert in C, so all the code here and its interpretation are in accordance with this clause. Also, I linked an unstable branch of Redis, so it is unstable. If you get the Redis source code yourself, you will find more differences in this article when you view it with your favorite editor, especially if you compile and run it.

The command table is located at the top of the src/redis.c file. It is an array whose element type is redisCommand struct. RedisCommand is defined in src/redis.h. At the top of the redisCommandTable is a more detailed comment explaining each of its field. The following is the definition of the get command:

{"get", getCommand,2, "r", 0penol, null, 1pjr, 1pr, 0re0}

The first field is the name of the command "get". The second field is a function pointer to the specific implementation of the command (you can see the implementation details t_string.c).

The third field is the limit on the number of parameters of the command (the number of arguments received by the command). Specifying this means that the code that finds and executes the command can do a pre-validation before calling the function pointer. This practice reduces the error handling code necessary for each command function. The number of parameters counts the command name itself, so it only accepts two parameters: its own name, the name of key (we want to get its value).

The fourth field, set to "r", indicates that the command is read-only and cannot modify the value or status of the key. There are a lot of letter signs that you can use in this position. And in the nearby comment blocks, each letter sign is explained in detail. The field immediately following the field is always set to 0, which will be used to calculate later. It is just a bit mask containing information in the fourth field string.

The sixth field is NULL, because it is only needed if you want to use complex logic to tell Redis which parameter is the real key. A key points to a reference to a value stored in Redis, corresponding to a simple parameter, such as our max parameter. This mechanism allows Redis to extract the value of key (and verify that the key is stored) before invoking the implementation of the command. If the field is set to a value, it will be a function pointer to which the function returns an integer array of argument indexes (zunionInterGetKeys in db.c is an example). In the case of the get command (most of the other commands), the information of this array is the same as that of the next three field. The get command has only one argument, and that is key. Therefore, * parameters (key) in position 1, * a parameter (also key) in position 1, the increment from * parameters to * parameters is also 1. (translator's note: source code comments are: intkeystep;/* The step between first and last key * /).

The two field of redisCommand are the metrics of the command, set by Redis, and are always initialized to 0.

Add our command to the bottom of the command list:

{"rand", "randCommand,2,"rRl", 0penol Null, 0re0re0re0re0re0jue 0}

The name of the command is "rand", and randCommand points to the pointer to the implementation (not yet implemented), which takes two parameters (the command name and max). As for the flag, it is read-only (r), returns random, uncertain output (R), and it can be used (l) while Redis is still loading data. It has no key parameters.

The next step is to add the function prototype of randCommand to src/redis.h. The function of the Redis command takes an argument, a redisClient structure, as an argument to the command and also sends a response to the actual client.

Void randCommand (redisClient * c)

This prototype should be placed in src/redis.h along with all other command prototypes. Search for the following line:

/ * Commands prototypes * /

This will help you find the right place.

Let's add an empty implementation to src/redis.c:

Void randCommand (redisClient * c) {}

I added it next to the definition of infoCommand. Now, let's execute the make command.

Make

Then, start the Redis service we just compiled into common (if you already have a Redis service running locally, you should stop it):

> src/redis-server

Then we run the Redis client in another terminal and try to run our command:

> redis-cli

First, let's try our exception handling:

Redis 127.0.0.1 ERR wrong number of arguments for 6379 > rand (error) ERR wrong number of arguments for 'rand' command

Well, it's normal to check the number of parameters. This time we specify a parameter:

Redis 127.0.0.1 6379 > rand 1

Redis is stuck. This is exactly what I expected, because I didn't have any response in the randCommand function. Stop the service, and we'll go back to the code.

We wanted to return an integer, so I looked for an example in the code and found zcardCommand in src/t_zset.c. This command uses addReplyLongLong to return a 64-bit (long long) integer to the client. Let's give it a try:

Void randCommand (redisClient * c) {addReplyLongLong (cMagne3);}

Then, we do it once in make and test the command:

Redis 127.0.0.1 redis 6379 > rand 1 (integer) 3 redis 127.0.1 0.1 redis 6379 > rand 2 (integer) 3 redis 127.0.0.1 integer 6379 > rand 3 (integer) 3

Well, the results aren't too random, but this is just the beginning. We take the parameter max from the command and return a random number restricted by max:

Void randCommand (redisClient * c) {long max; if (getLongFromObjectOrReply (cMagnec-> argv [1], & max,NULL)! = REDIS_OK) return; addReplyLongLong (cmagic random ()% max);}

Although Redis uses primitive types and C-type strings throughout the code base, it also has its own internal object system that exists in a more general way to represent strings, long integers, and more complex types. An example of taking advantage of this type is the parameters of each command. The parameters of each command are stored as a Redis object in the field of redisClient instance c, in the array argv. (translation note: in the source src/redis.c, redisClient is a structure, and argv is a pointer to a redisObject pointer.) In src/t_string.c, there is an example of getting a long integer from a Redis object: getrangeCommand, which calls the getLongFromObjectOrReply function in src/object.c.

The getLongFromObjectOrReply function takes an instance of redisClient as an argument and checks whether its second argument is a long integer, if so, assigns a pointer to the second argument to the third parameter (which is a pointer type), and returns REDIS_OK. If the second argument is not a long integer (or overflow), the function returns REDIS_ERR. The beauty of this approach is that if the return value we get from our randCommand function is REDIS_ERR, all the necessary error responses have been sent to the client. Let's try our order again:

Redis 127.0.0.1 redis 127.0.0.1 redis 6379 > rand notanumber (error) ERR value is notan integer or out of range redis 127.0.0.1 redis 6379 > rand 10 (integer) 3 redis 127.0.1 rand > rand 10 (integer) 1 redis 127.0.1 > rand 100 (integer) 43 redis 127.0.1 > rand 100 (integer) 55 redis 127.0.1

It will work! Rand seems like a meaningless command, but you've learned a lot about Redis in the process of implementing it, and I hope you learn a lot from it as well. Please tell me in the comments whether there are obvious mistakes in this article. I am also glad to know that this article is very useful to you or you like it very much. I'm thinking of writing something similar about Redis or some other open source code base.

The above is how to understand the Redis code base source code, the editor believes that there are some knowledge points that we may see or use in our daily work. I hope you can learn more from this article. For more details, please follow the industry information channel.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report