モーグルとカバとパウダーの日記 このページをアンテナに追加 RSSフィード Twitter

モーグルやカバ(EXカービングスキー)、山スキー(BC)の山行記録などがメインの日記です。
いろんな条件のいろんなところを、その時々の条件にあった滑り方で楽しむ、フリースキーをして遊んでいます。

検索で来られた方は、上の検索窓から再度検索していただくか、右サイドバーのカテゴリーやトピックスの項目で絞り込んでみてください。
仕事柄、コンピュータ系のネタも多いので、スキー関連ネタだけ読みたい方は[ski]、コンピュータ関連ネタは[pc]、スパム関連ネタは[spam]で絞り込んでください。

2016-09-21 (Wed)

[][]Dropoutが効果的な理由についての疑問 Dropoutが効果的な理由についての疑問を含むブックマーク Dropoutが効果的な理由についての疑問のブックマークコメント

現在のDeep Neural Networkがうまく収束できるようになっていることにはDropoutの効果が大きいと言われている。

Dropoutはニューラルネットで中間層などの入力を50%の確率で落としてやることで、非常に強い正規化が行われるというものだ。


なぜDropoutが効果がそのような効果を持つのかについて、Hinton先生が書かれたスライドに記述があった。


2012年のDeep Learningについての解説スライド資料

52ページあたりからDropoutについての解説がある

IPAM Summer School 2012 Tutorial on Deep Learning


層の入力となるニューロンをランダムに半分を落とすことで、組み合わせを多数作ることが出来るから、非常に多数のニューラルネット平均値を得ることと同じ効果があり、それで性能が上がると説明されていた。



Hinton先生が書いてることに僕なんぞが疑問を抱くなんて、まったくもっておこがましいのだが、この説明はなんかどうもしっくりこなかった。

たしかに組み合わせは多数作れるけど、個々の元になってるニューロンは同じものが使われるのだから、非常に多くの回数学習を回すと、最終的に学習誤差を足し合わせた値を見たら全数が「生きて」いるときのものと同じになるんじゃないのだろうか。


「『みんなの意見』は案外正しい」というのがあったけど、あれは「多様な」「独立した」結果が集まるから正しくなるという前提があり、その前提が崩れていると機能しない。

ほんとうに同様の効果を狙うのならば、それと同じ前提が必要なのではないか。

ただ、ニューロンの重みが完全にシェアされた多数のニューラルネットワークだから強い正規化が行われる、と書いてあるから、逆に独立していないからこそ効果が得られるのだとすると、さらによくわからない。


Dropoutが効果がないとは全く思って無くて、間違いなく大きな効果が得られているはずだが、理由として挙げられている、多数のニューラルネット平均値を取ったのと同じこと、という説明が別の理由があるのではないかと。


Dropoutにより超平面に「ゆれ」が起こるから、ローカルミニマムから脱出しやすいとか、そういうのかなあと思ったんだけど、なんの根拠もないのにそんな適当なこと書いてごめんなさいごめんなさい。


上記の疑問に対し、良い説明があるページや論文がありましたら教えてください。

トラックバック - http://d.hatena.ne.jp/stealthinu/20160921

2016-09-02 (Fri)

[]MySQLの接続最大数に達した時にどのクエリの問題か確認する MySQLの接続最大数に達した時にどのクエリの問題か確認するを含むブックマーク MySQLの接続最大数に達した時にどのクエリの問題か確認するのブックマークコメント

MySQL障害時にprocesslistを表示したいが、接続クライアント数最大に達していて入れず、セッション消費してるはずのアプリデーモン止めてもクライアント数減らないような場合があると思います。

このような場合に、Javaスレッドダンプ的に外から状況を吐かせたい、と思うことってありますよね。


んでそんなことをtwitterで嘆いていたら、とみたさんから

のように教えていただきました。


なんと、なにもしなくてもMySQLrootアカウントなら1接続だけ入れるとのこと!


MySQL :: MySQL 5.6 リファレンスマニュアル :: B.5.2.7 接続が多すぎます

mysqld は実際には max_connections+1 クライアントの接続を許可します。余分な接続は、SUPER 権限を持つアカウントが使用するために予約されています。SUPER 権限を管理者に付与して、通常のユーザー (その権限の必要のないユーザー) に付与しないことによって、権限のないクライアントが最大数接続されていても、管理者はサーバーに接続して SHOW PROCESSLIST を使用し、問題を診断することができます。


まさにやりたかったことをやるために用意されている心づかいでした。


ちなみにflatさんからPostgreSQLにも同様の仕組みがあることを教えていただきました。

接続と認証

superuser_reserved_connections

PostgreSQLのスーパユーザによる接続のために予約されている接続


次、同じ障害出たらこれで processlist 取れるぞ!

トラックバック - http://d.hatena.ne.jp/stealthinu/20160902

2016-08-31 (Wed)

[]mod_rewriteURL末尾に付いた「?」を取る mod_rewriteでURL末尾に付いた「?」を取るを含むブックマーク mod_rewriteでURL末尾に付いた「?」を取るのブックマークコメント

アクセスされたURLが例えば「http://example.jp/foo/?」のように「?」だけで他のクエリパラメータがついていない場合にだけ、mod_rewriteで「http://example.jp/foo/」に直したいという要望がありました。

このURLクエリが渡される場合があるため、単にクエリを全部消す、というだけでは満たされない条件です。


RewriteRuleがマッチングする文字列にはクエリ文字列が含まれないため単純に

RewriteRule (.*/)\?$ $1 [L,R]

のように末尾の「/?」とマッチさせるように書いても、「/foo/」のように末尾の「?」がないものと比較されてしまうのでマッチしません。

REQUEST_URIやREQUEST_FILENAMEにもクエリ文字列は含まれていないため、検知できません。


じゃあとQUERY_STRINGと比較しても、QUERY_STRINGは「?」以降の文字列になるため、QUERY_STRINGが空というだけでは「?」が有って空なのか、無くて空なのかがわからないのです。


ということで、REQUEST_URIQUERY_STRINGが分割されていないものはないか、と探したところ「THE_REQUEST」に

GET /index.html HTTP/1.1

のように入っていることがわかりました。

mod_rewrite - Apache HTTP Server Version 2.4


そこでTHE_REQUESTに対して下記のような条件で引っ掛ければ検出できることがわかりました。

RewriteCond %{THE_REQUEST} " .*/\? "

が、この条件で引っ掛けてREQUEST_URIに対してリダイレクトさせると、勝手にクエリ文字列を追加してくれてしまうため、結局「?」が追加されてしまい元の木阿弥に…


そこでクエリ文字列を引き継がない設定を探すと

mod_rewriteでクエリ文字列(/?q=)を引き継がずにURL置換 | ええかげんブログ(本店)

クエリ文字列を削除するには「置換文字列の最後をクエスチョンマークにする」

とすれば良いとのことでした。


これだとクエリがついていてもすべて削除されてしまうのですが、末尾が「?」で終わっている条件だからクエリは空なので、クエリ文字列自体を消してしまって大丈夫です。

なので、次のようなルールで動くようになりました。

RewriteCond %{THE_REQUEST} " .*/\? "
RewriteRule .* %{REQUEST_URI}? [L,R]

んで、これをtwitterで相談していたところ、ふみやすさんから

と教えていただきました。ありがたや!!

リダイレクトは正しくはフルで書いてないとダメなのですね。


ということで最終的には

RewriteCond %{THE_REQUEST} "/\? " 
RewriteRule .* http://%{HTTP_HOST}%{REQUEST_URI}? [redirect=301,last]

という形になりました。


しかし… 単にURL末尾の「?」消したいだけなのに、だいぶバッドノウハウ感の高いルールとなってしまいました。

なんかもそっと簡単に書ける方法はないもんなんでしょうかね。


(参照)

mod_rewriteの考え方。 - こせきの技術日記

Apacheのmod_rewriteモジュールの使い方を徹底的に解説 | OXY NOTES

mod_rewrite - Apache HTTP Server Version 2.4

mod_rewriteでクエリ文字列(/?q=)を引き継がずにURL置換 | ええかげんブログ(本店)

トラックバック - http://d.hatena.ne.jp/stealthinu/20160831

2016-06-23 (Thu)

[]Docker for Windowsオープンベータインストールと問題点 Docker for Windowsオープンベータのインストールと問題点を含むブックマーク Docker for Windowsオープンベータのインストールと問題点のブックマークコメント

先日6/21ごろから、Docker for Windows がオープンベータになったので早速試してみました。


Announcing the Docker for Mac and Windows Public Beta | Docker Blog

https://blog.docker.com/2016/06/docker-mac-windows-public-beta/


下記ページから Docker for Windowsインストーラを利用してインストールします。

バージョンは「DOCKER 1.12.0-RC2-BETA16」でした。


Getting Started with Docker for Windows

https://docs.docker.com/docker-for-windows/


Docker for WindowsWindows 10 64bitとHyper-Vが必須要件となっています。

Hyper-Vは「プログラムと機能」→「Windowsの機能」→「Hyper-V」から入れることが出来ます。

自分のWindows10Hyper-Vが入っていない状態でしたが、入っていないとインストーラが入れるか聞いてきて、入れてくれました。


また、事前にDocker Toolboxが入っていると動かないようです。

自分はこれで最初動かなくてはまったのですが、アンインストールしたら動くようになりました。


このページの書いてある例のように

$ docker run -d -p 80:80 --name webserver nginx

でnginxを起動してブラウザで「http://docker」を表示したところ、無事にページが見えることを確認出来ました。

コンテナの起動は非常に早く、コンテナイメージがローカルにあれば2秒程度で起動してくれました。これはほんとに手軽でよいです。


$ docker ps

で、現在起動しているコンテナを確認することが出来ます。


docker exec -it 【コンテナID】 bash

で、そのコンテナに入って操作や確認することが出来ます。


Docker ハンズオン - 基本コマンド編 - Qiita

http://qiita.com/hihihiroro/items/6dda871dc2566801a6da


が、次の日に同様に使おうと思ったところ、dockerがちゃんと立ち上がっていないことに気が付きました。

Docker for Windowsが起動していると、タスクバーのインジケータに白い鯨のアイコンが出ているのですが、うまく立ち上がっていない時は赤い鯨になっています。

赤い鯨にマウスを持って行くと「'MobyLinuxVM' failed to start.」と出ていました。


下記ページによるとWindows Updateの「KB3163018」が悪影響を及ぼしてるようで、これをアンインストールするとうまくいったという話や、ベータ16だと解決された、「KB3163018」が入っていてベータ16ではHyper-Vを再度入れなおすとうまくいくのでは、という話が出ていました。


'MobyLinuxVM' failed to start - Docker for Windows - Docker Forums

https://forums.docker.com/t/mobylinuxvm-failed-to-start/15175


自分が試した限り、ベータ16でHyper-Vを入れなおしても、再起動するとやはりこの状況になってしまい、改善しませんでした。

「KB3163018」のアンインストールは試していません。


ただ、dockerの設定ウィンドウからRestartを掛けると動くことがわかりました。

PC起動時に同時起動する場合だと、うまく動かないのかもしれません。


この状態だとMobyLinuxVMが動いているため、すでにローカルにイメージがあるdockerコンテナを立ち上げることは出来ました。

しかし、新しいdockerイメージを持ってくるような操作をすると「Network timed out while trying to connect」というエラーが出て使えない状況でした。

ネットワークが使えなくなっているのか、ca-certの鍵が古いのか、というあたりが考えられましたが、解決方法がわかりませんでした。


とりあえずこの時点であきらめて、今まで使っていたvagrantを立ち上げようとしたところ、今度は「Intel VT-xが見つからない」というようなエラーが出て、vagrantが動かなくなってることに気が付きました。

下記ページによると、どうもHyper-Vを入れるとVirtualBoxが動かなくなるようです。


Windows 10Hyper-VOracle VirtualBox v5.0.0 は両立できない !? – アプリ徹底紹介

http://app-review.poox.xyz/archives/1449


というわけで、もう少しDocker for Windowsが安定して使えるようになるまで様子見することにしました。

まずHyper-Vを「プログラムと機能」→「Windowsの機能」→「Hyper-V」からHyper-Vを外し、Docker for Windowsアンインストールしました。


こうやれば現バージョンのDocker for Windowsも問題なく使えるよ、というのをご存知でしたら、試してみたいので教えて下さい。

2016-06-09 (Thu)

[]ConEmuでMSYS2のbash上でvagrant sshした時に画面が崩れる件 ConEmuでMSYS2のbash上でvagrant sshした時に画面が崩れる件を含むブックマーク ConEmuでMSYS2のbash上でvagrant sshした時に画面が崩れる件のブックマークコメント

ターミナルとしてConEmuを使っていて、そこからMSYS2のbashzshbash.exe --login のようにして呼び出して使っていました。

で、そこからvagrantを動かしているのですが、vagrant sshして入った先のemacsが画面が崩れて使えない、みたいなことが起きていました。


で調べてみるとConEmu+MSYS2のbashzshで入る設定でTERMを確認すると

TERM=xterm-256color

になっており、これだと崩れてしまうことがわかりました。


ただ、ConEmu+Powershell等の環境から呼び出すと大丈夫であったため、確認すると

TERM=cygwin

となっており、TERMを「cygwin」等に指定にすれば良いということがわかりました。


そこでConEmu+MSYS2 bashを立ち上げた後

export TERM=cygwin

としてやってからemacs動かせば問題がないことを確認しました。


ただ、普通にスタートメニューからMSYS2のターミナルを開くとTERMが「xterm-256color」でも問題なく動くため、ConEmu+MSYS2の場合だと問題が起きるようです。


でそれについてさらに調べていると、


ConEmuからMSYS2のシェルを起動したときに256色対応させる - 水を見ると釣りがしたくなる

http://e8l.hatenablog.com/entry/2016/03/24/161206

MSYS2のシェルからansi color codeを上手にConEmuの方へ引き渡すコネクタプログラムを噛ませる必要がある


ConEmu | cygwin/msys terminal connector

https://conemu.github.io/en/CygwinMsysConnector.html

set MSYSTEM=MINGW64 & c:\tools\msys64\usr\bin\bash.exe --login -i

Change it to:

set MSYSTEM=MINGW64 & conemu-msys2-64.exe


ということで、コネクタプログラム経由にしないとxterm-256colorでの表示はうまくいかないそうです。

試してみると確かにこれでうまく動いてくれました。

ただ、そうするとzshではなくbashになってしまうのですよね。これはなにか方法あるのかな?


また、ConEmuのヘルプに起動時にTERMの指定が出来る記述

chcp 1251 & set TERM=MSYS & cmd

があったため、これでTERMの指定をcygwinにしてzshを動かせそうに思ったのですが、自分が試して見た限りではこれは動きませんでした。


で、この問題について色々と探しているときに、shellは「Nyagos」が良いというのをちょこちょこ見かけました。


Windowsターミナル環境にCmderを使う 〜Nyagosとmsys2を添えて〜 - 長文書くところ

http://zenito9970.hatenablog.com/entry/2015/06/19/163701


このエントリではCmder+Nyagos+MSYS2ですが、自分の場合はConEmu+Nyagos+MSYS2で使ってみました。

こちらのコメントにもあるようにChocolateyでインストールできるので簡単に入ります。

確かにNyagos良い感じで、TERMもcygwinになるためそのままvagrant sshしても表示が崩れる問題は起きませんでした。


というわけでまとめると

  • ConEmu + MSYS2 bash + vagrant ssh で崩れるのは TERM が「xterm-256color」になってるため
  • MSYS2 bashかvagrant中でTERMを「cygwin」などにすれば崩れなくなる
  • でもシェルをNyagosにしちゃったほうが快適

という感じでした。


(関連)

WindowsターミナルアプリConEmuのフォント設定 - モーグルとカバとパウダーの日記

http://d.hatena.ne.jp/stealthinu/20130527/p1

トラックバック - http://d.hatena.ne.jp/stealthinu/20160609

2016-05-26 (Thu)

[]revealjsで作ったプレゼン資料をphantomjsを利用してPDFrevealjsで作ったプレゼン資料をphantomjsを利用してPDF化を含むブックマーク revealjsで作ったプレゼン資料をphantomjsを利用してPDF化のブックマークコメント

こないだの勉強会で作った資料は、MarkDownで書いたものをrevealjsを使ってスライド化していました。


それだとSlideShareに載せれないのでrevealjsのPDF出力機能を使ってPDF化しました。

revealjsではプレゼンURLの後ろに「?print-pdf」と付けると、PDF出力用のページを表示してくれるので、それをブラウザのプリント機能からPDF出力させてやればPDF化することが出来ます。

ただ、それだと手でオペレートする必要があって、自動化出来ないのがちょっとイヤな感じでありました。


そしたら勉強会の時に @ktz_alias さんから、phantomjsを使うと自動化出来るよ!というナイス情報を教えていただきました。

結果的にはばっちり動いたのですが、画面サイズ指定などでちょこちょことハマったので使い方の説明を書きたいと思います。


phantomjsをインストールするためにnpmを使います。

自分はWindows環境なのですが、久しぶりにnpmを使おうとしたらなにやらエラーがでて、結局npmというかnode環境自体を入れ直すはめになりましたので、node環境を入れるところから説明します。

今、Windowsでnodeを入れるには、nodeのバージョン管理ツールであるnodistを入れて、そこから入れるのがお薦めのようです。


marcelklehr/nodist: Natural node.js and io.js version manager for windows.


ここからインストーラーをダウンロードしてインストールします。今だと0.7.2が入るはず。

% nodist -v
0.7.2

現在の安定版nodeを入れます。

% nodist stable
nodev6.2.0

これでnodeもnpmも入ります。

% node -v 
v6.2.0

% npm -v  
3.5.2

やっと本題のphantomjsを入れます。

すでにnode環境できてる方はここから。

% npm install -g phantomjs

なんかたくさんメッセージが出て、かつ途中でTypeErrorとかエラーが出るのですが、なんとか入ります。


次に、作ったプレゼン資料のrevealjsのディレクトリパスとそれを表示できるURLを調べます。

例えばパスと表示できるURL

だったとします。


revealjsのpluginの中にphantomjsで出力するための「print-pdf.js」というJSがおまけで入っているので、それを使うとコマンドラインからすぐPDFが吐けるようになっています。

「print-pdf.js」はパラメータとして、PDF用の表示URL、出力ファイル名、あとオプションで画面サイズを「480x350」のようにして渡すことが出来ます。

ただこの画面サイズがくせ者で、実際のサイズはこの2倍になります

デフォルトでは「960x700」となっており、すると画面サイズが「1920x1400」となるのでたぶん大きすぎるでしょう。

なので「480x350」と指定すると「960x700」のサイズになります。たぶんこれがちょうどいいと思います。

表示URLPDF出力用のURLにする必要があるので「?print-pdf」を追加してやります。するとコマンドに「?」が含まれてしまうことになるためURLはダブルクォートで括る必要があります


というわけでまとめると下記のようなコマンドでrevealjsで作ったプレゼン資料をPDFにすることができます。

% phantomjs C:/Users/hoge/Dropbox/Public/exampleslide/reveal.js/plugin/print-pdf/print-pdf.js \
 "https://dl.dropboxusercontent.com/u/99999999/exampleslide/index.html?print-pdf" \
 exampleslide.pdf 480x350
トラックバック - http://d.hatena.ne.jp/stealthinu/20160526

2016-05-24 (Tue)

[][]ニューロンになってみる ニューロンになってみるを含むブックマーク ニューロンになってみるのブックマークコメント

LIGさん主催の勉強会「づや会」の機械学習の回で『ニューロンになってみる』という題でLTをさせていただきました。


づや会 vol5 「機械学習の話」 - connpass

http://lig.connpass.com/event/30420/



ニューロンになってみる(reveal.js版)

https://dl.dropboxusercontent.com/u/4412680/zuyaneuro/handneuro.html


ディープラーニングとかニューラルネットワークがどうやって学習をするのか、数式で説明されてると、数式の意味するところがいまいちわからないという時があると思うんですが、実際にどんなアルゴリズムで動いているのかがわかると、以外に簡単なことを意味していたりします。

ニューロは元々生物の脳細胞の動きを元にしているので、一個一個のニューロの動きは実は単純だったりします。

そこで手で実際にニューロの動きをやってみて、ニューロがどうやって学習するのかを学習しよう、というわけです。


これ、『マッチ箱の脳』という本が元ネタで、そこではマッチ箱とマッチを使って、ニューロンのやってる学習をやっています。

ただ、勉強会でやるには準備が大変なので、紙とえんぴつかExcel上とかでやることを考えてそのフォーマットを作ってみました。


ただ、実際のLTでは時間が全然足らず、結局実際にやってみてもらうだけの時間が取れなくて、説明だけで終わってしまいうまくいきませんでした。

次回、NSEGとかでリベンジ出来たらなと思っています。

トラックバック - http://d.hatena.ne.jp/stealthinu/20160524

2016-04-22 (Fri)

[]NetCommons2で大きなサイズの画像アップロードに失敗する理由 NetCommons2で大きなサイズの画像アップロードに失敗する理由を含むブックマーク NetCommons2で大きなサイズの画像アップロードに失敗する理由のブックマークコメント

NetCommonsというCMSがあり、そこで画像ファイルアップロードするとある程度のサイズの画像なら問題ないが、大きなサイズの画像だとアップロードに失敗する、という問題が起きました。


メモリやアップロードファイルサイズの設定はすでにphp.iniでされており、phpinfo()で確認してみてもちゃんと設定が通っている状況でした。


しかしデバッガで追ってみると、携帯用のサムネイルを作るためにimagecreatefromjpegというGD関数を使うところで落ちてしまい、どうやらメモリが足らない状況でした。

どうやら、というのはここで落ちるとエラーを吐かずに死ぬので、メモリ不足のせいで死んだのかどうかをエラーログからは確認できないためです。


ちなみに、imagecreatefromjpegすると、ファイルサイズに関係なく画像のサイズx4byte分のメモリを必要とするらしく、例えば4000x3000pixの画像をアップロードするとそれだけで48Mのメモリが消費されることになります。


で、ぐぐってみると似たようなことで困っている人はいるようなのですが、どうもphp.iniではなく「ini_set」でやると大丈夫、という話がありました。ほんとに??


PHP GD Allowed memory size exhausted - Stack Overflow

http://stackoverflow.com/questions/2827908/php-gd-allowed-memory-size-exhausted


そこで、imagecreatefromjpegを呼ぶ前で「ini_set('memory_limit', '512M')」として試したところ、ちゃんと動くことがわかりました。


そうなると今度はなんでphp.iniで設定した値が使われないんだろう??という疑問がわくわけですが、その理由は実はCMS側の設定でした。


NetCommonsには

「システム管理」→「サーバ設定」→「PHP最大メモリ数」

という項目があり、ここでPHPの最大メモリ数設定が出来るとなっているのですが、どうやらここで設定した値でmemory_limitが設定されてしまうように書かれているようです。

ここに512M等設定すると、大きな画像アップロードでも落ちないようになりました。

トラックバック - http://d.hatena.ne.jp/stealthinu/20160422

2016-03-22 (Tue)

[][]CakePHP2.7以降はPHP5.2では動かない CakePHP2.7以降はPHP5.2では動かないを含むブックマーク CakePHP2.7以降はPHP5.2では動かないのブックマークコメント

今さらながらPHP5.2の環境で動くシステムを作らなければならなくて、でもまあCakePHP2系はPHP5.2対応だから大丈夫だよね、と思って作ってたのです。


が… 本番環境で動かしてみたら下記のようなエラーが出てはまりました。

PHP Parse error: syntax error, unexpected T_STATIC, expecting T_STRING or T_VARIABLE or …


実はCakePHP2.7以降だとPHP5.3以降対応になっているとのこと。

2.7 移行ガイド — CakePHP Cookbook 2.x ドキュメント

http://book.cakephp.org/2.0/ja/appendices/2-7-migration-guide.html

CakePHP 2.7 で必要な PHP バージョンは、 PHP 5.3.0 に引き上げられました。


CakePHP3系はPHP5.2では動かないことを確認していたのでCakePHP2系を選択したのですが、2.6と2.7でPHPの対応バージョンに違いが出てきてしまうのでした。

インストールCakePHP Cookbook 3.x ドキュメント

http://book.cakephp.org/3.0/ja/installation.html

システム要件

PHP 5.5.9 以上


また、DebugKitでもエラーが出たのでこれも調べてみると2013年7月時点ですらPHP5.3以降となっているそうでした。

PHP5.3以上のときだけDebugKitを読み込む - mikage014の日記

http://d.hatena.ne.jp/mikage014/20130704/1372895705

DebugKitのmasterブランチは2013年7月時点で

となっています。


ちなみにcomposerも対応バージョンは

Introduction - Composer

https://getcomposer.org/doc/00-intro.md

Composer requires PHP 5.3.2+

となっており使えません。

…のに使ってしまっていました。こっちはちゃんと確認すりゃわかることだったのに…


ということで自分のチェックミスが問題でした。

もう2016年時点で今さらPHP5.2環境で新規開発する案件なんてなかなかなかろうとは思いますが、つい普通の環境での開発と同じ感覚で環境構築してしまうとはまるということで。

トラックバック - http://d.hatena.ne.jp/stealthinu/20160322

2016-03-10 (Thu)

[]Vagrantの共有フォルダをapacheの公開ディレクトリにしていると更新が反映されない問題 Vagrantの共有フォルダをapacheの公開ディレクトリにしていると更新が反映されない問題を含むブックマーク Vagrantの共有フォルダをapacheの公開ディレクトリにしていると更新が反映されない問題のブックマークコメント

今、WindowsCakePHPの開発を行っているのですが、Vagrant上にCentOSを入れ、共有フォルダ /vagrant 以下にディレクトリを作ってそこにCakePHPを入れ、apacheの設定でそこをDocumentRootにして使っています。

開発はWindows上のNetBeansで直接共有フォルダのソースを編集するようにしています。

これだとWindows上のXAMPP使ってるのと同じような感じに開発が進められます。


さてその環境で、Javascriptのファイルを編集しても編集が反映されない、一度ファイル名を変更して、再度ファイル名を戻すとちゃんと動くんだけど… というような相談を受けました。

最初、CakePHPキャッシュブラウザキャッシュを疑ったのですが、Cake関係ないファイルでテストしても同様の状況が再現できて違うことがわかりました。

しかも色々とテストしてみると、単に修正が反映されない時ばかりではなく、なんか過去に修正した時の内容が出てきたり、一部欠けたものが出てくることがあったりと、不安定な動作をすることがあることがわかりました。


そこで今度はApache自身のキャッシュを疑ったのですが、Apacheにそんな機構あったっけ?と思ったのと、あと他ではこういうの経験したことが無かったから、Vagrantの共有フォルダがらみなんだろうなあ、と考えました。

そこで「vagrant 共有フォルダ apache」でぐぐったところすぐに答えがわかりました。


Vagrantの共有フォルダをDocumentRootに設定した場合にファイルの変更が反映されない | trapon : experience

Virtualbox上のApacheでホストマシンと共有している静的ファイル(CSSなど)の更新が検知されない問題を解決する方法 | tipshare.info


VirtualboxやVagrantではそこそこメジャーなトラブルっぽいです。

結局、共有フォルダはNFSとかと同じような機構なので、EnableMMAPとEnableSendfileが効いているとうまく動かないことが起こるそうです。


/etc/httpd/conf/httpd.confのデフォルト設定ファイルにもこの2項目の記述がありコメントになっているため、そこを外してやるか、無ければ下記のようにoffの記述を追加してやります。

EnableMMAP off
EnableSendfile off

これだけで無事に解決できました。


ただ自分の例のように、途中にキャッシュサーバフレームワークを利用している場合、どこのキャッシュのせいでこの問題が起こっているのか、がわかるまでに結構時間がかかるのではないかと思います。


(追記)

さとうふみやすさんより下記のように情報をいただきました。


VirtualBox の shared folder で sendfile(2) がバグってるやつを調べた - hibomaのはてなダイアリー

Nginx や Apache で sendfile(2) サポートを有効にしていると VirtualBox の shared folder ( /vagrant ) のファイルを ホストOS側からで更新しても反映されないバグが知られています。

・generic_file_splice_read はファイルが書き換えられているかどうかを確認しない

・ホストOSでファイルが更新されていても generic_file_splice_read は知らず知らず 古いページキャッシュを返してしまう

という問題

VirtualBoxのvboxsfに問題があるようで、根本解決できる道はありそうなんですが、未だにパッチされてないからなかなか難しそうなのか。

トラックバック - http://d.hatena.ne.jp/stealthinu/20160310