From fe89aabe8f851e4b3621758bac35a9c816eed014 Mon Sep 17 00:00:00 2001 From: Georgiy Lebedev <g.lebedev@tarantool.org> Date: Thu, 17 Nov 2022 13:51:37 +0300 Subject: [PATCH] box: export IPROTO constants and features to Lua MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Export IPROTO constants and features to Lua: for now, simply copy-paste all constants from `src/box/iproto_{constants, features}.h` — it would be nice to generate them in the future (#7103). Closes #7894 @TarantoolBot document Title: export IPROTO constants and features to Lua or the API description and usage exmaples, see: * [design document](https://www.notion.so/tarantool/box-iproto-override-44935a6ac7e04fb5a2c81ca713ed1bce#dcaf854d2a9f4743ae25661c16528523); * tarantool/tarantool#7894. --- ...94-export-iproto-constants-and-features.md | 3 + src/box/CMakeLists.txt | 1 + src/box/iproto_constants.h | 18 +- src/box/iproto_features.h | 3 + src/box/lua/init.c | 2 + src/box/lua/iproto.c | 283 ++++++++++++++++++ src/box/lua/iproto.h | 20 ++ ...ort_iproto_constants_and_features_test.lua | 183 +++++++++++ test/box/misc.result | 1 + 9 files changed, 512 insertions(+), 2 deletions(-) create mode 100644 changelogs/unreleased/gh-7894-export-iproto-constants-and-features.md create mode 100644 src/box/lua/iproto.c create mode 100644 src/box/lua/iproto.h create mode 100644 test/box-luatest/gh_7894_export_iproto_constants_and_features_test.lua diff --git a/changelogs/unreleased/gh-7894-export-iproto-constants-and-features.md b/changelogs/unreleased/gh-7894-export-iproto-constants-and-features.md new file mode 100644 index 0000000000..860e026959 --- /dev/null +++ b/changelogs/unreleased/gh-7894-export-iproto-constants-and-features.md @@ -0,0 +1,3 @@ +## feature/box + +* Exported IPROTO constants and features to Lua (gh-7894). diff --git a/src/box/CMakeLists.txt b/src/box/CMakeLists.txt index a6ae7cbf2a..1900e46b7f 100644 --- a/src/box/CMakeLists.txt +++ b/src/box/CMakeLists.txt @@ -248,6 +248,7 @@ set(box_sources lua/key_def.c lua/merger.c lua/watcher.c + lua/iproto.c ${bin_sources}) if(ENABLE_AUDIT_LOG) diff --git a/src/box/iproto_constants.h b/src/box/iproto_constants.h index 3a9b61db58..685ef83ea9 100644 --- a/src/box/iproto_constants.h +++ b/src/box/iproto_constants.h @@ -49,7 +49,10 @@ enum { XLOG_FIXHEADER_SIZE = 19 }; -/** IPROTO_FLAGS bitfield constants. */ +/** + * IPROTO_FLAGS bitfield constants. + * `box.iproto.flag` needs to be updated correspondingly. + */ enum { /** Set for the last xrow in a transaction. */ IPROTO_FLAG_COMMIT = 0x01, @@ -59,6 +62,9 @@ enum { IPROTO_FLAG_WAIT_ACK = 0x04, }; +/** + * `box.iproto.key` needs to be updated correspondingly. + */ enum iproto_key { IPROTO_REQUEST_TYPE = 0x00, IPROTO_SYNC = 0x01, @@ -179,6 +185,7 @@ enum iproto_key { * Keys, stored in IPROTO_METADATA. They can not be received * in a request. Only sent as response, so no necessity in _strs * or _key_type arrays. + * `box.iproto.metadata_key` needs to be updated correspondingly. */ enum iproto_metadata_key { IPROTO_FIELD_NAME = 0, @@ -189,6 +196,9 @@ enum iproto_metadata_key { IPROTO_FIELD_SPAN = 5, }; +/** + * `box.iproto.ballot_key` needs to be updated correspondingly. + */ enum iproto_ballot_key { IPROTO_BALLOT_IS_RO_CFG = 0x01, IPROTO_BALLOT_VCLOCK = 0x02, @@ -208,7 +218,8 @@ iproto_key_bit(unsigned char key) extern const unsigned char iproto_key_type[IPROTO_KEY_MAX]; /** - * IPROTO command codes + * IPROTO command codes. + * `box.iproto.type` needs to be updated correspondingly. */ enum iproto_type { /** Acknowledgement that request or command is successful */ @@ -320,6 +331,9 @@ enum iproto_type { /** IPROTO type name by code */ extern const char *iproto_type_strs[]; +/** + * `box.iproto.raft_key` needs to be updated correspondingly. + */ enum iproto_raft_keys { IPROTO_RAFT_TERM = 0, IPROTO_RAFT_VOTE = 1, diff --git a/src/box/iproto_features.h b/src/box/iproto_features.h index 797cdad529..4cb65b3418 100644 --- a/src/box/iproto_features.h +++ b/src/box/iproto_features.h @@ -17,6 +17,8 @@ extern "C" { /** * IPROTO protocol feature ids returned by the IPROTO_ID command. + * `box.iproto.protocol_features` and `box.iproto.feature` need to be updated + * correspondingly. */ enum iproto_feature_id { /** @@ -64,6 +66,7 @@ struct iproto_features { /** * Current IPROTO protocol version returned by the IPROTO_ID command. * It should be incremented every time a new feature is added or removed. + * `box.iproto.protocol_version` needs to be updated correspondingly. */ enum { IPROTO_CURRENT_VERSION = 4, diff --git a/src/box/lua/init.c b/src/box/lua/init.c index df9ab58a3a..2a484b848f 100644 --- a/src/box/lua/init.c +++ b/src/box/lua/init.c @@ -68,6 +68,7 @@ #include "box/lua/key_def.h" #include "box/lua/merger.h" #include "box/lua/watcher.h" +#include "box/lua/iproto.h" #include "mpstream/mpstream.h" @@ -529,6 +530,7 @@ box_lua_init(struct lua_State *L) box_lua_xlog_init(L); box_lua_sql_init(L); box_lua_watcher_init(L); + box_lua_iproto_init(L); #ifdef ENABLE_SPACE_UPGRADE box_lua_space_upgrade_init(L); #endif diff --git a/src/box/lua/iproto.c b/src/box/lua/iproto.c new file mode 100644 index 0000000000..fca5dd03d0 --- /dev/null +++ b/src/box/lua/iproto.c @@ -0,0 +1,283 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright 2010-2022, Tarantool AUTHORS, please see AUTHORS file. + */ + +#include "box/lua/iproto.h" + +#include "box/iproto_constants.h" +#include "box/iproto_features.h" + +#include <lua.h> + +/** + * IPROTO constant from `src/box/iproto_{constants, features}.h`. + */ +struct iproto_constant { + /** + * Constant literal, name of constant. + */ + const char *const name; + /** + * Constant literal, value of constant. + */ + const lua_Integer val; +}; + +/** + * Pushes an array of IPROTO constants onto Lua stack. + */ +static void +push_iproto_constant_subnamespace(struct lua_State *L, const char *subnamespace, + const struct iproto_constant *constants, + int constants_len) +{ + lua_createtable(L, 0, constants_len); + for (int i = 0; i < constants_len; ++i) { + lua_pushinteger(L, constants[i].val); + lua_setfield(L, -2, constants[i].name); + } + lua_setfield(L, -2, subnamespace); +} + +/** + * Pushes IPROTO constants related to `IPROTO_FLAG` key onto Lua stack. + */ +static void +push_iproto_flag_constants(struct lua_State *L) +{ + const struct iproto_constant flags[] = { + {"COMMIT", IPROTO_FLAG_COMMIT}, + {"WAIT_SYNC", IPROTO_FLAG_WAIT_SYNC}, + {"WAIT_ACK", IPROTO_FLAG_WAIT_ACK}, + }; + push_iproto_constant_subnamespace(L, "flag", flags, lengthof(flags)); +} + +/** + * Pushes IPROTO constants from `iproto_key` enumeration onto Lua stack. + */ +static void +push_iproto_key_enum(struct lua_State *L) +{ + const struct iproto_constant keys[] = { + {"REQUEST_TYPE", IPROTO_REQUEST_TYPE}, + {"SYNC", IPROTO_SYNC}, + {"REPLICA_ID", IPROTO_REPLICA_ID}, + {"LSN", IPROTO_LSN}, + {"TIMESTAMP", IPROTO_TIMESTAMP}, + {"SCHEMA_VERSION", IPROTO_SCHEMA_VERSION}, + {"SERVER_VERSION", IPROTO_SERVER_VERSION}, + {"GROUP_ID", IPROTO_GROUP_ID}, + {"TSN", IPROTO_TSN}, + {"FLAGS", IPROTO_FLAGS}, + {"STREAM_ID", IPROTO_STREAM_ID}, + {"SPACE_ID", IPROTO_SPACE_ID}, + {"INDEX_ID", IPROTO_INDEX_ID}, + {"LIMIT", IPROTO_LIMIT}, + {"OFFSET", IPROTO_OFFSET}, + {"ITERATOR", IPROTO_ITERATOR}, + {"INDEX_BASE", IPROTO_INDEX_BASE}, + {"FETCH_POSITION", IPROTO_FETCH_POSITION}, + {"KEY", IPROTO_KEY}, + {"TUPLE", IPROTO_TUPLE}, + {"FUNCTION_NAME", IPROTO_FUNCTION_NAME}, + {"USER_NAME", IPROTO_USER_NAME}, + {"INSTANCE_UUID", IPROTO_INSTANCE_UUID}, + {"CLUSTER_UUID", IPROTO_CLUSTER_UUID}, + {"VCLOCK", IPROTO_VCLOCK}, + {"EXPR", IPROTO_EXPR}, + {"OPS", IPROTO_OPS}, + {"BALLOT", IPROTO_BALLOT}, + {"TUPLE_META", IPROTO_TUPLE_META}, + {"OPTIONS", IPROTO_OPTIONS}, + {"OLD_TUPLE", IPROTO_OLD_TUPLE}, + {"NEW_TUPLE", IPROTO_NEW_TUPLE}, + {"IPROTO_AFTER_POSITION", IPROTO_AFTER_POSITION}, + {"IPROTO_AFTER_TUPLE", IPROTO_AFTER_TUPLE}, + {"DATA", IPROTO_DATA}, + {"ERROR_24", IPROTO_ERROR_24}, + {"METADATA", IPROTO_METADATA}, + {"BIND_METADATA", IPROTO_BIND_METADATA}, + {"BIND_COUNT", IPROTO_BIND_COUNT}, + {"IPROTO_POSITION", IPROTO_POSITION}, + {"SQL_TEXT", IPROTO_SQL_TEXT}, + {"SQL_BIND", IPROTO_SQL_BIND}, + {"SQL_INFO", IPROTO_SQL_INFO}, + {"STMT_ID", IPROTO_STMT_ID}, + {"REPLICA_ANON", IPROTO_REPLICA_ANON}, + {"ID_FILTER", IPROTO_ID_FILTER}, + {"ERROR", IPROTO_ERROR}, + {"TERM", IPROTO_TERM}, + {"VERSION", IPROTO_VERSION}, + {"FEATURES", IPROTO_FEATURES}, + {"TIMEOUT", IPROTO_TIMEOUT}, + {"EVENT_KEY", IPROTO_EVENT_KEY}, + {"EVENT_DATA", IPROTO_EVENT_DATA}, + {"TXN_ISOLATION", IPROTO_TXN_ISOLATION}, + {"VCLOCK_SYNC", IPROTO_VCLOCK_SYNC}, + }; + push_iproto_constant_subnamespace(L, "key", keys, lengthof(keys)); +} + +/** + * Pushes IPROTO constants from `iproto_metadata_key` enumeration onto Lua + * stack. + */ +static void +push_iproto_metadata_key_enum(struct lua_State *L) +{ + const struct iproto_constant metadata_keys[] = { + {"NAME", IPROTO_FIELD_NAME}, + {"TYPE", IPROTO_FIELD_TYPE}, + {"COLL", IPROTO_FIELD_COLL}, + {"IS_NULLABLE", IPROTO_FIELD_IS_NULLABLE}, + {"IS_AUTOINCREMENT", IPROTO_FIELD_IS_AUTOINCREMENT}, + {"SPAN", IPROTO_FIELD_SPAN}, + }; + push_iproto_constant_subnamespace(L, "metadata_key", metadata_keys, + lengthof(metadata_keys)); +} + +/** + * Pushes IPROTO constants from `iproto_ballot_key` enumeration onto Lua stack. + */ +static void +push_iproto_ballot_key_enum(struct lua_State *L) +{ + const struct iproto_constant ballot_keys[] = { + {"IS_RO_CFG", IPROTO_BALLOT_IS_RO_CFG}, + {"VCLOCK", IPROTO_BALLOT_VCLOCK}, + {"GC_VCLOCK", IPROTO_BALLOT_GC_VCLOCK}, + {"IS_RO", IPROTO_BALLOT_IS_RO}, + {"IS_ANON", IPROTO_BALLOT_IS_ANON}, + {"IS_BOOTED", IPROTO_BALLOT_IS_BOOTED}, + {"CAN_LEAD", IPROTO_BALLOT_CAN_LEAD}, + }; + push_iproto_constant_subnamespace(L, "ballot_key", ballot_keys, + lengthof(ballot_keys)); +} + +/** + * Pushes IPROTO constants from `iproto_type` enumeration onto Lua stack. + */ +static void +push_iproto_type_enum(struct lua_State *L) +{ + const struct iproto_constant types[] = { + {"OK", IPROTO_OK}, + {"SELECT", IPROTO_SELECT}, + {"INSERT", IPROTO_INSERT}, + {"REPLACE", IPROTO_REPLACE}, + {"UPDATE", IPROTO_UPDATE}, + {"DELETE", IPROTO_DELETE}, + {"CALL_16", IPROTO_CALL_16}, + {"AUTH", IPROTO_AUTH}, + {"EVAL", IPROTO_EVAL}, + {"UPSERT", IPROTO_UPSERT}, + {"CALL", IPROTO_CALL}, + {"EXECUTE", IPROTO_EXECUTE}, + {"NOP", IPROTO_NOP}, + {"PREPARE", IPROTO_PREPARE}, + {"BEGIN", IPROTO_BEGIN}, + {"COMMIT", IPROTO_COMMIT}, + {"ROLLBACK", IPROTO_ROLLBACK}, + {"RAFT", IPROTO_RAFT}, + {"RAFT_PROMOTE", IPROTO_RAFT_PROMOTE}, + {"RAFT_DEMOTE", IPROTO_RAFT_DEMOTE}, + {"RAFT_CONFIRM", IPROTO_RAFT_CONFIRM}, + {"RAFT_ROLLBACK", IPROTO_RAFT_ROLLBACK}, + {"PING", IPROTO_PING}, + {"JOIN", IPROTO_JOIN}, + {"SUBSCRIBE", IPROTO_SUBSCRIBE}, + {"VOTE_DEPRECATED", IPROTO_VOTE_DEPRECATED}, + {"VOTE", IPROTO_VOTE}, + {"FETCH_SNAPSHOT", IPROTO_FETCH_SNAPSHOT}, + {"REGISTER", IPROTO_REGISTER}, + {"JOIN_META", IPROTO_JOIN_META}, + {"JOIN_SNAPSHOT", IPROTO_JOIN_SNAPSHOT}, + {"ID", IPROTO_ID}, + {"WATCH", IPROTO_WATCH}, + {"UNWATCH", IPROTO_UNWATCH}, + {"EVENT", IPROTO_EVENT}, + {"CHUNK", IPROTO_CHUNK}, + {"TYPE_ERROR", IPROTO_TYPE_ERROR}, + }; + push_iproto_constant_subnamespace(L, "type", types, + lengthof(types)); +} + +/** + * Pushes IPROTO constants from `iproto_raft_keys` enumeration onto Lua stack. + */ +static void +push_iproto_raft_keys_enum(struct lua_State *L) +{ + const struct iproto_constant raft_keys[] = { + {"TERM", IPROTO_RAFT_TERM}, + {"VOTE", IPROTO_RAFT_VOTE}, + {"STATE", IPROTO_RAFT_STATE}, + {"VCLOCK", IPROTO_RAFT_VCLOCK}, + {"LEADER_ID", IPROTO_RAFT_LEADER_ID}, + {"IS_LEADER_SEEN", IPROTO_RAFT_IS_LEADER_SEEN}, + }; + push_iproto_constant_subnamespace(L, "raft_key", raft_keys, + lengthof(raft_keys)); +} + +/** + * Pushes IPROTO constants onto Lua stack. + */ +static void +push_iproto_constants(struct lua_State *L) +{ + push_iproto_flag_constants(L); + push_iproto_key_enum(L); + push_iproto_metadata_key_enum(L); + push_iproto_ballot_key_enum(L); + push_iproto_type_enum(L); + push_iproto_raft_keys_enum(L); +} + +/** + * Pushes IPROTO protocol features onto Lua stack. + */ +static void +push_iproto_protocol_features(struct lua_State *L) +{ + lua_pushinteger(L, IPROTO_CURRENT_VERSION); + lua_setfield(L, -2, "protocol_version"); + + const struct iproto_constant features[] = { + {"streams", IPROTO_FEATURE_STREAMS}, + {"transactions", IPROTO_FEATURE_TRANSACTIONS}, + {"error_extension", IPROTO_FEATURE_ERROR_EXTENSION}, + {"watchers", IPROTO_FEATURE_WATCHERS}, + {"pagination", IPROTO_FEATURE_PAGINATION}, + }; + + lua_createtable(L, 0, lengthof(features)); + for (size_t i = 0; i < lengthof(features); ++i) { + lua_pushboolean(L, true); + lua_setfield(L, -2, features[i].name); + } + lua_setfield(L, -2, "protocol_features"); + + push_iproto_constant_subnamespace(L, "feature", features, + lengthof(features)); +} + +/** + * Initializes module for working with Tarantool's network subsystem. + */ +void +box_lua_iproto_init(struct lua_State *L) +{ + lua_getfield(L, LUA_GLOBALSINDEX, "box"); + lua_newtable(L); + push_iproto_constants(L); + push_iproto_protocol_features(L); + lua_setfield(L, -2, "iproto"); + lua_pop(L, 1); +} diff --git a/src/box/lua/iproto.h b/src/box/lua/iproto.h new file mode 100644 index 0000000000..14a55e618a --- /dev/null +++ b/src/box/lua/iproto.h @@ -0,0 +1,20 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright 2010-2022, Tarantool AUTHORS, please see AUTHORS file. + */ + +#pragma once + +#if defined(__cplusplus) +extern "C" { +#endif /* defined(__cplusplus) */ + +struct lua_State; + +void +box_lua_iproto_init(struct lua_State *L); + +#if defined(__cplusplus) +} /* extern "C" */ +#endif /* defined(__cplusplus) */ 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 new file mode 100644 index 0000000000..6cd1ed8ecc --- /dev/null +++ b/test/box-luatest/gh_7894_export_iproto_constants_and_features_test.lua @@ -0,0 +1,183 @@ +local server = require('test.luatest_helpers.server') +local t = require('luatest') + +local g = t.group() + +g.before_all(function(cg) + cg.server = server:new{ + alias = 'dflt', + } + cg.server:start() +end) + +g.after_all(function(cg) + cg.server:drop() +end) + +local reference_table = { + -- `IPROTO_FLAGS` bitfield constants enumeration. + flag = { + COMMIT = 0x01, + WAIT_SYNC = 0x02, + WAIT_ACK = 0x04, + }, + + -- `iproto_key` enumeration. + key = { + REQUEST_TYPE = 0x00, + SYNC = 0x01, + REPLICA_ID = 0x02, + LSN = 0x03, + TIMESTAMP = 0x04, + SCHEMA_VERSION = 0x05, + SERVER_VERSION = 0x06, + GROUP_ID = 0x07, + TSN = 0x08, + FLAGS = 0x09, + STREAM_ID = 0x0a, + SPACE_ID = 0x10, + INDEX_ID = 0x11, + LIMIT = 0x12, + OFFSET = 0x13, + ITERATOR = 0x14, + INDEX_BASE = 0x15, + FETCH_POSITION = 0x1f, + KEY = 0x20, + TUPLE = 0x21, + FUNCTION_NAME = 0x22, + USER_NAME = 0x23, + INSTANCE_UUID = 0x24, + CLUSTER_UUID = 0x25, + VCLOCK = 0x26, + EXPR = 0x27, + OPS = 0x28, + BALLOT = 0x29, + TUPLE_META = 0x2a, + OPTIONS = 0x2b, + OLD_TUPLE = 0x2c, + NEW_TUPLE = 0x2d, + IPROTO_AFTER_POSITION = 0x2e, + IPROTO_AFTER_TUPLE = 0x2f, + DATA = 0x30, + ERROR_24 = 0x31, + METADATA = 0x32, + BIND_METADATA = 0x33, + BIND_COUNT = 0x34, + IPROTO_POSITION = 0x35, + SQL_TEXT = 0x40, + SQL_BIND = 0x41, + SQL_INFO = 0x42, + STMT_ID = 0x43, + REPLICA_ANON = 0x50, + ID_FILTER = 0x51, + ERROR = 0x52, + TERM = 0x53, + VERSION = 0x54, + FEATURES = 0x55, + TIMEOUT = 0x56, + EVENT_KEY = 0x57, + EVENT_DATA = 0x58, + TXN_ISOLATION = 0x59, + VCLOCK_SYNC = 0x5a, + }, + + -- `iproto_metadata_key` enumeration. + metadata_key = { + NAME = 0, + TYPE = 1, + COLL = 2, + IS_NULLABLE = 3, + IS_AUTOINCREMENT = 4, + SPAN = 5, + }, + + -- `iproto_ballot_key` enumeration. + ballot_key = { + IS_RO_CFG = 0x01, + VCLOCK = 0x02, + GC_VCLOCK = 0x03, + IS_RO = 0x04, + IS_ANON = 0x05, + IS_BOOTED = 0x06, + CAN_LEAD = 0x07, + }, + + -- `iproto_type` enumeration. + type = { + OK = 0, + SELECT = 1, + INSERT = 2, + REPLACE = 3, + UPDATE = 4, + DELETE = 5, + CALL_16 = 6, + AUTH = 7, + EVAL = 8, + UPSERT = 9, + CALL = 10, + EXECUTE = 11, + NOP = 12, + PREPARE = 13, + BEGIN = 14, + COMMIT = 15, + ROLLBACK = 16, + RAFT = 30, + RAFT_PROMOTE = 31, + RAFT_DEMOTE = 32, + RAFT_CONFIRM = 40, + RAFT_ROLLBACK = 41, + PING = 64, + JOIN = 65, + SUBSCRIBE = 66, + VOTE_DEPRECATED = 67, + VOTE = 68, + FETCH_SNAPSHOT = 69, + REGISTER = 70, + JOIN_META = 71, + JOIN_SNAPSHOT = 72, + ID = 73, + WATCH = 74, + UNWATCH = 75, + EVENT = 76, + CHUNK = 128, + TYPE_ERROR = bit.lshift(1, 15), + }, + + -- `iproto_raft_keys` enumeration + raft_key = { + TERM = 0, + VOTE = 1, + STATE = 2, + VCLOCK = 3, + LEADER_ID = 4, + IS_LEADER_SEEN = 5, + }, + + -- `IPROTO_CURRENT_VERSION` constant + protocol_version = 4, + + -- `feature_id` enumeration + protocol_features = { + streams = true, + transactions = true, + error_extension = true, + watchers = true, + pagination = true, + }, + feature = { + streams = 0, + transactions = 1, + error_extension = 2, + watchers = 3, + pagination = 4, + }, +} + +-- Checks that IPROTO constants and features are exported correctly. +g.test_iproto_constants_and_features_export = function(cg) + cg.server:exec(function(reference_table) + local t = require('luatest') + + t.assert_equals(box.iproto, reference_table) + end, {reference_table}) +end diff --git a/test/box/misc.result b/test/box/misc.result index f477458cff..46a892afb3 100644 --- a/test/box/misc.result +++ b/test/box/misc.result @@ -85,6 +85,7 @@ t - index - info - internal + - iproto - is_in_txn - lib - on_commit -- GitLab