Skip to content

[BACKPORT 2025.2][#6640] YSQL: Support ALTER TABLESPACE SET/RESET for placement options (#31948)#32113

Open
kai-franz wants to merge 1 commit into
yugabyte:2025.2from
kai-franz:backport-0af82c65c-2025.2
Open

[BACKPORT 2025.2][#6640] YSQL: Support ALTER TABLESPACE SET/RESET for placement options (#31948)#32113
kai-franz wants to merge 1 commit into
yugabyte:2025.2from
kai-franz:backport-0af82c65c-2025.2

Conversation

@kai-franz

@kai-franz kai-franz commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

DO NOT MERGE!! CSI ❌. Once CSI passes, comment trigger jenkins to clear this warning.

This patch makes ALTER TABLESPACE ... SET/RESET work for the YB
placement options (replica_placement and read_replica_placement), so
an existing tablespace can be updated in place. This avoids the awkward
evolution of tablespace definitions which require creating new ts,
altering all relations that use it, and then deleting the old ts.

tracking issue: #6640

Some details:

  • ALTER TABLESPACE validates the final spcoptions the same way we
    validate ALTER TABLE/INDEX/MATERIALIZED VIEW ... SET TABLESPACE.
  • If the tablespace is already in use, the new placement has to be
    satisfiable
  • Existing objects are not moved synchronously. We keep using the
    current master tablespace refresh + load balancer path, so movement
    happens asynchronously after the new tablespace options are picked up
  • read_replica_placement still requires replica_placement, so RESET (replica_placement) fails if read_replica_placement is still set.

Test coverage added for:

  • ALTER TABLESPACE ... SET/RESET regression cases
  • movement for tables, indexes, materialized views, and tablegroups
  • reset behavior
  • invalid placement / invalid JSON cases
  • read replica validation, including the RESET (replica_placement)
    case above

Also includes YSQL docs for ALTER TABLESPACE.

Tested successfully with:

  • ./yb_build.sh release --target postgres --skip-java --no-odyssey
  • JAVA_TOOL_OPTIONS='--add-opens=java.base/java.lang=ALL-UNNAMED' ./yb_build.sh release --java-test org.yb.pgsql.TestPgRegressTablespaces
  • JAVA_TOOL_OPTIONS='--add-opens=java.base/java.lang=ALL-UNNAMED' ./yb_build.sh release --java-test 'org.yb.pgsql.TestTablespaceProperties#testAlterTablespacePlacementMovesExistingObjects'
  • JAVA_TOOL_OPTIONS='--add-opens=java.base/java.lang=ALL-UNNAMED' ./yb_build.sh release --java-test 'org.yb.pgsql.TestTablespaceProperties#negativeTest'
  • JAVA_TOOL_OPTIONS='--add-opens=java.base/java.lang=ALL-UNNAMED' ./yb_build.sh release --java-test 'org.yb.pgsql.TestTablespaceProperties#readReplicaWithTablespaces'

Practical testing with ysqlsh:

yugabyte=# select spcname, spcoptions from pg_tablespace where spcname = 'ats_unused';
  spcname   | spcoptions
------------+------------
 ats_unused |
(1 row)

yugabyte=# \set valid_placement '{"num_replicas":1,"placement_blocks":[{"cloud":"cloud1","region":"datacenter1","zone":"rack1","min_num_replicas":1}]}'

yugabyte=# \echo :valid_placement
{"num_replicas":1,"placement_blocks":[{"cloud":"cloud1","region":"datacenter1","zone":"rack1","min_num_replicas":1}]}

yugabyte=# ALTER TABLESPACE ats_unused SET (
  replica_placement=:'valid_placement',
  read_replica_placement=:'valid_placement'
);
ALTER TABLESPACE

yugabyte=# select spcname, spcoptions from pg_tablespace where spcname = 'ats_unused';
  spcname   |                                                                                                                                                           spcoptions
------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 ats_unused | {"replica_placement={\"num_replicas\":1,\"placement_blocks\":[{\"cloud\":\"cloud1\",\"region\":\"datacenter1\",\"zone\":\"rack1\",\"min_num_replicas\":1}]}","read_replica_placement={\"num_replicas\":1,\"placement_blocks\":[{\"cloud\":\"cloud1\",\"region\":\"datacenter1\",\"zone\":\"rack1\",\"min_num_replicas\":1}]}"}
(1 row)

yugabyte=# ALTER TABLESPACE ats_unused RESET (replica_placement);
ERROR:  read_replica_placement option requires replica_placement to be set

yugabyte=# ALTER TABLESPACE ats_unused RESET (read_replica_placement);
ALTER TABLESPACE

yugabyte=# select spcname, spcoptions from pg_tablespace where spcname = 'ats_unused';
  spcname   |                                                                          spcoptions
------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------
 ats_unused | {"replica_placement={\"num_replicas\":1,\"placement_blocks\":[{\"cloud\":\"cloud1\",\"region\":\"datacenter1\",\"zone\":\"rack1\",\"min_num_replicas\":1}]}"}
(1 row)

yugabyte=# ALTER TABLESPACE ats_unused RESET (replica_placement);
ALTER TABLESPACE

yugabyte=# select spcname, spcoptions from pg_tablespace where spcname = 'ats_unused';
  spcname   | spcoptions                                                                                                                                                                                                        ------------+------------
 ats_unused |
(1 row)

Original commit: 0af82c6 / #31948

Merge conflicts

  • docs/content/stable/api/ysql/the-sql-language/statements/_index.md — DDL statement-list table had diverged from master (2025.2 wraps statement links in backticks and omits trailing slashes; master had since dropped the backticks, added trailing slashes, and a DROP VIEW row). Kept 2025.2's existing formatting and inserted only the single new row this change introduces — | [ALTER TABLESPACE](ddl_alter_tablespace) | Change tablespace placement options | — after the ALTER TABLE row, without pulling in the unrelated reformatting.

automated · Claude Code (Opus 4.8)

…ESET for placement options (yugabyte#31948)

This patch makes `ALTER TABLESPACE ... SET/RESET` work for the YB
placement options (`replica_placement` and `read_replica_placement`), so
an existing tablespace can be updated in place. This avoids the awkward
evolution of tablespace definitions which require creating new ts,
altering all relations that use it, and then deleting the old ts.

tracking issue: yugabyte#6640 

Some details:

- `ALTER TABLESPACE` validates the final `spcoptions` the same way we
validate `ALTER TABLE/INDEX/MATERIALIZED VIEW ... SET TABLESPACE`.
- If the tablespace is already in use, the new placement has to be
satisfiable
- Existing objects are not moved synchronously. We keep using the
current master tablespace refresh + load balancer path, so movement
happens asynchronously after the new tablespace options are picked up
- `read_replica_placement` still requires `replica_placement`, so `RESET
(replica_placement)` fails if `read_replica_placement` is still set.

Test coverage added for:

- `ALTER TABLESPACE ... SET/RESET` regression cases
- movement for tables, indexes, materialized views, and tablegroups
- reset behavior
- invalid placement / invalid JSON cases
- read replica validation, including the `RESET (replica_placement)`
case above

Also includes YSQL docs for `ALTER TABLESPACE`.

Tested successfully with:

- `./yb_build.sh release --target postgres --skip-java --no-odyssey`
- `JAVA_TOOL_OPTIONS='--add-opens=java.base/java.lang=ALL-UNNAMED'
./yb_build.sh release --java-test org.yb.pgsql.TestPgRegressTablespaces`
- `JAVA_TOOL_OPTIONS='--add-opens=java.base/java.lang=ALL-UNNAMED'
./yb_build.sh release --java-test
'org.yb.pgsql.TestTablespaceProperties#testAlterTablespacePlacementMovesExistingObjects'`
- `JAVA_TOOL_OPTIONS='--add-opens=java.base/java.lang=ALL-UNNAMED'
./yb_build.sh release --java-test
'org.yb.pgsql.TestTablespaceProperties#negativeTest'`
- `JAVA_TOOL_OPTIONS='--add-opens=java.base/java.lang=ALL-UNNAMED'
./yb_build.sh release --java-test
'org.yb.pgsql.TestTablespaceProperties#readReplicaWithTablespaces'`

Practical testing with `ysqlsh`:

```sql
yugabyte=# select spcname, spcoptions from pg_tablespace where spcname = 'ats_unused';
  spcname   | spcoptions
------------+------------
 ats_unused |
(1 row)

yugabyte=# \set valid_placement '{"num_replicas":1,"placement_blocks":[{"cloud":"cloud1","region":"datacenter1","zone":"rack1","min_num_replicas":1}]}'

yugabyte=# \echo :valid_placement
{"num_replicas":1,"placement_blocks":[{"cloud":"cloud1","region":"datacenter1","zone":"rack1","min_num_replicas":1}]}

yugabyte=# ALTER TABLESPACE ats_unused SET (
  replica_placement=:'valid_placement',
  read_replica_placement=:'valid_placement'
);
ALTER TABLESPACE

yugabyte=# select spcname, spcoptions from pg_tablespace where spcname = 'ats_unused';
  spcname   |                                                                                                                                                           spcoptions
------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 ats_unused | {"replica_placement={\"num_replicas\":1,\"placement_blocks\":[{\"cloud\":\"cloud1\",\"region\":\"datacenter1\",\"zone\":\"rack1\",\"min_num_replicas\":1}]}","read_replica_placement={\"num_replicas\":1,\"placement_blocks\":[{\"cloud\":\"cloud1\",\"region\":\"datacenter1\",\"zone\":\"rack1\",\"min_num_replicas\":1}]}"}
(1 row)

yugabyte=# ALTER TABLESPACE ats_unused RESET (replica_placement);
ERROR:  read_replica_placement option requires replica_placement to be set

yugabyte=# ALTER TABLESPACE ats_unused RESET (read_replica_placement);
ALTER TABLESPACE

yugabyte=# select spcname, spcoptions from pg_tablespace where spcname = 'ats_unused';
  spcname   |                                                                          spcoptions
------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------
 ats_unused | {"replica_placement={\"num_replicas\":1,\"placement_blocks\":[{\"cloud\":\"cloud1\",\"region\":\"datacenter1\",\"zone\":\"rack1\",\"min_num_replicas\":1}]}"}
(1 row)

yugabyte=# ALTER TABLESPACE ats_unused RESET (replica_placement);
ALTER TABLESPACE

yugabyte=# select spcname, spcoptions from pg_tablespace where spcname = 'ats_unused';
  spcname   | spcoptions                                                                                                                                                                                                        ------------+------------
 ats_unused |
(1 row)
```

Original commit: 0af82c6 / yugabyte#31948
@kai-franz

Copy link
Copy Markdown
Contributor Author

Trigger Jenkins

@yb-agentk-dev

yb-agentk-dev Bot commented Jun 9, 2026

Copy link
Copy Markdown

Jenkins build has been triggered. Results will be available in the CI checks. CSI

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements support for the ALTER TABLESPACE statement in YugabyteDB, allowing users to change or reset replica and read-replica placement options. It includes validation of placement options, asynchronous data movement handling for dependent objects, comprehensive Java and regression tests, and updated documentation. There are no review comments, and I have no feedback to provide.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants