dropbox-api: メモリサイズ以上のファイル同期不能に

FreeBSD は Dropbox 提供のクライアントアプリケーションはありませんが、dropbox API を利用した CUI レベルの dropbox-api-command があります。

私は深夜にcron で dropbox-api コマンドを発行して、必要なファイルを同期させていているのですが、最近、エラーが出力されず、ファイル同期が失敗していることがあることに気づきました。

下記の環境で同様の症状が発生することを確認。

FreeBSD9.3,  dropbox-api-command-2.09,1     Dropbox API wrapper command
FreeBSD10.3, dropbox-api-command-2.11,1     Dropbox API wrapper command
FreeBSD11.0, dropbox-api-command-2.11,1     Dropbox API wrapper command

現象

  • dropbox-api コマンドが正常に終了しているように見える。エラーは出ていない。
  • 同期したファイルがオリジナルサイズより小さい。
  • 例えば、Windows7 の XPモードの元ファイル WindowsXPMode_ja-jp.exe 616MB を転送してみると
    「302742822  7月  4  2016 WindowsXPMode_ja-jp.exe」
    で転送が終了してしまいます。
  • 確認した同期は、Dropbox → ローカル のみ。逆方向は未確認。

複数の FreeBSD サーバーで切り分けてみたところ

  • Dropbox 側が API に制限を設けたのかと、複数のホストで動作確認したところ、サーバー側の問題ではないことが判明。
  • 搭載している実メモリ容量が大きなホストでは、ファイル同期に失敗することが少ない
  • 搭載メモリが小さいホストでは、同期が正常に行われていないことが多い。

という現象で、どうも搭載メモリとの因果関係がありそうだと判明し、更に切り分けたところ、

  • 搭載メモリ以下のファイルサイズしか正常転送できない。
  • 例えば、512MB のホストでは、300MB くらいが最大同期ファイルサイズで、
  • 1GB 搭載しているホストでは730MBくらいが最大サイズ。
  • 1GBメモリ搭載しているマシンなら、上の、WindowsXPMode_ja-jp.exe を全部転送できます。
    「631040784  7月  4  2016 WindowsXPMode_ja-jp.exe」

になるということがわかりました。

以前は、256MB のホストで、1GB以上のファイルを転送できていたので、最近のパッケージ更新でこのような現象が発生しているものと思いますが、正確な問題発生時期はわかりません。
dropbox-api コマンドの更新はしばらく行っていなかったとから、依存関係があるパッケージの更新によるものだと思います。

ファイル同期中のファイルサイズを観察していると、「filename.dropbox-api.tmp」が長時間 0 のままで、転送終了時と思われるタイミングで突然巨大なファイルサイズになります。ということは、空いているメモリを使ってファイルダウンロードを行っているんでしょうね。

対策

自分で何とかしようと、いろいろ切り分けしてみましたが、これは私の手に負えるレベルじゃ無さそう。

開発者の方にコンタクトしてみました。(2017/01/11)

頂いた回答の一部を貼り付けておきます。

調べた所 LWP、Net::HTTP あたりの仕様によって起きているようでした。
現状できる回避策としてはFurlを追加インストールする他ありません、

推測通り、dropbox-api-command の中ではなく、依存関係があるパッケージの更に先の依存関係があるパッケージの仕様(ここ1年くらいの間の変更)のようです。

Furl というのは dropbox-api-command が呼び出す p5-WebService-Dropbox パッケージがオプションで利用可能なライブラリのようで、これを使って下さい ということです。

じたばた

私、dropbox-api-command を自分でビルドせず、pkg コマンドでネットワークインストールしていたため、p5-WebService-Dropbox の オプションを確認していませんでした。/usr/ports の下で、make config して確認してみると、FURL オプションはデフォルトでチェックが入っています。
また、pkg info コマンドで確認してみると、

# pkg info | grep Dropbox
dropbox-api-command-2.09,1 Dropbox API wrapper command
p5-WebService-Dropbox-2.05 Perl interface to Dropbox API

上のように、依存関係でパッケージ自体は入っています。ただ、入っているからと言って、有効であるかどうかはわかりません。

何も試さないまま製作者の方に細かい設定方法を尋ねるのも気が引けます。

dropbox-api-command と p5-WebService-Dropbox (と依存関係にあるパッケージ)を抜く。依存の依存は手の出しようがないので放置。
その後、/usr/ports/net/p5-WebService-Dropbox で FURL を外してビルド、dropbox-api-command をインストール。(これで、FURLを使わないdropbox-apiができあがり。)
再度、p5-WebService-Dropbox と dropbox-api-command を抜いたあとで、FURL を有効にした dropbox-api-command をビルドしてインストール。

ビルドの後、主記憶サイズより大きなファイルをダウンロードしてみないとわからないため、アンインストールしてはテスト、インストールしてはテストを繰り返し行いました。今考えると、作者の意図は p5-WebService-Dropbox の FURL オンしたものを使え ということだけだったと思うのですが、余計なことをたくさん行ってしまったようです。

上にも書きましたが、dropbox-api-command が使う perl ライブラリはメモリを使ってファイルをダウンロードしています。以前は、ftpのようにファイルに書き込みながらだったため、ファイルサイズを観察しているとダウンロードが進むにつれだんだんとファイルサイズが大きくなっていったものですが、今は、転送中もファイルサイズは0で、最後にドッカーンとファイルが生成されます。

では、メモリサイズよりも大きなファイルはどうやってダウンロードするのか?

仮想記憶、つまりスワップを使ってみるものと考えます。今回テストしている 512MBメモリのマシンは、こういう使い方をすることを想定していないため、スワップを1GB しか切っていませんでした。スワップ使用量を観察すると、スワップがガンガン消費されて行きます。スワップは、MySQLやApacheでも消費されて残量500MB以下。サーバー用途ならこれで十分なのですが、dropbox-api までスワップを使ってしまうとスワップ残量が無くなってコマンド自体が停止してしまいます。

長時間、パッケージを入れたり抜いたり、スワップを使い切ったり、アドバイスされたこと以外もいろいろ試していたら dropbox-api コマンドが、訳のわからないエラーを吐くようになってしまいました。

Can't call method "epoch" on an undefined value at /usr/local/bin/dropbox-api line 1115.
Can't call method "epoch" on an undefined value at /usr/local/bin/dropbox-api line 785.

このエラーを検索してみると、OSの Shared Library 依存関係が壊れた時やデータベースが壊れた時などに発生するエラーのようで、「うゎ〜」ってなものです。

現時点では、dropbox-api コマンドファイルサイズ問題は解決しておらず、OS を壊してしまった可能性もあり、dropbox-api コマンドを置き去りに別の問題へと泥沼進行中。(涙)

コメントを残す