Skip to content

Commit 56dc666

Browse files
committed
api: extend connect with fetch_schema param
Added support of the fetch_schema parameter, which allows to ignore schema changes on the server. Closes #219
1 parent f7e27a5 commit 56dc666

10 files changed

+294
-32
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,5 @@ test/data/*.key
5353
!test/data/localhost.enc.key
5454
test/data/*.pem
5555
test/data/*.srl
56+
57+
.rocks

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313
to decrypt private SSL key file (#224).
1414
- Support specifying authentication method with `auth_type`
1515
and Tarantool EE `pap-sha256` authentication method (#269).
16+
- Support of the fetch_schema parameter for connection (#219).
1617

1718
### Changed
1819

docs/source/quick-start.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ Through the :class:`~tarantool.Connection` object, you can access
359359
360360
>>> import tarantool
361361
>>> from tarantool.error import CrudModuleError, CrudModuleManyError, DatabaseError
362-
>>> conn = tarantool.Connection(host='localhost',port=3301)
362+
>>> conn = tarantool.Connection(host='localhost',port=3301,fetch_schema=False)
363363
364364
>>> conn.crud_
365365
conn.crud_count( conn.crud_insert( conn.crud_insert_object_many(

tarantool/connection.py

+58-10
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,8 @@ def __init__(self, host, port,
579579
ssl_password_file=DEFAULT_SSL_PASSWORD_FILE,
580580
packer_factory=default_packer_factory,
581581
unpacker_factory=default_unpacker_factory,
582-
auth_type=None):
582+
auth_type=None,
583+
fetch_schema=True):
583584
"""
584585
:param host: Server hostname or IP address. Use ``None`` for
585586
Unix sockets.
@@ -736,6 +737,18 @@ def __init__(self, host, port,
736737
``"chap-sha1"``.
737738
:type auth_type: :obj:`None` or :obj:`str`, optional
738739
740+
:param bool fetch_schema: If ``False``, allows to ignore schema
741+
changes on the server, schema updates are not automatically
742+
loaded. As a result, these methods become unavailable:
743+
:meth:`~tarantool.Connection.replace`,
744+
:meth:`~tarantool.Connection.insert`,
745+
:meth:`~tarantool.Connection.delete`,
746+
:meth:`~tarantool.Connection.upsert`,
747+
:meth:`~tarantool.Connection.update`,
748+
:meth:`~tarantool.Connection.select`,
749+
:meth:`~tarantool.Connection.space`.
750+
:type fetch_schema: :obj:`bool`, optional
751+
739752
:raise: :exc:`~tarantool.error.ConfigurationError`,
740753
:meth:`~tarantool.Connection.connect` exceptions
741754
@@ -766,6 +779,7 @@ def __init__(self, host, port,
766779
self.socket_timeout = socket_timeout
767780
self.reconnect_delay = reconnect_delay
768781
self.reconnect_max_attempts = reconnect_max_attempts
782+
self.fetch_schema = fetch_schema
769783
self.schema = Schema(self)
770784
self.schema_version = 1
771785
self._socket = None
@@ -1023,7 +1037,8 @@ def connect(self):
10231037
if self.transport == SSL_TRANSPORT:
10241038
self.wrap_socket_ssl()
10251039
self.handshake()
1026-
self.load_schema()
1040+
if self.fetch_schema:
1041+
self.load_schema()
10271042
except SslError as e:
10281043
raise e
10291044
except Exception as e:
@@ -1118,7 +1133,8 @@ def _send_request_wo_reconnect(self, request, on_push=None, on_push_ctx=None):
11181133
response = request.response_class(self, self._read_response())
11191134
break
11201135
except SchemaReloadException as e:
1121-
self.update_schema(e.schema_version)
1136+
if self.fetch_schema:
1137+
self.update_schema(e.schema_version)
11221138
continue
11231139

11241140
while response._code == IPROTO_CHUNK:
@@ -1269,6 +1285,18 @@ def flush_schema(self):
12691285
self.schema.flush()
12701286
self.load_schema()
12711287

1288+
def _fetch_schema_support_check(self):
1289+
"""
1290+
Checks the fetch_schema opt of the connection is enabled.
1291+
If the opt is disabled, an exception will be thrown
1292+
about unsupporting the method with fetch_schema=False.
1293+
1294+
:raise: :exc:`~tarantool.error.NotSupportedError`
1295+
"""
1296+
if not self.fetch_schema:
1297+
raise NotSupportedError('This method is not available in ' +
1298+
'connection opened with fetch_schema=False')
1299+
12721300
def call(self, func_name, *args, on_push=None, on_push_ctx=None):
12731301
"""
12741302
Execute a CALL request: call a stored Lua function.
@@ -1366,11 +1394,14 @@ def replace(self, space_name, values, on_push=None, on_push_ctx=None):
13661394
:exc:`~tarantool.error.DatabaseError`,
13671395
:exc:`~tarantool.error.SchemaError`,
13681396
:exc:`~tarantool.error.NetworkError`,
1369-
:exc:`~tarantool.error.SslError`
1397+
:exc:`~tarantool.error.SslError`,
1398+
:exc:`~tarantool.error.NotSupportedError`
13701399
13711400
.. _replace: https://www.tarantool.io/en/doc/latest/reference/reference_lua/box_space/replace/
13721401
"""
13731402

1403+
self._fetch_schema_support_check()
1404+
13741405
if isinstance(space_name, str):
13751406
space_name = self.schema.get_space(space_name).sid
13761407
if on_push is not None and not callable(on_push):
@@ -1411,7 +1442,7 @@ def authenticate(self, user, password):
14111442
password=self.password,
14121443
auth_type=self._get_auth_type())
14131444
auth_response = self._send_request_wo_reconnect(request)
1414-
if auth_response.return_code == 0:
1445+
if auth_response.return_code == 0 and self.fetch_schema:
14151446
self.flush_schema()
14161447
return auth_response
14171448

@@ -1584,11 +1615,14 @@ def insert(self, space_name, values, on_push=None, on_push_ctx=None):
15841615
:exc:`~tarantool.error.DatabaseError`,
15851616
:exc:`~tarantool.error.SchemaError`,
15861617
:exc:`~tarantool.error.NetworkError`,
1587-
:exc:`~tarantool.error.SslError`
1618+
:exc:`~tarantool.error.SslError`,
1619+
:exc:`~tarantool.error.NotSupportedError`
15881620
15891621
.. _insert: https://www.tarantool.io/en/doc/latest/reference/reference_lua/box_space/insert/
15901622
"""
15911623

1624+
self._fetch_schema_support_check()
1625+
15921626
if isinstance(space_name, str):
15931627
space_name = self.schema.get_space(space_name).sid
15941628
if on_push is not None and not callable(on_push):
@@ -1623,11 +1657,14 @@ def delete(self, space_name, key, *, index=0, on_push=None, on_push_ctx=None):
16231657
:exc:`~tarantool.error.DatabaseError`,
16241658
:exc:`~tarantool.error.SchemaError`,
16251659
:exc:`~tarantool.error.NetworkError`,
1626-
:exc:`~tarantool.error.SslError`
1660+
:exc:`~tarantool.error.SslError`,
1661+
:exc:`~tarantool.error.NotSupportedError`
16271662
16281663
.. _delete: https://www.tarantool.io/en/doc/latest/reference/reference_lua/box_space/delete/
16291664
"""
16301665

1666+
self._fetch_schema_support_check()
1667+
16311668
key = wrap_key(key)
16321669
if isinstance(space_name, str):
16331670
space_name = self.schema.get_space(space_name).sid
@@ -1682,11 +1719,14 @@ def upsert(self, space_name, tuple_value, op_list, *, index=0, on_push=None, on_
16821719
:exc:`~tarantool.error.DatabaseError`,
16831720
:exc:`~tarantool.error.SchemaError`,
16841721
:exc:`~tarantool.error.NetworkError`,
1685-
:exc:`~tarantool.error.SslError`
1722+
:exc:`~tarantool.error.SslError`,
1723+
:exc:`~tarantool.error.NotSupportedError`
16861724
16871725
.. _upsert: https://www.tarantool.io/en/doc/latest/reference/reference_lua/box_space/upsert/
16881726
"""
16891727

1728+
self._fetch_schema_support_check()
1729+
16901730
if isinstance(space_name, str):
16911731
space_name = self.schema.get_space(space_name).sid
16921732
if isinstance(index, str):
@@ -1770,11 +1810,14 @@ def update(self, space_name, key, op_list, *, index=0, on_push=None, on_push_ctx
17701810
:exc:`~tarantool.error.DatabaseError`,
17711811
:exc:`~tarantool.error.SchemaError`,
17721812
:exc:`~tarantool.error.NetworkError`,
1773-
:exc:`~tarantool.error.SslError`
1813+
:exc:`~tarantool.error.SslError`,
1814+
:exc:`~tarantool.error.NotSupportedError`
17741815
17751816
.. _update: https://www.tarantool.io/en/doc/latest/reference/reference_lua/box_space/update/
17761817
"""
17771818

1819+
self._fetch_schema_support_check()
1820+
17781821
key = wrap_key(key)
17791822
if isinstance(space_name, str):
17801823
space_name = self.schema.get_space(space_name).sid
@@ -1956,11 +1999,14 @@ def select(self, space_name, key=None, *, offset=0, limit=0xffffffff, index=0, i
19561999
:exc:`~tarantool.error.DatabaseError`,
19572000
:exc:`~tarantool.error.SchemaError`,
19582001
:exc:`~tarantool.error.NetworkError`,
1959-
:exc:`~tarantool.error.SslError`
2002+
:exc:`~tarantool.error.SslError`,
2003+
:exc:`~tarantool.error.NotSupportedError`
19602004
19612005
.. _select: https://www.tarantool.io/en/doc/latest/reference/reference_lua/box_space/select/
19622006
"""
19632007

2008+
self._fetch_schema_support_check()
2009+
19642010
if iterator is None:
19652011
iterator = ITERATOR_EQ
19662012
if key is None or (isinstance(key, (list, tuple)) and
@@ -1996,6 +2042,8 @@ def space(self, space_name):
19962042
:raise: :exc:`~tarantool.error.SchemaError`
19972043
"""
19982044

2045+
self._fetch_schema_support_check()
2046+
19992047
return Space(self, space_name)
20002048

20012049
def generate_sync(self):

tarantool/connection_pool.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,8 @@ def __init__(self,
378378
call_16=False,
379379
connection_timeout=CONNECTION_TIMEOUT,
380380
strategy_class=RoundRobinStrategy,
381-
refresh_delay=POOL_REFRESH_DELAY):
381+
refresh_delay=POOL_REFRESH_DELAY,
382+
fetch_schema=True):
382383
"""
383384
:param addrs: List of dictionaries describing server addresses:
384385
@@ -452,6 +453,9 @@ def __init__(self,
452453
`box.info.ro`_ status background refreshes, in seconds.
453454
:type connection_timeout: :obj:`float`, optional
454455
456+
:param fetch_schema: Refer to
457+
:paramref:`~tarantool.Connection.params.fetch_schema`.
458+
455459
:raise: :exc:`~tarantool.error.ConfigurationError`,
456460
:class:`~tarantool.Connection` exceptions
457461
@@ -500,7 +504,8 @@ def __init__(self,
500504
ssl_ciphers=addr['ssl_ciphers'],
501505
ssl_password=addr['ssl_password'],
502506
ssl_password_file=addr['ssl_password_file'],
503-
auth_type=addr['auth_type'])
507+
auth_type=addr['auth_type'],
508+
fetch_schema=fetch_schema)
504509
)
505510

506511
if connect_now:

tarantool/mesh_connection.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,8 @@ def __init__(self, host=None, port=None,
283283
addrs=None,
284284
strategy_class=RoundRobinStrategy,
285285
cluster_discovery_function=None,
286-
cluster_discovery_delay=CLUSTER_DISCOVERY_DELAY):
286+
cluster_discovery_delay=CLUSTER_DISCOVERY_DELAY,
287+
fetch_schema=True):
287288
"""
288289
:param host: Refer to
289290
:paramref:`~tarantool.Connection.params.host`.
@@ -425,6 +426,9 @@ def __init__(self, host=None, port=None,
425426
list refresh.
426427
:type cluster_discovery_delay: :obj:`float`, optional
427428
429+
:param fetch_schema: Refer to
430+
:paramref:`~tarantool.Connection.params.fetch_schema`.
431+
428432
:raises: :exc:`~tarantool.error.ConfigurationError`,
429433
:class:`~tarantool.Connection` exceptions,
430434
:class:`~tarantool.MeshConnection.connect` exceptions
@@ -489,7 +493,8 @@ def __init__(self, host=None, port=None,
489493
ssl_ciphers=addr['ssl_ciphers'],
490494
ssl_password=addr['ssl_password'],
491495
ssl_password_file=addr['ssl_password_file'],
492-
auth_type=addr['auth_type'])
496+
auth_type=addr['auth_type'],
497+
fetch_schema=fetch_schema)
493498

494499
def connect(self):
495500
"""

tarantool/request.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,13 @@ def header(self, length):
188188
"""
189189

190190
self._sync = self.conn.generate_sync()
191-
header = self._dumps({IPROTO_REQUEST_TYPE: self.request_type,
192-
IPROTO_SYNC: self._sync,
193-
IPROTO_SCHEMA_ID: self.conn.schema_version})
191+
header_fields = {
192+
IPROTO_REQUEST_TYPE: self.request_type,
193+
IPROTO_SYNC: self._sync,
194+
}
195+
if self.conn.fetch_schema:
196+
header_fields[IPROTO_SCHEMA_ID] = self.conn.schema_version
197+
header = self._dumps(header_fields)
194198

195199
return self._dumps(length + len(header)) + header
196200

test/suites/crud_server.lua

+2-4
Original file line numberDiff line numberDiff line change
@@ -71,17 +71,15 @@ box.schema.user.grant(
7171
)
7272

7373
if crud_imported == false or vshard_imported == false then
74+
-- Set flag for unittest.
75+
_G['ROCKS_IMPORT_FAIL'] = true
7476
local fail_msg = 'The crud/vshard modules are not detected, ' ..
7577
'installation via rocks install is required ' ..
7678
'for CRUD testing purposes. You can use ' ..
7779
'<tarantoolctl rocks install crud> or ' ..
7880
'<tt rocks install crud> to install modules'
7981
-- The print output will be captured in the logs.
8082
print(fail_msg)
81-
-- Because of the implementation of the testing framework,
82-
-- this will cause the crash of the CRUD test and display to user
83-
-- a message about require fail during instance configuration.
84-
box.info.status = fail_msg
8583
else
8684
configure_crud_instance(primary_listen, crud, vshard)
8785
end

test/suites/test_crud.py

+10-3
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,20 @@ def setUp(self):
3333
time.sleep(1)
3434
# Open connections to instance.
3535
self.conn = tarantool.Connection(host=self.host, port=self.port,
36-
user='guest', password='')
36+
user='guest', password='', fetch_schema=False)
3737
self.conn_mesh = tarantool.MeshConnection(host=self.host, port=self.port,
38-
user='guest', password='')
38+
user='guest', password='', fetch_schema=False)
3939
self.conn_pool = tarantool.ConnectionPool([{'host':self.host, 'port':self.port}],
40-
user='guest', password='')
40+
user='guest', password='',
41+
fetch_schema=False)
4142
# Time for vshard group configuration.
4243
time.sleep(1)
44+
if self.conn.eval('return ROCKS_IMPORT_FAIL').data[0] == True:
45+
raise unittest.SkipTest('The crud/vshard modules are not detected, ' +
46+
'installation via rocks install is required ' +
47+
'for CRUD testing purposes. You can use ' +
48+
'<tarantoolctl rocks install crud> or ' +
49+
'<tt rocks install crud> to install modules')
4350

4451
crud_test_cases = {
4552
'crud_insert': {

0 commit comments

Comments
 (0)