1. 程式人生 > >我是如何通過新增一條命令學習redis原始碼的

我是如何通過新增一條命令學習redis原始碼的

準備工作

這篇文章不會告訴你啥是redis,如果不瞭解請自行搜尋學習。

我的操作環境是cent OS 6.5系統,vim編輯器。

我打算下載一個比較穩定的redis原始碼包進行修改測試。

$ wget http://download.redis.io/redis-stable.tar.gz

$ tar -zxvf redis-stable.tar.gz

$ cd redis-stable

進入redis-stable目錄可以看到src目錄,裡面是redis的實現原始碼,我下面的工作基本就是修改這裡面的內容。

我打算增加一條自定義的命令,並希望由此學習redis究竟是如何處理一條命令的。在此之前先看看redis自帶的命令是怎麼玩的。

[[email protected] bin]# redis-server /etc/redis/redis.conf 
[[email protected] bin]# redis-cli 
127.0.0.1:6379> set "pony" "大帥哥"
OK
127.0.0.1:6379> get "pony"
"大帥哥"
127.0.0.1:6379> 

正式開始

我打算加入的命令叫STRUPPER,這條命令後面跟一個引數,也是key,返回key所對應的value的字母大寫轉換後的結果。比如key的值是”test”,那麼strupper key就返回”TEST”。

看起來似乎是一條沒有任何意義的命令(事實也是這樣,哈哈), 但是請明白我在意的不是命令本身,而是redis的命令處理機制。

在src/server.c中定義了redis的命令表,

struct redisCommand redisCommandTable[] = {
    {"get",getCommand,2,"rF",0,NULL,1,1,1,0,0},
    {"set",setCommand,-3,"wm",0,NULL,1,1,1,0,0},
    {"setnx",setnxCommand,3,"wmF",0,NULL,1,1,1,0,0},
    {"setex",setexCommand,4
,"wm",0,NULL,1,1,1,0,0}, ...

從程式碼中的註釋,我瞭解到如果要增加一條命令,應該首先在這個表中增加一行定義。並且我還了解到結構體的每個欄位的意義。

拿第一行舉例,”get”是命令的名字,getCommand是一個函式指標,型別是:

typedef void redisCommandProc(client *c);

2表示引數的數量,比如get命令的用法是get後面跟key,第一個引數是get本身,第二個引數是key。

“rF”是標識命令的屬性,r表示只讀,也就是這條命令不能修改key對應的value值。F表示這是條”快命令”,就是時間複雜度是O(1)或者O(log(N))。

緊接著的0暫時不用管,總是設定為0就行。

接下來的NULL域,大部分時候這個域都應該是NULL。少數時候可以放一個函式指標,用在命令後面引數比較多的時候,分不清哪個是key。

接下來的三個數字,對於get命令,第一個引數(key)在位置1上,最後一個引數(也是key)在位置1上,從第一個引數到最後一個引數的增量也是1。

最後兩個域總是初始化為0。

基於以上分析,我加了命令表底部加了一條命令:

{"strupper",strupperCommand,2,"w",0,NULL,1,1,1,0,0}

然後我需要在server.h中宣告下命令處理函式,

void strupperCommand(client *c);

函式的實現應該放在哪裡? redis是根據命令的型別來分類存放的,比如像getCommand和setCommand這樣的字串操作函式都是放在t_string.c檔案中實現的,strupper也算是字串處理函式,所以自然也是定義到這裡,我先定義一個空函式。

void strupperCommand(client *c)
{
}

到這裡,我先編譯下看看效果。

[[email protected] redis-stable]# make
[[email protected] redis-stable]# make install

[[email protected] bin]# redis-server /etc/redis/redis.conf
[[email protected] bin]# redis-cli
127.0.0.1:6379> 
127.0.0.1:6379> set pony "test"
OK
127.0.0.1:6379> strupper
(error) ERR wrong number of arguments for 'strupper' command
127.0.0.1:6379> strupper pony

可以看出,當我執行strupper pony時卡住了,是因為函式是空的還沒實現。實現也是非常簡單,

void strupperCommand(client *c)
{
    robj *o;

    if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL)
        return;

    if (o->type != OBJ_STRING) {
        addReply(c,shared.wrongtypeerr);
        return;
    } else {

        if (sdsEncodedObject(o)) 
        {
            sdstoupper(o->ptr);
        }
        addReplyBulk(c,o);
        return;
    }
}

大部分程式碼都是參考了get命令(因為這兩個命令實在是太像了),我只需把get取出來的value值轉換成大寫就行了,當然一些基本的檢查也是必須的。

lookupKeyReadOrReply函式根據傳入的key(c->argv[1])查詢,如果找到了會返回一個redis object物件,我們要的value就在這個物件裡。

addReply負責響應結果到客戶端。

sdsEncodedObject確保只對OBJ_ENCODING_RAW和OBJ_ENCODING_EMBSTR編碼的string物件進行操作,這樣才能用sdsXXX這樣的函式操作。

sdstoupper可以對字串整體進行大寫轉換。

重新編譯下,測試。

127.0.0.1:6379> set pony "test"
OK
127.0.0.1:6379> 
127.0.0.1:6379> get pony
"test"
127.0.0.1:6379> strupper pony
"TEST"

結果跟預想的一樣。是個好的開始,後面再慢慢深入研究redis。

參考

相關推薦

是如何通過新增命令學習redis原始碼

準備工作 這篇文章不會告訴你啥是redis,如果不瞭解請自行搜尋學習。 我的操作環境是cent OS 6.5系統,vim編輯器。 我打算下載一個比較穩定的redis原始碼包進行修改測試。 $ wget http://download.redis.io

命令停止所有lxc容器,刪除所有lxc容器

gre troy 停止 des def code done awk don for i in $(virsh -c lxc:/// list | grep -v ‘Id‘ | awk ‘{print $2}‘);do virsh -c lxc:/// destroy $

每5秒向數據庫中插入記錄-學習筆記

每5秒向數據庫中插入一條記錄-學習筆記 import java.sql.SQLException; import java.util.Timer; import java.util.TimerTask; import java.util.UUID; import cn.itcast.web.dao.Syste

web每5秒向數據庫中插入記錄-學習筆記

每5秒向數據庫中插入一條記錄-學習筆記SystemListener import java.util.Timer; import java.util.TimerTask; import java.util.UUID; import javax.servlet.ServletContextEvent; imp

命令解決mac版本python IDLE無法輸入中文問題

install 兩種 size tps 命令 輸入 homebrew NPU python3 安裝完Python通常自動就有了一個簡易的集成環境IDLE,但在mac上,無法在IDLE中使用中文。 通常故障有兩種情況: 在IDLE中,中文輸入法根本無法工作,不會彈出輸入框

命令深度清理你的mac

use DG 17. rep vid ash 通過 app pan 一條命令深度清理你的mac mac 用了一段時間後很快發現硬盤空間不夠了,就想找一些磁盤清理的工具,但是發現居然都是收費的. 就手工操作吧.方法其實非常簡單. 就一條命令, cd / du -hd 5 |

Linux如何讓命令快速修改用戶密碼?

div pre span display str echo one pan class 問題:修改密碼的命令為passwd,需要按Enter兩次,如何一條命令快速修改密碼呢? #實現命令: #echo 密碼 | passwd echo 密碼 | passwd --st

vue的資料來源-json格式陣列新增資料並重新整理。記錄一下

data () {     return {       arr: [{a:'111',b:'222',c:'333'},{a:'444',b:'555',c:'666'}],     }   }, method

Mac上命令搭建web伺服器

實際測試工作中偶爾會需要搭建Web伺服器環境,由於Mac OS X自帶了Apache和PHP環境,只需要簡單的啟動就可以。 開啟Apache 開啟Web伺服器的方法有兩種(預設啟動埠號是80): 開啟:系統偏好配置 ——> 共享 ——>Web共享 終端可以通過Apache啟動命令開

處理流程已辦完,選擇一個節點,新增待辦

---找到流程例項id--- select * from ACT_HI_PROCINST t where t.proc_inst_id_ in (select distinct t.proc_inst_id_ from ACT_HI_VARINST t where t.text_='402880e864

mybatis的Mapper中在mysql和oracl中新增記錄,返回記錄id

情景再現:專案中經常在mybatis的Mapper中在mysql和oracl中新增一條記錄後,需要返回記錄id: 1.使用mysql資料庫: //java的User物件,包含id,name,password三個屬性 <insert id="insert" useGenerate

新增新資料並返回此資料的ID(主鍵)

新增資料後返回Id <insert id="" parameterType="" useGeneratedKeys="true" keyProperty="id" keyColumn="id"> useGeneratedKeys:必須設定為true,否

ceph儲存 centos下通過Linux的ACL命令學習ACL許可權分配原理

注意:當然檔案和目錄的繼承又會有一些差異。因為檔案不像目錄,目錄的下層可再建立檔案和目錄,所以目錄在繼承上層目錄的ACL設定資訊時,會保證在它下層的目錄和檔案仍可以繼承它的ACL設定資訊。所以它要完全繼承上層目錄的ACL設定資訊。而檔案不需要繼承這些設定資訊。所以對於檔案來說僅會繼承scan使用者這條ACL設

Axure中繼器新增資料&刪除標記行

中繼器新增新增一條資料 1、新增一箇中繼器,並命名rep; 2、新增一個按鈕; 3、新增一個文字框,並命名txt。 4、點選按鈕設定互動。 5、雙擊“滑鼠單擊時”,進入“用例編輯對話方塊”, 選擇 “中繼器”->“資料集”->“新

Android7.0 Settings主選單新增item

往Android7.0的settings的主選單裡新增一條item. N與M的Settings不同,在M上只要找到Settings裡面的相應的佈局新增就好,但在N上由於Setting裡面的item不再受佈局控制,所以得在程式碼中新增. 找到/packages

新增新資料並返回此資料的ID

<insert id="" parameterType="" useGeneratedKeys="true" keyProperty="id" keyColumn="id"> useGeneratedKeys:必須設定為true,否則無法獲取到主鍵id。 keyPropert

mybatis 新增新資料並返回此資料的ID(主鍵)

通常資料庫中表的主鍵是‘自動遞增(mysql)’或’序列(oracle)‘,但插入資料後又要取得些條資料的ID(將ID做為主鍵) 利用Mybatis 的 selectKey來獲得: <!-- 新增部門 返回部門ID --> <insert id="ad

linux下安裝jdk 詳細步驟(命令即可安裝)

作為Java開發人員,在Linux下安裝一些開發工具是必備技能,本文以安裝jdk為例,詳細記錄了每一步的操作命令,以供參考。 第一種方法 只需要一條命令就可以安裝jdk: yum install java-1.8.0-openjdk* -y執行了這條命令不需要配

【轉】sqlplus中不能上下鍵選擇前命令解決方法

安裝一個叫rlwrap的工具: 已經上傳到本文附件:字尾為.rar,主要是51cto不支援.tar.gz字尾,實際上是一個tar.gz壓縮包 tar -zxvf rlwrap-0.30.tar.gz cd rlwrap-0.30 ./configure make

linux中命令修改使用者名稱的密碼

先要通過useradd新增使用者 useradd -d /opt/reconciliation -s /sbin/nologin -G root ftpUser 如果是普通的passwd,需要輸入兩次密碼: [[email protected] vsftpd]#