Redis Database design and implementation tutorial

Source: Internet
Author: User
Tags lua redis time in milliseconds

redis Database definition:

typedef struct REDISDB {
Dict *dict; /* The keyspace for this DB */
Dict *expires; /* Timeout of keys with a Timeout set */
Dict *blocking_keys; /* Keys with clients waiting for data (blpop) * *
Dict *ready_keys; /* Blocked keys that received a PUSH * *
Dict *watched_keys; /* Watched keys for multi/exec CAS */
int id;
Long Long Avg_ttl; /* Average TTL, just for stats * *
} Redisdb;

Dict

The dict array holds all the databases, and when Redis initializes, 16 databases are created by default
#define REDIS_DEFAULT_DBNUM 16

By default, the target database for the Redis client is the No. 0 database, which can be toggled through the Select command. Note that because Redis lacks the database command to get the current operation, using select switching requires special attention

When reading and writing the key-value pairs in the database, Redis has some additional actions in addition to the specified operation on the key space:

After reading the key (read and write will read first), record the number of key space hits or misses
After the key is read, the LRU of the update key
The expiration key is deleted when read is found to have expired
If a client uses the watch command to monitor key, it is marked as dirty after modification
After modification, 1 is added to the Dirty key counter for persistence and replication
If the database notification is turned on, the change will send the corresponding notification

RobJ *lookupkeyreadorreply (redisclient *c, RobJ *key, RobJ *reply) {
RobJ *o = Lookupkeyread (c->db, key);
if (!o) addreply (c,reply);
return o;
}
RobJ *lookupkeyread (Redisdb *db, RobJ *key) {
RobJ *val;

Whether the query has expired
Expireifneeded (Db,key);
val = LookupKey (Db,key);
if (val = NULL)
server.stat_keyspace_misses++;
Else
server.stat_keyspace_hits++;
return Val;
}
RobJ *lookupkey (Redisdb *db, RobJ *key) {
Dictentry *de = Dictfind (db->dict,key->ptr);
if (DE) {
RobJ *val = Dictgetval (DE);

/* Update the access time for the ageing algorithm.
* Don ' Does it if we have a saving child, as this'll trigger
* A copy on write madness. */
if (server.rdb_child_pid = = 1 && server.aof_child_pid = = 1)
Set LRU Time
VAL->LRU = Server.lruclock;
return Val;
} else {
return NULL;
}
}

Expires

You can set the TTL of a key by using the Exprire or Pexpire command, and if the TTL of the key is 0, it is automatically deleted.

The Expires dictionary holds the expiration time for all keys in the database.

The key of the outdated dictionary is a key object in a data
The value of the Expired field is an integer of long type, and the expiration time of the key is saved
void Expirecommand (Redisclient *c) {
Expiregenericcommand (C,mstime (), unit_seconds);
}
void Expiregenericcommand (Redisclient *c, Long long basetime, int unit) {
RobJ *key = c->argv[1], *param = c->argv[2];
Long long when; /* Unix time in milliseconds when the key would expire. */

if (getlonglongfromobjectorreply (c, Param, &when, NULL)!= REDIS_OK)
Return

if (unit = = unit_seconds) when *= 1000;
When + = Basetime;

/* No key, return zero. */
if (Lookupkeyread (c->db,key) = = NULL) {
Addreply (C,shared.czero);
Return
}

/* EXPIRE with negative TTL, or expireat with a timestamp into the past
* should never be executed as a DEL while load the aof or in the context
* of a Slave instance.
*
* Instead We take the other branch of the IF statement setting a expire
* (possibly in the past) and a explicit DEL from the master. */
if (when <= mstime () &&!server.loading &&!server.masterhost) {
RobJ *aux;

Redisassertwithinfo (C,key,dbdelete (C->db,key));
server.dirty++;

* Replicate/aof this as a explicit DEL. *
Aux = Createstringobject ("DEL", 3);
Rewriteclientcommandvector (C,2,aux,key);
Decrrefcount (aux);
Signalmodifiedkey (C->db,key);
Notifykeyspaceevent (Redis_notify_generic, "Del", Key,c->db->id);
Addreply (c, Shared.cone);
Return
} else {
Put it in the Expires dictionary.
Setexpire (C->db,key,when);
Addreply (C,shared.cone);
Signalmodifiedkey (C->db,key);
Notifykeyspaceevent (Redis_notify_generic, "expire", key,c->db->id);
server.dirty++;
Return
}
}

Expiration key deletion policy

Lazy Delete: Every time the command is executed, the expireifneeded function is invoked to check for expiration, and if it has expired, the change function deletes the expiration key
Timed deletion: Timed execution of the Activeexpirecycletryexpire function
expireifneeded
int expireifneeded (Redisdb *db, RobJ *key) {
mstime_t when = Getexpire (Db,key);
mstime_t now;

if (when < 0) return 0; /* No expire for this key * *

/* Don ' t expire anything while loading. It is done later. */
if (server.loading) return 0;

/* If We are in the "a" Lua script, we claim that
* Blocked to the Lua script started. This way a key can expire
* Only the ' the ' the ' It is accessed ' and not ' in the ' middle '
* Script execution, making propagation to slaves/aof consistent.
* Issue #1525 on Github for more information. */
now = Server.lua_caller? Server.lua_time_start:mstime ();

/* If We are running in the "a" Slave, return ASAP:
* The slave key expiration is controlled from the master that would
* Send us synthesized DEL operations for expired keys.
*
* Still we try to return the right information to the caller,
* This is, 0 if we are should be still valid, 1 if
* We are the ' key ' expired at this time. */
if (server.masterhost!= NULL) return to now > when;

/* Return is the key has not expired * *
If (now <= is) return 0;

/* Delete the key * *
server.stat_expiredkeys++;
Propagateexpire (Db,key);
Notifykeyspaceevent (redis_notify_expired,
"Expired", key,db->id);
Return Dbdelete (Db,key);
}

Activeexpirecycletryexpire

while (num–) {
Dictentry *de;
Long TTL;

if (de = Dictgetrandomkey (db->expires)) = = NULL) break;
TTL = Dictgetsignedintegerval (DE)-now;
if (Activeexpirecycletryexpire (Db,de,now)) expired++;
if (TTL < 0) ttl = 0;
Ttl_sum + + ttl;
ttl_samples++;
}

aof, RDB, and replication functions for handling expired keys

Keys that have expired are not saved to the new Rdb file when the Rdb file is generated
Load Rdb File:
The expiration key is ignored when the primary server is loaded
Loaded from the server, will be loaded (but will soon be overwritten because of synchronization)
AoF write, has expired not deleted keys have no effect, is deleted, will append a del command
AoF overrides, the key is checked, the expiration key is not saved to the rewritten aof file
Copy:
When the primary server deletes an expiration key, the DEL command is explicitly sent to all from the server
Read commands from the server are not deleted in a timely manner and will not be deleted until the master server del command is accepted

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.