1.redis Introduction
Redis is an open source API that is written in ANSI C, supports the web, can be persisted in memory, key-value databases, and provides multiple languages.
2. Blocking queues
One big problem with non-blocking queues is that it does not block the current thread, so it is cumbersome to implement additional synchronization policies and inter-thread wake-up policies in the face of similar consumer-producer models. But with the blocking queue it's different, it blocks the current thread, such as a thread fetching an element from an empty blocking queue, and the thread is blocked until the blocking queue has elements. When there are elements in the queue, the blocked thread is automatically awakened (no need for us to write code to wake up). This provides a great deal of convenience.
Blocking queue for 3.redis
REDIS provides remote access mode, in this paper, Redis remote blocking from the queue to take data as an example, the principle of redis blocking implementation.
/*-----------------------------------------------------------------------------* Blocking POP operations *-------- --------------------------------------------------------------------*//* The current blocking POP works, we Use Blpop as Example: *-If the user calls Blpop and the key exists and contains a non empty list * then Lpop is called instead. So Blpop is semantically the same as Lpop * if blocking are not required. *-If instead Blpop is called and the key does not exists or the list is * empty we need to block. In order to do, we remove the notification for * new data to read in the client socket (so, we ' ll not serve new * Requests if the blocking request is not served). Also we put the client * in a dictionary (db->blocking_keys) mapping keys to a list of clients * blocking for this Keys. *-If a PUSH operation against a key with blocked clients waiting are * performed, we mark this key as "ready", and Afte R the current command, * multi/EXEC block, or script, is executed, we serve all the clients waiting * for this list, from the one, blocked first, t o the last, accordingly * to the number of elements we had in the ready list. */
When a blocking queue fetch operation is called, the blocking branch of the code is really triggered when there is no data in the queue. On the client side, Redis removes the token (notification) from the new read request, so that the new read request is not able to be serviced properly until the blocked request is received by the service.
Blpop
void Blpopcommand (Redisclient *c) { blockingpopgenericcommand (c,redis_head);}
The table header and footer of the queue's left and right queue (list).
Blockingpopgenericcommand
/* Blocking rpop/lpop */void blockingpopgenericcommand (redisclient *c, int where) {robj *o; mstime_t timeout; Int J; if (gettimeoutfromobjectorreply (c,c->argv[c->argc-1],&timeout,unit_seconds)! = REDIS_OK) return; for (j = 1; J < c->argc-1; J + +) {o = Lookupkeywrite (c->db,c->argv[j]); if (o! = NULL) {if (O->type! = redis_list) {addreply (c,shared.wrongtypeerr); Return } else {if (Listtypelength (o)! = 0) {/* Non empty list, this was like a Non normal [LR] POP. */char *event = (where = = Redis_head)? "Lpop": "Rpop"; RobJ *value = Listtypepop (O,where); Redisassert (Value! = NULL); Addreplymultibulklen (c,2); Addreplybulk (C,c->argv[j]); Addreplybulk (C,value); Decrrefcount (value); NotifykeysPaceevent (Redis_notify_list,event, c->argv[j],c->db->id); if (Listtypelength (o) = = 0) {dbdelete (c->db,c->argv[j]); Notifykeyspaceevent (Redis_notify_generic, "Del", C->argv[j],c->db->id); } signalmodifiedkey (C->db,c->argv[j]); server.dirty++; /* Replicate it as an [lr]pop instead of B[lr]pop. */Rewriteclientcommandvector (c,2, (where = = Redis_head)? shared.lpop:shared. Rpop, C->argv[j]); Return }}}}//If We are inside a multi/exec and the list was empty the only thing * We can does is T Reating it as a timeout (even with timeout 0). */if (C->flags & Redis_multi) {addreply (C,shared.nullmultIbulk); Return }/* If the list is empty or the key does not exists we must block//////Here is the key to blocking Blockforkeys (c, c->argv + 1, c->argc-2, timeout, NULL);}
Blocking
/* Set a client in blocking mode for the specified key, with the specified * timeout */void blockforkeys (redisclient *c, R obj **keys, int numkeys, mstime_t timeout, robj *target) {dictentry *de; List *l; Int J; C->bpop.timeout = timeout; C->bpop.target = target; if (target! = NULL) Incrrefcount (target); for (j = 0; J < Numkeys; J + +) {/* If the key already exists in the dict ignore it. */if (dictadd Bpop.keys,keys[j],null)! = DICT_OK) Continue; Incrrefcount (Keys[j]); /* And in the other "side", to map keys, clients */de = Dictfind (c->db->blocking_keys,keys[j]); if (de = = NULL) {int retval; /* For every key we take a list of clients blocked for it */L = listcreate (); retval = Dictadd (c->db->blocking_keys,keys[j],l); Incrrefcount (Keys[j]); Redisassertwithinfo (C,keys[j],retval = = DICT_OK); } else {L = DICTGEtval (DE); } listaddnodetail (L,c); } blockclient (c,redis_blocked_list);}
Redis Blocking Queue Principle Learning