* [Tarantool-patches] [PATCH] box.execute should be immutable function @ 2019-11-14 11:50 Maria 2019-11-14 16:51 ` Nikita Pettik 2019-12-17 14:39 ` Igor Munkin 0 siblings, 2 replies; 31+ messages in thread From: Maria @ 2019-11-14 11:50 UTC (permalink / raw) To: tarantool-patches, georgy Using box.execute method before explicitly configuring box automatically invoked box.cfg nonetheless. Any further calls to the latter caused its reconfiguration which could lead to an error when trying to use the method. Closes #4231 Issue: https://github.com/tarantool/tarantool/issues/4231 Branch: https://github.com/tarantool/tarantool/compare/eljashm/gh-4231-box.execute-immutable-function --- src/box/lua/load_cfg.lua | 4 +++- test/box-tap/execute.test.lua | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100755 test/box-tap/execute.test.lua diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua index e7f62cf4e..042edf913 100644 --- a/src/box/lua/load_cfg.lua +++ b/src/box/lua/load_cfg.lua @@ -528,7 +528,9 @@ box.cfg = locked(load_cfg) -- metatable. -- function box.execute(...) - load_cfg() + if not box.cfg then + load_cfg() + end return box.execute(...) end diff --git a/test/box-tap/execute.test.lua b/test/box-tap/execute.test.lua new file mode 100755 index 000000000..301cf4a1c --- /dev/null +++ b/test/box-tap/execute.test.lua @@ -0,0 +1,17 @@ +#!/usr/bin/env tarantool + +local tap = require('tap') +local test = tap.test('execute') +test:plan(1) + +local box_execute = box.execute +box.cfg{} + +local status, err = pcall( + function() + box_execute("CREATE TABLE t1 (s1 INTEGER, PRIMARY KEY (s1));") + end) + +test:ok(status and err == nil, "box.execute after box.cfg") +test:check() +os.exit(0) -- 2.21.0 (Apple Git-122.2) ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Tarantool-patches] [PATCH] box.execute should be immutable function 2019-11-14 11:50 [Tarantool-patches] [PATCH] box.execute should be immutable function Maria @ 2019-11-14 16:51 ` Nikita Pettik 2019-12-17 14:39 ` Igor Munkin 1 sibling, 0 replies; 31+ messages in thread From: Nikita Pettik @ 2019-11-14 16:51 UTC (permalink / raw) To: Maria; +Cc: tarantool-patches On 14 Nov 14:50, Maria wrote: > Using box.execute method before explicitly > configuring box automatically invoked box.cfg > nonetheless. Any further calls to the latter > caused its reconfiguration which could lead > to an error when trying to use the method. Hello. I'm not going to comment patch iteself, just want to leave a couple of general nits. They are just recommendations. Feel free to use up to 72 characters while making up commit's body. I'd fix commit subject: box.execute should be immutable -> box: make box.execute() immutable despite box.cfg{} (or sort of). > Closes #4231 > Issue: > https://github.com/tarantool/tarantool/issues/4231 > Branch: > https://github.com/tarantool/tarantool/compare/eljashm/gh-4231-box.execute-immutable-function Please, put links under --- delimiter so that it will be ignored by git am. > --- > src/box/lua/load_cfg.lua | 4 +++- > test/box-tap/execute.test.lua | 17 +++++++++++++++++ > 2 files changed, 20 insertions(+), 1 deletion(-) > create mode 100755 test/box-tap/execute.test.lua > > diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua > index e7f62cf4e..042edf913 100644 > --- a/src/box/lua/load_cfg.lua > +++ b/src/box/lua/load_cfg.lua > @@ -528,7 +528,9 @@ box.cfg = locked(load_cfg) > -- metatable. > -- > function box.execute(...) > - load_cfg() > + if not box.cfg then > + load_cfg() > + end > return box.execute(...) > end > > diff --git a/test/box-tap/execute.test.lua b/test/box-tap/execute.test.lua > new file mode 100755 > index 000000000..301cf4a1c > --- /dev/null > +++ b/test/box-tap/execute.test.lua I'd better name this test ..box-tap/gh-4231-immutable-execute-func.test.lua It is generally accepted naming way. > @@ -0,0 +1,17 @@ > +#!/usr/bin/env tarantool > + > +local tap = require('tap') > +local test = tap.test('execute') > +test:plan(1) Please, leave comment explaining what exactly is tested here. For instance: -- Make sure that box.execute() method does not change after -- the very first box.cfg{} invokation. -- > + > +local box_execute = box.execute > +box.cfg{} > + > +local status, err = pcall( > + function() > + box_execute("CREATE TABLE t1 (s1 INTEGER, PRIMARY KEY (s1));") > + end) > + > +test:ok(status and err == nil, "box.execute after box.cfg") I guess this should be error message which is displayed in case test fails. If so, I'd rather use message like: "box.execute() is changed after box.cfg{} invokation" ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Tarantool-patches] [PATCH] box.execute should be immutable function 2019-11-14 11:50 [Tarantool-patches] [PATCH] box.execute should be immutable function Maria 2019-11-14 16:51 ` Nikita Pettik @ 2019-12-17 14:39 ` Igor Munkin 2019-12-24 15:32 ` [Tarantool-patches] [PATCH] box: make box.execute() immutable Maria Khaydich 1 sibling, 1 reply; 31+ messages in thread From: Igor Munkin @ 2019-12-17 14:39 UTC (permalink / raw) To: Maria; +Cc: tarantool-patches Masha, Thanks for the patch! I join to all remarks left by Nikita. Besides, I added a couple new below related to the patch itself. On 14.11.19, Maria wrote: > Using box.execute method before explicitly > configuring box automatically invoked box.cfg > nonetheless. Any further calls to the latter > caused its reconfiguration which could lead > to an error when trying to use the method. > > Closes #4231 > Issue: > https://github.com/tarantool/tarantool/issues/4231 > Branch: > https://github.com/tarantool/tarantool/compare/eljashm/gh-4231-box.execute-immutable-function > --- > src/box/lua/load_cfg.lua | 4 +++- > test/box-tap/execute.test.lua | 17 +++++++++++++++++ > 2 files changed, 20 insertions(+), 1 deletion(-) > create mode 100755 test/box-tap/execute.test.lua > > diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua > index e7f62cf4e..042edf913 100644 > --- a/src/box/lua/load_cfg.lua > +++ b/src/box/lua/load_cfg.lua > @@ -528,7 +528,9 @@ box.cfg = locked(load_cfg) > -- metatable. > -- > function box.execute(...) > - load_cfg() I had to read a lot of source code to dive into the problem to be fixed. It's OK, but IMHO it would be great if you dropped a few words right here about the bug and mentioned the related issue. This would definitely simplify further maintenance. > + if not box.cfg then This condition solves the reported problem (the test you provided within this patch is OK), but consider the following: | $ git lo -1 | ec09fcaac <snipped> box.execute should be immutable function | $ ./tarantool -V | Tarantool 2.3.0-161-gec09fcaac | <snipped> | $ echo 'box.execute("SELECT 1")' | timeout -s 9 3 ./tarantool | Killed Thus box.execute call prior to box.cfg invokation hangs Tarantool after your patch. I'm totally not into SQL design but AFAIS such box.execute invokation ought to call loag_cfg underneath. However it doesn't since box.cfg is initialized with function several lines above, the check is failed and Tarantool goes into deep recursion. I guess you can introduce a local flag and use it as an upvalue in both box.execute and load_cfg functions. The flag is to be initialized to false, set in the load_cfg call and check within box.execute. However feel free to provide your own solution. > + load_cfg() > + end > return box.execute(...) > end > > diff --git a/test/box-tap/execute.test.lua b/test/box-tap/execute.test.lua > new file mode 100755 > index 000000000..301cf4a1c > --- /dev/null > +++ b/test/box-tap/execute.test.lua > @@ -0,0 +1,17 @@ > +#!/usr/bin/env tarantool > + > +local tap = require('tap') > +local test = tap.test('execute') > +test:plan(1) > + > +local box_execute = box.execute Please consider to add the check related to the flaw found above. > +box.cfg{} > + > +local status, err = pcall( > + function() > + box_execute("CREATE TABLE t1 (s1 INTEGER, PRIMARY KEY (s1));") Minor: A trailing whitespace is left above. > + end) There is a common code style for pcall an anonymous multiline Lua function within box-tap (see [1] and [2]). Please adjust yours considering it. > + > +test:ok(status and err == nil, "box.execute after box.cfg") Please consider the comment regarding the test finalization[3]. > +test:check() > +os.exit(0) > -- > 2.21.0 (Apple Git-122.2) > [1]: https://github.com/tarantool/tarantool/blob/master/test/box-tap/cfg.test.lua#L148 [2]: https://github.com/tarantool/tarantool/blob/master/test/box-tap/merger.test.lua#L573 [3]: https://github.com/tarantool/tarantool/issues/4655#issue-529430689 -- Best regards, IM ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Tarantool-patches] [PATCH] box: make box.execute() immutable 2019-12-17 14:39 ` Igor Munkin @ 2019-12-24 15:32 ` Maria Khaydich 2019-12-25 1:30 ` Igor Munkin 2019-12-26 14:08 ` Alexander Turenko 0 siblings, 2 replies; 31+ messages in thread From: Maria Khaydich @ 2019-12-24 15:32 UTC (permalink / raw) To: Igor Munkin; +Cc: tarantool-patches, Vladislav Shpilevoy [-- Attachment #1: Type: text/plain, Size: 6776 bytes --] Igor, thank you for the review! Proposed fixes are done: Using box.execute method before explicitly configuring box automatically invoked box.cfg nonetheless. Any further calls to box.cfg caused its reconfiguration which then led to an error when trying to use execute method again. The patch introduces a fix making box.execute method immutable. Closes #4231 --- Issue: https://github.com/tarantool/tarantool/issues/4231 Branch: https://github.com/tarantool/tarantool/compare/eljashm/gh-4231-box.execute-immutable-function src/box/lua/load_cfg.lua | 15 +++++++++++- .../gh-4231_immutable_box.execute.test.lua | 24 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 test/box-tap/gh-4231_immutable_box.execute.test.lua diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua index e7f62cf4e..ad416e578 100644 --- a/src/box/lua/load_cfg.lua +++ b/src/box/lua/load_cfg.lua @@ -481,10 +481,14 @@ setmetatable(box, { end }) +-- Flag needed to keep immutable functions after box reconfiguration +local box_loaded = false + local function load_cfg(cfg) cfg = upgrade_cfg(cfg, translate_cfg) cfg = prepare_cfg(cfg, default_cfg, template_cfg, modify_cfg) apply_default_cfg(cfg, default_cfg); + box_loaded = true -- Save new box.cfg box.cfg = cfg if not pcall(private.cfg_check) then @@ -528,7 +532,16 @@ box.cfg = locked(load_cfg) -- metatable. -- function box.execute(...) - load_cfg() + -- + -- Calling box.execute before explicitly configuring box led to + -- automatic box.cfg invocation nonetheless. Following explicit + -- attempts to configure box led to its reconfiguratin and as a + -- result - to an error when trying to use execute method again. + -- The check makes sure box.execute is an immutable function. + -- + if not box_loaded then + load_cfg() + end return box.execute(...) end diff --git a/test/box-tap/gh-4231_immutable_box.execute.test.lua b/test/box-tap/gh-4231_immutable_box.execute.test.lua new file mode 100644 index 000000000..e2469630e --- /dev/null +++ b/test/box-tap/gh-4231_immutable_box.execute.test.lua @@ -0,0 +1,24 @@ +#!/usr/bin/env tarantool +local tap = require('tap') +local test = tap.test('execute') +test:plan(2) + +-- +-- gh-4231: box.execute should be immutable function meaning it doesn't +-- change after first box.cfg implicit invocation +-- + +local box_execute = box.execute +local status, err = pcall(function() + box_execute("SELECT 1") +end) +test:ok(status and err == nil, "box.execute does not work properly before box.cfg") + +box.cfg{} + +local status2, err2 = pcall(function() + box_execute("CREATE TABLE t1 (s1 INTEGER, PRIMARY KEY (s1));") +end) +test:ok(status2 and err2 == nil, "box.execute is changed after box.cfg invocation") + +os.exit(test:check() and 0 or 1) -- 2.24.0 >Вторник, 17 декабря 2019, 17:41 +03:00 от Igor Munkin <imun@tarantool.org>: > >Masha, > >Thanks for the patch! I join to all remarks left by Nikita. Besides, I >added a couple new below related to the patch itself. > >On 14.11.19, Maria wrote: >> Using box.execute method before explicitly >> configuring box automatically invoked box.cfg >> nonetheless. Any further calls to the latter >> caused its reconfiguration which could lead >> to an error when trying to use the method. >> >> Closes #4231 >> Issue: >> https://github.com/tarantool/tarantool/issues/4231 >> Branch: >> https://github.com/tarantool/tarantool/compare/eljashm/gh-4231-box.execute-immutable-function >> --- >> src/box/lua/load_cfg.lua | 4 +++- >> test/box-tap/execute.test.lua | 17 +++++++++++++++++ >> 2 files changed, 20 insertions(+), 1 deletion(-) >> create mode 100755 test/box-tap/execute.test.lua >> >> diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua >> index e7f62cf4e..042edf913 100644 >> --- a/src/box/lua/load_cfg.lua >> +++ b/src/box/lua/load_cfg.lua >> @@ -528,7 +528,9 @@ box.cfg = locked(load_cfg) >> -- metatable. >> -- >> function box.execute(...) >> - load_cfg() > >I had to read a lot of source code to dive into the problem to be fixed. >It's OK, but IMHO it would be great if you dropped a few words right >here about the bug and mentioned the related issue. This would >definitely simplify further maintenance. > >> + if not box.cfg then > >This condition solves the reported problem (the test you provided within >this patch is OK), but consider the following: >| $ git lo -1 >| ec09fcaac <snipped> box.execute should be immutable function >| $ ./tarantool -V >| Tarantool 2.3.0-161-gec09fcaac >| <snipped> >| $ echo 'box.execute("SELECT 1")' | timeout -s 9 3 ./tarantool >| Killed >Thus box.execute call prior to box.cfg invokation hangs Tarantool after >your patch. I'm totally not into SQL design but AFAIS such box.execute >invokation ought to call loag_cfg underneath. However it doesn't since >box.cfg is initialized with function several lines above, the check is >failed and Tarantool goes into deep recursion. > >I guess you can introduce a local flag and use it as an upvalue in both >box.execute and load_cfg functions. The flag is to be initialized to >false, set in the load_cfg call and check within box.execute. However >feel free to provide your own solution. > >> + load_cfg() >> + end >> return box.execute(...) >> end >> >> diff --git a/test/box-tap/execute.test.lua b/test/box-tap/execute.test.lua >> new file mode 100755 >> index 000000000..301cf4a1c >> --- /dev/null >> +++ b/test/box-tap/execute.test.lua >> @@ -0,0 +1,17 @@ >> +#!/usr/bin/env tarantool >> + >> +local tap = require('tap') >> +local test = tap.test('execute') >> +test:plan(1) >> + >> +local box_execute = box.execute > >Please consider to add the check related to the flaw found above. > >> +box.cfg{} >> + >> +local status, err = pcall( >> + function() >> + box_execute("CREATE TABLE t1 (s1 INTEGER, PRIMARY KEY (s1));") > >Minor: A trailing whitespace is left above. > >> + end) > >There is a common code style for pcall an anonymous multiline Lua >function within box-tap (see [1] and [2]). Please adjust yours >considering it. > >> + >> +test:ok(status and err == nil, "box.execute after box.cfg") > >Please consider the comment regarding the test finalization[3]. > >> +test:check() >> +os.exit(0) >> -- >> 2.21.0 (Apple Git-122.2) >> > >[1]: https://github.com/tarantool/tarantool/blob/master/test/box-tap/cfg.test.lua#L148 >[2]: https://github.com/tarantool/tarantool/blob/master/test/box-tap/merger.test.lua#L573 >[3]: https://github.com/tarantool/tarantool/issues/4655#issue-529430689 > >-- >Best regards, >IM -- Maria Khaydich [-- Attachment #2: Type: text/html, Size: 9110 bytes --] ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Tarantool-patches] [PATCH] box: make box.execute() immutable 2019-12-24 15:32 ` [Tarantool-patches] [PATCH] box: make box.execute() immutable Maria Khaydich @ 2019-12-25 1:30 ` Igor Munkin 2019-12-26 14:08 ` Alexander Turenko 1 sibling, 0 replies; 31+ messages in thread From: Igor Munkin @ 2019-12-25 1:30 UTC (permalink / raw) To: Maria Khaydich; +Cc: tarantool-patches, Vladislav Shpilevoy Masha, Thanks for the patch! It LGTM in general, but please consider a couple polishing-aimed comments below. On 24.12.19, Maria Khaydich wrote: > Igor, thank you for the review! > Proposed fixes are done: > At first, please adjust the commit message subject considering our contribution guide[1]. I see the component prefix is missing. > > Using box.execute method before explicitly configuring box > automatically invoked box.cfg nonetheless. Any further calls > to box.cfg caused its reconfiguration which then led to an > error when trying to use execute method again. > > The patch introduces a fix making box.execute method immutable. > > Closes #4231 > --- > Issue: > https://github.com/tarantool/tarantool/issues/4231 > Branch: > https://github.com/tarantool/tarantool/compare/eljashm/gh-4231-box.exec > ute-immutable-function > src/box/lua/load_cfg.lua | 15 +++++++++++- > .../gh-4231_immutable_box.execute.test.lua | 24 +++++++++++++++++++ > 2 files changed, 38 insertions(+), 1 deletion(-) > create mode 100644 test/box-tap/gh-4231_immutable_box.execute.test.lua > diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua > index e7f62cf4e..ad416e578 100644 > --- a/src/box/lua/load_cfg.lua > +++ b/src/box/lua/load_cfg.lua > @@ -481,10 +481,14 @@ setmetatable(box, { > end > }) > > +-- Flag needed to keep immutable functions after box reconfiguration > +local box_loaded = false > + > local function load_cfg(cfg) > cfg = upgrade_cfg(cfg, translate_cfg) > cfg = prepare_cfg(cfg, default_cfg, template_cfg, modify_cfg) > apply_default_cfg(cfg, default_cfg); > + box_loaded = true > -- Save new box.cfg > box.cfg = cfg > if not pcall(private.cfg_check) then > @@ -528,7 +532,16 @@ box.cfg = locked(load_cfg) > -- metatable. > -- > function box.execute(...) > - load_cfg() > + -- > + -- Calling box.execute before explicitly configuring box led to > + -- automatic box.cfg invocation nonetheless. Following explicit > + -- attempts to configure box led to its reconfiguratin and as a Typo: s/reconfiguratin/reconfiguration/. > + -- result - to an error when trying to use execute method again. > + -- The check makes sure box.execute is an immutable function. There is a trailing whitespace within this comment (I pulled your branch and checked it). Please adjust it. > + -- > + if not box_loaded then > + load_cfg() > + end > return box.execute(...) > end > > diff --git a/test/box-tap/gh-4231_immutable_box.execute.test.lua > b/test/box-tap/gh-4231_immutable_box.execute.test.lua > new file mode 100644 > index 000000000..e2469630e > --- /dev/null > +++ b/test/box-tap/gh-4231_immutable_box.execute.test.lua As Nikita mentioned before (and we have the issue for it[2]), we're going to use dashes instead of underscores. Please adjust the test chunk name regarding this policy. > @@ -0,0 +1,24 @@ > +#!/usr/bin/env tarantool > +local tap = require('tap') > +local test = tap.test('execute') > +test:plan(2) > + > +-- > +-- gh-4231: box.execute should be immutable function meaning it > doesn't > +-- change after first box.cfg implicit invocation > +-- > + > +local box_execute = box.execute > +local status, err = pcall(function() > + box_execute("SELECT 1") > +end) > +test:ok(status and err == nil, "box.execute does not work properly > before box.cfg") > + load_cfg has been already called here, so you can check that box.execute function prior to this call is the same as the one after it (as Nikita suggested before). > +box.cfg{} > + > +local status2, err2 = pcall(function() > + box_execute("CREATE TABLE t1 (s1 INTEGER, PRIMARY KEY (s1));") > +end) > +test:ok(status2 and err2 == nil, "box.execute is changed after box.cfg > invocation") Minor: I guess you can move these lines to a separate function, since they are quite similar to the ones prior to box.cfg call. > + > +os.exit(test:check() and 0 or 1) > -- > 2.24.0 > <snipped> [1]: https://www.tarantool.io/en/doc/2.2/dev_guide/developer_guidelines/ [2]: https://github.com/tarantool/doc/issues/1004 -- Best regards, IM ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Tarantool-patches] [PATCH] box: make box.execute() immutable 2019-12-24 15:32 ` [Tarantool-patches] [PATCH] box: make box.execute() immutable Maria Khaydich 2019-12-25 1:30 ` Igor Munkin @ 2019-12-26 14:08 ` Alexander Turenko 2020-01-13 12:13 ` Maria Khaydich 1 sibling, 1 reply; 31+ messages in thread From: Alexander Turenko @ 2019-12-26 14:08 UTC (permalink / raw) To: Maria Khaydich; +Cc: tarantool-patches, Vladislav Shpilevoy > function box.execute(...) > - load_cfg() > + -- > + -- Calling box.execute before explicitly configuring box led to > + -- automatic box.cfg invocation nonetheless. Following explicit > + -- attempts to configure box led to its reconfiguratin and as a > + -- result - to an error when trying to use execute method again. > + -- The check makes sure box.execute is an immutable function. > + -- I would describe all this hell with registering lbox_execute as box.execute, moving it to box_cfg_guard_whitelist, adding this box.execute function, then replacing back with lbox_execute at load_cfg(). This description would make clear why everything is fine if we just call box.execute(), but extra flag is necessary if a user saved box.execute before first box.execute() or box.cfg() call. ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Tarantool-patches] [PATCH] box: make box.execute() immutable 2019-12-26 14:08 ` Alexander Turenko @ 2020-01-13 12:13 ` Maria Khaydich 2020-01-13 15:48 ` Igor Munkin 0 siblings, 1 reply; 31+ messages in thread From: Maria Khaydich @ 2020-01-13 12:13 UTC (permalink / raw) To: Alexander Turenko; +Cc: tarantool-patches, Vladislav Shpilevoy [-- Attachment #1: Type: text/plain, Size: 4502 bytes --] Thank you for the review. I’ve changed the comment describing box.execute method to explain why an extra flag is needed. And also added polishing fixes proposed by Igor. Result: Using box.execute method before explicitly configuring box automatically invoked box.cfg nonetheless. Any further calls to box.cfg caused its reconfiguration which then led to an error when trying to use execute method again. The patch introduces a fix making box.execute immutable. Closes #4231 --- Branch: https://github.com/tarantool/tarantool/compare/eljashm/gh-4231-box.execute-immutable-function Issue: https://github.com/tarantool/tarantool/issues/4231 src/box/lua/load_cfg.lua | 15 ++++++++- .../gh-4231-immutable-box-execute.test.lua | 32 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100755 test/box-tap/gh-4231-immutable-box-execute.test.lua diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua index 85617c8f0..1f9b4392f 100644 --- a/src/box/lua/load_cfg.lua +++ b/src/box/lua/load_cfg.lua @@ -517,10 +517,14 @@ setmetatable(box, { end }) +-- Flag needed to keep immutable functions after box reconfiguration +local box_loaded = false + local function load_cfg(cfg) cfg = upgrade_cfg(cfg, translate_cfg) cfg = prepare_cfg(cfg, default_cfg, template_cfg, modify_cfg) apply_default_cfg(cfg, default_cfg); + box_loaded = true -- Save new box.cfg box.cfg = cfg if not pcall(private.cfg_check) then @@ -564,7 +568,16 @@ box.cfg = locked(load_cfg) -- metatable. -- function box.execute(...) - load_cfg() + -- + -- Saving box.execute method before explicit calls to either + -- box.execute() or box.cfg{} leads to implicit invocation of + -- box.cfg nonetheless. The flag box_loaded makes sure execute + -- is an immutable function meaning it won't be overwritten by + -- any following attempts to reconfigure box. + -- + if not box_loaded then + load_cfg() + end return box.execute(...) end diff --git a/test/box-tap/gh-4231-immutable-box-execute.test.lua b/test/box-tap/gh-4231-immutable-box-execute.test.lua new file mode 100755 index 000000000..d8940a0b2 --- /dev/null +++ b/test/box-tap/gh-4231-immutable-box-execute.test.lua @@ -0,0 +1,32 @@ +#!/usr/bin/env tarantool +local tap = require('tap') +local test = tap.test('execute') +test:plan(4) + +-- +-- gh-4231: box.execute should be immutable function meaning it's +-- address doesn't change after first box.cfg implicit invocation +-- + +local function execute_is_immutable(execute, cmd, msg) + local status, err = pcall(function() + execute(cmd) + end) + test:ok(status and err == nil, msg) +end + +local box_execute_stub = box.execute +test:is(box_execute_stub, box.execute, "execute is not the same before box.cfg") +execute_is_immutable(box_execute_stub, "SELECT 1", + "execute does not work properly before box.cfg") + +local box_execute_actual = box.execute +-- explicit call to load_cfg +box.cfg{} +-- checking the function was not reconfigured, i.e. adress stays the same +test:is(box_execute_actual, box.execute, "execute is not the same after box.cfg") +execute_is_immutable(box_execute_actual, + "CREATE TABLE t1 (s1 INTEGER, PRIMARY KEY (s1));", + "execute does not work properly after box.cfg") + +os.exit(test:check() and 0 or 1) -- 2.24.0 >Четверг, 26 декабря 2019, 17:08 +03:00 от Alexander Turenko < alexander.turenko@tarantool.org >: > >> function box.execute(...) >> - load_cfg() >> + -- >> + -- Calling box.execute before explicitly configuring box led to >> + -- automatic box.cfg invocation nonetheless. Following explicit >> + -- attempts to configure box led to its reconfiguratin and as a >> + -- result - to an error when trying to use execute method again. >> + -- The check makes sure box.execute is an immutable function. >> + -- >I would describe all this hell with registering lbox_execute as >box.execute, moving it to box_cfg_guard_whitelist, adding this >box.execute function, then replacing back with lbox_execute at >load_cfg(). > >This description would make clear why everything is fine if we just call >box.execute(), but extra flag is necessary if a user saved box.execute >before first box.execute() or box.cfg() call. -- Maria Khaydich [-- Attachment #2: Type: text/html, Size: 7286 bytes --] ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Tarantool-patches] [PATCH] box: make box.execute() immutable 2020-01-13 12:13 ` Maria Khaydich @ 2020-01-13 15:48 ` Igor Munkin 2020-01-18 10:56 ` Maria Khaydich 0 siblings, 1 reply; 31+ messages in thread From: Igor Munkin @ 2020-01-13 15:48 UTC (permalink / raw) To: Maria Khaydich; +Cc: tarantool-patches, Vladislav Shpilevoy Masha, Thanks, the patch LGTM, except a couple minor comments below. Please consider them. Sasha, please proceed with the patch. On 13.01.20, Maria Khaydich wrote: > Thank you for the review. > > I’ve changed the comment describing box.execute method to explain why > an extra flag is needed. > And also added polishing fixes proposed by Igor. > > Result: > > Using box.execute method before explicitly configuring box > automatically invoked box.cfg nonetheless. Any further calls > to box.cfg caused its reconfiguration which then led to an > error when trying to use execute method again. > > The patch introduces a fix making box.execute immutable. > > Closes #4231 > --- > Branch: > [1]https://github.com/tarantool/tarantool/compare/eljashm/gh-4231-box.e > xecute-immutable-function > Issue: > [2]https://github.com/tarantool/tarantool/issues/4231 > src/box/lua/load_cfg.lua | 15 ++++++++- > .../gh-4231-immutable-box-execute.test.lua | 32 +++++++++++++++++++ > 2 files changed, 46 insertions(+), 1 deletion(-) > create mode 100755 test/box-tap/gh-4231-immutable-box-execute.test.lua > diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua > index 85617c8f0..1f9b4392f 100644 > --- a/src/box/lua/load_cfg.lua > +++ b/src/box/lua/load_cfg.lua > @@ -517,10 +517,14 @@ setmetatable(box, { > end > }) > > +-- Flag needed to keep immutable functions after box reconfiguration > +local box_loaded = false > + > local function load_cfg(cfg) > cfg = upgrade_cfg(cfg, translate_cfg) > cfg = prepare_cfg(cfg, default_cfg, template_cfg, modify_cfg) > apply_default_cfg(cfg, default_cfg); > + box_loaded = true > -- Save new box.cfg > box.cfg = cfg > if not pcall(private.cfg_check) then > @@ -564,7 +568,16 @@ box.cfg = locked(load_cfg) > -- metatable. > -- > function box.execute(...) > - load_cfg() > + -- > + -- Saving box.execute method before explicit calls to either > + -- box.execute() or box.cfg{} leads to implicit invocation of > + -- box.cfg nonetheless. The flag box_loaded makes sure execute > + -- is an immutable function meaning it won't be overwritten by > + -- any following attempts to reconfigure box. > + -- > + if not box_loaded then > + load_cfg() > + end > return box.execute(...) > end > > diff --git a/test/box-tap/gh-4231-immutable-box-execute.test.lua > b/test/box-tap/gh-4231-immutable-box-execute.test.lua > new file mode 100755 > index 000000000..d8940a0b2 > --- /dev/null > +++ b/test/box-tap/gh-4231-immutable-box-execute.test.lua > @@ -0,0 +1,32 @@ > +#!/usr/bin/env tarantool > +local tap = require('tap') > +local test = tap.test('execute') > +test:plan(4) > + > +-- > +-- gh-4231: box.execute should be immutable function meaning it's > +-- address doesn't change after first box.cfg implicit invocation > +-- > + > +local function execute_is_immutable(execute, cmd, msg) > + local status, err = pcall(function() > + execute(cmd) > + end) > + test:ok(status and err == nil, msg) > +end > + > +local box_execute_stub = box.execute > +test:is(box_execute_stub, box.execute, "execute is not the same before > box.cfg") Minor: this test is a trivial and excess one. I suggest to drop it. > +execute_is_immutable(box_execute_stub, "SELECT 1", > + "execute does not work properly before box.cfg") > + > +local box_execute_actual = box.execute > +-- explicit call to load_cfg > +box.cfg{} > +-- checking the function was not reconfigured, i.e. adress stays the > same > +test:is(box_execute_actual, box.execute, "execute is not the same > after box.cfg") Minor: out of 80 chars > +execute_is_immutable(box_execute_actual, > + "CREATE TABLE t1 (s1 INTEGER, PRIMARY KEY (s1));", > + "execute does not work properly after box.cfg") > + > +os.exit(test:check() and 0 or 1) > -- > 2.24.0 > > Четверг, 26 декабря 2019, 17:08 +03:00 от Alexander Turenko > <alexander.turenko@tarantool.org>: > > > function box.execute(...) > > - load_cfg() > > + -- > > + -- Calling box.execute before explicitly configuring box led to > > + -- automatic box.cfg invocation nonetheless. Following explicit > > + -- attempts to configure box led to its reconfiguratin and as a > > + -- result - to an error when trying to use execute method > again. > > + -- The check makes sure box.execute is an immutable function. > > + -- > I would describe all this hell with registering lbox_execute as > box.execute, moving it to box_cfg_guard_whitelist, adding this > box.execute function, then replacing back with lbox_execute at > load_cfg(). > This description would make clear why everything is fine if we just > call > box.execute(), but extra flag is necessary if a user saved box.execute > before first box.execute() or box.cfg() call. > > > > -- > Maria Khaydich > > References > > 1. https://github.com/tarantool/tarantool/compare/eljashm/gh-4231-box.execute-immutable-function > 2. https://github.com/tarantool/tarantool/issues/4231 -- Best regards, IM ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Tarantool-patches] [PATCH] box: make box.execute() immutable 2020-01-13 15:48 ` Igor Munkin @ 2020-01-18 10:56 ` Maria Khaydich 2020-02-20 17:51 ` Alexander Turenko 0 siblings, 1 reply; 31+ messages in thread From: Maria Khaydich @ 2020-01-18 10:56 UTC (permalink / raw) To: Igor Munkin; +Cc: tarantool-patches [-- Attachment #1: Type: text/plain, Size: 5257 bytes --] Fixed minor comments. Sasha, you can proceed with the review. >Понедельник, 13 января 2020, 18:50 +03:00 от Igor Munkin <imun@tarantool.org>: > >Masha, > >Thanks, the patch LGTM, except a couple minor comments below. Please >consider them. > >Sasha, please proceed with the patch. > >On 13.01.20, Maria Khaydich wrote: >> Thank you for the review. >> >> I’ve changed the comment describing box.execute method to explain why >> an extra flag is needed. >> And also added polishing fixes proposed by Igor. >> >> Result: >> >> Using box.execute method before explicitly configuring box >> automatically invoked box.cfg nonetheless. Any further calls >> to box.cfg caused its reconfiguration which then led to an >> error when trying to use execute method again. >> >> The patch introduces a fix making box.execute immutable. >> >> Closes #4231 >> --- >> Branch: >> [1] https://github.com/tarantool/tarantool/compare/eljashm/gh-4231-box.e >> xecute-immutable-function >> Issue: >> [2] https://github.com/tarantool/tarantool/issues/4231 >> src/box/lua/load_cfg.lua | 15 ++++++++- >> .../gh-4231-immutable-box-execute.test.lua | 32 +++++++++++++++++++ >> 2 files changed, 46 insertions(+), 1 deletion(-) >> create mode 100755 test/box-tap/gh-4231-immutable-box-execute.test.lua >> diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua >> index 85617c8f0..1f9b4392f 100644 >> --- a/src/box/lua/load_cfg.lua >> +++ b/src/box/lua/load_cfg.lua >> @@ -517,10 +517,14 @@ setmetatable(box, { >> end >> }) >> >> +-- Flag needed to keep immutable functions after box reconfiguration >> +local box_loaded = false >> + >> local function load_cfg(cfg) >> cfg = upgrade_cfg(cfg, translate_cfg) >> cfg = prepare_cfg(cfg, default_cfg, template_cfg, modify_cfg) >> apply_default_cfg(cfg, default_cfg); >> + box_loaded = true >> -- Save new box.cfg >> box.cfg = cfg >> if not pcall(private.cfg_check) then >> @@ -564,7 +568,16 @@ box.cfg = locked(load_cfg) >> -- metatable. >> -- >> function box.execute(...) >> - load_cfg() >> + -- >> + -- Saving box.execute method before explicit calls to either >> + -- box.execute() or box.cfg{} leads to implicit invocation of >> + -- box.cfg nonetheless. The flag box_loaded makes sure execute >> + -- is an immutable function meaning it won't be overwritten by >> + -- any following attempts to reconfigure box. >> + -- >> + if not box_loaded then >> + load_cfg() >> + end >> return box.execute(...) >> end >> >> diff --git a/test/box-tap/gh-4231-immutable-box-execute.test.lua >> b/test/box-tap/gh-4231-immutable-box-execute.test.lua >> new file mode 100755 >> index 000000000..d8940a0b2 >> --- /dev/null >> +++ b/test/box-tap/gh-4231-immutable-box-execute.test.lua >> @@ -0,0 +1,32 @@ >> +#!/usr/bin/env tarantool >> +local tap = require('tap') >> +local test = tap.test('execute') >> +test:plan(4) >> + >> +-- >> +-- gh-4231: box.execute should be immutable function meaning it's >> +-- address doesn't change after first box.cfg implicit invocation >> +-- >> + >> +local function execute_is_immutable(execute, cmd, msg) >> + local status, err = pcall(function() >> + execute(cmd) >> + end) >> + test:ok(status and err == nil, msg) >> +end >> + >> +local box_execute_stub = box.execute >> +test:is(box_execute_stub, box.execute, "execute is not the same before >> box.cfg") > >Minor: this test is a trivial and excess one. I suggest to drop it. > >> +execute_is_immutable(box_execute_stub, "SELECT 1", >> + "execute does not work properly before box.cfg") >> + >> +local box_execute_actual = box.execute >> +-- explicit call to load_cfg >> +box.cfg{} >> +-- checking the function was not reconfigured, i.e. adress stays the >> same >> +test:is(box_execute_actual, box.execute, "execute is not the same >> after box.cfg") > >Minor: out of 80 chars > >> +execute_is_immutable(box_execute_actual, >> + "CREATE TABLE t1 (s1 INTEGER, PRIMARY KEY (s1));", >> + "execute does not work properly after box.cfg") >> + >> +os.exit(test:check() and 0 or 1) >> -- >> 2.24.0 >> >> Четверг, 26 декабря 2019, 17:08 +03:00 от Alexander Turenko >> < alexander.turenko@tarantool.org >: >> >> > function box.execute(...) >> > - load_cfg() >> > + -- >> > + -- Calling box.execute before explicitly configuring box led to >> > + -- automatic box.cfg invocation nonetheless. Following explicit >> > + -- attempts to configure box led to its reconfiguratin and as a >> > + -- result - to an error when trying to use execute method >> again. >> > + -- The check makes sure box.execute is an immutable function. >> > + -- >> I would describe all this hell with registering lbox_execute as >> box.execute, moving it to box_cfg_guard_whitelist, adding this >> box.execute function, then replacing back with lbox_execute at >> load_cfg(). >> This description would make clear why everything is fine if we just >> call >> box.execute(), but extra flag is necessary if a user saved box.execute >> before first box.execute() or box.cfg() call. >> >> >> >> -- >> Maria Khaydich >> >> References >> >> 1. https://github.com/tarantool/tarantool/compare/eljashm/gh-4231-box.execute-immutable-function >> 2. https://github.com/tarantool/tarantool/issues/4231 > >-- >Best regards, >IM -- Maria Khaydich [-- Attachment #2: Type: text/html, Size: 7115 bytes --] ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Tarantool-patches] [PATCH] box: make box.execute() immutable 2020-01-18 10:56 ` Maria Khaydich @ 2020-02-20 17:51 ` Alexander Turenko 2020-02-20 21:15 ` Igor Munkin ` (2 more replies) 0 siblings, 3 replies; 31+ messages in thread From: Alexander Turenko @ 2020-02-20 17:51 UTC (permalink / raw) To: Maria Khaydich; +Cc: tarantool-patches Sorry for the late response. See comments below. While looking into the patch, experimenting and commenting I made the patch (it is based on your changes), so I'll paste it at end of the email for the reference. WBR, Alexander Turenko. > commit 573318ea8749931741247f181333ab68b43a82c6 > Author: Maria <maria.khaydich@tarantool.org> > Date: Tue Oct 29 17:56:51 2019 +0300 > > box: box.execute should be immutable function Now I recalled the right term: idempotent. Nit: it would be good to use imperative mood in the commit header: | Use the imperative mood in the subject line. A properly formed Git | commit subject line should always be able to complete the following | sentence: “If applied, this commit will /your subject line here/”. https://www.tarantool.io/en/doc/1.10/dev_guide/developer_guidelines/#how-to-write-a-commit-message > > Using box.execute method before explicitly configuring box > automatically invoked box.cfg nonetheless. Any further calls > to box.cfg caused its reconfiguration which then led to an > error when trying to use execute method again. Sorry that I nitpick around wording again, but after the description I would check something like the following: | box.execute('SELECT 1') -- here box.cfg{} is called under hood | box.execute('SELECT 1') -- everything looks ok After that I would be confused, because everything works as expected. I would say that there are two different functions <box_load_and_execute> (which is assigned to box.execute when box is not configured) and <lbox_execute> (after box confguration) and would describe the case using those terms. I guess it would easier to understand. See also the comment about the test at very end of the email. > > The patch introduces a fix making box.execute immutable. > > Closes #4231 > > diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua > index 85617c8f0..1f9b4392f 100644 > --- a/src/box/lua/load_cfg.lua > +++ b/src/box/lua/load_cfg.lua > @@ -517,10 +517,14 @@ setmetatable(box, { > end > }) > > +-- Flag needed to keep immutable functions after box reconfiguration Nit: over 66 symbols. > +local box_loaded = false > + > local function load_cfg(cfg) > cfg = upgrade_cfg(cfg, translate_cfg) > cfg = prepare_cfg(cfg, default_cfg, template_cfg, modify_cfg) > apply_default_cfg(cfg, default_cfg); > + box_loaded = true After this we can failed to configure box, consider the case: | tarantool> box.cfg{listen = 'incorrect'} | --- | - error: 'Incorrect value for option ''listen'': expected host:service or /unix.socket' | ... | | tarantool> box.execute('SELECT 1') We should set the flag only at successful box configuration. I would also add such test case. > -- Save new box.cfg > box.cfg = cfg > if not pcall(private.cfg_check) then > @@ -564,7 +568,16 @@ box.cfg = locked(load_cfg) > -- metatable. > -- > function box.execute(...) > - load_cfg() > + -- > + -- Saving box.execute method before explicit calls to either > + -- box.execute() or box.cfg{} leads to implicit invocation of > + -- box.cfg nonetheless. Technically saving of box.execute does not lead to invocation of box.cfg. But anyway I would describe things in the way as proposed above. > + -- The flag box_loaded makes sure execute > + -- is an immutable function meaning it won't be overwritten by > + -- any following attempts to reconfigure box. > + -- The problem is not that <lbox_execute> will be overwritten with some <box_another_execute>, but that the initial <box_load_and_execute> does not work correctly after successful box configuration. > + if not box_loaded then > + load_cfg() > + end I considered using of `type(box.cfg) == 'function'` check as in tarantoolctl, but in fact it is not realiable: if box was not configured after box.cfg() due to an error (say, after `box.cfg{listen = 'invalid'}`) the type of box.cfg will be 'table' and reload_cfg() will work on the next box.cfg() call. So we should use box_is_configured C function: | local ffi = require('ffi') | | ffi.cdef([[ | bool | box_is_configured(void); | ]]) | | local function box_is_configured() | return ffi.C.box_is_configured() | end This way requires to add the function into extra/exports. BTW, it seems that it is possible that <box_load_and_execute> will be called when `box.cfg{}` is already in progress in another fiber: this is why all load_cfg() / reload_cfg() calls are decorated using `locked` wrapper. It seems we should do the same in <box_load_and_execute>: | function box.execute(...) | if not box_is_configured() then | locked(function() | -- Re-check, because after the lock release the box | -- state may be changed. We should call load_cfg() | -- only once. | if not box_is_configured() then | load_cfg() | end | end)() | end | return box.execute(...) | end I experimented with this like so: | $ ./src/tarantool | tarantool> box_execute = box.execute | tarantool> for i = 1, 10 do require('fiber').create(function() require('log').info(require('yaml').encode((box_execute('SELECT * FROM "_vindex"')))) end) end While looking into the code I found one more case: | tarantool> box_cfg = box.cfg | --- | ... | tarantool> box_cfg() | <...> | tarantool> box_cfg() | --- | - error: 'builtin/box/load_cfg.lua:19: builtin/box/load_cfg.lua:547: bad argument | #1 to ''pairs'' (table expected, got nil)' | ... I think it does NOT mean that we should not fix box.execute() code, because the expected behaviour is a bit different: * box.execute() (more specifically <box_load_and_execute>) should configure box if it is not configured or just execute otherwise (w/o box reconfiguration). * box.cfg() (more specifically <load_cfg>) should configure box if it is not configured, otherwise **reconfigure** it. So box.cfg() should call reload_cfg() if box is already configured. I propose to fix it in a separate patch (but within the scope of the issue). > return box.execute(...) > end > > diff --git a/test/box-tap/gh-4231-immutable-box-execute.test.lua b/test/box-tap/gh-4231-immutable-box-execute.test.lua > new file mode 100755 > index 000000000..5bdbec88f > --- /dev/null > +++ b/test/box-tap/gh-4231-immutable-box-execute.test.lua > @@ -0,0 +1,33 @@ > +#!/usr/bin/env tarantool > +local tap = require('tap') > +local test = tap.test('execute') > +test:plan(3) > + > +-- > +-- gh-4231: box.execute should be immutable function meaning it's > +-- address doesn't change after first box.cfg implicit invocation But it is not so even after the patch: | tarantool> box.execute | --- | - 'function: 0x4074bc30' | ... | tarantool> box.execute('SELECT 1') | <...> | tarantool> box.execute | --- | - 'function: 0x416b2600' | ... > +-- > + > +local function execute_is_immutable(execute, cmd, msg) > + local status, err = pcall(function() > + execute(cmd) > + end) Nit: Can be written as: | local status, err = pcall(execute, cmd) > + test:ok(status and err == nil, msg) > +end > + > +local box_execute_stub = box.execute > +execute_is_immutable(box_execute_stub, "SELECT 1", > + "execute does not work properly before box.cfg") This will print: ok - execute does not work properly before box.cfg --that looks counter-intuitive for me. BTW, it looks as the preparation code for the test rather than the test itself. Personally I think that such code should do assert() rather than produce 'ok/not ok' TAP13 output. This is not the strict requirement, however. Consider [1], from words 'I would split test preparation / clean up code from actual test cases'. [1]: https://lists.tarantool.org/pipermail/tarantool-patches/2020-January/013595.html > + > +local box_execute_actual = box.execute > +-- explicit call to load_cfg > +box.cfg{} > + > +-- checking the function was not reconfigured, i.e. adress stays the same Typo: adress -> address. > +test:is(box_execute_actual, box.execute, > + "execute is not the same after box.cfg") > +execute_is_immutable(box_execute_actual, > + "CREATE TABLE t1 (s1 INTEGER, PRIMARY KEY (s1));", > + "execute does not work properly after box.cfg") > + > +os.exit(test:check() and 0 or 1) The test case works properly (does not fail) on current master w/o the fix. I guess you intend to test box_execute_stub after box.cfg(). BTW, I suggest to run a test on a tarantool version before a fix to verify that the test actually able to catch the problem. ---- diff --git a/extra/exports b/extra/exports index 7b84a1452..8599614ee 100644 --- a/extra/exports +++ b/extra/exports @@ -118,6 +118,8 @@ swim_member_unref swim_member_is_dropped swim_member_is_payload_up_to_date +box_is_configured + # Module API _say diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua index 1f9b4392f..dfff772d7 100644 --- a/src/box/lua/load_cfg.lua +++ b/src/box/lua/load_cfg.lua @@ -6,6 +6,12 @@ local private = require('box.internal') local urilib = require('uri') local math = require('math') local fiber = require('fiber') +local ffi = require('ffi') + +ffi.cdef([[ + bool + box_is_configured(void); +]]) -- Function decorator that is used to prevent box.cfg() from -- being called concurrently by different fibers. @@ -517,14 +523,10 @@ setmetatable(box, { end }) --- Flag needed to keep immutable functions after box reconfiguration -local box_loaded = false - local function load_cfg(cfg) cfg = upgrade_cfg(cfg, translate_cfg) cfg = prepare_cfg(cfg, default_cfg, template_cfg, modify_cfg) apply_default_cfg(cfg, default_cfg); - box_loaded = true -- Save new box.cfg box.cfg = cfg if not pcall(private.cfg_check) then @@ -562,24 +564,43 @@ local function load_cfg(cfg) end box.cfg = locked(load_cfg) +local function box_is_configured() + return ffi.C.box_is_configured() +end + -- --- This makes possible do box.execute without calling box.cfg --- manually. The load_cfg call overwrites following table and --- metatable. +-- box.execute is <box_load_and_execute> when box is not loaded, +-- <lbox_execute> otherwise. See also <box_configured> variable. -- -function box.execute(...) - -- - -- Saving box.execute method before explicit calls to either - -- box.execute() or box.cfg{} leads to implicit invocation of - -- box.cfg nonetheless. The flag box_loaded makes sure execute - -- is an immutable function meaning it won't be overwritten by - -- any following attempts to reconfigure box. +-- <box_load_and_execute> loads box and calls <lbox_execute>. +-- +local box_load_and_execute +box_load_and_execute = function(...) + -- Configure box if it is not configured, no-op otherwise (not + -- reconfiguration). -- - if not box_loaded then - load_cfg() + -- We should check whether box is configured, because a user + -- may save <box_load_and_execute> function before box loading + -- and call it afterwards. + if not box_is_configured() then + locked(function() + -- Re-check, because after releasing of the lock the + -- box state may be changed. We should call load_cfg() + -- only once. + if not box_is_configured() then + load_cfg() + end + end)() end + + -- At this point box should be configured and box.execute() + -- function should be replaced with lbox_execute(). + assert(type(box.cfg) ~= 'function') + assert(box.execute ~= box_load_and_execute) + return box.execute(...) end +box.execute = box_load_and_execute -- gh-810: -- hack luajit default cpath ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Tarantool-patches] [PATCH] box: make box.execute() immutable 2020-02-20 17:51 ` Alexander Turenko @ 2020-02-20 21:15 ` Igor Munkin 2020-03-11 15:56 ` Maria Khaydich 2020-03-11 15:57 ` [Tarantool-patches] [PATCH 1/2] box: make box.cfg idempotent function Maria Khaydich 2 siblings, 0 replies; 31+ messages in thread From: Igor Munkin @ 2020-02-20 21:15 UTC (permalink / raw) To: Alexander Turenko; +Cc: tarantool-patches Sasha, On 20.02.20, Alexander Turenko wrote: > Sorry for the late response. > > See comments below. > > While looking into the patch, experimenting and commenting I made the > patch (it is based on your changes), so I'll paste it at end of the > email for the reference. > > WBR, Alexander Turenko. > <snipped> > > I considered using of `type(box.cfg) == 'function'` check as in > tarantoolctl, but in fact it is not realiable: if box was not configured > after box.cfg() due to an error (say, after `box.cfg{listen = > 'invalid'}`) the type of box.cfg will be 'table' and reload_cfg() will > work on the next box.cfg() call. So we should use box_is_configured C > function: > Nice. I overlooked it, but you found such a great solution here. > | local ffi = require('ffi') > | > | ffi.cdef([[ > | bool > | box_is_configured(void); > | ]]) > | > | local function box_is_configured() > | return ffi.C.box_is_configured() > | end > <snipped> -- Best regards, IM ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Tarantool-patches] [PATCH] box: make box.execute() immutable 2020-02-20 17:51 ` Alexander Turenko 2020-02-20 21:15 ` Igor Munkin @ 2020-03-11 15:56 ` Maria Khaydich 2020-03-18 22:25 ` Igor Munkin 2020-05-12 16:16 ` Alexander Turenko 2020-03-11 15:57 ` [Tarantool-patches] [PATCH 1/2] box: make box.cfg idempotent function Maria Khaydich 2 siblings, 2 replies; 31+ messages in thread From: Maria Khaydich @ 2020-03-11 15:56 UTC (permalink / raw) To: Alexander Turenko; +Cc: tarantool-patches [-- Attachment #1: Type: text/plain, Size: 16600 bytes --] Thank you for the review! I reworked the patch: ---------------------------------------------------------------------- Saving box.execute method before explicitly configuring box automatically invokes load_cfg() nonetheless. Further calls to box.cfg{} caused its reconfiguration and replacement of previously saved box.execute meaning it couldn't be used again without leading to an error. The patch introduces a workaround making box.execute idempotent and is heavily influenced by @Totktonada. Closes #4231 --- Issue: https://github.com/tarantool/tarantool/issues/4231 Branch: https://github.com/tarantool/tarantool/compare/eljashm/gh-4231-box.execute-immutable-function extra/exports | 2 + src/box/lua/load_cfg.lua | 42 ++++++++++++++++--- .../gh-4231-immutable-box-execute.test.lua | 28 +++++++++++++ 3 files changed, 67 insertions(+), 5 deletions(-) create mode 100755 test/box-tap/gh-4231-immutable-box-execute.test.lua diff --git a/extra/exports b/extra/exports index 7b84a1452..8599614ee 100644 --- a/extra/exports +++ b/extra/exports @@ -118,6 +118,8 @@ swim_member_unref swim_member_is_dropped swim_member_is_payload_up_to_date +box_is_configured + # Module API _say diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua index 85617c8f0..dc4293bdd 100644 --- a/src/box/lua/load_cfg.lua +++ b/src/box/lua/load_cfg.lua @@ -6,6 +6,12 @@ local private = require('box.internal') local urilib = require('uri') local math = require('math') local fiber = require('fiber') +local ffi = require('ffi') + +ffi.cdef([[ +bool +box_is_configured(void); +]]) -- Function decorator that is used to prevent box.cfg() from -- being called concurrently by different fibers. @@ -558,15 +564,41 @@ local function load_cfg(cfg) end box.cfg = locked(load_cfg) +local function box_is_configured() + return ffi.C.box_is_configured() +end + -- --- This makes possible do box.execute without calling box.cfg --- manually. The load_cfg call overwrites following table and --- metatable. +-- box.execute is <box_load_and_execute> when box is not loaded, +-- <lbox_execute> otherwise. See also <box_configured> variable. +-- <box_load_and_execute> loads box and calls <lbox_execute>. -- -function box.execute(...) - load_cfg() +local box_load_and_execute +box_load_and_execute = function(...) + -- Configure box if it is not configured, no-op otherwise (not + -- reconfiguration). + -- We should check whether box is configured, because a user + -- may save <box_load_and_execute> function before box loading + -- and call it afterwards. + if not box_is_configured() then + locked(function() + -- Re-check, because after releasing of the lock the + -- box state may be changed. We should call load_cfg() + -- only once. + if not box_is_configured() then + load_cfg() + end + end)() + end + + -- At this point box should be configured and box.execute() + -- function should be replaced with lbox_execute(). + assert(type(box.cfg) ~= 'function') + assert(box.execute ~= box_load_and_execute) + return box.execute(...) end +box.execute = box_load_and_execute -- gh-810: -- hack luajit default cpath diff --git a/test/box-tap/gh-4231-immutable-box-execute.test.lua b/test/box-tap/gh-4231-immutable-box-execute.test.lua new file mode 100755 index 000000000..1544591bf --- /dev/null +++ b/test/box-tap/gh-4231-immutable-box-execute.test.lua @@ -0,0 +1,28 @@ +#!/usr/bin/env tarantool +local tap = require('tap') +local test = tap.test('execute') +test:plan(2) + +-- +-- gh-4231: box.execute should be an idempotent function +-- meaning its effect should be the same if a user chooses +-- to use it before explicit box.cfg invocation +-- + +local function execute_is_immutable(execute, cmd, msg) + local status, err = pcall(execute, cmd) + test:ok(status and type(err) == 'table', msg) +end + +local box_execute_stub = box.execute +-- explicit call to load_cfg +box.cfg{} +local box_execute_actual = box.execute + +execute_is_immutable(box_execute_stub, + "CREATE TABLE t1 (s1 INTEGER, PRIMARY KEY (s1));", + "box.execute stub works before box.cfg") +execute_is_immutable(box_execute_actual, "DROP TABLE t1", + "box.execute works properly after box.cfg") + +os.exit(test:check() and 0 or 1) -- 2.24.0 >Четверг, 20 февраля 2020, 20:51 +03:00 от Alexander Turenko <alexander.turenko@tarantool.org>: > >Sorry for the late response. > >See comments below. > >While looking into the patch, experimenting and commenting I made the >patch (it is based on your changes), so I'll paste it at end of the >email for the reference. > >WBR, Alexander Turenko. > >> commit 573318ea8749931741247f181333ab68b43a82c6 >> Author: Maria < maria.khaydich@tarantool.org > >> Date: Tue Oct 29 17:56:51 2019 +0300 >> >> box: box.execute should be immutable function > >Now I recalled the right term: idempotent. > >Nit: it would be good to use imperative mood in the commit header: > > | Use the imperative mood in the subject line. A properly formed Git > | commit subject line should always be able to complete the following > | sentence: “If applied, this commit will /your subject line here/”. > >https://www.tarantool.io/en/doc/1.10/dev_guide/developer_guidelines/#how-to-write-a-commit-message > >> >> Using box.execute method before explicitly configuring box >> automatically invoked box.cfg nonetheless. Any further calls >> to box.cfg caused its reconfiguration which then led to an >> error when trying to use execute method again. > >Sorry that I nitpick around wording again, but after the description I >would check something like the following: > > | box.execute('SELECT 1') -- here box.cfg{} is called under hood > | box.execute('SELECT 1') -- everything looks ok > >After that I would be confused, because everything works as expected. > >I would say that there are two different functions ><box_load_and_execute> (which is assigned to box.execute when box is not >configured) and <lbox_execute> (after box confguration) and would >describe the case using those terms. I guess it would easier to >understand. > >See also the comment about the test at very end of the email. > >> >> The patch introduces a fix making box.execute immutable. >> >> Closes #4231 >> >> diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua >> index 85617c8f0..1f9b4392f 100644 >> --- a/src/box/lua/load_cfg.lua >> +++ b/src/box/lua/load_cfg.lua >> @@ -517,10 +517,14 @@ setmetatable(box, { >> end >> }) >> >> +-- Flag needed to keep immutable functions after box reconfiguration > >Nit: over 66 symbols. > >> +local box_loaded = false >> + >> local function load_cfg(cfg) >> cfg = upgrade_cfg(cfg, translate_cfg) >> cfg = prepare_cfg(cfg, default_cfg, template_cfg, modify_cfg) >> apply_default_cfg(cfg, default_cfg); >> + box_loaded = true > >After this we can failed to configure box, consider the case: > > | tarantool> box.cfg{listen = 'incorrect'} > | --- > | - error: 'Incorrect value for option ''listen'': expected host:service or /unix.socket' > | ... > | > | tarantool> box.execute('SELECT 1') > >We should set the flag only at successful box configuration. I would >also add such test case. > >> -- Save new box.cfg >> box.cfg = cfg >> if not pcall(private.cfg_check) then >> @@ -564,7 +568,16 @@ box.cfg = locked(load_cfg) >> -- metatable. >> -- >> function box.execute(...) >> - load_cfg() >> + -- >> + -- Saving box.execute method before explicit calls to either >> + -- box.execute() or box.cfg{} leads to implicit invocation of >> + -- box.cfg nonetheless. > >Technically saving of box.execute does not lead to invocation of >box.cfg. But anyway I would describe things in the way as proposed >above. > >> + -- The flag box_loaded makes sure execute >> + -- is an immutable function meaning it won't be overwritten by >> + -- any following attempts to reconfigure box. >> + -- > >The problem is not that <lbox_execute> will be overwritten with some ><box_another_execute>, but that the initial <box_load_and_execute> does >not work correctly after successful box configuration. > >> + if not box_loaded then >> + load_cfg() >> + end > >I considered using of `type(box.cfg) == 'function'` check as in >tarantoolctl, but in fact it is not realiable: if box was not configured >after box.cfg() due to an error (say, after `box.cfg{listen = >'invalid'}`) the type of box.cfg will be 'table' and reload_cfg() will >work on the next box.cfg() call. So we should use box_is_configured C >function: > > | local ffi = require('ffi') > | > | ffi.cdef([[ > | bool > | box_is_configured(void); > | ]]) > | > | local function box_is_configured() > | return ffi.C.box_is_configured() > | end > >This way requires to add the function into extra/exports. > >BTW, it seems that it is possible that <box_load_and_execute> will be >called when `box.cfg{}` is already in progress in another fiber: this is >why all load_cfg() / reload_cfg() calls are decorated using `locked` >wrapper. It seems we should do the same in <box_load_and_execute>: > > | function box.execute(...) > | if not box_is_configured() then > | locked(function() > | -- Re-check, because after the lock release the box > | -- state may be changed. We should call load_cfg() > | -- only once. > | if not box_is_configured() then > | load_cfg() > | end > | end)() > | end > | return box.execute(...) > | end > >I experimented with this like so: > > | $ ./src/tarantool > | tarantool> box_execute = box.execute > | tarantool> for i = 1, 10 do require('fiber').create(function() require('log').info(require('yaml').encode((box_execute('SELECT * FROM "_vindex"')))) end) end > >While looking into the code I found one more case: > > | tarantool> box_cfg = box.cfg > | --- > | ... > | tarantool> box_cfg() > | <...> > | tarantool> box_cfg() > | --- > | - error: 'builtin/box/load_cfg.lua:19: builtin/box/load_cfg.lua:547: bad argument > | #1 to ''pairs'' (table expected, got nil)' > | ... > >I think it does NOT mean that we should not fix box.execute() code, >because the expected behaviour is a bit different: > >* box.execute() (more specifically <box_load_and_execute>) should > configure box if it is not configured or just execute otherwise (w/o > box reconfiguration). >* box.cfg() (more specifically <load_cfg>) should configure box if it is > not configured, otherwise **reconfigure** it. > >So box.cfg() should call reload_cfg() if box is already configured. I >propose to fix it in a separate patch (but within the scope of the >issue). > >> return box.execute(...) >> end >> >> diff --git a/test/box-tap/gh-4231-immutable-box-execute.test.lua b/test/box-tap/gh-4231-immutable-box-execute.test.lua >> new file mode 100755 >> index 000000000..5bdbec88f >> --- /dev/null >> +++ b/test/box-tap/gh-4231-immutable-box-execute.test.lua >> @@ -0,0 +1,33 @@ >> +#!/usr/bin/env tarantool >> +local tap = require('tap') >> +local test = tap.test('execute') >> +test:plan(3) >> + >> +-- >> +-- gh-4231: box.execute should be immutable function meaning it's >> +-- address doesn't change after first box.cfg implicit invocation > >But it is not so even after the patch: > > | tarantool> box.execute > | --- > | - 'function: 0x4074bc30' > | ... > | tarantool> box.execute('SELECT 1') > | <...> > | tarantool> box.execute > | --- > | - 'function: 0x416b2600' > | ... > >> +-- >> + >> +local function execute_is_immutable(execute, cmd, msg) >> + local status, err = pcall(function() >> + execute(cmd) >> + end) > >Nit: Can be written as: > > | local status, err = pcall(execute, cmd) > >> + test:ok(status and err == nil, msg) >> +end >> + >> +local box_execute_stub = box.execute >> +execute_is_immutable(box_execute_stub, "SELECT 1", >> + "execute does not work properly before box.cfg") > >This will print: > >ok - execute does not work properly before box.cfg > >--that looks counter-intuitive for me. > >BTW, it looks as the preparation code for the test rather than the test >itself. Personally I think that such code should do assert() rather than >produce 'ok/not ok' TAP13 output. This is not the strict requirement, >however. > >Consider [1], from words 'I would split test preparation / clean up code >from actual test cases'. > >[1]: https://lists.tarantool.org/pipermail/tarantool-patches/2020-January/013595.html > >> + >> +local box_execute_actual = box.execute >> +-- explicit call to load_cfg >> +box.cfg{} >> + >> +-- checking the function was not reconfigured, i.e. adress stays the same > >Typo: adress -> address. > >> +test:is(box_execute_actual, box.execute, >> + "execute is not the same after box.cfg") >> +execute_is_immutable(box_execute_actual, >> + "CREATE TABLE t1 (s1 INTEGER, PRIMARY KEY (s1));", >> + "execute does not work properly after box.cfg") >> + >> +os.exit(test:check() and 0 or 1) > >The test case works properly (does not fail) on current master w/o the >fix. I guess you intend to test box_execute_stub after box.cfg(). > >BTW, I suggest to run a test on a tarantool version before a fix to >verify that the test actually able to catch the problem. > >---- > >diff --git a/extra/exports b/extra/exports >index 7b84a1452..8599614ee 100644 >--- a/extra/exports >+++ b/extra/exports >@@ -118,6 +118,8 @@ swim_member_unref > swim_member_is_dropped > swim_member_is_payload_up_to_date > >+box_is_configured >+ > # Module API > > _say >diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua >index 1f9b4392f..dfff772d7 100644 >--- a/src/box/lua/load_cfg.lua >+++ b/src/box/lua/load_cfg.lua >@@ -6,6 +6,12 @@ local private = require('box.internal') > local urilib = require('uri') > local math = require('math') > local fiber = require('fiber') >+local ffi = require('ffi') >+ >+ffi.cdef([[ >+ bool >+ box_is_configured(void); >+]]) > > -- Function decorator that is used to prevent box.cfg() from > -- being called concurrently by different fibers. >@@ -517,14 +523,10 @@ setmetatable(box, { > end > }) > >--- Flag needed to keep immutable functions after box reconfiguration >-local box_loaded = false >- > local function load_cfg(cfg) > cfg = upgrade_cfg(cfg, translate_cfg) > cfg = prepare_cfg(cfg, default_cfg, template_cfg, modify_cfg) > apply_default_cfg(cfg, default_cfg); >- box_loaded = true > -- Save new box.cfg > box.cfg = cfg > if not pcall(private.cfg_check) then >@@ -562,24 +564,43 @@ local function load_cfg(cfg) > end > box.cfg = locked(load_cfg) > >+local function box_is_configured() >+ return ffi.C.box_is_configured() >+end >+ > -- >--- This makes possible do box.execute without calling box.cfg >--- manually. The load_cfg call overwrites following table and >--- metatable. >+-- box.execute is <box_load_and_execute> when box is not loaded, >+-- <lbox_execute> otherwise. See also <box_configured> variable. > -- >-function box.execute(...) >- -- >- -- Saving box.execute method before explicit calls to either >- -- box.execute() or box.cfg{} leads to implicit invocation of >- -- box.cfg nonetheless. The flag box_loaded makes sure execute >- -- is an immutable function meaning it won't be overwritten by >- -- any following attempts to reconfigure box. >+-- <box_load_and_execute> loads box and calls <lbox_execute>. >+-- >+local box_load_and_execute >+box_load_and_execute = function(...) >+ -- Configure box if it is not configured, no-op otherwise (not >+ -- reconfiguration). > -- >- if not box_loaded then >- load_cfg() >+ -- We should check whether box is configured, because a user >+ -- may save <box_load_and_execute> function before box loading >+ -- and call it afterwards. >+ if not box_is_configured() then >+ locked(function() >+ -- Re-check, because after releasing of the lock the >+ -- box state may be changed. We should call load_cfg() >+ -- only once. >+ if not box_is_configured() then >+ load_cfg() >+ end >+ end)() > end >+ >+ -- At this point box should be configured and box.execute() >+ -- function should be replaced with lbox_execute(). >+ assert(type(box.cfg) ~= 'function') >+ assert(box.execute ~= box_load_and_execute) >+ > return box.execute(...) > end >+box.execute = box_load_and_execute > > -- gh-810: > -- hack luajit default cpath -- Maria Khaydich [-- Attachment #2: Type: text/html, Size: 20249 bytes --] ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Tarantool-patches] [PATCH] box: make box.execute() immutable 2020-03-11 15:56 ` Maria Khaydich @ 2020-03-18 22:25 ` Igor Munkin 2020-05-02 14:52 ` Alexander Turenko 2020-05-12 16:16 ` Alexander Turenko 1 sibling, 1 reply; 31+ messages in thread From: Igor Munkin @ 2020-03-18 22:25 UTC (permalink / raw) To: Maria Khaydich; +Cc: tarantool-patches Masha, Thanks for the patch! I left a couple of comments below, please consider them. Side note: Sasha, there is much work done to solve the issue but we have a ticket[1] requesting to drop the "feature". Could you please write a rationale to proceed with this fix, instead of removing the implicit box.cfg call from of box.execute? On 11.03.20, Maria Khaydich wrote: > > Thank you for the review! I reworked the patch: > ---------------------------------------------------------------------- > Saving box.execute method before explicitly configuring box > automatically invokes load_cfg() nonetheless. Further calls > to box.cfg{} caused its reconfiguration and replacement of > previously saved box.execute meaning it couldn't be used > again without leading to an error. > > The patch introduces a workaround making box.execute idempotent > and is heavily influenced by @Totktonada. > > Closes #4231 > --- > Issue: > https://github.com/tarantool/tarantool/issues/4231 > Branch: > https://github.com/tarantool/tarantool/compare/eljashm/gh-4231-box.execute-immutable-function > > extra/exports | 2 + > src/box/lua/load_cfg.lua | 42 ++++++++++++++++--- > .../gh-4231-immutable-box-execute.test.lua | 28 +++++++++++++ > 3 files changed, 67 insertions(+), 5 deletions(-) > create mode 100755 test/box-tap/gh-4231-immutable-box-execute.test.lua <snipped> > diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua > index 85617c8f0..dc4293bdd 100644 > --- a/src/box/lua/load_cfg.lua > +++ b/src/box/lua/load_cfg.lua <snipped> > @@ -558,15 +564,41 @@ local function load_cfg(cfg) > end > box.cfg = locked(load_cfg) > > +local function box_is_configured() > + return ffi.C.box_is_configured() > +end > + > -- > --- This makes possible do box.execute without calling box.cfg > --- manually. The load_cfg call overwrites following table and > --- metatable. > +-- box.execute is <box_load_and_execute> when box is not loaded, > +-- <lbox_execute> otherwise. See also <box_configured> variable. > +-- <box_load_and_execute> loads box and calls <lbox_execute>. > -- > -function box.execute(...) > - load_cfg() > +local box_load_and_execute > +box_load_and_execute = function(...) > + -- Configure box if it is not configured, no-op otherwise (not > + -- reconfiguration). > + -- We should check whether box is configured, because a user > + -- may save <box_load_and_execute> function before box loading > + -- and call it afterwards. > + if not box_is_configured() then It's better to use a sole function here instead of creating a new one for every call. > + locked(function() > + -- Re-check, because after releasing of the lock the > + -- box state may be changed. We should call load_cfg() > + -- only once. > + if not box_is_configured() then > + load_cfg() > + end > + end)() > + end > + > + -- At this point box should be configured and box.execute() > + -- function should be replaced with lbox_execute(). > + assert(type(box.cfg) ~= 'function') > + assert(box.execute ~= box_load_and_execute) > + > return box.execute(...) > end > +box.execute = box_load_and_execute > > -- gh-810: > -- hack luajit default cpath > diff --git a/test/box-tap/gh-4231-immutable-box-execute.test.lua b/test/box-tap/gh-4231-immutable-box-execute.test.lua Minor: test chunk name is left unchanged since the previous version and doesn't respect the commit message wording. > new file mode 100755 > index 000000000..1544591bf > --- /dev/null > +++ b/test/box-tap/gh-4231-immutable-box-execute.test.lua > @@ -0,0 +1,28 @@ > +#!/usr/bin/env tarantool > +local tap = require('tap') > +local test = tap.test('execute') > +test:plan(2) > + > +-- > +-- gh-4231: box.execute should be an idempotent function > +-- meaning its effect should be the same if a user chooses > +-- to use it before explicit box.cfg invocation > +-- > + > +local function execute_is_immutable(execute, cmd, msg) Typo: s/immutable/idempotent/. > + local status, err = pcall(execute, cmd) > + test:ok(status and type(err) == 'table', msg) > +end > + > +local box_execute_stub = box.execute > +-- explicit call to load_cfg > +box.cfg{} > +local box_execute_actual = box.execute > + > +execute_is_immutable(box_execute_stub, > + "CREATE TABLE t1 (s1 INTEGER, PRIMARY KEY (s1));", > + "box.execute stub works before box.cfg") > +execute_is_immutable(box_execute_actual, "DROP TABLE t1", > + "box.execute works properly after box.cfg") > + > +os.exit(test:check() and 0 or 1) > -- > 2.24.0 <snipped> > > > -- > Maria Khaydich > [1]: https://github.com/tarantool/tarantool/issues/4726 -- Best regards, IM ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Tarantool-patches] [PATCH] box: make box.execute() immutable 2020-03-18 22:25 ` Igor Munkin @ 2020-05-02 14:52 ` Alexander Turenko 0 siblings, 0 replies; 31+ messages in thread From: Alexander Turenko @ 2020-05-02 14:52 UTC (permalink / raw) To: Igor Munkin; +Cc: tarantool-patches > Side note: Sasha, there is much work done to solve the issue but we have > a ticket[1] requesting to drop the "feature". Could you please write a > rationale to proceed with this fix, instead of removing the implicit > box.cfg call from of box.execute? > > [1]: https://github.com/tarantool/tarantool/issues/4726 There is no decision about #4726 and now we have the flaw in the feature: it should be fixed so. WBR, Alexander Turenko. ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Tarantool-patches] [PATCH] box: make box.execute() immutable 2020-03-11 15:56 ` Maria Khaydich 2020-03-18 22:25 ` Igor Munkin @ 2020-05-12 16:16 ` Alexander Turenko 1 sibling, 0 replies; 31+ messages in thread From: Alexander Turenko @ 2020-05-12 16:16 UTC (permalink / raw) To: Maria Khaydich; +Cc: tarantool-patches > >I considered using of `type(box.cfg) == 'function'` check as in > >tarantoolctl, but in fact it is not realiable: if box was not configured > >after box.cfg() due to an error (say, after `box.cfg{listen = > >'invalid'}`) the type of box.cfg will be 'table' and reload_cfg() will > >work on the next box.cfg() call. So we should use box_is_configured C > >function: > > > > | local ffi = require('ffi') > > | > > | ffi.cdef([[ > > | bool > > | box_is_configured(void); > > | ]]) > > | > > | local function box_is_configured() > > | return ffi.C.box_is_configured() > > | end I was not right here: `type(box.cfg)` is changed only at successful box configuration, however it is performed before full box loading that is not suitable for box.execute(). We can set a module local `box_is_configured` variable at end of box configuration to eliminate the ffi call. I'll update and resend the patchset soon. > >BTW, it seems that it is possible that <box_load_and_execute> will be > >called when `box.cfg{}` is already in progress in another fiber: this is > >why all load_cfg() / reload_cfg() calls are decorated using `locked` > >wrapper. It seems we should do the same in <box_load_and_execute>: > > > > | function box.execute(...) > > | if not box_is_configured() then > > | locked(function() > > | -- Re-check, because after the lock release the box > > | -- state may be changed. We should call load_cfg() > > | -- only once. > > | if not box_is_configured() then > > | load_cfg() > > | end > > | end)() > > | end > > | return box.execute(...) > > | end > > > >I experimented with this like so: > > > > | $ ./src/tarantool > > | tarantool> box_execute = box.execute > > | tarantool> for i = 1, 10 do require('fiber').create(function() require('log').info(require('yaml').encode((box_execute('SELECT * FROM "_vindex"')))) end) end I'll add such test case. ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Tarantool-patches] [PATCH 1/2] box: make box.cfg idempotent function 2020-02-20 17:51 ` Alexander Turenko 2020-02-20 21:15 ` Igor Munkin 2020-03-11 15:56 ` Maria Khaydich @ 2020-03-11 15:57 ` Maria Khaydich 2020-03-12 13:29 ` Konstantin Osipov 2020-03-18 22:26 ` Igor Munkin 2 siblings, 2 replies; 31+ messages in thread From: Maria Khaydich @ 2020-03-11 15:57 UTC (permalink / raw) To: Alexander Turenko; +Cc: tarantool-patches [-- Attachment #1: Type: text/plain, Size: 15759 bytes --] Calling box.cfg{} more than once does not normally cause any errors (even though it might not have any effect). In contrast, assigning it to some variable and then using it after the box was configured caused an error since the method was overwritten by the initial call of <load_cfg>. The patch fixes this issue making box.cfg behave consistently in both scenarios and is a follow-up for box: make box.execute idempotent function. Follow-up #4231 --- Issue: https://github.com/tarantool/tarantool/issues/4231 Branch: https://github.com/tarantool/tarantool/compare/eljashm/gh-4231-box.execute-immutable-function src/box/lua/load_cfg.lua | 12 ++++--- .../gh-4231-immutable-box-execute.test.lua | 34 ++++++++++++------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua index dc4293bdd..6753be6f3 100644 --- a/src/box/lua/load_cfg.lua +++ b/src/box/lua/load_cfg.lua @@ -523,7 +523,15 @@ setmetatable(box, { end }) +local function box_is_configured() + return ffi.C.box_is_configured() +end + local function load_cfg(cfg) + if box_is_configured() then + reload_cfg(cfg) + return + end cfg = upgrade_cfg(cfg, translate_cfg) cfg = prepare_cfg(cfg, default_cfg, template_cfg, modify_cfg) apply_default_cfg(cfg, default_cfg); @@ -564,10 +572,6 @@ local function load_cfg(cfg) end box.cfg = locked(load_cfg) -local function box_is_configured() - return ffi.C.box_is_configured() -end - -- -- box.execute is <box_load_and_execute> when box is not loaded, -- <lbox_execute> otherwise. See also <box_configured> variable. diff --git a/test/box-tap/gh-4231-immutable-box-execute.test.lua b/test/box-tap/gh-4231-immutable-box-execute.test.lua index 1544591bf..49aad154b 100755 --- a/test/box-tap/gh-4231-immutable-box-execute.test.lua +++ b/test/box-tap/gh-4231-immutable-box-execute.test.lua @@ -1,28 +1,38 @@ #!/usr/bin/env tarantool local tap = require('tap') local test = tap.test('execute') -test:plan(2) +test:plan(4) -- --- gh-4231: box.execute should be an idempotent function --- meaning its effect should be the same if a user chooses --- to use it before explicit box.cfg invocation +-- gh-4231: box.execute should be an idempotent function meaning +-- its effect should be the same if the user chooses to save it +-- before explicit box.cfg{} invocation and use the saved version +-- afterwards. +-- Within the scope of the same issue box.cfg method should also +-- be kept idempotent for the same reasons. -- -local function execute_is_immutable(execute, cmd, msg) - local status, err = pcall(execute, cmd) - test:ok(status and type(err) == 'table', msg) -end - local box_execute_stub = box.execute --- explicit call to load_cfg +local box_cfg_stub = box.cfg + +-- Explicit box configuration that used to change the behavior. box.cfg{} + local box_execute_actual = box.execute +local box_cfg_actual = box.cfg -execute_is_immutable(box_execute_stub, +local function is_idempotent(method, cmd, msg) + local status, err = pcall(method, cmd) + test:ok(status, msg, nil, err) +end + +is_idempotent(box_execute_stub, "CREATE TABLE t1 (s1 INTEGER, PRIMARY KEY (s1));", "box.execute stub works before box.cfg") -execute_is_immutable(box_execute_actual, "DROP TABLE t1", +is_idempotent(box_execute_actual, "DROP TABLE t1", "box.execute works properly after box.cfg") +is_idempotent(box_cfg_stub, nil, "box.cfg stub works properly") +is_idempotent(box_cfg_actual, nil, "box.cfg after configuration") + os.exit(test:check() and 0 or 1) -- 2.24.0 >Четверг, 20 февраля 2020, 20:51 +03:00 от Alexander Turenko <alexander.turenko@tarantool.org>: > >Sorry for the late response. > >See comments below. > >While looking into the patch, experimenting and commenting I made the >patch (it is based on your changes), so I'll paste it at end of the >email for the reference. > >WBR, Alexander Turenko. > >> commit 573318ea8749931741247f181333ab68b43a82c6 >> Author: Maria < maria.khaydich@tarantool.org > >> Date: Tue Oct 29 17:56:51 2019 +0300 >> >> box: box.execute should be immutable function > >Now I recalled the right term: idempotent. > >Nit: it would be good to use imperative mood in the commit header: > > | Use the imperative mood in the subject line. A properly formed Git > | commit subject line should always be able to complete the following > | sentence: “If applied, this commit will /your subject line here/”. > >https://www.tarantool.io/en/doc/1.10/dev_guide/developer_guidelines/#how-to-write-a-commit-message > >> >> Using box.execute method before explicitly configuring box >> automatically invoked box.cfg nonetheless. Any further calls >> to box.cfg caused its reconfiguration which then led to an >> error when trying to use execute method again. > >Sorry that I nitpick around wording again, but after the description I >would check something like the following: > > | box.execute('SELECT 1') -- here box.cfg{} is called under hood > | box.execute('SELECT 1') -- everything looks ok > >After that I would be confused, because everything works as expected. > >I would say that there are two different functions ><box_load_and_execute> (which is assigned to box.execute when box is not >configured) and <lbox_execute> (after box confguration) and would >describe the case using those terms. I guess it would easier to >understand. > >See also the comment about the test at very end of the email. > >> >> The patch introduces a fix making box.execute immutable. >> >> Closes #4231 >> >> diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua >> index 85617c8f0..1f9b4392f 100644 >> --- a/src/box/lua/load_cfg.lua >> +++ b/src/box/lua/load_cfg.lua >> @@ -517,10 +517,14 @@ setmetatable(box, { >> end >> }) >> >> +-- Flag needed to keep immutable functions after box reconfiguration > >Nit: over 66 symbols. > >> +local box_loaded = false >> + >> local function load_cfg(cfg) >> cfg = upgrade_cfg(cfg, translate_cfg) >> cfg = prepare_cfg(cfg, default_cfg, template_cfg, modify_cfg) >> apply_default_cfg(cfg, default_cfg); >> + box_loaded = true > >After this we can failed to configure box, consider the case: > > | tarantool> box.cfg{listen = 'incorrect'} > | --- > | - error: 'Incorrect value for option ''listen'': expected host:service or /unix.socket' > | ... > | > | tarantool> box.execute('SELECT 1') > >We should set the flag only at successful box configuration. I would >also add such test case. > >> -- Save new box.cfg >> box.cfg = cfg >> if not pcall(private.cfg_check) then >> @@ -564,7 +568,16 @@ box.cfg = locked(load_cfg) >> -- metatable. >> -- >> function box.execute(...) >> - load_cfg() >> + -- >> + -- Saving box.execute method before explicit calls to either >> + -- box.execute() or box.cfg{} leads to implicit invocation of >> + -- box.cfg nonetheless. > >Technically saving of box.execute does not lead to invocation of >box.cfg. But anyway I would describe things in the way as proposed >above. > >> + -- The flag box_loaded makes sure execute >> + -- is an immutable function meaning it won't be overwritten by >> + -- any following attempts to reconfigure box. >> + -- > >The problem is not that <lbox_execute> will be overwritten with some ><box_another_execute>, but that the initial <box_load_and_execute> does >not work correctly after successful box configuration. > >> + if not box_loaded then >> + load_cfg() >> + end > >I considered using of `type(box.cfg) == 'function'` check as in >tarantoolctl, but in fact it is not realiable: if box was not configured >after box.cfg() due to an error (say, after `box.cfg{listen = >'invalid'}`) the type of box.cfg will be 'table' and reload_cfg() will >work on the next box.cfg() call. So we should use box_is_configured C >function: > > | local ffi = require('ffi') > | > | ffi.cdef([[ > | bool > | box_is_configured(void); > | ]]) > | > | local function box_is_configured() > | return ffi.C.box_is_configured() > | end > >This way requires to add the function into extra/exports. > >BTW, it seems that it is possible that <box_load_and_execute> will be >called when `box.cfg{}` is already in progress in another fiber: this is >why all load_cfg() / reload_cfg() calls are decorated using `locked` >wrapper. It seems we should do the same in <box_load_and_execute>: > > | function box.execute(...) > | if not box_is_configured() then > | locked(function() > | -- Re-check, because after the lock release the box > | -- state may be changed. We should call load_cfg() > | -- only once. > | if not box_is_configured() then > | load_cfg() > | end > | end)() > | end > | return box.execute(...) > | end > >I experimented with this like so: > > | $ ./src/tarantool > | tarantool> box_execute = box.execute > | tarantool> for i = 1, 10 do require('fiber').create(function() require('log').info(require('yaml').encode((box_execute('SELECT * FROM "_vindex"')))) end) end > >While looking into the code I found one more case: > > | tarantool> box_cfg = box.cfg > | --- > | ... > | tarantool> box_cfg() > | <...> > | tarantool> box_cfg() > | --- > | - error: 'builtin/box/load_cfg.lua:19: builtin/box/load_cfg.lua:547: bad argument > | #1 to ''pairs'' (table expected, got nil)' > | ... > >I think it does NOT mean that we should not fix box.execute() code, >because the expected behaviour is a bit different: > >* box.execute() (more specifically <box_load_and_execute>) should > configure box if it is not configured or just execute otherwise (w/o > box reconfiguration). >* box.cfg() (more specifically <load_cfg>) should configure box if it is > not configured, otherwise **reconfigure** it. > >So box.cfg() should call reload_cfg() if box is already configured. I >propose to fix it in a separate patch (but within the scope of the >issue). > >> return box.execute(...) >> end >> >> diff --git a/test/box-tap/gh-4231-immutable-box-execute.test.lua b/test/box-tap/gh-4231-immutable-box-execute.test.lua >> new file mode 100755 >> index 000000000..5bdbec88f >> --- /dev/null >> +++ b/test/box-tap/gh-4231-immutable-box-execute.test.lua >> @@ -0,0 +1,33 @@ >> +#!/usr/bin/env tarantool >> +local tap = require('tap') >> +local test = tap.test('execute') >> +test:plan(3) >> + >> +-- >> +-- gh-4231: box.execute should be immutable function meaning it's >> +-- address doesn't change after first box.cfg implicit invocation > >But it is not so even after the patch: > > | tarantool> box.execute > | --- > | - 'function: 0x4074bc30' > | ... > | tarantool> box.execute('SELECT 1') > | <...> > | tarantool> box.execute > | --- > | - 'function: 0x416b2600' > | ... > >> +-- >> + >> +local function execute_is_immutable(execute, cmd, msg) >> + local status, err = pcall(function() >> + execute(cmd) >> + end) > >Nit: Can be written as: > > | local status, err = pcall(execute, cmd) > >> + test:ok(status and err == nil, msg) >> +end >> + >> +local box_execute_stub = box.execute >> +execute_is_immutable(box_execute_stub, "SELECT 1", >> + "execute does not work properly before box.cfg") > >This will print: > >ok - execute does not work properly before box.cfg > >--that looks counter-intuitive for me. > >BTW, it looks as the preparation code for the test rather than the test >itself. Personally I think that such code should do assert() rather than >produce 'ok/not ok' TAP13 output. This is not the strict requirement, >however. > >Consider [1], from words 'I would split test preparation / clean up code >from actual test cases'. > >[1]: https://lists.tarantool.org/pipermail/tarantool-patches/2020-January/013595.html > >> + >> +local box_execute_actual = box.execute >> +-- explicit call to load_cfg >> +box.cfg{} >> + >> +-- checking the function was not reconfigured, i.e. adress stays the same > >Typo: adress -> address. > >> +test:is(box_execute_actual, box.execute, >> + "execute is not the same after box.cfg") >> +execute_is_immutable(box_execute_actual, >> + "CREATE TABLE t1 (s1 INTEGER, PRIMARY KEY (s1));", >> + "execute does not work properly after box.cfg") >> + >> +os.exit(test:check() and 0 or 1) > >The test case works properly (does not fail) on current master w/o the >fix. I guess you intend to test box_execute_stub after box.cfg(). > >BTW, I suggest to run a test on a tarantool version before a fix to >verify that the test actually able to catch the problem. > >---- > >diff --git a/extra/exports b/extra/exports >index 7b84a1452..8599614ee 100644 >--- a/extra/exports >+++ b/extra/exports >@@ -118,6 +118,8 @@ swim_member_unref > swim_member_is_dropped > swim_member_is_payload_up_to_date > >+box_is_configured >+ > # Module API > > _say >diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua >index 1f9b4392f..dfff772d7 100644 >--- a/src/box/lua/load_cfg.lua >+++ b/src/box/lua/load_cfg.lua >@@ -6,6 +6,12 @@ local private = require('box.internal') > local urilib = require('uri') > local math = require('math') > local fiber = require('fiber') >+local ffi = require('ffi') >+ >+ffi.cdef([[ >+ bool >+ box_is_configured(void); >+]]) > > -- Function decorator that is used to prevent box.cfg() from > -- being called concurrently by different fibers. >@@ -517,14 +523,10 @@ setmetatable(box, { > end > }) > >--- Flag needed to keep immutable functions after box reconfiguration >-local box_loaded = false >- > local function load_cfg(cfg) > cfg = upgrade_cfg(cfg, translate_cfg) > cfg = prepare_cfg(cfg, default_cfg, template_cfg, modify_cfg) > apply_default_cfg(cfg, default_cfg); >- box_loaded = true > -- Save new box.cfg > box.cfg = cfg > if not pcall(private.cfg_check) then >@@ -562,24 +564,43 @@ local function load_cfg(cfg) > end > box.cfg = locked(load_cfg) > >+local function box_is_configured() >+ return ffi.C.box_is_configured() >+end >+ > -- >--- This makes possible do box.execute without calling box.cfg >--- manually. The load_cfg call overwrites following table and >--- metatable. >+-- box.execute is <box_load_and_execute> when box is not loaded, >+-- <lbox_execute> otherwise. See also <box_configured> variable. > -- >-function box.execute(...) >- -- >- -- Saving box.execute method before explicit calls to either >- -- box.execute() or box.cfg{} leads to implicit invocation of >- -- box.cfg nonetheless. The flag box_loaded makes sure execute >- -- is an immutable function meaning it won't be overwritten by >- -- any following attempts to reconfigure box. >+-- <box_load_and_execute> loads box and calls <lbox_execute>. >+-- >+local box_load_and_execute >+box_load_and_execute = function(...) >+ -- Configure box if it is not configured, no-op otherwise (not >+ -- reconfiguration). > -- >- if not box_loaded then >- load_cfg() >+ -- We should check whether box is configured, because a user >+ -- may save <box_load_and_execute> function before box loading >+ -- and call it afterwards. >+ if not box_is_configured() then >+ locked(function() >+ -- Re-check, because after releasing of the lock the >+ -- box state may be changed. We should call load_cfg() >+ -- only once. >+ if not box_is_configured() then >+ load_cfg() >+ end >+ end)() > end >+ >+ -- At this point box should be configured and box.execute() >+ -- function should be replaced with lbox_execute(). >+ assert(type(box.cfg) ~= 'function') >+ assert(box.execute ~= box_load_and_execute) >+ > return box.execute(...) > end >+box.execute = box_load_and_execute > > -- gh-810: > -- hack luajit default cpath -- Maria Khaydich [-- Attachment #2: Type: text/html, Size: 19132 bytes --] ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Tarantool-patches] [PATCH 1/2] box: make box.cfg idempotent function 2020-03-11 15:57 ` [Tarantool-patches] [PATCH 1/2] box: make box.cfg idempotent function Maria Khaydich @ 2020-03-12 13:29 ` Konstantin Osipov 2020-03-12 19:25 ` Maria Khaydich 2020-03-18 22:26 ` Igor Munkin 1 sibling, 1 reply; 31+ messages in thread From: Konstantin Osipov @ 2020-03-12 13:29 UTC (permalink / raw) To: Maria Khaydich; +Cc: tarantool-patches * Maria Khaydich <maria.khaydich@tarantool.org> [20/03/11 19:02]: > > Calling box.cfg{} more than once does not normally cause any errors > (even though it might not have any effect). In contrast, assigning > it to some variable and then using it after the box was configured > caused an error since the method was overwritten by the initial call > of <load_cfg>. > > The patch fixes this issue making box.cfg behave consistently in both > scenarios and is a follow-up for box: make box.execute idempotent function. Did you benchmark it? > > Follow-up #4231 > --- > Issue: > https://github.com/tarantool/tarantool/issues/4231 > Branch: > https://github.com/tarantool/tarantool/compare/eljashm/gh-4231-box.execute-immutable-function -- Konstantin Osipov, Moscow, Russia ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Tarantool-patches] [PATCH 1/2] box: make box.cfg idempotent function 2020-03-12 13:29 ` Konstantin Osipov @ 2020-03-12 19:25 ` Maria Khaydich 2020-03-12 20:00 ` Konstantin Osipov 0 siblings, 1 reply; 31+ messages in thread From: Maria Khaydich @ 2020-03-12 19:25 UTC (permalink / raw) To: Konstantin Osipov; +Cc: tarantool-patches [-- Attachment #1: Type: text/plain, Size: 1080 bytes --] >Четверг, 12 марта 2020, 16:29 +03:00 от Konstantin Osipov <kostja.osipov@gmail.com>: > >* Maria Khaydich < maria.khaydich@tarantool.org > [20/03/11 19:02]: >> >> Calling box.cfg{} more than once does not normally cause any errors >> (even though it might not have any effect). In contrast, assigning >> it to some variable and then using it after the box was configured >> caused an error since the method was overwritten by the initial call >> of <load_cfg>. >> >> The patch fixes this issue making box.cfg behave consistently in both >> scenarios and is a follow-up for box: make box.execute idempotent function. > >Did you benchmark it? Do you think we need to? There’s basically one extra condition in the patch. I don’t see how it might degrade performance. > >> >> Follow-up #4231 >> --- >> Issue: >> https://github.com/tarantool/tarantool/issues/4231 >> Branch: >> https://github.com/tarantool/tarantool/compare/eljashm/gh-4231-box.execute-immutable-function > >-- >Konstantin Osipov, Moscow, Russia -- Maria Khaydich [-- Attachment #2: Type: text/html, Size: 2103 bytes --] ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Tarantool-patches] [PATCH 1/2] box: make box.cfg idempotent function 2020-03-12 19:25 ` Maria Khaydich @ 2020-03-12 20:00 ` Konstantin Osipov 2020-03-18 22:26 ` Igor Munkin 0 siblings, 1 reply; 31+ messages in thread From: Konstantin Osipov @ 2020-03-12 20:00 UTC (permalink / raw) To: Maria Khaydich; +Cc: tarantool-patches * Maria Khaydich <maria.khaydich@tarantool.org> [20/03/12 22:26]: > >> Calling box.cfg{} more than once does not normally cause any errors > >> (even though it might not have any effect). In contrast, assigning > >> it to some variable and then using it after the box was configured > >> caused an error since the method was overwritten by the initial call > >> of <load_cfg>. > >> > >> The patch fixes this issue making box.cfg behave consistently in both > >> scenarios and is a follow-up for box: make box.execute idempotent function. > > > >Did you benchmark it? > > Do you think we need to? There’s basically one extra condition > in the patch. I don’t see how it might degrade performance. It's not a one more condition, it's one more FFI C call. -- Konstantin Osipov, Moscow, Russia ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Tarantool-patches] [PATCH 1/2] box: make box.cfg idempotent function 2020-03-12 20:00 ` Konstantin Osipov @ 2020-03-18 22:26 ` Igor Munkin 2020-03-19 7:19 ` Konstantin Osipov 0 siblings, 1 reply; 31+ messages in thread From: Igor Munkin @ 2020-03-18 22:26 UTC (permalink / raw) To: Konstantin Osipov; +Cc: tarantool-patches Kostja, On 12.03.20, Konstantin Osipov wrote: > * Maria Khaydich <maria.khaydich@tarantool.org> [20/03/12 22:26]: > > >> Calling box.cfg{} more than once does not normally cause any errors > > >> (even though it might not have any effect). In contrast, assigning > > >> it to some variable and then using it after the box was configured > > >> caused an error since the method was overwritten by the initial call > > >> of <load_cfg>. > > >> > > >> The patch fixes this issue making box.cfg behave consistently in both > > >> scenarios and is a follow-up for box: make box.execute idempotent function. > > > > > >Did you benchmark it? > > > > Do you think we need to? There’s basically one extra condition > > in the patch. I don’t see how it might degrade performance. > > It's not a one more condition, it's one more FFI C call. I guess the problem have to be fixed anyway. However you might suggest another fix for the issue? There are several other ways to indicate whether box is configured, e.g. introduce the specific value to the box table. What do you think? I see for now box.cfg call as not the one performance critical, but I might be missing something you see. It would be great if you detailed a bit your proposal regarding the fix and its benchmarks. > > -- > Konstantin Osipov, Moscow, Russia -- Best regards, IM ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Tarantool-patches] [PATCH 1/2] box: make box.cfg idempotent function 2020-03-18 22:26 ` Igor Munkin @ 2020-03-19 7:19 ` Konstantin Osipov 2020-03-19 9:08 ` Igor Munkin 2020-05-06 11:17 ` Alexander Turenko 0 siblings, 2 replies; 31+ messages in thread From: Konstantin Osipov @ 2020-03-19 7:19 UTC (permalink / raw) To: Igor Munkin; +Cc: tarantool-patches * Igor Munkin <imun@tarantool.org> [20/03/19 10:08]: > I guess the problem have to be fixed anyway. > > However you might suggest another fix for the issue? There are several > other ways to indicate whether box is configured, e.g. introduce the > specific value to the box table. What do you think? Why not set a lua variable *from* C instead of calling from Lua *into* C each time? I mean, this is an obvious optimization, but it is only worth it if there is a measurable slowdown (which I suspect there is, at least a couple of %, but even a couple of % IMHO justify it). > I see for now box.cfg call as not the one performance critical, but I > might be missing something you see. > > It would be great if you detailed a bit your proposal regarding the fix > and its benchmarks. -- Konstantin Osipov, Moscow, Russia ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Tarantool-patches] [PATCH 1/2] box: make box.cfg idempotent function 2020-03-19 7:19 ` Konstantin Osipov @ 2020-03-19 9:08 ` Igor Munkin 2020-03-19 10:06 ` Konstantin Osipov 2020-05-06 11:17 ` Alexander Turenko 1 sibling, 1 reply; 31+ messages in thread From: Igor Munkin @ 2020-03-19 9:08 UTC (permalink / raw) To: Konstantin Osipov, Alexander Turenko; +Cc: tarantool-patches Kostja, On 19.03.20, Konstantin Osipov wrote: > * Igor Munkin <imun@tarantool.org> [20/03/19 10:08]: > > I guess the problem have to be fixed anyway. > > > > However you might suggest another fix for the issue? There are several > > other ways to indicate whether box is configured, e.g. introduce the > > specific value to the box table. What do you think? > > Why not set a lua variable *from* C instead of calling from Lua > *into* C each time? I guess we talk about the same thing. > > I mean, this is an obvious optimization, but it is only worth it > if there is a measurable slowdown (which I suspect there is, at > least a couple of %, but even a couple of % IMHO justify it). I'm OK with your proposal (but I still don't see the box.cfg as a performance bottleneck). Sasha, any thoughts? > > > I see for now box.cfg call as not the one performance critical, but I > > might be missing something you see. > > > > It would be great if you detailed a bit your proposal regarding the fix > > and its benchmarks. > > -- > Konstantin Osipov, Moscow, Russia -- Best regards, IM ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Tarantool-patches] [PATCH 1/2] box: make box.cfg idempotent function 2020-03-19 9:08 ` Igor Munkin @ 2020-03-19 10:06 ` Konstantin Osipov 2020-03-19 10:26 ` Igor Munkin 0 siblings, 1 reply; 31+ messages in thread From: Konstantin Osipov @ 2020-03-19 10:06 UTC (permalink / raw) To: Igor Munkin; +Cc: tarantool-patches * Igor Munkin <imun@tarantool.org> [20/03/19 12:17]: > > I mean, this is an obvious optimization, but it is only worth it > > if there is a measurable slowdown (which I suspect there is, at > > least a couple of %, but even a couple of % IMHO justify it). > > I'm OK with your proposal (but I still don't see the box.cfg as a > performance bottleneck). > > Sasha, any thoughts? box.cfg{} is *not* the bottleneck. box.execute() is, it is having a call to ffi c function now. -- Konstantin Osipov, Moscow, Russia ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Tarantool-patches] [PATCH 1/2] box: make box.cfg idempotent function 2020-03-19 10:06 ` Konstantin Osipov @ 2020-03-19 10:26 ` Igor Munkin 0 siblings, 0 replies; 31+ messages in thread From: Igor Munkin @ 2020-03-19 10:26 UTC (permalink / raw) To: Konstantin Osipov; +Cc: tarantool-patches Kostja, On 19.03.20, Konstantin Osipov wrote: > * Igor Munkin <imun@tarantool.org> [20/03/19 12:17]: > > > I mean, this is an obvious optimization, but it is only worth it > > > if there is a measurable slowdown (which I suspect there is, at > > > least a couple of %, but even a couple of % IMHO justify it). > > > > I'm OK with your proposal (but I still don't see the box.cfg as a > > performance bottleneck). > > > > Sasha, any thoughts? > > box.cfg{} is *not* the bottleneck. > box.execute() is, it is having a call to ffi c function now. I was misled, since you commented the patch with box.cfg related changes. Now the performance issue is clear, thanks. > > > -- > Konstantin Osipov, Moscow, Russia -- Best regards, IM ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Tarantool-patches] [PATCH 1/2] box: make box.cfg idempotent function 2020-03-19 7:19 ` Konstantin Osipov 2020-03-19 9:08 ` Igor Munkin @ 2020-05-06 11:17 ` Alexander Turenko 2020-05-06 11:49 ` Konstantin Osipov 1 sibling, 1 reply; 31+ messages in thread From: Alexander Turenko @ 2020-05-06 11:17 UTC (permalink / raw) To: Konstantin Osipov; +Cc: tarantool-patches > > However you might suggest another fix for the issue? There are several > > other ways to indicate whether box is configured, e.g. introduce the > > specific value to the box table. What do you think? > > Why not set a lua variable *from* C instead of calling from Lua > *into* C each time? This way it will be slower when called from C. Since we unable to 'unconfigure' box I would just cache C's value in Lua. C's box_is_configured() is used only in box.session.su() and its performance is not so critical as box.execute(). However I don't see a reason to slowdown C's box_is_configured()() if we can avoid it: it may be important if it will be called from some other code. I don't sure, but storing database settings and state in Lua looks a bit lopsided approach for me: even now we have three languages: C, Lua and SQL. Some caching, hovewer, is okay. > I mean, this is an obvious optimization, but it is only worth it > if there is a measurable slowdown (which I suspect there is, at > least a couple of %, but even a couple of % IMHO justify it). I failed to obtain stable results and maybe there is a difference, but I don't see it now. https://gist.github.com/Totktonada/407855389ed4da93bf0175cf8a11c7b9 I made those measurements on fixed CPU frequency and 10 times run each implementation 10 times: 300 runs at whole. I see that results becomes worse for all implementations from run to run. Looks strange. WBR, Alexander Turenko. ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Tarantool-patches] [PATCH 1/2] box: make box.cfg idempotent function 2020-05-06 11:17 ` Alexander Turenko @ 2020-05-06 11:49 ` Konstantin Osipov 2020-05-06 12:53 ` Alexander Turenko 0 siblings, 1 reply; 31+ messages in thread From: Konstantin Osipov @ 2020-05-06 11:49 UTC (permalink / raw) To: Alexander Turenko; +Cc: tarantool-patches * Alexander Turenko <alexander.turenko@tarantool.org> [20/05/06 14:17]: > https://gist.github.com/Totktonada/407855389ed4da93bf0175cf8a11c7b9 > > I made those measurements on fixed CPU frequency and 10 times run each > implementation 10 times: 300 runs at whole. I see that results becomes > worse for all implementations from run to run. Looks strange. Try with jit off? -- Konstantin Osipov, Moscow, Russia ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Tarantool-patches] [PATCH 1/2] box: make box.cfg idempotent function 2020-05-06 11:49 ` Konstantin Osipov @ 2020-05-06 12:53 ` Alexander Turenko 2020-05-06 13:02 ` Konstantin Osipov 0 siblings, 1 reply; 31+ messages in thread From: Alexander Turenko @ 2020-05-06 12:53 UTC (permalink / raw) To: Konstantin Osipov; +Cc: tarantool-patches On Wed, May 06, 2020 at 02:49:21PM +0300, Konstantin Osipov wrote: > * Alexander Turenko <alexander.turenko@tarantool.org> [20/05/06 14:17]: > > https://gist.github.com/Totktonada/407855389ed4da93bf0175cf8a11c7b9 > > > > I made those measurements on fixed CPU frequency and 10 times run each > > implementation 10 times: 300 runs at whole. I see that results becomes > > worse for all implementations from run to run. Looks strange. > > Try with jit off? Are there any production setup with jit.off()? This measurement would be artificial I think. Anyway, I collected the results and they are quite noisy again (~10% variation). I would not say anything based on them. But in average ffi call gives -0.5% (worse) and ffi call with caching -1.0% from the baseline (master). Maybe it is just noise. WBR, Alexander Turenko. ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Tarantool-patches] [PATCH 1/2] box: make box.cfg idempotent function 2020-05-06 12:53 ` Alexander Turenko @ 2020-05-06 13:02 ` Konstantin Osipov 2020-05-06 13:13 ` Alexander Turenko 0 siblings, 1 reply; 31+ messages in thread From: Konstantin Osipov @ 2020-05-06 13:02 UTC (permalink / raw) To: Alexander Turenko; +Cc: tarantool-patches * Alexander Turenko <alexander.turenko@tarantool.org> [20/05/06 15:58]: > On Wed, May 06, 2020 at 02:49:21PM +0300, Konstantin Osipov wrote: > > * Alexander Turenko <alexander.turenko@tarantool.org> [20/05/06 14:17]: > > > https://gist.github.com/Totktonada/407855389ed4da93bf0175cf8a11c7b9 > > > > > > I made those measurements on fixed CPU frequency and 10 times run each > > > implementation 10 times: 300 runs at whole. I see that results becomes > > > worse for all implementations from run to run. Looks strange. > > > > Try with jit off? > > Are there any production setup with jit.off()? This measurement would be > artificial I think. Why do you think you can assume that this trace will be jited in production? > Anyway, I collected the results and they are quite noisy again (~10% > variation). I would not say anything based on them. But in average ffi > call gives -0.5% (worse) and ffi call with caching -1.0% from the > baseline (master). Maybe it is just noise. > > WBR, Alexander Turenko. -- Konstantin Osipov, Moscow, Russia https://scylladb.com ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Tarantool-patches] [PATCH 1/2] box: make box.cfg idempotent function 2020-05-06 13:02 ` Konstantin Osipov @ 2020-05-06 13:13 ` Alexander Turenko 0 siblings, 0 replies; 31+ messages in thread From: Alexander Turenko @ 2020-05-06 13:13 UTC (permalink / raw) To: Konstantin Osipov; +Cc: tarantool-patches On Wed, May 06, 2020 at 04:02:09PM +0300, Konstantin Osipov wrote: > * Alexander Turenko <alexander.turenko@tarantool.org> [20/05/06 15:58]: > > On Wed, May 06, 2020 at 02:49:21PM +0300, Konstantin Osipov wrote: > > > * Alexander Turenko <alexander.turenko@tarantool.org> [20/05/06 14:17]: > > > > https://gist.github.com/Totktonada/407855389ed4da93bf0175cf8a11c7b9 > > > > > > > > I made those measurements on fixed CPU frequency and 10 times run each > > > > implementation 10 times: 300 runs at whole. I see that results becomes > > > > worse for all implementations from run to run. Looks strange. > > > > > > Try with jit off? > > > > Are there any production setup with jit.off()? This measurement would be > > artificial I think. > > Why do you think you can assume that this trace will be jited in production? Okay, good point. ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Tarantool-patches] [PATCH 1/2] box: make box.cfg idempotent function 2020-03-11 15:57 ` [Tarantool-patches] [PATCH 1/2] box: make box.cfg idempotent function Maria Khaydich 2020-03-12 13:29 ` Konstantin Osipov @ 2020-03-18 22:26 ` Igor Munkin 2020-05-12 16:17 ` Alexander Turenko 1 sibling, 1 reply; 31+ messages in thread From: Igor Munkin @ 2020-03-18 22:26 UTC (permalink / raw) To: Maria Khaydich; +Cc: tarantool-patches Masha, Thanks for the patch! Please consider my comments below. On 11.03.20, Maria Khaydich wrote: > > Calling box.cfg{} more than once does not normally cause any errors > (even though it might not have any effect). In contrast, assigning > it to some variable and then using it after the box was configured > caused an error since the method was overwritten by the initial call > of <load_cfg>. > > The patch fixes this issue making box.cfg behave consistently in both > scenarios and is a follow-up for box: make box.execute idempotent function. > > Follow-up #4231 > --- > Issue: > https://github.com/tarantool/tarantool/issues/4231 > Branch: > https://github.com/tarantool/tarantool/compare/eljashm/gh-4231-box.execute-immutable-function > > src/box/lua/load_cfg.lua | 12 ++++--- > .../gh-4231-immutable-box-execute.test.lua | 34 ++++++++++++------- > 2 files changed, 30 insertions(+), 16 deletions(-) > diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua > index dc4293bdd..6753be6f3 100644 > --- a/src/box/lua/load_cfg.lua > +++ b/src/box/lua/load_cfg.lua > @@ -523,7 +523,15 @@ setmetatable(box, { > end > }) > > +local function box_is_configured() > + return ffi.C.box_is_configured() > +end > + Minor: Since box_is_configured is introduced within this patchset it could be placed properly in the first patch of the series. Feel free to ignore. > local function load_cfg(cfg) > + if box_is_configured() then > + reload_cfg(cfg) > + return > + end > cfg = upgrade_cfg(cfg, translate_cfg) > cfg = prepare_cfg(cfg, default_cfg, template_cfg, modify_cfg) > apply_default_cfg(cfg, default_cfg); <snipped> > diff --git a/test/box-tap/gh-4231-immutable-box-execute.test.lua b/test/box-tap/gh-4231-immutable-box-execute.test.lua Minor: test chunk name is left unchanged since the previous version and doesn't respect the commit message wording. > index 1544591bf..49aad154b 100755 > --- a/test/box-tap/gh-4231-immutable-box-execute.test.lua > +++ b/test/box-tap/gh-4231-immutable-box-execute.test.lua > @@ -1,28 +1,38 @@ > #!/usr/bin/env tarantool > local tap = require('tap') > local test = tap.test('execute') > -test:plan(2) > +test:plan(4) > > -- > --- gh-4231: box.execute should be an idempotent function > --- meaning its effect should be the same if a user chooses > --- to use it before explicit box.cfg invocation > +-- gh-4231: box.execute should be an idempotent function meaning > +-- its effect should be the same if the user chooses to save it > +-- before explicit box.cfg{} invocation and use the saved version > +-- afterwards. > +-- Within the scope of the same issue box.cfg method should also > +-- be kept idempotent for the same reasons. > -- > > -local function execute_is_immutable(execute, cmd, msg) > - local status, err = pcall(execute, cmd) > - test:ok(status and type(err) == 'table', msg) > -end > - > local box_execute_stub = box.execute > --- explicit call to load_cfg > +local box_cfg_stub = box.cfg > + > +-- Explicit box configuration that used to change the behavior. > box.cfg{} > + > local box_execute_actual = box.execute > +local box_cfg_actual = box.cfg > > -execute_is_immutable(box_execute_stub, > +local function is_idempotent(method, cmd, msg) Minor: IMHO these changes are better to be moved to the first patch of the series. Feel free to ignore. > + local status, err = pcall(method, cmd) > + test:ok(status, msg, nil, err) > +end > + > +is_idempotent(box_execute_stub, > "CREATE TABLE t1 (s1 INTEGER, PRIMARY KEY (s1));", > "box.execute stub works before box.cfg") > -execute_is_immutable(box_execute_actual, "DROP TABLE t1", > +is_idempotent(box_execute_actual, "DROP TABLE t1", > "box.execute works properly after box.cfg") > > +is_idempotent(box_cfg_stub, nil, "box.cfg stub works properly") > +is_idempotent(box_cfg_actual, nil, "box.cfg after configuration") > + > os.exit(test:check() and 0 or 1) > -- > 2.24.0 <snipped> > > > -- > Maria Khaydich > -- Best regards, IM ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Tarantool-patches] [PATCH 1/2] box: make box.cfg idempotent function 2020-03-18 22:26 ` Igor Munkin @ 2020-05-12 16:17 ` Alexander Turenko 0 siblings, 0 replies; 31+ messages in thread From: Alexander Turenko @ 2020-05-12 16:17 UTC (permalink / raw) To: Igor Munkin; +Cc: tarantool-patches I updated the patchset and placed it on the Totktonada/gh-4231-box-execute-idempotence branch. I'll send it soon. Aside of changes around Igor's review I made the following changes: * Rewrote w/o ffi call, using a module local variable. * Fixed <load_cfg> to actually reconfigure box (reload_cfg(cfg) -> reload_cfg(box.cfg, cfg)). * Replace box.execute with lbox_execute at end of box loading. * Added a test for <box_load_and_execute>() and box.execute() at box loading (in parallel in separate fibers). * Polished tests: remove execute_is_immutable() function, splitted box.execute and box.cfg tests. * Clarified dynamic box option set functions contract. > > +local function box_is_configured() > > + return ffi.C.box_is_configured() > > +end > > + > > Minor: Since box_is_configured is introduced within this patchset it > could be placed properly in the first patch of the series. Feel free to > ignore. Fixed. > > diff --git a/test/box-tap/gh-4231-immutable-box-execute.test.lua b/test/box-tap/gh-4231-immutable-box-execute.test.lua > > Minor: test chunk name is left unchanged since the previous version and > doesn't respect the commit message wording. Renamed to gh-4231-box-execute-idempotence.test.lua. > > --- gh-4231: box.execute should be an idempotent function > > --- meaning its effect should be the same if a user chooses > > --- to use it before explicit box.cfg invocation > > +-- gh-4231: box.execute should be an idempotent function meaning > > +-- its effect should be the same if the user chooses to save it > > +-- before explicit box.cfg{} invocation and use the saved version > > +-- afterwards. > > +-- Within the scope of the same issue box.cfg method should also > > +-- be kept idempotent for the same reasons. > > -- > > > > -local function execute_is_immutable(execute, cmd, msg) > > - local status, err = pcall(execute, cmd) > > - test:ok(status and type(err) == 'table', msg) > > -end > > - > > local box_execute_stub = box.execute > > --- explicit call to load_cfg > > +local box_cfg_stub = box.cfg > > + > > +-- Explicit box configuration that used to change the behavior. > > box.cfg{} > > + > > local box_execute_actual = box.execute > > +local box_cfg_actual = box.cfg > > > > -execute_is_immutable(box_execute_stub, > > +local function is_idempotent(method, cmd, msg) > > Minor: IMHO these changes are better to be moved to the first patch of > the series. Feel free to ignore. Fixed. ^ permalink raw reply [flat|nested] 31+ messages in thread
end of thread, other threads:[~2020-05-12 16:17 UTC | newest] Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2019-11-14 11:50 [Tarantool-patches] [PATCH] box.execute should be immutable function Maria 2019-11-14 16:51 ` Nikita Pettik 2019-12-17 14:39 ` Igor Munkin 2019-12-24 15:32 ` [Tarantool-patches] [PATCH] box: make box.execute() immutable Maria Khaydich 2019-12-25 1:30 ` Igor Munkin 2019-12-26 14:08 ` Alexander Turenko 2020-01-13 12:13 ` Maria Khaydich 2020-01-13 15:48 ` Igor Munkin 2020-01-18 10:56 ` Maria Khaydich 2020-02-20 17:51 ` Alexander Turenko 2020-02-20 21:15 ` Igor Munkin 2020-03-11 15:56 ` Maria Khaydich 2020-03-18 22:25 ` Igor Munkin 2020-05-02 14:52 ` Alexander Turenko 2020-05-12 16:16 ` Alexander Turenko 2020-03-11 15:57 ` [Tarantool-patches] [PATCH 1/2] box: make box.cfg idempotent function Maria Khaydich 2020-03-12 13:29 ` Konstantin Osipov 2020-03-12 19:25 ` Maria Khaydich 2020-03-12 20:00 ` Konstantin Osipov 2020-03-18 22:26 ` Igor Munkin 2020-03-19 7:19 ` Konstantin Osipov 2020-03-19 9:08 ` Igor Munkin 2020-03-19 10:06 ` Konstantin Osipov 2020-03-19 10:26 ` Igor Munkin 2020-05-06 11:17 ` Alexander Turenko 2020-05-06 11:49 ` Konstantin Osipov 2020-05-06 12:53 ` Alexander Turenko 2020-05-06 13:02 ` Konstantin Osipov 2020-05-06 13:13 ` Alexander Turenko 2020-03-18 22:26 ` Igor Munkin 2020-05-12 16:17 ` Alexander Turenko
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox