We carefully listened to the feedback we got from the last release candidate and incorporated some of the suggested changes. On top of that, we have fixed several bugs to reach the desired maturity state.
Here are the highlights of this release!
MySQL Shell
For this release we have focused on fixing bugs within the AdminAPI (dba.*) and core Shell functionality in order to reach GA status. Below are some important highlights, starting with the one new feature that was added.
Vertical results
Queries which return a resultset containing many columns can be difficult to virtually impossible for a human to read. For example:
1
2
3
4
5
6
7
8
|
mysql-sql> SELECT * FROM mysql.user WHERE user="mysql_innodb_cluster_r1724308646"; +------+----------------------------------+-------------+-------------+-------------+-------------+-------------+-----------+-------------+---------------+--------------+-----------+------------+-----------------+------------+------------+--------------+------------+-----------------------+------------------+--------------+-----------------+------------------+------------------+----------------+---------------------+--------------------+------------------+------------+--------------+------------------------+----------+------------+-------------+--------------+---------------+-------------+-----------------+----------------------+-----------------------+-------------------------------------------+------------------+-----------------------+-------------------+----------------+ | Host | User | Select_priv | Insert_priv | Update_priv | Delete_priv | Create_priv | Drop_priv | Reload_priv | Shutdown_priv | Process_priv | File_priv | Grant_priv | References_priv | Index_priv | Alter_priv | Show_db_priv | Super_priv | Create_tmp_table_priv | Lock_tables_priv | Execute_priv | Repl_slave_priv | Repl_client_priv | Create_view_priv | Show_view_priv | Create_routine_priv | Alter_routine_priv | Create_user_priv | Event_priv | Trigger_priv | Create_tablespace_priv | ssl_type | ssl_cipher | x509_issuer | x509_subject | max_questions | max_updates | max_connections | max_user_connections | plugin | authentication_string | password_expired | password_last_changed | password_lifetime | account_locked | +------+----------------------------------+-------------+-------------+-------------+-------------+-------------+-----------+-------------+---------------+--------------+-----------+------------+-----------------+------------+------------+--------------+------------+-----------------------+------------------+--------------+-----------------+------------------+------------------+----------------+---------------------+--------------------+------------------+------------+--------------+------------------------+----------+------------+-------------+--------------+---------------+-------------+-----------------+----------------------+-----------------------+-------------------------------------------+------------------+-----------------------+-------------------+----------------+ | % | mysql_innodb_cluster_r1724308646 | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | Y | N | N | N | N | N | N | N | N | N | | | | | 0 | 0 | 0 | 0 | mysql_native_password | *B54D7F6778119060206595E88BE2A98548EA9A43 | N | 2017-04-04 18:43:04 | null | N | +------+----------------------------------+-------------+-------------+-------------+-------------+-------------+-----------+-------------+---------------+--------------+-----------+------------+-----------------+------------+------------+--------------+------------+-----------------------+------------------+--------------+-----------------+------------------+------------------+----------------+---------------------+--------------------+------------------+------------+--------------+------------------------+----------+------------+-------------+--------------+---------------+-------------+-----------------+----------------------+-----------------------+-------------------------------------------+------------------+-----------------------+-------------------+----------------+ 1 row in set (0.00 sec) |
By introducing the support for displaying the SQL result vertically we overcome this issue. Also, a new command-line option to display all result sets vertically was added:
--vertical (or -E)
So now coming back to the original example, this time displaying the results vertically by ending the statement with “\G” instead of “;” (just as in the mysql command-line client):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
mysql-sql> SELECT * FROM mysql.user WHERE user="mysql_innodb_cluster_r1724308646"\G *************************** 1. row *************************** Host: % User: mysql_innodb_cluster_r1724308646 Select_priv: N Insert_priv: N Update_priv: N Delete_priv: N Create_priv: N Drop_priv: N Reload_priv: N Shutdown_priv: N Process_priv: N File_priv: N Grant_priv: N References_priv: N Index_priv: N Alter_priv: N Show_db_priv: N Super_priv: N Create_tmp_table_priv: N Lock_tables_priv: N Execute_priv: N Repl_slave_priv: Y Repl_client_priv: N Create_view_priv: N Show_view_priv: N Create_routine_priv: N Alter_routine_priv: N Create_user_priv: N Event_priv: N Trigger_priv: N Create_tablespace_priv: N ssl_type: ssl_cipher: x509_issuer: x509_subject: max_questions: 0 max_updates: 0 max_connections: 0 max_user_connections: 0 plugin: mysql_native_password authentication_string: *B54D7F6778119060206595E88BE2A98548EA9A43 password_expired: N password_last_changed: 2017-04-04 18:43:04 password_lifetime: null account_locked: N 1 row in set (0.00 sec) |
dba.configureLocalInstance()
In the scenario where we lack permissions to read or edit the MySQL configuration file, dba.configureLocalInstance()
failed with a confusing and unclear error: “Unexpected error checking instance: append() takes exactly one argument (2 given)”.
The cause of this internal issue was fixed and a clear error message was added which states the actual problem:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
mysql-js> dba.configureLocalInstance("root@localhost:3310") Please provide the password for 'root@localhost:3310': ******* Detected as sandbox instance. Validating MySQL configuration file at: /home/miguel/mysql-sandboxes/3310/my.cnf Validating instance... The issues above can be fixed dynamically to get the server ready for InnoDB Cluster. { "errors": [ "Error checking instance: Option file '/home/miguel/mysql-sandboxes/3310/my.cnf' is not readable: '[Errno 13] Permission denied: '/home/miguel/mysql-sandboxes/3310/my.cnf''" ], "restart_required": false, "status": "error" } mysql-js> |
dba.checkInstanceConfiguration()
Having online help available directly within the client is certainly very convenient to obtain information about all of the AdminAPI commands. Each global object of the Shell has its own helper method which can be executed using .help()
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
mysql-js> dba.help() The global variable 'dba' is used to access the MySQL AdminAPI functionality and perform DBA operations. It is used for managing MySQL InnoDB clusters. The following properties are currently supported. - verbose Enables verbose mode on the Dba operations. The following functions are currently supported. - checkInstanceConfiguration Validates an instance for usage in Group Replication. - configureLocalInstance Validates and configures an instance for cluster usage. - createCluster Creates a MySQL InnoDB cluster. - deleteSandboxInstance Deletes an existing MySQL Server instance on localhost. - deploySandboxInstance Creates a new MySQL Server instance on localhost. - dropMetadataSchema Drops the Metadata Schema. - getCluster Retrieves a cluster from the Metadata Store. - help Provides help about this class and it's members - killSandboxInstance Kills a running MySQL Server instance on localhost. - rebootClusterFromCompleteOutage Brings a cluster back ONLINE when all members are OFFLINE. - resetSession Sets the session object to be used on the Dba operations. - startSandboxInstance Starts an existing MySQL Server instance on localhost. - stopSandboxInstance Stops a running MySQL Server instance on localhost. For more help on a specific function use: dba.help('<functionName>') e.g. dba.help('deploySandboxInstance') |
However, if you tried to obtain the help for dba.checkInstanceConfiguration()
you noticed that the output was completely empty. This has been addressed as shown below:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
mysql-js> dba.help("checkInstanceConfiguration") Validates an instance for usage in Group Replication. SYNTAX <Dba>.checkInstanceConfiguration(instance[, options]) WHERE instance: An instance definition. options: Data for the operation. DESCRIPTION This function reviews the instance configuration to identify if it is valid for usage in group replication. The instance definition can be any of: - URI string. - Connection data dictionary. The options dictionary may contain the next options: - mycnfPath: The path of the MySQL configuration file for the instance. - password: The password to get connected to the instance. - clusterAdmin: The name of the InnoDB cluster administrator user. - clusterAdminPassword: The password for the InnoDB cluster administrator account. The password may be contained on the instance definition, however, it can be overwritten if it is specified on the options. |
Dissolving a Cluster
One would expect that after dissolving a cluster, the cluster object would become invalid–thus returning an error when used–since the cluster is dissolved. However, before 1.0.9 GA, this wasn’t entirely true and several inconsistent and erroneous scenarios could occur as a result.
Proper invalidation was added in this release so the user gets an error when you try to execute any method on a previously dissolved cluster:
1
2
3
4
5
6
7
8
|
mysql-js> cluster.dissolve({force: true}) The cluster was successfully dissolved. Replication was disabled but user data was left intact. mysql-js> cluster.getName() Cluster.getName: Can't call function 'getName' on a dissolved cluster (RuntimeError) mysql-js> cluster.addInstance("root@localhost:3310") Cluster.addInstance: Can't call function 'addInstance' on a dissolved cluster (RuntimeError) |
Metadata Not in Sync With Topology Change
If a change in the cluster’s topology happened due to manually changing from the default single primary mode to multi-primary then the metadata wasn’t getting updated properly. This lead to erroneous behavior within the InnoDB cluster.
For example, when turning off single primary mode (group_replication_single_primary_mode=OFF), one could see incorrect status output like the following:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
mysql-js> cluster.status() { "clusterName": "devCluster", "defaultReplicaSet": { "name": "default", "status": "OK", "statusText": "Cluster is ONLINE and can tolerate up to ONE failure.", "topology": { "localhost:3310": { "address": "localhost:3310", "mode": "R/O", "readReplicas": {}, "role": "HA", "status": "ONLINE" }, "localhost:3320": { "address": "localhost:3320", "mode": "R/O", "readReplicas": {}, "role": "HA", "status": "ONLINE" }, "localhost:3330": { "address": "localhost:3330", "mode": "R/O", "readReplicas": {}, "role": "HA", "status": "ONLINE" } } } } |
As you can see, the cluster status output is wrong, since it shows all instances as being in read-only mode when they should all be read-write. Apart from the wrong status output, the metadata still contained information marking the cluster’s topology as single-primary.
This issue has been fixed so that both the cluster status and metadata information are correctly updated when there’s any change to the topology.
Cluster.addInstance()
One of the critical features of the AdminAPI is adding MySQL Server instances to a cluster by using a simple and straightforward command: cluster.addInstance()
. However, in the past it would allow you to specify "localhost"
when doing so, rather than a valid IP address or hostname. This could lead to later issues, so we now enforce the correct procedure, which is: in order to deploy a cluster using remote instances, first connect to the instance on which the cluster will be initialized using a valid IP address or hostname, and then create the cluster. For example:
1
2
3
|
mysql-js> shell.connect('root@ic01-mysql-1:3306'); mysql-js> var cluster = dba.createCluster('myCluster'); mysql-js> cluster.addInstance('root@ic02-mysql-1:3306'); |
SSL Support on Windows
If the user’s Python installation didn’t support SSL, an error would occur making it impossible to move forward on a cluster setup through an SSL connection:
1
2
3
4
|
mysql-js> c = dba.createCluster("C") A new InnoDB cluster will be created on instance 'root@localhost:3310'. Creating InnoDB cluster 'C' on 'root@localhost:3310'... Dba.createCluster: ERROR: Error starting cluster: 'localhost@3310' - Python installation has no SSL support (RuntimeError) |
This has been greatly improved by providing a clear error message indicating to the user what should be done:
1
2
3
|
mysql-js> c = dba.createCluster("C") A new InnoDB cluster will be created on instance 'root@localhost:3310'. Creating InnoDB cluster 'C' on 'root@localhost:3310'...Dba.createCluster: ERROR: SSL for communicating with MySQL server is currently not supported in this command. Please establish a new session to the current instance without using any ssl-certificate options and re-execute the same command again.(RuntimeError) |
mysqlprovision
mysqlprovision is one of the core internal components of the AdminAPI that is used “under the hood” for much of the orchestration. We also fixed a number of issues with this internal component in the GA release.
Since mysqlprovision is a separate binary (deployed together with the Shell), there was the option and in some cases a need to set a value for the MYSQLPROVISION
environment variable. This environment variable has been removed.
If one requires or decides to build the Shell from source, the mysqlprovision binary wasn’t being built by default. That has also been fixed for this release.
Access to Schema Objects
Before GA, access to schema objects using the property syntax wasn’t automatically available upon Shell initialization. Not even if the global schema was specified on the connection data, nor after changing the global schema with \use
. For example:
1
2
3
|
$ mysqlsh root@localhost/mysql mysql-js> db.user.select() Invalid object member select (AttributeError) |
To be able to use the property syntax, one had to perform a db.getCollection()
operation first.
This has now been fixed by automatically updating the schema cache on the following times:
- When establishing a global session with a default schema via the
\connect
command - When establishing a global session with a default schema via the
shell.connect
function - When establishing a global session with a default schema through command line arguments
- When changing the global schema via the
\use
command
Crash When Executing a Print in Python Mode
When executing print
while in Python mode via the --execute
option, a crash of the Shell would occur:
1
2
|
$ mysqlsh --py -e 'print("foobar")' Segmentation fault: 11 |
This has been fixed in this release.
Failure Importing a Dump File With Multi-Line Comments
Another bug fixed in this release is a failure that happened when importing an SQL dump file which contained multi-line comments (which is quite common).
In addition to fixing that specific issue, we have also added support for:
- Multi-line MySQL Extensions (the
/*! MySQL-specific code */
syntax) - Single-line Optimizer Hints
- Multi-line Optimizer Hints
Global DB Object Properties Could Change Their Semantics at Runtime
Shadowing of object properties could happen, leading to inconsistent behaviour.
For example, the “name” property of a schema, could later be displayed as a table object:
1
2
3
4
5
6
7
8
|
mysql-js> db.help() The db variable is not set, do you want to set the active schema? [y/N]:y Please specify the schema: mysql mysql-js> db.name mysql mysql-js> db.getName() mysql |
As you can see, db.name
printed the name of the database while there could also be a table in the schema with the name “name”, e.g. storing customer names.
db.name
is now fixed to return the actual table object. The schema name must now be accessed by calling the db.getName()
function on the schema object. For example:
1
2
3
4
5
6
|
mysql-js> db.name The db variable is not set, do you want to set the active schema? [y/N]:y Please specify the schema: test <Table:name> mysql-js> db.getName() mySchema |
This was related to how cached objects were given precedence. Now, on object retrieval, the cache is accessed only if the requested member is not a fixed member of the class.
MySQL Router
The main focus for MySQL Router was also on bug fixing, just as with MySQL Shell. Still, one new feature as added.
Scanning for Configuration Files
We added functionality to scan for Router configuration files with the .ini extension, to provide backwards compatibility with previous Router versions. Router also looks in the initial directory for the .conf version, then checks for a .ini version, and then repeats the process in the second directory that’s typically the user’s home directory.
Wrong Default Configuration Files on Linux Services
On systemd based Linux distributions the mysqlrouter.service file specified a default configuration file of /etc/mysqlrouter/mysqlrouter.ini, while the MySQL Router 2.1 binary now uses /etc/mysqlrouter/mysqlrouter.conf.
This led to MySQL Router running without the expected configuration.
Super User Bootstrapping Issue
On UNIX/Linux, when bootstrapping the Router as the super-user (using sudo), the configuration file was owned by the super-user and not accessible by others. If the router was installed as a service–and since systemd uses the mysqlrouter user–the Router would not be able to read its configuration file.
We have fixed this issue by adding a new requirement for the bootstrap operation when using a super-user account, which is that you must explicitly specify a user account to use with the --user
option. Still, using a super user for bootstrapping it not recommended.
OpenSSL Build Failures
The Router wouldn’t build using OpenSSL, but only using yaSSL. This has been fixed and now one can build the Router using OpenSSL.
MySQL Router Failed to Start on Solaris
Before the GA release it was impossible to start the Router on Solaris due to an error loading the logger library. This has been fixed in this release.
Unit-Test Failures on FreeBSD
On FreeBSD some unit-tests were failing due to the lack of some exception handling.
Conclusion
After two labs releases and a subsequent Release Candidate, we are proud to announce the General Availability (GA) release!
We have reached a state of maturity for the components of InnoDB Cluster, both in terms of features and stability, which fulfill our intended goals and requirements for the first release. Our continuous work to improve the ease-of-use and accessibility of the High Availability technologies now baked into MySQL has reached the first milestone!
But we also have many more milestones to come, as we continue our efforts in simultaneously making MySQL easier for the common user and giving full advanced control and capabilities to power users. And throughout this process we will be eagerly listening to the community and analyzing all of the feedback given in order to help us improve InnoDB Cluster–always having the mindset that we want to bring simplicity and power together.
We are looking forward to your feedback! Please let us know your thoughts here in the comments, via a bug report, or a support ticket.
Thank you for using MySQL!