[PATCH v2 3/4] session: store vtab in struct session

Vladislav Shpilevoy v.shpilevoy at tarantool.org
Tue Dec 11 19:10:22 MSK 2018


Before the patch vtabs were stored in a global array
accessed by session.type when necessary. But it does
not allow to change session vtab without affecting
session type. This feature is necessary to be able to
outdate binary sessions whose socket is closed.

Outdated session will return errors from all its
methods.

Needed for #3859
---
 src/box/applier.cc    |  3 ++-
 src/box/iproto.cc     | 50 ++++++++++++++++++++++++++-----------------
 src/box/lua/console.c | 15 ++++++-------
 src/box/lua/session.c |  5 +++--
 src/box/session.cc    | 19 ++++++----------
 src/box/session.h     | 25 ++++++++++++++--------
 6 files changed, 63 insertions(+), 54 deletions(-)

diff --git a/src/box/applier.cc b/src/box/applier.cc
index 4b5b851e6..1d9327d42 100644
--- a/src/box/applier.cc
+++ b/src/box/applier.cc
@@ -587,7 +587,8 @@ applier_f(va_list ap)
 	 * Set correct session type for use in on_replace()
 	 * triggers.
 	 */
-	if (session_create_on_demand(SESSION_TYPE_APPLIER) == NULL) {
+	if (session_create_on_demand(SESSION_TYPE_APPLIER,
+				     &generic_session_vtab) == NULL) {
 		diag_log();
 		return -1;
 	}
diff --git a/src/box/iproto.cc b/src/box/iproto.cc
index 03066dd59..e6eefc3d8 100644
--- a/src/box/iproto.cc
+++ b/src/box/iproto.cc
@@ -1747,6 +1747,32 @@ net_end_subscribe(struct cmsg *m)
 	iproto_connection_close(con);
 }
 
+static int
+iproto_session_fd(struct session *session);
+
+static int64_t
+iproto_session_sync(struct session *session);
+
+/**
+ * Push a message from @a port to a remote client.
+ * @param session iproto session.
+ * @param sync Request sync in scope of which to send the push.
+ * @param port Port with data to send.
+ *
+ * @retval -1 Memory error.
+ * @retval  0 Success, a message is written to the output buffer.
+ *            We don't wait here that the push has reached the
+ *            client: the output buffer is flushed asynchronously.
+ */
+static int
+iproto_session_push(struct session *session, uint64_t sync, struct port *port);
+
+static const struct session_vtab iproto_session_vtab = {
+	/* .push = */ iproto_session_push,
+	/* .fd = */ iproto_session_fd,
+	/* .sync = */ iproto_session_sync,
+};
+
 /**
  * Handshake a connection: invoke the on-connect trigger
  * and possibly authenticate. Try to send the client an error
@@ -1759,7 +1785,8 @@ tx_process_connect(struct cmsg *m)
 	struct iproto_connection *con = msg->connection;
 	struct obuf *out = msg->connection->tx.p_obuf;
 	try {              /* connect. */
-		con->session = session_create(SESSION_TYPE_BINARY);
+		con->session = session_create(SESSION_TYPE_BINARY,
+					      &iproto_session_vtab);
 		if (con->session == NULL)
 			diag_raise();
 		con->session->meta.connection = con;
@@ -1905,7 +1932,7 @@ net_cord_f(va_list /* ap */)
 	return 0;
 }
 
-int
+static int
 iproto_session_fd(struct session *session)
 {
 	struct iproto_connection *con =
@@ -1913,7 +1940,7 @@ iproto_session_fd(struct session *session)
 	return con->output.fd;
 }
 
-int64_t
+static int64_t
 iproto_session_sync(struct session *session)
 {
 	(void) session;
@@ -1962,17 +1989,6 @@ tx_end_push(struct cmsg *m)
 		tx_begin_push(con);
 }
 
-/**
- * Push a message from @a port to a remote client.
- * @param session iproto session.
- * @param sync Request sync in scope of which to send the push.
- * @param port Port with data to send.
- *
- * @retval -1 Memory error.
- * @retval  0 Success, a message is written to the output buffer.
- *            We don't wait here that the push has reached the
- *            client: the output buffer is flushed asynchronously.
- */
 static int
 iproto_session_push(struct session *session, uint64_t sync, struct port *port)
 {
@@ -2007,12 +2023,6 @@ iproto_init()
 	/* Create a pipe to "net" thread. */
 	cpipe_create(&net_pipe, "net");
 	cpipe_set_max_input(&net_pipe, iproto_msg_max / 2);
-	struct session_vtab iproto_session_vtab = {
-		/* .push = */ iproto_session_push,
-		/* .fd = */ iproto_session_fd,
-		/* .sync = */ iproto_session_sync,
-	};
-	session_vtab_registry[SESSION_TYPE_BINARY] = iproto_session_vtab;
 }
 
 /** Available iproto configuration changes. */
diff --git a/src/box/lua/console.c b/src/box/lua/console.c
index 085aedfaf..ef29ffc53 100644
--- a/src/box/lua/console.c
+++ b/src/box/lua/console.c
@@ -414,8 +414,6 @@ static int
 console_session_push(struct session *session, uint64_t sync, struct port *port)
 {
 	(void) sync;
-	assert(session_vtab_registry[session->type].push ==
-	       console_session_push);
 	uint32_t text_len;
 	const char *text = port_dump_plain(port, &text_len);
 	if (text == NULL)
@@ -424,6 +422,12 @@ console_session_push(struct session *session, uint64_t sync, struct port *port)
 				     TIMEOUT_INFINITY);
 }
 
+const struct session_vtab console_session_vtab = {
+	/* .push = */ console_session_push,
+	/* .fd = */ console_session_fd,
+	/* .sync = */ generic_session_sync,
+};
+
 void
 tarantool_lua_console_init(struct lua_State *L)
 {
@@ -457,13 +461,6 @@ tarantool_lua_console_init(struct lua_State *L)
 	 * load_history work the same way.
 	 */
 	lua_setfield(L, -2, "formatter");
-	struct session_vtab console_session_vtab = {
-		/* .push = */ console_session_push,
-		/* .fd = */ console_session_fd,
-		/* .sync = */ generic_session_sync,
-	};
-	session_vtab_registry[SESSION_TYPE_CONSOLE] = console_session_vtab;
-	session_vtab_registry[SESSION_TYPE_REPL] = console_session_vtab;
 }
 
 /*
diff --git a/src/box/lua/session.c b/src/box/lua/session.c
index 51582f749..ba45ef62b 100644
--- a/src/box/lua/session.c
+++ b/src/box/lua/session.c
@@ -44,6 +44,7 @@
 #include "box/port.h"
 
 static const char *sessionlib_name = "box.session";
+extern const struct session_vtab console_session_vtab;
 
 /* Create session and pin it to fiber */
 static int
@@ -51,12 +52,12 @@ lbox_session_create(struct lua_State *L, enum session_type type)
 {
 	struct session *session = fiber_get_session(fiber());
 	if (session == NULL) {
-		session = session_create_on_demand(type);
+		session = session_create_on_demand(type, &console_session_vtab);
 		if (session == NULL)
 			return luaT_error(L);
 		session->meta.fd = lua_tointeger(L, 1);
 	} else {
-		session_set_type(session, type);
+		session_set_type(session, type, &console_session_vtab);
 	}
 
 	lua_pushnumber(L, session->id);
diff --git a/src/box/session.cc b/src/box/session.cc
index 36da9ce69..216057921 100644
--- a/src/box/session.cc
+++ b/src/box/session.cc
@@ -45,20 +45,12 @@ const char *session_type_strs[] = {
 	"unknown",
 };
 
-static struct session_vtab generic_session_vtab = {
+const struct session_vtab generic_session_vtab = {
 	/* .push = */ generic_session_push,
 	/* .fd = */ generic_session_fd,
 	/* .sync = */ generic_session_sync,
 };
 
-struct session_vtab session_vtab_registry[] = {
-	/* BACKGROUND */ generic_session_vtab,
-	/* BINARY */ generic_session_vtab,
-	/* CONSOLE */ generic_session_vtab,
-	/* REPL */ generic_session_vtab,
-	/* APPLIER */ generic_session_vtab,
-};
-
 static struct mh_i64ptr_t *session_registry;
 
 uint32_t default_flags = 0;
@@ -93,7 +85,7 @@ session_on_stop(struct trigger *trigger, void * /* event */)
 }
 
 struct session *
-session_create(enum session_type type)
+session_create(enum session_type type, const struct session_vtab *vtab)
 {
 	struct session *session =
 		(struct session *) mempool_alloc(&session_pool);
@@ -105,7 +97,7 @@ session_create(enum session_type type)
 
 	session->id = sid_max();
 	memset(&session->meta, 0, sizeof(session->meta));
-	session_set_type(session, type);
+	session_set_type(session, type, vtab);
 	session->sql_flags = default_flags;
 	session->sql_default_engine = SQL_STORAGE_ENGINE_MEMTX;
 
@@ -127,12 +119,13 @@ session_create(enum session_type type)
 }
 
 struct session *
-session_create_on_demand(enum session_type type)
+session_create_on_demand(enum session_type type,
+			 const struct session_vtab *vtab)
 {
 	assert(fiber_get_session(fiber()) == NULL);
 
 	/* Create session on demand */
-	struct session *s = session_create(type);
+	struct session *s = session_create(type, vtab);
 	if (s == NULL)
 		return NULL;
 	s->fiber_on_stop = {
diff --git a/src/box/session.h b/src/box/session.h
index 45f0899b1..631d649e2 100644
--- a/src/box/session.h
+++ b/src/box/session.h
@@ -97,6 +97,8 @@ struct session {
 	/** SQL Connection flag for current user session */
 	uint32_t sql_flags;
 	enum session_type type;
+	/** Session virtual methods. */
+	const struct session_vtab *vtab;
 	/** Session metadata. */
 	union session_meta meta;
 	/** Session user id and global grants */
@@ -138,12 +140,14 @@ struct session_vtab {
 	(*sync)(struct session *session);
 };
 
-extern struct session_vtab session_vtab_registry[];
+extern const struct session_vtab generic_session_vtab;
 
 static inline void
-session_set_type(struct session *session, enum session_type new_type)
+session_set_type(struct session *session, enum session_type new_type,
+		 const struct session_vtab *vtab)
 {
 	session->type = new_type;
+	session->vtab = vtab;
 }
 
 /**
@@ -206,7 +210,8 @@ extern struct credentials admin_credentials;
  * trigger to destroy it when this fiber ends.
  */
 struct session *
-session_create_on_demand(enum session_type type);
+session_create_on_demand(enum session_type type,
+			 const struct session_vtab *vtab);
 
 /*
  * When creating a new fiber, the database (box)
@@ -223,7 +228,8 @@ current_session()
 {
 	struct session *session = fiber_get_session(fiber());
 	if (session == NULL) {
-		session = session_create_on_demand(SESSION_TYPE_BACKGROUND);
+		session = session_create_on_demand(SESSION_TYPE_BACKGROUND,
+						   &generic_session_vtab);
 		if (session == NULL)
 			diag_raise();
 	}
@@ -242,7 +248,8 @@ effective_user()
 	struct fiber *f = fiber();
 	struct credentials *u = f->storage.credentials;
 	if (u == NULL) {
-		session_create_on_demand(SESSION_TYPE_BACKGROUND);
+		session_create_on_demand(SESSION_TYPE_BACKGROUND,
+					 &generic_session_vtab);
 		u = f->storage.credentials;
 	}
 	return u;
@@ -266,7 +273,7 @@ session_storage_cleanup(int sid);
  * trigger fails or runs out of resources.
  */
 struct session *
-session_create(enum session_type type);
+session_create(enum session_type type, const struct session_vtab *vtab);
 
 /**
  * Destroy a session.
@@ -308,19 +315,19 @@ access_check_universe(user_access_t access);
 static inline int
 session_push(struct session *session, uint64_t sync, struct port *port)
 {
-	return session_vtab_registry[session->type].push(session, sync, port);
+	return session->vtab->push(session, sync, port);
 }
 
 static inline int
 session_fd(struct session *session)
 {
-	return session_vtab_registry[session->type].fd(session);
+	return session->vtab->fd(session);
 }
 
 static inline int
 session_sync(struct session *session)
 {
-	return session_vtab_registry[session->type].sync(session);
+	return session->vtab->sync(session);
 }
 
 /**
-- 
2.17.2 (Apple Git-113)




More information about the Tarantool-patches mailing list