]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | /* | |
4 | * Ceph - scalable distributed file system | |
5 | * | |
6 | * Copyright (C) 2016 Michael Sevilla <mikesevilla3@gmail.com> | |
7 | * | |
8 | * This is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public | |
10 | * License version 2.1, as published by the Free Software | |
11 | * Foundation. See file COPYING. | |
12 | * | |
13 | */ | |
14 | ||
15 | #include "mdstypes.h" | |
16 | #include "MDSRank.h" | |
17 | #include "Mantle.h" | |
18 | #include "msg/Messenger.h" | |
19 | #include "common/Clock.h" | |
20 | #include "CInode.h" | |
21 | ||
22 | #include <fstream> | |
23 | ||
24 | #define dout_context g_ceph_context | |
25 | #define dout_subsys ceph_subsys_mds_balancer | |
26 | #undef dout_prefix | |
27 | #define dout_prefix *_dout << "mds.mantle " | |
28 | #define mantle_dout(lvl) \ | |
29 | do {\ | |
30 | auto subsys = ceph_subsys_mds;\ | |
31 | if ((dout_context)->_conf->subsys.should_gather(ceph_subsys_mds_balancer, lvl)) {\ | |
32 | subsys = ceph_subsys_mds_balancer;\ | |
33 | }\ | |
34 | dout_impl(dout_context, subsys, lvl) dout_prefix | |
35 | ||
36 | #define mantle_dendl dendl; } while (0) | |
37 | ||
38 | ||
39 | static int dout_wrapper(lua_State *L) | |
40 | { | |
41 | int level = luaL_checkinteger(L, 1); | |
42 | lua_concat(L, lua_gettop(L)-1); | |
43 | mantle_dout(level) << lua_tostring(L, 2) << mantle_dendl; | |
44 | return 0; | |
45 | } | |
46 | ||
47 | int Mantle::balance(const std::string &script, | |
48 | mds_rank_t whoami, | |
49 | const std::vector<std::map<std::string, double>> &metrics, | |
50 | std::map<mds_rank_t, double> &my_targets) | |
51 | { | |
52 | lua_settop(L, 0); /* clear the stack */ | |
53 | ||
54 | /* load the balancer */ | |
55 | if (luaL_loadstring(L, script.c_str())) { | |
56 | mantle_dout(0) << "WARNING: mantle could not load balancer: " | |
57 | << lua_tostring(L, -1) << mantle_dendl; | |
58 | return -EINVAL; | |
59 | } | |
60 | ||
61 | /* tell the balancer which mds is making the decision */ | |
62 | lua_pushinteger(L, (lua_Integer)whoami); | |
63 | lua_setglobal(L, "whoami"); | |
64 | ||
65 | /* global mds metrics to hold all dictionaries */ | |
66 | lua_newtable(L); | |
67 | ||
68 | /* push name of mds (i) and its metrics onto Lua stack */ | |
69 | for (size_t i=0; i < metrics.size(); i++) { | |
70 | lua_newtable(L); | |
71 | ||
72 | /* push values into this mds's table; setfield assigns key/pops val */ | |
73 | for (const auto &it : metrics[i]) { | |
74 | lua_pushnumber(L, it.second); | |
75 | lua_setfield(L, -2, it.first.c_str()); | |
76 | } | |
77 | ||
78 | /* in global mds table at stack[-3], set k=stack[-1] to v=stack[-2] */ | |
79 | lua_seti(L, -2, i); | |
80 | } | |
81 | ||
82 | /* set the name of the global mds table */ | |
83 | lua_setglobal(L, "mds"); | |
84 | ||
85 | assert(lua_gettop(L) == 1); | |
86 | if (lua_pcall(L, 0, 1, 0) != LUA_OK) { | |
87 | mantle_dout(0) << "WARNING: mantle could not execute script: " | |
88 | << lua_tostring(L, -1) << mantle_dendl; | |
89 | return -EINVAL; | |
90 | } | |
91 | ||
92 | /* parse response by iterating over Lua stack */ | |
93 | if (lua_istable(L, -1) == 0) { | |
94 | mantle_dout(0) << "WARNING: mantle script returned a malformed response" << mantle_dendl; | |
95 | return -EINVAL; | |
96 | } | |
97 | ||
98 | /* fill in return value */ | |
99 | for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { | |
100 | if (!lua_isinteger(L, -2) || !lua_isnumber(L, -1)) { | |
101 | mantle_dout(0) << "WARNING: mantle script returned a malformed response" << mantle_dendl; | |
102 | return -EINVAL; | |
103 | } | |
104 | mds_rank_t rank(lua_tointeger(L, -2)); | |
105 | my_targets[rank] = lua_tonumber(L, -1); | |
106 | } | |
107 | ||
108 | return 0; | |
109 | } | |
110 | ||
111 | Mantle::Mantle (void) | |
112 | { | |
113 | /* build lua vm state */ | |
114 | L = luaL_newstate(); | |
115 | if (!L) { | |
116 | mantle_dout(0) << "WARNING: mantle could not load Lua state" << mantle_dendl; | |
117 | throw std::bad_alloc(); | |
118 | } | |
119 | ||
120 | /* balancer policies can use basic Lua functions */ | |
121 | luaopen_base(L); | |
122 | luaopen_coroutine(L); | |
123 | luaopen_string(L); | |
124 | luaopen_math(L); | |
125 | luaopen_table(L); | |
126 | luaopen_utf8(L); | |
127 | ||
128 | /* setup debugging */ | |
129 | lua_register(L, "BAL_LOG", dout_wrapper); | |
130 | } |