Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-02-14 Thread Michael Paquier
On Sun, Feb 14, 2021 at 08:10:50PM -0600, Justin Pryzby wrote:
> Isn't this dead code ?

Nope, it's not dead.  Those two code paths can be hit when attempting
a reidex with a tablespace move directly on toast tables and indexes,
see:
=# create table aa (a text);
CREATE TABLE
=# select relname from pg_class where oid > 16000;
   relname
--
 aa
 pg_toast_16385
 pg_toast_16385_index
(3 rows)
=# reindex (concurrently, tablespace pg_default) table
  pg_toast.pg_toast_16385;
ERROR:  0A000: cannot move system relation "pg_toast_16385"
LOCATION:  ReindexRelationConcurrently, indexcmds.c:3295
=# reindex (concurrently, tablespace pg_default) index
  pg_toast.pg_toast_16385_index;
ERROR:  0A000: cannot move system relation "pg_toast_16385_index"
LOCATION:  ReindexRelationConcurrently, indexcmds.c:3439

It is easy to save the relation name using \gset in a regression test,
but we had better keep a reference to the relation name in the error
message so this would not be really portable.  Using a PL function to
do that with a CATCH block would not work either as CONCURRENTLY
cannot be run in a transaction block.  This leaves 090_reindexdb.pl,
but I was not really convinced that this was worth the extra test
cycles (I am aware of the --tablespace option missing in reindexdb,
someone I know was trying to get that done for the next CF).
--
Michael


signature.asc
Description: PGP signature


Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-02-14 Thread Justin Pryzby
On Thu, Feb 04, 2021 at 03:38:39PM +0900, Michael Paquier wrote:
> On Wed, Feb 03, 2021 at 07:54:42PM +0900, Michael Paquier wrote:
> > Not sure I like that.  Here is a proposal:
> > "it is recommended to separately use ALTER TABLE ONLY on them so as
> > any new partitions attached inherit the new tablespace value."
> 
> So, I have done more work on this stuff today, and applied that as of
> c5b2860.

> A second thing I have come back to is allow_system_table_mods for
> toast relations, and decided to just forbid TABLESPACE if attempting
> to use it directly on a system table even if allow_system_table_mods
> is true.  This was leading to inconsistent behaviors and weirdness in
> the concurrent case because all the indexes are processed in series
> after building a list.  As we want to ignore the move of toast indexes
> when moving the indexes of the parent table, this was leading to extra
> conditions that are not really worth supporting after thinking about
> it.  One other issue was the lack of consistency when using pg_global
> that was a no-op for the concurrent case but failed in the 
> non-concurrent case.  I have put in place more regression tests for
> all that.

Isn't this dead code ?

postgres=# REINDEX (CONCURRENTLY, TABLESPACE pg_global) TABLE pg_class;
ERROR:  0A000: cannot reindex system catalogs concurrently
LOCATION:  ReindexRelationConcurrently, indexcmds.c:3276

diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 127ba7835d..c77a9b2563 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -3260,73 +3260,66 @@ ReindexRelationConcurrently(Oid relationOid, 
ReindexParams *params)
{
if (IsCatalogRelationOid(relationOid))
ereport(ERROR,

(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 errmsg("cannot reindex 
system catalogs concurrently")));
 
...
 
-   if (OidIsValid(params->tablespaceOid) &&
-   IsSystemRelation(heapRelation))
-   ereport(ERROR,
-   
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-errmsg("cannot move 
system relation \"%s\"",
-   
RelationGetRelationName(heapRelation;
-
@@ -3404,73 +3397,66 @@ ReindexRelationConcurrently(Oid relationOid, 
ReindexParams *params)
if (IsCatalogRelationOid(heapId))
ereport(ERROR,

(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 errmsg("cannot reindex 
system catalogs concurrently")));
... 
 
-   if (OidIsValid(params->tablespaceOid) &&
-   IsSystemRelation(heapRelation))
-   ereport(ERROR,
-   
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-errmsg("cannot move 
system relation \"%s\"",
-   
get_rel_name(relationOid;
-
>From b4347c18bc732d30295c065ef71edaac65e68fe6 Mon Sep 17 00:00:00 2001
From: Justin Pryzby 
Date: Sun, 14 Feb 2021 19:49:52 -0600
Subject: [PATCH] Dead code: REINDEX (CONCURRENTLY, TABLESPACE ..):
 c5b286047cd698021e57a527215b48865fd4ad4e

---
 src/backend/commands/indexcmds.c | 14 --
 1 file changed, 14 deletions(-)

diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 127ba7835d..c77a9b2563 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -3260,73 +3260,66 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
 			{
 /*
  * In the case of a relation, find all its indexes including
  * toast indexes.
  */
 Relation	heapRelation;
 
 /* Save the list of relation OIDs in private context */
 oldcontext = MemoryContextSwitchTo(private_context);
 
 /* Track this relation for session locks */
 heapRelationIds = lappend_oid(heapRelationIds, relationOid);
 
 MemoryContextSwitchTo(oldcontext);
 
 if (IsCatalogRelationOid(relationOid))
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("cannot reindex system catalogs concurrently")));
 
 /* Open relation to get its indexes */
 if ((params->options & REINDEXOPT_MISSING_OK) != 0)
 {
 	heapRelation = try_table_open(relationOid,
   ShareUpdateExclusiveLock);
 	/* leave if relation does not exist */
 	

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-02-03 Thread Michael Paquier
On Wed, Feb 03, 2021 at 07:54:42PM +0900, Michael Paquier wrote:
> Not sure I like that.  Here is a proposal:
> "it is recommended to separately use ALTER TABLE ONLY on them so as
> any new partitions attached inherit the new tablespace value."

So, I have done more work on this stuff today, and applied that as of
c5b2860.  While reviewing my changes, I have noticed that I have
managed to break ALTER TABLE SET TABLESPACE which would have failed
when cascading to a toast relation, the extra check placed previously
in CheckRelationTableSpaceMove() being incorrect.  The most surprising
part was that we had zero in-core tests to catch this mistake, so I
have added an extra test to cover this scenario while on it.

A second thing I have come back to is allow_system_table_mods for
toast relations, and decided to just forbid TABLESPACE if attempting
to use it directly on a system table even if allow_system_table_mods
is true.  This was leading to inconsistent behaviors and weirdness in
the concurrent case because all the indexes are processed in series
after building a list.  As we want to ignore the move of toast indexes
when moving the indexes of the parent table, this was leading to extra
conditions that are not really worth supporting after thinking about
it.  One other issue was the lack of consistency when using pg_global
that was a no-op for the concurrent case but failed in the 
non-concurrent case.  I have put in place more regression tests for
all that.

Regarding the VACUUM and CLUSTER cases, I am not completely sure if
going through these for a tablespace case is the best move we can do,
as ALTER TABLE is able to mix multiple operations and all of them
require already an AEL to work.  REINDEX was different thanks to the
case of CONCURRENTLY.  Anyway, as a lot of work has been done here
already, I would recommend to create new threads about those two
topics.  I am also closing this patch in the CF app.
--
Michael


signature.asc
Description: PGP signature


Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-02-03 Thread Michael Paquier
On Wed, Feb 03, 2021 at 01:35:26PM +0300, Alexey Kondratov wrote:
> This check for OidIsValid() seems to be excessive, since you moved the whole
> ACL check under 'if (tablespacename != NULL)' here.

That's more consistent with ATPrepSetTableSpace().

> +SELECT relid, parentrelid, level FROM
> pg_partition_tree('tbspace_reindex_part_index')
> +  ORDER BY relid, level;
> +SELECT relid, parentrelid, level FROM
> pg_partition_tree('tbspace_reindex_part_index')
> +  ORDER BY relid, level;
> 
> Why do you do the same twice in a row? It looks like a typo. Maybe it was
> intended to be called for partitioned table AND index.

Yes, my intention was to show the tree of the set of tables.  It is
not really interesting for this test anyway, so let's just remove this
extra query.
--
Michael


signature.asc
Description: PGP signature


Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-02-03 Thread Michael Paquier
On Wed, Feb 03, 2021 at 12:53:42AM -0600, Justin Pryzby wrote:
> On Wed, Feb 03, 2021 at 03:37:39PM +0900, Michael Paquier wrote:
>> index 627b36300c..4ee3951ca0 100644
>> --- a/doc/src/sgml/ref/reindex.sgml
>> +++ b/doc/src/sgml/ref/reindex.sgml
>> @@ -293,8 +311,30 @@ REINDEX [ ( > class="parameter">option [, ...] ) ] { IN
>> respectively. Each partition of the specified partitioned relation is
>> reindexed in a separate transaction. Those commands cannot be used inside
>> a transaction block when working on a partitioned table or index.
>> +   If a REINDEX command fails when run on a partitioned
>> +   relation, and TABLESPACE was specified, then it may 
>> not
>> +   have moved all indexes to the new tablespace. Re-running the command
>> +   will rebuild again all the partitions and move previously-unprocessed
> 
> remove "again"

Okay.

>> +   indexes to the new tablespace.
>> +  
>> +  
>> +  
>> +   When using the TABLESPACE clause with
>> +   REINDEX on a partitioned index or table, only the
>> +   tablespace references of the partitions are updated. As partitioned 
>> indexes
> 
> I think you should say "of the LEAF partitions ..".  The intermediate,
> partitioned tables are also "partitions" (partitioned partitions if you like).

Indeed, I can see how that's confusing.

>> +   are not updated, it is recommended to separately use
>> +   ALTER TABLE ONLY on them to achieve that.
> 
> Maybe say: "..to set the default tablespace of any new partitions created in
> the future".

Not sure I like that.  Here is a proposal:
"it is recommended to separately use ALTER TABLE ONLY on them so as
any new partitions attached inherit the new tablespace value."
--
Michael


signature.asc
Description: PGP signature


Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-02-03 Thread Alexey Kondratov

On 2021-02-03 09:37, Michael Paquier wrote:

On Tue, Feb 02, 2021 at 10:32:19AM +0900, Michael Paquier wrote:

On Mon, Feb 01, 2021 at 06:28:57PM +0300, Alexey Kondratov wrote:
> Hm, IIUC, REINDEX CONCURRENTLY doesn't use either of them. It directly uses
> index_create() with a proper tablespaceOid instead of
> SetRelationTableSpace(). And its checks structure is more restrictive even
> without tablespace change, so it doesn't use CheckRelationTableSpaceMove().

Sure.  I have not checked the patch in details, but even with that it
would be much safer to me if we apply the same sanity checks
everywhere.  That's less potential holes to worry about.


Thanks Alexey for the new patch.  I have been looking at the main
patch in details.

/*
-* Don't allow reindex on temp tables of other backends ... their 
local

-* buffer manager is not going to cope.
+* We don't support moving system relations into different 
tablespaces

+* unless allow_system_table_mods=1.
 */
If you remove the check on RELATION_IS_OTHER_TEMP() in
reindex_index(), you would allow the reindex of a temp relation owned
by a different session if its tablespace is not changed, so this
cannot be removed.

+!allowSystemTableMods && IsSystemRelation(iRel))
 ereport(ERROR,
-(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("cannot reindex temporary tables of other 
sessions")));

+(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("permission denied: \"%s\" is a system 
catalog",

+RelationGetRelationName(iRel;
Indeed, a system relation with a relfilenode should be allowed to move
under allow_system_table_mods.  I think that we had better move this
check into CheckRelationTableSpaceMove() instead of reindex_index() to
centralize the logic.  ALTER TABLE does this business in
RangeVarCallbackForAlterRelation(), but our code path opening the
relation is different for the non-concurrent case.

+   if (OidIsValid(params->tablespaceOid) &&
+   IsSystemClass(relid, classtuple))
+   {
+   if (!allowSystemTableMods)
+   {
+   /* Skip all system relations, if not 
allowSystemTableMods *

I don't see the need for having two warnings here to say the same
thing if a relation is mapped or not mapped, so let's keep it simple.



Yeah, I just wanted to separate mapped and system relations, but 
probably it is too complicated.




I have found that the test suite was rather messy in its
organization.  Table creations were done first with a set of tests not
really ordered, so that was really hard to follow.  This has also led
to a set of tests that were duplicated, while other tests have been
missed, mainly some cross checks for the concurrent and non-concurrent
behaviors.  I have reordered the whole so as tests on catalogs, normal
tables and partitions are done separately with relations created and
dropped for each set.  Partitions use a global check for tablespaces
and relfilenodes after one concurrent reindex (didn't see the point in
doubling with the non-concurrent case as the same code path to select
the relations from the partition tree is taken).  An ACL test has been
added at the end.

The case of partitioned indexes was kind of interesting and I thought
about that a couple of days, and I took the decision to ignore
relations that have no storage as you did, documenting that ALTER
TABLE can be used to update the references of the partitioned
relations.  The command is still useful with this behavior, and the
tests I have added track that.

Finally, I have reworked the docs, separating the limitations related
to system catalogs and partitioned relations, to be more consistent
with the notes at the end of the page.



Thanks for working on this.

+   if (tablespacename != NULL)
+   {
+   params.tablespaceOid = get_tablespace_oid(tablespacename, 
false);
+
+   /* Check permissions except when moving to database's default */
+   if (OidIsValid(params.tablespaceOid) &&

This check for OidIsValid() seems to be excessive, since you moved the 
whole ACL check under 'if (tablespacename != NULL)' here.


+   params.tablespaceOid != MyDatabaseTableSpace)
+   {
+   AclResult   aclresult;


+CREATE INDEX regress_tblspace_test_tbl_idx ON regress_tblspace_test_tbl 
(num1);

+-- move to global tablespace move fails

Maybe 'move to global tablespace, fail', just to match a style of the 
previous comments.


+REINDEX (TABLESPACE pg_global) INDEX regress_tblspace_test_tbl_idx;


+SELECT relid, parentrelid, level FROM 
pg_partition_tree('tbspace_reindex_part_index')

+  ORDER BY relid, level;
+SELECT relid, parentrelid, level FROM 
pg_partition_tree('tbspace_reindex_part_index')

+  ORDER BY relid, level;

Why do you do the same twice in a row? It looks like a typo. Maybe it 
was intended to be called for 

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-02-02 Thread Justin Pryzby
On Wed, Feb 03, 2021 at 03:37:39PM +0900, Michael Paquier wrote:
> index 627b36300c..4ee3951ca0 100644
> --- a/doc/src/sgml/ref/reindex.sgml
> +++ b/doc/src/sgml/ref/reindex.sgml
> @@ -293,8 +311,30 @@ REINDEX [ (  class="parameter">option [, ...] ) ] { IN
> respectively. Each partition of the specified partitioned relation is
> reindexed in a separate transaction. Those commands cannot be used inside
> a transaction block when working on a partitioned table or index.
> +   If a REINDEX command fails when run on a partitioned
> +   relation, and TABLESPACE was specified, then it may not
> +   have moved all indexes to the new tablespace. Re-running the command
> +   will rebuild again all the partitions and move previously-unprocessed

remove "again"

> +   indexes to the new tablespace.
> +  
> +  
> +  
> +   When using the TABLESPACE clause with
> +   REINDEX on a partitioned index or table, only the
> +   tablespace references of the partitions are updated. As partitioned 
> indexes

I think you should say "of the LEAF partitions ..".  The intermediate,
partitioned tables are also "partitions" (partitioned partitions if you like).

> +   are not updated, it is recommended to separately use
> +   ALTER TABLE ONLY on them to achieve that.

Maybe say: "..to set the default tablespace of any new partitions created in
the future".

-- 
Justin




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-02-02 Thread Michael Paquier
On Tue, Feb 02, 2021 at 10:32:19AM +0900, Michael Paquier wrote:
> On Mon, Feb 01, 2021 at 06:28:57PM +0300, Alexey Kondratov wrote:
> > Hm, IIUC, REINDEX CONCURRENTLY doesn't use either of them. It directly uses
> > index_create() with a proper tablespaceOid instead of
> > SetRelationTableSpace(). And its checks structure is more restrictive even
> > without tablespace change, so it doesn't use CheckRelationTableSpaceMove().
> 
> Sure.  I have not checked the patch in details, but even with that it
> would be much safer to me if we apply the same sanity checks
> everywhere.  That's less potential holes to worry about.

Thanks Alexey for the new patch.  I have been looking at the main
patch in details.

/*
-* Don't allow reindex on temp tables of other backends ... their local
-* buffer manager is not going to cope.
+* We don't support moving system relations into different tablespaces
+* unless allow_system_table_mods=1.
 */
If you remove the check on RELATION_IS_OTHER_TEMP() in
reindex_index(), you would allow the reindex of a temp relation owned
by a different session if its tablespace is not changed, so this
cannot be removed.

+!allowSystemTableMods && IsSystemRelation(iRel))
 ereport(ERROR,
-(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("cannot reindex temporary tables of other sessions")));
+(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("permission denied: \"%s\" is a system catalog",
+RelationGetRelationName(iRel;
Indeed, a system relation with a relfilenode should be allowed to move
under allow_system_table_mods.  I think that we had better move this
check into CheckRelationTableSpaceMove() instead of reindex_index() to 
centralize the logic.  ALTER TABLE does this business in
RangeVarCallbackForAlterRelation(), but our code path opening the
relation is different for the non-concurrent case.

+   if (OidIsValid(params->tablespaceOid) &&
+   IsSystemClass(relid, classtuple))
+   {
+   if (!allowSystemTableMods)
+   {
+   /* Skip all system relations, if not allowSystemTableMods *
I don't see the need for having two warnings here to say the same
thing if a relation is mapped or not mapped, so let's keep it simple.

+REINDEX (TABLESPACE regress_tblspace) SYSTEM CONCURRENTLY postgres; -- fail
+ERROR:  cannot reindex system catalogs concurrently
[...]
+REINDEX (TABLESPACE regress_tblspace) DATABASE regression; -- ok with warning
+WARNING:  cannot change tablespace of indexes on system relations, skipping all
+REINDEX (TABLESPACE pg_default) DATABASE regression; -- ok with warning
+WARNING:  cannot change tablespace of indexes on system relations, skipping all
Those tests are costly by design, so let's drop them.  They have been
useful to check the patch, but if tests are changed with objects
remaining around this would cost a lot of resources.

+   /* It's not a shared catalog, so refuse to move it to shared tablespace */
+   if (params->tablespaceOid == GLOBALTABLESPACE_OID)
+   ereport(ERROR,
+   (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+errmsg("cannot move non-shared relation totablespace \"%s\"",
+get_tablespace_name(params->tablespaceOid;
There is no test coverage for this case with REINDEX CONCURRENTLY, and
that's easy enough to stress.  So I have added one.

I have found that the test suite was rather messy in its
organization.  Table creations were done first with a set of tests not
really ordered, so that was really hard to follow.  This has also led
to a set of tests that were duplicated, while other tests have been
missed, mainly some cross checks for the concurrent and non-concurrent
behaviors.  I have reordered the whole so as tests on catalogs, normal
tables and partitions are done separately with relations created and
dropped for each set.  Partitions use a global check for tablespaces
and relfilenodes after one concurrent reindex (didn't see the point in
doubling with the non-concurrent case as the same code path to select
the relations from the partition tree is taken).  An ACL test has been
added at the end.

The case of partitioned indexes was kind of interesting and I thought
about that a couple of days, and I took the decision to ignore
relations that have no storage as you did, documenting that ALTER
TABLE can be used to update the references of the partitioned
relations.  The command is still useful with this behavior, and the
tests I have added track that.

Finally, I have reworked the docs, separating the limitations related
to system catalogs and partitioned relations, to be more consistent
with the notes at the end of the page.
--
Michael
From c021aeca905a738d38acb257cbc4724804273499 Mon Sep 17 00:00:00 2001
From: Michael Paquier 
Date: Wed, 3 Feb 2021 15:26:21 +0900
Subject: [PATCH v11] Allow REINDEX to change tablespace

REINDEX already 

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-02-01 Thread Michael Paquier
On Mon, Feb 01, 2021 at 06:28:57PM +0300, Alexey Kondratov wrote:
> Hm, IIUC, REINDEX CONCURRENTLY doesn't use either of them. It directly uses
> index_create() with a proper tablespaceOid instead of
> SetRelationTableSpace(). And its checks structure is more restrictive even
> without tablespace change, so it doesn't use CheckRelationTableSpaceMove().

Sure.  I have not checked the patch in details, but even with that it
would be much safer to me if we apply the same sanity checks
everywhere.  That's less potential holes to worry about.

> Basically, it implements this option "we could silently *not* do the switch
> for partitioned indexes in the flow of REINDEX, letting users handle that
> with an extra ALTER TABLE SET TABLESPACE once REINDEX has finished". It
> probably makes sense, since we are doing tablespace change altogether with
> index relation rewrite and don't touch relations without storage. Doing
> ALTER INDEX ... SET TABLESPACE will be almost cost-less on them, since they
> do not hold any data.

Yeah, they'd still need an AEL for a short time on the partitioned
bits with what's on HEAD.  I'll keep in mind to look at the
possibility to downgrade this lock if cascading only on partitioned
tables.  The main take is that AlterTableGetLockLevel() cannot select
a lock type based on the table meta-data.  Tricky problem it is if
taken as a whole, but I guess that we should be able to tweak ALTER
TABLE ONLY on a partitioned table/index pretty easily (inh = false).
--
Michael


signature.asc
Description: PGP signature


Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-02-01 Thread Justin Pryzby
On Mon, Feb 01, 2021 at 06:28:57PM +0300, Alexey Kondratov wrote:
> On 2021-01-30 05:23, Michael Paquier wrote:
> > This makes me really wonder if we would not be better to restrict this
> > operation for partitioned relation as part of REINDEX as a first step.
> > Another thing, mentioned upthread, is that we could do this part of
> > the switch at the last transaction, or we could silently *not* do the
> > switch for partitioned indexes in the flow of REINDEX, letting users
> > handle that with an extra ALTER TABLE SET TABLESPACE once REINDEX has
> > finished on all the partitions, cascading the command only on the
> > partitioned relation of a tree.  

I suggest that it'd be un-intuitive to skip partitioned rels , silently
requiring a user to also run "ALTER .. SET TABLESPACE".  

But I think it'd be okay if REINDEX(TABLESPACE) didn't support partitioned
tables/indexes at first.  I think it'd be better as an ERROR.

-- 
Justin




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-02-01 Thread Alexey Kondratov

On 2021-01-30 05:23, Michael Paquier wrote:

On Fri, Jan 29, 2021 at 08:56:47PM +0300, Alexey Kondratov wrote:

On 2021-01-28 14:42, Alexey Kondratov wrote:
No, you are right, we are doing REINDEX with AccessExclusiveLock as 
it

was before. This part is a more specific one. It only applies to
partitioned indexes, which do not hold any data, so we do not reindex
them directly, only their leafs. However, if we are doing a 
TABLESPACE

change, we have to record it in their pg_class entry, so all future
leaf partitions were created in the proper tablespace.

That way, we open partitioned index relation only for a reference,
i.e. read-only, but modify pg_class entry under a proper lock
(RowExclusiveLock). That's why I thought that ShareLock will be
enough.

IIUC, 'ALTER TABLE ... SET TABLESPACE' uses AccessExclusiveLock even
for relations with no storage, since AlterTableGetLockLevel() chooses
it if AT_SetTableSpace is met. This is very similar to our case, so
probably we should do the same?

Actually it is not completely clear for me why
ShareUpdateExclusiveLock is sufficient for newly added
SetRelationTableSpace() as Michael wrote in the comment.


Nay, it was not fine.  That's something Alvaro has mentioned, leading
to 2484329.  This also means that the main patch of this thread should
refresh the comments at the top of CheckRelationTableSpaceMove() and
SetRelationTableSpace() to mention that this is used by REINDEX
CONCURRENTLY with a lower lock.



Hm, IIUC, REINDEX CONCURRENTLY doesn't use either of them. It directly 
uses index_create() with a proper tablespaceOid instead of 
SetRelationTableSpace(). And its checks structure is more restrictive 
even without tablespace change, so it doesn't use 
CheckRelationTableSpaceMove().


Changed patch to use AccessExclusiveLock in this part for now. This is 
what
'ALTER TABLE/INDEX ... SET TABLESPACE' and 'REINDEX' usually do. 
Anyway, all
real leaf partitions are processed in the independent transactions 
later.


+   if (partkind == RELKIND_PARTITIONED_INDEX)
+   {
+   Relation iRel = index_open(partoid, AccessExclusiveLock);
+
+   if (CheckRelationTableSpaceMove(iRel, 
params->tablespaceOid))

+   SetRelationTableSpace(iRel,
+ params->tablespaceOid,
+ InvalidOid);
+   index_close(iRel, NoLock);
Are you sure that this does not represent a risk of deadlocks as EAL
is not taken consistently across all the partitions?  A second issue
here is that this breaks the assumption of REINDEX CONCURRENTLY kicked
on partitioned relations that should use ShareUpdateExclusiveLock for
all its steps.  This would make the first transaction invasive for the
user, but we don't want that.

This makes me really wonder if we would not be better to restrict this
operation for partitioned relation as part of REINDEX as a first step.
Another thing, mentioned upthread, is that we could do this part of
the switch at the last transaction, or we could silently *not* do the
switch for partitioned indexes in the flow of REINDEX, letting users
handle that with an extra ALTER TABLE SET TABLESPACE once REINDEX has
finished on all the partitions, cascading the command only on the
partitioned relation of a tree.  It may be interesting to look as well
at if we could lower the lock used for partitioned relations with
ALTER TABLE SET TABLESPACE from AEL to SUEL, choosing AEL only if at
least one partition with storage is involved in the command,
CheckRelationTableSpaceMove() discarding anything that has no need to
change.



I am not sure right now, so I split previous patch into two parts:

0001: Adds TABLESPACE into REINDEX with tests, doc and all the stuff we 
did before with the only exception that it doesn't move partitioned 
indexes into the new tablespace.


Basically, it implements this option "we could silently *not* do the 
switch for partitioned indexes in the flow of REINDEX, letting users 
handle that with an extra ALTER TABLE SET TABLESPACE once REINDEX has 
finished". It probably makes sense, since we are doing tablespace change 
altogether with index relation rewrite and don't touch relations without 
storage. Doing ALTER INDEX ... SET TABLESPACE will be almost cost-less 
on them, since they do not hold any data.


0002: Implements the remaining part where pg_class entry is also changed 
for partitioned indexes. I think that we should think more about it, 
maybe it is not so dangerous and proper locking strategy could be 
achieved.



Regards
--
Alexey Kondratov

Postgres Professional https://www.postgrespro.com
Russian Postgres CompanyFrom 6322032b472e6b1a76e0ca9326974e5774371fb9 Mon Sep 17 00:00:00 2001
From: Alexey Kondratov 
Date: Mon, 1 Feb 2021 15:20:29 +0300
Subject: [PATCH v10 2/2] Change tablespace of partitioned indexes during
 REINDEX.

There are some doubts about proper locking of partitions
here. AccessExclusiveLock is surely enough, but may be
a reason of 

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-01-29 Thread Michael Paquier
On Fri, Jan 29, 2021 at 08:56:47PM +0300, Alexey Kondratov wrote:
> On 2021-01-28 14:42, Alexey Kondratov wrote:
>> No, you are right, we are doing REINDEX with AccessExclusiveLock as it
>> was before. This part is a more specific one. It only applies to
>> partitioned indexes, which do not hold any data, so we do not reindex
>> them directly, only their leafs. However, if we are doing a TABLESPACE
>> change, we have to record it in their pg_class entry, so all future
>> leaf partitions were created in the proper tablespace.
>> 
>> That way, we open partitioned index relation only for a reference,
>> i.e. read-only, but modify pg_class entry under a proper lock
>> (RowExclusiveLock). That's why I thought that ShareLock will be
>> enough.
>> 
>> IIUC, 'ALTER TABLE ... SET TABLESPACE' uses AccessExclusiveLock even
>> for relations with no storage, since AlterTableGetLockLevel() chooses
>> it if AT_SetTableSpace is met. This is very similar to our case, so
>> probably we should do the same?
>> 
>> Actually it is not completely clear for me why
>> ShareUpdateExclusiveLock is sufficient for newly added
>> SetRelationTableSpace() as Michael wrote in the comment.

Nay, it was not fine.  That's something Alvaro has mentioned, leading
to 2484329.  This also means that the main patch of this thread should
refresh the comments at the top of CheckRelationTableSpaceMove() and
SetRelationTableSpace() to mention that this is used by REINDEX
CONCURRENTLY with a lower lock.

> Changed patch to use AccessExclusiveLock in this part for now. This is what
> 'ALTER TABLE/INDEX ... SET TABLESPACE' and 'REINDEX' usually do. Anyway, all
> real leaf partitions are processed in the independent transactions later.

+   if (partkind == RELKIND_PARTITIONED_INDEX)
+   {
+   Relation iRel = index_open(partoid, AccessExclusiveLock);
+
+   if (CheckRelationTableSpaceMove(iRel, params->tablespaceOid))
+   SetRelationTableSpace(iRel,
+ params->tablespaceOid,
+ InvalidOid);
+   index_close(iRel, NoLock);
Are you sure that this does not represent a risk of deadlocks as EAL
is not taken consistently across all the partitions?  A second issue
here is that this breaks the assumption of REINDEX CONCURRENTLY kicked
on partitioned relations that should use ShareUpdateExclusiveLock for
all its steps.  This would make the first transaction invasive for the
user, but we don't want that.

This makes me really wonder if we would not be better to restrict this
operation for partitioned relation as part of REINDEX as a first step.
Another thing, mentioned upthread, is that we could do this part of
the switch at the last transaction, or we could silently *not* do the
switch for partitioned indexes in the flow of REINDEX, letting users
handle that with an extra ALTER TABLE SET TABLESPACE once REINDEX has
finished on all the partitions, cascading the command only on the
partitioned relation of a tree.  It may be interesting to look as well
at if we could lower the lock used for partitioned relations with
ALTER TABLE SET TABLESPACE from AEL to SUEL, choosing AEL only if at
least one partition with storage is involved in the command,
CheckRelationTableSpaceMove() discarding anything that has no need to
change.
--
Michael


signature.asc
Description: PGP signature


Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-01-29 Thread Alexey Kondratov

On 2021-01-28 14:42, Alexey Kondratov wrote:

On 2021-01-28 00:36, Alvaro Herrera wrote:



I didn't look at the patch closely enough to understand why you're
trying to do something like CLUSTER, VACUUM FULL or REINDEX without
holding full AccessExclusiveLock on the relation.  But do keep in mind
that once you hold a lock on a relation, trying to grab a weaker lock
afterwards is pretty pointless.



No, you are right, we are doing REINDEX with AccessExclusiveLock as it
was before. This part is a more specific one. It only applies to
partitioned indexes, which do not hold any data, so we do not reindex
them directly, only their leafs. However, if we are doing a TABLESPACE
change, we have to record it in their pg_class entry, so all future
leaf partitions were created in the proper tablespace.

That way, we open partitioned index relation only for a reference,
i.e. read-only, but modify pg_class entry under a proper lock
(RowExclusiveLock). That's why I thought that ShareLock will be
enough.

IIUC, 'ALTER TABLE ... SET TABLESPACE' uses AccessExclusiveLock even
for relations with no storage, since AlterTableGetLockLevel() chooses
it if AT_SetTableSpace is met. This is very similar to our case, so
probably we should do the same?

Actually it is not completely clear for me why
ShareUpdateExclusiveLock is sufficient for newly added
SetRelationTableSpace() as Michael wrote in the comment.



Changed patch to use AccessExclusiveLock in this part for now. This is 
what 'ALTER TABLE/INDEX ... SET TABLESPACE' and 'REINDEX' usually do. 
Anyway, all real leaf partitions are processed in the independent 
transactions later.


Also changed some doc/comment parts Justin pointed me to.

+  then all "mapped" and system relations will be skipped and a 
single
+  WARNING will be generated. Indexes on TOAST 
tables

+  are reindexed, but not moved the new tablespace.


moved *to* the new tablespace.



Fixed.



I don't know if that needs to be said at all.  We talked about it a lot 
to
arrive at the current behavior, but I think that's only due to the 
difficulty

of correcting the initial mistake.



I do not think that it will be a big deal to move indexes on TOAST 
tables as well. I just thought that since 'ALTER TABLE/INDEX ... SET 
TABLESPACE' only moves them together with host table, we also should not 
do that. Yet, I am ready to change this logic if requested.



Regards
--
Alexey Kondratov

Postgres Professional https://www.postgrespro.com
Russian Postgres CompanyFrom 6e9db8d362e794edf421733bc7cade38c917bff4 Mon Sep 17 00:00:00 2001
From: Alexey Kondratov 
Date: Wed, 27 Jan 2021 00:46:17 +0300
Subject: [PATCH v9] Allow REINDEX to change tablespace

REINDEX already does full relation rewrite, this patch adds a
possibility to specify a new tablespace where new relfilenode
will be created.
---
 doc/src/sgml/ref/reindex.sgml |  31 +++-
 src/backend/catalog/index.c   |  47 +-
 src/backend/commands/indexcmds.c  | 112 -
 src/bin/psql/tab-complete.c   |   4 +-
 src/include/catalog/index.h   |   9 +-
 src/test/regress/input/tablespace.source  | 106 +
 src/test/regress/output/tablespace.source | 181 ++
 7 files changed, 478 insertions(+), 12 deletions(-)

diff --git a/doc/src/sgml/ref/reindex.sgml b/doc/src/sgml/ref/reindex.sgml
index 627b36300c..2b39699d42 100644
--- a/doc/src/sgml/ref/reindex.sgml
+++ b/doc/src/sgml/ref/reindex.sgml
@@ -27,6 +27,7 @@ REINDEX [ ( option [, ...] ) ] { IN
 
 CONCURRENTLY [ boolean ]
 VERBOSE [ boolean ]
+TABLESPACE new_tablespace
 
  
 
@@ -187,6 +188,21 @@ REINDEX [ ( option [, ...] ) ] { IN
 

 
+   
+TABLESPACE
+
+ 
+  Specifies that indexes will be rebuilt on a new tablespace.
+  Cannot be used with "mapped" or (unless allow_system_table_mods)
+  system relations. If SCHEMA,
+  DATABASE or SYSTEM are specified,
+  then all "mapped" and system relations will be skipped and a single
+  WARNING will be generated. Indexes on TOAST tables
+  are reindexed, but not moved to the new tablespace.
+ 
+
+   
+

 VERBOSE
 
@@ -210,6 +226,14 @@ REINDEX [ ( option [, ...] ) ] { IN
 

 
+   
+new_tablespace
+
+ 
+  The tablespace where indexes will be rebuilt.
+ 
+
+   
   
  
 
@@ -292,7 +316,12 @@ REINDEX [ ( option [, ...] ) ] { IN
with REINDEX INDEX or REINDEX TABLE,
respectively. Each partition of the specified partitioned relation is
reindexed in a separate transaction. Those commands cannot be used inside
-   a transaction block when working on a partitioned table or index.
+   a transaction block when working on a partitioned table or index. If
+   a REINDEX command fails when run on a partitioned
+   relation, and TABLESPACE was specified, then it may have
+   moved indexes on some partitions to the new tablespace.  Re-running the command
+   will reindex all 

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-01-28 Thread Alexey Kondratov

On 2021-01-28 00:36, Alvaro Herrera wrote:

On 2021-Jan-28, Alexey Kondratov wrote:

I have read more about lock levels and ShareLock should prevent any 
kind of

physical modification of indexes. We already hold ShareLock doing
find_all_inheritors(), which is higher than ShareUpdateExclusiveLock, 
so

using ShareLock seems to be safe here, but I will look on it closer.


You can look at lock.c where LockConflicts[] is; that would tell you
that ShareLock indeed conflicts with ShareUpdateExclusiveLock ... but 
it

does not conflict with itself!  So it would be possible to have more
than one process doing this thing at the same time, which surely makes
no sense.



Thanks for the explanation and pointing me to the LockConflicts[]. This 
is a good reference.




I didn't look at the patch closely enough to understand why you're
trying to do something like CLUSTER, VACUUM FULL or REINDEX without
holding full AccessExclusiveLock on the relation.  But do keep in mind
that once you hold a lock on a relation, trying to grab a weaker lock
afterwards is pretty pointless.



No, you are right, we are doing REINDEX with AccessExclusiveLock as it 
was before. This part is a more specific one. It only applies to 
partitioned indexes, which do not hold any data, so we do not reindex 
them directly, only their leafs. However, if we are doing a TABLESPACE 
change, we have to record it in their pg_class entry, so all future leaf 
partitions were created in the proper tablespace.


That way, we open partitioned index relation only for a reference, i.e. 
read-only, but modify pg_class entry under a proper lock 
(RowExclusiveLock). That's why I thought that ShareLock will be enough.


IIUC, 'ALTER TABLE ... SET TABLESPACE' uses AccessExclusiveLock even for 
relations with no storage, since AlterTableGetLockLevel() chooses it if 
AT_SetTableSpace is met. This is very similar to our case, so probably 
we should do the same?


Actually it is not completely clear for me why ShareUpdateExclusiveLock 
is sufficient for newly added SetRelationTableSpace() as Michael wrote 
in the comment.



Regards
--
Alexey Kondratov

Postgres Professional https://www.postgrespro.com
Russian Postgres Company




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-01-27 Thread Alvaro Herrera
On 2021-Jan-28, Alexey Kondratov wrote:

> I have read more about lock levels and ShareLock should prevent any kind of
> physical modification of indexes. We already hold ShareLock doing
> find_all_inheritors(), which is higher than ShareUpdateExclusiveLock, so
> using ShareLock seems to be safe here, but I will look on it closer.

You can look at lock.c where LockConflicts[] is; that would tell you
that ShareLock indeed conflicts with ShareUpdateExclusiveLock ... but it
does not conflict with itself!  So it would be possible to have more
than one process doing this thing at the same time, which surely makes
no sense.

I didn't look at the patch closely enough to understand why you're
trying to do something like CLUSTER, VACUUM FULL or REINDEX without
holding full AccessExclusiveLock on the relation.  But do keep in mind
that once you hold a lock on a relation, trying to grab a weaker lock
afterwards is pretty pointless.

-- 
Álvaro Herrera39°49'30"S 73°17'W
"E pur si muove" (Galileo Galilei)




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-01-27 Thread Justin Pryzby
Thanks for updating the patch.  I have just a couple comments on the new (and
old) language.

On Thu, Jan 28, 2021 at 12:19:06AM +0300, Alexey Kondratov wrote:
> Also added tests for ACL checks, relfilenode changes. Added ACL recheck for
> multi-transactional case. Added info about TOAST index reindexing. Changed
> some comments.

> +  Specifies that indexes will be rebuilt on a new tablespace.
> +  Cannot be used with "mapped" and system (unless 
> allow_system_table_mods

say mapped *or* system relations
Or maybe:
mapped or (unless >allow_system_table_mods<) system relations.

> +  is set to TRUE) relations. If 
> SCHEMA,
> +  DATABASE or SYSTEM are specified,
> +  then all "mapped" and system relations will be skipped and a single
> +  WARNING will be generated. Indexes on TOAST tables
> +  are reindexed, but not moved the new tablespace.

moved *to* the new tablespace.
I don't know if that needs to be said at all.  We talked about it a lot to
arrive at the current behavior, but I think that's only due to the difficulty
of correcting the initial mistake.

> + /*
> +  * Set the new tablespace for the relation.  Do that only in the
> +  * case where the reindex caller wishes to enforce a new tablespace.

I'd say just "/* Set new tablespace, if requested */
You wrote something similar in an earlier revision of your refactoring patch.

> +  * Mark the relation as ready to be dropped at transaction 
> commit,
> +  * before making visible the new tablespace change so as this 
> won't
> +  * miss things.

This comment is vague.  I think Michael first wrote this comment about a year
ago.  Does it mean "so the new tablespace won't be missed" ?  Missed by what ?

-- 
Justin




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-01-27 Thread Alexey Kondratov

On 2021-01-27 06:14, Michael Paquier wrote:

On Wed, Jan 27, 2021 at 01:00:50AM +0300, Alexey Kondratov wrote:
In the new 0002 I moved ACL check to the upper level, i.e. 
ExecReindex(),
and removed expensive text generation in test. Not touched yet some of 
your
previously raised concerns. Also, you made SetRelationTableSpace() to 
accept

Relation instead of Oid, so now we have to open/close indexes in the
ReindexPartitions(), I am not sure that I use proper locking there, 
but it

works.


Passing down Relation to the new routines makes the most sense to me
because we force the callers to think about the level of locking
that's required when doing any tablespace moves.

+   Relation iRel = index_open(partoid, ShareLock);
+
+   if (CheckRelationTableSpaceMove(iRel, 
params->tablespaceOid))

+   SetRelationTableSpace(iRel,
+ params->tablespaceOid,
+ InvalidOid);
Speaking of which, this breaks the locking assumptions of
SetRelationTableSpace().  I feel that we should think harder about
this part for partitioned indexes and tables because this looks rather
unsafe in terms of locking assumptions with partition trees.  If we
cannot come up with a safe solution, I would be fine with disallowing
TABLESPACE in this case, as a first step.  Not all problems have to be
solved at once, and even without this part the feature is still
useful.



I have read more about lock levels and ShareLock should prevent any kind 
of physical modification of indexes. We already hold ShareLock doing 
find_all_inheritors(), which is higher than ShareUpdateExclusiveLock, so 
using ShareLock seems to be safe here, but I will look on it closer.




+   /* It's not a shared catalog, so refuse to move it to shared 
tablespace */

+   if (params->tablespaceOid == GLOBALTABLESPACE_OID)
+   ereport(ERROR,
+   (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+errmsg("cannot move non-shared relation to tablespace 
\"%s\"",

+get_tablespace_name(params->tablespaceOid;
Why is that needed if CheckRelationTableSpaceMove() is used?



This is from ReindexRelationConcurrently() where we do not use 
CheckRelationTableSpaceMove(). For me it makes sense to add only this 
GLOBALTABLESPACE_OID check there, since before we already check for 
system catalogs and after for temp relations, so adding 
CheckRelationTableSpaceMove() will be a double-check.




- indexRelation->rd_rel->reltablespace,
+ OidIsValid(tablespaceOid) ?
+   tablespaceOid :
indexRelation->rd_rel->reltablespace,
Let's remove this logic from index_concurrently_create_copy() and let
the caller directly decide the tablespace to use, without a dependency
on InvalidOid in the inner routine.  A share update exclusive lock is
already hold on the old index when creating the concurrent copy, so
there won't be concurrent schema changes.



Changed.

Also added tests for ACL checks, relfilenode changes. Added ACL recheck 
for multi-transactional case. Added info about TOAST index reindexing. 
Changed some comments.



Regards
--
Alexey Kondratov

Postgres Professional https://www.postgrespro.com
Russian Postgres CompanyFrom f176a6e5a81ab133fee849f72e4edb8b287d6062 Mon Sep 17 00:00:00 2001
From: Alexey Kondratov 
Date: Wed, 27 Jan 2021 00:46:17 +0300
Subject: [PATCH v8] Allow REINDEX to change tablespace

REINDEX already does full relation rewrite, this patch adds a
possibility to specify a new tablespace where new relfilenode
will be created.
---
 doc/src/sgml/ref/reindex.sgml |  31 +++-
 src/backend/catalog/index.c   |  50 +-
 src/backend/commands/indexcmds.c  | 112 -
 src/bin/psql/tab-complete.c   |   4 +-
 src/include/catalog/index.h   |   9 +-
 src/test/regress/input/tablespace.source  | 106 +
 src/test/regress/output/tablespace.source | 181 ++
 7 files changed, 481 insertions(+), 12 deletions(-)

diff --git a/doc/src/sgml/ref/reindex.sgml b/doc/src/sgml/ref/reindex.sgml
index 627b36300c..e610a0f52c 100644
--- a/doc/src/sgml/ref/reindex.sgml
+++ b/doc/src/sgml/ref/reindex.sgml
@@ -27,6 +27,7 @@ REINDEX [ ( option [, ...] ) ] { IN
 
 CONCURRENTLY [ boolean ]
 VERBOSE [ boolean ]
+TABLESPACE new_tablespace
 
  
 
@@ -187,6 +188,21 @@ REINDEX [ ( option [, ...] ) ] { IN
 

 
+   
+TABLESPACE
+
+ 
+  Specifies that indexes will be rebuilt on a new tablespace.
+  Cannot be used with "mapped" and system (unless allow_system_table_mods
+  is set to TRUE) relations. If SCHEMA,
+  DATABASE or SYSTEM are specified,
+  then all "mapped" and system relations will be skipped and a single
+  WARNING will be generated. Indexes on TOAST tables
+  are reindexed, but not moved the new tablespace.
+ 
+
+   
+

 

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-01-26 Thread Michael Paquier
On Wed, Jan 27, 2021 at 01:00:50AM +0300, Alexey Kondratov wrote:
> CheckRelationTableSpaceMove() does not feel like a right place for invoking
> post alter hooks. It is intended only to check for tablespace change
> possibility. Anyway, ATExecSetTableSpace() and
> ATExecSetTableSpaceNoStorage() already do that in the no-op case.
>
> I have removed this InvokeObjectPostAlterHook() from your 0001 and made 0002
> to work on top of it. I think that now it should look closer to what you
> described above.

Yeah, I was a bit hesitating about this part as those new routines
would not be used by ALTER-related commands in the next steps.  Your
patch got that midway in-between though, by adding the hook to
SetRelationTableSpace but not to CheckRelationTableSpaceMove().  For
now, I have kept the hook out of those new routines because using an
ALTER hook for a utility command is inconsistent.  Perhaps we'd want a
separate hook type dedicated to utility commands in objectaccess.c.

I have double-checked the code, and applied it after a few tweaks.

> In the new 0002 I moved ACL check to the upper level, i.e. ExecReindex(),
> and removed expensive text generation in test. Not touched yet some of your
> previously raised concerns. Also, you made SetRelationTableSpace() to accept
> Relation instead of Oid, so now we have to open/close indexes in the
> ReindexPartitions(), I am not sure that I use proper locking there, but it
> works.

Passing down Relation to the new routines makes the most sense to me
because we force the callers to think about the level of locking
that's required when doing any tablespace moves.

+   Relation iRel = index_open(partoid, ShareLock);
+
+   if (CheckRelationTableSpaceMove(iRel, params->tablespaceOid))
+   SetRelationTableSpace(iRel,
+ params->tablespaceOid,
+ InvalidOid);
Speaking of which, this breaks the locking assumptions of
SetRelationTableSpace().  I feel that we should think harder about
this part for partitioned indexes and tables because this looks rather
unsafe in terms of locking assumptions with partition trees.  If we
cannot come up with a safe solution, I would be fine with disallowing
TABLESPACE in this case, as a first step.  Not all problems have to be
solved at once, and even without this part the feature is still
useful.

+   /* It's not a shared catalog, so refuse to move it to shared tablespace */
+   if (params->tablespaceOid == GLOBALTABLESPACE_OID)
+   ereport(ERROR,
+   (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+errmsg("cannot move non-shared relation to tablespace \"%s\"",
+get_tablespace_name(params->tablespaceOid;
Why is that needed if CheckRelationTableSpaceMove() is used?

bits32  options;/* bitmask of REINDEXOPT_* */
+   Oid  tablespaceOid; /* tablespace to rebuild index */
} ReindexParams;
Mentioned upthread, but here I think that we should tell that
InvalidOid => keep the existing tablespace.
--
Michael


signature.asc
Description: PGP signature


Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-01-26 Thread Alexey Kondratov

On 2021-01-26 09:58, Michael Paquier wrote:

On Mon, Jan 25, 2021 at 11:11:38PM +0300, Alexey Kondratov wrote:
I updated comment with CCI info, did pgindent run and renamed new 
function

to SetRelationTableSpace(). New patch is attached.

[...]

Yeah, all these checks we complicated from the beginning. I will try 
to find

a better place tomorrow or put more info into the comments at least.


I was reviewing that, and I think that we can do a better
consolidation on several points that will also help the features
discussed on this thread for VACUUM, CLUSTER and REINDEX.

If you look closely, ATExecSetTableSpace() uses the same logic as the
code modified here to check if a relation can be moved to a new
tablespace, with extra checks for mapped relations,
GLOBALTABLESPACE_OID or if attempting to manipulate a temp relation
from another session.  There are two differences though:
- Custom actions are taken between the phase where we check if a
relation can be moved to a new tablespace, and the update of
pg_class.
- ATExecSetTableSpace() needs to be able to set a given relation
relfilenode on top of reltablespace, the newly-created one.

So I think that the heart of the problem is made of two things here:
- We should have one common routine for the existing code paths and
the new code paths able to check if a tablespace move can be done or
not.  The case of a cluster, reindex or vacuum on a list of relations
extracted from pg_class would still require a different handling
as incorrect relations have to be skipped, but the case of individual
relations can reuse the refactoring pieces done here
(see CheckRelationTableSpaceMove() in the attached).
- We need to have a second routine able to update reltablespace and
optionally relfilenode for a given relation's pg_class entry, once the
caller has made sure that CheckRelationTableSpaceMove() validates a
tablespace move.



I think that I got your idea. One comment:

+bool
+CheckRelationTableSpaceMove(Relation rel, Oid newTableSpaceId)
+{
+   Oid oldTableSpaceId;
+   Oid reloid = RelationGetRelid(rel);
+
+   /*
+* No work if no change in tablespace.  Note that MyDatabaseTableSpace
+* is stored as 0.
+*/
+   oldTableSpaceId = rel->rd_rel->reltablespace;
+   if (newTableSpaceId == oldTableSpaceId ||
+   (newTableSpaceId == MyDatabaseTableSpace && oldTableSpaceId == 
0))
+   {
+   InvokeObjectPostAlterHook(RelationRelationId, reloid, 0);
+   return false;
+   }

CheckRelationTableSpaceMove() does not feel like a right place for 
invoking post alter hooks. It is intended only to check for tablespace 
change possibility. Anyway, ATExecSetTableSpace() and 
ATExecSetTableSpaceNoStorage() already do that in the no-op case.



Please note that was a bug in your previous patch 0002: shared
dependencies need to be registered if reltablespace is updated of
course, but also iff the relation has no physical storage.  So
changeDependencyOnTablespace() requires a check based on
RELKIND_HAS_STORAGE(), or REINDEX would have registered shared
dependencies even for relations with storage, something we don't
want per the recent work done by Alvaro in ebfe2db.



Yes, thanks.

I have removed this InvokeObjectPostAlterHook() from your 0001 and made 
0002 to work on top of it. I think that now it should look closer to 
what you described above.


In the new 0002 I moved ACL check to the upper level, i.e. 
ExecReindex(), and removed expensive text generation in test. Not 
touched yet some of your previously raised concerns. Also, you made 
SetRelationTableSpace() to accept Relation instead of Oid, so now we 
have to open/close indexes in the ReindexPartitions(), I am not sure 
that I use proper locking there, but it works.



Regards
--
Alexey Kondratov

Postgres Professional https://www.postgrespro.com
Russian Postgres CompanyFrom 96a37399a9cf9ae08d62e28496e73b36087e5a19 Mon Sep 17 00:00:00 2001
From: Michael Paquier 
Date: Tue, 26 Jan 2021 15:53:06 +0900
Subject: [PATCH v7 1/2] Refactor code to detect and process tablespace moves

---
 src/backend/commands/tablecmds.c | 218 +--
 src/include/commands/tablecmds.h |   4 +
 2 files changed, 127 insertions(+), 95 deletions(-)

diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 8687e9a97c..c08eedf995 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -3037,6 +3037,116 @@ SetRelationHasSubclass(Oid relationId, bool relhassubclass)
 	table_close(relationRelation, RowExclusiveLock);
 }
 
+/*
+ * CheckRelationTableSpaceMove
+ *		Check if relation can be moved to new tablespace.
+ *
+ * NOTE: caller must be holding an appropriate lock on the relation.
+ * ShareUpdateExclusiveLock is sufficient to prevent concurrent schema
+ * changes.
+ *
+ * Returns true if the relation can be moved to the new tablespace;
+ * false 

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-01-25 Thread Michael Paquier
On Mon, Jan 25, 2021 at 11:11:38PM +0300, Alexey Kondratov wrote:
> I updated comment with CCI info, did pgindent run and renamed new function
> to SetRelationTableSpace(). New patch is attached.
>
> [...]
>
> Yeah, all these checks we complicated from the beginning. I will try to find
> a better place tomorrow or put more info into the comments at least.

I was reviewing that, and I think that we can do a better
consolidation on several points that will also help the features
discussed on this thread for VACUUM, CLUSTER and REINDEX.

If you look closely, ATExecSetTableSpace() uses the same logic as the
code modified here to check if a relation can be moved to a new
tablespace, with extra checks for mapped relations,
GLOBALTABLESPACE_OID or if attempting to manipulate a temp relation
from another session.  There are two differences though:
- Custom actions are taken between the phase where we check if a
relation can be moved to a new tablespace, and the update of
pg_class.
- ATExecSetTableSpace() needs to be able to set a given relation
relfilenode on top of reltablespace, the newly-created one.

So I think that the heart of the problem is made of two things here:
- We should have one common routine for the existing code paths and
the new code paths able to check if a tablespace move can be done or
not.  The case of a cluster, reindex or vacuum on a list of relations
extracted from pg_class would still require a different handling
as incorrect relations have to be skipped, but the case of individual
relations can reuse the refactoring pieces done here
(see CheckRelationTableSpaceMove() in the attached).
- We need to have a second routine able to update reltablespace and
optionally relfilenode for a given relation's pg_class entry, once the
caller has made sure that CheckRelationTableSpaceMove() validates a
tablespace move.

Please note that was a bug in your previous patch 0002: shared
dependencies need to be registered if reltablespace is updated of
course, but also iff the relation has no physical storage.  So
changeDependencyOnTablespace() requires a check based on
RELKIND_HAS_STORAGE(), or REINDEX would have registered shared
dependencies even for relations with storage, something we don't
want per the recent work done by Alvaro in ebfe2db.
--
Michael
From 265631fb5966ae7b454287c489684c8275b7b001 Mon Sep 17 00:00:00 2001
From: Michael Paquier 
Date: Tue, 26 Jan 2021 15:53:06 +0900
Subject: [PATCH v6] Refactor code to detect and process tablespace moves

---
 src/include/commands/tablecmds.h |   4 +
 src/backend/commands/tablecmds.c | 222 ++-
 2 files changed, 131 insertions(+), 95 deletions(-)

diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h
index 08c463d3c4..b3d30acc35 100644
--- a/src/include/commands/tablecmds.h
+++ b/src/include/commands/tablecmds.h
@@ -61,6 +61,10 @@ extern void ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_
 
 extern void SetRelationHasSubclass(Oid relationId, bool relhassubclass);
 
+extern bool CheckRelationTableSpaceMove(Relation rel, Oid newTableSpaceId);
+extern void SetRelationTableSpace(Relation rel, Oid newTableSpaceId,
+  Oid newRelFileNode);
+
 extern ObjectAddress renameatt(RenameStmt *stmt);
 
 extern ObjectAddress RenameConstraint(RenameStmt *stmt);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 8687e9a97c..1f88eebabd 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -3037,6 +3037,120 @@ SetRelationHasSubclass(Oid relationId, bool relhassubclass)
 	table_close(relationRelation, RowExclusiveLock);
 }
 
+/*
+ * CheckRelationTableSpaceMove
+ *		Check if relation can be moved to new tablespace.
+ *
+ * NOTE: caller must be holding an appropriate lock on the relation.
+ * ShareUpdateExclusiveLock is sufficient to prevent concurrent schema
+ * changes.
+ *
+ * Returns true if the relation can be moved to the new tablespace;
+ * false otherwise.
+ */
+bool
+CheckRelationTableSpaceMove(Relation rel, Oid newTableSpaceId)
+{
+	Oid			oldTableSpaceId;
+	Oid			reloid = RelationGetRelid(rel);
+
+	/*
+	 * No work if no change in tablespace.  Note that MyDatabaseTableSpace
+	 * is stored as 0.
+	 */
+	oldTableSpaceId = rel->rd_rel->reltablespace;
+	if (newTableSpaceId == oldTableSpaceId ||
+		(newTableSpaceId == MyDatabaseTableSpace && oldTableSpaceId == 0))
+	{
+		InvokeObjectPostAlterHook(RelationRelationId, reloid, 0);
+		return false;
+	}
+
+	/*
+	 * We cannot support moving mapped relations into different tablespaces.
+	 * (In particular this eliminates all shared catalogs.)
+	 */
+	if (RelationIsMapped(rel))
+		ereport(ERROR,
+(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot move system relation \"%s\"",
+		RelationGetRelationName(rel;
+
+	/* Cannot move a non-shared relation into pg_global */
+	if (newTableSpaceId == GLOBALTABLESPACE_OID)
+		ereport(ERROR,
+

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-01-25 Thread Alexey Kondratov

On 2021-01-25 11:07, Michael Paquier wrote:

On Fri, Jan 22, 2021 at 05:07:02PM +0300, Alexey Kondratov wrote:
I have updated patches accordingly and also simplified tablespaceOid 
checks
and assignment in the newly added SetRelTableSpace(). Result is 
attached as
two separate patches for an ease of review, but no objections to merge 
them

and apply at once if everything is fine.


 extern void SetRelationHasSubclass(Oid relationId, bool 
relhassubclass);

+extern bool SetRelTableSpace(Oid reloid, Oid tablespaceOid);
Seeing SetRelationHasSubclass(), wouldn't it be more consistent to use
SetRelationTableSpace() as routine name?

I think that we should document that the caller of this routine had
better do a CCI once done to make the tablespace chage visible.
Except for those two nits, the patch needs an indentation run and some
style tweaks but its logic looks fine.  So I'll apply that first
piece.



I updated comment with CCI info, did pgindent run and renamed new 
function to SetRelationTableSpace(). New patch is attached.



+INSERT INTO regress_tblspace_test_tbl (num1, num2, t)
+  SELECT round(random()*100), random(), repeat('text', 100)
+  FROM generate_series(1, 10) s(i);
Repeating 1M times a text value is too costly for such a test.  And as
even for empty tables there is one page created for toast indexes,
there is no need for that?



Yes, TOAST relation is created anyway. I just wanted to put some data 
into a TOAST index, so REINDEX did some meaningful work there, not only 
a new relfilenode creation. However you are right and this query 
increases tablespace tests execution for more for more than 2 times on 
my machine. I think that it is not really required.




This patch is introducing three new checks for system catalogs:
- don't use tablespace for mapped relations.
- don't use tablespace for system relations, except if
allowSystemTableMods.
- don't move non-shared relation to global tablespace.
For the non-concurrent case, all three checks are in reindex_index().
For the concurrent case, the two first checks are in
ReindexMultipleTables() and the third one is in
ReindexRelationConcurrently().  That's rather tricky to follow because
CONCURRENTLY is not allowed on system relations.  I am wondering if it
would be worth an extra comment effort, or if there is a way to
consolidate that better.



Yeah, all these checks we complicated from the beginning. I will try to 
find a better place tomorrow or put more info into the comments at 
least.


I am also going to check/fix the remaining points regarding 002 
tomorrow.



Regards
--
Alexey Kondratov

Postgres Professional https://www.postgrespro.com
Russian Postgres CompanyFrom 39880842d7af31dcbfcffe7219250b31102955d5 Mon Sep 17 00:00:00 2001
From: Alexey Kondratov 
Date: Wed, 20 Jan 2021 20:21:12 +0300
Subject: [PATCH v5 1/2] Extract common part from ATExecSetTableSpaceNoStorage
 for a future usage

---
 src/backend/commands/tablecmds.c | 95 +++-
 src/include/commands/tablecmds.h |  2 +
 2 files changed, 58 insertions(+), 39 deletions(-)

diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 8687e9a97c..ec9c440e4e 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -13291,6 +13291,59 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
 	list_free(reltoastidxids);
 }
 
+/*
+ * SetRelationTableSpace - modify relation tablespace in the pg_class entry.
+ *
+ * 'reloid' is an Oid of relation to be modified.
+ * 'tablespaceOid' is an Oid of new tablespace.
+ *
+ * Catalog modification is done only if tablespaceOid is different from
+ * the currently set.  Returned bool value is indicating whether any changes
+ * were made or not.  Note that caller is responsible for doing
+ * CommandCounterIncrement() to make tablespace changes visible.
+ */
+bool
+SetRelationTableSpace(Oid reloid, Oid tablespaceOid)
+{
+	Relation	pg_class;
+	HeapTuple	tuple;
+	Form_pg_class rd_rel;
+	bool		changed = false;
+
+	/* Get a modifiable copy of the relation's pg_class row. */
+	pg_class = table_open(RelationRelationId, RowExclusiveLock);
+
+	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(reloid));
+	if (!HeapTupleIsValid(tuple))
+		elog(ERROR, "cache lookup failed for relation %u", reloid);
+	rd_rel = (Form_pg_class) GETSTRUCT(tuple);
+
+	/* MyDatabaseTableSpace is stored as InvalidOid. */
+	if (tablespaceOid == MyDatabaseTableSpace)
+		tablespaceOid = InvalidOid;
+
+	/* No work if no change in tablespace. */
+	if (tablespaceOid != rd_rel->reltablespace)
+	{
+		/* Update the pg_class row. */
+		rd_rel->reltablespace = tablespaceOid;
+		CatalogTupleUpdate(pg_class, >t_self, tuple);
+
+		/* Record dependency on tablespace. */
+		changeDependencyOnTablespace(RelationRelationId,
+	 reloid, rd_rel->reltablespace);
+
+		changed = true;
+	}
+
+	InvokeObjectPostAlterHook(RelationRelationId, reloid, 0);
+
+	heap_freetuple(tuple);
+	

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-01-25 Thread Justin Pryzby
On Mon, Jan 25, 2021 at 05:07:29PM +0900, Michael Paquier wrote:
> On Fri, Jan 22, 2021 at 05:07:02PM +0300, Alexey Kondratov wrote:
> > I have updated patches accordingly and also simplified tablespaceOid checks
> > and assignment in the newly added SetRelTableSpace(). Result is attached as
> > two separate patches for an ease of review, but no objections to merge them
> > and apply at once if everything is fine.
...
> +SELECT relname FROM pg_class
> +WHERE reltablespace=(SELECT oid FROM pg_tablespace WHERE 
> spcname='regress_tblspace');
> [...]
> +-- first, check a no-op case
> +REINDEX (TABLESPACE pg_default) INDEX regress_tblspace_test_tbl_idx;
> +REINDEX (TABLESPACE pg_default) TABLE regress_tblspace_test_tbl;
> Reindexing means that the relfilenodes are changed, so the tests
> should track the original and new relfilenodes and compare them, no?
> In short, this set of regression tests does not make sure that a
> REINDEX actually happens or not, and this may read as a reindex not
> happening at all for those tests.  For single units, these could be
> saved in a variable and compared afterwards.  create_index.sql does
> that a bit with REINDEX SCHEMA for a set of relations.

You might also check my "CLUSTER partitioned" patch for another way to do that.

https://www.postgresql.org/message-id/20210118183459.GJ8560%40telsasoft.com
https://www.postgresql.org/message-id/attachment/118126/v6-0002-Implement-CLUSTER-of-partitioned-table.patch

-- 
Justin




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-01-22 Thread Alexey Kondratov

On 2021-01-22 00:26, Justin Pryzby wrote:

On Thu, Jan 21, 2021 at 11:48:08PM +0300, Alexey Kondratov wrote:
Attached is a new patch set of first two patches, that should resolve 
all
the issues raised before (ACL, docs, tests) excepting TOAST. Double 
thanks
for suggestion to add more tests with nested partitioning. I have 
found and
squashed a huge bug related to the returning back to the default 
tablespace

using newly added tests.

Regarding TOAST. Now we skip moving toast indexes or throw error if 
someone

wants to move TOAST index directly. I had a look on ALTER TABLE SET
TABLESPACE and it has a bit complicated logic:

1) You cannot move TOAST table directly.
2) But if you move basic relation that TOAST table belongs to, then 
they are

moved altogether.
3) Same logic as 2) happens if one does ALTER TABLE ALL IN TABLESPACE 
...


That way, ALTER TABLE allows moving TOAST tables (with indexes) 
implicitly,
but does not allow doing that explicitly. In the same time I found 
docs to

be vague about such behavior it only says:

All tables in the current database in a tablespace can be moved
by using the ALL IN TABLESPACE ... Note that system catalogs are
not moved by this command

Changing any part of a system catalog table is not permitted.

So actually ALTER TABLE treats TOAST relations as system sometimes, 
but

sometimes not.

From the end user perspective it makes sense to move TOAST with main 
table
when doing ALTER TABLE SET TABLESPACE. But should we touch indexes on 
TOAST
table with REINDEX? We cannot move TOAST relation itself, since we are 
doing
only a reindex, so we end up in the state when TOAST table and its 
index are
placed in the different tablespaces. This state is not reachable with 
ALTER
TABLE/INDEX, so it seem we should not allow it with REINDEX as well, 
should

we?


+		 * Even if a table's indexes were moved to a new tablespace, the 
index

+* on its toast table is not normally moved.
 */
ReindexParams newparams = *params;

newparams.options &= ~(REINDEXOPT_MISSING_OK);
+   if (!allowSystemTableMods)
+   newparams.tablespaceOid = InvalidOid;


I think you're right.  So actually TOAST should never move, even if
allowSystemTableMods, right ?



I think so. I would prefer to do not move TOAST indexes implicitly at 
all during reindex.




@@ -292,7 +315,11 @@ REINDEX [ ( class="parameter">option [, ...] ) ] { IN
with REINDEX INDEX or REINDEX 
TABLE,
respectively. Each partition of the specified partitioned relation 
is
reindexed in a separate transaction. Those commands cannot be used 
inside

-   a transaction block when working on a partitioned table or index.
+   a transaction block when working on a partitioned table or index. 
If
+   REINDEX with TABLESPACE 
executed
+   on partitioned relation fails it may have moved some partitions to 
the new
+   tablespace. Repeated command will still reindex all partitions 
even if they

+   are already in the new tablespace.


Minor corrections here:

If a REINDEX command fails when run on a partitioned
relation, and TABLESPACE was specified, then it may 
have
moved indexes on some partitions to the new tablespace.  Re-running the 
command
will reindex all partitions and move previously-unprocessed indexes to 
the new

tablespace.


Sounds good to me.

I have updated patches accordingly and also simplified tablespaceOid 
checks and assignment in the newly added SetRelTableSpace(). Result is 
attached as two separate patches for an ease of review, but no 
objections to merge them and apply at once if everything is fine.



Regards
--
Alexey Kondratov

Postgres Professional https://www.postgrespro.com
Russian Postgres CompanyFrom 87e47e9b5b3d6b49230045e5db8f844b14b34ba0 Mon Sep 17 00:00:00 2001
From: Alexey Kondratov 
Date: Mon, 23 Mar 2020 21:10:29 +0300
Subject: [PATCH v4 2/2] Allow REINDEX to change tablespace

REINDEX already does full relation rewrite, this patch adds a
possibility to specify a new tablespace where new relfilenode
will be created.
---
 doc/src/sgml/ref/reindex.sgml |  30 +++-
 src/backend/catalog/index.c   |  81 ++-
 src/backend/commands/indexcmds.c  |  81 ++-
 src/bin/psql/tab-complete.c   |   4 +-
 src/include/catalog/index.h   |   2 +
 src/test/regress/input/tablespace.source  |  85 
 src/test/regress/output/tablespace.source | 159 ++
 7 files changed, 436 insertions(+), 6 deletions(-)

diff --git a/doc/src/sgml/ref/reindex.sgml b/doc/src/sgml/ref/reindex.sgml
index 627b36300c..a1c7736aec 100644
--- a/doc/src/sgml/ref/reindex.sgml
+++ b/doc/src/sgml/ref/reindex.sgml
@@ -27,6 +27,7 @@ REINDEX [ ( option [, ...] ) ] { IN
 
 CONCURRENTLY [ boolean ]
 VERBOSE [ boolean ]
+TABLESPACE new_tablespace
 
  
 
@@ -187,6 +188,20 @@ REINDEX [ ( option [, ...] ) ] { IN
 

 
+   
+ 

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-01-21 Thread Justin Pryzby
On Thu, Jan 21, 2021 at 11:48:08PM +0300, Alexey Kondratov wrote:
> Attached is a new patch set of first two patches, that should resolve all
> the issues raised before (ACL, docs, tests) excepting TOAST. Double thanks
> for suggestion to add more tests with nested partitioning. I have found and
> squashed a huge bug related to the returning back to the default tablespace
> using newly added tests.
> 
> Regarding TOAST. Now we skip moving toast indexes or throw error if someone
> wants to move TOAST index directly. I had a look on ALTER TABLE SET
> TABLESPACE and it has a bit complicated logic:
> 
> 1) You cannot move TOAST table directly.
> 2) But if you move basic relation that TOAST table belongs to, then they are
> moved altogether.
> 3) Same logic as 2) happens if one does ALTER TABLE ALL IN TABLESPACE ...
> 
> That way, ALTER TABLE allows moving TOAST tables (with indexes) implicitly,
> but does not allow doing that explicitly. In the same time I found docs to
> be vague about such behavior it only says:
> 
> All tables in the current database in a tablespace can be moved
> by using the ALL IN TABLESPACE ... Note that system catalogs are
> not moved by this command
> 
> Changing any part of a system catalog table is not permitted.
> 
> So actually ALTER TABLE treats TOAST relations as system sometimes, but
> sometimes not.
> 
> From the end user perspective it makes sense to move TOAST with main table
> when doing ALTER TABLE SET TABLESPACE. But should we touch indexes on TOAST
> table with REINDEX? We cannot move TOAST relation itself, since we are doing
> only a reindex, so we end up in the state when TOAST table and its index are
> placed in the different tablespaces. This state is not reachable with ALTER
> TABLE/INDEX, so it seem we should not allow it with REINDEX as well, should
> we?

> +  * Even if a table's indexes were moved to a new tablespace, 
> the index
> +  * on its toast table is not normally moved.
>*/
>   ReindexParams newparams = *params;
>  
>   newparams.options &= ~(REINDEXOPT_MISSING_OK);
> + if (!allowSystemTableMods)
> + newparams.tablespaceOid = InvalidOid;

I think you're right.  So actually TOAST should never move, even if
allowSystemTableMods, right ?

> @@ -292,7 +315,11 @@ REINDEX [ (  class="parameter">option [, ...] ) ] { IN
> with REINDEX INDEX or REINDEX TABLE,
> respectively. Each partition of the specified partitioned relation is
> reindexed in a separate transaction. Those commands cannot be used inside
> -   a transaction block when working on a partitioned table or index.
> +   a transaction block when working on a partitioned table or index. If
> +   REINDEX with TABLESPACE executed
> +   on partitioned relation fails it may have moved some partitions to the new
> +   tablespace. Repeated command will still reindex all partitions even if 
> they
> +   are already in the new tablespace.

Minor corrections here:

If a REINDEX command fails when run on a partitioned
relation, and TABLESPACE was specified, then it may have
moved indexes on some partitions to the new tablespace.  Re-running the command
will reindex all partitions and move previously-unprocessed indexes to the new
tablespace.


-- 
Justin




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-01-21 Thread Alexey Kondratov

On 2021-01-21 17:06, Alexey Kondratov wrote:

On 2021-01-21 04:41, Michael Paquier wrote:


There are no tests for partitioned tables, aka we'd want to make sure
that the new partitioned index is on the correct tablespace, as well
as all its leaves.  It may be better to have at least two levels of
partitioned tables, as well as a partitioned table with no leaves in
the cases dealt with.



Yes, sure, it makes sense.


+*
+* Even if a table's indexes were moved to a new tablespace, 
the index

+* on its toast table is not normally moved.
 */
Still, REINDEX (TABLESPACE) TABLE should move all of them to be
consistent with ALTER TABLE SET TABLESPACE, but that's not the case
with this code, no?  This requires proper test coverage, but there is
nothing of the kind in this patch.


You are right, we do not move TOAST indexes now, since
IsSystemRelation() is true for TOAST indexes, so I thought that we
should not allow moving them without allow_system_table_mods=true. Now
I wonder why ALTER TABLE does that.

I am going to attach the new version of patch set today or tomorrow.



Attached is a new patch set of first two patches, that should resolve 
all the issues raised before (ACL, docs, tests) excepting TOAST. Double 
thanks for suggestion to add more tests with nested partitioning. I have 
found and squashed a huge bug related to the returning back to the 
default tablespace using newly added tests.


Regarding TOAST. Now we skip moving toast indexes or throw error if 
someone wants to move TOAST index directly. I had a look on ALTER TABLE 
SET TABLESPACE and it has a bit complicated logic:


1) You cannot move TOAST table directly.
2) But if you move basic relation that TOAST table belongs to, then they 
are moved altogether.
3) Same logic as 2) happens if one does ALTER TABLE ALL IN TABLESPACE 
...


That way, ALTER TABLE allows moving TOAST tables (with indexes) 
implicitly, but does not allow doing that explicitly. In the same time I 
found docs to be vague about such behavior it only says:


All tables in the current database in a tablespace can be moved
by using the ALL IN TABLESPACE ... Note that system catalogs are
not moved by this command

Changing any part of a system catalog table is not permitted.

So actually ALTER TABLE treats TOAST relations as system sometimes, but 
sometimes not.


From the end user perspective it makes sense to move TOAST with main 
table when doing ALTER TABLE SET TABLESPACE. But should we touch indexes 
on TOAST table with REINDEX? We cannot move TOAST relation itself, since 
we are doing only a reindex, so we end up in the state when TOAST table 
and its index are placed in the different tablespaces. This state is not 
reachable with ALTER TABLE/INDEX, so it seem we should not allow it with 
REINDEX as well, should we?



Regards
--
Alexey Kondratov

Postgres Professional https://www.postgrespro.com
Russian Postgres CompanyFrom bcd690da6bc3db16a96305b45546d3c9e400f769 Mon Sep 17 00:00:00 2001
From: Alexey Kondratov 
Date: Mon, 23 Mar 2020 21:10:29 +0300
Subject: [PATCH v3 2/2] Allow REINDEX to change tablespace

REINDEX already does full relation rewrite, this patch adds a
possibility to specify a new tablespace where new relfilenode
will be created.
---
 doc/src/sgml/ref/reindex.sgml |  29 +++-
 src/backend/catalog/index.c   |  82 +++-
 src/backend/commands/indexcmds.c  |  81 +++-
 src/bin/psql/tab-complete.c   |   4 +-
 src/include/catalog/index.h   |   2 +
 src/test/regress/input/tablespace.source  |  79 +++
 src/test/regress/output/tablespace.source | 154 ++
 7 files changed, 425 insertions(+), 6 deletions(-)

diff --git a/doc/src/sgml/ref/reindex.sgml b/doc/src/sgml/ref/reindex.sgml
index 627b36300c..90fdad0b4c 100644
--- a/doc/src/sgml/ref/reindex.sgml
+++ b/doc/src/sgml/ref/reindex.sgml
@@ -27,6 +27,7 @@ REINDEX [ ( option [, ...] ) ] { IN
 
 CONCURRENTLY [ boolean ]
 VERBOSE [ boolean ]
+TABLESPACE new_tablespace
 
  
 
@@ -187,6 +188,20 @@ REINDEX [ ( option [, ...] ) ] { IN
 

 
+   
+TABLESPACE
+
+ 
+  Specifies that indexes will be rebuilt on a new tablespace.
+  Cannot be used with "mapped" and system (unless allow_system_table_mods
+  is set to TRUE) relations. If SCHEMA,
+  DATABASE or SYSTEM are specified, then
+  all "mapped" and system relations will be skipped and a single
+  WARNING will be generated.
+ 
+
+   
+

 VERBOSE
 
@@ -210,6 +225,14 @@ REINDEX [ ( option [, ...] ) ] { IN
 

 
+   
+new_tablespace
+
+ 
+  The tablespace where indexes will be rebuilt.
+ 
+
+   
   
  
 
@@ -292,7 +315,11 @@ REINDEX [ ( option [, ...] ) ] { IN
with REINDEX INDEX or REINDEX TABLE,
respectively. Each partition of the specified partitioned relation is
reindexed in a separate transaction. Those 

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-01-21 Thread Alexey Kondratov

On 2021-01-21 04:41, Michael Paquier wrote:

On Wed, Jan 20, 2021 at 03:34:39PM -0300, Alvaro Herrera wrote:

On 2021-Jan-20, Alexey Kondratov wrote:

Ugh, forgot to attach the patches. Here they are.


Yeah, looks reasonable.



+
+   if (changed)
+   /* Record dependency on tablespace */
+   changeDependencyOnTablespace(RelationRelationId,
+reloid, 
rd_rel->reltablespace);


Why have a separate "if (changed)" block here instead of merging with
the above?


Yep.



Sure, this is a refactoring artifact.


+   if (SetRelTablespace(reloid, newTableSpace))
+   /* Make sure the reltablespace change is visible */
+   CommandCounterIncrement();
At quick glance, I am wondering why you just don't do a CCI within
SetRelTablespace().



I did it that way for a better readability at first, since it looks more 
natural when you do some change (SetRelTablespace) and then make them 
visible with CCI. Second argument was that in the case of 
reindex_index() we have to also call RelationAssumeNewRelfilenode() and 
RelationDropStorage() before doing CCI and making the new tablespace 
visible. And this part is critical, I guess.




+  This specifies that indexes will be rebuilt on a new tablespace.
+  Cannot be used with "mapped" relations. If 
SCHEMA,

+  DATABASE or SYSTEM is
specified, then
+  all unsuitable relations will be skipped and a single
WARNING
+  will be generated.
What is an unsuitable relation?  How can the end user know that?



This was referring to mapped relations mentioned in the previous 
sentence. I have tried to rewrite this part and make it more specific in 
my current version. Also added Justin's changes to the docs and comment.



This is missing ACL checks when moving the index into a new location,
so this requires some pg_tablespace_aclcheck() calls, and the other
patches share the same issue.



I added proper pg_tablespace_aclcheck()'s into the reindex_index() and 
ReindexPartitions().



+   else if (partkind == RELKIND_PARTITIONED_TABLE)
+   {
+   Relation rel = table_open(partoid, ShareLock);
+   List*indexIds = RelationGetIndexList(rel);
+   ListCell *lc;
+
+   table_close(rel, NoLock);
+   foreach (lc, indexIds)
+   {
+   Oid indexid = lfirst_oid(lc);
+   (void) set_rel_tablespace(indexid, 
params->tablespaceOid);

+   }
+   }
This is really a good question.  ReindexPartitions() would trigger one
transaction per leaf to work on.  Changing the tablespace of the
partitioned table(s) before doing any work has the advantage to tell
any new partition to use the new tablespace.  Now, I see a struggling
point here: what should we do if the processing fails in the middle of
the move, leaving a portion of the leaves in the previous tablespace?
On a follow-up reindex with the same command, should the command force
a reindex even on the partitions that have been moved?  Or could there
be a point in skipping the partitions that are already on the new
tablespace and only process the ones on the previous tablespace?  It
seems to me that the first scenario makes the most sense as currently
a REINDEX works on all the relations defined, though there could be
use cases for the second case.  This should be documented, I think.



I agree that follow-up REINDEX should also reindex moved partitions, 
since REINDEX (TABLESPACE ...) is still reindex at first. I will try to 
put something about this part into the docs. Also I think that we cannot 
be sure that nothing happened with already reindexed partitions between 
two consequent REINDEX calls.



There are no tests for partitioned tables, aka we'd want to make sure
that the new partitioned index is on the correct tablespace, as well
as all its leaves.  It may be better to have at least two levels of
partitioned tables, as well as a partitioned table with no leaves in
the cases dealt with.



Yes, sure, it makes sense.


+*
+* Even if a table's indexes were moved to a new tablespace, 
the index

+* on its toast table is not normally moved.
 */
Still, REINDEX (TABLESPACE) TABLE should move all of them to be
consistent with ALTER TABLE SET TABLESPACE, but that's not the case
with this code, no?  This requires proper test coverage, but there is
nothing of the kind in this patch.


You are right, we do not move TOAST indexes now, since 
IsSystemRelation() is true for TOAST indexes, so I thought that we 
should not allow moving them without allow_system_table_mods=true. Now I 
wonder why ALTER TABLE does that.


I am going to attach the new version of patch set today or tomorrow.


Regards
--
Alexey Kondratov

Postgres Professional https://www.postgrespro.com
Russian Postgres Company




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-01-20 Thread Michael Paquier
On Wed, Jan 20, 2021 at 03:34:39PM -0300, Alvaro Herrera wrote:
> On 2021-Jan-20, Alexey Kondratov wrote:
>> Ugh, forgot to attach the patches. Here they are.
> 
> Yeah, looks reasonable.

Patch 0002 still has a whole set of issues as I pointed out a couple
of hours ago, but if we agree on 0001 as being useful if done
independently, I'd rather get that done first.  This way or just
merging both things in a single commit is not a big deal seeing the
amount of code, so I am fine with any approach.  It may be possible
that 0001 requires more changes depending on the work to-be-done for
0002 though?

>> +/* No work if no change in tablespace. */
>> +oldTablespaceOid = rd_rel->reltablespace;
>> +if (tablespaceOid != oldTablespaceOid ||
>> +(tablespaceOid == MyDatabaseTableSpace && 
>> OidIsValid(oldTablespaceOid)))
>> +{
>> +/* Update the pg_class row. */
>> +rd_rel->reltablespace = (tablespaceOid == MyDatabaseTableSpace) 
>> ?
>> +InvalidOid : tablespaceOid;
>> +CatalogTupleUpdate(pg_class, >t_self, tuple);
>> +
>> +changed = true;
>> +}
>> +
>> +if (changed)
>> +/* Record dependency on tablespace */
>> +changeDependencyOnTablespace(RelationRelationId,
>> + 
>> reloid, rd_rel->reltablespace);
> 
> Why have a separate "if (changed)" block here instead of merging with
> the above?

Yep.

+   if (SetRelTablespace(reloid, newTableSpace))
+   /* Make sure the reltablespace change is visible */
+   CommandCounterIncrement();
At quick glance, I am wondering why you just don't do a CCI within
SetRelTablespace().
--
Michael


signature.asc
Description: PGP signature


Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-01-20 Thread Alvaro Herrera
On 2021-Jan-20, Alexey Kondratov wrote:

> On 2021-01-20 21:08, Alexey Kondratov wrote:
> > 
> > I did a refactoring of ATExecSetTableSpaceNoStorage() in the 0001. New
> > function SetRelTablesapce() is placed into the tablecmds.c. Following
> > 0002 gets use of it. Is it close to what you and Michael suggested?
> 
> Ugh, forgot to attach the patches. Here they are.

Yeah, looks reasonable.

> + /* No work if no change in tablespace. */
> + oldTablespaceOid = rd_rel->reltablespace;
> + if (tablespaceOid != oldTablespaceOid ||
> + (tablespaceOid == MyDatabaseTableSpace && 
> OidIsValid(oldTablespaceOid)))
> + {
> + /* Update the pg_class row. */
> + rd_rel->reltablespace = (tablespaceOid == MyDatabaseTableSpace) 
> ?
> + InvalidOid : tablespaceOid;
> + CatalogTupleUpdate(pg_class, >t_self, tuple);
> +
> + changed = true;
> + }
> +
> + if (changed)
> + /* Record dependency on tablespace */
> + changeDependencyOnTablespace(RelationRelationId,
> +  
> reloid, rd_rel->reltablespace);

Why have a separate "if (changed)" block here instead of merging with
the above?


-- 
Álvaro Herrera39°49'30"S 73°17'W




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-01-20 Thread Alexey Kondratov

On 2021-01-20 21:08, Alexey Kondratov wrote:

On 2021-01-20 18:54, Alvaro Herrera wrote:

On 2021-Jan-20, Alvaro Herrera wrote:


On 2021-Jan-20, Michael Paquier wrote:

> +/*
> + * This is mostly duplicating ATExecSetTableSpaceNoStorage,
> + * which should maybe be factored out to a library function.
> + */
> Wouldn't it be better to do first the refactoring of 0002 and then
> 0001 so as REINDEX can use the new routine, instead of putting that
> into a comment?

I think merging 0001 and 0002 into a single commit is a reasonable
approach.


... except it doesn't make a lot of sense to have set_rel_tablespace 
in

either indexcmds.c or index.c.  I think tablecmds.c is a better place
for it.  (I would have thought catalog/storage.c, but that one's not 
the

right abstraction level it seems.)



I did a refactoring of ATExecSetTableSpaceNoStorage() in the 0001. New
function SetRelTablesapce() is placed into the tablecmds.c. Following
0002 gets use of it. Is it close to what you and Michael suggested?



Ugh, forgot to attach the patches. Here they are.

--
AlexeyFrom 2c3876f99bc8ebdd07c532619992e7ec3093e50a Mon Sep 17 00:00:00 2001
From: Alexey Kondratov 
Date: Mon, 23 Mar 2020 21:10:29 +0300
Subject: [PATCH v2 2/2] Allow REINDEX to change tablespace

REINDEX already does full relation rewrite, this patch adds a
possibility to specify a new tablespace where new relfilenode
will be created.
---
 doc/src/sgml/ref/reindex.sgml |  22 +
 src/backend/catalog/index.c   |  72 ++-
 src/backend/commands/indexcmds.c  |  68 ++-
 src/bin/psql/tab-complete.c   |   4 +-
 src/include/catalog/index.h   |   2 +
 src/test/regress/input/tablespace.source  |  53 +++
 src/test/regress/output/tablespace.source | 102 ++
 7 files changed, 318 insertions(+), 5 deletions(-)

diff --git a/doc/src/sgml/ref/reindex.sgml b/doc/src/sgml/ref/reindex.sgml
index 627b36300c..4f84060c4d 100644
--- a/doc/src/sgml/ref/reindex.sgml
+++ b/doc/src/sgml/ref/reindex.sgml
@@ -27,6 +27,7 @@ REINDEX [ ( option [, ...] ) ] { IN
 
 CONCURRENTLY [ boolean ]
 VERBOSE [ boolean ]
+TABLESPACE new_tablespace
 
  
 
@@ -187,6 +188,19 @@ REINDEX [ ( option [, ...] ) ] { IN
 

 
+   
+TABLESPACE
+
+ 
+  This specifies that indexes will be rebuilt on a new tablespace.
+  Cannot be used with "mapped" relations. If SCHEMA,
+  DATABASE or SYSTEM is specified, then
+  all unsuitable relations will be skipped and a single WARNING
+  will be generated.
+ 
+
+   
+

 VERBOSE
 
@@ -210,6 +224,14 @@ REINDEX [ ( option [, ...] ) ] { IN
 

 
+   
+new_tablespace
+
+ 
+  The tablespace where indexes will be rebuilt.
+ 
+
+   
   
  
 
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index b8cd35e995..ed98b17483 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -57,6 +57,7 @@
 #include "commands/event_trigger.h"
 #include "commands/progress.h"
 #include "commands/tablecmds.h"
+#include "commands/tablespace.h"
 #include "commands/trigger.h"
 #include "executor/executor.h"
 #include "miscadmin.h"
@@ -1394,9 +1395,13 @@ index_update_collation_versions(Oid relid, Oid coll)
  * Create concurrently an index based on the definition of the one provided by
  * caller.  The index is inserted into catalogs and needs to be built later
  * on.  This is called during concurrent reindex processing.
+ *
+ * "tablespaceOid" is the new tablespace to use for this index.  If
+ * InvalidOid, use the tablespace in-use instead.
  */
 Oid
-index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, const char *newName)
+index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId,
+			   Oid tablespaceOid, const char *newName)
 {
 	Relation	indexRelation;
 	IndexInfo  *oldInfo,
@@ -1526,7 +1531,8 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, const char
 			  newInfo,
 			  indexColNames,
 			  indexRelation->rd_rel->relam,
-			  indexRelation->rd_rel->reltablespace,
+			  OidIsValid(tablespaceOid) ?
+tablespaceOid : indexRelation->rd_rel->reltablespace,
 			  indexRelation->rd_indcollation,
 			  indclass->values,
 			  indcoloptions->values,
@@ -3591,6 +3597,8 @@ IndexGetRelation(Oid indexId, bool missing_ok)
 
 /*
  * reindex_index - This routine is used to recreate a single index
+ *
+ * See comments of reindex_relation() for details about "tablespaceOid".
  */
 void
 reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
@@ -3603,6 +3611,7 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
 	volatile bool skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
+	bool		set_tablespace = OidIsValid(params->tablespaceOid);
 
 	pg_rusage_init();
 

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-01-20 Thread Alexey Kondratov

On 2021-01-20 18:54, Alvaro Herrera wrote:

On 2021-Jan-20, Alvaro Herrera wrote:


On 2021-Jan-20, Michael Paquier wrote:

> +/*
> + * This is mostly duplicating ATExecSetTableSpaceNoStorage,
> + * which should maybe be factored out to a library function.
> + */
> Wouldn't it be better to do first the refactoring of 0002 and then
> 0001 so as REINDEX can use the new routine, instead of putting that
> into a comment?

I think merging 0001 and 0002 into a single commit is a reasonable
approach.


... except it doesn't make a lot of sense to have set_rel_tablespace in
either indexcmds.c or index.c.  I think tablecmds.c is a better place
for it.  (I would have thought catalog/storage.c, but that one's not 
the

right abstraction level it seems.)



I did a refactoring of ATExecSetTableSpaceNoStorage() in the 0001. New 
function SetRelTablesapce() is placed into the tablecmds.c. Following 
0002 gets use of it. Is it close to what you and Michael suggested?




But surely ATExecSetTableSpaceNoStorage should be using this new
routine.  (I first thought 0002 was doing that, since that commit is
calling itself a "refactoring", but now that I look closer, it's not.)



Yeah, this 'refactoring' was initially referring to refactoring of what 
Justin added to one of the previous 0001. And it was meant to be merged 
with 0001, once agreed, but we got distracted by other stuff.


I have not yet addressed Michael's concerns regarding reindex of 
partitions. I am going to look closer on it tomorrow.



Regards
--
Alexey Kondratov

Postgres Professional https://www.postgrespro.com
Russian Postgres Company




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-01-20 Thread Alvaro Herrera
On 2021-Jan-20, Alvaro Herrera wrote:

> On 2021-Jan-20, Michael Paquier wrote:
> 
> > +/*
> > + * This is mostly duplicating ATExecSetTableSpaceNoStorage,
> > + * which should maybe be factored out to a library function.
> > + */
> > Wouldn't it be better to do first the refactoring of 0002 and then
> > 0001 so as REINDEX can use the new routine, instead of putting that
> > into a comment?
> 
> I think merging 0001 and 0002 into a single commit is a reasonable
> approach.

... except it doesn't make a lot of sense to have set_rel_tablespace in
either indexcmds.c or index.c.  I think tablecmds.c is a better place
for it.  (I would have thought catalog/storage.c, but that one's not the
right abstraction level it seems.)

But surely ATExecSetTableSpaceNoStorage should be using this new
routine.  (I first thought 0002 was doing that, since that commit is
calling itself a "refactoring", but now that I look closer, it's not.)

-- 
Álvaro Herrera39°49'30"S 73°17'W
"On the other flipper, one wrong move and we're Fatal Exceptions"
(T.U.X.: Term Unit X  - http://www.thelinuxreview.com/TUX/)




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-01-20 Thread Alvaro Herrera
On 2021-Jan-20, Michael Paquier wrote:

> +/*
> + * This is mostly duplicating ATExecSetTableSpaceNoStorage,
> + * which should maybe be factored out to a library function.
> + */
> Wouldn't it be better to do first the refactoring of 0002 and then
> 0001 so as REINDEX can use the new routine, instead of putting that
> into a comment?

I think merging 0001 and 0002 into a single commit is a reasonable
approach.  I don't oppose an initial refactoring commit if you want to
do that, but it doesn't seem necessary.

-- 
Álvaro Herrera39°49'30"S 73°17'W




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-01-20 Thread Michael Paquier
On Mon, Jan 18, 2021 at 02:37:57AM -0600, Justin Pryzby wrote:
> Attached.  I will re-review these myself tomorrow.

I have begun looking at 0001 and 0002...

+/*
+ * This is mostly duplicating ATExecSetTableSpaceNoStorage,
+ * which should maybe be factored out to a library function.
+ */
Wouldn't it be better to do first the refactoring of 0002 and then
0001 so as REINDEX can use the new routine, instead of putting that
into a comment?

+  This specifies that indexes will be rebuilt on a new tablespace.
+  Cannot be used with "mapped" relations. If SCHEMA,
+  DATABASE or SYSTEM is specified, 
then
+  all unsuitable relations will be skipped and a single 
WARNING
+  will be generated.
What is an unsuitable relation?  How can the end user know that?

This is missing ACL checks when moving the index into a new location,
so this requires some pg_tablespace_aclcheck() calls, and the other
patches share the same issue.

+   else if (partkind == RELKIND_PARTITIONED_TABLE)
+   {
+   Relation rel = table_open(partoid, ShareLock);
+   List*indexIds = RelationGetIndexList(rel);
+   ListCell *lc;
+
+   table_close(rel, NoLock);
+   foreach (lc, indexIds)
+   {
+   Oid indexid = lfirst_oid(lc);
+   (void) set_rel_tablespace(indexid, params->tablespaceOid);
+   }
+   }
This is really a good question.  ReindexPartitions() would trigger one
transaction per leaf to work on.  Changing the tablespace of the
partitioned table(s) before doing any work has the advantage to tell
any new partition to use the new tablespace.  Now, I see a struggling
point here: what should we do if the processing fails in the middle of
the move, leaving a portion of the leaves in the previous tablespace?
On a follow-up reindex with the same command, should the command force
a reindex even on the partitions that have been moved?  Or could there
be a point in skipping the partitions that are already on the new
tablespace and only process the ones on the previous tablespace?  It
seems to me that the first scenario makes the most sense as currently
a REINDEX works on all the relations defined, though there could be
use cases for the second case.  This should be documented, I think.

There are no tests for partitioned tables, aka we'd want to make sure
that the new partitioned index is on the correct tablespace, as well
as all its leaves.  It may be better to have at least two levels of
partitioned tables, as well as a partitioned table with no leaves in
the cases dealt with.

+*
+* Even if a table's indexes were moved to a new tablespace, the index
+* on its toast table is not normally moved.
 */
Still, REINDEX (TABLESPACE) TABLE should move all of them to be
consistent with ALTER TABLE SET TABLESPACE, but that's not the case
with this code, no?  This requires proper test coverage, but there is
nothing of the kind in this patch.
--
Michael


signature.asc
Description: PGP signature


Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-01-18 Thread Zhihong Yu
Hi,
For 0001-Allow-REINDEX-to-change-tablespace.patch :

+ * InvalidOid, use the tablespace in-use instead.

'in-use' seems a bit redundant in the sentence.
How about : InvalidOid, use the tablespace of the index instead.

Cheers

On Mon, Jan 18, 2021 at 12:38 AM Justin Pryzby  wrote:

> On Mon, Jan 18, 2021 at 02:18:44PM +0900, Michael Paquier wrote:
> > On Sat, Dec 12, 2020 at 01:45:26PM -0600, Justin Pryzby wrote:
> > > It's a lot like what I wrote as [PATCH v31 1/5] ExecReindex and
> ReindexParams
> > > In my v31 patch, I moved ReindexOptions to a private structure in
> indexcmds.c,
> > > with an "int options" bitmask which is passed to reindex_index() et
> al.  Your
> > > patch keeps/puts ReindexOptions index.h, so it also applies to
> reindex_index,
> > > which I think is good.
> >
> > a3dc926 is an equivalent of 0001~0003 merged together.  0008 had
> > better be submitted into a separate thread if there is value to it.
> > 0004~0007 are the pieces remaining.  Could it be possible to rebase
> > things on HEAD and put the tablespace bits into the structures
> > {Vacuum,Reindex,Cluster}Params?
>
> Attached.  I will re-review these myself tomorrow.
>
> --
> Justin
>


Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-01-18 Thread Justin Pryzby
On Mon, Jan 18, 2021 at 02:18:44PM +0900, Michael Paquier wrote:
> On Sat, Dec 12, 2020 at 01:45:26PM -0600, Justin Pryzby wrote:
> > It's a lot like what I wrote as [PATCH v31 1/5] ExecReindex and 
> > ReindexParams
> > In my v31 patch, I moved ReindexOptions to a private structure in 
> > indexcmds.c,
> > with an "int options" bitmask which is passed to reindex_index() et al.  
> > Your
> > patch keeps/puts ReindexOptions index.h, so it also applies to 
> > reindex_index,
> > which I think is good.
> 
> a3dc926 is an equivalent of 0001~0003 merged together.  0008 had
> better be submitted into a separate thread if there is value to it.
> 0004~0007 are the pieces remaining.  Could it be possible to rebase
> things on HEAD and put the tablespace bits into the structures 
> {Vacuum,Reindex,Cluster}Params?

Attached.  I will re-review these myself tomorrow.

-- 
Justin
>From 42991c90afda1b2a9fe4095418a87b5ead4b23d9 Mon Sep 17 00:00:00 2001
From: Alexey Kondratov 
Date: Mon, 23 Mar 2020 21:10:29 +0300
Subject: [PATCH 1/4] Allow REINDEX to change tablespace

REINDEX already does full relation rewrite, this patch adds a
possibility to specify a new tablespace where new relfilenode
will be created.
---
 doc/src/sgml/ref/reindex.sgml |  22 +
 src/backend/catalog/index.c   |  93 ++-
 src/backend/commands/indexcmds.c  | 103 +-
 src/bin/psql/tab-complete.c   |   4 +-
 src/include/catalog/index.h   |   2 +
 src/test/regress/input/tablespace.source  |  53 +++
 src/test/regress/output/tablespace.source | 102 +
 7 files changed, 374 insertions(+), 5 deletions(-)

diff --git a/doc/src/sgml/ref/reindex.sgml b/doc/src/sgml/ref/reindex.sgml
index 627b36300c..4f84060c4d 100644
--- a/doc/src/sgml/ref/reindex.sgml
+++ b/doc/src/sgml/ref/reindex.sgml
@@ -27,6 +27,7 @@ REINDEX [ ( option [, ...] ) ] { IN
 
 CONCURRENTLY [ boolean ]
 VERBOSE [ boolean ]
+TABLESPACE new_tablespace
 
  
 
@@ -187,6 +188,19 @@ REINDEX [ ( option [, ...] ) ] { IN
 

 
+   
+TABLESPACE
+
+ 
+  This specifies that indexes will be rebuilt on a new tablespace.
+  Cannot be used with "mapped" relations. If SCHEMA,
+  DATABASE or SYSTEM is specified, then
+  all unsuitable relations will be skipped and a single WARNING
+  will be generated.
+ 
+
+   
+

 VERBOSE
 
@@ -210,6 +224,14 @@ REINDEX [ ( option [, ...] ) ] { IN
 

 
+   
+new_tablespace
+
+ 
+  The tablespace where indexes will be rebuilt.
+ 
+
+   
   
  
 
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index b8cd35e995..9aa9fdf291 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -57,6 +57,7 @@
 #include "commands/event_trigger.h"
 #include "commands/progress.h"
 #include "commands/tablecmds.h"
+#include "commands/tablespace.h"
 #include "commands/trigger.h"
 #include "executor/executor.h"
 #include "miscadmin.h"
@@ -1394,9 +1395,13 @@ index_update_collation_versions(Oid relid, Oid coll)
  * Create concurrently an index based on the definition of the one provided by
  * caller.  The index is inserted into catalogs and needs to be built later
  * on.  This is called during concurrent reindex processing.
+ *
+ * "tablespaceOid" is the new tablespace to use for this index.  If
+ * InvalidOid, use the tablespace in-use instead.
  */
 Oid
-index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, const char *newName)
+index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId,
+			   Oid tablespaceOid, const char *newName)
 {
 	Relation	indexRelation;
 	IndexInfo  *oldInfo,
@@ -1526,7 +1531,8 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, const char
 			  newInfo,
 			  indexColNames,
 			  indexRelation->rd_rel->relam,
-			  indexRelation->rd_rel->reltablespace,
+			  OidIsValid(tablespaceOid) ?
+tablespaceOid : indexRelation->rd_rel->reltablespace,
 			  indexRelation->rd_indcollation,
 			  indclass->values,
 			  indcoloptions->values,
@@ -3591,6 +3597,8 @@ IndexGetRelation(Oid indexId, bool missing_ok)
 
 /*
  * reindex_index - This routine is used to recreate a single index
+ *
+ * See comments of reindex_relation() for details about "tablespaceOid".
  */
 void
 reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
@@ -3603,6 +3611,7 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
 	volatile bool skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
+	bool		set_tablespace = OidIsValid(params->tablespaceOid);
 
 	pg_rusage_init();
 
@@ -3654,6 +3663,35 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
 			 get_namespace_name(RelationGetNamespace(iRel)),
 			 RelationGetRelationName(iRel));
 

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-01-17 Thread Michael Paquier
On Sat, Dec 12, 2020 at 01:45:26PM -0600, Justin Pryzby wrote:
> It's a lot like what I wrote as [PATCH v31 1/5] ExecReindex and ReindexParams
> In my v31 patch, I moved ReindexOptions to a private structure in indexcmds.c,
> with an "int options" bitmask which is passed to reindex_index() et al.  Your
> patch keeps/puts ReindexOptions index.h, so it also applies to reindex_index,
> which I think is good.

a3dc926 is an equivalent of 0001~0003 merged together.  0008 had
better be submitted into a separate thread if there is value to it.
0004~0007 are the pieces remaining.  Could it be possible to rebase
things on HEAD and put the tablespace bits into the structures 
{Vacuum,Reindex,Cluster}Params?
--
Michael


signature.asc
Description: PGP signature


Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-01-17 Thread Michael Paquier
On Thu, Jan 14, 2021 at 02:18:45PM +0900, Michael Paquier wrote:
> Indeed.  Let's first wait a couple of days and see if others have any
> comments or objections about this v6.

Hearing nothing, I have looked at that again this morning and applied
v6 after a reindent and some adjustments in the comments.
--
Michael


signature.asc
Description: PGP signature


Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-01-13 Thread Michael Paquier
On Wed, Jan 13, 2021 at 04:39:40PM +0300, Alexey Kondratov wrote:
> + bits32  options;/* bitmask of 
> CLUSTEROPT_* */
> 
> This should say '/* bitmask of CLUOPT_* */', I guess, since there are only
> CLUOPT's defined. Otherwise, everything looks as per discussed upthread.

Indeed.  Let's first wait a couple of days and see if others have any
comments or objections about this v6.

> By the way, something went wrong with the last email subject, so I have
> changed it back to the original in this response. I also attached your patch
> (with only this CLUOPT_* correction) to keep it in the thread for sure.
> Although, postgresql.org's web archive is clever enough to link your email
> to the same thread even with different subject.

Oops.  Not sure what went wrong here.  Thanks.
--
Michael


signature.asc
Description: PGP signature


Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-01-13 Thread Alexey Kondratov

On 2021-01-13 14:34, Michael Paquier wrote:

On Wed, Jan 13, 2021 at 05:22:49PM +0900, Michael Paquier wrote:

Yeah, that makes sense.  I'll send an updated patch based on that.


And here you go as per the attached.  I don't think that there was
anything remaining on my radar.  This version still needs to be
indented properly though.

Thoughts?



Thanks.

+   bits32  options;/* bitmask of 
CLUSTEROPT_* */

This should say '/* bitmask of CLUOPT_* */', I guess, since there are 
only CLUOPT's defined. Otherwise, everything looks as per discussed 
upthread.


By the way, something went wrong with the last email subject, so I have 
changed it back to the original in this response. I also attached your 
patch (with only this CLUOPT_* correction) to keep it in the thread for 
sure. Although, postgresql.org's web archive is clever enough to link 
your email to the same thread even with different subject.



Regards
--
Alexey Kondratov

Postgres Professional https://www.postgrespro.com
Russian Postgres Companydiff --git a/src/include/catalog/index.h b/src/include/catalog/index.h
index 9904a76387..43cfdeaa6b 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.h
@@ -30,13 +30,16 @@ typedef enum
 } IndexStateFlagsAction;
 
 /* options for REINDEX */
-typedef enum ReindexOption
+typedef struct ReindexParams
 {
-	REINDEXOPT_VERBOSE = 1 << 0,	/* print progress info */
-	REINDEXOPT_REPORT_PROGRESS = 1 << 1,	/* report pgstat progress */
-	REINDEXOPT_MISSING_OK = 1 << 2, /* skip missing relations */
-	REINDEXOPT_CONCURRENTLY = 1 << 3	/* concurrent mode */
-} ReindexOption;
+	bits32		options;			/* bitmask of REINDEXOPT_* */
+} ReindexParams;
+
+/* flag bits for ReindexParams->flags */
+#define REINDEXOPT_VERBOSE		0x01	/* print progress info */
+#define REINDEXOPT_REPORT_PROGRESS 0x02 /* report pgstat progress */
+#define REINDEXOPT_MISSING_OK 	0x04	/* skip missing relations */
+#define REINDEXOPT_CONCURRENTLY	0x08	/* concurrent mode */
 
 /* state info for validate_index bulkdelete callback */
 typedef struct ValidateIndexState
@@ -146,7 +149,7 @@ extern void index_set_state_flags(Oid indexId, IndexStateFlagsAction action);
 extern Oid	IndexGetRelation(Oid indexId, bool missing_ok);
 
 extern void reindex_index(Oid indexId, bool skip_constraint_checks,
-		  char relpersistence, int options);
+		  char relpersistence, ReindexParams *params);
 
 /* Flag bits for reindex_relation(): */
 #define REINDEX_REL_PROCESS_TOAST			0x01
@@ -155,7 +158,7 @@ extern void reindex_index(Oid indexId, bool skip_constraint_checks,
 #define REINDEX_REL_FORCE_INDEXES_UNLOGGED	0x08
 #define REINDEX_REL_FORCE_INDEXES_PERMANENT 0x10
 
-extern bool reindex_relation(Oid relid, int flags, int options);
+extern bool reindex_relation(Oid relid, int flags, ReindexParams *params);
 
 extern bool ReindexIsProcessingHeap(Oid heapOid);
 extern bool ReindexIsProcessingIndex(Oid indexOid);
diff --git a/src/include/commands/cluster.h b/src/include/commands/cluster.h
index 401a0827ae..1245d944dc 100644
--- a/src/include/commands/cluster.h
+++ b/src/include/commands/cluster.h
@@ -18,16 +18,17 @@
 #include "storage/lock.h"
 #include "utils/relcache.h"
 
-
 /* options for CLUSTER */
-typedef enum ClusterOption
+#define CLUOPT_RECHECK 0x01		/* recheck relation state */
+#define CLUOPT_VERBOSE 0x02		/* print progress info */
+
+typedef struct ClusterParams
 {
-	CLUOPT_RECHECK = 1 << 0,	/* recheck relation state */
-	CLUOPT_VERBOSE = 1 << 1		/* print progress info */
-} ClusterOption;
+	bits32		options;			/* bitmask of CLUOPT_* */
+} ClusterParams;
 
 extern void cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel);
-extern void cluster_rel(Oid tableOid, Oid indexOid, int options);
+extern void cluster_rel(Oid tableOid, Oid indexOid, ClusterParams *params);
 extern void check_index_is_clusterable(Relation OldHeap, Oid indexOid,
 	   bool recheck, LOCKMODE lockmode);
 extern void mark_index_clustered(Relation rel, Oid indexOid, bool is_internal);
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index e2d2a77ca4..91281d6f8e 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -14,6 +14,7 @@
 #ifndef DEFREM_H
 #define DEFREM_H
 
+#include "catalog/index.h"
 #include "catalog/objectaddress.h"
 #include "nodes/params.h"
 #include "parser/parse_node.h"
@@ -34,11 +35,7 @@ extern ObjectAddress DefineIndex(Oid relationId,
  bool check_not_in_use,
  bool skip_build,
  bool quiet);
-extern int	ReindexParseOptions(ParseState *pstate, ReindexStmt *stmt);
-extern void ReindexIndex(RangeVar *indexRelation, int options, bool isTopLevel);
-extern Oid	ReindexTable(RangeVar *relation, int options, bool isTopLevel);
-extern void ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
-  int options);
+extern void ExecReindex(ParseState *pstate, ReindexStmt *stmt, bool isTopLevel);
 extern char 

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2021-01-13 Thread Michael Paquier
On Wed, Dec 23, 2020 at 07:30:35PM +0300, Alexey Kondratov wrote:
> After eyeballing the patch I can add that we should alter this comment:
> 
>   int options;/* bitmask of VacuumOption */
> 
> as you are going to replace VacuumOption with VACOPT_* defs. So this should
> say:
> 
> /* bitmask of VACOPT_* */

Check.

> 
> Also I have found naming to be a bit inconsistent:
>  * we have ReindexOptions, but VacuumParams
>  * and ReindexOptions->flags, but VacuumParams->options

Check.  As ReindexOptions and ClusterOptions are the new members of
the family here, we could change them to use Params instead with
"options" as bits32 internally.

> And the last one, you have used bits32 for Cluster/ReindexOptions, but left
> VacuumParams->options as int. Maybe we should also change it to bits32 for
> consistency?

Yeah, that makes sense.  I'll send an updated patch based on that.
--
Michael


signature.asc
Description: PGP signature


Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-23 Thread Michael Paquier
On Thu, Dec 24, 2020 at 10:50:34AM +0900, Michael Paquier wrote:
> FWIW, it still makes the most sense to me to keep the options that are
> extracted from the grammar or things that apply to all the
> sub-routines of REINDEX to be tracked in a single structure, so this
> should include only the REINDEXOPT_* set for now, with the tablespace
> OID as of this thread, and also the reindex filtering options.
> REINDEX_REL_* is in my opinion of a different family because they only
> apply to reindex_relation(), and partially to reindex_index(), so they
> are very localized.  In short, anything in need of only
> reindex_relation() has no need to know about the whole ReindexOption
> business.

I need more coffee here..  reindex_relation() knows about
ReindexOptions.  Still it would be weird to track REINDEX_REL_* at a
global level as ExecReindex(), ReindexTable(), ReindexMultipleTables()
and the like don't need to know about that.
--
Michael


signature.asc
Description: PGP signature


Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-23 Thread Michael Paquier
On Wed, Dec 23, 2020 at 07:07:54PM -0600, Justin Pryzby wrote:
> On Wed, Dec 23, 2020 at 09:14:18PM -0300, Alvaro Herrera wrote:
>> On 2020-Dec-23, Justin Pryzby wrote: 
>>> This was getting ugly:
>>> 
>>> extern void reindex_index(Oid indexId, bool skip_constraint_checks,
>>>   char relpersistence, int options, Oid 
>>> tablespaceOid)
>> 
>> Is this what I suggested?

No idea if this is what you suggested, but it would be annoying to
have to change this routine's signature each time we need to pass down
a new option.

> No ; that was from an earlier revision of the patch adding the tablespace,
> before Michael suggested a ReindexOptions struct, which subsumes 'options' and
> 'tablespaceOid'.
> 
> I see now that 'skip_constraint_checks' is from REINDEX_REL_CHECK_CONSTRAINTS.
> It seems like that should be a REINDEXOPT_* flag, rather than REINDEX_REL_*,
> so doesn't need to be a separate boolean.  See also: 2d3320d3d.

FWIW, it still makes the most sense to me to keep the options that are
extracted from the grammar or things that apply to all the
sub-routines of REINDEX to be tracked in a single structure, so this
should include only the REINDEXOPT_* set for now, with the tablespace
OID as of this thread, and also the reindex filtering options.
REINDEX_REL_* is in my opinion of a different family because they only
apply to reindex_relation(), and partially to reindex_index(), so they
are very localized.  In short, anything in need of only
reindex_relation() has no need to know about the whole ReindexOption
business.
--
Michael


signature.asc
Description: PGP signature


Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-23 Thread Justin Pryzby
On Wed, Dec 23, 2020 at 09:14:18PM -0300, Alvaro Herrera wrote:
> On 2020-Dec-23, Justin Pryzby wrote:
> 
> > This was getting ugly:
> > 
> > extern void reindex_index(Oid indexId, bool skip_constraint_checks,
> >   char relpersistence, int options, Oid 
> > tablespaceOid)Z
> 
> Is this what I suggested?

No ; that was from an earlier revision of the patch adding the tablespace,
before Michael suggested a ReindexOptions struct, which subsumes 'options' and
'tablespaceOid'.

I see now that 'skip_constraint_checks' is from REINDEX_REL_CHECK_CONSTRAINTS.
It seems liek that should be a REINDEXOPT_* flag, rather than REINDEX_REL_*,
so doesn't need to be a separate boolean.  See also: 2d3320d3d.

-- 
Justin




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-23 Thread Alvaro Herrera
On 2020-Dec-23, Justin Pryzby wrote:

> This was getting ugly:
> 
> extern void reindex_index(Oid indexId, bool skip_constraint_checks,
>   char relpersistence, int options, Oid 
> tablespaceOid)Z

Is this what I suggested?




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-23 Thread Justin Pryzby
On Wed, Dec 23, 2020 at 07:22:05PM -0300, Alvaro Herrera wrote:
> Also: it seems a bit weird to me to put the flags inside the options
> struct.  I would keep them separate -- so initially the options struct
> would only have the tablespace OID, on API cleanliness grounds:

I don't see why they'd be separate or why it's cleaner ?

If the user says REINDEX (CONCURRENTLY, VERBOSE, TABLESPACE ts) , why would we
pass around the boolean flags separately from the other options ?

> struct ReindexOptions
> {
>   tablepaceOidoid;
> };
> extern bool
> reindex_relation(Oid relid, bits32 flags, ReindexOptions *options);


> But also, are we really envisioning that these routines would have all
> that many additional options?  Maybe it is sufficient to do just
> 
> extern bool
> reindex_relation(Oid relid, bits32 flags, tablespaceOid Oid);

That's what we did initially, and Michael suggested to put it into a struct.
Which makes the tablespace patches cleaner for each of REINDEX, CLUSTER,
VACUUM, since it doesn't require modifying the signature of 5-10 functions.
And future patches get to reap the benefit.

These are intended to be like VacuumParams.  Consider that ClusterOptions is
proposed to get not just a tablespaceOid but also an idxtablespaceOid.

This was getting ugly:

extern void reindex_index(Oid indexId, bool skip_constraint_checks, 

   
  char relpersistence, int options, Oid tablespaceOid); 


-- 
Justin




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-23 Thread Alvaro Herrera
On 2020-Dec-23, Michael Paquier wrote:

>  bool
> -reindex_relation(Oid relid, int flags, int options)
> +reindex_relation(Oid relid, int flags, ReindexOptions *options)
>  {
>   Relationrel;
>   Oid toast_relid;

Wait a minute.  reindex_relation has 'flags' and *also* 'options' with
an embedded 'flags' member?  Surely that's not right.  I see that they
carry orthogonal sets of options ... but why aren't they a single
bitmask instead of two separate ones?  This looks weird and confusing.


Also: it seems a bit weird to me to put the flags inside the options
struct.  I would keep them separate -- so initially the options struct
would only have the tablespace OID, on API cleanliness grounds:

struct ReindexOptions
{
tablepaceOidoid;
};
extern bool
reindex_relation(Oid relid, bits32 flags, ReindexOptions *options);

I guess you could argue that it's more performance to set up only two
arguments to the function call instead of three .. but I doubt that's
measurable for anything in DDL-land.

But also, are we really envisioning that these routines would have all
that many additional options?  Maybe it is sufficient to do just

extern bool
reindex_relation(Oid relid, bits32 flags, tablespaceOid Oid);




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-23 Thread Alexey Kondratov

On 2020-12-23 10:38, Michael Paquier wrote:

On Tue, Dec 22, 2020 at 03:15:37PM -0600, Justin Pryzby wrote:

Now, I really think utility.c ought to pass in a pointer to a local
ReindexOptions variable to avoid all the memory context, which is 
unnecessary

and prone to error.


Yeah, it sounds right to me to just bite the bullet and do this
refactoring, limiting the manipulations of the options as much as
possible across contexts.  So +1 from me to merge 0001 and 0002
together.

I have adjusted a couple of comments and simplified a bit more the
code in utility.c.  I think that this is commitable, but let's wait
more than a couple of days for Alvaro and Peter first.  This is a
period of vacations for a lot of people, and there is no point to
apply something that would need more work at the end.  Using hexas for
the flags with bitmasks is the right conclusion IMO, but we are not
alone.



After eyeballing the patch I can add that we should alter this comment:

int options;/* bitmask of VacuumOption */

as you are going to replace VacuumOption with VACOPT_* defs. So this 
should say:


/* bitmask of VACOPT_* */

Also I have found naming to be a bit inconsistent:

 * we have ReindexOptions, but VacuumParams
 * and ReindexOptions->flags, but VacuumParams->options

And the last one, you have used bits32 for Cluster/ReindexOptions, but 
left VacuumParams->options as int. Maybe we should also change it to 
bits32 for consistency?



Regards
--
Alexey Kondratov

Postgres Professional https://www.postgrespro.com
Russian Postgres Company




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-23 Thread Alexey Kondratov

On 2020-12-23 08:22, Justin Pryzby wrote:

On Tue, Dec 22, 2020 at 03:22:19PM -0800, Zhihong Yu wrote:

Justin:
For reindex_index() :

+   if (options->tablespaceOid == MyDatabaseTableSpace)
+   options->tablespaceOid = InvalidOid;
...
+   oldTablespaceOid = iRel->rd_rel->reltablespace;
+   if (set_tablespace &&
+   (options->tablespaceOid != oldTablespaceOid ||
+   (options->tablespaceOid == MyDatabaseTableSpace &&
OidIsValid(oldTablespaceOid

I wonder why the options->tablespaceOid == MyDatabaseTableSpace clause
appears again in the second if statement.
Since the first if statement would assign InvalidOid
to options->tablespaceOid when the first if condition is satisfied.


Good question.  Alexey mentioned on Sept 23 that he added the first 
stanza.  to

avoid storing the DB's tablespace OID (rather than InvalidOid).

I think the 2nd half of the "or" is unnecessary since that was added 
setting to

options->tablespaceOid = InvalidOid.
If requesting to move to the DB's default tablespace, it'll now hit the 
first

part of the OR:


+   (options->tablespaceOid != oldTablespaceOid ||


Without the first stanza setting, it would've hit the 2nd condition:

+   (options->tablespaceOid == MyDatabaseTableSpace && 
OidIsValid(oldTablespaceOid


which means: "user requested to move a table to the DB's default 
tblspace, and

it was previously on a nondefault space".

So I think we can drop the 2nd half of the OR.  Thanks for noticing.


Yes, I have not noticed that we would have already assigned 
tablespaceOid to InvalidOid in this case. Back to the v7 we were doing 
this assignment a bit later, so this could make sense, but now it seems 
to be redundant. For some reason I have mixed these refactorings 
separated by a dozen of versions...



Thanks
--
Alexey Kondratov

Postgres Professional https://www.postgrespro.com
Russian Postgres Company




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-22 Thread Michael Paquier
On Tue, Dec 22, 2020 at 03:15:37PM -0600, Justin Pryzby wrote:
> Now, I really think utility.c ought to pass in a pointer to a local
> ReindexOptions variable to avoid all the memory context, which is unnecessary
> and prone to error.

Yeah, it sounds right to me to just bite the bullet and do this 
refactoring, limiting the manipulations of the options as much as
possible across contexts.  So +1 from me to merge 0001 and 0002
together.

I have adjusted a couple of comments and simplified a bit more the
code in utility.c.  I think that this is commitable, but let's wait
more than a couple of days for Alvaro and Peter first.  This is a
period of vacations for a lot of people, and there is no point to
apply something that would need more work at the end.  Using hexas for
the flags with bitmasks is the right conclusion IMO, but we are not
alone.

> ExecReindex() will set options.tablespaceOid, not a pointer.  Like
> this.

OK.  Good to know, I have not looked at this part of the patch yet.
--
Michael
diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h
index c041628049..89394b648e 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.h
@@ -30,13 +30,16 @@ typedef enum
 } IndexStateFlagsAction;
 
 /* options for REINDEX */
-typedef enum ReindexOption
+typedef struct ReindexOptions
 {
-	REINDEXOPT_VERBOSE = 1 << 0,	/* print progress info */
-	REINDEXOPT_REPORT_PROGRESS = 1 << 1,	/* report pgstat progress */
-	REINDEXOPT_MISSING_OK = 1 << 2, /* skip missing relations */
-	REINDEXOPT_CONCURRENTLY = 1 << 3	/* concurrent mode */
-} ReindexOption;
+	bits32		flags;			/* bitmask of REINDEXOPT_* */
+} ReindexOptions;
+
+/* flag bits for ReindexOptions->flags */
+#define REINDEXOPT_VERBOSE		0x01	/* print progress info */
+#define REINDEXOPT_REPORT_PROGRESS 0x02 /* report pgstat progress */
+#define REINDEXOPT_MISSING_OK 	0x04	/* skip missing relations */
+#define REINDEXOPT_CONCURRENTLY	0x08	/* concurrent mode */
 
 /* state info for validate_index bulkdelete callback */
 typedef struct ValidateIndexState
@@ -146,7 +149,7 @@ extern void index_set_state_flags(Oid indexId, IndexStateFlagsAction action);
 extern Oid	IndexGetRelation(Oid indexId, bool missing_ok);
 
 extern void reindex_index(Oid indexId, bool skip_constraint_checks,
-		  char relpersistence, int options);
+		  char relpersistence, ReindexOptions *options);
 
 /* Flag bits for reindex_relation(): */
 #define REINDEX_REL_PROCESS_TOAST			0x01
@@ -155,7 +158,7 @@ extern void reindex_index(Oid indexId, bool skip_constraint_checks,
 #define REINDEX_REL_FORCE_INDEXES_UNLOGGED	0x08
 #define REINDEX_REL_FORCE_INDEXES_PERMANENT 0x10
 
-extern bool reindex_relation(Oid relid, int flags, int options);
+extern bool reindex_relation(Oid relid, int flags, ReindexOptions *options);
 
 extern bool ReindexIsProcessingHeap(Oid heapOid);
 extern bool ReindexIsProcessingIndex(Oid indexOid);
diff --git a/src/include/commands/cluster.h b/src/include/commands/cluster.h
index 7cfb37c9b2..c66629cf73 100644
--- a/src/include/commands/cluster.h
+++ b/src/include/commands/cluster.h
@@ -18,16 +18,17 @@
 #include "storage/lock.h"
 #include "utils/relcache.h"
 
-
 /* options for CLUSTER */
-typedef enum ClusterOption
+#define CLUOPT_RECHECK 0x01		/* recheck relation state */
+#define CLUOPT_VERBOSE 0x02		/* print progress info */
+
+typedef struct ClusterOptions
 {
-	CLUOPT_RECHECK = 1 << 0,	/* recheck relation state */
-	CLUOPT_VERBOSE = 1 << 1		/* print progress info */
-} ClusterOption;
+	bits32		flags;			/* bitmask of CLUSTEROPT_* */
+} ClusterOptions;
 
 extern void cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel);
-extern void cluster_rel(Oid tableOid, Oid indexOid, int options);
+extern void cluster_rel(Oid tableOid, Oid indexOid, ClusterOptions *options);
 extern void check_index_is_clusterable(Relation OldHeap, Oid indexOid,
 	   bool recheck, LOCKMODE lockmode);
 extern void mark_index_clustered(Relation rel, Oid indexOid, bool is_internal);
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 1133ae1143..d4ea57e757 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -14,6 +14,7 @@
 #ifndef DEFREM_H
 #define DEFREM_H
 
+#include "catalog/index.h"
 #include "catalog/objectaddress.h"
 #include "nodes/params.h"
 #include "parser/parse_node.h"
@@ -34,11 +35,7 @@ extern ObjectAddress DefineIndex(Oid relationId,
  bool check_not_in_use,
  bool skip_build,
  bool quiet);
-extern int	ReindexParseOptions(ParseState *pstate, ReindexStmt *stmt);
-extern void ReindexIndex(RangeVar *indexRelation, int options, bool isTopLevel);
-extern Oid	ReindexTable(RangeVar *relation, int options, bool isTopLevel);
-extern void ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
-  int options);
+extern void ExecReindex(ParseState *pstate, ReindexStmt *stmt, bool isTopLevel);
 extern char *makeObjectName(const char *name1, 

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-22 Thread Justin Pryzby
On Tue, Dec 22, 2020 at 03:22:19PM -0800, Zhihong Yu wrote:
> Justin:
> For reindex_index() :
> 
> +   if (options->tablespaceOid == MyDatabaseTableSpace)
> +   options->tablespaceOid = InvalidOid;
> ...
> +   oldTablespaceOid = iRel->rd_rel->reltablespace;
> +   if (set_tablespace &&
> +   (options->tablespaceOid != oldTablespaceOid ||
> +   (options->tablespaceOid == MyDatabaseTableSpace &&
> OidIsValid(oldTablespaceOid
> 
> I wonder why the options->tablespaceOid == MyDatabaseTableSpace clause
> appears again in the second if statement.
> Since the first if statement would assign InvalidOid
> to options->tablespaceOid when the first if condition is satisfied.

Good question.  Alexey mentioned on Sept 23 that he added the first stanza.  to
avoid storing the DB's tablespace OID (rather than InvalidOid).

I think the 2nd half of the "or" is unnecessary since that was added setting to
options->tablespaceOid = InvalidOid.
If requesting to move to the DB's default tablespace, it'll now hit the first
part of the OR:

> +   (options->tablespaceOid != oldTablespaceOid ||

Without the first stanza setting, it would've hit the 2nd condition:

> +   (options->tablespaceOid == MyDatabaseTableSpace && 
> OidIsValid(oldTablespaceOid

which means: "user requested to move a table to the DB's default tblspace, and
it was previously on a nondefault space".

So I think we can drop the 2nd half of the OR.  Thanks for noticing.

-- 
Justin




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-22 Thread Zhihong Yu
Justin:
For reindex_index() :

+   if (options->tablespaceOid == MyDatabaseTableSpace)
+   options->tablespaceOid = InvalidOid;
...
+   if (set_tablespace &&
+   (options->tablespaceOid != oldTablespaceOid ||
+   (options->tablespaceOid == MyDatabaseTableSpace &&
OidIsValid(oldTablespaceOid

I wonder why the options->tablespaceOid == MyDatabaseTableSpace clause
appears again in the second if statement.
Since the first if statement would assign InvalidOid
to options->tablespaceOid when the first if condition is satisfied.

Cheers


On Tue, Dec 22, 2020 at 1:15 PM Justin Pryzby  wrote:

> On Tue, Dec 22, 2020 at 06:57:41PM +0900, Michael Paquier wrote:
> > On Tue, Dec 22, 2020 at 02:32:05AM -0600, Justin Pryzby wrote:
> > > Also, this one is going to be subsumed by ExecReindex(), so the palloc
> will go
> > > away (otherwise I would ask to pass it in from the caller):
> >
> > Yeah, maybe.  Still you need to be very careful if you have any
> > allocated variables like a tablespace or a path which requires to be
> > in the private context used by ReindexMultipleInternal() or even
> > ReindexRelationConcurrently(), so I am not sure you can avoid that
> > completely.  For now, we could choose the option to still use a
> > palloc(), and then save the options in the private contexts.  Forgot
> > that in the previous version actually.
>
> I can't see why this still uses memset instead of structure assignment.
>
> Now, I really think utility.c ought to pass in a pointer to a local
> ReindexOptions variable to avoid all the memory context, which is
> unnecessary
> and prone to error.
>
> ExecReindex() will set options.tablesapceOid, not a pointer.  Like this.
>
> I also changed the callback to be a ReindexOptions and not a pointer.
>
> --
> Justin
>


Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-22 Thread Justin Pryzby
On Tue, Dec 22, 2020 at 06:57:41PM +0900, Michael Paquier wrote:
> On Tue, Dec 22, 2020 at 02:32:05AM -0600, Justin Pryzby wrote:
> > Also, this one is going to be subsumed by ExecReindex(), so the palloc will 
> > go
> > away (otherwise I would ask to pass it in from the caller):
> 
> Yeah, maybe.  Still you need to be very careful if you have any
> allocated variables like a tablespace or a path which requires to be
> in the private context used by ReindexMultipleInternal() or even
> ReindexRelationConcurrently(), so I am not sure you can avoid that
> completely.  For now, we could choose the option to still use a
> palloc(), and then save the options in the private contexts.  Forgot
> that in the previous version actually.

I can't see why this still uses memset instead of structure assignment.

Now, I really think utility.c ought to pass in a pointer to a local
ReindexOptions variable to avoid all the memory context, which is unnecessary
and prone to error.

ExecReindex() will set options.tablesapceOid, not a pointer.  Like this.

I also changed the callback to be a ReindexOptions and not a pointer.

-- 
Justin
>From f12723a8e4ad550c009935fa5397d1d4a968c7bf Mon Sep 17 00:00:00 2001
From: Michael Paquier 
Date: Tue, 22 Dec 2020 18:57:41 +0900
Subject: [PATCH 1/3] refactor-utility-opts-michael-2.patch - hacked on by
 Justin

---
 src/backend/catalog/index.c  | 19 ---
 src/backend/commands/cluster.c   | 19 ---
 src/backend/commands/indexcmds.c | 97 +---
 src/backend/commands/tablecmds.c |  3 +-
 src/backend/commands/vacuum.c|  6 +-
 src/backend/tcop/utility.c   | 12 ++--
 src/include/catalog/index.h  | 19 ---
 src/include/commands/cluster.h   | 13 +++--
 src/include/commands/defrem.h| 17 --
 src/include/commands/vacuum.h| 20 +++
 src/tools/pgindent/typedefs.list |  2 +
 11 files changed, 124 insertions(+), 103 deletions(-)

diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 731610c701..d776c661d7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3594,7 +3594,7 @@ IndexGetRelation(Oid indexId, bool missing_ok)
  */
 void
 reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
-			  int options)
+			  ReindexOptions *options)
 {
 	Relation	iRel,
 heapRelation;
@@ -3602,7 +3602,7 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
 	IndexInfo  *indexInfo;
 	volatile bool skipped_constraint = false;
 	PGRUsage	ru0;
-	bool		progress = (options & REINDEXOPT_REPORT_PROGRESS) != 0;
+	bool		progress = ((options->flags & REINDEXOPT_REPORT_PROGRESS) != 0);
 
 	pg_rusage_init();
 
@@ -3611,12 +3611,12 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
 	 * we only need to be sure no schema or data changes are going on.
 	 */
 	heapId = IndexGetRelation(indexId,
-			  (options & REINDEXOPT_MISSING_OK) != 0);
+			  (options->flags & REINDEXOPT_MISSING_OK) != 0);
 	/* if relation is missing, leave */
 	if (!OidIsValid(heapId))
 		return;
 
-	if ((options & REINDEXOPT_MISSING_OK) != 0)
+	if ((options->flags & REINDEXOPT_MISSING_OK) != 0)
 		heapRelation = try_table_open(heapId, ShareLock);
 	else
 		heapRelation = table_open(heapId, ShareLock);
@@ -3792,7 +3792,7 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
 	}
 
 	/* Log what we did */
-	if (options & REINDEXOPT_VERBOSE)
+	if ((options->flags & REINDEXOPT_VERBOSE) != 0)
 		ereport(INFO,
 (errmsg("index \"%s\" was reindexed",
 		get_rel_name(indexId)),
@@ -3846,7 +3846,7 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
  * index rebuild.
  */
 bool
-reindex_relation(Oid relid, int flags, int options)
+reindex_relation(Oid relid, int flags, ReindexOptions *options)
 {
 	Relation	rel;
 	Oid			toast_relid;
@@ -3861,7 +3861,7 @@ reindex_relation(Oid relid, int flags, int options)
 	 * to prevent schema and data changes in it.  The lock level used here
 	 * should match ReindexTable().
 	 */
-	if ((options & REINDEXOPT_MISSING_OK) != 0)
+	if ((options->flags & REINDEXOPT_MISSING_OK) != 0)
 		rel = try_table_open(relid, ShareLock);
 	else
 		rel = table_open(relid, ShareLock);
@@ -3965,8 +3965,9 @@ reindex_relation(Oid relid, int flags, int options)
 		 * Note that this should fail if the toast relation is missing, so
 		 * reset REINDEXOPT_MISSING_OK.
 		 */
-		result |= reindex_relation(toast_relid, flags,
-   options & ~(REINDEXOPT_MISSING_OK));
+		ReindexOptions newoptions = *options;
+		newoptions.flags &= ~(REINDEXOPT_MISSING_OK);
+		result |= reindex_relation(toast_relid, flags, );
 	}
 
 	return result;
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index fd5a6eec86..32f5ae848f 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -103,7 +103,7 @@ void
 cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel)
 {
 	ListCell 

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-22 Thread Michael Paquier
On Tue, Dec 22, 2020 at 02:32:05AM -0600, Justin Pryzby wrote:
> Also, this one is going to be subsumed by ExecReindex(), so the palloc will go
> away (otherwise I would ask to pass it in from the caller):

Yeah, maybe.  Still you need to be very careful if you have any
allocated variables like a tablespace or a path which requires to be
in the private context used by ReindexMultipleInternal() or even
ReindexRelationConcurrently(), so I am not sure you can avoid that
completely.  For now, we could choose the option to still use a
palloc(), and then save the options in the private contexts.  Forgot
that in the previous version actually.
--
Michael
diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h
index c041628049..89394b648e 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.h
@@ -30,13 +30,16 @@ typedef enum
 } IndexStateFlagsAction;
 
 /* options for REINDEX */
-typedef enum ReindexOption
+typedef struct ReindexOptions
 {
-	REINDEXOPT_VERBOSE = 1 << 0,	/* print progress info */
-	REINDEXOPT_REPORT_PROGRESS = 1 << 1,	/* report pgstat progress */
-	REINDEXOPT_MISSING_OK = 1 << 2, /* skip missing relations */
-	REINDEXOPT_CONCURRENTLY = 1 << 3	/* concurrent mode */
-} ReindexOption;
+	bits32		flags;			/* bitmask of REINDEXOPT_* */
+} ReindexOptions;
+
+/* flag bits for ReindexOptions->flags */
+#define REINDEXOPT_VERBOSE		0x01	/* print progress info */
+#define REINDEXOPT_REPORT_PROGRESS 0x02 /* report pgstat progress */
+#define REINDEXOPT_MISSING_OK 	0x04	/* skip missing relations */
+#define REINDEXOPT_CONCURRENTLY	0x08	/* concurrent mode */
 
 /* state info for validate_index bulkdelete callback */
 typedef struct ValidateIndexState
@@ -146,7 +149,7 @@ extern void index_set_state_flags(Oid indexId, IndexStateFlagsAction action);
 extern Oid	IndexGetRelation(Oid indexId, bool missing_ok);
 
 extern void reindex_index(Oid indexId, bool skip_constraint_checks,
-		  char relpersistence, int options);
+		  char relpersistence, ReindexOptions *options);
 
 /* Flag bits for reindex_relation(): */
 #define REINDEX_REL_PROCESS_TOAST			0x01
@@ -155,7 +158,7 @@ extern void reindex_index(Oid indexId, bool skip_constraint_checks,
 #define REINDEX_REL_FORCE_INDEXES_UNLOGGED	0x08
 #define REINDEX_REL_FORCE_INDEXES_PERMANENT 0x10
 
-extern bool reindex_relation(Oid relid, int flags, int options);
+extern bool reindex_relation(Oid relid, int flags, ReindexOptions *options);
 
 extern bool ReindexIsProcessingHeap(Oid heapOid);
 extern bool ReindexIsProcessingIndex(Oid indexOid);
diff --git a/src/include/commands/cluster.h b/src/include/commands/cluster.h
index 7cfb37c9b2..c66629cf73 100644
--- a/src/include/commands/cluster.h
+++ b/src/include/commands/cluster.h
@@ -18,16 +18,17 @@
 #include "storage/lock.h"
 #include "utils/relcache.h"
 
-
 /* options for CLUSTER */
-typedef enum ClusterOption
+#define CLUOPT_RECHECK 0x01		/* recheck relation state */
+#define CLUOPT_VERBOSE 0x02		/* print progress info */
+
+typedef struct ClusterOptions
 {
-	CLUOPT_RECHECK = 1 << 0,	/* recheck relation state */
-	CLUOPT_VERBOSE = 1 << 1		/* print progress info */
-} ClusterOption;
+	bits32		flags;			/* bitmask of CLUSTEROPT_* */
+} ClusterOptions;
 
 extern void cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel);
-extern void cluster_rel(Oid tableOid, Oid indexOid, int options);
+extern void cluster_rel(Oid tableOid, Oid indexOid, ClusterOptions *options);
 extern void check_index_is_clusterable(Relation OldHeap, Oid indexOid,
 	   bool recheck, LOCKMODE lockmode);
 extern void mark_index_clustered(Relation rel, Oid indexOid, bool is_internal);
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 1133ae1143..43d5480c20 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -14,6 +14,7 @@
 #ifndef DEFREM_H
 #define DEFREM_H
 
+#include "catalog/index.h"
 #include "catalog/objectaddress.h"
 #include "nodes/params.h"
 #include "parser/parse_node.h"
@@ -34,11 +35,16 @@ extern ObjectAddress DefineIndex(Oid relationId,
  bool check_not_in_use,
  bool skip_build,
  bool quiet);
-extern int	ReindexParseOptions(ParseState *pstate, ReindexStmt *stmt);
-extern void ReindexIndex(RangeVar *indexRelation, int options, bool isTopLevel);
-extern Oid	ReindexTable(RangeVar *relation, int options, bool isTopLevel);
-extern void ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
-  int options);
+extern ReindexOptions *ReindexParseOptions(ParseState *pstate, ReindexStmt *stmt);
+extern void ReindexIndex(RangeVar *indexRelation,
+		 ReindexOptions *options,
+		 bool isTopLevel);
+extern Oid	ReindexTable(RangeVar *relation,
+		 ReindexOptions *options,
+		 bool isTopLevel);
+extern void ReindexMultipleTables(const char *objectName,
+  ReindexObjectType objectKind,
+  ReindexOptions *options);
 extern char *makeObjectName(const char *name1, 

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-22 Thread Justin Pryzby
On Tue, Dec 22, 2020 at 03:47:57PM +0900, Michael Paquier wrote:
> On Wed, Dec 16, 2020 at 10:01:11AM +0900, Michael Paquier wrote:
> > On Tue, Dec 15, 2020 at 09:45:17PM -0300, Alvaro Herrera wrote:
> > > I don't like this idea too much, because adding an option causes an ABI
> > > break.  I don't think we commonly add options in backbranches, but it
> > > has happened.  The bitmask is much easier to work with in that regard.
> > 
> > ABI flexibility is a good point here.  I did not consider this point
> > of view.  Thanks!
> 
> FWIW, I have taken a shot at this part of the patch, and finished with
> the attached.  This uses bits32 for the bitmask options and an hex
> style for the bitmask params, while bundling all the flags into
> dedicated structures for all the options that can be extended for the
> tablespace case (or some filtering for REINDEX).

Seems fine, but why do you do memcpy() instead of a structure assignment ?

> @@ -3965,8 +3965,11 @@ reindex_relation(Oid relid, int flags, int options)
>* Note that this should fail if the toast relation is missing, 
> so
>* reset REINDEXOPT_MISSING_OK.
>*/
> - result |= reindex_relation(toast_relid, flags,
> -options & 
> ~(REINDEXOPT_MISSING_OK));
> + ReindexOptions newoptions;
> +
> + memcpy(, options, sizeof(ReindexOptions));
> + newoptions.flags &= ~(REINDEXOPT_MISSING_OK);
> + result |= reindex_relation(toast_relid, flags, );

Could be newoptions = *options;

Also, this one is going to be subsumed by ExecReindex(), so the palloc will go
away (otherwise I would ask to pass it in from the caller):

> +ReindexOptions *
>  ReindexParseOptions(ParseState *pstate, ReindexStmt *stmt)
>  {
>   ListCell   *lc;
> - int options = 0;
> + ReindexOptions *options;
>   boolconcurrently = false;
>   boolverbose = false;
>  
> + options = (ReindexOptions *) palloc0(sizeof(ReindexOptions));
> +

-- 
Justin 




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-21 Thread Michael Paquier
On Wed, Dec 16, 2020 at 10:01:11AM +0900, Michael Paquier wrote:
> On Tue, Dec 15, 2020 at 09:45:17PM -0300, Alvaro Herrera wrote:
> > I don't like this idea too much, because adding an option causes an ABI
> > break.  I don't think we commonly add options in backbranches, but it
> > has happened.  The bitmask is much easier to work with in that regard.
> 
> ABI flexibility is a good point here.  I did not consider this point
> of view.  Thanks!

FWIW, I have taken a shot at this part of the patch, and finished with
the attached.  This uses bits32 for the bitmask options and an hex
style for the bitmask params, while bundling all the flags into
dedicated structures for all the options that can be extended for the
tablespace case (or some filtering for REINDEX).
--
Michael
diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h
index c041628049..89394b648e 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.h
@@ -30,13 +30,16 @@ typedef enum
 } IndexStateFlagsAction;
 
 /* options for REINDEX */
-typedef enum ReindexOption
+typedef struct ReindexOptions
 {
-	REINDEXOPT_VERBOSE = 1 << 0,	/* print progress info */
-	REINDEXOPT_REPORT_PROGRESS = 1 << 1,	/* report pgstat progress */
-	REINDEXOPT_MISSING_OK = 1 << 2, /* skip missing relations */
-	REINDEXOPT_CONCURRENTLY = 1 << 3	/* concurrent mode */
-} ReindexOption;
+	bits32		flags;			/* bitmask of REINDEXOPT_* */
+} ReindexOptions;
+
+/* flag bits for ReindexOptions->flags */
+#define REINDEXOPT_VERBOSE		0x01	/* print progress info */
+#define REINDEXOPT_REPORT_PROGRESS 0x02 /* report pgstat progress */
+#define REINDEXOPT_MISSING_OK 	0x04	/* skip missing relations */
+#define REINDEXOPT_CONCURRENTLY	0x08	/* concurrent mode */
 
 /* state info for validate_index bulkdelete callback */
 typedef struct ValidateIndexState
@@ -146,7 +149,7 @@ extern void index_set_state_flags(Oid indexId, IndexStateFlagsAction action);
 extern Oid	IndexGetRelation(Oid indexId, bool missing_ok);
 
 extern void reindex_index(Oid indexId, bool skip_constraint_checks,
-		  char relpersistence, int options);
+		  char relpersistence, ReindexOptions *options);
 
 /* Flag bits for reindex_relation(): */
 #define REINDEX_REL_PROCESS_TOAST			0x01
@@ -155,7 +158,7 @@ extern void reindex_index(Oid indexId, bool skip_constraint_checks,
 #define REINDEX_REL_FORCE_INDEXES_UNLOGGED	0x08
 #define REINDEX_REL_FORCE_INDEXES_PERMANENT 0x10
 
-extern bool reindex_relation(Oid relid, int flags, int options);
+extern bool reindex_relation(Oid relid, int flags, ReindexOptions *options);
 
 extern bool ReindexIsProcessingHeap(Oid heapOid);
 extern bool ReindexIsProcessingIndex(Oid indexOid);
diff --git a/src/include/commands/cluster.h b/src/include/commands/cluster.h
index 7cfb37c9b2..c66629cf73 100644
--- a/src/include/commands/cluster.h
+++ b/src/include/commands/cluster.h
@@ -18,16 +18,17 @@
 #include "storage/lock.h"
 #include "utils/relcache.h"
 
-
 /* options for CLUSTER */
-typedef enum ClusterOption
+#define CLUOPT_RECHECK 0x01		/* recheck relation state */
+#define CLUOPT_VERBOSE 0x02		/* print progress info */
+
+typedef struct ClusterOptions
 {
-	CLUOPT_RECHECK = 1 << 0,	/* recheck relation state */
-	CLUOPT_VERBOSE = 1 << 1		/* print progress info */
-} ClusterOption;
+	bits32		flags;			/* bitmask of CLUSTEROPT_* */
+} ClusterOptions;
 
 extern void cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel);
-extern void cluster_rel(Oid tableOid, Oid indexOid, int options);
+extern void cluster_rel(Oid tableOid, Oid indexOid, ClusterOptions *options);
 extern void check_index_is_clusterable(Relation OldHeap, Oid indexOid,
 	   bool recheck, LOCKMODE lockmode);
 extern void mark_index_clustered(Relation rel, Oid indexOid, bool is_internal);
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 1133ae1143..43d5480c20 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -14,6 +14,7 @@
 #ifndef DEFREM_H
 #define DEFREM_H
 
+#include "catalog/index.h"
 #include "catalog/objectaddress.h"
 #include "nodes/params.h"
 #include "parser/parse_node.h"
@@ -34,11 +35,16 @@ extern ObjectAddress DefineIndex(Oid relationId,
  bool check_not_in_use,
  bool skip_build,
  bool quiet);
-extern int	ReindexParseOptions(ParseState *pstate, ReindexStmt *stmt);
-extern void ReindexIndex(RangeVar *indexRelation, int options, bool isTopLevel);
-extern Oid	ReindexTable(RangeVar *relation, int options, bool isTopLevel);
-extern void ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
-  int options);
+extern ReindexOptions *ReindexParseOptions(ParseState *pstate, ReindexStmt *stmt);
+extern void ReindexIndex(RangeVar *indexRelation,
+		 ReindexOptions *options,
+		 bool isTopLevel);
+extern Oid	ReindexTable(RangeVar *relation,
+		 ReindexOptions *options,
+		 bool isTopLevel);
+extern void ReindexMultipleTables(const char *objectName,
+		

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-15 Thread Michael Paquier
On Tue, Dec 15, 2020 at 09:45:17PM -0300, Alvaro Herrera wrote:
> I don't like this idea too much, because adding an option causes an ABI
> break.  I don't think we commonly add options in backbranches, but it
> has happened.  The bitmask is much easier to work with in that regard.

ABI flexibility is a good point here.  I did not consider this point
of view.  Thanks!
--
Michael


signature.asc
Description: PGP signature


Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-15 Thread Alvaro Herrera
On 2020-Dec-12, Peter Eisentraut wrote:

> On 2020-12-11 21:27, Alvaro Herrera wrote:
> > By the way--  What did you think of the idea of explictly marking the
> > types used for bitmasks using types bits32 and friends, instead of plain
> > int, which is harder to spot?
> 
> If we want to make it clearer, why not turn the thing into a struct, as in
> the attached patch, and avoid the bit fiddling altogether.

I don't like this idea too much, because adding an option causes an ABI
break.  I don't think we commonly add options in backbranches, but it
has happened.  The bitmask is much easier to work with in that regard.





Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-15 Thread Justin Pryzby
On Mon, Dec 14, 2020 at 06:14:17PM -0600, Justin Pryzby wrote:
> On Sat, Dec 12, 2020 at 01:45:26PM -0600, Justin Pryzby wrote:
> > On Sat, Dec 12, 2020 at 09:20:35AM +0100, Peter Eisentraut wrote:
> > > On 2020-12-11 21:27, Alvaro Herrera wrote:
> > > > By the way--  What did you think of the idea of explictly marking the
> > > > types used for bitmasks using types bits32 and friends, instead of plain
> > > > int, which is harder to spot?
> > > 
> > > If we want to make it clearer, why not turn the thing into a struct, as in
> > > the attached patch, and avoid the bit fiddling altogether.
> > 
> > I like this.
> > It's a lot like what I wrote as [PATCH v31 1/5] ExecReindex and 
> > ReindexParams
> > In my v31 patch, I moved ReindexOptions to a private structure in 
> > indexcmds.c,
> > with an "int options" bitmask which is passed to reindex_index() et al.  
> > Your
> > patch keeps/puts ReindexOptions index.h, so it also applies to 
> > reindex_index,
> > which I think is good.
> > 
> > So I've rebased this branch on your patch.
> > 
> > Some thoughts:
> > 
> >  - what about removing the REINDEXOPT_* prefix ?
> >  - You created local vars with initialization like "={}". But I thought it's
> >needed to include at least one struct member like "={false}", or else
> >they're not guaranteed to be zerod ?
> >  - You passed the structure across function calls.  The usual convention is 
> > to
> >pass a pointer.
> 
> I think maybe Michael missed this message (?)
> I had applied some changes on top of Peter's patch.
> 
> I squished those commits now, and also handled ClusterOption and VacuumOption
> in the same style.
> 
> Some more thoughts:
>  - should the structures be named in plural ? "ReindexOptions" etc.  Since 
> they
>define *all* the options, not just a single bit.
>  - For vacuum, do we even need a separate structure, or should the members be
>directly within VacuumParams ?  It's a bit odd to write
>params.options.verbose.  Especially since there's also ternary options 
> which
>are directly within params.
>  - Then, for cluster, I think it should be called ClusterParams, and 
> eventually
>include the tablespaceOid, like what we're doing for Reindex.
> 
> I am awaiting feedback on these before going further since I've done too much
> rebasing with these ideas going back and forth and back.

With Alexey's agreement, I propose something like this.

I've merged some commits and kept separate the ones which are more likely to be
disputed/amended.  But it may be best to read the series as a single commit,
like "git diff origin.."

-- 
Justin
>From ee702a6f49392e84bb51ec432d0974c7369b Mon Sep 17 00:00:00 2001
From: Justin Pryzby 
Date: Tue, 15 Dec 2020 17:55:21 -0600
Subject: [PATCH 1/4] Convert options to struct: Reindex/Cluster/Vacuum

Remove prefixes and lowercase structure member variables;
Rename to plural: Vacuum/ClusterOptions;
---
 src/backend/access/heap/vacuumlazy.c |   8 +-
 src/backend/catalog/index.c  |  26 +++---
 src/backend/commands/analyze.c   |  15 ++--
 src/backend/commands/cluster.c   |  29 +++---
 src/backend/commands/indexcmds.c | 100 ++---
 src/backend/commands/tablecmds.c |   4 +-
 src/backend/commands/vacuum.c| 128 +--
 src/backend/postmaster/autovacuum.c  |  14 +--
 src/backend/tcop/utility.c   |  10 +--
 src/include/catalog/index.h  |  16 ++--
 src/include/commands/cluster.h   |  10 +--
 src/include/commands/defrem.h|   9 +-
 src/include/commands/vacuum.h|  29 +++---
 13 files changed, 198 insertions(+), 200 deletions(-)

diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index 25f2d5df1b..6bfed2b2da 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -456,7 +456,7 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params,
 		starttime = GetCurrentTimestamp();
 	}
 
-	if (params->options & VACOPT_VERBOSE)
+	if (params->options.verbose)
 		elevel = INFO;
 	else
 		elevel = DEBUG2;
@@ -484,7 +484,7 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params,
 			   xidFullScanLimit);
 	aggressive |= MultiXactIdPrecedesOrEquals(onerel->rd_rel->relminmxid,
 			  mxactFullScanLimit);
-	if (params->options & VACOPT_DISABLE_PAGE_SKIPPING)
+	if (params->options.disable_page_skipping)
 		aggressive = true;
 
 	vacrelstats = (LVRelStats *) palloc0(sizeof(LVRelStats));
@@ -902,7 +902,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
 	 * be replayed on any hot standby, where it can be disruptive.
 	 */
 	next_unskippable_block = 0;
-	if ((params->options & VACOPT_DISABLE_PAGE_SKIPPING) == 0)
+	if (!params->options.disable_page_skipping)
 	{
 		while (next_unskippable_block < nblocks)
 		{
@@ -960,7 +960,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
 		{
 			/* Time to advance 

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-15 Thread Alexey Kondratov

On 2020-12-15 03:14, Justin Pryzby wrote:

On Sat, Dec 12, 2020 at 01:45:26PM -0600, Justin Pryzby wrote:

On Sat, Dec 12, 2020 at 09:20:35AM +0100, Peter Eisentraut wrote:
> On 2020-12-11 21:27, Alvaro Herrera wrote:
> > By the way--  What did you think of the idea of explictly marking the
> > types used for bitmasks using types bits32 and friends, instead of plain
> > int, which is harder to spot?
>
> If we want to make it clearer, why not turn the thing into a struct, as in
> the attached patch, and avoid the bit fiddling altogether.

I like this.
It's a lot like what I wrote as [PATCH v31 1/5] ExecReindex and 
ReindexParams
In my v31 patch, I moved ReindexOptions to a private structure in 
indexcmds.c,
with an "int options" bitmask which is passed to reindex_index() et 
al.  Your
patch keeps/puts ReindexOptions index.h, so it also applies to 
reindex_index,

which I think is good.

So I've rebased this branch on your patch.

Some thoughts:

 - what about removing the REINDEXOPT_* prefix ?
 - You created local vars with initialization like "={}". But I 
thought it's
   needed to include at least one struct member like "={false}", or 
else

   they're not guaranteed to be zerod ?
 - You passed the structure across function calls.  The usual 
convention is to

   pass a pointer.


I think maybe Michael missed this message (?)
I had applied some changes on top of Peter's patch.

I squished those commits now, and also handled ClusterOption and 
VacuumOption

in the same style.

Some more thoughts:
 - should the structures be named in plural ? "ReindexOptions" etc.  
Since they

   define *all* the options, not just a single bit.
 - For vacuum, do we even need a separate structure, or should the 
members be

   directly within VacuumParams ?  It's a bit odd to write
   params.options.verbose.  Especially since there's also ternary 
options which

   are directly within params.


This is exactly what I have thought after looking on Peter's patch. 
Writing 'params.options.some_option' looks just too verbose. I even 
started moving all vacuum options into VacuumParams on my own and was in 
the middle of the process when realized that there are some places that 
do not fit well, like:


if (!vacuum_is_relation_owner(RelationGetRelid(onerel),
onerel->rd_rel,
params->options & VACOPT_ANALYZE))

Here we do not want to set option permanently, but rather to trigger 
some additional code path in the vacuum_is_relation_owner(), IIUC. With 
unified VacuumParams we should do:


bool opt_analyze = params->analyze;
...
params->analyze = true;
if (!vacuum_is_relation_owner(RelationGetRelid(onerel),
onerel->rd_rel, params))
...
params->analyze = opt_analyze;

to achieve the same, but it does not look good to me, or change the 
whole interface. I have found at least one other place like that so far 
--- vacuum_open_relation() in the analyze_rel().


Not sure how we could better cope with such logic.

 - Then, for cluster, I think it should be called ClusterParams, and 
eventually

   include the tablespaceOid, like what we're doing for Reindex.

I am awaiting feedback on these before going further since I've done 
too much

rebasing with these ideas going back and forth and back.


Yes, we have moved a bit from my original patch set in the thread with 
all this refactoring. However, all the consequent patches are heavily 
depend on this interface, so let us decide first on the proposed 
refactoring.



Regards
--
Alexey Kondratov

Postgres Professional https://www.postgrespro.com
Russian Postgres Company




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-14 Thread Justin Pryzby
On Sat, Dec 12, 2020 at 01:45:26PM -0600, Justin Pryzby wrote:
> On Sat, Dec 12, 2020 at 09:20:35AM +0100, Peter Eisentraut wrote:
> > On 2020-12-11 21:27, Alvaro Herrera wrote:
> > > By the way--  What did you think of the idea of explictly marking the
> > > types used for bitmasks using types bits32 and friends, instead of plain
> > > int, which is harder to spot?
> > 
> > If we want to make it clearer, why not turn the thing into a struct, as in
> > the attached patch, and avoid the bit fiddling altogether.
> 
> I like this.
> It's a lot like what I wrote as [PATCH v31 1/5] ExecReindex and ReindexParams
> In my v31 patch, I moved ReindexOptions to a private structure in indexcmds.c,
> with an "int options" bitmask which is passed to reindex_index() et al.  Your
> patch keeps/puts ReindexOptions index.h, so it also applies to reindex_index,
> which I think is good.
> 
> So I've rebased this branch on your patch.
> 
> Some thoughts:
> 
>  - what about removing the REINDEXOPT_* prefix ?
>  - You created local vars with initialization like "={}". But I thought it's
>needed to include at least one struct member like "={false}", or else
>they're not guaranteed to be zerod ?
>  - You passed the structure across function calls.  The usual convention is to
>pass a pointer.

I think maybe Michael missed this message (?)
I had applied some changes on top of Peter's patch.

I squished those commits now, and also handled ClusterOption and VacuumOption
in the same style.

Some more thoughts:
 - should the structures be named in plural ? "ReindexOptions" etc.  Since they
   define *all* the options, not just a single bit.
 - For vacuum, do we even need a separate structure, or should the members be
   directly within VacuumParams ?  It's a bit odd to write
   params.options.verbose.  Especially since there's also ternary options which
   are directly within params.
 - Then, for cluster, I think it should be called ClusterParams, and eventually
   include the tablespaceOid, like what we're doing for Reindex.

I am awaiting feedback on these before going further since I've done too much
rebasing with these ideas going back and forth and back.

-- 
Justin
>From 34bf8abaca50d39cb9fd00b21752f931b05a62f3 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut 
Date: Sat, 12 Dec 2020 09:17:55 +0100
Subject: [PATCH 1/4] Convert reindex options to struct

---
 src/backend/catalog/index.c  | 24 
 src/backend/commands/cluster.c   |  3 +-
 src/backend/commands/indexcmds.c | 96 
 src/backend/commands/tablecmds.c |  4 +-
 src/backend/tcop/utility.c   | 10 ++--
 src/include/catalog/index.h  | 16 +++---
 src/include/commands/defrem.h|  9 +--
 7 files changed, 83 insertions(+), 79 deletions(-)

diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 731610c701..da2f45b796 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3594,7 +3594,7 @@ IndexGetRelation(Oid indexId, bool missing_ok)
  */
 void
 reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
-			  int options)
+			  ReindexOptions *options)
 {
 	Relation	iRel,
 heapRelation;
@@ -3602,7 +3602,6 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
 	IndexInfo  *indexInfo;
 	volatile bool skipped_constraint = false;
 	PGRUsage	ru0;
-	bool		progress = (options & REINDEXOPT_REPORT_PROGRESS) != 0;
 
 	pg_rusage_init();
 
@@ -3611,12 +3610,12 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
 	 * we only need to be sure no schema or data changes are going on.
 	 */
 	heapId = IndexGetRelation(indexId,
-			  (options & REINDEXOPT_MISSING_OK) != 0);
+			  options->REINDEXOPT_MISSING_OK);
 	/* if relation is missing, leave */
 	if (!OidIsValid(heapId))
 		return;
 
-	if ((options & REINDEXOPT_MISSING_OK) != 0)
+	if (options->REINDEXOPT_MISSING_OK)
 		heapRelation = try_table_open(heapId, ShareLock);
 	else
 		heapRelation = table_open(heapId, ShareLock);
@@ -3625,7 +3624,7 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
 	if (!heapRelation)
 		return;
 
-	if (progress)
+	if (options->REINDEXOPT_REPORT_PROGRESS)
 	{
 		pgstat_progress_start_command(PROGRESS_COMMAND_CREATE_INDEX,
 	  heapId);
@@ -3641,7 +3640,7 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
 	 */
 	iRel = index_open(indexId, AccessExclusiveLock);
 
-	if (progress)
+	if (options->REINDEXOPT_REPORT_PROGRESS)
 		pgstat_progress_update_param(PROGRESS_CREATEIDX_ACCESS_METHOD_OID,
 	 iRel->rd_rel->relam);
 
@@ -3792,14 +3791,14 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
 	}
 
 	/* Log what we did */
-	if (options & REINDEXOPT_VERBOSE)
+	if (options->REINDEXOPT_VERBOSE)
 		ereport(INFO,
 (errmsg("index \"%s\" was reindexed",
 		get_rel_name(indexId)),
  errdetail_internal("%s",
 	pg_rusage_show(;
 
-	if 

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-13 Thread Michael Paquier
On Sat, Dec 12, 2020 at 01:45:26PM -0600, Justin Pryzby wrote:
> On Sat, Dec 12, 2020 at 09:20:35AM +0100, Peter Eisentraut wrote:
>> On 2020-12-11 21:27, Alvaro Herrera wrote:
>>> By the way--  What did you think of the idea of explictly marking the
>>> types used for bitmasks using types bits32 and friends, instead of plain
>>> int, which is harder to spot?
>> 
>> If we want to make it clearer, why not turn the thing into a struct, as in
>> the attached patch, and avoid the bit fiddling altogether.

-   reindex_relation(OIDOldHeap, reindex_flags, 0);
+   reindex_relation(OIDOldHeap, reindex_flags, (ReindexOptions){});
This is not common style in the PG code.  Usually we would do that
with memset(0) or similar.

+   bool REINDEXOPT_VERBOSE;/* print progress info */
+   bool REINDEXOPT_REPORT_PROGRESS;/* report pgstat progress */
+   bool REINDEXOPT_MISSING_OK; /* skip missing relations */
+   bool REINDEXOPT_CONCURRENTLY;   /* concurrent mode */
+} ReindexOptions
Neither is this one to use upper-case characters for variable names.

Now, we will need a ReindexOptions in the long-term to store all those
options and there would be much more coming that booleans here (this
thread talks about tablespaces, there is another thread about
collation filtering).  Between using bits32 with some hex flags or
just a set of booleans within a structure, I would choose the former
as a matter of habit but yours has the advantage to make debugging a
no-brainer, which is good.  For any approach taken, it seems to me
that the same style should be applied to ClusterOption and
Vacuum{Option,Params}.
--
Michael


signature.asc
Description: PGP signature


Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-12 Thread Justin Pryzby
On Sat, Dec 12, 2020 at 01:45:26PM -0600, Justin Pryzby wrote:
> On Sat, Dec 12, 2020 at 09:20:35AM +0100, Peter Eisentraut wrote:
> > On 2020-12-11 21:27, Alvaro Herrera wrote:
> > > By the way--  What did you think of the idea of explictly marking the
> > > types used for bitmasks using types bits32 and friends, instead of plain
> > > int, which is harder to spot?
> > 
> > If we want to make it clearer, why not turn the thing into a struct, as in
> > the attached patch, and avoid the bit fiddling altogether.
> 
> I like this.
> It's a lot like what I wrote as [PATCH v31 1/5] ExecReindex and ReindexParams
> In my v31 patch, I moved ReindexOptions to a private structure in indexcmds.c,
> with an "int options" bitmask which is passed to reindex_index() et al.  Your
> patch keeps/puts ReindexOptions index.h, so it also applies to reindex_index,
> which I think is good.
> 
> So I've rebased this branch on your patch.

Also, the cfbot's windows VS compilation failed due to "compound literal",
which I don't think is used anywhere else.

https://ci.appveyor.com/project/postgresql-cfbot/postgresql/build/1.0.120108

  src/backend/commands/cluster.c(1580): warning C4133: 'return' : incompatible 
types - from 'List *' to 'int *' [C:\projects\postgresql\postgres.vcxproj]
"C:\projects\postgresql\pgsql.sln" (default target) (1) ->
"C:\projects\postgresql\cyrillic_and_mic.vcxproj" (default target) (5) ->
"C:\projects\postgresql\postgres.vcxproj" (default target) (6) ->
(ClCompile target) ->
  src/backend/commands/cluster.c(1415): error C2059: syntax error : '}' 
[C:\projects\postgresql\postgres.vcxproj]
  src/backend/commands/cluster.c(1534): error C2143: syntax error : missing '{' 
before '*' [C:\projects\postgresql\postgres.vcxproj]
  src/backend/commands/cluster.c(1536): error C2371: 'get_tables_to_cluster' : 
redefinition; different basic types [C:\projects\postgresql\postgres.vcxproj]
  src/backend/commands/indexcmds.c(2462): error C2059: syntax error : '}' 
[C:\projects\postgresql\postgres.vcxproj]
  src/backend/commands/tablecmds.c(1894): error C2059: syntax error : '}' 
[C:\projects\postgresql\postgres.vcxproj]

My fix! patch resolves that.

-- 
Justin




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-12 Thread Peter Eisentraut

On 2020-12-11 21:27, Alvaro Herrera wrote:

By the way--  What did you think of the idea of explictly marking the
types used for bitmasks using types bits32 and friends, instead of plain
int, which is harder to spot?


If we want to make it clearer, why not turn the thing into a struct, as 
in the attached patch, and avoid the bit fiddling altogether.
From d3125b3bfb8a3dc23e38f38bcf850ca6fc36f492 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut 
Date: Sat, 12 Dec 2020 09:17:55 +0100
Subject: [PATCH] Convert reindex options to struct

---
 src/backend/catalog/index.c  | 19 ---
 src/backend/commands/cluster.c   |  2 +-
 src/backend/commands/indexcmds.c | 94 
 src/backend/commands/tablecmds.c |  2 +-
 src/backend/tcop/utility.c   |  4 +-
 src/include/catalog/index.h  | 16 +++---
 src/include/commands/defrem.h|  9 +--
 7 files changed, 74 insertions(+), 72 deletions(-)

diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 731610c701..06342fddf1 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3594,7 +3594,7 @@ IndexGetRelation(Oid indexId, bool missing_ok)
  */
 void
 reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
- int options)
+ ReindexOptions options)
 {
RelationiRel,
heapRelation;
@@ -3602,7 +3602,7 @@ reindex_index(Oid indexId, bool skip_constraint_checks, 
char persistence,
IndexInfo  *indexInfo;
volatile bool skipped_constraint = false;
PGRUsageru0;
-   boolprogress = (options & REINDEXOPT_REPORT_PROGRESS) != 0;
+   boolprogress = options.REINDEXOPT_REPORT_PROGRESS;
 
pg_rusage_init();
 
@@ -3611,12 +3611,12 @@ reindex_index(Oid indexId, bool skip_constraint_checks, 
char persistence,
 * we only need to be sure no schema or data changes are going on.
 */
heapId = IndexGetRelation(indexId,
- (options & 
REINDEXOPT_MISSING_OK) != 0);
+ 
options.REINDEXOPT_MISSING_OK);
/* if relation is missing, leave */
if (!OidIsValid(heapId))
return;
 
-   if ((options & REINDEXOPT_MISSING_OK) != 0)
+   if (options.REINDEXOPT_MISSING_OK)
heapRelation = try_table_open(heapId, ShareLock);
else
heapRelation = table_open(heapId, ShareLock);
@@ -3792,7 +3792,7 @@ reindex_index(Oid indexId, bool skip_constraint_checks, 
char persistence,
}
 
/* Log what we did */
-   if (options & REINDEXOPT_VERBOSE)
+   if (options.REINDEXOPT_VERBOSE)
ereport(INFO,
(errmsg("index \"%s\" was reindexed",
get_rel_name(indexId)),
@@ -3846,7 +3846,7 @@ reindex_index(Oid indexId, bool skip_constraint_checks, 
char persistence,
  * index rebuild.
  */
 bool
-reindex_relation(Oid relid, int flags, int options)
+reindex_relation(Oid relid, int flags, ReindexOptions options)
 {
Relationrel;
Oid toast_relid;
@@ -3861,7 +3861,7 @@ reindex_relation(Oid relid, int flags, int options)
 * to prevent schema and data changes in it.  The lock level used here
 * should match ReindexTable().
 */
-   if ((options & REINDEXOPT_MISSING_OK) != 0)
+   if (options.REINDEXOPT_MISSING_OK)
rel = try_table_open(relid, ShareLock);
else
rel = table_open(relid, ShareLock);
@@ -3965,8 +3965,9 @@ reindex_relation(Oid relid, int flags, int options)
 * Note that this should fail if the toast relation is missing, 
so
 * reset REINDEXOPT_MISSING_OK.
 */
-   result |= reindex_relation(toast_relid, flags,
-  options & 
~(REINDEXOPT_MISSING_OK));
+   ReindexOptions newoptions = options;
+   newoptions.REINDEXOPT_MISSING_OK = false;
+   result |= reindex_relation(toast_relid, flags, newoptions);
}
 
return result;
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index fd5a6eec86..b0aa3536d1 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -1412,7 +1412,7 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
pgstat_progress_update_param(PROGRESS_CLUSTER_PHASE,
 
PROGRESS_CLUSTER_PHASE_REBUILD_INDEX);
 
-   reindex_relation(OIDOldHeap, reindex_flags, 0);
+   reindex_relation(OIDOldHeap, reindex_flags, (ReindexOptions){});
 
/* Report that we are now doing clean up */
pgstat_progress_update_param(PROGRESS_CLUSTER_PHASE,

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-11 Thread Michael Paquier
On Fri, Dec 11, 2020 at 05:27:03PM -0300, Alvaro Herrera wrote:
> By the way--  What did you think of the idea of explictly marking the
> types used for bitmasks using types bits32 and friends, instead of plain
> int, which is harder to spot?

Right, we could just do that while the area is changed.  It is worth
noting that all the REINDEX_REL_* handling could be brushed.  Another
point that has been raised on a recent thread by Peter was that people
preferred an hex style for the declarations rather than bit shifts.
What do you think?
--
Michael


signature.asc
Description: PGP signature


Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-11 Thread Alvaro Herrera
By the way--  What did you think of the idea of explictly marking the
types used for bitmasks using types bits32 and friends, instead of plain
int, which is harder to spot?




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-11 Thread Peter Eisentraut

On 2020-12-05 02:30, Michael Paquier wrote:

On Fri, Dec 04, 2020 at 04:28:26PM -0300, Alvaro Herrera wrote:

FWIW I'm with Peter on this.


Okay, attached is a patch to adjust the enums for the set of utility
commands that is the set of things I have touched lately.  Should that
be extended more?  I have not done that as a lot of those structures
exist as such for a long time.


I think this patch is good.

I have in the meantime committed a similar patch for cleaning up this 
issue in pg_dump.





Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-04 Thread Michael Paquier
On Fri, Dec 04, 2020 at 04:28:26PM -0300, Alvaro Herrera wrote:
> FWIW I'm with Peter on this.

Okay, attached is a patch to adjust the enums for the set of utility
commands that is the set of things I have touched lately.  Should that
be extended more?  I have not done that as a lot of those structures
exist as such for a long time.
--
Michael
diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h
index c041628049..8f80f9f3aa 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.h
@@ -30,13 +30,10 @@ typedef enum
 } IndexStateFlagsAction;
 
 /* options for REINDEX */
-typedef enum ReindexOption
-{
-	REINDEXOPT_VERBOSE = 1 << 0,	/* print progress info */
-	REINDEXOPT_REPORT_PROGRESS = 1 << 1,	/* report pgstat progress */
-	REINDEXOPT_MISSING_OK = 1 << 2, /* skip missing relations */
-	REINDEXOPT_CONCURRENTLY = 1 << 3	/* concurrent mode */
-} ReindexOption;
+#define REINDEXOPT_VERBOSE			(1 << 0)	/* print progress info */
+#define REINDEXOPT_REPORT_PROGRESS	(1 << 1)	/* report pgstat progress */
+#define REINDEXOPT_MISSING_OK		(1 << 2)	/* skip missing relations */
+#define REINDEXOPT_CONCURRENTLY		(1 << 3)	/* concurrent mode */
 
 /* state info for validate_index bulkdelete callback */
 typedef struct ValidateIndexState
diff --git a/src/include/commands/cluster.h b/src/include/commands/cluster.h
index 7cfb37c9b2..ded9379818 100644
--- a/src/include/commands/cluster.h
+++ b/src/include/commands/cluster.h
@@ -20,11 +20,8 @@
 
 
 /* options for CLUSTER */
-typedef enum ClusterOption
-{
-	CLUOPT_RECHECK = 1 << 0,	/* recheck relation state */
-	CLUOPT_VERBOSE = 1 << 1		/* print progress info */
-} ClusterOption;
+#define CLUOPT_RECHECK	(1 << 0)	/* recheck relation state */
+#define CLUOPT_VERBOSE	(1 << 1)	/* print progress info */
 
 extern void cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel);
 extern void cluster_rel(Oid tableOid, Oid indexOid, int options);
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index a4cd721400..1d7b6eaf04 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -174,17 +174,16 @@ typedef struct VacAttrStats
 	int			rowstride;
 } VacAttrStats;
 
-typedef enum VacuumOption
-{
-	VACOPT_VACUUM = 1 << 0,		/* do VACUUM */
-	VACOPT_ANALYZE = 1 << 1,	/* do ANALYZE */
-	VACOPT_VERBOSE = 1 << 2,	/* print progress info */
-	VACOPT_FREEZE = 1 << 3,		/* FREEZE option */
-	VACOPT_FULL = 1 << 4,		/* FULL (non-concurrent) vacuum */
-	VACOPT_SKIP_LOCKED = 1 << 5,	/* skip if cannot get lock */
-	VACOPT_SKIPTOAST = 1 << 6,	/* don't process the TOAST table, if any */
-	VACOPT_DISABLE_PAGE_SKIPPING = 1 << 7	/* don't skip any pages */
-} VacuumOption;
+/* options for VACUUM */
+#define VACOPT_VACUUM		(1 << 0)	/* do VACUUM */
+#define VACOPT_ANALYZE		(1 << 1)	/* do ANALYZE */
+#define VACOPT_VERBOSE		(1 << 2)	/* print progress info */
+#define VACOPT_FREEZE		(1 << 3)	/* FREEZE option */
+#define VACOPT_FULL			(1 << 4)	/* FULL (non-concurrent) vacuum */
+#define VACOPT_SKIP_LOCKED	(1 << 5)	/* skip if cannot get lock */
+#define VACOPT_SKIPTOAST	(1 << 6)	/* don't process the TOAST table, if
+		 * any */
+#define VACOPT_DISABLE_PAGE_SKIPPING (1 << 7)	/* don't skip any pages */
 
 /*
  * A ternary value used by vacuum parameters.
@@ -207,7 +206,7 @@ typedef enum VacOptTernaryValue
  */
 typedef struct VacuumParams
 {
-	int			options;		/* bitmask of VacuumOption */
+	int			options;		/* bitmask of VACOPT_* values */
 	int			freeze_min_age; /* min freeze age, -1 to use default */
 	int			freeze_table_age;	/* age at which to scan whole table */
 	int			multixact_freeze_min_age;	/* min multixact freeze age, -1 to
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 14d24b3cc4..5e2cbba407 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -2453,7 +2453,8 @@ ChooseIndexColumnNames(List *indexElems)
 
 /*
  * ReindexParseOptions
- *		Parse list of REINDEX options, returning a bitmask of ReindexOption.
+ *		Parse list of REINDEX options, returning a bitmask of REINDEXOPT_*
+ *		values.
  */
 int
 ReindexParseOptions(ParseState *pstate, ReindexStmt *stmt)


signature.asc
Description: PGP signature


Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-04 Thread Justin Pryzby
On Fri, Dec 04, 2020 at 09:40:31PM +0300, Alexey Kondratov wrote:
> >  I liked the bools, but dropped them so the patch is smaller.
> 
> I had a look on 0001 and it looks mostly fine to me except some strange
> mixture of tabs/spaces in the ExecReindex(). There is also a couple of
> meaningful comments:
> 
> - options =
> - (verbose ? REINDEXOPT_VERBOSE : 0) |
> - (concurrently ? REINDEXOPT_CONCURRENTLY : 0);
> + if (verbose)
> + params.options |= REINDEXOPT_VERBOSE;
> 
> Why do we need this intermediate 'verbose' variable here? We only use it
> once to set a bitmask. Maybe we can do it like this:
> 
> params.options |= defGetBoolean(opt) ?
>   REINDEXOPT_VERBOSE : 0;

That allows *setting* REINDEXOPT_VERBOSE, but doesn't *unset* it if someone
runs (VERBOSE OFF).  So I kept the bools like Michael originally had rather
than writing "else: params.options &= ~REINDEXOPT_VERBOSE"

> See also attached txt file with diff (I wonder can I trick cfbot this way,
> so it does not apply the diff).

Yes, I think that works :)
I believe it looks for *.diff and *.patch.

> + int options;/* bitmask of lowlevel REINDEXOPT_* */
> 
> I would prefer if the comment says '/* bitmask of ReindexOption */' as in
> the VacuumOptions, since citing the exact enum type make it easier to
> navigate source code.

Yes, thanks.

This also fixes some minor formatting and rebase issues, including broken doc/.

-- 
Justin
>From 5d874da6f93341cb5aed4d3cc54137cbc341d57c Mon Sep 17 00:00:00 2001
From: Justin Pryzby 
Date: Wed, 2 Dec 2020 20:54:47 -0600
Subject: [PATCH v33 1/5] ExecReindex and ReindexParams

TODO: typedef
---
 src/backend/commands/indexcmds.c | 145 ---
 src/backend/tcop/utility.c   |  40 +
 src/include/commands/defrem.h|   7 +-
 3 files changed, 97 insertions(+), 95 deletions(-)

diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 14d24b3cc4..c2ee88f2c3 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -67,6 +67,10 @@
 #include "utils/syscache.h"
 
 
+typedef struct ReindexParams {
+	int options;	/* bitmask of ReindexOption */
+} ReindexParams;
+
 /* non-export function prototypes */
 static bool CompareOpclassOptions(Datum *opts1, Datum *opts2, int natts);
 static void CheckPredicate(Expr *predicate);
@@ -86,12 +90,15 @@ static char *ChooseIndexName(const char *tabname, Oid namespaceId,
 			 bool primary, bool isconstraint);
 static char *ChooseIndexNameAddition(List *colnames);
 static List *ChooseIndexColumnNames(List *indexElems);
+static void ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel);
+static Oid ReindexTable(RangeVar *relation, ReindexParams *params, bool isTopLevel);
+static void ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind, ReindexParams *params);
 static void RangeVarCallbackForReindexIndex(const RangeVar *relation,
 			Oid relId, Oid oldRelId, void *arg);
 static void reindex_error_callback(void *args);
-static void ReindexPartitions(Oid relid, int options, bool isTopLevel);
-static void ReindexMultipleInternal(List *relids, int options);
-static bool ReindexRelationConcurrently(Oid relationOid, int options);
+static void ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel);
+static void ReindexMultipleInternal(List *relids, ReindexParams *params);
+static bool ReindexRelationConcurrently(Oid relationOid, ReindexParams *params);
 static void update_relispartition(Oid relationId, bool newval);
 static inline void set_indexsafe_procflags(void);
 
@@ -100,7 +107,7 @@ static inline void set_indexsafe_procflags(void);
  */
 struct ReindexIndexCallbackState
 {
-	int			options;		/* options from statement */
+	ReindexParams		*params;
 	Oid			locked_table_oid;	/* tracks previously locked table */
 };
 
@@ -2452,14 +2459,17 @@ ChooseIndexColumnNames(List *indexElems)
 }
 
 /*
- * ReindexParseOptions
- *		Parse list of REINDEX options, returning a bitmask of ReindexOption.
+ * Reindex accordinging to stmt.
+ * This calls the intermediate routines: ReindexIndex, ReindexTable, ReindexMultipleTables,
+ * which ultimately call reindex_index, reindex_relation, ReindexRelationConcurrently.
+ * Note that partitioned relations are handled by ReindexPartitions, except that
+ * ReindexRelationConcurrently handles concurrently reindexing a table.
  */
-int
-ReindexParseOptions(ParseState *pstate, ReindexStmt *stmt)
+void
+ExecReindex(ParseState *pstate, ReindexStmt *stmt, bool isTopLevel)
 {
-	ListCell   *lc;
-	int			options = 0;
+	ListCell   	*lc;
+	ReindexParams		params = {0};
 	bool		concurrently = false;
 	bool		verbose = false;
 
@@ -2480,19 +2490,53 @@ ReindexParseOptions(ParseState *pstate, ReindexStmt *stmt)
 	 parser_errposition(pstate, opt->location)));
 	}
 
-	options =
-		(verbose ? REINDEXOPT_VERBOSE : 0) |
-		(concurrently ? REINDEXOPT_CONCURRENTLY : 0);
+	if 

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-04 Thread Alvaro Herrera
On 2020-Dec-04, Michael Paquier wrote:

> VacuumOption does that since 6776142, and ClusterOption since 9ebe057,
> so switching ReindexOption to just match the two others still looks
> like the most consistent move.

9ebe057 goes to show why this is a bad idea, since it has this:

+typedef enum ClusterOption
+{
+   CLUOPT_RECHECK, /* recheck relation state */
+   CLUOPT_VERBOSE  /* print progress info */
+} ClusterOption;

and then you do things like

+   if ($2)
+   n->options |= CLUOPT_VERBOSE;

and then tests like

+   if ((options & VACOPT_VERBOSE) != 0)

Now if you were to ever define third and fourth values in that enum,
this would immediately start malfunctioning.

FWIW I'm with Peter on this.




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-04 Thread Alexey Kondratov

On 2020-12-04 04:25, Justin Pryzby wrote:

On Thu, Dec 03, 2020 at 04:12:53PM +0900, Michael Paquier wrote:

> +typedef struct ReindexParams {
> +  bool concurrently;
> +  bool verbose;
> +  bool missingok;
> +
> +  int options;/* bitmask of lowlevel REINDEXOPT_* */
> +} ReindexParams;
> +

By moving everything into indexcmds.c, keeping ReindexParams within it
makes sense to me.  Now, there is no need for the three booleans
because options stores the same information, no?


 I liked the bools, but dropped them so the patch is smaller.



I had a look on 0001 and it looks mostly fine to me except some strange 
mixture of tabs/spaces in the ExecReindex(). There is also a couple of 
meaningful comments:


-   options =
-   (verbose ? REINDEXOPT_VERBOSE : 0) |
-   (concurrently ? REINDEXOPT_CONCURRENTLY : 0);
+   if (verbose)
+   params.options |= REINDEXOPT_VERBOSE;

Why do we need this intermediate 'verbose' variable here? We only use it 
once to set a bitmask. Maybe we can do it like this:


params.options |= defGetBoolean(opt) ?
REINDEXOPT_VERBOSE : 0;

See also attached txt file with diff (I wonder can I trick cfbot this 
way, so it does not apply the diff).


+   int options;/* bitmask of lowlevel REINDEXOPT_* */

I would prefer if the comment says '/* bitmask of ReindexOption */' as 
in the VacuumOptions, since citing the exact enum type make it easier to 
navigate source code.




Regarding the REINDEX patch, I think this comment is misleading:

|+* Even if table was moved to new tablespace,
normally toast cannot move.
| */
|+   Oid toasttablespaceOid = allowSystemTableMods ?
tablespaceOid : InvalidOid;
|result |= reindex_relation(toast_relid, flags,

I think it ought to say "Even if a table's indexes were moved to a new
tablespace, its toast table's index is not normally moved"
Right ?



Yes, I think so, we are dealing only with index tablespace changing 
here. Thanks for noticing.




Also, I don't know whether we should check for GLOBALTABLESPACE_OID 
after

calling get_tablespace_oid(), or in the lowlevel routines.  Note that
reindex_relation is called during cluster/vacuum, and in the later 
patches, I
moved the test from from cluster() and ExecVacuum() to 
rebuild_relation().




IIRC, I wanted to do GLOBALTABLESPACE_OID check as early as possible 
(just after getting Oid), since it does not make sense to proceed 
further if tablespace is set to that value. So initially there were a 
lot of duplicative GLOBALTABLESPACE_OID checks, since there were a lot 
of reindex entry-points (index, relation, concurrently, etc.). Now we 
are going to have ExecReindex(), so there are much less entry-points and 
in my opinion it is fine to keep this validation just after 
get_tablespace_oid().


However, this is mostly a sanity check. I can hardly imagine a lot of 
users trying to constantly move indexes to the global tablespace, so it 
is also OK to put this check deeper into guts.



Regards
--
Alexey Kondratov

Postgres Professional https://www.postgrespro.com
Russian Postgres Companydiff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index a27f8f9d83..0b1884815c 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -2472,8 +2472,6 @@ void
 ExecReindex(ParseState *pstate, ReindexStmt *stmt, bool isTopLevel)
 {
 	ReindexParams		params = {0};
-	bool		verbose = false,
-concurrently = false;
 	ListCell   	*lc;
 	char	*tablespace = NULL;
 
@@ -2483,9 +2481,11 @@ ExecReindex(ParseState *pstate, ReindexStmt *stmt, bool isTopLevel)
 		DefElem*opt = (DefElem *) lfirst(lc);
 
 		if (strcmp(opt->defname, "verbose") == 0)
-			verbose = defGetBoolean(opt);
+			params.options |= defGetBoolean(opt) ?
+REINDEXOPT_VERBOSE : 0;
 		else if (strcmp(opt->defname, "concurrently") == 0)
-			concurrently = defGetBoolean(opt);
+			params.options |= defGetBoolean(opt) ?
+REINDEXOPT_CONCURRENTLY : 0;
 		else if (strcmp(opt->defname, "tablespace") == 0)
 			tablespace = defGetString(opt);
 		else
@@ -2496,18 +2496,12 @@ ExecReindex(ParseState *pstate, ReindexStmt *stmt, bool isTopLevel)
 	 parser_errposition(pstate, opt->location)));
 	}
 
-	if (verbose)
-		params.options |= REINDEXOPT_VERBOSE;
+	params.tablespaceOid = tablespace ?
+		get_tablespace_oid(tablespace, false) : InvalidOid;
 
-	if (concurrently)
-	{
-		params.options |= REINDEXOPT_CONCURRENTLY;
+	if (params.options & REINDEXOPT_CONCURRENTLY)
 		PreventInTransactionBlock(isTopLevel,
   "REINDEX CONCURRENTLY");
-	}
-
-	params.tablespaceOid = tablespace ?
-		get_tablespace_oid(tablespace, false) : InvalidOid;
 
 	switch (stmt->kind)
 	{


Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-03 Thread Michael Paquier
On Thu, Dec 03, 2020 at 08:46:09PM +0100, Peter Eisentraut wrote:
> There are a couple of more places like this, including the existing
> ClusterOption that this patched moved around, but we should be removing
> those.
> 
> My reasoning is that if you look at an enum value of this type, either say
> in a switch statement or a debugger, the enum value might not be any of the
> defined symbols.  So that way you lose all the type checking that an enum
> might give you.

VacuumOption does that since 6776142, and ClusterOption since 9ebe057,
so switching ReindexOption to just match the two others still looks
like the most consistent move.  Please note that there is more than
that, like ScanOptions, relopt_kind, RVROption, InstrumentOption,
TableLikeOption.

I would not mind changing that, though I am not sure that this
improves readability.  And if we'd do it, it may make sense to extend
that even more to the places where it would apply like the places
mentioned one paragraph above.
--
Michael


signature.asc
Description: PGP signature


Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-03 Thread Justin Pryzby
On Thu, Dec 03, 2020 at 04:12:53PM +0900, Michael Paquier wrote:
> > +typedef struct ReindexParams {
> > +   bool concurrently;
> > +   bool verbose;
> > +   bool missingok;
> > +
> > +   int options;/* bitmask of lowlevel REINDEXOPT_* */
> > +} ReindexParams;
> > +
> 
> By moving everything into indexcmds.c, keeping ReindexParams within it
> makes sense to me.  Now, there is no need for the three booleans
> because options stores the same information, no?

 I liked the bools, but dropped them so the patch is smaller.

> >  struct ReindexIndexCallbackState
> >  {
> > -   int options;/* options from 
> > statement */
> > +   boolconcurrently;
> > Oid locked_table_oid;   /* tracks previously 
> > locked table */
> >  };
> 
> Here also, I think that we should just pass down the full
> ReindexParams set.

Ok.

Regarding the REINDEX patch, I think this comment is misleading:

|/*
| * If the relation has a secondary toast rel, reindex that too while we
| * still hold the lock on the main table.
| */
|if ((flags & REINDEX_REL_PROCESS_TOAST) && OidIsValid(toast_relid))
|{
|/*
| * Note that this should fail if the toast relation is 
missing, so
| * reset REINDEXOPT_MISSING_OK.
|+*
|+* Even if table was moved to new tablespace, normally toast 
cannot move.
| */
|+   Oid toasttablespaceOid = allowSystemTableMods ? tablespaceOid 
: InvalidOid;
|result |= reindex_relation(toast_relid, flags,
|-  options & 
~(REINDEXOPT_MISSING_OK));
|+  options & 
~(REINDEXOPT_MISSING_OK),
|+  
toasttablespaceOid);
|}

I think it ought to say "Even if a table's indexes were moved to a new
tablespace, its toast table's index is not normally moved"
Right ?

Also, I don't know whether we should check for GLOBALTABLESPACE_OID after
calling get_tablespace_oid(), or in the lowlevel routines.  Note that
reindex_relation is called during cluster/vacuum, and in the later patches, I
moved the test from from cluster() and ExecVacuum() to rebuild_relation().

-- 
Justin
>From df43fe542081178ea74ffb2d1d77342e6c657c2f Mon Sep 17 00:00:00 2001
From: Justin Pryzby 
Date: Wed, 2 Dec 2020 20:54:47 -0600
Subject: [PATCH v32 1/5] ExecReindex and ReindexParams

TODO: typedef
---
 src/backend/commands/indexcmds.c | 151 ---
 src/backend/tcop/utility.c   |  40 +---
 src/include/commands/defrem.h|   7 +-
 3 files changed, 101 insertions(+), 97 deletions(-)

diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 14d24b3cc4..f0456dcbef 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -67,6 +67,10 @@
 #include "utils/syscache.h"
 
 
+typedef struct ReindexParams {
+	int options;	/* bitmask of lowlevel REINDEXOPT_* */
+} ReindexParams;
+
 /* non-export function prototypes */
 static bool CompareOpclassOptions(Datum *opts1, Datum *opts2, int natts);
 static void CheckPredicate(Expr *predicate);
@@ -86,12 +90,17 @@ static char *ChooseIndexName(const char *tabname, Oid namespaceId,
 			 bool primary, bool isconstraint);
 static char *ChooseIndexNameAddition(List *colnames);
 static List *ChooseIndexColumnNames(List *indexElems);
+
+static void ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel);
+static Oid ReindexTable(RangeVar *relation, ReindexParams *params, bool isTopLevel);
+static void ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind, ReindexParams *params);
+
 static void RangeVarCallbackForReindexIndex(const RangeVar *relation,
 			Oid relId, Oid oldRelId, void *arg);
 static void reindex_error_callback(void *args);
-static void ReindexPartitions(Oid relid, int options, bool isTopLevel);
-static void ReindexMultipleInternal(List *relids, int options);
-static bool ReindexRelationConcurrently(Oid relationOid, int options);
+static void ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel);
+static void ReindexMultipleInternal(List *relids, ReindexParams *params);
+static bool ReindexRelationConcurrently(Oid relationOid, ReindexParams *params);
 static void update_relispartition(Oid relationId, bool newval);
 static inline void set_indexsafe_procflags(void);
 
@@ -100,7 +109,7 @@ static inline void set_indexsafe_procflags(void);
  */
 struct ReindexIndexCallbackState
 {
-	int			options;		/* options from statement */
+	ReindexParams		*params;
 	Oid			locked_table_oid;	/* tracks previously locked table */
 };
 
@@ -2452,16 +2461,19 @@ ChooseIndexColumnNames(List *indexElems)
 }
 
 /*
- * ReindexParseOptions
- *		Parse list of 

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-03 Thread Peter Eisentraut
A side comment on this patch:  I think using enums as bit mask values is 
bad style.  So changing this:


-/* Reindex options */
-#define REINDEXOPT_VERBOSE (1 << 0) /* print progress info */
-#define REINDEXOPT_REPORT_PROGRESS (1 << 1) /* report pgstat progress */
-#define REINDEXOPT_MISSING_OK (1 << 2) /* skip missing relations */
-#define REINDEXOPT_CONCURRENTLY (1 << 3)   /* concurrent mode */

to this:

+typedef enum ReindexOption
+{
+   REINDEXOPT_VERBOSE = 1 << 0,/* print progress info */
+   REINDEXOPT_REPORT_PROGRESS = 1 << 1,/* report pgstat progress */
+   REINDEXOPT_MISSING_OK = 1 << 2, /* skip missing relations */
+   REINDEXOPT_CONCURRENTLY = 1 << 3/* concurrent mode */
+} ReindexOption;

seems wrong.

There are a couple of more places like this, including the existing 
ClusterOption that this patched moved around, but we should be removing 
those.


My reasoning is that if you look at an enum value of this type, either 
say in a switch statement or a debugger, the enum value might not be any 
of the defined symbols.  So that way you lose all the type checking that 
an enum might give you.


Let's just keep the #define's like it is done in almost all other places.




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-02 Thread Michael Paquier
On Wed, Dec 02, 2020 at 10:30:08PM -0600, Justin Pryzby wrote:
> Good idea.  I think you mean like this.

Yes, something like that.  Thanks.

> +typedef struct ReindexParams {
> + bool concurrently;
> + bool verbose;
> + bool missingok;
> +
> + int options;/* bitmask of lowlevel REINDEXOPT_* */
> +} ReindexParams;
> +

By moving everything into indexcmds.c, keeping ReindexParams within it
makes sense to me.  Now, there is no need for the three booleans
because options stores the same information, no?

>  struct ReindexIndexCallbackState
>  {
> - int options;/* options from 
> statement */
> + boolconcurrently;
>   Oid locked_table_oid;   /* tracks previously 
> locked table */
>  };

Here also, I think that we should just pass down the full
ReindexParams set.
--
Michael


signature.asc
Description: PGP signature


Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-02 Thread Justin Pryzby
On Thu, Dec 03, 2020 at 10:19:43AM +0900, Michael Paquier wrote:
> OK, this one is now committed.  As of this thread, I think that we are
> going to need to do a bit more once we add options that are not just
> booleans for both commands (the grammar rules do not need to be
> changed now):
> - Have a ReindexParams, similarly to VacuumParams except that we store
> the results of the parsing in a single place.  With the current HEAD,
> I did not see yet the point in doing so because we just need an
> integer that maps to a bitmask made of ReindexOption.
> - The part related to ReindexStmt in utility.c is getting more and
> more complicated, so we could move most of the execution into
> indexcmds.c with some sort of ExecReindex() doing the option parsing
> job, and go to the correct code path depending on the object type
> dealt with.

Good idea.  I think you mean like this.

I don't know where to put the struct.
I thought maybe the lowlevel, integer options should live in the struct, in
addition to bools, but it's not important.

-- 
Justin
>From 520d1c54d6988d69768178b4abf03c5837654b9a Mon Sep 17 00:00:00 2001
From: Alexey Kondratov 
Date: Wed, 23 Sep 2020 18:21:16 +0300
Subject: [PATCH v31 3/5] Refactor and reuse set_rel_tablespace()

---
 src/backend/catalog/index.c  | 74 
 src/backend/commands/indexcmds.c | 35 ---
 src/include/catalog/index.h  |  2 +
 3 files changed, 49 insertions(+), 62 deletions(-)

diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 532c11e9dd..b317f556df 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3607,7 +3607,6 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
 	Relation	iRel,
 heapRelation;
 	Oid			heapId;
-	Oid			oldTablespaceOid;
 	IndexInfo  *indexInfo;
 	volatile bool skipped_constraint = false;
 	PGRUsage	ru0;
@@ -3723,41 +3722,17 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
 		tablespaceOid = InvalidOid;
 
 	/*
-	 * Set the new tablespace for the relation.  Do that only in the
-	 * case where the reindex caller wishes to enforce a new tablespace.
+	 * Set the new tablespace for the relation if requested.
 	 */
-	oldTablespaceOid = iRel->rd_rel->reltablespace;
 	if (set_tablespace &&
-		(tablespaceOid != oldTablespaceOid ||
-		(tablespaceOid == MyDatabaseTableSpace && OidIsValid(oldTablespaceOid
+		set_rel_tablespace(indexId, tablespaceOid))
 	{
-		Relation		pg_class;
-		Form_pg_class	rd_rel;
-		HeapTuple		tuple;
-
-		/* First get a modifiable copy of the relation's pg_class row */
-		pg_class = table_open(RelationRelationId, RowExclusiveLock);
-
-		tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(indexId));
-		if (!HeapTupleIsValid(tuple))
-			elog(ERROR, "cache lookup failed for relation %u", indexId);
-		rd_rel = (Form_pg_class) GETSTRUCT(tuple);
-
 		/*
 		 * Mark the relation as ready to be dropped at transaction commit,
 		 * before making visible the new tablespace change so as this won't
 		 * miss things.
 		 */
 		RelationDropStorage(iRel);
-
-		/* Update the pg_class row */
-		rd_rel->reltablespace = tablespaceOid;
-		CatalogTupleUpdate(pg_class, >t_self, tuple);
-
-		heap_freetuple(tuple);
-
-		table_close(pg_class, RowExclusiveLock);
-
 		RelationAssumeNewRelfilenode(iRel);
 
 		/* Make sure the reltablespace change is visible */
@@ -4063,6 +4038,51 @@ reindex_relation(Oid relid, int flags, int options, Oid tablespaceOid)
 	return result;
 }
 
+/*
+ * set_rel_tablespace - modify relation tablespace in the pg_class entry.
+ *
+ * 'reloid' is an Oid of relation to be modified.
+ * 'tablespaceOid' is an Oid of new tablespace.
+ *
+ * Catalog modification is done only if tablespaceOid is different from
+ * the currently set.  Returned bool value is indicating whether any changes
+ * were made or not.
+ */
+bool
+set_rel_tablespace(Oid reloid, Oid tablespaceOid)
+{
+	Relation		pg_class;
+	HeapTuple		tuple;
+	Form_pg_class	rd_rel;
+	bool			changed = false;
+	Oid			oldTablespaceOid;
+
+	/* Get a modifiable copy of the relation's pg_class row. */
+	pg_class = table_open(RelationRelationId, RowExclusiveLock);
+
+	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(reloid));
+	if (!HeapTupleIsValid(tuple))
+		elog(ERROR, "cache lookup failed for relation %u", reloid);
+	rd_rel = (Form_pg_class) GETSTRUCT(tuple);
+
+	/* No work if no change in tablespace. */
+	oldTablespaceOid = rd_rel->reltablespace;
+	if (tablespaceOid != oldTablespaceOid ||
+		(tablespaceOid == MyDatabaseTableSpace && OidIsValid(oldTablespaceOid)))
+	{
+		/* Update the pg_class row. */
+		rd_rel->reltablespace = (tablespaceOid == MyDatabaseTableSpace) ?
+			InvalidOid : tablespaceOid;
+		CatalogTupleUpdate(pg_class, >t_self, tuple);
+
+		changed = true;
+	}
+
+	heap_freetuple(tuple);
+	table_close(pg_class, RowExclusiveLock);
+
+	return changed;
+}
 
 /* 
  *		

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-12-02 Thread Michael Paquier
On Tue, Dec 01, 2020 at 03:10:13PM +0900, Michael Paquier wrote:
> Well, my impression is that both of you kept exchanging patches,
> touching and reviewing each other's patch (note that Alexei has also
> sent a rebase of 0002 just yesterday), so I think that it is fair to
> say that both of you should be listed as authors and credited as such
> in the release notes for this one.

OK, this one is now committed.  As of this thread, I think that we are
going to need to do a bit more once we add options that are not just
booleans for both commands (the grammar rules do not need to be
changed now):
- Have a ReindexParams, similarly to VacuumParams except that we store
the results of the parsing in a single place.  With the current HEAD,
I did not see yet the point in doing so because we just need an
integer that maps to a bitmask made of ReindexOption.
- The part related to ReindexStmt in utility.c is getting more and
more complicated, so we could move most of the execution into
indexcmds.c with some sort of ExecReindex() doing the option parsing
job, and go to the correct code path depending on the object type
dealt with.
--
Michael


signature.asc
Description: PGP signature


Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-11-30 Thread Michael Paquier
On Mon, Nov 30, 2020 at 11:43:08PM -0600, Justin Pryzby wrote:
> I eyeballed the patch and rebased the rest of the series on top if it to play
> with.  Looks fine - thanks.

Cool, thanks.

> FYI, the commit messages have the proper "author" for attribution.  I proposed
> and implemented the grammar changes in 0002, and implemented INDEX_TABLESPACE,
> but I'm a reviewer for the main patches.

Well, my impression is that both of you kept exchanging patches,
touching and reviewing each other's patch (note that Alexei has also
sent a rebase of 0002 just yesterday), so I think that it is fair to
say that both of you should be listed as authors and credited as such
in the release notes for this one.
--
Michael


signature.asc
Description: PGP signature


Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-11-30 Thread Justin Pryzby
On Tue, Dec 01, 2020 at 11:46:55AM +0900, Michael Paquier wrote:
> On Mon, Nov 30, 2020 at 05:12:42PM +0300, Alexey Kondratov wrote:
> > Thanks. I have rebased the remaining patches on top of 873ea9ee to use
> > 'utility_option_list' instead of 'common_option_list'.
> 
> Thanks, that helps a lot.  I have gone through 0002, and tweaked it as
> the attached (note that this patch is also interesting for another
> thing in development: backend-side reindex filtering of
> collation-sensitive indexes).  Does that look right to you?

I eyeballed the patch and rebased the rest of the series on top if it to play
with.  Looks fine - thanks.

FYI, the commit messages have the proper "author" for attribution.  I proposed
and implemented the grammar changes in 0002, and implemented INDEX_TABLESPACE,
but I'm a reviewer for the main patches.

-- 
Justin




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-11-30 Thread Michael Paquier
On Mon, Nov 30, 2020 at 05:12:42PM +0300, Alexey Kondratov wrote:
> Thanks. I have rebased the remaining patches on top of 873ea9ee to use
> 'utility_option_list' instead of 'common_option_list'.

Thanks, that helps a lot.  I have gone through 0002, and tweaked it as
the attached (note that this patch is also interesting for another
thing in development: backend-side reindex filtering of
collation-sensitive indexes).  Does that look right to you?

These are mostly matters of consistency with the other commands using
DefElem, but I think that it is important to get things right:
- Having the list of options in parsenodes.h becomes incorrect,
because these get now only used at execution time, like VACUUM.  So I
have moved that to cluster.h and index.h.
- Let's use an enum for REINDEX, like the others.
- Having parse_reindex_params() in utility.c is wrong for something
aimed at being used only for REINDEX, so I have moved that to
indexcmds.c, and renamed the routine to be more consistent with the
rest.  I think that we could more here by having an ExecReindex() that
does all the work based on object types, but I have left that out for
now to keep the change minimal.
- Switched one of the existing tests to stress CONCURRENTLY within
parenthesis.
- Indented the whole.

A couple of extra things below.

  *  CLUSTER [VERBOSE]  [ USING  ]
+ *  CLUSTER [VERBOSE] [(options)]  [ USING  ]
This line is wrong, and should be:
CLUSTER [ (options) ]  [ USING  ]

+CLUSTER [VERBOSE] [ ( option
+CLUSTER [VERBOSE] [ ( option [, 
...] ) ]
The docs in cluster.sgml are wrong as well, you can have VERBOSE as a
single option or as a parenthesized option, but never both at the same
time.  On the contrary, psql completion got that right.  I was first a
bit surprised that you would not allow the parenthesized set for the
case where a relation is not specified in the command, but I agree
that this does not seem worth the extra complexity now as this thread
aims at being able to use TABLESPACE which makes little sense
database-wide.

-VERBOSE
+VERBOSE [ boolean ]
Forgot about CONCURRENTLY as an option here, as this becomes
possible.
--
Michael
diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h
index f4559b09d7..c041628049 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.h
@@ -29,6 +29,15 @@ typedef enum
 	INDEX_DROP_SET_DEAD
 } IndexStateFlagsAction;
 
+/* options for REINDEX */
+typedef enum ReindexOption
+{
+	REINDEXOPT_VERBOSE = 1 << 0,	/* print progress info */
+	REINDEXOPT_REPORT_PROGRESS = 1 << 1,	/* report pgstat progress */
+	REINDEXOPT_MISSING_OK = 1 << 2, /* skip missing relations */
+	REINDEXOPT_CONCURRENTLY = 1 << 3	/* concurrent mode */
+} ReindexOption;
+
 /* state info for validate_index bulkdelete callback */
 typedef struct ValidateIndexState
 {
diff --git a/src/include/commands/cluster.h b/src/include/commands/cluster.h
index e05884781b..7cfb37c9b2 100644
--- a/src/include/commands/cluster.h
+++ b/src/include/commands/cluster.h
@@ -14,11 +14,19 @@
 #define CLUSTER_H
 
 #include "nodes/parsenodes.h"
+#include "parser/parse_node.h"
 #include "storage/lock.h"
 #include "utils/relcache.h"
 
 
-extern void cluster(ClusterStmt *stmt, bool isTopLevel);
+/* options for CLUSTER */
+typedef enum ClusterOption
+{
+	CLUOPT_RECHECK = 1 << 0,	/* recheck relation state */
+	CLUOPT_VERBOSE = 1 << 1		/* print progress info */
+} ClusterOption;
+
+extern void cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel);
 extern void cluster_rel(Oid tableOid, Oid indexOid, int options);
 extern void check_index_is_clusterable(Relation OldHeap, Oid indexOid,
 	   bool recheck, LOCKMODE lockmode);
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 7a079ef07f..1133ae1143 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -34,6 +34,7 @@ extern ObjectAddress DefineIndex(Oid relationId,
  bool check_not_in_use,
  bool skip_build,
  bool quiet);
+extern int	ReindexParseOptions(ParseState *pstate, ReindexStmt *stmt);
 extern void ReindexIndex(RangeVar *indexRelation, int options, bool isTopLevel);
 extern Oid	ReindexTable(RangeVar *relation, int options, bool isTopLevel);
 extern void ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index d1f9ef29ca..d6a6969b0d 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -3196,18 +3196,12 @@ typedef struct AlterSystemStmt
  *		Cluster Statement (support pbrown's cluster index implementation)
  * --
  */
-typedef enum ClusterOption
-{
-	CLUOPT_RECHECK = 1 << 0,	/* recheck relation state */
-	CLUOPT_VERBOSE = 1 << 1		/* print progress info */
-} ClusterOption;
-
 typedef struct ClusterStmt
 {
 	NodeTag		type;
 	RangeVar   *relation;		/* relation being indexed, or NULL if all */
 	char	   *indexname;	

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-11-30 Thread Alexey Kondratov

On 2020-11-30 14:33, Michael Paquier wrote:

On Tue, Nov 24, 2020 at 09:31:23AM -0600, Justin Pryzby wrote:

@cfbot: rebased


Catching up with the activity here, I can see four different things in
the patch set attached:
1) Refactoring of the grammar of CLUSTER, VACUUM, ANALYZE and REINDEX
to support values in parameters.
2) Tablespace change for REINDEX.
3) Tablespace change for VACUUM FULL/CLUSTER.
4) Tablespace change for indexes with VACUUM FULL/CLUSTER.

I am not sure yet about the last three points, so let's begin with 1)
that is dealt with in 0001 and 0002.  I have spent some time on 0001,
renaming the rule names to be less generic than "common", and applied
it.  0002 looks to be in rather good shape, still there are a few
things that have caught my eyes.  I'll look at that more closely
tomorrow.



Thanks. I have rebased the remaining patches on top of 873ea9ee to use 
'utility_option_list' instead of 'common_option_list'.



Regards
--
Alexey Kondratov

Postgres Professional https://www.postgrespro.com
Russian Postgres CompanyFrom ac3b77aec26a40016784ada9dab8b9059f424fa4 Mon Sep 17 00:00:00 2001
From: Justin Pryzby 
Date: Tue, 31 Mar 2020 20:35:41 -0500
Subject: [PATCH v31 5/5] Implement vacuum full/cluster (INDEX_TABLESPACE
 )

---
 doc/src/sgml/ref/cluster.sgml | 12 -
 doc/src/sgml/ref/vacuum.sgml  | 12 -
 src/backend/commands/cluster.c| 64 ++-
 src/backend/commands/matview.c|  3 +-
 src/backend/commands/tablecmds.c  |  2 +-
 src/backend/commands/vacuum.c | 46 +++-
 src/backend/postmaster/autovacuum.c   |  1 +
 src/include/commands/cluster.h|  6 ++-
 src/include/commands/vacuum.h |  5 +-
 src/test/regress/input/tablespace.source  | 13 +
 src/test/regress/output/tablespace.source | 20 +++
 11 files changed, 123 insertions(+), 61 deletions(-)

diff --git a/doc/src/sgml/ref/cluster.sgml b/doc/src/sgml/ref/cluster.sgml
index cbfc0582be..6781e3a025 100644
--- a/doc/src/sgml/ref/cluster.sgml
+++ b/doc/src/sgml/ref/cluster.sgml
@@ -28,6 +28,7 @@ CLUSTER [VERBOSE] [ ( option [, ...
 
 VERBOSE [ boolean ]
 TABLESPACE new_tablespace
+INDEX_TABLESPACE new_tablespace
 
 
  
@@ -105,6 +106,15 @@ CLUSTER [VERBOSE] [ ( option [, ...
 

 
+   
+INDEX_TABLESPACE
+
+ 
+  Specifies that the table's indexes will be rebuilt on a new tablespace.
+ 
+
+   
+

 table_name
 
@@ -141,7 +151,7 @@ CLUSTER [VERBOSE] [ ( option [, ...
 new_tablespace
 
  
-  The tablespace where the table will be rebuilt.
+  The tablespace where the table or its indexes will be rebuilt.
  
 

diff --git a/doc/src/sgml/ref/vacuum.sgml b/doc/src/sgml/ref/vacuum.sgml
index 5261a7c727..28cab119b6 100644
--- a/doc/src/sgml/ref/vacuum.sgml
+++ b/doc/src/sgml/ref/vacuum.sgml
@@ -36,6 +36,7 @@ VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] [ ANALYZE ] [ boolean ]
 PARALLEL integer
 TABLESPACE new_tablespace
+INDEX_TABLESPACE new_tablespace
 
 and table_and_columns is:
 
@@ -265,6 +266,15 @@ VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] [ ANALYZE ] [ boolean
 
@@ -314,7 +324,7 @@ VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] [ ANALYZE ] [ new_tablespace
 
  
-  The tablespace where the relation will be rebuilt.
+  The tablespace where the relation or its indexes will be rebuilt.
  
 

diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index b289a76d58..0f9f09a15a 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -71,7 +71,7 @@ typedef struct
 
 
 static void rebuild_relation(Relation OldHeap, Oid indexOid, bool verbose,
-			 Oid NewTableSpaceOid);
+			 Oid NewTableSpaceOid, Oid NewIdxTableSpaceOid);
 static void copy_table_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex,
 			bool verbose, bool *pSwapToastByContent,
 			TransactionId *pFreezeXid, MultiXactId *pCutoffMulti);
@@ -107,9 +107,11 @@ cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel)
 {
 	ListCell	*lc;
 	int			options = 0;
-	/* Name and Oid of tablespace to use for clustered relation. */
-	char		*tablespaceName = NULL;
-	Oid			tablespaceOid = InvalidOid;
+	/* Name and Oid of tablespaces to use for clustered relations. */
+	char		*tablespaceName = NULL,
+*idxtablespaceName = NULL;
+	Oid			tablespaceOid,
+idxtablespaceOid;
 
 	/* Parse list of generic parameters not handled by the parser */
 	foreach(lc, stmt->params)
@@ -123,6 +125,8 @@ cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel)
 options &= ~CLUOPT_VERBOSE;
 		else if (strcmp(opt->defname, "tablespace") == 0)
 			tablespaceName = defGetString(opt);
+		else if (strcmp(opt->defname, "index_tablespace") == 0)
+			idxtablespaceName = defGetString(opt);
 		else
 			ereport(ERROR,
 	(errcode(ERRCODE_SYNTAX_ERROR),
@@ -131,18 +135,11 @@ cluster(ParseState *pstate, 

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-11-30 Thread Michael Paquier
On Tue, Nov 24, 2020 at 09:31:23AM -0600, Justin Pryzby wrote:
> @cfbot: rebased

Catching up with the activity here, I can see four different things in
the patch set attached:
1) Refactoring of the grammar of CLUSTER, VACUUM, ANALYZE and REINDEX
to support values in parameters.
2) Tablespace change for REINDEX.
3) Tablespace change for VACUUM FULL/CLUSTER.
4) Tablespace change for indexes with VACUUM FULL/CLUSTER.

I am not sure yet about the last three points, so let's begin with 1)
that is dealt with in 0001 and 0002.  I have spent some time on 0001,
renaming the rule names to be less generic than "common", and applied
it.  0002 looks to be in rather good shape, still there are a few
things that have caught my eyes.  I'll look at that more closely
tomorrow.
--
Michael


signature.asc
Description: PGP signature


Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-11-24 Thread Justin Pryzby
On Sat, Oct 31, 2020 at 01:36:11PM -0500, Justin Pryzby wrote:
> > > From the grammar perspective ANY option is available for any command
> > > that uses parenthesized option list. All the checks and validations
> > > are performed at the corresponding command code.
> > > This analyze_keyword is actually doing only an ANALYZE word
> > > normalization if it's used as an option. Why it could be harmful?
> > 
> > Michael has not replied since then, but he was relatively positive about
> > 0005 initially, so I put it as a first patch now.
> 
> Thanks.  I rebased Alexey's latest patch on top of recent changes to 
> cluster.c.
> This puts the generic grammar changes first.  I wasn't paying much attention 
> to
> that part, so still waiting for a committer review.

@cfbot: rebased
>From 4a8e71ac704bd4c58e54703298b5234946c666a3 Mon Sep 17 00:00:00 2001
From: Alexey Kondratov 
Date: Wed, 2 Sep 2020 23:05:16 +0300
Subject: [PATCH v30 1/6] Refactor gram.y in order to add a common
 parenthesized option list

Previously there were two identical option lists
(explain_option_list and vac_analyze_option_list) + very similar
reindex_option_list.  It does not seem to make
sense to maintain identical option lists in the grammar, since
all new options are added and parsed in the backend code.

That way, new common_option_list added in order to replace all
explain_option_list, vac_analyze_option_list and probably
also reindex_option_list.
---
 src/backend/parser/gram.y | 61 +--
 1 file changed, 14 insertions(+), 47 deletions(-)

diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index efc9c99754..5c86063459 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -315,10 +315,10 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 create_extension_opt_item alter_extension_opt_item
 
 %type 	opt_lock lock_type cast_context
-%type 		vac_analyze_option_name
-%type 	vac_analyze_option_elem
-%type 	vac_analyze_option_list
-%type 	vac_analyze_option_arg
+%type 		common_option_name
+%type 	common_option_elem
+%type 	common_option_list
+%type 	common_option_arg
 %type 	drop_option
 %type 	opt_or_replace opt_no
 opt_grant_grant_option opt_grant_admin_option
@@ -513,10 +513,6 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %type 	generic_option_arg
 %type 	generic_option_elem alter_generic_option_elem
 %type 	generic_option_list alter_generic_option_list
-%type 		explain_option_name
-%type 	explain_option_arg
-%type 	explain_option_elem
-%type 	explain_option_list
 
 %type 	reindex_target_type reindex_target_multitable
 %type 	reindex_option_list reindex_option_elem
@@ -10483,7 +10479,7 @@ VacuumStmt: VACUUM opt_full opt_freeze opt_verbose opt_analyze opt_vacuum_relati
 	n->is_vacuumcmd = true;
 	$$ = (Node *)n;
 }
-			| VACUUM '(' vac_analyze_option_list ')' opt_vacuum_relation_list
+			| VACUUM '(' common_option_list ')' opt_vacuum_relation_list
 {
 	VacuumStmt *n = makeNode(VacuumStmt);
 	n->options = $3;
@@ -10504,7 +10500,7 @@ AnalyzeStmt: analyze_keyword opt_verbose opt_vacuum_relation_list
 	n->is_vacuumcmd = false;
 	$$ = (Node *)n;
 }
-			| analyze_keyword '(' vac_analyze_option_list ')' opt_vacuum_relation_list
+			| analyze_keyword '(' common_option_list ')' opt_vacuum_relation_list
 {
 	VacuumStmt *n = makeNode(VacuumStmt);
 	n->options = $3;
@@ -10514,12 +10510,12 @@ AnalyzeStmt: analyze_keyword opt_verbose opt_vacuum_relation_list
 }
 		;
 
-vac_analyze_option_list:
-			vac_analyze_option_elem
+common_option_list:
+			common_option_elem
 {
 	$$ = list_make1($1);
 }
-			| vac_analyze_option_list ',' vac_analyze_option_elem
+			| common_option_list ',' common_option_elem
 {
 	$$ = lappend($1, $3);
 }
@@ -10530,19 +10526,19 @@ analyze_keyword:
 			| ANALYSE /* British */
 		;
 
-vac_analyze_option_elem:
-			vac_analyze_option_name vac_analyze_option_arg
+common_option_elem:
+			common_option_name common_option_arg
 {
 	$$ = makeDefElem($1, $2, @1);
 }
 		;
 
-vac_analyze_option_name:
+common_option_name:
 			NonReservedWord			{ $$ = $1; }
 			| analyze_keyword		{ $$ = "analyze"; }
 		;
 
-vac_analyze_option_arg:
+common_option_arg:
 			opt_boolean_or_string	{ $$ = (Node *) makeString($1); }
 			| NumericOnly			{ $$ = (Node *) $1; }
 			| /* EMPTY */			{ $$ = NULL; }
@@ -10624,7 +10620,7 @@ ExplainStmt:
 	n->options = list_make1(makeDefElem("verbose", NULL, @2));
 	$$ = (Node *) n;
 }
-		| EXPLAIN '(' explain_option_list ')' ExplainableStmt
+		| EXPLAIN '(' common_option_list ')' ExplainableStmt
 {
 	ExplainStmt *n = makeNode(ExplainStmt);
 	n->query = $5;
@@ -10645,35 +10641,6 @@ ExplainableStmt:
 			| ExecuteStmt	/* by default all are $$=$1 */
 		;
 
-explain_option_list:
-			explain_option_elem
-{
-	$$ = list_make1($1);
-}
-			| 

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-10-31 Thread Justin Pryzby
On Wed, Sep 23, 2020 at 07:43:01PM +0300, Alexey Kondratov wrote:
> On 2020-09-09 18:36, Justin Pryzby wrote:
> > Rebased on a6642b3ae: Add support for partitioned tables and indexes in
> > REINDEX
> > 
> > So now this includes the new functionality and test for reindexing a
> > partitioned table onto a new tablespace.  That part could use some
> > additional
> > review.
> 
> I have finally had a look on your changes regarding partitioned tables.
> 
> +set_rel_tablespace(Oid indexid, char *tablespace)
> +{
> + Oid tablespaceOid = tablespace ? get_tablespace_oid(tablespace, false) :
> + InvalidOid;
> 
> You pass a tablespace name to set_rel_tablespace(), but it is already parsed
> into the Oid before. So I do not see why we need this extra work here
> instead of just passing Oid directly.
> 
> Also set_rel_tablespace() does not check for a no-op case, i.e. if requested
> tablespace is the same as before.
> 
> + /*
> +  * Set the new tablespace for the relation.  Do that only in the
> +  * case where the reindex caller wishes to enforce a new tablespace.
> +  */
> + if (set_tablespace &&
> + tablespaceOid != iRel->rd_rel->reltablespace)
> 
> Just noticed that this check is not completely correct as well, since it
> does not check for MyDatabaseTableSpace (stored as InvalidOid) logic.
> 
> I put these small fixes directly into the attached 0003.
> 
> Also, I thought about your comment above set_rel_tablespace() and did a bit
> 'extreme' refactoring, which is attached as a separated patch 0004. The only
> one doubtful change IMO is reordering of RelationDropStorage() operation
> inside reindex_index(). However, it only schedules unlinking of physical
> storage at transaction commit, so this refactoring seems to be safe.
> 
> If there will be no objections I would merge it with 0003.
> 
> On 2020-09-09 16:03, Alexey Kondratov wrote:
> > On 2020-09-09 15:22, Michael Paquier wrote:
> > > 
> > > By the way, skimming through the patch set, I was wondering if we
> > > could do the refactoring of patch 0005 as a first step
> > > 
> > 
> > Yes, I did it with intention to put as a first patch, but wanted to
> > get some feedback. It's easier to refactor the last patch without
> > rebasing others.
> > 
> > > 
> > > until I
> > > noticed this part:
> > > +common_option_name:
> > > NonReservedWord { $$ = $1; }
> > >   | analyze_keyword { $$ = "analyze"; }
> > > This is not a good idea as you make ANALYZE an option available for
> > > all the commands involved in the refactoring.  A portion of that could
> > > be considered though, like the use of common_option_arg.
> > > 
> > 
> > From the grammar perspective ANY option is available for any command
> > that uses parenthesized option list. All the checks and validations
> > are performed at the corresponding command code.
> > This analyze_keyword is actually doing only an ANALYZE word
> > normalization if it's used as an option. Why it could be harmful?
> > 
> 
> Michael has not replied since then, but he was relatively positive about
> 0005 initially, so I put it as a first patch now.

Thanks.  I rebased Alexey's latest patch on top of recent changes to cluster.c.
This puts the generic grammar changes first.  I wasn't paying much attention to
that part, so still waiting for a committer review.

-- 
Justin
>From 72f7af2b39587304c945e75d2b82a3a09a2cf7fa Mon Sep 17 00:00:00 2001
From: Alexey Kondratov 
Date: Wed, 2 Sep 2020 23:05:16 +0300
Subject: [PATCH v29 1/7] Refactor gram.y in order to add a common
 parenthesized option list

Previously there were two identical option lists
(explain_option_list and vac_analyze_option_list) + very similar
reindex_option_list.  It does not seem to make
sense to maintain identical option lists in the grammar, since
all new options are added and parsed in the backend code.

That way, new common_option_list added in order to replace all
explain_option_list, vac_analyze_option_list and probably
also reindex_option_list.
---
 src/backend/parser/gram.y | 61 +--
 1 file changed, 14 insertions(+), 47 deletions(-)

diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 480d168346..0828c27944 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -315,10 +315,10 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 create_extension_opt_item alter_extension_opt_item
 
 %type 	opt_lock lock_type cast_context
-%type 		vac_analyze_option_name
-%type 	vac_analyze_option_elem
-%type 	vac_analyze_option_list
-%type 	vac_analyze_option_arg
+%type 		common_option_name
+%type 	common_option_elem
+%type 	common_option_list
+%type 	common_option_arg
 %type 	drop_option
 %type 	opt_or_replace opt_no
 opt_grant_grant_option opt_grant_admin_option
@@ -513,10 +513,6 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %type 	generic_option_arg
 %type 	

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-09-09 Thread Justin Pryzby
On Wed, Sep 09, 2020 at 09:22:00PM +0900, Michael Paquier wrote:
> On Tue, Sep 08, 2020 at 07:17:58PM -0500, Justin Pryzby wrote:
> > Initially I added List *params, and Michael suggested to retire
> > ReindexStmt->concurrent.  I provided a patch to do so, initially by leaving 
> > int
> > options and then, after this, removing it to "complete the thought", and get
> > rid of the remnants of the "old way" of doing it.  This is also how vacuum 
> > and
> > explain are done.
> > https://www.postgresql.org/message-id/20200902022410.GA20149%40telsasoft.com
> 
> Defining a set of DefElem when parsing and then using the int
> "options" with bitmasks where necessary at the beginning of the
> execution looks like a good balance to me.  This way, you can extend
> the grammar to use things like (verbose = true), etc.

It doesn't need to be extended - defGetBoolean already handles that.  I don't
see what good can come from storing the information in two places in the same
structure.

|postgres=# CLUSTER (VERBOSE on) pg_attribute USING 
pg_attribute_relid_attnum_index ;
|INFO:  clustering "pg_catalog.pg_attribute" using index scan on 
"pg_attribute_relid_attnum_index"
|INFO:  "pg_attribute": found 0 removable, 2968 nonremovable row versions in 55 
pages
|DETAIL:  0 dead row versions cannot be removed yet.
|CPU: user: 0.01 s, system: 0.00 s, elapsed: 0.01 s.
|CLUSTER

-- 
Justin




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-09-09 Thread Alexey Kondratov

On 2020-09-09 15:22, Michael Paquier wrote:

On Tue, Sep 08, 2020 at 07:17:58PM -0500, Justin Pryzby wrote:

Initially I added List *params, and Michael suggested to retire
ReindexStmt->concurrent.  I provided a patch to do so, initially by 
leaving int
options and then, after this, removing it to "complete the thought", 
and get
rid of the remnants of the "old way" of doing it.  This is also how 
vacuum and

explain are done.
https://www.postgresql.org/message-id/20200902022410.GA20149%40telsasoft.com


Defining a set of DefElem when parsing and then using the int
"options" with bitmasks where necessary at the beginning of the
execution looks like a good balance to me.  This way, you can extend
the grammar to use things like (verbose = true), etc.

By the way, skimming through the patch set, I was wondering if we
could do the refactoring of patch 0005 as a first step



Yes, I did it with intention to put as a first patch, but wanted to get 
some feedback. It's easier to refactor the last patch without rebasing 
others.




until I
noticed this part:
+common_option_name:
NonReservedWord { $$ = $1; }
| analyze_keyword { $$ = "analyze"; }
This is not a good idea as you make ANALYZE an option available for
all the commands involved in the refactoring.  A portion of that could
be considered though, like the use of common_option_arg.



From the grammar perspective ANY option is available for any command 
that uses parenthesized option list. All the checks and validations are 
performed at the corresponding command code.
This analyze_keyword is actually doing only an ANALYZE word 
normalization if it's used as an option. Why it could be harmful?



Regards
--
Alexey Kondratov

Postgres Professional https://www.postgrespro.com
Russian Postgres Company




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-09-09 Thread Michael Paquier
On Tue, Sep 08, 2020 at 07:17:58PM -0500, Justin Pryzby wrote:
> Initially I added List *params, and Michael suggested to retire
> ReindexStmt->concurrent.  I provided a patch to do so, initially by leaving 
> int
> options and then, after this, removing it to "complete the thought", and get
> rid of the remnants of the "old way" of doing it.  This is also how vacuum and
> explain are done.
> https://www.postgresql.org/message-id/20200902022410.GA20149%40telsasoft.com

Defining a set of DefElem when parsing and then using the int
"options" with bitmasks where necessary at the beginning of the
execution looks like a good balance to me.  This way, you can extend
the grammar to use things like (verbose = true), etc.

By the way, skimming through the patch set, I was wondering if we
could do the refactoring of patch 0005 as a first step, until I
noticed this part:
+common_option_name:
NonReservedWord { $$ = $1; }
| analyze_keyword { $$ = "analyze"; }
This is not a good idea as you make ANALYZE an option available for
all the commands involved in the refactoring.  A portion of that could
be considered though, like the use of common_option_arg.
--
Michael


signature.asc
Description: PGP signature


Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-09-08 Thread Justin Pryzby
On Tue, Sep 08, 2020 at 09:02:38PM -0300, Alvaro Herrera wrote:
> On 2020-Sep-08, Justin Pryzby wrote:
> 
> > From 992e0121925c74d5c5a4e5b132cddb3d6b31da86 Mon Sep 17 00:00:00 2001
> > From: Justin Pryzby 
> > Date: Fri, 27 Mar 2020 17:50:46 -0500
> > Subject: [PATCH v27 1/5] Change REINDEX/CLUSTER to accept an option list..
> > 
> > ..like EXPLAIN (..), VACUUM (..), and ANALYZE (..).
> > 
> > Change docs in the style of VACUUM.  See also: 
> > 52dcfda48778d16683c64ca4372299a099a15b96
> 
> I don't understand why you change all options to DefElem instead of
> keeping the bitmask for those options that can use it.

That's originally how I did it, too.

Initially I added List *params, and Michael suggested to retire
ReindexStmt->concurrent.  I provided a patch to do so, initially by leaving int
options and then, after this, removing it to "complete the thought", and get
rid of the remnants of the "old way" of doing it.  This is also how vacuum and
explain are done.
https://www.postgresql.org/message-id/20200902022410.GA20149%40telsasoft.com

-- 
Justin




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-09-08 Thread Alvaro Herrera
On 2020-Sep-08, Justin Pryzby wrote:

> From 992e0121925c74d5c5a4e5b132cddb3d6b31da86 Mon Sep 17 00:00:00 2001
> From: Justin Pryzby 
> Date: Fri, 27 Mar 2020 17:50:46 -0500
> Subject: [PATCH v27 1/5] Change REINDEX/CLUSTER to accept an option list..
> 
> ..like EXPLAIN (..), VACUUM (..), and ANALYZE (..).
> 
> Change docs in the style of VACUUM.  See also: 
> 52dcfda48778d16683c64ca4372299a099a15b96

I don't understand why you change all options to DefElem instead of
keeping the bitmask for those options that can use it.

-- 
Álvaro Herrerahttps://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-09-08 Thread Justin Pryzby
On Thu, Sep 03, 2020 at 09:43:51PM -0500, Justin Pryzby wrote:
> And rebased on Michael's commit removing ReindexStmt->concurrent.

Rebased on a6642b3ae: Add support for partitioned tables and indexes in REINDEX

So now this includes the new functionality and test for reindexing a
partitioned table onto a new tablespace.  That part could use some additional
review.

I guess this patch series will also conflict with the CLUSTER part of this
other one.  Once its CLUSTER patch is commited, this patch should to be updated
to test clustering a partitioned table to a new tbspc.
https://commitfest.postgresql.org/29/2584/
REINDEX/CIC/CLUSTER of partitioned tables

-- 
Justin
>From 992e0121925c74d5c5a4e5b132cddb3d6b31da86 Mon Sep 17 00:00:00 2001
From: Justin Pryzby 
Date: Fri, 27 Mar 2020 17:50:46 -0500
Subject: [PATCH v27 1/5] Change REINDEX/CLUSTER to accept an option list..

..like EXPLAIN (..), VACUUM (..), and ANALYZE (..).

Change docs in the style of VACUUM.  See also: 52dcfda48778d16683c64ca4372299a099a15b96
---
 doc/src/sgml/ref/cluster.sgml  | 27 ++---
 doc/src/sgml/ref/reindex.sgml  | 43 ++-
 src/backend/commands/cluster.c | 28 --
 src/backend/nodes/copyfuncs.c  |  4 +--
 src/backend/nodes/equalfuncs.c |  4 +--
 src/backend/parser/gram.y  | 54 +++---
 src/backend/tcop/utility.c | 38 ++--
 src/bin/psql/tab-complete.c| 22 ++
 src/include/commands/cluster.h |  3 +-
 src/include/nodes/parsenodes.h |  4 +--
 10 files changed, 167 insertions(+), 60 deletions(-)

diff --git a/doc/src/sgml/ref/cluster.sgml b/doc/src/sgml/ref/cluster.sgml
index 4da60d8d56..e6ebce27e6 100644
--- a/doc/src/sgml/ref/cluster.sgml
+++ b/doc/src/sgml/ref/cluster.sgml
@@ -21,8 +21,13 @@ PostgreSQL documentation
 
  
 
-CLUSTER [VERBOSE] table_name [ USING index_name ]
-CLUSTER [VERBOSE]
+CLUSTER [VERBOSE] [ ( option [, ...] ) ] table_name [ USING index_name ]
+CLUSTER [VERBOSE] [ ( option [, ...] ) ]
+
+where option can be one of:
+
+VERBOSE [ boolean ]
+
 
  
 
@@ -81,6 +86,15 @@ CLUSTER [VERBOSE]
   Parameters
 
   
+   
+VERBOSE
+
+ 
+  Prints a progress report as each table is clustered.
+ 
+
+   
+

 table_name
 
@@ -100,10 +114,15 @@ CLUSTER [VERBOSE]

 

-VERBOSE
+boolean
 
  
-  Prints a progress report as each table is clustered.
+  Specifies whether the selected option should be turned on or off.
+  You can write TRUE, ON, or
+  1 to enable the option, and FALSE,
+  OFF, or 0 to disable it.  The
+  boolean value can also
+  be omitted, in which case TRUE is assumed.
  
 

diff --git a/doc/src/sgml/ref/reindex.sgml b/doc/src/sgml/ref/reindex.sgml
index 33af4ae02a..593b38a7ee 100644
--- a/doc/src/sgml/ref/reindex.sgml
+++ b/doc/src/sgml/ref/reindex.sgml
@@ -25,7 +25,7 @@ REINDEX [ ( option [, ...] ) ] { IN
 
 where option can be one of:
 
-VERBOSE
+VERBOSE [ boolean ]
 
  
 
@@ -145,19 +145,6 @@ REINDEX [ ( option [, ...] ) ] { IN
 

 
-   
-name
-
- 
-  The name of the specific index, table, or database to be
-  reindexed.  Index and table names can be schema-qualified.
-  Presently, REINDEX DATABASE and REINDEX SYSTEM
-  can only reindex the current database, so their parameter must match
-  the current database's name.
- 
-
-   
-

 CONCURRENTLY
 
@@ -185,6 +172,34 @@ REINDEX [ ( option [, ...] ) ] { IN
  
 

+
+   
+name
+
+ 
+  The name of the specific index, table, or database to be
+  reindexed.  Index and table names can be schema-qualified.
+  Presently, REINDEX DATABASE and REINDEX SYSTEM
+  can only reindex the current database, so their parameter must match
+  the current database's name.
+ 
+
+   
+
+   
+boolean
+
+ 
+  Specifies whether the selected option should be turned on or off.
+  You can write TRUE, ON, or
+  1 to enable the option, and FALSE,
+  OFF, or 0 to disable it.  The
+  boolean value can also
+  be omitted, in which case TRUE is assumed.
+ 
+
+   
+
   
  
 
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 0d647e912c..4a3678831d 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -35,6 +35,7 @@
 #include "catalog/pg_am.h"
 #include "catalog/toasting.h"
 #include "commands/cluster.h"
+#include "commands/defrem.h"
 #include "commands/progress.h"
 #include "commands/tablecmds.h"
 #include "commands/vacuum.h"
@@ -102,8 +103,29 @@ static List *get_tables_to_cluster(MemoryContext cluster_context);
  *---
  */
 void
-cluster(ClusterStmt *stmt, bool isTopLevel)
+cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel)
 {
+	ListCell	*lc;
+	int			options = 0;
+
+	/* Parse list of 

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-09-03 Thread Justin Pryzby
On Wed, Sep 02, 2020 at 06:07:06PM -0500, Justin Pryzby wrote:
> On my side, I've also rearranged function parameters to make the diff more
> readable.  And squishes your changes into the respective patches.

This resolves a breakage I failed to notice from a last-minute edit.
And squishes two commits.
And rebased on Michael's commit removing ReindexStmt->concurrent.

-- 
Justin
>From 7e04caad0d010b5fd3eeca8d9bd436e89b657e4a Mon Sep 17 00:00:00 2001
From: Justin Pryzby 
Date: Fri, 27 Mar 2020 17:50:46 -0500
Subject: [PATCH v26 1/5] Change REINDEX/CLUSTER to accept an option list..

..like EXPLAIN (..), VACUUM (..), and ANALYZE (..).

Change docs in the style of VACUUM.  See also: 52dcfda48778d16683c64ca4372299a099a15b96
---
 doc/src/sgml/ref/cluster.sgml  | 27 ++---
 doc/src/sgml/ref/reindex.sgml  | 43 ++-
 src/backend/commands/cluster.c | 28 --
 src/backend/nodes/copyfuncs.c  |  4 +--
 src/backend/nodes/equalfuncs.c |  4 +--
 src/backend/parser/gram.y  | 54 +++---
 src/backend/tcop/utility.c | 42 ++
 src/bin/psql/tab-complete.c| 22 ++
 src/include/commands/cluster.h |  3 +-
 src/include/commands/defrem.h  |  2 +-
 src/include/nodes/parsenodes.h |  4 +--
 11 files changed, 170 insertions(+), 63 deletions(-)

diff --git a/doc/src/sgml/ref/cluster.sgml b/doc/src/sgml/ref/cluster.sgml
index 4da60d8d56..e6ebce27e6 100644
--- a/doc/src/sgml/ref/cluster.sgml
+++ b/doc/src/sgml/ref/cluster.sgml
@@ -21,8 +21,13 @@ PostgreSQL documentation
 
  
 
-CLUSTER [VERBOSE] table_name [ USING index_name ]
-CLUSTER [VERBOSE]
+CLUSTER [VERBOSE] [ ( option [, ...] ) ] table_name [ USING index_name ]
+CLUSTER [VERBOSE] [ ( option [, ...] ) ]
+
+where option can be one of:
+
+VERBOSE [ boolean ]
+
 
  
 
@@ -81,6 +86,15 @@ CLUSTER [VERBOSE]
   Parameters
 
   
+   
+VERBOSE
+
+ 
+  Prints a progress report as each table is clustered.
+ 
+
+   
+

 table_name
 
@@ -100,10 +114,15 @@ CLUSTER [VERBOSE]

 

-VERBOSE
+boolean
 
  
-  Prints a progress report as each table is clustered.
+  Specifies whether the selected option should be turned on or off.
+  You can write TRUE, ON, or
+  1 to enable the option, and FALSE,
+  OFF, or 0 to disable it.  The
+  boolean value can also
+  be omitted, in which case TRUE is assumed.
  
 

diff --git a/doc/src/sgml/ref/reindex.sgml b/doc/src/sgml/ref/reindex.sgml
index c16f223e4e..a32e192a87 100644
--- a/doc/src/sgml/ref/reindex.sgml
+++ b/doc/src/sgml/ref/reindex.sgml
@@ -25,7 +25,7 @@ REINDEX [ ( option [, ...] ) ] { IN
 
 where option can be one of:
 
-VERBOSE
+VERBOSE [ boolean ]
 
  
 
@@ -141,19 +141,6 @@ REINDEX [ ( option [, ...] ) ] { IN
 

 
-   
-name
-
- 
-  The name of the specific index, table, or database to be
-  reindexed.  Index and table names can be schema-qualified.
-  Presently, REINDEX DATABASE and REINDEX SYSTEM
-  can only reindex the current database, so their parameter must match
-  the current database's name.
- 
-
-   
-

 CONCURRENTLY
 
@@ -181,6 +168,34 @@ REINDEX [ ( option [, ...] ) ] { IN
  
 

+
+   
+name
+
+ 
+  The name of the specific index, table, or database to be
+  reindexed.  Index and table names can be schema-qualified.
+  Presently, REINDEX DATABASE and REINDEX SYSTEM
+  can only reindex the current database, so their parameter must match
+  the current database's name.
+ 
+
+   
+
+   
+boolean
+
+ 
+  Specifies whether the selected option should be turned on or off.
+  You can write TRUE, ON, or
+  1 to enable the option, and FALSE,
+  OFF, or 0 to disable it.  The
+  boolean value can also
+  be omitted, in which case TRUE is assumed.
+ 
+
+   
+
   
  
 
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 0d647e912c..4a3678831d 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -35,6 +35,7 @@
 #include "catalog/pg_am.h"
 #include "catalog/toasting.h"
 #include "commands/cluster.h"
+#include "commands/defrem.h"
 #include "commands/progress.h"
 #include "commands/tablecmds.h"
 #include "commands/vacuum.h"
@@ -102,8 +103,29 @@ static List *get_tables_to_cluster(MemoryContext cluster_context);
  *---
  */
 void
-cluster(ClusterStmt *stmt, bool isTopLevel)
+cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel)
 {
+	ListCell	*lc;
+	int			options = 0;
+
+	/* Parse list of generic parameters not handled by the parser */
+	foreach(lc, stmt->params)
+	{
+		DefElem	*opt = (DefElem *) lfirst(lc);
+
+		if (strcmp(opt->defname, "verbose") == 0)
+			if (defGetBoolean(opt))
+options |= CLUOPT_VERBOSE;
+			else
+options 

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-09-02 Thread Justin Pryzby
On Thu, Sep 03, 2020 at 12:00:17AM +0300, Alexey Kondratov wrote:
> On 2020-09-02 07:56, Justin Pryzby wrote:
> > 
> > Done in the attached, which is also rebased on 1d6541666.
> > 
> > And added RelationAssumeNewRelfilenode() as I mentioned - but I'm hoping
> > to
> > hear from Michael about any reason not to call
> > RelationSetNewRelfilenode()
> > instead of directly calling the things it would itself call.
> 
> The latest patch set immediately got a conflict with Michael's fixup
> 01767533, so I've rebased it first of all.

On my side, I've also rearranged function parameters to make the diff more
readable.  And squishes your changes into the respective patches.

Michael started a new thread about retiring ReindexStmt->concurrent, which I
guess will cause more conflicts (although I don't see why we wouldn't implement
a generic List grammar now rather than only after a preliminary patch).

-- 
Justin
>From 704d230463deca5303b0eae6c55e0e197c6fa473 Mon Sep 17 00:00:00 2001
From: Justin Pryzby 
Date: Fri, 27 Mar 2020 17:50:46 -0500
Subject: [PATCH v25 1/6] Change REINDEX/CLUSTER to accept an option list..

..like EXPLAIN (..), VACUUM (..), and ANALYZE (..).

Change docs in the style of VACUUM.  See also: 52dcfda48778d16683c64ca4372299a099a15b96
---
 doc/src/sgml/ref/cluster.sgml| 27 +---
 doc/src/sgml/ref/reindex.sgml| 43 +---
 src/backend/commands/cluster.c   | 23 -
 src/backend/commands/indexcmds.c | 41 --
 src/backend/nodes/copyfuncs.c|  2 ++
 src/backend/nodes/equalfuncs.c   |  2 ++
 src/backend/parser/gram.y| 33 +---
 src/backend/tcop/utility.c   | 36 +++---
 src/bin/psql/tab-complete.c  | 22 
 src/include/commands/cluster.h   |  3 ++-
 src/include/commands/defrem.h|  7 +++---
 src/include/nodes/parsenodes.h   |  2 ++
 12 files changed, 175 insertions(+), 66 deletions(-)

diff --git a/doc/src/sgml/ref/cluster.sgml b/doc/src/sgml/ref/cluster.sgml
index 4da60d8d56..e6ebce27e6 100644
--- a/doc/src/sgml/ref/cluster.sgml
+++ b/doc/src/sgml/ref/cluster.sgml
@@ -21,8 +21,13 @@ PostgreSQL documentation
 
  
 
-CLUSTER [VERBOSE] table_name [ USING index_name ]
-CLUSTER [VERBOSE]
+CLUSTER [VERBOSE] [ ( option [, ...] ) ] table_name [ USING index_name ]
+CLUSTER [VERBOSE] [ ( option [, ...] ) ]
+
+where option can be one of:
+
+VERBOSE [ boolean ]
+
 
  
 
@@ -81,6 +86,15 @@ CLUSTER [VERBOSE]
   Parameters
 
   
+   
+VERBOSE
+
+ 
+  Prints a progress report as each table is clustered.
+ 
+
+   
+

 table_name
 
@@ -100,10 +114,15 @@ CLUSTER [VERBOSE]

 

-VERBOSE
+boolean
 
  
-  Prints a progress report as each table is clustered.
+  Specifies whether the selected option should be turned on or off.
+  You can write TRUE, ON, or
+  1 to enable the option, and FALSE,
+  OFF, or 0 to disable it.  The
+  boolean value can also
+  be omitted, in which case TRUE is assumed.
  
 

diff --git a/doc/src/sgml/ref/reindex.sgml b/doc/src/sgml/ref/reindex.sgml
index c16f223e4e..a32e192a87 100644
--- a/doc/src/sgml/ref/reindex.sgml
+++ b/doc/src/sgml/ref/reindex.sgml
@@ -25,7 +25,7 @@ REINDEX [ ( option [, ...] ) ] { IN
 
 where option can be one of:
 
-VERBOSE
+VERBOSE [ boolean ]
 
  
 
@@ -141,19 +141,6 @@ REINDEX [ ( option [, ...] ) ] { IN
 

 
-   
-name
-
- 
-  The name of the specific index, table, or database to be
-  reindexed.  Index and table names can be schema-qualified.
-  Presently, REINDEX DATABASE and REINDEX SYSTEM
-  can only reindex the current database, so their parameter must match
-  the current database's name.
- 
-
-   
-

 CONCURRENTLY
 
@@ -181,6 +168,34 @@ REINDEX [ ( option [, ...] ) ] { IN
  
 

+
+   
+name
+
+ 
+  The name of the specific index, table, or database to be
+  reindexed.  Index and table names can be schema-qualified.
+  Presently, REINDEX DATABASE and REINDEX SYSTEM
+  can only reindex the current database, so their parameter must match
+  the current database's name.
+ 
+
+   
+
+   
+boolean
+
+ 
+  Specifies whether the selected option should be turned on or off.
+  You can write TRUE, ON, or
+  1 to enable the option, and FALSE,
+  OFF, or 0 to disable it.  The
+  boolean value can also
+  be omitted, in which case TRUE is assumed.
+ 
+
+   
+
   
  
 
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 0d647e912c..a42dfe98f4 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -35,6 +35,7 @@
 #include "catalog/pg_am.h"
 #include "catalog/toasting.h"
 #include "commands/cluster.h"
+#include "commands/defrem.h"
 #include "commands/progress.h"
 #include "commands/tablecmds.h"
 

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-09-01 Thread Justin Pryzby
On Tue, Sep 01, 2020 at 09:24:10PM -0500, Justin Pryzby wrote:
> On Wed, Sep 02, 2020 at 10:00:12AM +0900, Michael Paquier wrote:
> > On Tue, Sep 01, 2020 at 11:48:30AM -0400, Alvaro Herrera wrote:
> > > On 2020-Sep-01, Justin Pryzby wrote:
> > >> The question isn't whether to use a parenthesized option list.  I 
> > >> realized that
> > >> long ago (even though Alexey didn't initially like it).  Check 0002, 
> > >> which gets
> > >> rid of "bool concurrent" in favour of 
> > >> stmt->options_CONCURRENT.
> > > 
> > > Ah!  I see, sorry for the noise.  Well, respectfully, having a separate
> > > boolean to store one option when you already have a bitmask for options
> > > is silly.
> > 
> > Yeah, I am all for removing "concurrent" from ReindexStmt, but I don't
> > think that the proposed 0002 is that, because it is based on the
> > assumption that we'd want more than just boolean-based options in
> > those statements, and this case is not justified yet except if it
> > becomes possible to enforce tablespaces.  At this stage, I think that
> > it is more sensible to just update gram.y and add a
> > REINDEXOPT_CONCURRENTLY.  I also think that it would also make sense
> > to pass down "options" within ReindexIndexCallbackState() (for example
> > imagine a SKIP_LOCKED for REINDEX).
> 
> Uh, this whole thread is about implementing REINDEX (TABLESPACE foo), and the
> preliminary patch 0001 is to keep separate the tablespace parts of that
> content.  0002 is a minor tangent which I assume would be squished into 0001
> which cleans up historic cruft, using new params in favour of historic 
> options.
> 
> I think my change is probably incomplete, and ReindexStmt node should not have
> an int options.  parse_reindex_params() would parse it into local int *options
> and char **tablespacename params.

Done in the attached, which is also rebased on 1d6541666.

And added RelationAssumeNewRelfilenode() as I mentioned - but I'm hoping to
hear from Michael about any reason not to call RelationSetNewRelfilenode()
instead of directly calling the things it would itself call.

-- 
Justin
>From 9d881a6aa401cebef0a2ce781d34a2a5ea8ded60 Mon Sep 17 00:00:00 2001
From: Justin Pryzby 
Date: Fri, 27 Mar 2020 17:50:46 -0500
Subject: [PATCH v23 1/5] Change REINDEX/CLUSTER to accept an option list..

..like EXPLAIN (..), VACUUM (..), and ANALYZE (..).

Change docs in the style of VACUUM.  See also: 52dcfda48778d16683c64ca4372299a099a15b96
---
 doc/src/sgml/ref/cluster.sgml| 28 ++---
 doc/src/sgml/ref/reindex.sgml| 43 +---
 src/backend/commands/cluster.c   | 23 -
 src/backend/commands/indexcmds.c | 41 --
 src/backend/nodes/copyfuncs.c|  2 ++
 src/backend/nodes/equalfuncs.c   |  2 ++
 src/backend/parser/gram.y| 35 +++---
 src/backend/tcop/utility.c   | 36 +++---
 src/bin/psql/tab-complete.c  | 23 +
 src/include/commands/cluster.h   |  3 ++-
 src/include/commands/defrem.h|  7 +++---
 src/include/nodes/parsenodes.h   |  2 ++
 12 files changed, 179 insertions(+), 66 deletions(-)

diff --git a/doc/src/sgml/ref/cluster.sgml b/doc/src/sgml/ref/cluster.sgml
index 4da60d8d56..110fb3083e 100644
--- a/doc/src/sgml/ref/cluster.sgml
+++ b/doc/src/sgml/ref/cluster.sgml
@@ -21,8 +21,13 @@ PostgreSQL documentation
 
  
 
-CLUSTER [VERBOSE] table_name [ USING index_name ]
-CLUSTER [VERBOSE]
+CLUSTER [VERBOSE] [ ( option [, ...] ) ] table_name [ USING index_name ]
+CLUSTER [VERBOSE] [ ( option [, ...] ) ]
+
+where option can be one of:
+
+VERBOSE [ boolean ]
+
 
  
 
@@ -81,6 +86,16 @@ CLUSTER [VERBOSE]
   Parameters
 
   
+   
+VERBOSE
+
+ 
+  Prints a progress report as each table is clustered.
+
+ 
+
+   
+

 table_name
 
@@ -100,10 +115,15 @@ CLUSTER [VERBOSE]

 

-VERBOSE
+boolean
 
  
-  Prints a progress report as each table is clustered.
+  Specifies whether the selected option should be turned on or off.
+  You can write TRUE, ON, or
+  1 to enable the option, and FALSE,
+  OFF, or 0 to disable it.  The
+  boolean value can also
+  be omitted, in which case TRUE is assumed.
  
 

diff --git a/doc/src/sgml/ref/reindex.sgml b/doc/src/sgml/ref/reindex.sgml
index c16f223e4e..a32e192a87 100644
--- a/doc/src/sgml/ref/reindex.sgml
+++ b/doc/src/sgml/ref/reindex.sgml
@@ -25,7 +25,7 @@ REINDEX [ ( option [, ...] ) ] { IN
 
 where option can be one of:
 
-VERBOSE
+VERBOSE [ boolean ]
 
  
 
@@ -141,19 +141,6 @@ REINDEX [ ( option [, ...] ) ] { IN
 

 
-   
-name
-
- 
-  The name of the specific index, table, or database to be
-  reindexed.  Index and table names can be schema-qualified.
-  Presently, REINDEX DATABASE and REINDEX SYSTEM
-  can only reindex the current database, so their parameter must match
-  the current database's 

Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-09-01 Thread Justin Pryzby
On Wed, Sep 02, 2020 at 10:00:12AM +0900, Michael Paquier wrote:
> On Tue, Sep 01, 2020 at 11:48:30AM -0400, Alvaro Herrera wrote:
> > On 2020-Sep-01, Justin Pryzby wrote:
> >> The question isn't whether to use a parenthesized option list.  I realized 
> >> that
> >> long ago (even though Alexey didn't initially like it).  Check 0002, which 
> >> gets
> >> rid of "bool concurrent" in favour of stmt->options_CONCURRENT.
> > 
> > Ah!  I see, sorry for the noise.  Well, respectfully, having a separate
> > boolean to store one option when you already have a bitmask for options
> > is silly.
> 
> Yeah, I am all for removing "concurrent" from ReindexStmt, but I don't
> think that the proposed 0002 is that, because it is based on the
> assumption that we'd want more than just boolean-based options in
> those statements, and this case is not justified yet except if it
> becomes possible to enforce tablespaces.  At this stage, I think that
> it is more sensible to just update gram.y and add a
> REINDEXOPT_CONCURRENTLY.  I also think that it would also make sense
> to pass down "options" within ReindexIndexCallbackState() (for example
> imagine a SKIP_LOCKED for REINDEX).

Uh, this whole thread is about implementing REINDEX (TABLESPACE foo), and the
preliminary patch 0001 is to keep separate the tablespace parts of that
content.  0002 is a minor tangent which I assume would be squished into 0001
which cleans up historic cruft, using new params in favour of historic options.

I think my change is probably incomplete, and ReindexStmt node should not have
an int options.  parse_reindex_params() would parse it into local int *options
and char **tablespacename params.

-- 
Justin




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-09-01 Thread Michael Paquier
On Tue, Sep 01, 2020 at 09:29:28PM -0400, Alvaro Herrera wrote:
> Seems sensible, but only to be done when actually needed, right?

Of course.
--
Michael


signature.asc
Description: PGP signature


Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-09-01 Thread Alvaro Herrera
On 2020-Sep-02, Michael Paquier wrote:

> Yeah, I am all for removing "concurrent" from ReindexStmt, but I don't
> think that the proposed 0002 is that, because it is based on the
> assumption that we'd want more than just boolean-based options in
> those statements, and this case is not justified yet except if it
> becomes possible to enforce tablespaces.  At this stage, I think that
> it is more sensible to just update gram.y and add a
> REINDEXOPT_CONCURRENTLY.

Yes, agreed.  I had not seen the "params" business.

> I also think that it would also make sense to pass down "options"
> within ReindexIndexCallbackState() (for example imagine a SKIP_LOCKED
> for REINDEX).

Seems sensible, but only to be done when actually needed, right?

-- 
Álvaro Herrerahttps://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-09-01 Thread Michael Paquier
On Tue, Sep 01, 2020 at 11:48:30AM -0400, Alvaro Herrera wrote:
> On 2020-Sep-01, Justin Pryzby wrote:
>> The question isn't whether to use a parenthesized option list.  I realized 
>> that
>> long ago (even though Alexey didn't initially like it).  Check 0002, which 
>> gets
>> rid of "bool concurrent" in favour of stmt->options_CONCURRENT.
> 
> Ah!  I see, sorry for the noise.  Well, respectfully, having a separate
> boolean to store one option when you already have a bitmask for options
> is silly.

Yeah, I am all for removing "concurrent" from ReindexStmt, but I don't
think that the proposed 0002 is that, because it is based on the
assumption that we'd want more than just boolean-based options in
those statements, and this case is not justified yet except if it
becomes possible to enforce tablespaces.  At this stage, I think that
it is more sensible to just update gram.y and add a
REINDEXOPT_CONCURRENTLY.  I also think that it would also make sense
to pass down "options" within ReindexIndexCallbackState() (for example
imagine a SKIP_LOCKED for REINDEX).
--
Michael


signature.asc
Description: PGP signature


Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-09-01 Thread Alvaro Herrera
On 2020-Sep-01, Justin Pryzby wrote:

> On Tue, Sep 01, 2020 at 11:40:18AM -0400, Alvaro Herrera wrote:

> > The advantage of using a parenthesized option list is that you can add
> > *further* options without making the new keywords reserved.  Of course,
> > we already reserve CONCURRENTLY and VERBOSE pretty severely, so there's
> > no change.  If you wanted REINDEX FLUFFY then it wouldn't work without
> > making that at least type_func_name_keyword I think; but REINDEX
> > (FLUFFY) would work just fine.  And of course the new feature at hand
> > can be implemented.
> 
> The question isn't whether to use a parenthesized option list.  I realized 
> that
> long ago (even though Alexey didn't initially like it).  Check 0002, which 
> gets
> rid of "bool concurrent" in favour of stmt->options_CONCURRENT.

Ah!  I see, sorry for the noise.  Well, respectfully, having a separate
boolean to store one option when you already have a bitmask for options
is silly.

-- 
Álvaro Herrerahttps://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-09-01 Thread Justin Pryzby
On Tue, Sep 01, 2020 at 11:40:18AM -0400, Alvaro Herrera wrote:
> On 2020-Aug-11, Justin Pryzby wrote:
> > On Tue, Aug 11, 2020 at 02:39:45PM +0900, Michael Paquier wrote:
> 
> > > The grammar that has been committed was the one that for the most
> > > support, so we need to live with that.  I wonder if we should simplify
> > > ReindexStmt and move the "concurrent" flag to be under "options", but
> > > that may not be worth the time spent on as long as we don't have
> > > CONCURRENTLY part of the parenthesized grammar.
> > 
> > I think it's kind of a good idea, since the next patch does exactly that
> > (parenthesize (CONCURRENTLY)).
> > 
> > I included that as a new 0002, but it doesn't save anything though, so maybe
> > it's not a win.
> 
> The advantage of using a parenthesized option list is that you can add
> *further* options without making the new keywords reserved.  Of course,
> we already reserve CONCURRENTLY and VERBOSE pretty severely, so there's
> no change.  If you wanted REINDEX FLUFFY then it wouldn't work without
> making that at least type_func_name_keyword I think; but REINDEX
> (FLUFFY) would work just fine.  And of course the new feature at hand
> can be implemented.

The question isn't whether to use a parenthesized option list.  I realized that
long ago (even though Alexey didn't initially like it).  Check 0002, which gets
rid of "bool concurrent" in favour of stmt->options_CONCURRENT.

-- 
Justin




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-09-01 Thread Alvaro Herrera
On 2020-Aug-11, Justin Pryzby wrote:
> On Tue, Aug 11, 2020 at 02:39:45PM +0900, Michael Paquier wrote:

> > The grammar that has been committed was the one that for the most
> > support, so we need to live with that.  I wonder if we should simplify
> > ReindexStmt and move the "concurrent" flag to be under "options", but
> > that may not be worth the time spent on as long as we don't have
> > CONCURRENTLY part of the parenthesized grammar.
> 
> I think it's kind of a good idea, since the next patch does exactly that
> (parenthesize (CONCURRENTLY)).
> 
> I included that as a new 0002, but it doesn't save anything though, so maybe
> it's not a win.

The advantage of using a parenthesized option list is that you can add
*further* options without making the new keywords reserved.  Of course,
we already reserve CONCURRENTLY and VERBOSE pretty severely, so there's
no change.  If you wanted REINDEX FLUFFY then it wouldn't work without
making that at least type_func_name_keyword I think; but REINDEX
(FLUFFY) would work just fine.  And of course the new feature at hand
can be implemented.

-- 
Álvaro Herrerahttps://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services




Re: Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace on the fly

2020-09-01 Thread Alexey Kondratov

On 2020-09-01 13:12, Justin Pryzby wrote:
This patch seems to be missing a call to RelationAssumeNewRelfilenode() 
in

reindex_index().

That's maybe the related to the cause of the crashes I pointed out 
earlier this

year.

Alexey's v4 patch changed RelationSetNewRelfilenode() to accept a 
tablespace
parameter, but Michael seemed to object to that.  However that seems 
cleaner

and ~30 line shorter.

Michael, would you comment on that ?  The v4 patch and your comments 
are here.

https://www.postgresql.org/message-id/attachment/105574/v4-0001-Allow-REINDEX-and-REINDEX-CONCURRENTLY-to-change-tablespace.patch
https://www.postgresql.org/message-id/20191127035416.GG5435%40paquier.xyz



Actually, the last time we discussed this point I only got the gut 
feeling that this is a subtle place and it is very easy to break things 
with these changes. However, it isn't clear for me how exactly. That 
way, I'd be glad if Michael could reword his explanation, so it'd more 
clear for me as well.


BTW, I've started doing a review of the last patch set yesterday and 
will try to post some comments later.



Regards
--
Alexey Kondratov

Postgres Professional https://www.postgrespro.com
Russian Postgres Company




  1   2   >