We all know that Redis pursues simplicity, speed, and efficiency, and in this case it rejects the window platform, and when we learn SQL Server, we know that business is a more complicated thing.
So if the hair is copied into Redis, it's not so simple and pure, but it's a scenario where we write programs that can't be avoided, so the Redis author has a compromise to write a simple
Version of the transaction mechanism, let me pull the egg.
One: Practical affairs
Specific to the business is what, to guarantee what ... I don't think I need to say that. 3,721, take a look at the Redis Handbook and discover its magic.
1. multi,exec
Do you remember how SQL Server is playing? This is typically three steps, generating a transaction, generating a command, executing a transaction, right, and corresponding to Redis?? Multi is the build transaction, and then
Enter the Redis command, and finally execute the command with exec, just like this:
As you can see, after I set the command, the feedback information is queued, and finally I execute EXEC, these commands will be really executed, it is so simple, all the execution is so smooth,
No, no, no, no, no, no, maybe some people say, in fact, there is a rollback operation in the business, but it seems that in the Redis did not see, haha, ah, very sorry is
There are no rollback operations in Redis, such as the following.
In the diagram I deliberately use the Lpush command to execute a string, it is conceivable that nature will not succeed, but from the results, you see what? Two ok, one error, this is a violation of the transaction
Atom, right, but how can I refute it??? I would say, wrong your sister Ah ... Even a basic command has been written wrong, you have a hair ah ... Also write a hair code, Reids just
is a data structure server, a lot of simple thing, 10,000 steps back, it is obvious that the error command it will return directly, for example, I deliberately write Lpush lpush1:
2. Watch
I don't know if you read the three set commands behind multi, there is no feeling of guilty, how to say, just as long as the order is correct, Redis guarantee will be executed, to the end
Task, although the command is executed together, but who can guarantee that I am in the process of executing the command, the other client will not modify these values??? If these values are modified, then my exec
What's the point??? It doesn't matter, the demand of this kind of bad street, how can redis stand idly by??? Watch here will help you.
Watchwatch key [Key ...] Monitor one (or more) key, and if this (or these) key is changed by another command before the transaction executes, the transaction will be interrupted.
The above is the Redis Manual on the Explanation of watch, it seems very simple to use, is that I before multi, with watch to monitor the key I want to change, if I say before the exec,
This time after multi, key is modified by other clients, then exec will fail, return (nil), so simple, I would like to give an example:
Second: the principle of exploration
The source code of the transaction operation, mostly in the Redis source Multi.c file, Next I will be a simple analysis:
1. Multi
In the Redis source code, it's probably written like this:
1 voidMulticommand (Redisclient *c) {2 if(C->flags &Redis_multi) {3Addreplyerror (c,"MULTI calls can not be nested");4 return;5 }6C->flags |=Redis_multi;7 addreply (C,shared.ok);8}
From this code, you can see that multi simply opens the Redisclient redis_multi state and tells the Redis client that it has entered transaction mode, right.
2. Generate commands
In Redisclient, there is a multistate command:
struct redisclient { ... multistate mstate; /* */ ... } redisclient;
From the note you probably see that this command has something to do with multi/exec, and then I'm curious to see the definition of multistate:
typedef struct multistate {Multicmd *commands; /* Array of MULTI commands */ int count; /* Total number of MULTI commands */ int Minreplicas; /* Minreplicas for synchronous replication */ time_t Minreplicas_timeout; /* Minreplicas timeout as unixtime. */
From this enumeration of multistate, you can see that there is a *command command below, which you can see from the comments that it actually points to an array, which I think you have closed your eyes
Can you imagine ... It's just a few of your orders ... There is also a count below that can be seen as the total number of actual commands.
3. Watch
To make it easy to talk about the back of exec, here's a look at how watch might be implemented, as it is written in the MULTI.C source code.
1typedefstructWatchedkey {2RobJ *key;3REDISDB *db;4 } Watchedkey;5 6 voidWatchcommand (Redisclient *c) {7 intJ;8 9 if(C->flags &Redis_multi) {TenAddreplyerror (c,"WATCH inside MULTI is not allowed"); One return; A } - for(j =1; J < c->argc; J + +) -Watchforkey (c,c->argv[j]); the addreply (C,shared.ok); - } - - /*Watch for the specified key*/ + voidWatchforkey (redisclient *c, RobJ *key) { -List *clients =NULL; + Listiter Li; AListNode *Ln; atWatchedkey *wk; - - /*Check If we is already watching for this key*/ -Listrewind (c->watched_keys,&Li); - while(ln = listnext (&Li )) { -WK =listnodevalue (LN); in if(wk->db = = c->db && equalstringobjects (key,wk->key)) - return;/*Key already watched*/ to } + /*This key isn't already watched in the this DB. Let ' s add it*/ -Clients = Dictfetchvalue (c->db->watched_keys,key); the if(!clients) { *Clients =listcreate (); $Dictadd (c->db->watched_keys,key,clients);Panax Notoginseng Incrrefcount (key); - } the Listaddnodetail (clients,c); + /*ADD The new key to the list of keys watched by this client*/ Awk = Zmalloc (sizeof(*wk)); theWk->key =key; +Wk->db = c->db; - Incrrefcount (key); $Listaddnodetail (c->watched_keys,wk); $}
One of the most important pieces of this code is:
/** * = Dictfetchvalue (C->db->watched_keys,key);
is by Dicfetchvalue This dictionary method, from the Watched_keys to find the value of the specified key, and this value is a clients linked list, that people actually want to find
All the clients about this key, right, will finally plug this key into Redisclient's Watched_keys dictionary, the following code:
/** * = zmalloc (sizeof(* wk)); WK->key = key; WK->db = c->db; Incrrefcount (key); Listaddnodetail (c->watched_keys,wk);
If you want to paint, that's probably it:
Where Watched_key is a dictionary structure, the key of the dictionary is the above key1,key2 ... , value is the list of the client, so I know very well that a key
Which client is watching, right?
4.exec
There are probably two things in this command:
<1>: Determine if c->flags=redis_dirty_exec is open or not, and if so, cancel transaction discardtransaction (c), which means the key is already
modified by the client.
<2>: If there is no modification, then the For Loop executes the command in comannd[], such as two information in:
Okay, that's probably it, I hope it helps you, huh ~ ~ ~
15 Days redis--Eighth chapter you have to do business play