From a5cc637f32a262c3ce5f84c064b4f88b15f2cf14 Mon Sep 17 00:00:00 2001
From: Dmitry Simonenko <pmwkaa@gmail.com>
Date: Thu, 3 Sep 2015 13:49:29 +0300
Subject: [PATCH] fix for #1004: sophia monitoring access

Work the same way as box.stat does.

Support access by index: box.sophia['compaction.page_size']
and by call box.sophia()
---
 src/box/CMakeLists.txt          |   1 +
 src/box/lua/call.cc             |   3 +-
 src/box/lua/info.cc             |  50 --------
 src/box/lua/info.h              |   1 -
 src/box/lua/sophia.cc           | 208 ++++++++++++++++++++++++++++++++
 src/box/lua/sophia.h            |  37 ++++++
 src/box/sophia_engine.cc        |  19 ++-
 src/box/sophia_engine.h         |   3 +-
 test/sophia/monitoring.result   |   2 +-
 test/sophia/monitoring.test.lua |   2 +-
 10 files changed, 267 insertions(+), 59 deletions(-)
 create mode 100644 src/box/lua/sophia.cc
 create mode 100644 src/box/lua/sophia.h

diff --git a/src/box/CMakeLists.txt b/src/box/CMakeLists.txt
index bcd9e17b4d..7c4d8a4bff 100644
--- a/src/box/CMakeLists.txt
+++ b/src/box/CMakeLists.txt
@@ -67,6 +67,7 @@ add_library(box
     lua/space.cc
     lua/info.cc
     lua/stat.cc
+    lua/sophia.cc
     lua/error.cc
     lua/session.cc
     lua/net_box.cc
diff --git a/src/box/lua/call.cc b/src/box/lua/call.cc
index 4d933247e2..9b9ed4ce76 100644
--- a/src/box/lua/call.cc
+++ b/src/box/lua/call.cc
@@ -36,6 +36,7 @@
 #include "box/lua/index.h"
 #include "box/lua/space.h"
 #include "box/lua/stat.h"
+#include "box/lua/sophia.h"
 #include "box/lua/info.h"
 #include "box/lua/session.h"
 #include "box/lua/net_box.h"
@@ -726,8 +727,8 @@ box_lua_init(struct lua_State *L)
 	box_lua_index_init(L);
 	box_lua_space_init(L);
 	box_lua_info_init(L);
-	box_lua_sophia_init(L);
 	box_lua_stat_init(L);
+	box_lua_sophia_init(L);
 	box_lua_session_init(L);
 
 	/* Load Lua extension */
diff --git a/src/box/lua/info.cc b/src/box/lua/info.cc
index d112e5a971..11b6cc1c6a 100644
--- a/src/box/lua/info.cc
+++ b/src/box/lua/info.cc
@@ -224,53 +224,3 @@ box_lua_info_init(struct lua_State *L)
 
 	lua_pop(L, 1); /* info module */
 }
-
-void sophia_info(void (*)(const char*, const char*, int, void*), void*);
-
-static void
-lbox_sophia_cb(const char *key, const char *value, int /* pos */, void *arg)
-{
-	struct lua_State *L;
-	L = (struct lua_State*)arg;
-	if (value == NULL)
-		return;
-	lua_pushstring(L, key);
-	lua_pushstring(L, value);
-	lua_settable(L, -3);
-}
-
-/**
- * When user invokes box.sophia(), return a table of key/value
- * pairs containing the current info.
- */
-static int
-lbox_sophia_call(struct lua_State *L)
-{
-	lua_newtable(L);
-	sophia_info(lbox_sophia_cb, (void*)L);
-	return 1;
-}
-
-/** Initialize box.sophia package. */
-void
-box_lua_sophia_init(struct lua_State *L)
-{
-	static const struct luaL_reg sophialib [] = {
-		{NULL, NULL}
-	};
-
-	luaL_register_module(L, "box.sophia", sophialib);
-
-	lua_newtable(L);
-
-	lua_pushstring(L, "__call");
-	lua_pushcfunction(L, lbox_sophia_call);
-	lua_settable(L, -3);
-
-	lua_pushstring(L, "__serialize");
-	lua_pushcfunction(L, lbox_sophia_call);
-	lua_settable(L, -3);
-
-	lua_setmetatable(L, -2);
-	lua_pop(L, 1);
-}
diff --git a/src/box/lua/info.h b/src/box/lua/info.h
index ab4695e81e..a6093f47a5 100644
--- a/src/box/lua/info.h
+++ b/src/box/lua/info.h
@@ -34,6 +34,5 @@
 
 struct lua_State;
 void box_lua_info_init(struct lua_State *L);
-void box_lua_sophia_init(struct lua_State *L);
 
 #endif /* INCLUDES_TARANTOOL_LUA_INFO_H */
diff --git a/src/box/lua/sophia.cc b/src/box/lua/sophia.cc
new file mode 100644
index 0000000000..de0083702f
--- /dev/null
+++ b/src/box/lua/sophia.cc
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2010-2015, Tarantool AUTHORS, please see AUTHORS file.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ *    copyright notice, this list of conditions and the
+ *    following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "sophia.h"
+
+extern "C" {
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+} /* extern "C" */
+
+#include "lua/utils.h"
+
+#if 0
+/**
+ * When user invokes box.sophia(), return a table of key/value
+ * pairs containing the current info.
+ */
+static int
+lbox_sophia_call(struct lua_State *L)
+{
+	lua_newtable(L);
+	sophia_info(lbox_sophia_cb, (void*)L);
+	return 1;
+}
+
+#if 0
+static int
+lbox_sophia_index(struct lua_State *L)
+{
+	lbox_sophia_call(L);
+	//lua_pushvalue(L, -2);
+	lua_gettable(L, -2);
+	return 1;
+}
+#endif
+
+/** Initialize box.sophia package. */
+void
+box_lua_sophia_init(struct lua_State *L)
+{
+	/*
+	static const struct luaL_reg sophialib [] = {
+		{NULL, NULL}
+	};
+	*/
+
+	//luaL_register_module(L, "box.sophia", sophialib);
+	lua_register(L, "box.sophia", lbox_sophia_call);
+
+	//lbox_sophia_call(L);
+
+	/*
+	lua_newtable(L);
+
+	lua_pushstring(L, "__index");
+	lua_pushcfunction(L, lbox_sophia_index);
+	lua_settable(L, -3);
+
+	lua_pushstring(L, "__serialize");
+	lua_pushcfunction(L, lbox_sophia_call);
+	lua_settable(L, -3);
+	*/
+
+	//lua_setmetatable(L, -2);
+	lua_pop(L, 1);
+}
+#endif
+
+#if 0
+static void
+fill_stat_item(struct lua_State *L, int rps, int64_t total)
+{
+	lua_pushstring(L, "rps");
+	lua_pushnumber(L, rps);
+	lua_settable(L, -3);
+
+	lua_pushstring(L, "total");
+	lua_pushnumber(L, total);
+	lua_settable(L, -3);
+}
+
+static int
+set_stat_item(const char *name, int rps, int64_t total, void *cb_ctx)
+{
+	struct lua_State *L = (struct lua_State *) cb_ctx;
+
+	lua_pushstring(L, name);
+	lua_newtable(L);
+
+	fill_stat_item(L, rps, total);
+
+	lua_settable(L, -3);
+
+	return 0;
+}
+
+/**
+ * A stat_foreach() callback used to handle access to e.g.
+ * box.stats.DELETE.
+ */
+static int
+seek_stat_item(const char *name, int rps, int64_t total, void *cb_ctx)
+{
+	struct lua_State *L = (struct lua_State *) cb_ctx;
+	if (strcmp(name, lua_tostring(L, -1)) != 0)
+		return 0;
+
+	lua_newtable(L);
+	fill_stat_item(L, rps, total);
+
+	return 1;
+}
+#endif
+
+typedef void (*sophia_info_f)(const char*, const char*, void*);
+
+int sophia_info(const char *name, sophia_info_f, void*);
+
+static void
+lbox_sophia_cb_index(const char* /* key */, const char *value, void *arg)
+{
+	struct lua_State *L;
+	L = (struct lua_State*)arg;
+	if (value == NULL) {
+		lua_pushnil(L);
+		return;
+	}
+	lua_pushstring(L, value);
+}
+
+static int
+lbox_sophia_index(struct lua_State *L)
+{
+	luaL_checkstring(L, -1);
+	const char *name = lua_tostring(L, -1);
+	return sophia_info(name, lbox_sophia_cb_index, (void*)L);
+}
+
+static void
+lbox_sophia_cb(const char *key, const char *value, void *arg)
+{
+	struct lua_State *L;
+	L = (struct lua_State*)arg;
+	if (value == NULL)
+		return;
+	lua_pushstring(L, key);
+	lua_pushstring(L, value);
+	lua_settable(L, -3);
+}
+
+static int
+lbox_sophia_call(struct lua_State *L)
+{
+	lua_newtable(L);
+	sophia_info(NULL, lbox_sophia_cb, (void*)L);
+	return 1;
+}
+
+static const struct luaL_reg lbox_sophia_meta [] = {
+	{"__index", lbox_sophia_index},
+	{"__call",  lbox_sophia_call},
+	{NULL, NULL}
+};
+
+void
+box_lua_sophia_init(struct lua_State *L)
+{
+	static const struct luaL_reg sophialib [] = {
+		{NULL, NULL}
+	};
+
+	luaL_register_module(L, "box.sophia", sophialib);
+
+	lua_newtable(L);
+	luaL_register(L, NULL, lbox_sophia_meta);
+	lua_setmetatable(L, -2);
+
+	lua_pop(L, 1); /* sophia module */
+}
diff --git a/src/box/lua/sophia.h b/src/box/lua/sophia.h
new file mode 100644
index 0000000000..165d1b312e
--- /dev/null
+++ b/src/box/lua/sophia.h
@@ -0,0 +1,37 @@
+#ifndef INCLUDES_TARANTOOL_LUA_SOPHIA_H
+#define INCLUDES_TARANTOOL_LUA_SOPHIA_H
+/*
+ * Copyright 2010-2015, Tarantool AUTHORS, please see AUTHORS file.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ *    copyright notice, this list of conditions and the
+ *    following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+struct lua_State;
+void box_lua_sophia_init(struct lua_State *L);
+
+#endif /* INCLUDES_TARANTOOL_LUA_SOPHIA_H */
diff --git a/src/box/sophia_engine.cc b/src/box/sophia_engine.cc
index 4f5c6ac868..a8a60c941e 100644
--- a/src/box/sophia_engine.cc
+++ b/src/box/sophia_engine.cc
@@ -62,19 +62,30 @@ void sophia_error(void *env)
 	tnt_raise(ClientError, ER_SOPHIA, msg);
 }
 
-void sophia_info(void (*cb)(const char*, const char*, int, void*), void *arg)
+int sophia_info(const char *name, sophia_info_f cb, void *arg)
 {
 	SophiaEngine *e = (SophiaEngine *)engine_find("sophia");
 	void *cursor = sp_getobject(e->env, NULL);
 	void *o = NULL;
-	int i = 0;
+	if (name) {
+		while ((o = sp_get(cursor, o))) {
+			char *key = (char *)sp_getstring(o, "key", 0);
+			if (name && strcmp(key, name) != 0)
+				continue;
+			char *value = (char *)sp_getstring(o, "value", 0);
+			cb(key, value, arg);
+			return 1;
+		}
+		sp_destroy(cursor);
+		return 0;
+	}
 	while ((o = sp_get(cursor, o))) {
 		char *key = (char *)sp_getstring(o, "key", 0);
 		char *value = (char *)sp_getstring(o, "value", 0);
-		cb(key, value, i, arg);
-		i++;
+		cb(key, value, arg);
 	}
 	sp_destroy(cursor);
+	return 0;
 }
 
 struct SophiaSpace: public Handler {
diff --git a/src/box/sophia_engine.h b/src/box/sophia_engine.h
index c9ffcaee88..4c7fd746f3 100644
--- a/src/box/sophia_engine.h
+++ b/src/box/sophia_engine.h
@@ -64,7 +64,8 @@ struct SophiaEngine: public Engine {
 	ev_idle idle;
 };
 
+typedef void (*sophia_info_f)(const char*, const char*, void*);
+int  sophia_info(const char*, sophia_info_f, void*);
 void sophia_error(void*);
-void sophia_info(void (*)(const char*, const char*, int, void*), void*);
 
 #endif /* TARANTOOL_BOX_SOPHIA_ENGINE_H_INCLUDED */
diff --git a/test/sophia/monitoring.result b/test/sophia/monitoring.result
index 1d5bac8d48..35f969269b 100644
--- a/test/sophia/monitoring.result
+++ b/test/sophia/monitoring.result
@@ -4,7 +4,7 @@ space = box.schema.space.create('test', { engine = 'sophia' })
 index = space:create_index('primary', { type = 'tree', parts = {1, 'str'} })
 ---
 ...
-box.sophia()['sophia.version']
+box.sophia['sophia.version']
 ---
 - 2.1.1
 ...
diff --git a/test/sophia/monitoring.test.lua b/test/sophia/monitoring.test.lua
index e15a49e8c4..e7e2647bfe 100644
--- a/test/sophia/monitoring.test.lua
+++ b/test/sophia/monitoring.test.lua
@@ -1,5 +1,5 @@
 
 space = box.schema.space.create('test', { engine = 'sophia' })
 index = space:create_index('primary', { type = 'tree', parts = {1, 'str'} })
-box.sophia()['sophia.version']
+box.sophia['sophia.version']
 space:drop()
-- 
GitLab