GitBucket のデータが壊れた！のを復旧させてみた

## 事の起こり

あるとき、gitbucketのプラグインがうまく動いてないことに気付いた私は、本体のバージョン確認をしながら本家 GitHub をのぞいたのでした。
https://github.com/gitbucket/gitbucket

そしたらなんと。いつの間にやら 4.30.x まで上がってるじゃないですか。
手元の gitbucketを見ると 4.19.3 とか。
バージョンアップしたくなりますよね。(*・ω・)(*-ω-)(*・ω・)(*-ω-)ウンウン♪

おもむろに、warファイルをダウンロードしてtomcat再起動したさ。

```
[root@localhost] cd /var/lib/tomcat/webapps
[root@localhost] mv gitbucket.war gitbucket.war.version4.19.3
[root@localhost] wget https://github.com/gitbucket/gitbucket/releases/download/4.30.1/gitbucket.war
[root@localhost] service tomcat restart

```
これで、コミットグラフもネットワーク図もちゃんと表示できるだろー ﾌﾝﾌﾝ～♪ などと鼻歌混じりで待つこと数分。

> 503 Service Unavailable

うーん？？
apache再起動しても同じ。
めんどくさいから避けてたけど、仕方ないのでtomcatのログ見ると・・・

```
02:26:14.966 [localhost-startStop-1] ERROR com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Exception during pool initialization.
org.h2.jdbc.JdbcSQLException: 制約 "IDX_DEPLOY_KEY_FK0" はすでに存在します
Constraint "IDX_DEPLOY_KEY_FK0" already exists; SQL statement:
ALTER TABLE PUBLIC.DEPLOY_KEY ADD CONSTRAINT PUBLIC.IDX_DEPLOY_KEY_FK0 FOREIGN KEY(USER_NAME, REPOSITORY_NAME) INDEX PUBLIC.IDX_DEPLOY_KEY_FK0_INDEX_9 REFERENCES PUBLIC.REPOSITORY(USER_NAME, REPOSITORY_NAME) INDEX PUBLIC.IDX_DEPLOY_KEY_FK0_INDEX_8 NOCHECK [90045-197]
        at org.h2.message.DbException.getJdbcSQLException(DbException.java:357)
        at org.h2.message.DbException.get(DbException.java:179)
        at org.h2.message.DbException.get(DbException.java:155)
        at org.h2.command.ddl.AlterTableAddConstraint.tryUpdate(AlterTableAddConstraint.java:110)
        at org.h2.command.ddl.AlterTableAddConstraint.update(AlterTableAddConstraint.java:78)
    :
    以後略
```
∑(￣皿￣;;)

データベースのエラー？
> しまった・・・DBバックアップしてから更新かけるのが通常の手順だった・・・

と気づいたときにはすでに遅し。
gitbucketのバージョン下げて再起動してもエラーで起動しない・・・・
ローカルに持ってきてh2のコンソール立ち上げて中見てみても何もデータがない・・・
H2 databaseのコトな何も知らないけど壊れたと思っていいんだろうか・・・

いろいろ考えた挙句、「壊れた」と仮定してすべての作業を開始することにしました。
まずは社内告知。
それからデータのバックアップ（いまさら）
で、解決策を探ります。

H2なんて触ったことないけど、なんか復旧させる手があるだろうか・・
「クリーンインストールしたから登録しなおしてね！(￣∇￣*)ゞﾃﾍｯ」なんてことになると大ごとだから避けたいな・・・
なんで気軽に更新かけちゃったかな・・
ていうかこのサーバーなんでバックアップ取ってないんだ・・・

とか思いつつも・・しかたなくデータベース復旧を始めるのでした。

## 試行錯誤の手順は省略

読んでも仕方ないから書かないのです。

## 最終的に復旧させた手順（ざっくり）

### まず本家にアクセス

http://www.h2database.com/html/main.html
なにはともあれ、h2 databaseの障害なのだから本家をのぞきます。

なにやらtoolがダウンロードできるみたいだったので、Download の "All Platforms (zip, 8 MB)" っていうやつをダウンロードします。

### ツールを起動してDBからSQLを作成

ダウンロードするところから書いときます。

```
[root@localhost] wget http://www.h2database.com/h2-2018-03-18.zip
[root@localhost] unzip h2-2018-03-18.zip
[root@localhost] cd h2/bin
[root@localhost] cp (dbファイルがあった場所)/data.mv.db .
※念のためコピーを使って作業します
[root@localhost] java -cp h2-1.4.197.jar org.h2.tools.Recover
[root@localhost] 
```
ん？何も言わずに帰って来たぞ・・・・？
失敗したのか・・・？と思いきや、

```
[root@localhost] ls
data.h2.sql  data.mv.db  data.mv.txt  h2-1.4.197.jar  h2.bat  h2.sh  h2w.bat
```
おお、SQLファイルができていました。

### 悪銭苦闘のSQLインポート

ここまで来たらあとはうまいことインポートするだけだ！
と思います。たぶん。

```
[root@localhost] cd /usr/share/tomcat
[root@localhost] service tomcat stop
[root@localhost] mv .gitbucket （バックアップ先）
[root@localhost] service tomcat start
[root@localhost] 
```
なにしてるかというと。
認証データの data.mv.db や、リポジトリのデータファイルはすべてこの GITBUCKET_HOME である、/usr/share/tomcat/.gitbucket に入ってます。
なので、いったん環境を初期化するという意味で、.gitbucket をバックアップしたのち、削除してtomcatを起動させています。

こうすることで gitbucket自体は正常に起動し、初期アカウントである root / root でログインできるようになります。
もちろん、中身は空っぽですが・・・

![login.JPG](https://qiita-image-store.s3.amazonaws.com/0/184209/ab7fac3e-debf-2ac5-e99f-8b6257d19321.jpeg)

root / root でログインします。

ログインしたら、アカウントメニュー（ドロップダウン）から、"System Administration" を選択、サイドメニューの "Data export / Import" をクリックします。

そしたら、画面の下の方に Importっていう欄が出てくるので、さっきの SQL をこいつに食わせてしまいましょう。
![import.jpg](https://qiita-image-store.s3.amazonaws.com/0/184209/6f3adbcb-0411-979e-19ab-91dbfdb9fa38.jpeg)

遠慮なく「Import」ボタンを押してください。
ここで壊れても中身空っぽだから大丈夫なのです。
さぁ！

画面が切り替わりましたね？
文字がズラズラ～っと出ていますね？
はい。失敗です。
インポート用のSQLに問題があったようです。
最初に出るエラーはたぶん、INFORMATION_SCHEMA.LOB_BLOCKS のユニークインデックス制約に関することでしょう。
（移行元と移行先のバージョンによると思います）
これ、直すの非常に苦労しました。
結局、以下のようなエラーがたくさん出ます。
・インデックスキーの制約違反
・外部キーの制約違反
・テーブルは既に存在している
・など

今回のケースでは、インデックスキーの制約に関しては、もともとgitbucketで初期に作成しちゃうテーブルのうち、すでにデータが入ってるものに無理矢理INSERT仕様としてるからエラーになるみたいだったので。
最初にTABLEやらSEQUENCEやらを先に削除しとくと良さそうでした。
ただ、構造が同じテーブルならいいですけど、バージョンが上がってることでテーブルの構造がもし変わってると痛い事になりそうです。
なので、DROPするテーブルは最初にしっかりと構造を確認してから。
このバージョンのgitbucketの System Administration メニューには Database viewer があります。
これを使えばテーブルの状況や構造を見ることができますので、SQLファイルとにらめっこして構造に変わりがないかを見ておくと良いです。

```
DROP TABLE IF EXISTS INFORMATION_SCHEMA.LOB_BLOCKS;
DROP TABLE IF EXISTS INFORMATION_SCHEMA.LOB_BLOCKS;
DROP TABLE IF EXISTS O_0;
       : （中略）
DROP TABLE IF EXISTS O_61;
DROP VIEW IF EXISTS PUBLIC.ISSUE_OUTLINE_VIEW;

DROP SEQUENCE IF EXISTS PUBLIC.SYSTEM_SEQUENCE_F3363260_5E52_45EA_B00C_8DA03F753437;
       : （中略）
DROP SEQUENCE IF EXISTS PUBLIC.SYSTEM_SEQUENCE_981C4248_2793_4C3C_820E_A4701D46EC04;
```
INSERT が始まる前にずらーっと書きましょう。
SQLのファイルの中で、"CREATE ～" で始まる行を検索して、作成対象の名前を抜き出して DROP文に食わせるようにするだけです。（私はここまでを秀丸のファイル検索とマクロでやりました）

インポートをやり直すときは、私は面倒なので、 
1 tomcat 停止
2 .gitbucketのディレクトリを削除
3 tomcat 起動
の手順でやりました。
そうすると、時々gitbucketが起動しないことがあります。そんな時は、1の停止させる時点ですでに兆候がでていて、終了させるのにすごく時間がかかるのです。
そんな場合も、私は何度も言いますが**面倒**なので！ 

```
rm -rf /var/lib/tomcat/webapps/gitbucket
```
で対応しました。どうせ deployされるから消しても問題ないッス。

この後はかなり力技ですし、どこをどう直すかは環境によって全然違うと思うので
> 頑張ってください
としか言えません！

うちの環境では、以上の手順のあと、もともとあったアカウントでログインできることを確認、リポジトリのファイルをバックアップから戻して、正常に利用できるようになりました。

リポジトリのファイルを戻さなくてもなんとなく使えてしまうからうっかりログインできることだけ確認してメシ喰いに行ったら怒られたッス。

失敗体験のメモってことで、笑ってやってください。