write ahead log

ロールフォワード用

システム起動時にUNEXPECTED INCONSISTENCYエラーが発生した時の対処

サーバを再起動すると, 見たくないものを見てしまった.

Checking filesystems

/12: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.
            (i.e., without -a or -p options)

            *** An error occurred during the file system check.
            *** Dropping you to a shell; the system will reboot
            *** when you leave the shell.
            Give root password for maintenance
            (or type Control-D to continue):

人間とは困ったもので, こういう時にはじめてバックアップの不確実さに気づくのだ.

なんとかする

何がともあれメッセージ通りに従うことにする.

メッセージによるとファイルシステムのサイズが物理デバイスのブロックと一致していないらしい.

(※結果的に今回はLVMボリューム割り当て変更時のミスだった.もしその他の理由でブロックサイズが一致していなければハード故障の可能性があるので最善の対処は別かもしれない.)

/dev/mapper/VolGroup-lv_home: The filesystem size (according to the superblock) is 2621440 blocks  
The physical size of the device is 2500608 blocks  
Either the superblock or the partition table is likely to be corrupt!

/dev/mapper/VolGroup-lv_home: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.
(i.e., without -a or -p options)
                                [FAILED]

            *** An error occurred during the file system check.
            *** Dropping you to a shell; the system will reboot
            *** when you leave the shell.
            Give root password for maintenance
            (or type Control-D to continue):

上記画面でrootのパスワードを入力する.

Give root password for maintenance
(or type Control-D to continue): [パスワードを入力]

するとrootでログインできる.

(Repair filesystem) 1# 

/etc/fstabを見ると対象のファイルシステムがわかるので確認しておく.

# cat /etc/fstab
[]
/dev/mapper/VolGroup-lv_home   /home     ext4    defaults    1    2
[]

メッセージの指示通り, fsckをかける.

# fsck -t ext4 /dev/mapper/VolGroup-lv_home

すると以下のメッセージが出てくる.
ビビりながらnを入力する.

fsck from util-linux-ng 2.17.2
e2fsck 1.41.12 (17-May-2010)
The filesystem size (according to the superblock) is 2621440 blocks
The physical size of the device is 2500608 blocks
Either the superblock or the partition table is likely to be corrupt!
Abort<y>? [nを入力]

色々出るが, Yで. 以下のようなメッセージが出ると思う.

/12: 107499/2560864 files (1.5% non-contiguous), 83124/2621440 blocks

とりあえずこれで次のステップへ進める.

ファイルシステムの認識と物理ブロックが異なるということだったので,ファイルシステムの認識を是正する.

# resize2fs /dev/mapper/VolGroup-lv_home 2500608 [<= サイズは上記のphysicalに合わせる]

最後にもう一度fsckをかける.fをつけるとcleanな状況でも強制的にかけるらしい.

# fsck -f /dev/maper/VolGroup-lv_home 

締めにリブートする

# reboot

上記まででとりあえずブートできた.

ただ,すぐバックアップを取らないと悲惨なことになるので....

参考

vpsget ディスクイメージを縮小する システム起動時にUNEXPECTED INCONSISTENCYエラーが発生した場合は

golangでプログラムをデーモン化する(ように見せる)

golang標準ではデーモンを作れないという話を聞いたことがありましたが,
デーモン化対応は続いているみたいです.

さて、困った.標準でやりたかったなー.と思っていたのですが,とりあえず作成したプログラム単体でできるように以下の方法を取りました.

  1. os.Args[0]で自身のファイルパスを得る
  2. exec.Command.Start()で外部プログラムとして実行する

ざっくり以下のようになります.

if デーモン化する == true {
    cmd := exec.Command(os.Args[0], "--server")
    cmd.Start()
    return
}
if --serverオプションが指定されていた == true {
    デーモン実行するときに行う処理
}

終了する時にプロセスIDを探してkillしないとならないのがちょっと面倒ですが
要件によってはこれで十分かと思います.

以下は大変参考になりました.ありがたい.

「ほい、これ」ってファイルを渡せる Hoi というツールをつくった

上記のプログラムのgithub


2017/04/27 追記

まともにデーモン化する方法も書いた.

UbuntuでUpstartを使ってプログラムをデーモン化する

golangでWindows10上でSQLite3を使う

golangでSQLite3を使う情報は多いのだけれど,
Windowsで使うとなると一気に情報が減ってしまう.

事前準備

ちょっと面倒ですが,まずはgccが必要です.
以下からダウンロードします.

tdm-gcc

msys2なんかでよく使うMinGWではダメっぽいです.
(msys2使ってるので良い方法があるなら知りたいです)

ライブラリ作者のmattnさんもgolangのビルドにはmsys2使ってないっぽいですね.
github - issues -

そういうわけでcmd.exeでgo getします.

C:\Users\Twinbird>go get github.com/mattn/go-sqlite3

これで準備はOKです.

サンプルコード

見た方が早いですね.

package main

import (
    "os"
    "database/sql"
    _ "github.com/mattn/go-sqlite3"
)

func main() {
    dbfile := "./test.db"

    os.Remove(dbfile)

    db, err := sql.Open("sqlite3", dbfile)
    if err != nil { panic(err) }

    // 単発で実行
    _, err = db.Exec(`CREATE TABLE "messages" ("id" INTEGER PRIMARY KEY AUTOINCREMENT, "msg" VARCHAR(255))`)
    if err != nil { panic(err) }

    // 単発で実行
    _, err = db.Exec(`
      INSERT INTO "messages" ("msg") VALUES(?)`,
        "こんにちは",
    )
    if err != nil { panic(err) }

    // プリペアステートメント
    stmt, err := db.Prepare(`INSERT INTO "messages" ("msg") VALUES(?)`)
    if err != nil { panic(err) }

    if _, err = stmt.Exec("世界"); err != nil { panic(err) }
    if _, err = stmt.Exec("Hello"); err != nil { panic(err) }
    if _, err = stmt.Exec("World"); err != nil { panic(err) }

    stmt.Close()

    db.Close()
}

ビルド

これもcmd.exeでやりましょう.

C:\Users\Twinbird\samples>go build

実行と確認

実行はmsys2環境でもできます.

SQLiteで確認してみましょう.

SQLite version 3.10.0 2016-01-06 11:01:07
Enter ".help" for usage hints.
sqlite> .tables
messages
sqlite> select * from messages;
1|こんにちは
2|世界
3|Hello
4|World

うまくいきました.

msys2-launcherがすごい便利

msys2ってタスクバーにピン留めできんのかーと思っていたら
twitterでmattnさんが以下の様な事をつぶやいておられました.

探してみるとこりゃ便利そうです.

github - msys2-launcher

入れてみる

pacmanでお手軽に入れられます.

pacman -Sy msys2-launcher

msys64(64bit環境の場合)の配下にmsys2.exeが生成されているのでこれを使えばよいです.
バッチリタスクバーにピン留めできます.

参考

MSYS2 users list

Eclipseでビルド時に"Java heap space"が発生する

Eclipseでビルドするとすぐメモリ不足エラーが発生する.

大体は"GC"とか"heap"とかがメッセージに入る.

(だからロースペックマシンをよく使う私はJavaはあまり使いたくない....)

解決するにはJavaVMをちょっとチューニングとよい.
(メモリがあればの話ではありますが)

eclipse.iniを以下のように変更

~~~~~
中略
~~~~~
--launcher.XXMaxPermSize
1024M # 512Mから変更
~~~~~
中略
~~~~~
-Xms512m #256から変更

これでEclipseを再起動すればそこそこそれっぽく動く.
割り当ての変更だけなので実メモリが小さいと遅くなりますが.

ubuntuでtmuxを使うとlsで色がつかなくなった

現象

ubuntuでtmuxを使うとlsで色がつかなくなった.

なんでだ?と思ったら下記のコマンドでは色がつく.

ls --color=auto

どうも.bashrcが読み込まれていないらしい.(Ubuntuは.bashrcでalias入るので色がつく)
地味に困る.

対処

色々探したらこのサイトの一番下の追記に記載があった.感謝.

.tmux.confに以下を追記.

set-option -g default-shell /bin/bash
set-option -g default-command /bin/bash

bash以外のユーザさんは適宜変えてください.

これで元通り便利になった.

net/httpのhttp.HandlerFuncをラップするテクニック

golangでnet/httpを使うと下記のようなコードを書くことになる.

func main() {
    http.HandleFunc("/foo", fooHandler)
    http.HandleFunc("/bar", barHandler)

    http.ListenAndServe(":8080", nil)
}

ここで全てのハンドラの前に認証を追加したいなどと考えると,各ハンドラ関数に処理を書くのが明らかに無駄だと気づく.

こういう時にはHandlerFuncをwrapするテクニックが一般的なようだ.

func main() {
    http.HandleFunc("/foo", authenticate(fooHandler)) // authenticateでラップする.
    http.HandleFunc("/bar", authenticate(barHandler)) // authenticateでラップする.

    http.ListenAndServe(":8080", nil)
}

func authenticate(fn http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        log.Println("before process") // 処理の前の共通処理
        fn(w, r)
        log.Println("after process") // 処理の後の共通処理
    }
}

シンプルで良い.