Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Greenplum
Gpdb
提交
48789804
G
Gpdb
项目概览
Greenplum
/
Gpdb
通知
7
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
G
Gpdb
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
48789804
编写于
5月 17, 2017
作者:
H
Heikki Linnakangas
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Set indcheckxmin in master, if it was set on any segment.
Fixes github issue #1774.
上级
3b4dea5e
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
170 addition
and
1 deletion
+170
-1
src/backend/commands/indexcmds.c
src/backend/commands/indexcmds.c
+97
-1
src/test/isolation/expected/create_index_hot.out
src/test/isolation/expected/create_index_hot.out
+25
-0
src/test/isolation/isolation_schedule
src/test/isolation/isolation_schedule
+1
-0
src/test/isolation/specs/create_index_hot.spec
src/test/isolation/specs/create_index_hot.spec
+47
-0
未找到文件。
src/backend/commands/indexcmds.c
浏览文件 @
48789804
...
...
@@ -68,6 +68,7 @@
#include "cdb/cdbcat.h"
#include "cdb/cdbrelsize.h"
#include "cdb/cdboidsync.h"
#include "gp-libpq-fe.h"
/* non-export function prototypes */
static
void
CheckPredicate
(
Expr
*
predicate
);
...
...
@@ -85,6 +86,96 @@ static bool relationHasPrimaryKey(Relation rel);
static
bool
relationHasUniqueIndex
(
Relation
rel
);
/*
* Helper function, to check indcheckxmin for an index on all segments, and
* set it on the master if it was set on any segment.
*
* If CREATE INDEX creates a "broken" HOT chain, the new index must not be
* used by new queries, with an old snapshot, that would need to see the old
* values. See src/backend/access/heap/README.HOT. This is enforced by
* setting indcheckxmin in the pg_index row. In GPDB, we use the pg_index
* row in the master for planning, but all the data is stored in the
* segments, so indcheckxmin must be set in the master, if it's set in any
* of the segments.
*/
static
void
cdb_sync_indcheckxmin_with_segments
(
Oid
indexRelationId
)
{
CdbPgResults
cdb_pgresults
=
{
NULL
,
0
};
int
i
;
char
cmd
[
100
];
bool
indcheckxmin_set_in_any_segment
;
Assert
(
Gp_role
==
GP_ROLE_DISPATCH
&&
!
IsBootstrapProcessingMode
());
/*
* Query all the segments, for their indcheckxmin value for this index.
*/
snprintf
(
cmd
,
sizeof
(
cmd
),
"select indcheckxmin from pg_catalog.pg_index where indexrelid = '%u'"
,
indexRelationId
);
CdbDispatchCommand
(
cmd
,
DF_WITH_SNAPSHOT
,
&
cdb_pgresults
);
indcheckxmin_set_in_any_segment
=
false
;
for
(
i
=
0
;
i
<
cdb_pgresults
.
numResults
;
i
++
)
{
char
*
val
;
if
(
PQresultStatus
(
cdb_pgresults
.
pg_results
[
i
])
!=
PGRES_TUPLES_OK
)
{
cdbdisp_clearCdbPgResults
(
&
cdb_pgresults
);
elog
(
ERROR
,
"could not fetch indcheckxmin from segment"
);
}
if
(
PQntuples
(
cdb_pgresults
.
pg_results
[
i
])
!=
1
||
PQnfields
(
cdb_pgresults
.
pg_results
[
i
])
!=
1
||
PQgetisnull
(
cdb_pgresults
.
pg_results
[
i
],
0
,
0
))
elog
(
ERROR
,
"unexpected shape of result set for indcheckxmin query"
);
val
=
PQgetvalue
(
cdb_pgresults
.
pg_results
[
i
],
0
,
0
);
if
(
val
[
0
]
==
't'
)
{
indcheckxmin_set_in_any_segment
=
true
;
break
;
}
else
if
(
val
[
0
]
!=
'f'
)
elog
(
ERROR
,
"invalid boolean value received from segment: %s"
,
val
);
}
cdbdisp_clearCdbPgResults
(
&
cdb_pgresults
);
/*
* If indcheckxmin was set on any segment, also set it in the master.
*/
if
(
indcheckxmin_set_in_any_segment
)
{
Relation
pg_index
;
HeapTuple
indexTuple
;
Form_pg_index
indexForm
;
pg_index
=
heap_open
(
IndexRelationId
,
RowExclusiveLock
);
indexTuple
=
SearchSysCacheCopy
(
INDEXRELID
,
ObjectIdGetDatum
(
indexRelationId
),
0
,
0
,
0
);
if
(
!
HeapTupleIsValid
(
indexTuple
))
elog
(
ERROR
,
"cache lookup failed for index %u"
,
indexRelationId
);
indexForm
=
(
Form_pg_index
)
GETSTRUCT
(
indexTuple
);
if
(
!
indexForm
->
indcheckxmin
)
{
indexForm
->
indcheckxmin
=
true
;
simple_heap_update
(
pg_index
,
&
indexTuple
->
t_self
,
indexTuple
);
CatalogUpdateIndexes
(
pg_index
,
indexTuple
);
}
heap_freetuple
(
indexTuple
);
heap_close
(
pg_index
,
RowExclusiveLock
);
}
}
/*
* DefineIndex
* Creates a new index.
...
...
@@ -530,7 +621,6 @@ DefineIndex(RangeVar *heapRelation,
else
heap_close
(
rel
,
heap_lockmode
);
/* create the index on the QEs first, so we can get their stats when we create on the QD */
if
(
shouldDispatch
)
{
cdb_sync_oid_to_segments
();
...
...
@@ -559,6 +649,7 @@ DefineIndex(RangeVar *heapRelation,
* (For a concurrent build, we do this later, see below.)
*/
if
(
shouldDispatch
)
{
CdbDispatchUtilityStatement
((
Node
*
)
stmt
,
DF_CANCEL_ON_ERROR
|
DF_WITH_SNAPSHOT
|
...
...
@@ -566,6 +657,11 @@ DefineIndex(RangeVar *heapRelation,
GetAssignedOidsForDispatch
(),
NULL
);
/* Set indcheckxmin in the master, if it was set on any segment */
if
(
!
indexInfo
->
ii_BrokenHotChain
)
cdb_sync_indcheckxmin_with_segments
(
indexRelationId
);
}
return
;
/* We're done, in the standard case */
}
...
...
src/test/isolation/expected/create_index_hot.out
0 → 100644
浏览文件 @
48789804
Parsed test spec with 2 sessions
starting permutation: s2begin s2select s1update s1createindexonc s2select s2forceindexscan s2select
step s2begin: BEGIN ISOLATION LEVEL SERIALIZABLE;
step s2select: select '#' as expected, c from hot where c = '#'
union all
select '$', c from hot where c = '$';
expected c
# #
step s1update: update hot set c = '$' where c = '#';
step s1createindexonc: create index idx_c on hot (c);
step s2select: select '#' as expected, c from hot where c = '#'
union all
select '$', c from hot where c = '$';
expected c
# #
step s2forceindexscan: set enable_indexscan=on; set enable_seqscan=off;
step s2select: select '#' as expected, c from hot where c = '#'
union all
select '$', c from hot where c = '$';
expected c
# #
src/test/isolation/isolation_schedule
浏览文件 @
48789804
...
...
@@ -5,3 +5,4 @@ test: heap-serializable-vacuum
test: ao-serializable-read
test: ao-serializable-vacuum
test: ao-insert-eof
test: create_index_hot
src/test/isolation/specs/create_index_hot.spec
0 → 100644
浏览文件 @
48789804
#
# Test behavior with HOT and CREATE INDEX.
#
# If CREATE INDEX creates a "broken" HOT chain, the new index must not be
# used by new queries, with an old snapshot, that would need to see the
# old values. See src/backend/access/heap/README.HOT.
#
# This is enforced by setting indcheckxmin in the pg_index row. In GPDB,
# we use the pg_index row in the master for planning, but all the data is
# stored in the segments, so indcheckxmin must be set in the master, if
# it's set in any of the segments.
setup
{
create table hot (dummy int, a int, b char, c char);
create index idx_a on hot (a);
insert into hot values (1,1,'A','#');
}
teardown
{
drop table hot;
}
# Update a row, and create an index on the updated column. This produces
# a broken HOT chain.
session "s1"
step "s1update" { update hot set c = '$' where c = '#'; }
step "s1createindexonc" { create index idx_c on hot (c); }
session "s2"
step "s2begin" { BEGIN ISOLATION LEVEL SERIALIZABLE; }
step "s2select" { select '#' as expected, c from hot where c = '#'
union all
select '$', c from hot where c = '$'; }
step "s2forceindexscan" { set enable_indexscan=on; set enable_seqscan=off; }
teardown { abort; }
permutation
"s2begin"
"s2select"
"s1update"
"s1createindexonc"
"s2select"
"s2forceindexscan"
"s2select"
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录