Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unify admin behavior #856

Merged
merged 5 commits into from
Apr 27, 2023
Merged

Unify admin behavior #856

merged 5 commits into from
Apr 27, 2023

Conversation

brfrn169
Copy link
Collaborator

@brfrn169 brfrn169 commented Apr 26, 2023

This PR unifies the behavior of the admin implementations (e.g. an error is thrown when dropping a namespace but the namespace has some tables). I'll add inline comments for the details. Please take a look!

@@ -15,6 +15,7 @@ public interface Admin {
*
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Documented the unified admin behaviors.

@@ -14,6 +14,8 @@ public interface DistributedTransactionAdmin extends Admin {
* Creates coordinator namespace and tables.
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ditto. Documented the unified admin behaviors.

import java.util.Set;
import javax.annotation.Nullable;

public class CheckedDistributedStorageAdmin implements DistributedStorageAdmin {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This CheckedDistributedStorageAdmin is the main component in this PR.

This class wraps the DistributedStorageAdmin implementations, and adds some checks to them.

Comment on lines +16 to +20
/**
* Whether to check if the namespace exists or not. Set false when the storage does not support
* namespaces.
*/
private final boolean checkNamespace;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Since we have several implementations that don't support namespaces (DynamoDB, SQLite), we set it to false for them.

Maybe we can remove it after supporting the namespace listing feature. (CC: @Torch3333 )

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe we can remove it after supporting the namespace listing feature.

Agreed.

}

@Override
public void addNewColumnToTable(
String namespace, String table, String columnName, DataType columnType)
throws ExecutionException {
try {
if (getTableMetadata(namespace, table).getColumnNames().contains(columnName)) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Since we have checks in CheckedDistributedStorageAdmin, removed these checks from the admin implementations.

@@ -54,18 +54,30 @@ public ConsensusCommitAdmin(DatabaseConfig databaseConfig) {

@Override
public void createCoordinatorTables(Map<String, String> options) throws ExecutionException {
if (coordinatorTablesExist()) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Also, added some checks to ConsensusCommitAdmin.

@brfrn169 brfrn169 changed the title Unify admin behaviors Unify admin behavior Apr 26, 2023
throw new IllegalArgumentException("Namespace does not exist: " + namespace);
}
if (tableExists(namespace, table)) {
throw new IllegalArgumentException("Table already exists: " + namespace + "." + table);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
throw new IllegalArgumentException("Table already exists: " + namespace + "." + table);
throw new IllegalArgumentException("Table already exists: " + ScalarDbUtils.getFullTableName(namespace, table));

Should the utility function be used all the time?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed in fcb2338. Thanks.

@Override
public void dropTable(String namespace, String table) throws ExecutionException {
if (!tableExists(namespace, table)) {
throw new IllegalArgumentException("Table does not exist: " + namespace + "." + table);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
throw new IllegalArgumentException("Table does not exist: " + namespace + "." + table);
throw new IllegalArgumentException("Table does not exist: " + ScalarDbUtils.getFullTableName(namespace, table));

Likewise.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed in fcb2338. Thanks.

@Override
public void truncateTable(String namespace, String table) throws ExecutionException {
if (!tableExists(namespace, table)) {
throw new IllegalArgumentException("Table does not exist: " + namespace + "." + table);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
throw new IllegalArgumentException("Table does not exist: " + namespace + "." + table);
throw new IllegalArgumentException("Table does not exist: " + ScalarDbUtils.getFullTableName(namespace, table));

Likewise

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed in fcb2338. Thanks.

public void dropIndex(String namespace, String table, String columnName)
throws ExecutionException {
if (!tableExists(namespace, table)) {
throw new IllegalArgumentException("Table does not exist: " + namespace + "." + table);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
throw new IllegalArgumentException("Table does not exist: " + namespace + "." + table);
throw new IllegalArgumentException("Table does not exist: " + ScalarDbUtils.getFullTableName(namespace, table));

Likewise.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed in fcb2338. Thanks.

@@ -165,6 +177,9 @@ public void addNewColumnToTable(
String namespace, String table, String columnName, DataType columnType)
throws ExecutionException {
TableMetadata tableMetadata = getTableMetadata(namespace, table);
if (tableMetadata == null) {
throw new IllegalArgumentException("Table does not exist: " + namespace + "." + table);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
throw new IllegalArgumentException("Table does not exist: " + namespace + "." + table);
throw new IllegalArgumentException("Table does not exist: " + ScalarDbUtils.getFullTableName(namespace, table));

Likewise.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed in fbe7195. Thanks.

Comment on lines +16 to +20
/**
* Whether to check if the namespace exists or not. Set false when the storage does not support
* namespaces.
*/
private final boolean checkNamespace;
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe we can remove it after supporting the namespace listing feature.

Agreed.

String namespace, String table, TableMetadata metadata, Map<String, String> options)
throws ExecutionException {
if (checkNamespace && !namespaceExists(namespace)) {
throw new IllegalArgumentException("Namespace does not exist: " + namespace);
Copy link
Contributor

Choose a reason for hiding this comment

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

When the underlying admin is the DynamoAdmin used with a namespace prefix, the value of the namespace argument used in this class here is not prefixed. The error message may be confusing since it will mention the unprefixed namespace.
For clarity, mentioning the prefixed namespace in the error message throughout this class would be great. What do you think ?

I have the same concern about using the unprefixed namespace in the error message in the ConsensusCommitAdmin

Copy link
Collaborator Author

@brfrn169 brfrn169 Apr 26, 2023

Choose a reason for hiding this comment

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

I think since users pass the logical name (the unprefixed name) to the APIs, I feel it's consistent and natural for the error messages to use the logical name. In CheckedDistributedStorageAdmin, the IllegalArgumentException always has the logical name. However, when an error occurs, the message of the exception also uses the logical name, but the cause of the exception should have the physical name. So we can use it for debugging.

What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

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

Indeed, this makes sense. Let's keep it as is. Thank you.

}

@Override
public void dropTable(String namespace, String table) throws ExecutionException {
Copy link
Contributor

Choose a reason for hiding this comment

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

These xxxxTable() and xxxxIndex() should check namespace as well as createTable()? I think either is fine as long as they're consistent.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

In the operations that assumes the the target table exists, we don't have the namespace check. In that sense, they should be consistent. And the table check contains the namespace check, so I think that should be okay.

@@ -77,7 +77,7 @@ public String dropNamespaceSql(String namespace) {
@Override
public void dropNamespaceTranslateSQLException(SQLException e, String namespace)
throws ExecutionException {
throw new ExecutionException(String.format("error dropping the schema %s", namespace), e);
throw new ExecutionException("dropping the schema failed: %s" + namespace, e);
Copy link
Contributor

Choose a reason for hiding this comment

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

%s should be removed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ah my bad. Good catch! Thanks. Fixed in 87166ae.

@@ -86,7 +86,7 @@ public String dropNamespaceSql(String namespace) {
@Override
public void dropNamespaceTranslateSQLException(SQLException e, String namespace)
throws ExecutionException {
throw new ExecutionException(String.format("error dropping the schema %s", namespace), e);
throw new ExecutionException("dropping the schema failed: %s" + namespace, e);
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as above

Copy link
Collaborator Author

@brfrn169 brfrn169 Apr 26, 2023

Choose a reason for hiding this comment

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

Fixed in 87166ae. Thanks.

@@ -78,7 +78,7 @@ public String dropNamespaceSql(String namespace) {
@Override
public void dropNamespaceTranslateSQLException(SQLException e, String namespace)
throws ExecutionException {
throw new ExecutionException(String.format("error dropping the schema %s", namespace), e);
throw new ExecutionException("dropping the schema failed: %s" + namespace, e);
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as above

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed in 87166ae. Thanks.

Copy link
Contributor

@feeblefakie feeblefakie left a comment

Choose a reason for hiding this comment

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

LGTM! Thank you!

Copy link
Contributor

@komamitsu komamitsu left a comment

Choose a reason for hiding this comment

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

LGTM! 👍

Copy link
Contributor

@Torch3333 Torch3333 left a comment

Choose a reason for hiding this comment

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

LGTM, thank you!

Copy link
Contributor

@kota2and3kan kota2and3kan left a comment

Choose a reason for hiding this comment

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

LGTM! Thank you!
(Sorry for the late review...)


For your reference, I was able to get the error as expected as follows (i.e., the bug I found is fixed).

  • Create schemas/tables on MySQL
    0: scalardb>
    0: scalardb> CREATE COORDINATOR TABLES;
    No rows affected (1.027 seconds)
    0: scalardb>
    0: scalardb>
    0: scalardb> CREATE NAMESPACE s0;
    No rows affected (0.03 seconds)
    0: scalardb>
    0: scalardb>
    0: scalardb> CREATE NAMESPACE s1;
    No rows affected (0.044 seconds)
    0: scalardb>
    0: scalardb>
    0: scalardb> CREATE TABLE s0.t0 (c1 INT PRIMARY KEY, c2 INT);
    No rows affected (0.426 seconds)
    0: scalardb>
    0: scalardb>
    0: scalardb> CREATE TABLE s1.t1 (c1 INT PRIMARY KEY, c2 INT);
    No rows affected (0.302 seconds)
    0: scalardb>
  • Check schemas/tables on MySQL
    mysql> show databases;
    +--------------------+
    | Database           |
    +--------------------+
    | coordinator        |
    | information_schema |
    | my_database        |
    | mysql              |
    | performance_schema |
    | s0                 |
    | s1                 |
    | scalardb           |
    | sys                |
    +--------------------+
    9 rows in set (0.00 sec)
    
    mysql>
    mysql> show tables from s0;
    +--------------+
    | Tables_in_s0 |
    +--------------+
    | t0           |
    +--------------+
    1 row in set (0.00 sec)
    
    mysql>
    mysql> show tables from s1;
    +--------------+
    | Tables_in_s1 |
    +--------------+
    | t1           |
    +--------------+
    1 row in set (0.00 sec)
  • Check table metadata
    mysql> select * from scalardb.metadata;
    +-------------------+------------------------+-----------+-----------+------------------+---------+------------------+
    | full_table_name   | column_name            | data_type | key_type  | clustering_order | indexed | ordinal_position |
    +-------------------+------------------------+-----------+-----------+------------------+---------+------------------+
    | coordinator.state | tx_created_at          | BIGINT    | NULL      | NULL             |       0 |                3 |
    | coordinator.state | tx_id                  | TEXT      | PARTITION | NULL             |       0 |                1 |
    | coordinator.state | tx_state               | INT       | NULL      | NULL             |       0 |                2 |
    | s0.t0             | before_c2              | INT       | NULL      | NULL             |       0 |               13 |
    | s0.t0             | before_tx_committed_at | BIGINT    | NULL      | NULL             |       0 |               12 |
    | s0.t0             | before_tx_id           | TEXT      | NULL      | NULL             |       0 |                8 |
    | s0.t0             | before_tx_prepared_at  | BIGINT    | NULL      | NULL             |       0 |               11 |
    | s0.t0             | before_tx_state        | INT       | NULL      | NULL             |       0 |                9 |
    | s0.t0             | before_tx_version      | INT       | NULL      | NULL             |       0 |               10 |
    | s0.t0             | c1                     | INT       | PARTITION | NULL             |       0 |                1 |
    | s0.t0             | c2                     | INT       | NULL      | NULL             |       0 |                2 |
    | s0.t0             | tx_committed_at        | BIGINT    | NULL      | NULL             |       0 |                7 |
    | s0.t0             | tx_id                  | TEXT      | NULL      | NULL             |       0 |                3 |
    | s0.t0             | tx_prepared_at         | BIGINT    | NULL      | NULL             |       0 |                6 |
    | s0.t0             | tx_state               | INT       | NULL      | NULL             |       0 |                4 |
    | s0.t0             | tx_version             | INT       | NULL      | NULL             |       0 |                5 |
    | s1.t1             | before_c2              | INT       | NULL      | NULL             |       0 |               13 |
    | s1.t1             | before_tx_committed_at | BIGINT    | NULL      | NULL             |       0 |               12 |
    | s1.t1             | before_tx_id           | TEXT      | NULL      | NULL             |       0 |                8 |
    | s1.t1             | before_tx_prepared_at  | BIGINT    | NULL      | NULL             |       0 |               11 |
    | s1.t1             | before_tx_state        | INT       | NULL      | NULL             |       0 |                9 |
    | s1.t1             | before_tx_version      | INT       | NULL      | NULL             |       0 |               10 |
    | s1.t1             | c1                     | INT       | PARTITION | NULL             |       0 |                1 |
    | s1.t1             | c2                     | INT       | NULL      | NULL             |       0 |                2 |
    | s1.t1             | tx_committed_at        | BIGINT    | NULL      | NULL             |       0 |                7 |
    | s1.t1             | tx_id                  | TEXT      | NULL      | NULL             |       0 |                3 |
    | s1.t1             | tx_prepared_at         | BIGINT    | NULL      | NULL             |       0 |                6 |
    | s1.t1             | tx_state               | INT       | NULL      | NULL             |       0 |                4 |
    | s1.t1             | tx_version             | INT       | NULL      | NULL             |       0 |                5 |
    +-------------------+------------------------+-----------+-----------+------------------+---------+------------------+
    29 rows in set (0.00 sec)
  • Drop namespaces with/without CASCADE option
    0: scalardb> DROP NAMESPACE s0;
    Error: Invalid query (INVALID_ARGUMENT: Namespace is not empty: s0, [t0]) (state=42000,code=501)
    0: scalardb>
    0: scalardb> DROP NAMESPACE s1 CASCADE;
    No rows affected (0.149 seconds)
    0: scalardb>
    • When I run the DROP SCHEMA without CASCADE option, ScalarDB returns error as expected.
  • Check schemas/tables on MySQL
    mysql> show databases;
    +--------------------+
    | Database           |
    +--------------------+
    | coordinator        |
    | information_schema |
    | my_database        |
    | mysql              |
    | performance_schema |
    | s0                 |
    | scalardb           |
    | sys                |
    +--------------------+
    8 rows in set (0.00 sec)
    
    mysql>
    mysql> show tables from s0;
    +--------------+
    | Tables_in_s0 |
    +--------------+
    | t0           |
    +--------------+
    1 row in set (0.00 sec)
  • Check table metadata
    mysql> select * from scalardb.metadata;
    +-------------------+------------------------+-----------+-----------+------------------+---------+------------------+
    | full_table_name   | column_name            | data_type | key_type  | clustering_order | indexed | ordinal_position |
    +-------------------+------------------------+-----------+-----------+------------------+---------+------------------+
    | coordinator.state | tx_created_at          | BIGINT    | NULL      | NULL             |       0 |                3 |
    | coordinator.state | tx_id                  | TEXT      | PARTITION | NULL             |       0 |                1 |
    | coordinator.state | tx_state               | INT       | NULL      | NULL             |       0 |                2 |
    | s0.t0             | before_c2              | INT       | NULL      | NULL             |       0 |               13 |
    | s0.t0             | before_tx_committed_at | BIGINT    | NULL      | NULL             |       0 |               12 |
    | s0.t0             | before_tx_id           | TEXT      | NULL      | NULL             |       0 |                8 |
    | s0.t0             | before_tx_prepared_at  | BIGINT    | NULL      | NULL             |       0 |               11 |
    | s0.t0             | before_tx_state        | INT       | NULL      | NULL             |       0 |                9 |
    | s0.t0             | before_tx_version      | INT       | NULL      | NULL             |       0 |               10 |
    | s0.t0             | c1                     | INT       | PARTITION | NULL             |       0 |                1 |
    | s0.t0             | c2                     | INT       | NULL      | NULL             |       0 |                2 |
    | s0.t0             | tx_committed_at        | BIGINT    | NULL      | NULL             |       0 |                7 |
    | s0.t0             | tx_id                  | TEXT      | NULL      | NULL             |       0 |                3 |
    | s0.t0             | tx_prepared_at         | BIGINT    | NULL      | NULL             |       0 |                6 |
    | s0.t0             | tx_state               | INT       | NULL      | NULL             |       0 |                4 |
    | s0.t0             | tx_version             | INT       | NULL      | NULL             |       0 |                5 |
    +-------------------+------------------------+-----------+-----------+------------------+---------+------------------+
    16 rows in set (0.00 sec)

@brfrn169 brfrn169 merged commit 7c2cb33 into master Apr 27, 2023
12 checks passed
@brfrn169 brfrn169 deleted the unify-admin-behaviors branch April 27, 2023 08:53
@brfrn169 brfrn169 added this to Done in 3.9.0 Apr 27, 2023
brfrn169 added a commit that referenced this pull request Apr 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
No open projects
3.9.0
Done
Development

Successfully merging this pull request may close these issues.

None yet

5 participants