From 490a73edb676f624d93d13490d029e37b46cc9fc Mon Sep 17 00:00:00 2001
From: Konstantin Osipov <kostja@tarantool.org>
Date: Fri, 24 Apr 2015 15:36:54 +0300
Subject: [PATCH] gh-812: session.sync()

Provide access to iproto sync via session.sync() binding.

The value is valid only at start of a Lua call before the first yield,
after which it may be replaced with a sync from another request
running on the same session.
---
 src/box/iproto.cc         |  1 +
 src/box/lua/session.cc    | 13 +++++++++++++
 src/box/session.cc        |  1 +
 src/box/session.h         | 18 ++++++++++++++++--
 test/box/session.result   |  8 ++++++++
 test/box/session.test.lua |  2 ++
 6 files changed, 41 insertions(+), 2 deletions(-)

diff --git a/src/box/iproto.cc b/src/box/iproto.cc
index 809e534db6..a5db59fd98 100644
--- a/src/box/iproto.cc
+++ b/src/box/iproto.cc
@@ -653,6 +653,7 @@ iproto_process(struct iproto_request *ireq)
 	if (unlikely(! evio_is_active(&con->output)))
 		return;
 
+	ireq->session->sync = ireq->header.sync;
 	struct obuf_svp svp = obuf_create_svp(out);
 	try {
 		switch (ireq->header.type) {
diff --git a/src/box/lua/session.cc b/src/box/lua/session.cc
index 8571df7129..991f2205b5 100644
--- a/src/box/lua/session.cc
+++ b/src/box/lua/session.cc
@@ -60,6 +60,18 @@ lbox_session_id(struct lua_State *L)
 	return 1;
 }
 
+/**
+ * Return the id of currently executed request.
+ * Many requests share the same session so this is only
+ * valid at session start. 0 for non-iproto sessions.
+ */
+static int
+lbox_session_sync(struct lua_State *L)
+{
+	lua_pushnumber(L, current_session()->sync);
+	return 1;
+}
+
 /**
  * Session user id.
  * Note: effective user id (current_user()->uid)
@@ -249,6 +261,7 @@ box_lua_session_init(struct lua_State *L)
 {
 	static const struct luaL_reg sessionlib[] = {
 		{"id", lbox_session_id},
+		{"sync", lbox_session_sync},
 		{"uid", lbox_session_uid},
 		{"user", lbox_session_user},
 		{"su", lbox_session_su},
diff --git a/src/box/session.cc b/src/box/session.cc
index 840ef3a0f0..e694f7c854 100644
--- a/src/box/session.cc
+++ b/src/box/session.cc
@@ -76,6 +76,7 @@ session_create(int fd, uint64_t cookie)
 	session->id = sid_max();
 	session->fd =  fd;
 	session->cookie = cookie;
+	session->sync = 0;
 	/* For on_connect triggers. */
 	credentials_init(&session->credentials, guest_user);
 	if (fd >= 0)
diff --git a/src/box/session.h b/src/box/session.h
index e1720f51b6..09a9ea34a5 100644
--- a/src/box/session.h
+++ b/src/box/session.h
@@ -48,10 +48,24 @@ enum {	SESSION_SEED_SIZE = 32, SESSION_DELIM_SIZE = 16 };
 struct session {
 	/** Session id. */
 	uint32_t id;
-	/** File descriptor - socket of the connected peer. */
+	/** File descriptor - socket of the connected peer.
+	 * Only if the session has a peer.
+	 */
 	int fd;
-	/** Peer cookie - description of the peer. */
+	/**
+	 * Peer cookie - description of the peer.
+	 * Only if the session has a peer.
+	 */
 	uint64_t cookie;
+	/**
+	 * For iproto requests, we set this field
+	 * to the value of packet sync. Since the
+	 * session may be reused between many requests,
+	 * the value is true only at the beginning
+	 * of the request, and gets distorted after
+	 * the first yield.
+	 */
+	uint64_t sync;
 	/** Authentication salt. */
 	char salt[SESSION_SEED_SIZE];
 	/** Cached user id and global grants */
diff --git a/test/box/session.result b/test/box/session.result
index 1d254e10f7..dead886005 100644
--- a/test/box/session.result
+++ b/test/box/session.result
@@ -193,6 +193,10 @@ a:call('dostring', 'return space:get{session.id()}[1] == session.id()')[1][1]
 ---
 - true
 ...
+a:eval('return session.sync() ~= 0')
+---
+- true
+...
 a:close()
 ---
 ...
@@ -218,6 +222,10 @@ session.user()
 ---
 - admin
 ...
+session.sync()
+---
+- 0
+...
 fiber = nil
 ---
 ...
diff --git a/test/box/session.test.lua b/test/box/session.test.lua
index 3474dbb34c..56e5a0c350 100644
--- a/test/box/session.test.lua
+++ b/test/box/session.test.lua
@@ -75,6 +75,7 @@ session.on_disconnect(audit_disconnect)
 box.schema.user.grant('guest', 'read,write,execute', 'universe')
 a = net.box:new(LISTEN.host, LISTEN.service)
 a:call('dostring', 'return space:get{session.id()}[1] == session.id()')[1][1]
+a:eval('return session.sync() ~= 0')
 a:close()
 
 -- cleanup
@@ -86,6 +87,7 @@ space:drop()
 
 session.uid()
 session.user()
+session.sync()
 fiber = nil
 session = nil
 box.schema.user.revoke('guest', 'read,write,execute', 'universe')
-- 
GitLab