From d0ebca641773120c7574d5f67c51e9ae3a8d4185 Mon Sep 17 00:00:00 2001
From: Konstantin Osipov <kostja@tarantool.org>
Date: Mon, 17 Dec 2012 20:22:00 +0400
Subject: [PATCH] Provide a unique session identifier in fibers,
 box.fiber.sid().

---
 include/fiber.h       | 20 ++++++++++++++++++++
 include/tarantool.h   |  6 ++++++
 src/admin.m           |  1 +
 src/admin.rl          |  1 +
 src/box/box.m         |  8 ++++++++
 src/fiber.m           |  1 +
 src/iproto.m          |  5 +++++
 src/lua/init.m        | 13 +++++++++++++
 test/box/fiber.result | 21 +++++++++++++++++++++
 test/box/fiber.test   | 11 +++++++++++
 10 files changed, 87 insertions(+)

diff --git a/include/fiber.h b/include/fiber.h
index debae0dd54..1ef42904df 100644
--- a/include/fiber.h
+++ b/include/fiber.h
@@ -69,7 +69,18 @@ struct fiber {
 	struct tarantool_coro coro;
 	/* A garbage-collected memory pool. */
 	struct palloc_pool *gc_pool;
+	/** Fiber id. */
 	uint32_t fid;
+	/**
+	 * Session id of the session the fiber is running
+	 * on behalf of. The concept of an associated session
+	 * is similar to the concept of controlling tty
+	 * in a UNIX process. When a fiber is created,
+	 * its sid is 0. If it's running a request on behalf
+	 * of a user connection, it's sid is changed to module-
+	 * generated identifier of the session.
+	 */
+	uint32_t sid;
 
 	struct rlist link;
 	struct rlist state;
@@ -128,4 +139,13 @@ struct tbuf;
 void fiber_info(struct tbuf *out);
 void fiber_schedule(ev_watcher *watcher, int event __attribute__((unused)));
 
+/**
+ * Attach this fiber to a session identified by sid.
+ */
+static inline void
+fiber_set_sid(struct fiber *f, uint32_t sid)
+{
+	f->sid = sid;
+}
+
 #endif /* TARANTOOL_FIBER_H_INCLUDED */
diff --git a/include/tarantool.h b/include/tarantool.h
index 4fc14067f8..a24561673d 100644
--- a/include/tarantool.h
+++ b/include/tarantool.h
@@ -46,6 +46,12 @@ int mod_cat(const char *filename);
 void mod_snapshot(struct log_io *, struct fio_batch *batch);
 void mod_info(struct tbuf *out);
 const char *mod_status(void);
+/**
+ * Issue a new session identifier -
+ * called by the networking layer
+ * when a new connection is established.
+ */
+uint32_t mod_sid();
 
 extern int snapshot_pid;
 extern struct tarantool_cfg cfg;
diff --git a/src/admin.m b/src/admin.m
index 5b95ab7583..31c92d08ed 100644
--- a/src/admin.m
+++ b/src/admin.m
@@ -1888,6 +1888,7 @@ admin_handler(va_list ap)
 {
 	struct ev_io coio = va_arg(ap, struct ev_io);
 	struct iobuf *iobuf = va_arg(ap, struct iobuf *);
+	fiber_set_sid(fiber, mod_sid());
 	lua_State *L = lua_newthread(tarantool_L);
 	int coro_ref = luaL_ref(tarantool_L, LUA_REGISTRYINDEX);
 	@try {
diff --git a/src/admin.rl b/src/admin.rl
index efebc095a3..752a09a37e 100644
--- a/src/admin.rl
+++ b/src/admin.rl
@@ -329,6 +329,7 @@ admin_handler(va_list ap)
 {
 	struct ev_io coio = va_arg(ap, struct ev_io);
 	struct iobuf *iobuf = va_arg(ap, struct iobuf *);
+	fiber_set_sid(fiber, mod_sid());
 	lua_State *L = lua_newthread(tarantool_L);
 	int coro_ref = luaL_ref(tarantool_L, LUA_REGISTRYINDEX);
 	@try {
diff --git a/src/box/box.m b/src/box/box.m
index 8d6668944c..ffba2b7eb9 100644
--- a/src/box/box.m
+++ b/src/box/box.m
@@ -543,3 +543,11 @@ mod_status(void)
 {
     return status;
 }
+
+
+uint32_t
+mod_sid()
+{
+	static uint32_t sid = 1;
+	return sid++;
+}
diff --git a/src/fiber.m b/src/fiber.m
index 693203f443..6fd21fd7e8 100644
--- a/src/fiber.m
+++ b/src/fiber.m
@@ -429,6 +429,7 @@ fiber_create(const char *name, void (*f) (va_list))
 	if (++last_used_fid < 100)
 		last_used_fid = 100;
 	fiber->fid = last_used_fid;
+	fiber->sid = 0;
 	fiber->flags = 0;
 	fiber->waiter = NULL;
 	fiber_set_name(fiber, name);
diff --git a/src/iproto.m b/src/iproto.m
index 1e622ef106..bbaed4aaa8 100644
--- a/src/iproto.m
+++ b/src/iproto.m
@@ -32,6 +32,7 @@
 #include <stdarg.h>
 #include <stdio.h>
 
+#include "tarantool.h"
 #include "exception.h"
 #include "errcode.h"
 #include "fiber.h"
@@ -254,6 +255,8 @@ struct iproto_session
 	mod_process_func *handler;
 	struct ev_io input;
 	struct ev_io output;
+	/** Mod session id. */
+	uint32_t sid;
 };
 
 SLIST_HEAD(, iproto_session) iproto_session_cache =
@@ -297,6 +300,7 @@ iproto_session_create(const char *name, int fd, mod_process_func *param)
 	session->iobuf[1] = iobuf_create(name);
 	session->parse_size = 0;
 	session->write_pos = obuf_create_svp(&session->iobuf[0]->out);
+	session->sid = mod_sid();
 	return session;
 }
 
@@ -618,6 +622,7 @@ restart:
 			continue;
 		}
 		@try {
+			fiber_set_sid(fiber, session->sid);
 			iproto_reply(&port, *session->handler, &iobuf->out, header);
 		} @finally {
 			iobuf->in.pos += sizeof(*header) + header->len;
diff --git a/src/lua/init.m b/src/lua/init.m
index 527c67ce98..50b56c3a69 100644
--- a/src/lua/init.m
+++ b/src/lua/init.m
@@ -568,6 +568,14 @@ lbox_fiber_id(struct lua_State *L)
 	return 1;
 }
 
+static int
+lbox_fiber_sid(struct lua_State *L)
+{
+	struct fiber *f = lua_gettop(L) ? lbox_checkfiber(L, 1) : fiber;
+	lua_pushinteger(L, f->sid);
+	return 1;
+}
+
 static struct lua_State *
 box_lua_fiber_get_coro(struct lua_State *L, struct fiber *f)
 {
@@ -680,6 +688,8 @@ lbox_fiber_detach(struct lua_State *L)
 	/* Clear the caller, to avoid a reference leak. */
 	/* Request a detach. */
 	lua_pushinteger(L, DETACH);
+	/* A detached fiber has no associated session. */
+	fiber_set_sid(fiber, 0);
 	fiber_yield_to(caller);
 	return 0;
 }
@@ -788,6 +798,7 @@ lbox_fiber_create(struct lua_State *L)
 			   " reached");
 
 	struct fiber *f = fiber_create("lua", box_lua_fiber_run);
+	fiber_set_sid(f, fiber->sid);
 	/* Initially the fiber is cancellable */
 	f->flags |= FIBER_USER_MODE | FIBER_CANCELLABLE;
 
@@ -1037,6 +1048,7 @@ lbox_fiber_testcancel(struct lua_State *L)
 
 static const struct luaL_reg lbox_fiber_meta [] = {
 	{"id", lbox_fiber_id},
+	{"sid", lbox_fiber_sid},
 	{"name", lbox_fiber_name},
 	{"__gc", lbox_fiber_gc},
 	{NULL, NULL}
@@ -1046,6 +1058,7 @@ static const struct luaL_reg fiberlib[] = {
 	{"sleep", lbox_fiber_sleep},
 	{"self", lbox_fiber_self},
 	{"id", lbox_fiber_id},
+	{"sid", lbox_fiber_sid},
 	{"find", lbox_fiber_find},
 	{"cancel", lbox_fiber_cancel},
 	{"testcancel", lbox_fiber_testcancel},
diff --git a/test/box/fiber.result b/test/box/fiber.result
index b44c7713d2..efe9afecf3 100644
--- a/test/box/fiber.result
+++ b/test/box/fiber.result
@@ -201,3 +201,24 @@ lua box.fiber.find(920)
 lua box.space[0]:truncate()
 ---
 ...
+lua box.fiber.sid() > 0
+---
+ - true
+...
+lua f = box.fiber.create(function() box.fiber.detach() failed = box.fiber.sid() ~= 0 end)
+---
+...
+lua box.fiber.resume(f)
+---
+...
+lua failed
+---
+ - false
+...
+lua f = box.fiber.create(function() if box.fiber.sid() == 0 then error('wrong sid') end end)
+---
+...
+lua box.fiber.resume(f)
+---
+ - true
+...
diff --git a/test/box/fiber.test b/test/box/fiber.test
index bdd160e8fa..ff6b2e9f79 100644
--- a/test/box/fiber.test
+++ b/test/box/fiber.test
@@ -1,4 +1,5 @@
 # encoding: tarantool
+import sys
 # A test case for a race condition between ev_schedule
 # and wal_schedule fiber schedulers. 
 # The same fiber should not be scheduled by ev_schedule (e.g. 
@@ -79,3 +80,13 @@ exec admin "lua box.fiber.find(900)"
 exec admin "lua box.fiber.find(910)"
 exec admin "lua box.fiber.find(920)"
 exec admin "lua box.space[0]:truncate()"
+
+# check fiber.sid() and fiber.id()
+exec admin "lua box.fiber.sid() > 0"
+exec admin "lua f = box.fiber.create(function() box.fiber.detach() failed = box.fiber.sid() ~= 0 end)"
+exec admin "lua box.fiber.resume(f)"
+exec admin "lua failed"
+exec admin "lua f = box.fiber.create(function() if box.fiber.sid() == 0 then error('wrong sid') end end)"
+exec admin "lua box.fiber.resume(f)"
+
+
-- 
GitLab