From 62c49367a2eab6d8008da2d7201ffa03e002c31e Mon Sep 17 00:00:00 2001 From: Nikita Zheleztsov <n.zheleztsov@proton.me> Date: Tue, 16 Jul 2024 18:56:56 +0300 Subject: [PATCH] iproto: introduce FETCH_SNAPSHOT_CURSOR feature This commit introduces FETCH_SNAPSHOT_CURSOR feature, which is available only in EE. The feature is not returned in response to IPROTO_ID and is not shown in box.iproto.protocol_features in Community Edition. Its id is shown only in box.iproto.feature, which is a list of all available features in the current version. Needed for tarantool/tarantool-ee#741 NO_CHANGELOG=minor @TarantoolBot document Title: Document iproto feature FETCH_SNAPSHOT_CURSOR Root document: https://www.tarantool.io/en/doc/latest/reference/reference_lua/net_box/#net-box-connect FETCH_SNAPSHOT_CURSOR feature requires cursor FETCH_SNAPSHOT on the server. Its ID is IPROTO_FEATURE_FETCH_SNAPSHOT_CURSOR. IPROTO version is 8 or more, Enterprise Edition is also required. --- src/box/box.cc | 1 + src/box/iproto.cc | 2 -- src/box/iproto_features.c | 4 ++++ src/box/iproto_features.h | 8 ++++++- src/box/lua/iproto.c | 6 +++-- src/box/lua/net_box.c | 2 +- ...ort_iproto_constants_and_features_test.lua | 9 ++++++- test/box-py/iproto.result | 6 ++--- test/box-py/iproto.test.py | 8 ++++++- test/box/net.box_iproto_id.result | 24 ++++++++++++------- test/box/net.box_iproto_id.test.lua | 16 +++++++++---- 11 files changed, 62 insertions(+), 24 deletions(-) diff --git a/src/box/box.cc b/src/box/box.cc index d2c5c18ab7..ff25901f88 100644 --- a/src/box/box.cc +++ b/src/box/box.cc @@ -6082,6 +6082,7 @@ void box_init(void) { iproto_constants_init(); + iproto_features_init(); port_init(); box_on_recovery_state_event = event_get("box.ctl.on_recovery_state", true); diff --git a/src/box/iproto.cc b/src/box/iproto.cc index 78c099a875..1cfac9e161 100644 --- a/src/box/iproto.cc +++ b/src/box/iproto.cc @@ -3851,8 +3851,6 @@ TRIGGER(trigger_on_change, trigger_on_change_iproto_notify); void iproto_init(int threads_count) { - iproto_features_init(); - iproto_threads_count = 0; struct session_vtab iproto_session_vtab = { /* .push = */ iproto_session_push, diff --git a/src/box/iproto_features.c b/src/box/iproto_features.c index 5ee3ad1668..821faed7b6 100644 --- a/src/box/iproto_features.c +++ b/src/box/iproto_features.c @@ -85,4 +85,8 @@ iproto_features_init(void) IPROTO_FEATURE_CALL_RET_TUPLE_EXTENSION); iproto_features_set(&IPROTO_CURRENT_FEATURES, IPROTO_FEATURE_CALL_ARG_TUPLE_EXTENSION); +#if defined(ENABLE_FETCH_SNAPSHOT_CURSOR) + iproto_features_set(&IPROTO_CURRENT_FEATURES, + IPROTO_FEATURE_FETCH_SNAPSHOT_CURSOR); +#endif /* defined(ENABLE_FETCH_SNAPSHOT_CURSOR) */ } diff --git a/src/box/iproto_features.h b/src/box/iproto_features.h index 8dcca26837..d8907d5f7b 100644 --- a/src/box/iproto_features.h +++ b/src/box/iproto_features.h @@ -77,6 +77,12 @@ extern "C" { * tuple formats are received in IPROTO_TUPLE_FORMATS field. */ \ _(CALL_ARG_TUPLE_EXTENSION, 9) \ + /** + * Cursor (for checkpoint join) in FETCH_SNAPSHOT support: + * IPROTO_IS_CHECKPOINT_JOIN, IPROTO_CHECKPOINT_VCLOCK and + * IRPOTO_CHECKPOINT_LSN. + */ \ + _(FETCH_SNAPSHOT_CURSOR, 10) \ #define IPROTO_FEATURE_MEMBER(s, v) IPROTO_FEATURE_ ## s = v, @@ -101,7 +107,7 @@ struct iproto_features { * `box.iproto.protocol_version` needs to be updated correspondingly. */ enum { - IPROTO_CURRENT_VERSION = 7, + IPROTO_CURRENT_VERSION = 8, }; /** diff --git a/src/box/lua/iproto.c b/src/box/lua/iproto.c index f8c5e4c3e8..aa2e61f7de 100644 --- a/src/box/lua/iproto.c +++ b/src/box/lua/iproto.c @@ -188,8 +188,10 @@ push_iproto_protocol_features(struct lua_State *L) lua_newtable(L); for (int i = 0; i < iproto_feature_id_MAX; i++) { char *name = strtolowerdup(iproto_feature_id_strs[i]); - lua_pushboolean(L, true); - lua_setfield(L, -2, name); + if (iproto_features_test(&IPROTO_CURRENT_FEATURES, i)) { + lua_pushboolean(L, true); + lua_setfield(L, -2, name); + } lua_pushinteger(L, i); lua_setfield(L, -3, name); free(name); diff --git a/src/box/lua/net_box.c b/src/box/lua/net_box.c index b84b01c15b..8efa41d200 100644 --- a/src/box/lua/net_box.c +++ b/src/box/lua/net_box.c @@ -82,7 +82,7 @@ enum { /** * IPROTO protocol version supported by the netbox connector. */ - NETBOX_IPROTO_VERSION = 7, + NETBOX_IPROTO_VERSION = 8, }; /** diff --git a/test/box-luatest/gh_7894_export_iproto_constants_and_features_test.lua b/test/box-luatest/gh_7894_export_iproto_constants_and_features_test.lua index b9c599258b..64c341ed2b 100644 --- a/test/box-luatest/gh_7894_export_iproto_constants_and_features_test.lua +++ b/test/box-luatest/gh_7894_export_iproto_constants_and_features_test.lua @@ -3,6 +3,8 @@ local t = require('luatest') local g = t.group() +local is_enterprise = t.tarantool.is_enterprise_package() + g.before_all(function(cg) cg.server = server:new{ alias = 'dflt', @@ -86,6 +88,9 @@ local reference_table = { INDEX_NAME = 0x5f, TUPLE_FORMATS = 0x60, IS_SYNC = 0x61, + IS_CHECKPOINT_JOIN = 0x62, + CHECKPOINT_VCLOCK = 0x63, + CHECKPOINT_LSN = 0x64, }, -- `iproto_metadata_key` enumeration. @@ -166,7 +171,7 @@ local reference_table = { }, -- `IPROTO_CURRENT_VERSION` constant - protocol_version = 7, + protocol_version = 8, -- `feature_id` enumeration protocol_features = { @@ -180,6 +185,7 @@ local reference_table = { dml_tuple_extension = true, call_ret_tuple_extension = true, call_arg_tuple_extension = true, + fetch_snapshot_cursor = is_enterprise and true or nil, }, feature = { streams = 0, @@ -192,6 +198,7 @@ local reference_table = { dml_tuple_extension = 7, call_ret_tuple_extension = 8, call_arg_tuple_extension = 9, + fetch_snapshot_cursor = 10, }, } diff --git a/test/box-py/iproto.result b/test/box-py/iproto.result index d8224563cd..edc6abc610 100644 --- a/test/box-py/iproto.result +++ b/test/box-py/iproto.result @@ -210,11 +210,11 @@ Invalid MsgPack - request body # Invalid auth_type Invalid MsgPack - request body # Empty request body -version=7, features=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], auth_type=chap-sha1 +version=8, features=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], auth_type=chap-sha1 # Unknown version and features -version=7, features=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], auth_type=chap-sha1 +version=8, features=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], auth_type=chap-sha1 # Unknown request key -version=7, features=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], auth_type=chap-sha1 +version=8, features=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], auth_type=chap-sha1 # # gh-6257 Watchers diff --git a/test/box-py/iproto.test.py b/test/box-py/iproto.test.py index 487e92c032..a661343970 100644 --- a/test/box-py/iproto.test.py +++ b/test/box-py/iproto.test.py @@ -490,8 +490,14 @@ print(""" """) def print_id_response(resp): if resp["header"][IPROTO_CODE] == REQUEST_TYPE_OK: + features = resp["body"][IPROTO_FEATURES] + # Some features are available only in EE, so remove them + # from the list of features so that diff test passes. + # IPROTO_FEATURES_FETCH_SNAPSHOT_CURSOR - 10. + if 10 in features: + features.remove(10) print("version={}, features={}, auth_type={}".format( - resp["body"][IPROTO_VERSION], resp["body"][IPROTO_FEATURES], + resp["body"][IPROTO_VERSION], features, resp["body"].get(IPROTO_AUTH_TYPE, "").decode("utf-8"))) else: print(str(resp["body"][IPROTO_ERROR].decode("utf-8"))) diff --git a/test/box/net.box_iproto_id.result b/test/box/net.box_iproto_id.result index 1f613a5150..94ea756fdc 100644 --- a/test/box/net.box_iproto_id.result +++ b/test/box/net.box_iproto_id.result @@ -9,15 +9,23 @@ errinj = box.error.injection | --- | ... +function print_features(conn) \ + local f = c.peer_protocol_features \ + f.fetch_snapshot_cursor = nil \ + return f \ +end + | --- + | ... + -- actual version and feautures c = net.connect(box.cfg.listen) | --- | ... c.peer_protocol_version | --- - | - 7 + | - 8 | ... -c.peer_protocol_features +print_features(c) | --- | - transactions: true | watchers: true @@ -50,7 +58,7 @@ c.peer_protocol_version | --- | - 0 | ... -c.peer_protocol_features +print_features(c) | --- | - transactions: false | watchers: false @@ -104,7 +112,7 @@ c.peer_protocol_version | --- | - 9000 | ... -c.peer_protocol_features +print_features(c) | --- | - transactions: true | watchers: true @@ -161,9 +169,9 @@ c.error -- error | ... c.peer_protocol_version | --- - | - 7 + | - 8 | ... -c.peer_protocol_features +print_features(c) | --- | - transactions: false | watchers: true @@ -193,9 +201,9 @@ c.error -- error | ... c.peer_protocol_version | --- - | - 7 + | - 8 | ... -c.peer_protocol_features +print_features(c) | --- | - transactions: true | watchers: true diff --git a/test/box/net.box_iproto_id.test.lua b/test/box/net.box_iproto_id.test.lua index a69ffd1a37..dc936fd41f 100644 --- a/test/box/net.box_iproto_id.test.lua +++ b/test/box/net.box_iproto_id.test.lua @@ -2,10 +2,16 @@ test_run = require('test_run').new() net = require('net.box') errinj = box.error.injection +function print_features(conn) \ + local f = c.peer_protocol_features \ + f.fetch_snapshot_cursor = nil \ + return f \ +end + -- actual version and feautures c = net.connect(box.cfg.listen) c.peer_protocol_version -c.peer_protocol_features +print_features(c) c:close() -- no IPROTO_ID => assume no features @@ -13,7 +19,7 @@ errinj.set('ERRINJ_IPROTO_DISABLE_ID', true) c = net.connect(box.cfg.listen) c.error -- none c.peer_protocol_version -c.peer_protocol_features +print_features(c) errinj.set('ERRINJ_IPROTO_DISABLE_ID', false) -- required version @@ -27,7 +33,7 @@ c:close() c = net.connect(box.cfg.listen, {required_protocol_version = 9001}) c.error -- error c.peer_protocol_version -c.peer_protocol_features +print_features(c) c:close() errinj.set('ERRINJ_IPROTO_SET_VERSION', -1) @@ -44,14 +50,14 @@ c = net.connect(box.cfg.listen, \ {required_protocol_features = {'streams', 'transactions'}}) c.error -- error c.peer_protocol_version -c.peer_protocol_features +print_features(c) c:close() errinj.set('ERRINJ_IPROTO_FLIP_FEATURE', -1) c = net.connect(box.cfg.listen, \ {required_protocol_features = {'foo', 'transactions', 'bar'}}) c.error -- error c.peer_protocol_version -c.peer_protocol_features +print_features(c) c:close() -- required features and version are checked on reconnect -- GitLab