この広告は30日以上更新がないブログに表示されております。
新規記事の投稿を行うことで、非表示にすることが可能です。
広告
posted by fanblog
2014年05月31日
サーバ方式ではないログの多重追記方式を考えてみる (2)
前回は LockFile の範囲が期待通りではなく、おかしい結果 (文字列がオーバーラップしていた) が得られていたが、実は、サイズ計算のミスであることがわかり、基本構造は正しかったことがわかった
前回の
の内容はそのままで、呼び出し部分でのサイズ計算を正しく実施したら、期待通り、重ならずに文字列を書き込めた
ただし、この方式は先着順ということであり、OSの制御によっては、後から書き込んだものが先に出力される可能性が残っているため、ログシステムとして考えると、ちょっと心もとない
(もちろん、後からタイムスタンプでソートすれば問題はないし、多くの場合では逆転することはなさそうだから、無視することも考えられる)
本格的に実装するなら、やはりFILOキュー方式が必要になり、そうした実装にするには、誰かがキューを制御しなくてはならない
ここでの目標は特定のサーバを設けないということなので、1つの案としては、最初に起動されたライブラリ実装が、キューを生成・管理するための仕組みを共有メモリに作成し、常に同時使用するプロセス・スレッド間で調停しながら進めるということになるのかもしれない
その雰囲気で実装できたら、ちょうど分散システムでのログ管理方式としても考えられそうだが、いかんせん、実装が Win32 に依存して (かつ、ファイルシステムAPIに依存) しているのでは、ちょっと汎用性がなさすぎだろうな
やはり、この実装が生きてくるのは、単一PC上での同一ログファイル競合くらいだという気がしてきた
前回の
void CWin32Logger::write(void* buffer, DWORD size)
の内容はそのままで、呼び出し部分でのサイズ計算を正しく実施したら、期待通り、重ならずに文字列を書き込めた
ただし、この方式は先着順ということであり、OSの制御によっては、後から書き込んだものが先に出力される可能性が残っているため、ログシステムとして考えると、ちょっと心もとない
(もちろん、後からタイムスタンプでソートすれば問題はないし、多くの場合では逆転することはなさそうだから、無視することも考えられる)
本格的に実装するなら、やはりFILOキュー方式が必要になり、そうした実装にするには、誰かがキューを制御しなくてはならない
ここでの目標は特定のサーバを設けないということなので、1つの案としては、最初に起動されたライブラリ実装が、キューを生成・管理するための仕組みを共有メモリに作成し、常に同時使用するプロセス・スレッド間で調停しながら進めるということになるのかもしれない
その雰囲気で実装できたら、ちょうど分散システムでのログ管理方式としても考えられそうだが、いかんせん、実装が Win32 に依存して (かつ、ファイルシステムAPIに依存) しているのでは、ちょっと汎用性がなさすぎだろうな
やはり、この実装が生きてくるのは、単一PC上での同一ログファイル競合くらいだという気がしてきた
2014年05月30日
サーバ方式ではないログの多重追記方式を考えてみる
同じログ出力ライブラリを使用していて、たまたま同じファイル名になる場合というのも、結構あったりする
こうした際、通常は先にログファイルをオープンしている方が排他的にファイルに書き込むことができえるわけだ
ところが、こうした方式の場合、同じファイル名だと、後から書こうとしていたプロセスのログが失われててしまう
度々非同期に呼ばれるコマンドが、同じログファイルを使用していると、こうしたことになってしまい、後から解析するのに困ってしまうわけだ
とりあえず、Win32 に限って考えてみると、 LockFile API が何となく使えそうな気がした
例えば次のようなインタフェースでログを書くとする
書き込み動作の最終インターフェースがこうした形式であれば、ファイルの最後の領域をロックして、そのロックした両機に指定サイズのデータを書き込めば、うまくいくのではないかと思えた
そこで、次のようなコードを考えてみた
一見これでうまく行きそうに見えたのだが、残念ながらうまくいかず、ファイルの書き込みがオーバーラップしてしまっていた
重なった領域はロックできないと思ったのだが、先頭部分のロック獲得ループがあっさりと抜けてしまい、前のプロセスの書き込み途中から上書きするようになってしまった
もう少し工夫しないといけなさそうだ
こうした際、通常は先にログファイルをオープンしている方が排他的にファイルに書き込むことができえるわけだ
ところが、こうした方式の場合、同じファイル名だと、後から書こうとしていたプロセスのログが失われててしまう
度々非同期に呼ばれるコマンドが、同じログファイルを使用していると、こうしたことになってしまい、後から解析するのに困ってしまうわけだ
とりあえず、Win32 に限って考えてみると、 LockFile API が何となく使えそうな気がした
例えば次のようなインタフェースでログを書くとする
void write(void* buffer, size);
書き込み動作の最終インターフェースがこうした形式であれば、ファイルの最後の領域をロックして、そのロックした両機に指定サイズのデータを書き込めば、うまくいくのではないかと思えた
そこで、次のようなコードを考えてみた
void CWin32Logger::write(void* buffer, DWORD size)
{
DWORD dwSize = GetFileSize(m_hFile, NULL);
while (!LockFile(m_hFile, dwSize, 0, size, 0)) {
Sleep(10);
dwSize = GetFileSize(m_hFile, NULL);
}
if (INVALID_SET_FILE_POINTER != SetFilePointer(m_hFile, 0, NULL, FILE_END)) {
DWORD sz;
if (WriteFile(m_hFile, buffer, size, &sz, NULL)) {
m_dwLoPos = dwSize + size;
FlushFileBuffers(m_hFile);
SetEndOfFile(m_hFile);
}
} else {
TCHAR msg[256] = {0};
wsprintf(msg, _T("%d\r\n"), GetLastError());
OutputDebugString(msg);
}
UnlockFile(m_hFile, dwSize, 0, size, 0);
}
一見これでうまく行きそうに見えたのだが、残念ながらうまくいかず、ファイルの書き込みがオーバーラップしてしまっていた
重なった領域はロックできないと思ったのだが、先頭部分のロック獲得ループがあっさりと抜けてしまい、前のプロセスの書き込み途中から上書きするようになってしまった
もう少し工夫しないといけなさそうだ
2014年05月29日
Shell_NotifyIcon がエラー 0 を返す
PC起動時に動き出すプログラムを開発しているが、通知エリア(昔はタスクトレイとも言っていた) にアイコンを登録するために Shell_NotifyIcon API を使用するが、PC起動時の忙しい時には、結構失敗していることがわかった
http://nyaruru.hatenablog.com/entry/20071008/p3 でも紹介されていたが、 API が FALSE を返したときに GetLastError() でエラーコードを取得すると、 ERROR_TIMEOUT (1460) が返ると説明されているが、自分のプログラムのログを調べると、ERROR_SUCCESS (0) が返ってきており、よくわからない状況となっている
実際上、想像するに、アプリケーション全体がハングアップするのを防ぐ目的で、タイムアウトしているというのが起きているのは間違いないだろうと思っているのだが、 Windows 7 になってからなのか、ERROR_SUCCESS が返ってきているのに違和感を覚えている
いずれにせよエラーには違いないのだろうから、リトライするなどの処置が必要とは思うが、アイコンの変更だけで何秒も待たさせるのも嫌な話だ
今のところは適当に5回程度リトライしてもだめなら、ログを出して無視するという対処にしてあるが、こういうのが解決することはあるのだろうか?
http://nyaruru.hatenablog.com/entry/20071008/p3 でも紹介されていたが、 API が FALSE を返したときに GetLastError() でエラーコードを取得すると、 ERROR_TIMEOUT (1460) が返ると説明されているが、自分のプログラムのログを調べると、ERROR_SUCCESS (0) が返ってきており、よくわからない状況となっている
実際上、想像するに、アプリケーション全体がハングアップするのを防ぐ目的で、タイムアウトしているというのが起きているのは間違いないだろうと思っているのだが、 Windows 7 になってからなのか、ERROR_SUCCESS が返ってきているのに違和感を覚えている
いずれにせよエラーには違いないのだろうから、リトライするなどの処置が必要とは思うが、アイコンの変更だけで何秒も待たさせるのも嫌な話だ
今のところは適当に5回程度リトライしてもだめなら、ログを出して無視するという対処にしてあるが、こういうのが解決することはあるのだろうか?
2014年05月26日
AWS での電話認証
AWS の Free Tier を試してみようとおもったが、電話認証で躓いてしまったという話
結局、電話認証用のページで、言語設定を日本語にし、電話をかけてもらったら解決した
※12時間も待たなくてよかった
ポイントは、待ち受け電話が携帯電話の場合に、キー入力を認識しない場合があるということ
特に自分の携帯電話はいわゆるガラケーなので、キー入力してもプッシュトーンが再生できていないよう
おそらくそれが原因でキー入力は認識しなかったのだろうと推測している
では、どうやったかというと、音声認識
数字を「日本語」で1文字づつ、ゆっくりと(1文字t1秒くらいからな?)発音したら、ちゃんと認識し、「認証されました」との案内が流れた
※言語設定を English にしたままだったら、英語で発音しなきゃだめだったんだろうな
結局、電話認証用のページで、言語設定を日本語にし、電話をかけてもらったら解決した
※12時間も待たなくてよかった
ポイントは、待ち受け電話が携帯電話の場合に、キー入力を認識しない場合があるということ
特に自分の携帯電話はいわゆるガラケーなので、キー入力してもプッシュトーンが再生できていないよう
おそらくそれが原因でキー入力は認識しなかったのだろうと推測している
では、どうやったかというと、音声認識
数字を「日本語」で1文字づつ、ゆっくりと(1文字t1秒くらいからな?)発音したら、ちゃんと認識し、「認証されました」との案内が流れた
※言語設定を English にしたままだったら、英語で発音しなきゃだめだったんだろうな
2014年05月24日
テスト用のサーバを準備したい
AWS 用の環境設定のために、サーバを準備したいということになった
AWS を直接申し込んだが、PIN 確認に規定回数以上失敗し、12時間待ちとなってしまった
12時間も遊んで待っているのもいやなので、手っ取り早く、いつも使っているサーバを準備しようかと思いった
AWS を直接申し込んだが、PIN 確認に規定回数以上失敗し、12時間待ちとなってしまった
ここの仕様もちょっと不親切だと感じた
この時、国番号もUSに初期化されてしまっているのを見落として、何度もリコールに失敗してしまい、もうリトライできない状況になってしまった
12時間も遊んで待っているのもいやなので、手っ取り早く、いつも使っているサーバを準備しようかと思いった
タグ: サーバ