we know that the Redis database, as a memory database, is similar to memcached, where the basic operations are stored in a memory buffer until the data in the buffer is full and persisted to disk. Today, I focused on working with the in-memory database for Redis. Compared to normal data manipulation, there is nothing particularly more to do with some of the other operations. Here are some of the APIs I've sorted out:
/*-----------------------------------------------------------------------------* c-level DB API *----------------- -----------------------------------------------------------*/robj *lookupkey (redisdb *db, RobJ *key)/* Get the value represented by the key from the DB */robj *lookupkeyread (redisdb *db, RobJ *key)/* Find the value of a key, the difference from the LookupKey method is that the expiration check */robj *lookupkeywrite ( Redisdb *db, RobJ *key)/* As with Lookupkeyread, just less hit brush statistics */robj *lookupkeyreadorreply (redisclient *c, RobJ *key, RobJ *reply /* Read-erase operation with reply */robj *lookupkeywriteorreply (redisclient *c, RobJ *key, RobJ *reply)/* Write operation with reply */void dbadd (Redisdb *db, R Obj *key, robj *val)/* Adds a value to the in-memory database, if key already exists, the operation is invalid */void dboverwrite (redisdb *db, RobJ *key, RobJ *val)/* DB key value Cover operation, if this key does not exist, the operation fails */void Setkey (redisdb *db, RobJ *key, RobJ *val)/* Advanced set operation, if not present directly add, the existing will overwrite */int dbexists (redisdb *db , RobJ *key)/* DB exists this key */robj *dbrandomkey (Redisdb *db)/* Randomly returns no expired key */int Dbdelete (Redisdb *db, RobJ *key)/* DB Delete Operation */robj *dbunsharestringvalue (Redisdb *db, RobJ *kEY, robj *o)/* Remove the share of key, and then you can modify the operation */long long emptyDb (void (callback))/* Clears all databases in the server, and the callback function is passed in as a parameter void* */int CtDb (redisclient *c, int id)/* The client chooses a DB */void Signalmodifiedkey (redisdb *db, RobJ *key)/* On the server to call this method whenever key is modified, TOUCHW Atchedkey (Db,key) method, the client that corresponds to this key is locked */void signalflusheddb (int dbid)/* and the key in dbid is touch once */void flushdbcommand ( Redisclient *c)/* Refreshes the DB command where the client is located */void Flushallcommand (redisclient *c)/* Refreshes all the databases in the server */void Delcommand ( Redisclient *c)/* Delete the database */void Existscommand (redisclient *c)/* Based on the command parameters of the client or if a key exists command */void SelectCommand ( Redisclient *c)/* Client clients Select Database command */void randomkeycommand (redisclient *c)/* Get random key instruction */void Keyscommand (redisclient * c)/* Reply to client key obj command */void scancallback (void *privdata, const dictentry *de)/* Type scan out key,val */int parsescancurso Rorreply (redisclient *c, RobJ *o, unsigned long *cursor)/* Determine if the scan cursor is valid */void Scangenericcommand (redisclient *c, RO BJ *o, unsigned long cursor)/* 3:filter elements. (filter element) 4:reply to the client. (Reply-to-client) */void Scancommand (redisclient *c)/* Scan command */void dbsizecommand (redisclient *c)/* Total number of DB dictionaries used by the client */void Lastsaveco Mmand (redisclient *c)/* Server Last saved Operation */void Typecommand (redisclient *c)/* Client query for key type */void Shutdowncommand ( Redisclient *c)/* Shutdown terminate command, server to do the last save Operation */void Renamegenericcommand (redisclient *c, int nx)/* For key rename operation */void Renam Ecommand (redisclient *c)/* Rename may overwrite the original value command */void Renamenxcommand (redisclient *c)/* Rename without overwriting the original value */void Movecommand ( Redisclient *c)/* Move key from source db to Destination DB */int Removeexpire (redisdb *db, RobJ *key)/* Remove expired key */void Setexpire (Redisdb *db, R Obj *key, long long when)/* Set the expired key to move key Dict key into expire dict, and set time for this key */long long Getexpire (Redisdb *db, RobJ *ke Y)/* Get Expiration time of key */void Propagateexpire (Redisdb *db, robj *key) int expireifneeded (Redisdb *db, RobJ *key)/* To determine if this key expires, 2 condition, 1 whether there is a expire key is not expired 2. In expire, judge when time has not exceeded the current time, no more than also not expired */void Expiregenericcommand (redisclient *c, long Long basetime, int unit) void Expirecommand (redisclient *c) void Expireatcommand (redisclient *c) void Pexpirecommand (redisclient *c) void Pexpireatcommand (redisclient *c) void Ttlgenericcommand (redisclient *c, int output_ms)/* Returns the TTL lifetime of key, Some of the following methods are different for time units, the default is seconds */void Ttlcommand (redisclient *c) void Pttlcommand (redisclient *c) void Persistcommand ( Redisclient *c)/* key exists command */int *getkeysusingcommandtable (struct rediscommand *cmd,robj **argv, int argc, int *numkeys ) int *getkeysfromcommand (struct rediscommand *cmd,robj **argv, int argc, int *numkeys, int flags) void Getkeysfreeresult (i NT *result) int *nopreloadgetkeys (struct rediscommand *cmd,robj **argv, int argc, int *numkeys, int flags) int *renamegetkey S (struct Rediscommand *cmd,robj **argv, int argc, int *numkeys, int flags) int *zunionintergetkeys (struct Rediscommand *cmd , RobJ **argv, int argc, int *numkeys, int flags)
In the latter part of the API are some of the functions encapsulated by some command operations. Open to system calls. In the above API, the typical is, Read,write and other APIs,
/* Gets the value represented by the key from the DB */robj *lookupkey (redisdb *db, RobJ *key) {//find dict dictentry = *de from the db dictfind dictionary (db->dict, KEY->PTR); if (DE) { robj *val = Dictgetval (DE); /* Update the access time for the ageing algorithm. * Don ' t do it if we had a saving child, as this would trigger * A copy on Write madness. * /if (server.rdb_child_p id = =-1 && server.aof_child_pid = =-1) VAL->LRU = Server.lruclock; return val; } else { return NULL;} }
But when the call is actually called, this method is not called directly, there are some restrictions that will filter out the expired key and the number of buffer hits:
/* Find the value of a key, the difference from the LookupKey method is that the expiration check */robj *lookupkeyread (redisdb *db, RobJ *key) { robj *val; Expireifneeded (Db,key); val = LookupKey (db,key); if (val = = NULL) //hit number minus one server.stat_keyspace_misses++; else //number of hits incremented by 1 server.stat_keyspace_hits++; return Val;}
Buffers can be effectively adjusted. Here's an operation to modify the in-memory database:
/* High level Set operation. This function can is used in order to set * A key, whatever it is existing or not, to a new object. * * 1) The ref count of the value object is incremented. * 2) clients watching for the destination key notified. * 3) The expire time of the key is reset (the key is made persistent). *//* Advanced Setup operation, if not present directly add, exists on overwrite */void setkey (redisdb *db, RobJ *key, RobJ *val) { if (lookupkeywrite (db,key) = = NULL) { Dbadd (db,key,val); } else { dboverwrite (db,key,val); } Add Reference Count Incrrefcount (val) to this key; Removeexpire (Db,key); Signalmodifiedkey (Db,key);}
We see in fact every time the database operation changes, will appear Signalmodifiedkey (Db,key) This method, the general meaning is to change the value of the key to the corresponding values, the implementation of the operation in the end is what it, the implementation of this method is in the DB.C:
/*-----------------------------------------------------------------------------* Hooks for key space changes. * * Every time a key in the database is modified the function * Signalmodifiedkey () is called. * * Every time a DB is flushed the function signalflushdb () is called. *----------------------------------------------------------------------------*//* This method is called whenever the key is modified, Touchwatchedkey (Db,key) method, the client that corresponds to this key is locked */void Signalmodifiedkey (redisdb *db, RobJ *key) { Touchwatchedkey (db, key);}
Call is the Touch-key method, is to listen to this key to set the client list, only one client operation successful execution, the client's other operations are not valid, to achieve synchronization. When the memory data is becoming full, it is periodically flushed to disk:
/* Refresh all the databases in the server */void Flushallcommand (redisclient *c) { signalflusheddb ( -1); Server.dirty + = EmptyDb (NULL); Addreply (C,shared.ok); if (server.rdb_child_pid! =-1) { Kill (SERVER.RDB_CHILD_PID,SIGUSR1); Rdbremovetempfile (server.rdb_child_pid); } if (Server.saveparamslen > 0) {/ * normally rdbsave () would reset dirty, but we don ' t want this here * as Otherw Ise Flushall is not being replicated nor put into the AOF. */ int saved_dirty = Server.dirty; Re-Save the RDB here rdbsave (server.rdb_filename); Server.dirty = Saved_dirty; } server.dirty++;}
Rdbsave Focus when operating. In DB.C also mentioned a concept, expire outdated concept, that is, there is the concept of key expiration, in the memory database, frequent operations such as will cause a lot of outdated key-value pairs exist, so in the DB, maintained a db->expires thing, All expired can exist in the db->expires, periodically will be removed, so in the earliest function, to the memory database when the value of the time to determine whether to expire
/* To determine if this key expires, 2 conditions, 1 whether there is a expire key does not expire 2. In expire inside, judge when time is not more than the current time, no more than also not expired */int expireifneeded (Redisdb *db , RobJ *key) {mstime_t when = Getexpire (Db,key); mstime_t now; if (when < 0) return 0; /* No expire for the This key *//* Don ' t expire anything while loading. It'll be done later. */if (server.loading) return 0; /* If We are in the context of a LUA script, we claim that time was * blocked to when the Lua script started. This-a key can expire * Only the first time it's accessed and not in the middle of the * script execution, MA King propagation to slaves/aof consistent. * See issue #1525 on Github for more information. * * now = Server.lua_caller? Server.lua_time_start:mstime (); /* If We are running in the context of a Slave, return ASAP: * The slave key expiration be controlled by the master th At would * send us synthesized DEL operations for expired keys. * * Still we try to return the right information to The caller, * are, 0 if we think the key should be still valid, 1 if * We think the key are expired at this Ti Me. */if (server.masterhost! = NULL) return now > when; /* Return when the This key had not expired */if (now <= when) return 0; /* Delete the key */server.stat_expiredkeys++; Propagateexpire (Db,key); Notifykeyspaceevent (redis_notify_expired, "EXPIRED", key,db->id); Return Dbdelete (Db,key);}
Each expire key has a TTL concept, which is "Time to Live" lifetime:
/* Returns the TTL lifetime of key */void Ttlgenericcommand (redisclient *c, int output_ms) { Long long expire, TTL =-1; /* If the key does not exist @ all, return-2 * /if (Lookupkeyread (c->db,c->argv[1]) = = NULL) { Addreplylon Glong (c,-2); return; } /* The key exists. Return-1 if it has no expire, or the actual * TTL value otherwise. * /expire = Getexpire (c->db,c->argv[1]); if (expire! =-1) { //If it has been moved into an expired key, calculate the current time in the expiration time is still much worse, TTL is the current time to live units for MS TTL = Expire-mstime (); if (TTL < 0) ttl = 0; } if (ttl = =-1) { addreplylonglong (c,-1); } else { addreplylonglong (C,output_ms ttl: ((ttl+500)/1000)); }}
Used to determine whether or not to expire.
Redis Source Code Analysis (18)---DB.C in-memory database operations