[pgsql-jp: 31030] Re: TL8 AMD64で共有メモリに上限?

Tatsuo Ishii t-ishii @ sra.co.jp
2003年 9月 10日 (水) 23:43:12 JST


石井です.フォローが遅くなりました.

> >失礼.見たいのは ipcs -l -sの結果でした.
> >
> ありゃ。今、マシンはバラしてあるんですが、あとで報告しましょうか?

今回の場合,そんなに本質的な情報ではないので,可能ならばで結構です.

> >明らかにTLD AMD64上のPostgreSQLは異常な動作をしていますね.32bitモード
> >でコンパイルしたPostgreSQLでも動作がおかしいということは,TLD AMD64に
> >問題があるような気がします.残念ながらここから先はデバッガでも使わない
> >とちょっとわからないですね.
> >--
> 
> そうですか。デバッガでコードを追うようなことは、もう10数年やってないし、
> UNIX系OSの知識も乏しいのですが、ちょっとやってみたい気もします。
> 厚かましいですが、簡単に手ほどきして、いただけませんか?
> そんな、甘いもんじゃないですかね?

なぜ不具合が起きているかはすぐにわかると思いますが,対処法がわかるかど
うかはまた別問題です:-)それでもよければ,ということで...

まずソースコードをしらみつぶしに当るのは効率悪すぎるので,エラーメッセー
ジであたりをつけます.

cd postgresql-7.3.4/src/backend
find . -name '*.c' -print|xargs grep IpcSemaphoreCreate
./port/sysv_sema.c:76:static IpcSemaphoreId IpcSemaphoreCreate(int numSems);
./port/sysv_sema.c:116:		fprintf(stderr, "IpcSemaphoreCreate: semget(key=%d, num=%d, 0%o) failed: %s\n",
./port/sysv_sema.c:218:IpcSemaphoreCreate(int numSems)
./port/sysv_sema.c:359:		mySemaSets[numSemaSets] = IpcSemaphoreCreate(SEMAS_PER_SET);
./port/pg_sema.c:76:static IpcSemaphoreId IpcSemaphoreCreate(int numSems);
./port/pg_sema.c:116:		fprintf(stderr, "IpcSemaphoreCreate: semget(key=%d, num=%d, 0%o) failed: %s\n",
./port/pg_sema.c:218:IpcSemaphoreCreate(int numSems)
./port/pg_sema.c:359:		mySemaSets[numSemaSets] = IpcSemaphoreCreate(SEMAS_PER_SET);

怪しそうなのは ./port/sysv_sema.c:116: ではないかとあたりがつきます(ち
なみに,Linuxの場合,./port/pg_sema.cはpg_sema.cへのリンク).そのあた
りはstatic IpcSemaphoreId InternalIpcSemaphoreCreate(IpcSemaphoreKey
semKey, int numSems)なんですが,コードを見ると,単にsemget()しているだ
けです.semget()自体がおかしいと言うわけでもなさそうなので,その上位関
数へと探索の手を延します.すると,230行目あたりの

		semId = InternalIpcSemaphoreCreate(nextSemaKey,	numSems + 1);

が目につきます.InternalIpcSemaphoreCreateが1回呼ばれるとsemget()が1回
呼ばれるようなので,どうもなんらかの理由でInternalIpcSemaphoreCreateが
呼ばれすぎているのではないか,と考えます.さらにこれを呼び出している関
数は同じファイルの中の以下です.

PGSemaphoreCreate(PGSemaphore sema)
{
	/* Can't do this in a backend, because static state is postmaster's */
	Assert(!IsUnderPostmaster);

	if (nextSemaNumber >= SEMAS_PER_SET)
	{
		/* Time to allocate another semaphore set */
		if (numSemaSets >= maxSemaSets)
			elog(PANIC, "PGSemaphoreCreate: too many semaphores created");
		mySemaSets[numSemaSets] = IpcSemaphoreCreate(SEMAS_PER_SET);
		numSemaSets++;
		nextSemaNumber = 0;
	}
	/* Assign the next free semaphore in the current set */
	sema->semId = mySemaSets[numSemaSets - 1];
	sema->semNum = nextSemaNumber++;
	/* Initialize it to count 1 */
	IpcSemaphoreInitialize(sema->semId, sema->semNum, 1);
}


でも,これも関数呼び出しごとに1回セマフォをgetしているだけなので,更に
これを呼び出している関数を探すと,storage/lmgr/proc.cにInitProcGlobal
というのがあります.この中で,

		for (i = 0; i < maxBackends; i++)
		{
			PGPROC	   *proc;

			proc = (PGPROC *) ShmemAlloc(sizeof(PGPROC));
			if (!proc)
				elog(FATAL, "cannot create new proc: out of memory");
			MemSet(proc, 0, sizeof(PGPROC));
			PGSemaphoreCreate(&proc->sem);
			proc->links.next = ProcGlobal->freeProcs;
			ProcGlobal->freeProcs = MAKE_OFFSET(proc);
		}

のようなことをやっています.ここでmaxBackendsは同時接続数
(max_connections)です.つまり,同時接続数分だけセマフォを取得している
わけです.どうもmaxBackendsよりも余計にこのループを回っているような気
がするのですが,とりあえずこのあたりを調べてみてはいかがでしょう?
--
Tatsuo Ishii



pgsql-jp メーリングリストの案内