ソースに近づく:Redisがコマンドを実行する方法
前文ではRedisの起動手順について説明した.InitServer()関数では、TCPポートとUnixのSocketsをリスニングするループイベントが作成され、Redisサーバが新しい接続を受信できるようになります.今日は、Redisがコマンドをどのように処理し、結果を返したのかを見てみましょう.
新しい接続の処理
RedisはinitServer()関数で循環イベントを作成し、受信したTCP接続およびUnixのSockets接続を処理するためにaccepttTcpHandlerおよびacceptUnixHandler関数(いずれもnetworking.cファイル)を呼び出します.この2つの関数はまたacceptCommonHandler()関数を呼び出し、この関数でcreateClient()関数を呼び出して新しいクライアント接続を表す新しいclientオブジェクトを作成します.
createClient()関数は具体的にどのようなことをしていますか?
まず変数cにメモリを割り当て,次いでSocket接続を非ブロック状態にし,TCP無遅延を設定した.その後、readQueryFromClient関数を呼び出すためにFileループイベント(aeCreateFileEvent)が作成されます.新しいクライアントのデフォルト接続は、サーバの最初のデータベース(0符号化)であり、最後にクライアントのさまざまなプロパティとステータスを設定する必要があります.
クライアントのコマンドを読む
先ほどreadQueryFromClient関数に言及しましたが、この関数はクライアントからコマンドを読み出すために使用されていることが名前からわかります.関数の具体的な実装を見てみましょう.
Redisはまずコマンドをバッファに読み込み、1回の最大読み取りサイズはPROTO_IOBUF_LEN(1024*16)bit.次にprocessInputBufferAndReplicate()関数を呼び出してバッファ内のデータを処理し、クライアントがmaster(プライマリスレーブ同期プロセス)である場合、Redisは処理前後のバッファの異なる部分を計算して、ノードからどのくらいのデータを受信したかを決定する.processInputBufferAndReplicate()関数は、クライアントがサーバにコマンドを送信する場合と、プライマリノードがノードからコマンドを送信する場合の両方を処理しますが、最後にprocessInputBuffer()関数を呼び出す必要があります.
processInputBuffer()関数は、クライアントが正常かどうかを先に判断し、接続が中断したり、クライアントがブロックされたりすると、すぐに処理コマンドを停止し、無駄なことをしません.そして、読み出した要求に応じて、対応するRedisが実行可能なコマンド(パラメータを含む)を生成する.異なる要求タイプは、processInlineBuffer()関数とprocessMultibulkBuffer()関数をそれぞれ呼び出します.コマンドを生成したら、processCommand()(server.cファイル)関数に渡して実行し、C_を返すとOKはクライアントをリセットし、次のコマンドを待ちます.C_を返すとERRでは、クライアントは破棄されます(例えばQUITコマンドを実行します).
プロセスCommand()関数は、Redis起動時にロードされたコマンドテーブルからコマンドを検索し、コマンドの実行権限を確認します.
clusterの場合、keyが現在のmasterに属しているかどうかを判断し、リダイレクト情報を返す必要はありません.
メモリが足りない場合は、ここでも解放できるメモリがあるかどうかを判断し、なければコマンドを実行できず、エラーメッセージを返す必要があります.
次に、書き込みコマンドを受信できない場合を判断します.サーバは永続化できない はmasterとして十分なslave がない.このサーバは読み取り専用slaveであり、そのmasterのみが書き込みコマンド を受信することができる.
サブスクリプションモードでは、§SUBSCRIBE/§UNSUBSCRIBE/PING/QUITという指定されたコマンドしか受信できません.
slaveとmasterが接続されていない場合、flag「t」のコマンド、例えばINFO、SLAVEOFなどしか受信できません.
コマンドにCMDがない場合LOADINGフラグで、現在サーバーがデータをロードしている場合は、このコマンドを受信できません.
luaスクリプトの長さを制限します.
上記の様々な条件判断を行った後、call()関数実行コマンドの呼び出しを本格的に開始することができます.
コマンドを実行して戻る
call()関数のパラメータはclientタイプであり,cmdメンバーを取り出して実行する.
コマンドを書くと、サーバが「汚い」になります.つまり、サーバはメモリの一部のページに変更があることをマークする必要があります.これはRedisの永続化にとって非常に重要であり,このコマンドがどれだけのkeyに影響を及ぼすかを知ることができる.コマンドの実行が完了しても終了しません.call関数は他の操作も行います.例えばログを記録したり、AOFファイルを書いたり、ノードからコマンドを同期したりします.
戻り値については,各コマンドにそれぞれの処理方法があり,後述する.
ここでRedisが命令を処理する過程も完了する.
後で具体的なコマンドでこのプロセスをより明確に紹介します.
新しい接続の処理
RedisはinitServer()関数で循環イベントを作成し、受信したTCP接続およびUnixのSockets接続を処理するためにaccepttTcpHandlerおよびacceptUnixHandler関数(いずれもnetworking.cファイル)を呼び出します.この2つの関数はまたacceptCommonHandler()関数を呼び出し、この関数でcreateClient()関数を呼び出して新しいクライアント接続を表す新しいclientオブジェクトを作成します.
createClient()関数は具体的にどのようなことをしていますか?
まず変数cにメモリを割り当て,次いでSocket接続を非ブロック状態にし,TCP無遅延を設定した.その後、readQueryFromClient関数を呼び出すためにFileループイベント(aeCreateFileEvent)が作成されます.新しいクライアントのデフォルト接続は、サーバの最初のデータベース(0符号化)であり、最後にクライアントのさまざまなプロパティとステータスを設定する必要があります.
クライアントのコマンドを読む
先ほどreadQueryFromClient関数に言及しましたが、この関数はクライアントからコマンドを読み出すために使用されていることが名前からわかります.関数の具体的な実装を見てみましょう.
Redisはまずコマンドをバッファに読み込み、1回の最大読み取りサイズはPROTO_IOBUF_LEN(1024*16)bit.次にprocessInputBufferAndReplicate()関数を呼び出してバッファ内のデータを処理し、クライアントがmaster(プライマリスレーブ同期プロセス)である場合、Redisは処理前後のバッファの異なる部分を計算して、ノードからどのくらいのデータを受信したかを決定する.processInputBufferAndReplicate()関数は、クライアントがサーバにコマンドを送信する場合と、プライマリノードがノードからコマンドを送信する場合の両方を処理しますが、最後にprocessInputBuffer()関数を呼び出す必要があります.
processInputBuffer()関数は、クライアントが正常かどうかを先に判断し、接続が中断したり、クライアントがブロックされたりすると、すぐに処理コマンドを停止し、無駄なことをしません.そして、読み出した要求に応じて、対応するRedisが実行可能なコマンド(パラメータを含む)を生成する.異なる要求タイプは、processInlineBuffer()関数とprocessMultibulkBuffer()関数をそれぞれ呼び出します.コマンドを生成したら、processCommand()(server.cファイル)関数に渡して実行し、C_を返すとOKはクライアントをリセットし、次のコマンドを待ちます.C_を返すとERRでは、クライアントは破棄されます(例えばQUITコマンドを実行します).
プロセスCommand()関数は、Redis起動時にロードされたコマンドテーブルからコマンドを検索し、コマンドの実行権限を確認します.
clusterの場合、keyが現在のmasterに属しているかどうかを判断し、リダイレクト情報を返す必要はありません.
メモリが足りない場合は、ここでも解放できるメモリがあるかどうかを判断し、なければコマンドを実行できず、エラーメッセージを返す必要があります.
次に、書き込みコマンドを受信できない場合を判断します.
サブスクリプションモードでは、§SUBSCRIBE/§UNSUBSCRIBE/PING/QUITという指定されたコマンドしか受信できません.
slaveとmasterが接続されていない場合、flag「t」のコマンド、例えばINFO、SLAVEOFなどしか受信できません.
コマンドにCMDがない場合LOADINGフラグで、現在サーバーがデータをロードしている場合は、このコマンドを受信できません.
luaスクリプトの長さを制限します.
上記の様々な条件判断を行った後、call()関数実行コマンドの呼び出しを本格的に開始することができます.
コマンドを実行して戻る
call()関数のパラメータはclientタイプであり,cmdメンバーを取り出して実行する.
/* Call the command. */
dirty = server.dirty;
start = ustime();
c->cmd->proc(c);
duration = ustime()-start;
dirty = server.dirty-dirty;
if (dirty < 0) dirty = 0;
コマンドを書くと、サーバが「汚い」になります.つまり、サーバはメモリの一部のページに変更があることをマークする必要があります.これはRedisの永続化にとって非常に重要であり,このコマンドがどれだけのkeyに影響を及ぼすかを知ることができる.コマンドの実行が完了しても終了しません.call関数は他の操作も行います.例えばログを記録したり、AOFファイルを書いたり、ノードからコマンドを同期したりします.
戻り値については,各コマンドにそれぞれの処理方法があり,後述する.
ここでRedisが命令を処理する過程も完了する.
後で具体的なコマンドでこのプロセスをより明確に紹介します.