Skip to content

Commit e1011e1

Browse files
committed
Modify LOCK to LOCK-NOWAIT-and-loop at swap tables to avoid holding exclusive locks long time. Suggested by Kenny Gorman.
1 parent 942180c commit e1011e1

File tree

6 files changed

+849
-680
lines changed

6 files changed

+849
-680
lines changed

bin/pg_reorg.c

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ typedef struct reorg_index
7474

7575
static void reorg_all_databases(const char *orderby);
7676
static bool reorg_one_database(const char *orderby, const char *table);
77-
static void reorg_one_table(const reorg_table *table, const char* orderby);
77+
static void reorg_one_table(const reorg_table *table, const char *orderby);
7878

7979
static void reconnect(void);
8080
static void disconnect(void);
@@ -93,6 +93,13 @@ static void PrintVersion(void);
9393
static char *getstr(PGresult *res, int row, int col);
9494
static Oid getoid(PGresult *res, int row, int col);
9595

96+
#define SQLSTATE_INVALID_SCHEMA_NAME "3F000"
97+
#define SQLSTATE_LOCK_NOT_AVAILABLE "55P03"
98+
99+
static bool sqlstate_equals(PGresult *res, const char *state)
100+
{
101+
return strcmp(PQresultErrorField(res, PG_DIAG_SQLSTATE), state) == 0;
102+
}
96103

97104
static const char *progname = NULL;
98105
static bool echo = false;
@@ -390,8 +397,7 @@ reorg_one_database(const char *orderby, const char *table)
390397

391398
if (PQresultStatus(res) != PGRES_TUPLES_OK)
392399
{
393-
const char *state = PQresultErrorField(res, PG_DIAG_SQLSTATE);
394-
if (state && strcmp(state, "3F000") == 0)
400+
if (sqlstate_equals(res, SQLSTATE_INVALID_SCHEMA_NAME))
395401
{
396402
/* Schema reorg does not exist. Skip the database. */
397403
ret = false;
@@ -657,8 +663,32 @@ reorg_one_table(const reorg_table *table, const char *orderby)
657663
if (verbose)
658664
fprintf(stderr, "---- swap ----\n");
659665

660-
command("BEGIN ISOLATION LEVEL READ COMMITTED", 0, NULL);
661-
command(table->lock_table, 0, NULL);
666+
for (;;)
667+
{
668+
command("BEGIN ISOLATION LEVEL READ COMMITTED", 0, NULL);
669+
res = execute_nothrow(table->lock_table, 0, NULL);
670+
if (PQresultStatus(res) == PGRES_COMMAND_OK)
671+
{
672+
PQclear(res);
673+
break;
674+
}
675+
else if (sqlstate_equals(res, SQLSTATE_LOCK_NOT_AVAILABLE))
676+
{
677+
/* retry if lock conflicted */
678+
PQclear(res);
679+
command("ROLLBACK", 0, NULL);
680+
sleep(1);
681+
continue;
682+
}
683+
else
684+
{
685+
/* exit otherwise */
686+
printf("%s", PQerrorMessage(current_conn));
687+
PQclear(res);
688+
exit_with_cleanup(1);
689+
}
690+
}
691+
662692
apply_log(table, 0);
663693
params[0] = utoa(table->target_oid, buffer);
664694
command("SELECT reorg.reorg_swap($1)", 1, params);
@@ -761,7 +791,7 @@ execute_nothrow(const char *query, int nParams, const char **params)
761791
}
762792

763793
/*
764-
* execute - Execute a SQL and discard the result, or exit() if failed.
794+
* execute - Execute a SQL and return the result, or exit() if failed.
765795
*/
766796
static PGresult *
767797
execute(const char *query, int nParams, const char **params)
@@ -834,7 +864,6 @@ static void
834864
PrintVersion(void)
835865
{
836866
fprintf(stderr, "pg_reorg " REORG_VERSION "\n");
837-
return;
838867
}
839868

840869
/*

doc/index-ja.html

Lines changed: 123 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,123 @@
1-
<?xml version="1.0" encoding="UTF-8"?>
2-
<!DOCTYPE html
3-
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4-
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5-
6-
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
7-
<head>
8-
<link rel="icon" type="image/png" href="http://pgfoundry.org/images/elephant-icon.png" />
9-
<link rel="stylesheet" type="text/css" href="style.css" />
10-
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
11-
<title>pg_reorg: Project Home Page</title>
12-
</head>
13-
14-
<body>
15-
<center><img style="border: none; margin-left: auto; margin-right: auto; " src="http://pgfoundry.org/images/elephantSmall.png" height="75" width="75" />
16-
<hr />
17-
<h1>pg_reorg ホームページへようこそ</h1>
18-
<hr />
19-
</center>
20-
<p>
21-
pg_reorg は PostgreSQL のテーブルを再編成するシェルコマンドです。
22-
共有ロックや排他ロックを取得しないため、再編成中であっても行の参照や更新を行うことができます。
23-
このモジュールは CLUSTER や VACUUM FULL コマンドのより良い代替になります。
24-
</p>
25-
<p>この pg_reorg プロジェクトは <a href="http://www.postgresql.org">PostgreSQL</a> コミュニティによる <a href="http://pgfoundry.org">pgFoundry</a> の中の<a href="http://pgfoundry.org/projects/reorg">プロジェクト</a>です。</p>
26-
<ul>
27-
<li><a href="http://pgfoundry.org/frs/?group_id=1000411">ダウンロード</a> : ソースコードのほか、Windows 用バイナリもダウンロードできます。</li>
28-
<li><a href="http://pgfoundry.org/tracker/?group_id=1000411">バグレポート</li></li>
29-
<li><a href="http://pgfoundry.org/mail/?group_id=1000411">メーリングリスト</a> への参加</li>
30-
</ul>
31-
<div>
32-
<a href="index.html">Here is an English page.</a>
33-
</div>
34-
<hr />
35-
36-
<p>
37-
<a href="pg_reorg-ja.html">ドキュメントはこちら</a>
38-
</p>
39-
40-
<hr />
41-
<div align="right">
42-
Copyright (c) 2008-2009, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
43-
</div>
44-
45-
<!-- PLEASE LEAVE "Powered By GForge" on your site -->
46-
<br />
47-
<center>
48-
<a href="http://gforge.org/"><img src="http://gforge.org/images/pow-gforge.png"
49-
alt="Powered By GForge Collaborative Development Environment" border="0" /></a>
50-
</center>
51-
52-
</body>
53-
</html>
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!DOCTYPE html
3+
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5+
6+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
7+
<head>
8+
<link rel="icon" type="image/png" href="http://pgfoundry.org/images/elephant-icon.png" />
9+
<link rel="stylesheet" type="text/css" href="style.css" />
10+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
11+
<title>pg_reorg: Project Home Page</title>
12+
</head>
13+
14+
<body>
15+
<center><img style="border: none; margin-left: auto; margin-right: auto; " src="http://pgfoundry.org/images/elephantSmall.png" height="75" width="75" />
16+
<hr />
17+
<h1>pg_reorg ホームページへようこそ</h1>
18+
<hr />
19+
</center>
20+
<p>
21+
pg_reorg は PostgreSQL のテーブルを再編成するシェルコマンドです。
22+
共有ロックや排他ロックを取得しないため、再編成中であっても行の参照や更新を行うことができます。
23+
このモジュールは CLUSTER や VACUUM FULL コマンドのより良い代替になります。
24+
</p>
25+
<p>この pg_reorg プロジェクトは <a href="http://www.postgresql.org">PostgreSQL</a> コミュニティによる <a href="http://pgfoundry.org">pgFoundry</a> の中の<a href="http://pgfoundry.org/projects/reorg">プロジェクト</a>です。</p>
26+
<ul>
27+
<li><a href="http://pgfoundry.org/frs/?group_id=1000411">ダウンロード</a> : ソースコードのほか、Windows 用バイナリもダウンロードできます。</li>
28+
<li><a href="http://pgfoundry.org/tracker/?group_id=1000411">バグレポート</li></li>
29+
<li><a href="http://pgfoundry.org/mail/?group_id=1000411">メーリングリスト</a> への参加</li>
30+
</ul>
31+
<div>
32+
<a href="index.html">Here is an English page.</a>
33+
</div>
34+
<hr />
35+
36+
<h2>ドキュメント</h2>
37+
<p>
38+
<a href="pg_reorg-ja.html">ドキュメントはこちら</a>
39+
</p>
40+
41+
<h2>実行時間</h2>
42+
<p>
43+
pg_reorg とclusterdb の比較に示します。
44+
断片化のないソートされた状態 (not fragmented) では clusterdb のほうが高速ですが、完全に断片化した状態 (fully fragmented) では pg_reorg が大幅に高速です。
45+
一般的に、再編成は断片化が進行した状態で実施されることを考えると、pg_reorg は clusterdb よりも実行時間が短いと言えます。
46+
</p>
47+
48+
<center>
49+
<div style="margin: 2em">
50+
<img src="result.png" />
51+
</div>
52+
53+
<table border="1">
54+
<caption>測定環境</caption>
55+
<tr>
56+
<th>大項目</th>
57+
<th>小項目</th>
58+
<th>環境</th>
59+
</tr>
60+
<tr>
61+
<td rowspan="3">ハードウェア</td>
62+
<td>CPU</td>
63+
<td>2 × Xeon 5160 3.00GHz (Dual core)</td>
64+
</tr>
65+
<tr>
66+
<td>メモリ</td>
67+
<td>2GB</td>
68+
</tr>
69+
<tr>
70+
<td>ストレージ</td>
71+
<td>Ultra320 SCSI, 15000rpm (220GB)</td>
72+
</tr>
73+
<tr>
74+
<td rowspan="4">ソフトウェア</td>
75+
<td>OS</td>
76+
<td>RHEL 5.2 (64bit) 2.6.18-92.el5</td>
77+
</tr>
78+
<tr>
79+
<td>DB</td>
80+
<td>PostgreSQL 8.3.3</td>
81+
</tr>
82+
<tr>
83+
<td>pg_reorg</td>
84+
<td>1.0.0</td>
85+
</tr>
86+
<tr>
87+
<td>clusterdb</td>
88+
<td>clusterdb (PostgreSQL) 8.3.3</td>
89+
</tr>
90+
<tr>
91+
<td rowspan="2">データ</td>
92+
<td>スキーマ</td>
93+
<td><code><pre>CREATE TABLE tbl (
94+
id bigserial PRIMARY KEY,
95+
seqkey timestamp NOT NULL,
96+
rndkey timestamp NOT NULL,
97+
filler char(75) NOT NULL
98+
);
99+
CREATE INDEX idx_seq ON tbl (seqkey);
100+
CREATE INDEX idx_rnd ON tbl (rndkey);</pre></code></td>
101+
</tr>
102+
<tr>
103+
<td>件数</td>
104+
<td>1650万件 (約2GB)</td>
105+
</tr>
106+
</table>
107+
108+
</center>
109+
110+
<hr />
111+
<div align="right">
112+
Copyright (c) 2008-2009, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
113+
</div>
114+
115+
<!-- PLEASE LEAVE "Powered By GForge" on your site -->
116+
<br />
117+
<center>
118+
<a href="http://gforge.org/"><img src="http://gforge.org/images/pow-gforge.png"
119+
alt="Powered By GForge Collaborative Development Environment" border="0" /></a>
120+
</center>
121+
122+
</body>
123+
</html>

0 commit comments

Comments
 (0)