PostgreSQL が起動しなくなることがある。ログには、
2012-06-15 09:52:59 GMT [6133]: FATAL: lock file "postmaster.pid" already exists
2012-06-15 09:52:59 GMT [6133]: HINT: Is another postmaster (PID 2225) running in data directory "/var/lib/pgsql/data"?
原因は、Apache httpd の時と同じ。
ソースコードでは次の部分。(PostgreSQL 9.0 以降は使ってないので知らない)
postgresql-8.4.11/src/backend/utils/init/miscinit.c:
static void
CreateLockFile(const char *filename, bool amPostmaster,
bool isDDLock, const char *refName)
{
/* ...snip... */
/*
* Check to see if the other process still exists
*
* If the PID in the lockfile is our own PID or our parent's PID, then
* the file must be stale (probably left over from a previous system
* boot cycle). We need this test because of the likelihood that a
* reboot will assign exactly the same PID as we had in the previous
* reboot. Also, if there is just one more process launch in this
* reboot than in the previous one, the lockfile might mention our
* parent's PID. We can reject that since we'd never be launched
* directly by a competing postmaster. We can't detect grandparent
* processes unfortunately, but if the init script is written
* carefully then all but the immediate parent shell will be
* root-owned processes and so the kill test will fail with EPERM.
*
* We can treat the EPERM-error case as okay because that error
* implies that the existing process has a different userid than we
* do, which means it cannot be a competing postmaster. A postmaster
* cannot successfully attach to a data directory owned by a userid
* other than its own. (This is now checked directly in
* checkDataDir(), but has been true for a long time because of the
* restriction that the data directory isn't group- or
* world-accessible.) Also, since we create the lockfiles mode 600,
* we'd have failed above if the lockfile belonged to another userid
* --- which means that whatever process kill() is reporting about
* isn't the one that made the lockfile. (NOTE: this last
* consideration is the only one that keeps us from blowing away a
* Unix socket file belonging to an instance of Postgres being run by
* someone else, at least on machines where /tmp hasn't got a
* stickybit.)
*
* Windows hasn't got getppid(), but doesn't need it since it's not
* using real kill() either...
*
* Normally kill() will fail with ESRCH if the given PID doesn't
* exist.
*/
if (other_pid != my_pid
#ifndef WIN32
&& other_pid != getppid()
#endif
)
{
if (kill(other_pid, 0) == 0 ||
(errno != ESRCH && errno != EPERM))
{
/* lockfile belongs to a live process */
ereport(FATAL,
(errcode(ERRCODE_LOCK_FILE_EXISTS),
errmsg("lock file \"%s\" already exists",
filename),
isDDLock ?
(encoded_pid < 0 ?
errhint("Is another postgres (PID %d) running in data directory \"%s\"?",
(int) other_pid, refName) :
errhint("Is another postmaster (PID %d) running in data directory \"%s\"?",
(int) other_pid, refName)) :
(encoded_pid < 0 ?
errhint("Is another postgres (PID %d) using socket file \"%s\"?",
(int) other_pid, refName) :
errhint("Is another postmaster (PID %d) using socket file \"%s\"?",
(int) other_pid, refName))));
}
}
ちょっと長いが、全てはコメント部に書いてある。やはり PID ファイルにあるプロセスの存在をチェックしているが、httpd との違いはプロセスの所有者まで見ていること。プロセスの所有者が異なれば、二重起動とは見なさない。
PostgreSQL が postgres ユーザーで起動するようになっている場合、postgres ユーザーで起動するプロセスは基本的に PostgreSQL しかないはず。よって PostgreSQL を複数起動しているのでもない限り、この現象に遭遇することはまずない。私の場合、PostgreSQL を起動している runit の logger プロセス(svlogd)を postgres ユーザーで起動しており、運良く:-)この現象に遭遇した。
PostgreSQL を複数起動させたり、postgres ユーザーで他にプロセスを起動しているのであれば、httpd の時と同じく起動スクリプトで PID ファイルを削除した方が良いだろう。
その場合、やはり二重起動チェックを自力で行うことになるが、pg_ctl status はその用途には役に立たない(たぶん上記のコードを通るのだと思われる)。その代わり PostgreSQL は $PGDATA が一意となるので、プロセスのコマンドラインや環境変数を見る(/proc/<PID>/{cmdline,environ})と良いかも知れない。
例によって私は runit を使っていて二重起動チェックとは無縁なので、実際に動くコードは載せられない。
0 件のコメント:
コメントを投稿
注: コメントを投稿できるのは、このブログのメンバーだけです。