php-srcのコードリーディングした内容をコツコツ残すテスト。その17
opcache続き。コードを読む前にnikic大先生の記事を読むのが良さそう
https://www.npopov.com/2021/10/13/How-opcache-works.html
zend_なんちゃらの差し替え
main()
=> php_cli_startup()
=> php_module_startup()
=> zend_startup_extensions()
=> zend_llist_apply_with_del()
=> zend_extension_startup()
=> opcache.so!accel_startup()
という感じで accel_startup()
が呼ばれる
accel_startup()
では zend_post_startup_cb
に accel_post_startup()
をセットしている。
https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L3156:L3156
zend_post_startup_cb
は以下の経路で呼ばれる
main()
=> php_cli_startup()
=> php_module_startup()
=> zend_post_startup()
=> opcache.so!accel_post_startup()
https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend.c#L1045
zend_compile_file
zend_stream_open_function
zend_resolve_path
にそれぞれ、
persistent_compile_file
persistent_stream_open_function
persistent_zend_resolve_path
を設定
https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L3279-L3291
キャッシュの取得と保存
zend_compile_file
経由で persistent_compile_file()
が呼ばれキャッシュを検索する。
https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L2000-L2007
ZCSG(hash)
というのがファイル名から生成したキー => キャッシュの実態(oparrayとかclassやfunction tableなど) のハッシュテーブルになる(後述)
ファイルの場合はこの辺で判定
https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L1961-L1965
https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L2136-L2138
キャッシュがない場合 opcache_compile_file()
を呼び出す
https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L2160:L2160
opcache_compile_file()
は accelerator_orig_compile_file()
を呼び出し、元のzend_compile_fileでop_arrayを生成する。
https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L1789:L1789
その後 cache_script_in_shared_memory()
でキャッシュする
https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L2169:L2169
cache_script_in_shared_memory()
は zend_accel_script_persist()
を呼び出す
https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L1600:L1600
zend_accel_script_persist()
では共有メモリ内にopcacheを生成している。
例えば zend_shared_memdup_put()
などで共有メモリ内に領域を確保する。
https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/zend_persist.c#L525:L525
https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/zend_shared_alloc.c#L391-L393
zend_persistent_scriptはここで共有メモリ内に領域を確保している。
https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/zend_persist.c#L1289:L1289
ので大丈夫と思いきや、 zend_persistent_script 内のフィールドでポインタになっているデータの実体は共有メモリ内に確保されていないので、それらも共有メモリ内に入れる必要がある。
https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/zend_persist.c#L1315-L1322
scriptのfunction_table, class_table, main_op_arrayなど
https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L3202-L3211
shmgetでメモリ確保した領域に ZCSG(hash)
が存在する。
https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/shared_alloc_shm.c#L53-L125
https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/zend_shared_alloc.c#L127:L127
https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L2862:L2862
zend_accel_hash_update()
で &ZCSG(hash)
にキーがスクリプトの絶対パス、値に new_persistent_script
が格納される。
https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L1620:L1620
validate_timestamps
や revalidate_freq
の設定はこのあたりでチェックされる。opcacheのハッシュキーがヒットした場合でも条件が合致した場合は再度コンパイルされる。
https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L2092-L2108
last_usedやhitsはここで更新される。これによって opcache_get_status
を使ってopcacheの統計情報を取得できる
https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L2195:L2195
https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L2227:L2227
https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/zend_accelerator_module.c#L536-L564