Skip to content
This repository was archived by the owner on Apr 8, 2025. It is now read-only.

Commit 09110ba

Browse files
committed
Add session setting support for specs
This adds support for session settings for the various specs formats. These session settings will be applied by the http/pg client before the spec is executed.
1 parent 9d07688 commit 09110ba

File tree

9 files changed

+77
-18
lines changed

9 files changed

+77
-18
lines changed

cr8/bench_spec.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,13 @@ def from_dict(d):
3030

3131

3232
class Spec:
33-
def __init__(self, setup, teardown, queries=None, load_data=None, meta=None):
33+
def __init__(self, setup, teardown, queries=None, load_data=None, meta=None, session_settings=None):
3434
self.setup = setup
3535
self.teardown = teardown
3636
self.queries = queries
3737
self.load_data = load_data
3838
self.meta = meta or {}
39+
self.session_settings = session_settings or {}
3940

4041
@staticmethod
4142
def from_dict(d):
@@ -45,6 +46,7 @@ def from_dict(d):
4546
meta=d.get('meta', {}),
4647
queries=d.get('queries', []),
4748
load_data=d.get('load_data', []),
49+
session_settings=d.get('session_settings', {}),
4850
)
4951

5052
@staticmethod

cr8/clients.py

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -216,18 +216,25 @@ def _verify_ssl_from_first(hosts):
216216

217217

218218
class AsyncpgClient:
219-
def __init__(self, hosts, pool_size=25):
219+
def __init__(self, hosts, pool_size=25, session_settings=None):
220220
self.dsn = _to_dsn(hosts)
221221
self.pool_size = pool_size
222222
self._pool = None
223223
self.is_cratedb = True
224+
self.session_settings = session_settings or {}
224225

225226
async def _get_pool(self):
227+
228+
async def set_session_settings(conn):
229+
for setting, value in self.session_settings.items():
230+
await conn.execute(f'set {setting}={value}')
231+
226232
if not self._pool:
227233
self._pool = await asyncpg.create_pool(
228234
self.dsn,
229235
min_size=self.pool_size,
230-
max_size=self.pool_size
236+
max_size=self.pool_size,
237+
setup=set_session_settings
231238
)
232239
return self._pool
233240

@@ -308,7 +315,7 @@ def _append_sql(host):
308315

309316

310317
class HttpClient:
311-
def __init__(self, hosts, conn_pool_limit=25):
318+
def __init__(self, hosts, conn_pool_limit=25, session_settings=None):
312319
self.hosts = hosts
313320
self.urls = itertools.cycle(list(map(_append_sql, hosts)))
314321
self._connector_params = {
@@ -317,13 +324,21 @@ def __init__(self, hosts, conn_pool_limit=25):
317324
}
318325
self.__session = None
319326
self.is_cratedb = True
327+
self.session_settings = session_settings or {}
320328

321329
@property
322330
async def _session(self):
323331
session = self.__session
324332
if session is None:
325333
conn = aiohttp.TCPConnector(**self._connector_params)
326334
self.__session = session = aiohttp.ClientSession(connector=conn)
335+
for setting, value in self.session_settings.items():
336+
payload = {'stmt': f'set {setting}={value}'}
337+
await _exec(
338+
session,
339+
next(self.urls),
340+
dumps(payload, cls=CrateJsonEncoder)
341+
)
327342
return session
328343

329344
async def execute(self, stmt, args=None):
@@ -372,10 +387,10 @@ def __exit__(self, exc_type, exc_val, exc_tb):
372387
self.close()
373388

374389

375-
def client(hosts, concurrency=25):
390+
def client(hosts, session_settings=None, concurrency=25):
376391
hosts = hosts or 'localhost:4200'
377392
if hosts.startswith('asyncpg://'):
378393
if not asyncpg:
379394
raise ValueError('Cannot use "asyncpg" scheme if asyncpg is not available')
380-
return AsyncpgClient(hosts, pool_size=concurrency)
381-
return HttpClient(_to_http_hosts(hosts), conn_pool_limit=concurrency)
395+
return AsyncpgClient(hosts, pool_size=concurrency, session_settings=session_settings)
396+
return HttpClient(_to_http_hosts(hosts), conn_pool_limit=concurrency, session_settings=session_settings)

cr8/engine.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,9 @@ def _generate_statements(stmt, args, iterations, duration):
6969

7070

7171
class Runner:
72-
def __init__(self, hosts, concurrency, sample_mode):
72+
def __init__(self, hosts, concurrency, sample_mode, session_settings=None):
7373
self.concurrency = concurrency
74-
self.client = client(hosts, concurrency=concurrency)
74+
self.client = client(hosts, session_settings=session_settings, concurrency=concurrency)
7575
self.sampler = get_sampler(sample_mode)
7676

7777
def warmup(self, stmt, num_warmup, concurrency=0, args=None):

cr8/run_spec.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,13 @@ def __init__(self,
8181
result_hosts,
8282
log,
8383
fail_if,
84-
sample_mode):
84+
sample_mode,
85+
session_settings):
8586
self.benchmark_hosts = benchmark_hosts
8687
self.sample_mode = sample_mode
88+
self.session_settings = session_settings
8789
self.spec_dir = spec_dir
88-
self.client = clients.client(benchmark_hosts)
90+
self.client = clients.client(benchmark_hosts, session_settings)
8991
self.result_client = clients.client(result_hosts)
9092
self.server_version_info = aio.run(self.client.get_server_version)
9193
self.server_version = parse_version(self.server_version_info['number'])
@@ -204,7 +206,7 @@ def run_queries(self, queries: Iterable[dict], meta=None):
204206
f' Concurrency: {concurrency}\n'
205207
f' {mode_desc}: {duration or iterations}')
206208
)
207-
with Runner(self.benchmark_hosts, concurrency, self.sample_mode) as runner:
209+
with Runner(self.benchmark_hosts, concurrency, self.sample_mode, self.session_settings) as runner:
208210
if warmup > 0:
209211
runner.warmup(stmt, warmup, concurrency, args)
210212
timed_stats = runner.run(
@@ -242,15 +244,17 @@ def do_run_spec(spec,
242244
action=None,
243245
fail_if=None,
244246
re_name=None):
247+
spec_dir = os.path.dirname(spec)
248+
spec = load_spec(spec)
245249
with Executor(
246-
spec_dir=os.path.dirname(spec),
250+
spec_dir=spec_dir,
247251
benchmark_hosts=benchmark_hosts,
248252
result_hosts=result_hosts,
249253
log=log,
250254
fail_if=fail_if,
251-
sample_mode=sample_mode
255+
sample_mode=sample_mode,
256+
session_settings=spec.session_settings
252257
) as executor:
253-
spec = load_spec(spec)
254258
try:
255259
if not action or 'setup' in action:
256260
log.info('# Running setUp')

specs/count_countries.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414
}
1515
]
1616
},
17+
"session_settings": {
18+
"application_name": "my_app",
19+
"timezone": "UTC"
20+
},
1721
"queries": [{
1822
"iterations": 1000,
1923
"statement": "select count(*) from countries"

specs/sample.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
from itertools import count
32
from cr8.bench_spec import Spec, Instructions
43

@@ -21,4 +20,5 @@ def queries():
2120
setup=Instructions(statements=["create table t (x int)"]),
2221
teardown=Instructions(statements=["drop table t"]),
2322
queries=queries(),
24-
)
23+
session_settings={'application_name': 'my_app', 'timezone': 'UTC'}
24+
)

specs/sample.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ statement_files = ["sql/create_countries.sql"]
1414
target = "countries"
1515
cmd = ['echo', '{"capital": "Demo"}']
1616

17+
[session_settings]
18+
application_name = 'my_app'
19+
timezone = 'UTC'
20+
1721
[[queries]]
1822
name = "count countries" # Can be used to give the queries a name for easier analytics of the results
1923
statement = "select count(*) from countries"

tests/test_integration.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def parse(self, string, name='<string>'):
6363
class SourceBuildTest(TestCase):
6464

6565
def test_build_from_branch(self):
66-
self.assertIsNotNone(get_crate('4.1'))
66+
self.assertIsNotNone(get_crate('5.8'))
6767

6868

6969
def load_tests(loader, tests, ignore):

tests/test_spec.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import os
2+
from unittest import TestCase
3+
from doctest import DocTestSuite
4+
5+
from cr8.bench_spec import load_spec
6+
7+
from cr8 import engine
8+
9+
10+
class SpecTest(TestCase):
11+
12+
def test_session_settings_from_spec(self):
13+
spec = self.get_spec('sample.py')
14+
self.assertEqual(spec.session_settings, {'application_name': 'my_app', 'timezone': 'UTC'})
15+
16+
def test_session_settings_from_toml(self):
17+
spec = self.get_spec('sample.toml')
18+
self.assertEqual(spec.session_settings, {'application_name': 'my_app', 'timezone': 'UTC'})
19+
20+
def test_session_settings_from_json(self):
21+
spec = self.get_spec('count_countries.json')
22+
self.assertEqual(spec.session_settings, {'application_name': 'my_app', 'timezone': 'UTC'})
23+
24+
def get_spec(self, name):
25+
return load_spec(os.path.abspath(os.path.join(os.path.dirname(__file__), '../specs/', name)))
26+
27+
28+
def load_tests(loader, tests, ignore):
29+
tests.addTests(DocTestSuite(engine))
30+
return tests

0 commit comments

Comments
 (0)