VMware + Ubuntu 18.04 + CLion調試 Redis5 源碼

前言

Redis 是目前最火熱的緩存中間件之一,各大公司在面試時,都會把 Redis 做爲重點考察的一部分。可是由於 Redis 是使用 C 語言開發的,它不像咱們平時使用 Java、C# 等高級語言,在編輯器中就能夠直接看到源碼進行學習,學習 Redis 只能經過平常使用,或者遇到問題的時候去網上 Google 查找,而這種級別所能學到的知識是不夠,要較好的掌握 Redis 的原理,經過源碼學習是較好的一條路徑,並且 Redis 的源碼並不困難,是做爲進階學習 C 語言的優秀教材。git

若是你沒有 C 語言基礎,那麼仍是推薦你去看看 《C Primer Plus》,若是你有一門高級語言的基礎,你會發生 C 比這些高級語言都要簡單,惟一須要注意的就是咱們常說的指針。做爲一個程序員,掌握 C 語言也會使你學習計算機組成原理、計算機網絡、操做系統更加輕鬆。程序員

曾經聽過一個行業中的大佬說過:面試

不會 C 語言的程序員不是一個合格的程序員。redis

工具介紹

工欲善其事,必先利其器json

咱們首先要有一些趁手的工具來幫助咱們閱讀、調試源碼,就像開發 Java 應用使用 IDEA 同樣,一個趁手的工具能夠達到事倍功半的效果。api

由於官方提供的 Redis 只支持 Linux 系統,因此咱們須要一個 Linux 環境。咱們這裏使用 VMware 開啓一個虛擬機、Ubuntu 18.04 做爲操做系統、CLion 做爲閱讀、調試工具(使用過 IDEA 的同窗,確定能夠很快掌握 CLion 的使用,基本沒有區別)。緩存

關於 VMware、Ubuntu 18.0四、CLion 的安裝這裏就再也不贅述了,由於都是很簡單的步驟,若是連這一步都能攔住你,那麼能夠 Google 一下,有不少教程能夠幫你跨過這個小坎。網絡

源碼能夠直接從 Github 上克隆下來,若是從 Github 上克隆的速度較慢,能夠從這個連接克隆:gitee.com/lhd951220/r…數據結構

總所周知,直接從 Github 上克隆項目會比較慢,這裏建議你們能夠開通一個 Gitee 帳戶,而後把須要從 Github 上的克隆的源碼導入到 Gitee 中,而後使用 Gitee 上的連接進行下載,你會體驗到什麼叫飛通常的速度。關於這裏的教程也很簡單,網上也有不少資源,能夠自行搜索。編輯器

正式開始

首先,須要介紹一下,CLion 是使用 CMake 做爲項目構建工具的,這裏不須要知道 CMake 是什麼(我也不是很懂),大概理解爲 Maven 就能夠了。

CMake 是經過一種 CMakeLists.txt 文件來構建項目的,因此咱們首先須要建立一個該文件。

注意:咱們在克隆完項目的時候,最後將分支切換到 commitId 爲 767977c 的分支,由於我發現一些分支缺乏部分文件,沒法構建。切換的方法很簡單,直接在命令行執行 git checkout 767977c

第一步

在項目的主目錄下建立一個CMakeLists.txt 文件。

image-20200627221404699

建立完文件以後會出現下圖所示的提示,而後咱們要點擊箭頭指向的文字(此時它會提示構建失敗,可是沒關係,咱們能夠不用管)這樣它就會將該項目看做是一個 CMake 項目,而且最下方也會出現一個快捷的構建窗口,方便咱們後面進行構建項目。

image-20200627222308664

而後將以下內容複製進該文件:

cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
project(redis VERSION 5.0)
set(CMAKE_BUILD_TYPE "Debug")

get_filename_component(REDIS_ROOT "${CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE)

execute_process(
        COMMAND sh -c ./mkreleasehdr.sh
        WORKING_DIRECTORY ${REDIS_ROOT}/src/
)

add_subdirectory(deps)
add_subdirectory(src/modules)

set(SRC_SERVER_TMP
        src/adlist.c
        src/acl.c
        src/ae.c
        src/anet.c
        src/ae_epoll.c
        src/dict.c
        src/sds.c
        src/zmalloc.c
        src/lzf_c.c
        src/lzf_d.c
        src/pqsort.c
        src/zipmap.c
        src/sha1.c
        src/sha256.c
        src/ziplist.c
        src/release.c
        src/networking.c
        src/util.c
        src/object.c
        src/db.c
        src/replication.c
        src/rdb.c
        src/t_string.c
        src/t_stream.c
        src/t_list.c
        src/t_set.c
        src/t_zset.c
        src/timeout.c
        src/tls.c
        src/evict.c
        src/defrag.c
        src/module.c
        src/quicklist.c
        src/expire.c
        src/childinfo.c
        src/redis-check-aof.c
        src/redis-check-rdb.c
        src/lazyfree.c
        src/geohash.c
        src/gopher.c
        src/rax.c
        src/geohash_helper.c
        src/siphash.c
        src/geo.c
        src/t_hash.c
        src/config.c
        src/connection.c
        src/aof.c
        src/pubsub.c
        src/multi.c
        src/debug.c
        src/sort.c
        src/intset.c
        src/syncio.c
        src/cluster.c
        src/crc16.c
        src/endianconv.c
        src/slowlog.c
        src/scripting.c
        src/bio.c
        src/rio.c
        src/rand.c
        src/memtest.c
        src/crc64.c
        src/bitops.c
        src/sentinel.c
        src/notify.c
        src/setproctitle.c
        src/blocked.c
        src/hyperloglog.c
        src/latency.c
        src/sparkline.c
        src/t_stream.c
        src/lolwut.c
        src/tracking.c
        src/lolwut5.c
        src/lolwut6.c
        src/listpack.c
        src/localtime.c
        )
set(SRC_SERVER src/server.c ${SRC_SERVER_TMP})

set(SRC_CLI
        src/anet.c
        src/sds.c
        src/adlist.c
        src/redis-cli.c
        src/zmalloc.c
        src/release.c
        src/anet.c
        src/ae.c
        src/crc64.c
        src/crc16.c
        src/dict.c
        src/siphash.c
        )


set(EXECUTABLE_OUTPUT_PATH src)
link_directories(deps/linenoise/ deps/lua/src deps/hiredis)

add_executable(redis-server ${SRC_SERVER})
target_include_directories(redis-server
        PRIVATE ${REDIS_ROOT}/deps/linenoise
        PRIVATE ${REDIS_ROOT}/deps/hiredis
        PRIVATE ${REDIS_ROOT}/deps/lua/src)
target_link_libraries(redis-server
        PRIVATE dl
        PRIVATE pthread
        PRIVATE m
        PRIVATE lua
        PRIVATE linenoise
        PRIVATE hiredis)

add_executable(redis-cli ${SRC_CLI})
target_include_directories(redis-cli
        PRIVATE ${REDIS_ROOT}/deps/linenoise
        PRIVATE ${REDIS_ROOT}/deps/hiredis
        PRIVATE ${REDIS_ROOT}/deps/lua/src)

target_link_libraries(redis-cli
        PRIVATE pthread
        PRIVATE m
        PRIVATE linenoise
        PRIVATE hiredis
        )
複製代碼

第二步

在 dept/ 目錄下也建立一個 CMakeLists.txt 文件

image-20200627221515958

而後將以下內容複製進該文件:

add_subdirectory(hiredis)
add_subdirectory(linenoise)
add_subdirectory(lua)
複製代碼

第三步

在 dept/lineboise/ 目錄下建立一個 CmakeLists.txt 文件

image-20200627221725484

而後將以下內容複製進該文件:

add_library(linenoise linenoise.c)
複製代碼

第四步

在 dept/lua/ 目錄下建立一個 CmakeLists.txt 文件

image-20200627221853985

而後將以下內容複製進該文件:

set(LUA_SRC
        src/lapi.c src/lcode.c src/ldebug.c src/ldo.c src/ldump.c src/lfunc.c
        src/lgc.c src/llex.c src/lmem.c
        src/lobject.c src/lopcodes.c src/lparser.c src/lstate.c src/lstring.c
        src/ltable.c src/ltm.c
        src/lundump.c src/lvm.c src/lzio.c src/strbuf.c src/fpconv.c
        src/lauxlib.c src/lbaselib.c src/ldblib.c src/liolib.c src/lmathlib.c
        src/loslib.c src/ltablib.c
        src/lstrlib.c src/loadlib.c src/linit.c src/lua_cjson.c
        src/lua_struct.c
        src/lua_cmsgpack.c
        src/lua_bit.c
        )

add_library(lua STATIC ${LUA_SRC})
複製代碼

到了這一步,咱們已經完成一大半了。

第五步

在 src/modules/ 目錄下建立一個 CmakeLists.txt 文件

image-20200627222644164

而後將以下內容複製進該文件:

cmake_minimum_required(VERSION 3.9)
set(CMAKE_BUILD_TYPE "Debug")
add_library(helloworld SHARED helloworld.c)
set_target_properties(helloworld PROPERTIES PREFIX "" SUFFIX ".so")


add_library(hellotype SHARED hellotype.c)
set_target_properties(hellotype PROPERTIES PREFIX "" SUFFIX ".so")


add_library(helloblock SHARED helloblock.c)
set_target_properties(helloblock PROPERTIES PREFIX "" SUFFIX ".so")


add_library(testmodule SHARED testmodule.c)
set_target_properties(testmodule PROPERTIES PREFIX "" SUFFIX ".so")
複製代碼

第六步

在 src/ae_epoll.c 文件下添加下面代碼

#include "ae.h"
#include <zconf.h>
#include "zmalloc.h"
複製代碼

最終如圖所示:

image-20200627222840862

開始調試

此時,咱們就完成了全部步驟,能夠開始調試了。

image-20200627223036394

安裝圖中數字所示步驟點擊,看到圖中框中顯示的信息則表示編譯成功。此時編譯器的右上角會出現下圖所示的列表

image-20200627223207484

而後,咱們選擇 redis-server,點擊綠色小箭頭便可開啓 Redis 服務,而後咱們就能夠在源碼中打斷點進行調試了。

總結

Redis 的源碼中包含了大量的數據結構,咱們能夠在裏面學到 SDS、跳躍表、字典、哈希表、布隆過濾器等等數據結構的實現,而且這些數據結構並不會比咱們平時接觸到的知識複雜,還想深刻一點還能夠看看 Redis 是如何使用 epoll 實現多路複用的。

學習 Redis 源碼配套此教程效果更佳。

總之,源碼是學習一個工具第二好的方式,第一好固然文檔啦!

相關文章
相關標籤/搜索