2018/05/26

[c/c++]socketのshutdown()だけでは足りない

socketを使った、サーバっぽいアプリを作っている。

長時間動かしていると、なんか調子が悪い・・・。
メモリの使用量なんかも問題ないし、負荷が高いわけでもない。

なんとなくnetstatで見てみると、大量のFIN_WAIT2が残っていた。
なんだこれは・・・。


原因は、shutdown()だけしかしていないせいだったようだ。
close()したら、解決したようである。


い、言い訳をさせてください!


システムコールの本を読んでいて、shutdown()のところで「close()やプロセス終了でも閉じられるので、shutdown()を省略することもあります」みたいな説明が書いてあったのだ(手元に本がないので、私の記憶では、だが)。

そこを、何を勘違いしたのか「じゃあ、close()を書かずにshutdown()でもいいんだ」と解釈したのである。
冷静に考えれば、close()だけすればいいやん、と思いそうなのだが、そのときの私の心理を解説できるものはどこにもいない。。。



その前も、cURLでcurl_easy_init()とcurl_easy_cleanup()を繰り返していたら、TIME_WAITが大量に残るという現象を味わったばかりだった。
そのときは、接続先が1つしかなかったので、最初にinitしてハンドルをもらってきて、ずっと使い回すことで対応できたようだ。
サイトにも「You can do any amount of calls to curl_easy_perform while using the same easy_handle.」と書いているし、そのやり方でいいんだろうと思っている。

しかし、毎回異なるところへ接続するようだったら、また別のやり方を考えねばならんだろう。


socket関連って、原因に思い当たるノウハウがないと、なかなかつらいですな。

2018/05/20

[git]ブランチを消すとcommit履歴も消える

以前、gitでちまちまcommitするので、Pull Requestしてマージするときにまとめたい話をした。

http://hiro99ma.blogspot.com/2018/05/git-merge-squash.html


merge --squashするときれいになったので、こりゃいいや、と使っていた。

それはよかったのだが、てっきりこう思っていたのだ。

Pull Request用に作ったブランチにcommitがまとまっただけで、ローカルにはcommit履歴が残っている

しかし、ひさびさにcommit履歴を見てみると、squashでまとめたものしか残っていない。。。
あれ、commitの履歴って、全部残っているものではないの??


わからないときは、実験だ。


$ git init
$ touch test.txt
$ git add test.txt
$ git commit -m "first"
$ git checkout -b work/aaa
$ (test.txtを編集)
$ git commit -a -m "hello"
$ (test.txtを編集)
$ git commit -a -m "world"
$ (test.txtを編集)
$ git commit -a -m "morning"

image

$ git checkout master
$ git checkout -b aaa
$ git merge --squash work/aaa
$ git commit -m "squash merge"

image

$ git branch -D work/aaa

image


ああ、消えた!!!


$ git checkout master
$ git merge aaa
$ git branch -d aaa

image


むう、ブランチaaaがあったことすらわからないのか。
reflogには残っているけど、手元に残っているだけだろう。

image


fast-forwardだったから、ログに残っていないのだろうか?


fast-forwardを無効にしてやってみよう。

$ git config merge.ff false
(同じ手順でやっていく)
$ git merge --squash work/aaa
fatal: You cannot combine --squash with --no-ff.

ダメやん。

$ git merge --ff --squash work/aaa

これならできたけど・・・branchを消すと当然同じ結果になった。



そもそも、私は何がしたかったのかというと、以下を何とかしたかったのだ。

  • mergeしたという記録が見えない
    • ログで残すしかない?
  • --squashしたcommitの履歴が残らない
    • squashしたブランチを消さない?


--squashした記録は、ログで残すしかなさそうだ。
上でやった手順では commit -mとコメントを指定したのだが、-m なしで実行するとエディタが起動して、squash対象のcommit logを自動的に埋めん込んでくれていた。

ただ、これはこれで悩ましいな。
commitを頻繁にするのは、細かく履歴を残しているときもあるが、別の環境に移動する際にgit経由でやる場合もあるからだ。
「家に帰るのでcommit」とかも、しばしば。

まあ、ログを編集すれば良いのだけど、それだったら自分で「mergeした」と入れるだけでもよい気がする。


それよりも、問題は2番目だ。
commitはgitのどこかに必ず残っていて、ブランチはcommit idをつなげているだけだと思っていたのだ。
しかし、ブランチを削除してcommit履歴も消えると言うことは、commitはブランチに紐付いているということになる。
今までsquashせずにmergeしていて、commit履歴が全部残っていたので、そう勘違いしていたのだろう。


ブランチを消さなければ残るのだろうが、私はそこまでして履歴を残したいのだろうか?
「この行は何のためにこうしたんだっけ?」という確認をしたいときに見るかもしれないけど、そもそも記憶にないのにcommitログを見ただけでわかるとは思えない。
それよりは、mergeする単位を大きくしすぎないというか、1つの目的のためにmergeするようにしておけばよいのではなかろうか。


issueを上げて対応するためにブランチを作っていたのだけど、複数の問題が絡んでいる場合がある。
そうすると、1つのブランチでの作業が大きくなってしまう。。。

そんなときは、気付いた時点でさらにブランチを作っておけばよいのかもしれん。
あれこれ試して、自分というかチームにあう運用スタイルを作っていくしかなかろう。

2018/05/17

[android][ndk]MbedTLSをビルドしてみよう (4 挫折)

久々に挫折した・・・。
いや、「久々に挫折した」という記事を書きます。


前回からも修正を続け、よくわからないなりにMbedTLSの.aファイルを作ることができた。
それで終わらせれば良かったのだが、もともとは、複数のライブラリを使うライブラリがあるので、それをAndroid Studioからビルドしたい、ということだったのを思い出した。


MbedTLSだけのとき、build.gradleに-Dで設定をすることでビルドができていた。
それをset()で置き換えられるのであればよかったのだが、それは失敗している。

となると、他のライブラリをビルドするときにも、同じbuild.gradleの影響下で行うならば、同じ設定を使うことになる。
それは、まずい。
もしかしたら問題ないのかもしれないが、不安要素は残しておきたくない。

それを回避してできるように、ああでもないこうでもないと数日やっていたのだが、さすがに時間を掛けすぎている。
Android Studioを捨てれば、Makefileでビルドはできているので、そんなに難しいことはないだろう。



という流れで、「今回はこれで挫折して終わらせ、MakefileでAndroid用にビルドする」のが無駄が少なかろうと判断したのだ。
時間ができたらやり直そう、とは思うが・・・まあ、そういうのって、やらんよね。


ただ、まだ回避方法はあると思っている。

たとえば、今はMbedTLSに入っているCMakeLists.txtをそのまま使っているけど、それをコピーして、build.gradleに設定しないと有効にならなかった設定を編集してしまっておく、とか。


なぜやらなかったかといえば、正攻法ではない気がしたからだ。
しかし、正攻法ではない、というのは気分的なもので、実はそうするのが普通なのかもしれん。
ライブラリがアップデートされたときに、コピー&編集したCMakeLists.txtへの反映を忘れそうだから嫌だ、というだけかもしれない。


判断ができないのは、cmakeに詳しくないからだ。
付け焼き刃の知識で逃げようとしているのも、cmakeに詳しくないからだ。

では、cmakeを覚える気力があるかというと・・・無い。
なんだか、暗黙のルールが多い感じがして、気力が湧かないのだ。
まあ、そんなことをいえばmakeだって同じようなものかもしれないが、同じようなものを2つ覚えるには歳を取り過ぎたのだ。


という言い訳をして、今回は挫折した、で終わらせてもらおう。

2018/05/13

[android][ndk]MbedTLSをビルドしてみよう (3)

Android Libraryとして、既にあるCMakeLists.txtを取り込み、static libraryを作ってみる方法は分かったと思う。
まあ、単純なCファイル1つだけだったので、CMakeLists.txtもシンプルだったから問題が出なかったのだろう。

本題であるMbedTLSを取り込んだら失敗するんじゃないかと思うが、MbedTLSはAndroid OSでも動くと書いているので、案外とあっさり動くのかもしれない。

さあ、どちらだ?


はい、前者でしたー。

前回と同じようにcppディレクトリを作って、今回はその中にMbedTLSをcloneしたファイルを置き、ディレクトリの直下にあるCMakeLists.txtを「Link C++ Project with Gradle」で取り込んでみたのだが、その時点でエラーが発生した。

まあ、そうよね。。。

Android Studioに出ているログを見ると、testsあたりで失敗しているようだ。
うん、Arm用にビルドしたものは、たぶんテストできないだろうねぇ。


MbedTLSでライブラリを作るときにはlibraryディレクトリの中しか使わないので、そこにあるCMakeLists.txtを使ってみたがエラーになった。
こっちは、cmake_minimum_requiredがないとか。
では、オプションでMbedTLSをcloneした直下にあるCMakeLists.txtを制御するか、自分でCMakeLists.txtを作ってlibrary/CMakeLists.txtを呼び出すかがよいだろう。


うーん・・・・。
testsを呼び出さないようにするためのオプションは、"MSVC"らしい。
MSVCじゃないのに"MSVC"をセットするのはいやだから、後者にするか。


そう書いて、あれこれ試しながら数時間・・・。
ぜんぜんうまくいかない・・・。

L.138でエラーが出るのだが、私としてはそのルート自体を通さないつもりでいるのだ。
L.125のif文がfalseになるように、呼び出し元のCMakeLists.txtで「set(USE_STATIC_MBEDTLS_LIBRARY OFF)」としているのだが、効果があるようには見えない。


やはり、適当な解釈ではダメなのか。


少し、CMakeLists.txtのことを調べた。

「"MSVC"をセットしないと」と思っていたが、optionという項目はデフォルト値を決めているようだ。
setで設定すれば、そちらが上書きされるようである。

まあ、そう思ったからsetを使ってみたのだが、どうにもダメっぽい。
testsを通る箇所を全部コメントアウトすればライブラリができているから、そこだけのようだ。

今日はここまで。
github

[android][ndk]MbedTLSをビルドしてみよう (2)

前回の復習から。


NDKでMbedTLSをビルドしようとしたが、それ以外にもビルドしたいライブラリがあるので、まずは複数のC/C++ライブラリをビルドする用意をしておきたい。

Android Studioではcmakeを使えるようだし、MbedTLSもcmakeの設定があるので、取り込めばよさそうだ。

そのサンプルが、hello-libsであった。


hello-libsは、pre-builtされたライブラリを使うサンプルになっているが、2箇所変更するだけでpre-builtされたライブラリをビルドするところもやってくれるようになっている。


で、今回は、どうやればいいのかを調べるところからだ。


Android Studioの左下に「Build Variants」があるが、settings.gradleのコメントアウトを消すと"gen-libs"が出てきた。
設定値は"debug"である。


ツリーはこうなっている。
有効にした"gen-libs"が増えているから、settings.gradleが効いたのだろう。

image

このファイルでincludeしているのは、"app"と"gen-libs"で、両方ともフォルダがあり、中にbuild.gradleがある。
ライブラリたちを、同じように専用のフォルダを作ってまとめてしまうか、あるいはライブラリごとにフォルダを作るかだろう。

アイコンがappとは違っているので、そういうフォルダが作れるようだ。
どうも、Module、というもののようである。

image

ここで+アイコンをクリックしても良いのだろうが、ツリー画面のコンテキストメニューに「New>Module」もある。
出てくるウィザード画面はどちらも同じなので、どっちでもよいのだろう。


ウィザード画面を見たが、どれを選べばよいのだろう?
JNIになるからJava Libraryかと思ったが、違う気がする。

そもそも、最後はJNIになるし、MbedTLSも使いたいのだが、MbedTLSをJNI経由で直接扱いたいわけではなく、JNIで使いたいライブラリが中でMbedTLSを使っているだけなのだ。
gen-libsはJavaを持ってないので、同じようになっているはず。
build.gradleの「apply plugin」が"com.android.library"になっているから、Android Libraryを選べばよさそうだ。

作ってみると、アイコンも同じだったので、大丈夫だろう。
ここでは「build-libs」という名前で作った。
モジュール設定画面を見ていっても、testrunnerが入っているくらいで、gen-libsとあまり違いは無かった。


image


デフォルトで「java」というフォルダと、その中にパッケージのフォルダ階層が作られたが、それだけのようだ。

image

gen-libsの方には、cppの中にCMakeLists.txtがある。
build.gradleの中にCMakeLists.txtへのパスが書かれているので、同じようにやれば良いのだろう。
相対パスで書けるので、このフォルダごと別のプロジェクトに持っていってインポートするようなこともできるのかもしれん。


まず、javaディレクトリを削除して、cppディレクトリを作成。
その中に、const char*を返すだけのCソースとヘッダファイルを追加。
cmake関係は後回しにして、まずはjavaの痕跡を消しておきたかったのだが、syncっぽいことをしても消えないし、cppも出てこない。
testrunnerがあるせいかと思って消したが、効果無し。

だが、コンテキストメニューを出してみると「Link C++ Project with Gradle」が出てきた。
これで「Android Studio UIの使用」に書いてあることができるのだ。

image


では、cmakeの作業をせねばなるまい。
私はcmakeに詳しくないので、gen-libsの中にあるgmathのCMakeLists.txtをコピーして、"gmath"と書いてあるところを適当に置き換えた。
ライブラリやヘッダファイルがあった distributionディレクトリへのコピーもこの中でやるようなので、パスを変更する。

そして、作ったCMakeLists.txtを「Link C++ Project with Gradle」でリンクさせる。
CMakeLists.txtを指定するだけなのだが、相対パスへの変換もちゃんとやってくれる。


取りあえずビルドだ、ビルド。
とボタンを押してみるが、バイナリができないし、includeファイルのコピーもされていない。
ただ、distributionディレクトリの中にはディレクトリが追加されている。


そういえば、gen-libsをビルドできるようにしたとき、appのbuild.gradleにも変更を加えたのだった。
コメントを見ると、native libraryのビルドが行われないというissueが出ているらしく、その対応のように見える(今はv3.1.2だから直ってるかも)。
同じように追加すればビルドされるかと思ったのだが・・・ダメだ。
distributionディレクトリの中にディレクトリが追加されたのも、cmakeが行われたからというよりは、リンクする作業を行ったからやってくれただけのようにも見える。
distributionディレクトリの中を削除してビルドし直しても、gmathとgprefしか生成されないからだ。


設定ファイルを見直していくと、build.gradleに"android.defaultConfig.externalNativeBuild"が無いことに気付いた。
gen-libsだと"targets"にライブラリの名を書いているだけなのか?
appの方は"arguments"で、g++だかclangだかに与えるパラメータを書いているように見える。
よくわからんので、"targets"に今回追加したライブラリ名を書いてみた。
が、変わらず。


ツリーのビューを"Packages"に変更すると、追加したライブラリのパッケージ名が違っていることに気付いた。
AndroidManifest.xmlで変更するようだったので、書き換えた。


ここら辺までやると、distributionディレクトリの中に追加したライブラリとヘッダファイルがコピーされていた。
されていたけど、あれこれやりすぎて、どれが有効だったのかが分からん。。。


新規に、hello-libsに自分のライブラリを追加していこう。


  1. Android Studio v3.1.2を起動して、「Import an Android code sample」の"hello-libs"プロジェクトを選択。
  2. メニュー:File > Project Structure
    1. +アイコンをクリック
    2. "Android Library"を選択してNext
    3. 「Application/Library name」に"mklib"、「Package name」に"com.example.buildlibs"を設定して、Finish
    4. Android Studioがぐりぐり動き出すので、OKでダイアログを閉じて安定するまで待つ。
      1. ダイアログを閉じずに待っていたのだが、10分くらいしてもぐりぐりしたままだった
  3. 安定したら、もう一度Project Structureを開いて、左からmklibを選択し、「Dependencies」タブでjunitとtestrunner関係を削除して、OK
  4. ディレクトリ"mklib/src"にある"androidTest"、"test"、"main/java"を削除
  5. mklib/src/mainの中に"cpp"ディレクトリを作り、ソースファイルとCMakeLists.txtを置く
    1. ライブラリ名は"mklibtest"
  6. mklib/build.gradleの編集
    1. android.externalNativeBuildを追加し、cmake.pathにCMakeLists.txtのパスを追加
    2. android.defaultConfig.externalNativeBuildを追加し、cmake.targetsに"mklibtest"を追加
      1. これは、コンテキストメニューの「Link C++ Project with Gradle」から行ってもよい
    3. testInstrumentationRunnerの行を削除
  7. app/build.gradle(これはやらなくてもよいかもしれん)
    1. tasks.whenTaskAddedに、"gen-libs"のまねをして"mklib"を追加
    2. tasks.whenTaskAddedのコメントアウトを戻す
  8. メニュー:Build > Make Project


これで、distribution/mklibtestにヘッダファイルとライブラリがコピーされた。
ライブラリは今回staticにしていて、libmklibtest.a、という名前になった。

ここまでをgithubに上げておこう。


さて、ここまででライブラリはビルドできた。
アプリで使うには、app/build.gradleに追加したり、JNIを作ったりせんといかんが、今回の目的ではないのでよかろう。

次回はMbedTLSをビルドできるようにしたいが、すごく苦労しそうな気がする。

2018/05/12

[android][ndk]MbedTLSをビルドしてみよう (1)

久々にAndroidだが、アプリではなくNDKだ。


LinuxでMbedTLSを使ったアプリを作ったのだが、それをAndroidで動かしたい。
もちろん、私が作っているので、C言語だ。
理想は、画面だけAndroidのJavaなどで作って、機能的な部分はNDK/JNIで今作っているものを流用したい。

その前に、まずMbedTLSをAndroidでビルドできるのか?というところが課題となっている。
なお、私はNDKはほとんど知識がないという前提だ(実際、ないのだが)。


https://tls.mbed.org/features

一番下に移植性のことが書いてあり、Android OSも入っている。
じゃあ、ビルドは簡単かもしれん。


まず、Android Studio v3.1.2でプロジェクトを作る。
Lollipopがデフォルトで出てきたので、そのまま進める。
ただ、C++だけはチェックしておく。

image


ビルドして動かすと、画面の真ん中に「Hello from C++」とだけ表示される。
C++のnative-lib.cppで文字列を返して、それをJavaで出力させているのだ。

ビルドするソースファイルの指定は、CMakeLists.txtでやっている。
cmakeを使うようだ。
Android.mkなんかは、もう使わなくなったのかな?


NDKやcmakeは、インストールされていなければビルドエラーと一緒にリンクも出てきて、それをクリックするとインストールしてくれる。
進化したものだ。。。


MbedTLSもcppフォルダ内にcloneしておこう。
https://github.com/ARMmbed/mbedtls


cloneしたものを"android"でgrepしたが、ヒットしない。。。
ビルドしやすいようなサポートはやってないということか。


新規でC/C++ファイルをAndroid Studioに作成していくのであれば、既存のCMakeLists.txtにファイル名を記載していけばよいのだろう。
しかし、既存のライブラリを取り込むのであれば、何か簡単な方法があるのではないだろうか?

今回はMbedTLSだけだが、それ以外の既存ライブラリを使いたいことの方が多いだろう。
そのとき、全部のライブラリに関するファイル名を列挙するのも嫌だし、そもそもライブラリを1つにまとめることになってしまうのが嫌だ。

既存のライブラリは、その単位で扱いたいものである。


Android StudioのUIを使って、cmakeなりndk-buildなりでビルドできるようにしたプロジェクトをリンクできるそうだ。
https://developer.android.com/studio/projects/add-native-code?hl=JA#link-gradle

ライブラリごとにビルドするスクリプトなどを用意しておけば、それぞれプロジェクトをリンクさせるだけでよい、ということではなかろうか?


Android StudioのAndroidビューから、appなどでコンテキストメニューを表示させると「Link C++ Project with Gradle」という項目が出てきそうなことが書いてあるのだが、メニューにはない。
既にC++が使えるプロジェクトにしているから、出てこないのだろうか?

build.gradleにcmakeの項目があったので、pathをもう1つ追加してみたが、ビルドエラーになった。
なんとなく、1つしか書けないような気がする。


他のCMakeLists.txtを取り込むのは、こちらか?
https://developer.android.com/studio/projects/configure-cmake#include-other-cmake-projects

まねをしようとしたが、何をしたらまねになるのかが分からん。。。



こちらが、複数のライブラリを扱った場合のサンプルのようだ。

https://github.com/googlesamples/android-ndk/tree/master/hello-libs


pre-builtと書いてあるので、既にビルドされたライブラリを取り込むのかと思ったが、ソースファイルもあるな。
どっちを使っているのだろう?


  • hello-libs: app/src/main/cpp/CMakeLists.txt + ソースファイル
    • gen-libs: gen-libs/src/main/cpp/CMakeLists.txt
    • lib_gmath: gen-libs/src/main/cpp/gmath/CMakeLists.txt + ソースファイル(static)
    • lib_gpref: gen-libs/src/main/cpp/gpref/CMakeLists.txt + ソースファイル(shared)
    • log: NDK付属


プロジェクトを開くと、こういう風に見える。

image


組み込むライブラリのソースファイルは見えない。
distributionディレクトリを削除してリビルドしたら、やはりビルドに失敗した。


READMEにも書かれているが、ビルドしたものをdistributionにコピーしているようだ。
もし再生成したいなら、setting.gradle, app/build.gradleを変更すれば良いそうだ。


setting.gradle

include ':app'

// To generate libs used in this sample:
//   1) enable the gen-libs at end of this file
//   2) enable module build dependency in app/build.gradle
//   3) build the app's APK in Android Studio or on command line
//   4) undo step 1) and 2) above
// include ':gen-libs'

app/build.gradleは、一番最後がコメントアウトされていたから、それか?

tasks.whenTaskAdded { task ->
    if (task.name == 'externalNativeBuildRelease') {
        task.dependsOn ":gen-libs:externalNativeBuildRelease"
    } else if (task.name == 'externalNativeBuildDebug') {
        task.dependsOn ":gen-libs:externalNativeBuildDebug"
    }
}


両方を有効にしてビルドし直すと・・・おお、distributionディレクトリが復活している。
次は、これを理解するところから始めよう。

先は長いな・・・。

2018/05/06

git merge --squashによるコミットまとめ

先日、こういう記事を書いた。

クラウド上のVMとのファイル同期はどうやるのがよいのだろう?
http://hiro99ma.blogspot.com/2018/05/vm.html


あれこれ考えたが、私にとってはgitを使った方が無難だという判断に至った。
性格的に、突然大きな変更なんかをやらかしてしまいがち(そして動かなくなる)なので、こまめにgit commitしていく方が安心なのだ。


が、コミットログが乱れるのはよろしくない。
今までは気にもしなかったのだが、そういうお年頃になったのだと思おう。


お仕事用のプロジェクトで、ほぼ自分しかリポジトリを触っていなかったので、直接commit・直接pull request・直接merge、と、やっていたのだ(githubを使っている)。
それを、forkしてからpull requestするタイプにすればよさそうだった。

参考にしたのは、こちら。

慣れてきたらコミットをまとめてPull Requestしよう(git merge --squash) | 株式会社グランフェアズ
https://www.granfairs.com/blog/cto/git-merge-squash


たぶんだが、forkせずに同じリポジトリで作業していたら、それはそれでログが汚れてしまいそうな気がしたのだ。
だ、だよね??

まあ、そうじゃなくてもよいのだ。
プロジェクト用のリポジトリだから、自分は自分のリポジトリで作業して、結果だけを残せば良いのである。


やり方は、リンク先を見た方がわかりやすい。


で、その後だ。

実は・・・forkして作業するというのをほとんどやったことがない。
pull requestがマージされると、fork先が先に進んでしまうけど、どうしたらよいのだか。。。

GitHubでFork/cloneしたリポジトリを本家リポジトリに追従する - Qiita
https://qiita.com/xtetsuji/items/555a1ef19ed21ee42873

ありがたい。


手元にbranchが3つ(upstreamのもの、作業中だったもの、作業中をsquashしたもの)が残り、upstreamはそのままだし、squashしたものもmergeしたからよいのだが、作業中だったものは "git branch -d xxx"では消せず、 "git branch -D xxx"にしなくてはならなかった。
squashされたものの履歴までは追わないのだろう。


しかし、今回はsubmoduleも変わってしまったためか、mergeしてもcommitしていないものが残ってしまった。
commitしてpushしたのだが、当然オリジナルとは別のcommit idになる。


もしかして・・・forkしないでやるべきものなのだろうか?
いや、今まではそうせずにやっていて、commitログが乱れたものになってしまったのだから、それだと期待通りではない。


ずっとローカルで作業できるのであれば、forkせずにいけるような気がする。
だが、私はpushしてしまいたいのだ。
そうなると、第2のローカルという感じで、forkして自分のリポジトリで作業することになると思う。



今日はもうpull requestしたくなるようなものがないので、次回試すしかないな。


pull requestするものができたので、試した。

流れを復習しておこう。

  1. 本体からfork
  2. 本体側でsubmoduleの更新が発生
  3. fork側でpull requestし、本体側でmerge
  4. fork側を本体側に同期させようとして、upstreamをfetchして、メインブランチにmerge
    1. submoduleに差分が出たので、commit


この状態で、fork側からpull requestしたのだが、fork側のsubmode差分によるcommitも対象になってしまった。
おかげで、本体側のcommitログには、submoduleの更新が複数出てきてしまっている。
やはりか。。。


そんなに神経質になるつもりもないのだが、回避できるのであればやりたい。

簡単なのは、手順4をせずに、forkしたものを削除して、新たにforkする、だろう。
本体と同じものになるから、悩むこともない。


upstreamというブランチは、本体側と同じものだ。
それと同じように、手順4でmergeなどせず、mergeしようとしたブランチ自体を捨てて、fetchしたあとのupstreamからブランチを作ってしまえば良いのか?

何か違う、という感触はあるのだが、何がどうダメなのかはわからん。。。


だいたい、forkやらpull requestって、githubやbitbucketの機能で、git自体の機能じゃないよなぁ。
cloneして、remote set-urlで変更するとかか? いや、それじゃ足りないか。。。

使えば使うほど、gitへの理解が足りてないのが身にしみるわ。

2018/05/05

[lmdb][win10]Windows10 1803でWSLのファイル書込みがうまく動いてない?(2018/05/05)

Windows10で、2018年春のアップデートが行われた。
ありがちだが、バグはいろいろあるようだ。

そしてうちでも、そのバグに悩まされることになった。
WSLだ。


https://gist.github.com/hirokuma/4ea889b2a596c59ef4f862e9df54e469


lmdbのmdb_put()がうまく処理できないようなのだ。

MDB_BAD_TXN: Transaction must abort, has a child, or is invalid

最初はmdb_get_cursor()を使って失敗していたのでcursor関連かと思い込んでいたのだが、どうもMDB_txnのチェックでエラーになっているようだ。

https://github.com/LMDB/lmdb/blob/86a90cad721cbdc0bb0a9c3bf15396f5c946ae95/libraries/liblmdb/mdb.c#L7164



そして、DBファイルを残したままであれば、test1()を実行しなければ発生しない。
test1()のmdb_put()をコメントアウトするだけでも大丈夫そうだ。

MDB_txnは毎回MDB_envから取ってきているので、MDB_envに何か残っているということか・・・。


mdb_env_sync()というAPIがあった。
http://www.lmdb.tech/doc/group__mdb.html#ga85e61f05aa68b520cc6c3b981dba5037

何か残っているというならば、ファイルシステムへの書き込みができていないとかだろう。
ただ、ライトキャッシュが吐き出されていなかったとしても、再起動しているわけでも無い状態でOS経由で読み込む分にはキャッシュから読み込んでくれないといかんはずだ。
じゃないと、単に「書込みをしなかった」のと同じになってしまうではないか。。。

ひとまず、test1()とtest2()の間に、以下を追加した。

mdb_env_sync(env, 1);

そして、DBファイルを削除して実行すると・・・動いた。



じゃあ、mdb_env_sync()せずに、コマンドでsyncを実行したらうまく行くのでは?と思ったが、そうでもなかった。
が、syncせずとも、LMDBサンプルを一度実行して失敗した後、5~10秒くらい待ってからもう一度実行すると成功した。


なんじゃそりゃー


そんな感じで、一時的に回避したいなら、強制的に吐き出させるしかなさそうだ。
まいったなぁ。


そして、mdb_env_sync()をmdb_txn_commit()後に行うようにしてみたのだが、作ったサンプル程度であれば動いたのだが、作業でやってるアプリだとダメだった。。。
サンプルでダメだったときはmdb_get()なんかで発生していたのだが、私のアプリだとmdb_txn_commit()で起きてしまう。

MDB_TXN_FINISHEDかMDB_TXN_ERRORが原因のようだが、ファイルの書き込みが疑わしいとなってしまうと、DBとしては何が正しいのかわからんので、WSLが原因なのか、私の実装が悪いのかは、今回の現象が直ってからだな。

2018/05/04

クラウド上のVMとのファイル同期はどうやるのがよいのだろう?

ソースファイルを、ローカルで編集したり、ビルドしたりする。
gitを使っているので、適当なタイミングでpushする。

Linux向けのプログラムなので、ローカルマシンがWindowsではあまり確認がちゃんとできない。
なので、Windowsで実装し、クラウド上のLinuxVMで実行する、ということをしばしば行う。
このとき、どうやってファイルを同期させるのが良いのだろう?
(オープンソースで開発しているので、セキュリティにはそんなに考慮しなくて良い前提)


git経由でやっていたのだが、コミットログが「Linuxで動作確認するためにpush」みたいな感じになってしまい、それで動いたならまだしも、動かないこともしばしば。。。
gitのことを検索すると「コミットログを汚さない方法」みたいなものが結構出てくるのだが、世の中ではそういうやり方をして、なるべく不要なコミットログを残さないように努力しているのだろうか??



あるいは、DropBoxみたいなものを使うという手段もあろう。
Googleドライブだと同期が遅いのでやりづらいのだが、DropBoxは比較的速いので、手元で編集したらすぐにアップされるようだ。
これなら、コミットせずにVMと連携できるし、ファイルを変更するだけでよいから手軽だ。

しかし・・・なんか抵抗がある。
なんかちょっと違うんじゃなかろうか、という、漠然とした思いだけだ。



クラウド上のファイルを正とする、というパターンもありだ。
なんでローカルで編集しているかというと、使い慣れたテキストエディタが使いたいというだけなのだ。
SFTPなんかで編集したいファイルを持ってきて、編集したらアップする、みたいなことはSFTPツールで実現しているものも多い(私はWinSCPでやってる)。
ちょっとした変更だったら、これでもよいのだ。
ただ、複数のファイルを扱ったり、テキストエディタの機能で置換を掛けようとしても、それはできない。

まるまるマウントできると、非常にありがたい。
そういうわけで、今日はAzure Filesを使って、Windowsのネットワークドライブとして接続してみた。
ルータのフィルタリングで445が止められているのに気付かなくて時間がかかったが、困ったのはそれくらいだ(ルータが止めているというのにたどり着くまでが非常に大変だったが)。

WindowsのExplorerから見えるようになって便利なのだが、いくつか問題が。
私の環境で大きい問題は、シンボリックリンク。
CIFSというファイルシステムだからだろうが、シンボリックリンクが使えないようだ。
実行権限なんかは生きているようだから、ファイルコピーすればよいのだけど、そのために作りを変えるのも負けた気がするので避けたい。

また、アクセスがちょっと遅い気がする。
これはVMの方が原因かもしれないので、はっきりしたことは言えない。

あと、ポート445を開けるというのも、ちょっと嫌かも。


いま思いつく方法は、このくらいだ。

なんかいい方法を模索していかねば。。。