プログラマーのメモ書き

伊勢在住のプログラマーが気になることを気ままにメモったブログです

trim_osc.py の更新失敗

OpenStreetmap のタイルサーバーの運用ですが、またエラーで更新が止まってしまいました。トホホ。

しかし、今回は、こちらの記事で設定したメール通知のおかげですぐに気づくことができたのが不幸中の幸いでしょうかね? ですが、実際に対応が完了するまでにおおよそ一か月以上かかってしまいました。せっかく通知が来たのに時間がかかるとは難しいもんですね。

一応、原因調査や対策時のメモを残しておきます。

症状

出力されていたエラーは次のようなものです。

[2018-10-29 22:06:01] 4620 start import from seq-nr 53056, replag is 27 day(s) and 14 hour(s)
[2018-10-29 22:06:01] 4620 downloading diff
[2018-10-29 22:17:43] 4620 filtering diff
Traceback (most recent call last):
  File "/home/osm/src/regional/trim_osc.py", line 131, in <module>
    for nd in root.xpath('//way[@id={}]/nd'.format(row[0])):
  File "src/lxml/lxml.etree.pyx", line 1587, in lxml.etree._Element.xpath (src/lxml/lxml.etree.c:61854)
  File "src/lxml/xpath.pxi", line 307, in lxml.etree.XPathElementEvaluator.__call__ (src/lxml/lxml.etree.c:178516)
  File "src/lxml/xpath.pxi", line 227, in lxml.etree._XPathEvaluatorBase._handle_result (src/lxml/lxml.etree.c:177421)
lxml.etree.XPathEvalError: Invalid expression
[2018-10-29 22:20:04] 4620 [error] Trim_osc error
[2018-10-29 22:20:04] 4620 resetting state
osm@map:/var/log/tiles$

詳細は置いといて、 trim_osc.py 内部の処理でこけているようです。

オープンソースなんでこちらを調べるのも一つの手なのですが、Githubのリポジトリを見ると、既にいくつかコミットがあります。なので、とりあえず最新版を pull して動作するか試してみます。

更新

ということで、更新します。

osm@map:~/src/regional$ git fetch
osm@map:~/src/regional$ git merge origin/master

試します。

[2018-10-09 09:06:02] 653 start import from seq-nr 53056, replag is 7 day(s) and 1 hour(s)
[2018-10-09 09:06:02] 653 downloading diff
[2018-10-09 09:07:13] 653 filtering diff
Traceback (most recent call last):
  File "/home/osm/src/regional/trim_osc.py", line 9, in <module>
    import psycopg2
ImportError: No module named 'psycopg2'
[2018-10-09 09:07:14] 653 [error] Trim_osc error
[2018-10-09 09:07:14] 653 resetting state

あれ?今度は別のエラーで落ちてます。

リポジトリを見ると

Force python3 · Zverik/regional@2271549 · GitHub

このコミットで python3 を使うようになったみたいです。 なるほど、多分、 psycopg2 の python3 用モジュールが無いんでしょうね。

ということで、python3 用モジュールをインストールしてやって再度試します。 ただし、 python3 のほうは pip 経由でモジュールをインストールしてみます(pipのほうがaptよりも新しいバージョンがインストールされるっぽいので)

mor@map:~$ sudo apt-get update
mor@map:~$ sudo apt-get install pip3
mor@map:~$ su - osm
osm@map:~$ pip3 install shapely
osm@map:~$ pip3 install psycopg2
osm@map:~$ pip3 install lxml

pip でのインストールの場合、ユーザーごとにインストールされるようなので、実際にデータの更新をしているユーザー(osm)に切り替えてインストールします。 なお、インストールしたモジュールは、最初に設定した時のものと同じです。

で、再度試してみると。。。あれ?同じくエラーがでますね。

trim_osc.py の調査と修正

さて、最新版にしただけだと、エラーが解決できなかったので、頑張って処理を追いかけてみました。

上述したように、最新のリポジトリ(この時点では、)にアップして、動かしたころ、

osm@map:~/tmp/osmosis_test3$ ~/src/regional/trim_osc.py -d gis -p region.poly -z -v changes.osc.gz trimed.osc.gz
/home/osm/.local/lib/python3.5/site-packages/psycopg2/__init__.py:144: UserWarning: The psycopg2 wheel package will be renamed from release 2.8; in order to keep installing from binary please use "pip install psycopg2-binary" instead. For details see: <http://initd.org/psycopg/docs/install.html#binary-install-from-pypi>.
  """)
Traceback (most recent call last):
  File "shapely/speedups/_speedups.pyx", line 234, in shapely.speedups._speedups.geos_linearring_from_py
AttributeError: 'list' object has no attribute '__array_interface__'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/osm/src/regional/trim_osc.py", line 82, in <module>
    tpoly = poly_parse(options.poly)
  File "/home/osm/src/regional/trim_osc.py", line 42, in poly_parse
    result = Polygon(poly)
  File "/home/osm/.local/lib/python3.5/site-packages/shapely/geometry/polygon.py", line 240, in __init__
    ret = geos_polygon_from_py(shell, holes)
  File "/home/osm/.local/lib/python3.5/site-packages/shapely/geometry/polygon.py", line 494, in geos_polygon_from_py
    ret = geos_linearring_from_py(shell)
  File "shapely/speedups/_speedups.pyx", line 319, in shapely.speedups._speedups.geos_linearring_from_py
TypeError: object of type 'map' has no len()
osm@map:~/tmp/osmosis_test3$ 

のようなエラーになりました。

エラーが shapely の部分で起きていたので、ライブラリを apt でインストールしたものに切り替えても試したのですが、結論としては、微妙に呼んでるライブラリなどが違うけど、大筋同じエラーになっていました。

元に戻って、スタックトレースをよく見ていくと、trim_osc.py の引数で与えている領域指定のファイル(polyのファイル)の処理で落ちているようです。

とりあえずbounding box を使い、poly を迂回して実行できるか試します。

osm@map:~/tmp/osmosis_test3$ ~/src/regional/trim_osc.py -d gis -b 136.202763 34.482312 136.6553727 34.4756217  -z -v changes.osc.gz trimed.osc.gz
/home/osm/.local/lib/python3.5/site-packages/psycopg2/__init__.py:144: UserWarning: The psycopg2 wheel package will be renamed from release 2.8; in order to keep installing from binary ple
ase use "pip install psycopg2-binary" instead. For details see: <http://initd.org/psycopg/docs/install.html#binary-install-from-pypi>.
  """)
Traceback (most recent call last):
  File "/home/osm/src/regional/trim_osc.py", line 161, in <module>
    for nd in root.xpath('//way[@id={}]/nd'.format(row[0])):
  File "src/lxml/etree.pyx", line 1577, in lxml.etree._Element.xpath
  File "src/lxml/xpath.pxi", line 307, in lxml.etree.XPathElementEvaluator.__call__
  File "src/lxml/xpath.pxi", line 227, in lxml.etree._XPathEvaluatorBase._handle_result
lxml.etree.XPathEvalError: Error in xpath expression

やはり落ちます。しかも、今回の作業のきっかけとなった最初のエラーと似たような箇所(xpath の処理)で落ちています。

ここまでの経緯を整理すると、最新版の trim_osc.py は2つの問題がありそうに思えます。

  • poly でポリゴンがつくれない
  • xpath でエラーになる

後者の xpath の問題は、今回のきっかけでも出てきましたね(まったく同じではないかもしれませんが)。

いろいろと調べると、どうも、昔、MLで指摘されていたようで、大きなファイルの場合 xpath に述語(predicate、四角いかっこでの指定)を与えて実行してもエラーとなる場合があったようです。

[lxml] lxml.etree.XPathEvalError: Invalid expression for correct XPath expression on large XML file

残念ながら、上記の ML では、問題の指摘以後、特に動きはなかったようです。

xpath 現象の確認

後者の問題を確かめるため、今回問題となった xml ファイルをダウンロードして、python3 のコンソールで同様にxpathを呼び出してエラーになるのを確認します。

その後、テキストエディタを使い、先頭の60行程度で別ファイルとして保存し、同じくコンソールで動かしてみると、同じようにxpathを指定しても正しく動きます。

ということで、ここはファイルサイズが大きい場合の xpath の述語の処理が怪しいと検討をつけ、 xpath の処理を述語を使わない形に修正しました(修正内容を Pull Request しておいたので、詳しくはそちらを参照)。 これで、動かすと、なんと、最後まで処理が進みました!

これで一個解決です。

ポリゴンファイルの確認

こちらの処理は

Polygon(poly)

という部分で落ちています。よくよく見てみると、python3 では mapの戻り値は map オブジェクトであり、listではないとのことです。 でも、Polygonのコンストラクタはtupleのリストが与えられることを想定しています。

きっとこれが原因ですね。

というわけで、poly を作るところで、

51c51
<             poly.append(map(lambda x: float(x.strip()), l.split()[:2]))
---
>             poly.append(list(map(lambda x: float(x.strip()), l.split()[:2])))

のように、map を list に変換して情報を格納するようにしたら、問題なく動作するようになりました。

めでたしめでたし。

余談

一応、上記の修正内容は Pull Request で送ってるのですが、今日時点(2018/12/4)でまだ取り込んでもらえていません。 まあ、進捗は GitHub上のリポジトリ を見ればわかるので、そちらを追いかけてください。

Windows, 共有リソースへの別ユーザー名でのアクセスについて

時々必要になって、毎回調べてるのでメモ書き残します。

※ こちらに書いてあることと同じです。

blog.livedoor.jp

困っていること

Windows 10 (他のバージョンでも同じはず)のエクスプローラとかで、ネットワーク上の共有フォルダを表示させる時にユーザー名・パスワードを入力するときがあると思います。

f:id:junichim:20181203093416p:plain

一度、ユーザー名を入力して、表示可能になると、別のユーザー名で表示させようとしても、最初に入力したユーザー名で接続されてしまい、どうすればユーザーを切り替えられるのか迷います。 なお、『資格情報を記憶する』にはチェックは入れていません。

状況確認

コマンドプロンプトで試してみます。

C:\Users\mor>net use \\homeserver /user:new_user_name
システム エラー 1219 が発生しました。

同じユーザーによる、サーバーまたは共有リソースへの複数のユーザー名での複数の接続は許可されません。サーバーまたは共有リソースへの以前の接続をすべて切断してから、再試行してください。

C:\Users\mor>

というエラーが表示されます。

これは、すでに共有リソースへの接続が存在しているために発生します。net use コマンドで表示させると、

C:\Users\mor>net use
新しい接続は記憶されます。


ステータス  ローカル名 リモート名                ネットワーク名

-------------------------------------------------------------------------------
OK                     \\homeserver\IPC$         Microsoft Windows Network
コマンドは正常に終了しました。

という感じですね。

解決方法

一度共有リソースを削除してやればよいとのことです。

C:\Users\mor>net use \\homeserver /delete
\\homeserver が削除されました。

再確認

C:\Users\mor>net use
新しい接続は記憶されます。

一覧にエントリが存在しません。


C:\Users\mor>

この状態で、再度エクスプローラから接続すると、再びユーザー名・パスワードの入力画面が表示されました。

めでたしめでたし。

QNAP Container station のデータ保存フォルダについて

前の記事 でシステムボリュームの作成についていろいろと試しましたが、その際、システムボリュームにアプリがインストール済みの場合、どうなるか?も試しました。

ここでは、これをもう少し踏み込んで、アプリが Container Station だった場合、どうなるか?というのを試してみました。

なお、 QTS のバージョンは 4.3.5.0728 Build 20181013 です。

Container Station のセットアップ方法

まず改めて Container Station のセットアップ方法を確認します。

www.qnap.com

基本的に、上記に書かれているように App Center からインストールし、初回起動時にデータを保存する共有フォルダを指定すれば完了です。

データ保存先が、システムボリュームにある場合

この場合は、システムボリューム削除時に、データも一緒に消えてしまうので、特に問題ありません。

データ保存先が、別ボリュームにある場合

気になるのはこのケースです。

例えば、 Container Station そのものはシステムボリュームにインストールしておいて、イメージ及びコンテナの保存先として、別ボリュームの共有フォルダを指定したとします。

f:id:junichim:20181123005235p:plain

上記の例の場合、qnapData というフォルダは Container Station をインストールしているボリュームとは別ボリュームの共有フォルダになっています。 ですので、システムボリューム(および Container Station)を削除しても、データ部分は別ボリュームにあるので残っています。

ここで、再度システムボリュームを設定し、 Container Station も再インストールし、再セットアップを行った際に、この既存の共有フォルダを指定すると、

f:id:junichim:20181123001339p:plain

のように、既存のデータを維持するか、新規で作成するかを聞かれました。

この時、『保存』(維持するの意味)を選択すると、ちゃんと以前 Container Station で設定していた内容が復元されていました。

Container Station が含まれているボリュームを削除することになったとしても、データ保存先さえ別ボリュームにあれば、Container Station のコンテナを全部エクスポート・インポートしなくてもいいので、これはいいですね。もっとも、バックアップ的な観点からはエクスポートしておいたほうがいとは思いますが、実際手間ですからね。