こんにちは。CTOの馬場です。
できるようになった、というのは見たものの、 具体的にどのように実現しているのか気になったので調べてみました。
こういうの、気になりません?わたしは気になります。
最近はコードの追い方の紹介をあまり見ないので、探し方を含めて紹介します。
なお30代後半以降の方にはお馴染みの、
find ... | xargs grep
を使っていますが、
GitHubの検索機能でも代替可能です。
5秒でわかる結論
- LeakyBucketです
- aws-cliではなくbotoで実装されています
コードの追い方
ここからは地道に追ってみます。 読むだけだと何がなんだか...だと思うので、 操作したりリンクに飛んだりしながら試してみてください。
※jediやVSCodeで定義にジャンプできる環境がある場合はインストールしてジャンプしていけばもっと楽に追えると思います
下準備
まずはawscliのソースコードを落としてきます。
❯❯ ~/Documents/project/github.com/aws
❯ git clone git@github.com:aws/aws-cli.git
...
❯❯ ~/Documents/project/github.com/aws
❯ cd aws-cli
❯❯ (git:develop) ~/Documents/project/github.com/aws/aws-cli
❯ git checkout 1.14.39
...
とっかかり
設定項目が s3.max_bandwidth
なので、
aws-cliのリポジトリで max_bandwidth
を探します。
❯❯ (git:1.14.39) ~/Documents/project/github.com/aws/aws-cli
❯ find awscli -type f -name "*.py" | xargs grep -Hnw max_bandwidth
awscli/customizations/s3/transferconfig.py:25: 'max_bandwidth': None
awscli/customizations/s3/transferconfig.py:37: 'max_bandwidth']
awscli/customizations/s3/transferconfig.py:39: HUMAN_READABLE_RATES = ['max_bandwidth']
awscli/customizations/s3/transferconfig.py:112: 'max_bandwidth': 'max_bandwidth',
create_transfer_config_from_runtime_config
内で
TransferConfig
を生成する際に利用されているようです。
呼び出し元を探す
この create_transfer_config_from_runtime_config
を呼んでいるのはどこでしょう?
❯❯ (git:1.14.39) ~/Documents/project/github.com/aws/aws-cli
❯ find awscli -type f -name "*.py" | xargs grep -Hnw create_transfer_config_from_runtime_config
awscli/customizations/s3/s3handler.py:22: create_transfer_config_from_runtime_config
awscli/customizations/s3/s3handler.py:83: transfer_config = create_transfer_config_from_runtime_config(
awscli/customizations/s3/transferconfig.py:97:def create_transfer_config_from_runtime_config(runtime_config):
transferconfig.py
は先程のものなので、 s3handler.py
があたりです。
ここでは transfer_config
を生成しているようです。
この生成された transfer_config
は TransferManager
で利用されます。
定義元を探す
TransferManager
とは何でしょう?
from s3transfer.manager import TransferManager
を見ると s3transfer
配下です。
awscli
ではなく外部ライブラリのようです。
外部ライブラリを探す
依存している外部パッケージはsetup.py
に記載しておくことでインストール時にpipにて解決されます。
setup.py
を見てみましょう。
s3transfer
というそのままの名前のパッケージがありました。
PyPIを探す
外部パッケージはPyPIにあるので、そこでs3transfer
を探します。
https://pypi.python.org/pypi/s3transfer/
Home Page: https://github.com/boto/s3transfer
https://github.com/boto/s3transfer にコードがあるようです。
外部ライブラリの定義元を探す
boto/s3transferのリポジトリを見てみましょう。
❯❯ ~/Documents/project/github.com/boto
❯ git clone git@github.com:boto/s3transfer.git
...
❯❯ ~/Documents/project/github.com/boto
❯ cd s3transfer
❯❯ (git:develop) ~/Documents/project/github.com/boto/s3transfer
❯ git checkout 0.1.13
...
❯❯ (git:0.1.13) ~/Documents/project/github.com/boto/s3transfer
❯ grep -n TransferManager s3transfer/manager.py
69: processing a call to a TransferManager method. Processing a
84: TransferManager method calls that can be queued at a time. A value
156:class TransferManager(object):
535: """Shutdown the TransferManager
TransferManager
の定義がありました。
処理を追う
コンストラクタの中でmax_bandwidth
を含むtransfer_config
(だったもの)が self._config
として保持されています。
コンストラクタを下に読み進めると、なんと max_bandwidth
が利用されています。
leaky_bucket = LeakyBucket(self._config.max_bandwidth)
self._bandwidth_limiter = BandwidthLimiter(leaky_bucket)
これっぽい
帯域などの制限でよくある leaky bucket (水漏れバケツ) 方式のようですね。 めでたしめでたし。
さらに深追いするなら
あとはコードを読んで定義にジャンプしていけば大丈夫です。 このような流れで追っていく形になると思います。
- https://github.com/boto/s3transfer/blob/0.1.13/s3transfer/bandwidth.py#L92-L94
- https://github.com/boto/s3transfer/blob/0.1.13/s3transfer/bandwidth.py#L138-L156
- https://github.com/boto/s3transfer/blob/0.1.13/s3transfer/bandwidth.py#L158-L173
- https://github.com/boto/s3transfer/blob/0.1.13/s3transfer/bandwidth.py#L237-L264
さらにさらに深追いするにはこのあたりを読むことになると思います。
- https://github.com/boto/s3transfer/blob/0.1.13/s3transfer/bandwidth.py#L288
- https://github.com/boto/s3transfer/blob/0.1.13/s3transfer/bandwidth.py#L341
まとめ
単にユーザとして使ってるだけだと仕組みも何もわからなくて不安ですよね? せっかくコードが公開されているので、活用してきちんと自分の掌に収めていきましょう。