Skip to content

Commit 2476135

Browse files
ScottLinnncopybara-github
authored andcommitted
Adding support for DSQL
PiperOrigin-RevId: 834812092
1 parent 6e8e266 commit 2476135

5 files changed

Lines changed: 382 additions & 1 deletion

File tree

perfkitbenchmarker/linux_benchmarks/benchbase_benchmark.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,24 +34,36 @@
3434
relational_db:
3535
cloud: GCP
3636
engine: spanner-postgres
37-
spanner_nodes: 3
3837
db_spec:
3938
GCP:
39+
machine_type: db-n1-standard-16
4040
zone: us-central1-f
41+
AWS:
42+
machine_type: db.m4.4xlarge
43+
zone: us-east-1a
4144
db_disk_spec:
4245
GCP:
4346
disk_size: 2048
4447
disk_type: pd-ssd
48+
AWS: # not actually used by it's a required spec so fill random values
49+
disk_size: 6144
50+
disk_type: gp2
4551
vm_groups:
4652
clients:
4753
vm_spec:
4854
GCP:
4955
machine_type: n2-standard-21
5056
zone: us-central1-c
57+
AWS:
58+
machine_type: m5.8xlarge
59+
zone: us-east-1
5160
disk_spec:
5261
GCP:
5362
disk_size: 500
5463
disk_type: pd-ssd
64+
AWS:
65+
disk_size: 500
66+
disk_type: gp3
5567
"""
5668

5769
FLAGS = flags.FLAGS
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
# Copyright 2025 PerfKitBenchmarker Authors. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
"""Managed relational database provisioning and teardown for AWS Aurora DSQL."""
15+
16+
import json
17+
from typing import Any
18+
19+
from absl import flags
20+
from absl import logging
21+
from perfkitbenchmarker import errors
22+
from perfkitbenchmarker import sql_engine_utils
23+
from perfkitbenchmarker import vm_util
24+
from perfkitbenchmarker.providers.aws import aws_relational_db
25+
from perfkitbenchmarker.providers.aws import util
26+
27+
28+
# TODO(shuninglin): Add cluster creation from a backup.
29+
# TODO(shuninglin): Add reaper for this new resource.
30+
31+
FLAGS = flags.FLAGS
32+
33+
DEFAULT_AURORA_DSQL_POSTGRES_VERSION = '16.2'
34+
35+
_MAP_ENGINE_TO_DEFAULT_VERSION = {
36+
sql_engine_utils.AURORA_DSQL_POSTGRES: DEFAULT_AURORA_DSQL_POSTGRES_VERSION,
37+
}
38+
39+
_AURORA_DSQL_ENGINES = [
40+
sql_engine_utils.AURORA_DSQL_POSTGRES,
41+
]
42+
43+
44+
class AwsAuroraDsqlRelationalDb(aws_relational_db.BaseAwsRelationalDb):
45+
"""Implements the aurora DSQL database for AWS."""
46+
47+
CLOUD = 'AWS'
48+
IS_MANAGED = True
49+
ENGINE = _AURORA_DSQL_ENGINES
50+
51+
def __init__(self, relational_db_spec):
52+
super().__init__(relational_db_spec)
53+
self.cluster_id = None
54+
55+
# DSQL has different format for tags:
56+
# https://docs.aws.amazon.com/cli/v1/reference/rds/create-db-cluster.html
57+
def _MakeDsqlTags(self) -> list[str]:
58+
"""Returns the tags to be used for the DSQL cluster."""
59+
tags: dict[str, Any] = util.MakeDefaultTags()
60+
formatted_tags_list: list[str] = [
61+
'%s=%s' % (k, v) for k, v in sorted(tags.items())
62+
]
63+
formatted_tags_str = ','.join(formatted_tags_list)
64+
return [formatted_tags_str]
65+
66+
def _Create(self) -> None:
67+
"""Creates the AWS Aurora DSQL instance.
68+
69+
Raises:
70+
Exception: if unknown how to create self.spec.engine.
71+
"""
72+
cmd = (
73+
util.AWS_PREFIX
74+
+ [
75+
'dsql',
76+
'create-cluster',
77+
'--region=%s' % self.region,
78+
# Make it easier for deletion/reaping
79+
'--no-deletion-protection-enabled',
80+
'--tags',
81+
]
82+
+ self._MakeDsqlTags()
83+
)
84+
85+
stdout, _, _ = vm_util.IssueCommand(cmd)
86+
response = json.loads(stdout)
87+
# We are not allowed to define cluster id ourselves, so we have to use the
88+
# one returned by the create-cluster command.
89+
self.cluster_id = response['identifier']
90+
91+
def _DescribeCluster(self) -> dict[str, Any] | None:
92+
cmd = util.AWS_PREFIX + [
93+
'dsql',
94+
'get-cluster',
95+
'--identifier=%s' % self.cluster_id,
96+
'--region=%s' % self.region,
97+
]
98+
stdout, _, retcode = vm_util.IssueCommand(cmd, raise_on_failure=False)
99+
if retcode != 0:
100+
return None
101+
json_output: dict[str, Any] = json.loads(stdout)
102+
return json_output
103+
104+
def _IsReady(self, timeout=aws_relational_db.IS_READY_TIMEOUT) -> bool:
105+
"""Returns true if the cluster is ready."""
106+
json_output = self._DescribeCluster()
107+
return bool(json_output and json_output['status'] == 'ACTIVE')
108+
109+
def _Exists(self) -> bool:
110+
"""Returns true if the underlying cluster exists."""
111+
json_output = self._DescribeCluster()
112+
if json_output:
113+
return True
114+
return False
115+
116+
def _Delete(self) -> None:
117+
"""Deletes the DSQL cluster."""
118+
119+
logging.info(
120+
'Deleting DSQL cluster %s in region %s',
121+
self.cluster_id,
122+
self.region,
123+
)
124+
125+
cmd = util.AWS_PREFIX + [
126+
'dsql',
127+
'delete-cluster',
128+
'--identifier=%s' % self.cluster_id,
129+
'--region',
130+
self.region,
131+
]
132+
vm_util.IssueCommand(cmd, raise_on_failure=False)
133+
134+
@vm_util.Retry(
135+
poll_interval=60,
136+
fuzz=0,
137+
timeout=3600,
138+
retryable_exceptions=(errors.Resource.RetryableDeletionError,),
139+
)
140+
def WaitUntilClusterDeleted():
141+
if self._Exists():
142+
raise errors.Resource.RetryableDeletionError('Not yet deleted')
143+
144+
WaitUntilClusterDeleted()
145+
146+
@staticmethod
147+
def GetDefaultEngineVersion(engine) -> str:
148+
"""Returns the default version of a given database engine.
149+
150+
Args:
151+
engine (string): type of database (my_sql or postgres).
152+
153+
Returns:
154+
(string): Default engine version.
155+
Raises:
156+
errors.Config.InvalidValue: If unrecognized engine is specified.
157+
"""
158+
if engine not in _MAP_ENGINE_TO_DEFAULT_VERSION:
159+
raise errors.Config.InvalidValue(
160+
'Unspecified default version for {}'.format(engine)
161+
)
162+
return _MAP_ENGINE_TO_DEFAULT_VERSION[engine]
163+
164+
def GetResourceMetadata(self) -> dict[str, Any]:
165+
metadata = super().GetResourceMetadata()
166+
metadata['dsql_cluster_id'] = self.cluster_id
167+
return metadata

perfkitbenchmarker/providers/aws/aws_relational_db.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ class BaseAwsRelationalDb(relational_db.BaseRelationalDb):
9292
the common methods across both offerings.
9393
"""
9494

95+
# TODO(shuninglin): Remove REQUIRED_ATTRS from rds and aurora subclasses.
96+
REQUIRED_ATTRS = ['CLOUD', 'IS_MANAGED', 'ENGINE']
97+
9598
def __init__(self, relational_db_spec):
9699
super().__init__(relational_db_spec)
97100
self.all_instance_ids = []

perfkitbenchmarker/sql_engine_utils.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
MARIADB = 'mariadb'
3737
POSTGRES = 'postgres'
3838
AURORA_POSTGRES = 'aurora-postgresql'
39+
AURORA_DSQL_POSTGRES = 'aurora-dsql-postgres'
3940
AURORA_MYSQL = 'aurora-mysql'
4041
SQLSERVER = 'sqlserver'
4142
SQLSERVER_EXPRESS = 'sqlserver-ex'
@@ -51,6 +52,7 @@
5152
MARIADB,
5253
MYSQL,
5354
POSTGRES,
55+
AURORA_DSQL_POSTGRES,
5456
AURORA_POSTGRES,
5557
AURORA_MYSQL,
5658
SQLSERVER,
@@ -569,6 +571,7 @@ def GetDbEngineType(db_engine: str) -> str:
569571
return SQLSERVER
570572
elif (
571573
db_engine == AWS_AURORA_POSTGRES_ENGINE
574+
or db_engine == AURORA_DSQL_POSTGRES
572575
or db_engine == FLEXIBLE_SERVER_POSTGRES
573576
):
574577
return POSTGRES

0 commit comments

Comments
 (0)