mroongaで「Can't open shared library」エラーが発生した場合の対処方法について

> もっとgroongaを知ってもらおう!ということで週刊groongaをはじめました。毎週木曜にgroongaやmroonga、rroongaのトピックを投稿予定です。

[gihyo.jp](http://gihyo.jp/)さんでgroongaの隔週更新連載が始まっています。第10回の記事も公開されたので、一読をおすすめします。

* [「第10回　[実録] MySQL向け全文検索エンジン「Tritonn」から「mroonga」への移行ガイド（3）](http://gihyo.jp/dev/clip/01/groonga/0010)

第1回から第9回までの過去記事については、[隔週連載groonga](http://gihyo.jp/dev/clip/01/groonga)のページを参照してください。

# はじめに

MySQLで高速に全文検索するためのオープンソースのストレージエンジンとして[mroonga](http://mroonga.org/ja/) (むるんが)を公開しています。
最新のバージョンは2013年8月29日にリリースした[3.07](http://mroonga.org/ja/docs/news.html#release-3-07-2013-8-29)です。

今回は、mroongaをアップグレードするときに、シンボルが未解決なため「Can't open shared library」エラーが発生してしまったときの対処方法を紹介します。

# 問題の内容

mroonga 3.07にアップグレードするときに、mroongaが意図せずアンインストールされるという不具合があり、暫定的な対処については、mroongaのリリースアナウンスでも紹介されています。

* [[groonga-dev,01726] [ANN] mroonga 3.07 (アップグレードに関する不具合の告知あり)](http://sourceforge.jp/projects/groonga/lists/archive/dev/2013-August/001727.html)
* [mroonga 3.07にアップグレードしたときのエラーでmroongaが意図せずアンインストールされる](http://redmine.groonga.org/issues/1918)

それとは別に、アップグレード中に以下のようなエラーメッセージが表示されることがあります。

```
ERROR 1126 (HY000) at line 1: Can't open shared library '/usr/lib64/mysql/plugin/ha_mroonga.so' (errno: 2 undefined symbol: grn_expr_syntax_escape_query)
```

mroongaはgroongaをストレージエンジンとして使っているので、groongaで新規APIが追加されることがあります。
``grn_expr_syntax_escape_query`` はまさに、groonga 3.0.7で新規に追加されたAPIです。
mroonga 3.07にアップグレードするときに、groonga 3.0.7も一緒にアップグレードされるはずなのにどうしてこうなるのでしょうか。

まずは、エラーが発生したときのプロセスが使用中のファイルを確認してみることにしましょう。mroongaをアップグレードするときには、プラグインをアンインストールしてから、再度インストールするという手順を踏んでいます。lsofでmroongaが使用中になっているかを確認します。

```
$ sudo lsof -c mysql|grep mroonga
$ 
```

MySQLがプラグインのファイルであるha_mroonga.soを使用中というわけではなさそうです。では、mroongaが使用しているgroongaも確認してみましょう。

```
$ sudo lsof -c mysql|grep groonga
mysqld    13602 mysql  DEL    REG              253,0          2890926 /usr/lib64/libgroonga.so.0.0.0
```

lsofのTYPEが``DEL``となっていました。 man lsofでドキュメントを確認してみるとマップファイルは削除されたけれども、という状態であることがわかりました。

```
or DEL for a Linux map file that has been deleted;
```

groongaのパッケージ自体は更新されているので、新しいlibgroonga.so.0.0.0が参照されるようにすれば良さそうです。

# 問題への対処方法

古いgroongaの共有ライブラリが参照されたままになっていることが問題であることがわかりました。そのため、この場合の対処としては、MySQLを再起動してからプラグインの再登録を行うのが良さそうです。

```
$ sudo service mysqld restart
Stopping mysqld:                                           [  OK  ]
Starting mysqld:                                           [  OK  ]
```

その後、mroongaを再度登録します。

```
$ mysql -u root -p -e "
    USE mysql;
    DROP FUNCTION IF EXISTS mroonga_snippet;
    DROP FUNCTION IF EXISTS last_insert_grn_id;
    DROP FUNCTION IF EXISTS mroonga_command;
    DROP FUNCTION IF EXISTS mroonga_escape;
    UNINSTALL PLUGIN mroonga;
    FLUSH TABLES;
    DELETE IGNORE FROM mysql.plugin WHERE name = 'mroonga';
    INSTALL PLUGIN mroonga SONAME 'ha_mroonga.so';
    CREATE FUNCTION last_insert_grn_id RETURNS INTEGER SONAME 'ha_mroonga.so';
    CREATE FUNCTION mroonga_snippet RETURNS STRING SONAME 'ha_mroonga.so';
    CREATE FUNCTION mroonga_command RETURNS STRING SONAME 'ha_mroonga.so';
    CREATE FUNCTION mroonga_escape RETURNS STRING SONAME 'ha_mroonga.so';
    "
```

再度、 lsofで確認してみましょう。

```
$ sudo lsof -c mysql|grep mroonga
mysqld    2010 mysql  mem    REG              253,0   273160 2892514 /usr/lib64/mysql/plugin/ha_mroonga.so.0.0.0
$ sudo lsof -c mysql|grep groonga
mysqld    2010 mysql  mem    REG              253,0  2228768 2890548 /usr/lib64/libgroonga.so.0.0.0
mysqld    2010 mysql   10w   REG              253,0      468 1181820 /var/lib/mysql/groonga.log
```

TYPEがmemになっているので、共有ライブラリが再度読み込まれていることがわかります。
groonga 3.0.7で新規に追加されたAPIをmroonga_escapeが使っているので、以下のように動作確認を行うことができます。

```
mysql> select mroonga_escape("(仮)*", "()");
+--------------------------------+
| mroonga_escape("(仮)*", "()") |
+--------------------------------+
| \(仮\)*                       |
+--------------------------------+
1 row in set (0.00 sec)
```

きちんと結果を取得できていることがわかります。

# まとめ

今回は、mroongaをアップグレードするときに、シンボルが未解決なため「Can't open shared library」エラーが発生してしまったときの対処方法を紹介しました。

mroongaの基本的な動作を知るための[ユーザガイド](http://mroonga.org/ja/docs/userguide.html)もあります。インストールしたら試してみてください。