From dbeb277c86c061d269931e1f09f4d16cc91b6ec3 Mon Sep 17 00:00:00 2001 From: Konstantin Osipov <kostja@tarantool.org> Date: Tue, 28 May 2013 10:48:26 +0400 Subject: [PATCH] Code review for box.net.box implementation: - write the docs - remove unnecessary introduction of Perl - properly implement, document and test box.fiber.wrap() - rename box.find, explore alternatives (none) - rewrite box.unpack('R') to reuse code and do what's expected of it. --- .gitignore | 2 +- doc/user/errcode.xml | 8 + doc/user/replication.xml | 4 +- doc/user/stored-procedures.xml | 242 ++++++++++++++++------ doc/user/target.db | 4 +- extra/pack_lua | 66 ------ include/errcode.h | 2 +- include/fiber.h | 3 + src/box/CMakeLists.txt | 53 +++-- src/box/box_lua.m | 115 ++++------ src/box/lua/box.autoincrement.lua | 22 -- src/box/lua/box.bless_space.lua | 111 ---------- src/box/lua/box.fiber.lua | 21 -- src/box/lua/box.lua | 110 ++++++++++ src/box/lua/{box.net.lua => box_net.lua} | 59 ++++-- src/box/lua/{box.counter.lua => misc.lua} | 23 ++ src/fiber.m | 8 +- src/lua/init.m | 54 ++++- test/box/lua.result | 36 +++- test/box/lua.test | 29 ++- test/box/lua_misc.result | 11 +- test/box/net.box.result | 9 +- test/box/net.box.test | 4 +- test/lib/sql_ast.py | 2 +- 24 files changed, 571 insertions(+), 427 deletions(-) delete mode 100755 extra/pack_lua delete mode 100644 src/box/lua/box.autoincrement.lua delete mode 100644 src/box/lua/box.bless_space.lua delete mode 100644 src/box/lua/box.fiber.lua rename src/box/lua/{box.net.lua => box_net.lua} (90%) rename src/box/lua/{box.counter.lua => misc.lua} (61%) diff --git a/.gitignore b/.gitignore index 97d442eb02..42fb64587f 100644 --- a/.gitignore +++ b/.gitignore @@ -65,7 +65,7 @@ third_party/luajit/src/lj_recdef.h third_party/luajit/src/lj_vm.s *.reject extra/txt2c -src/box/*.lua.c +src/box/lua/*.lua.c doc/www-data/*.html doc/www-data/*.ru.html doc/www-data.in/download diff --git a/doc/user/errcode.xml b/doc/user/errcode.xml index 4838ef0b3a..173c9b77c7 100644 --- a/doc/user/errcode.xml +++ b/doc/user/errcode.xml @@ -77,6 +77,14 @@ file <filename xlink:href="https://github.com/mailru/tarantool/blob/master/inclu </para></listitem> </varlistentry> + <varlistentry> + <term xml:id="ER_FIBER_STACK" xreflabel="ER_FIBER_STACK">ER_FIBER_STACK</term> + <listitem><para>Recursion limit reached when creating a new fiber. This is + usually an indicator of a bug in a stored procedure, recursively invoking itself + ad infinitum. + </para></listitem> + </varlistentry> + </variablelist> </appendix> diff --git a/doc/user/replication.xml b/doc/user/replication.xml index a4e5c8d01d..f97bcee166 100644 --- a/doc/user/replication.xml +++ b/doc/user/replication.xml @@ -177,8 +177,8 @@ <para> Recover the old master. If there are updates that didn't make it to the new master, they have to be applied - manually. You can use <olink targetptr="cat-option"/> - option to read server logs. + manually. You can use Tarantool command line client + to read server logs. </para> </listitem> </itemizedlist> diff --git a/doc/user/stored-procedures.xml b/doc/user/stored-procedures.xml index 67d8e7b116..e261ce51f7 100644 --- a/doc/user/stored-procedures.xml +++ b/doc/user/stored-procedures.xml @@ -319,7 +319,7 @@ localhost> lua type(i), type(i*2), type(i/2), i, i*2, i/2 <variablelist xml:id="box" xreflabel="box"> <varlistentry> <term> - <emphasis role="lua">box.process(op, request)</emphasis> + <emphasis role="lua" xml:id="box.process">box.process(op, request)</emphasis> </term> <listitem> <para> @@ -422,7 +422,7 @@ localhost> lua box.select(5, 1, 'firstname', 'lastname') <varlistentry> <term> - <emphasis role="lua">box.insert(space_no, ...)</emphasis> + <emphasis role="lua" xml:id="box.insert">box.insert(space_no, ...)</emphasis> </term> <listitem><simpara></simpara></listitem> </varlistentry> @@ -430,7 +430,7 @@ localhost> lua box.select(5, 1, 'firstname', 'lastname') <varlistentry> <term> <emphasis role="lua" xml:id="box.select_limit" xreflabel="box.select_limit"> - box.select(space_no, index_no, offset, limit, ...) + box.select_limit(space_no, index_no, offset, limit, ...) </emphasis> </term> <listitem> @@ -448,7 +448,7 @@ localhost> lua box.select(5, 1, 'firstname', 'lastname') <varlistentry> <term> - <emphasis role="lua">box.replace(space_no, ...)</emphasis> + <emphasis role="lua" xml:id="box.replace">box.replace(space_no, ...)</emphasis> </term> <listitem> <para> @@ -467,7 +467,7 @@ localhost> lua box.select(5, 1, 'firstname', 'lastname') <varlistentry> <term> - <emphasis role="lua">box.update(space_no, key, format, ...)</emphasis> + <emphasis role="lua" xml:id="box.update">box.update(space_no, key, format, ...)</emphasis> </term> <listitem> <para> @@ -540,7 +540,7 @@ localhost> lua box.update(0, 2, '#p', 2, 'Bienvenue tout le monde!') <varlistentry> <term> - <emphasis role="lua">box.delete(space_no, ...)</emphasis> + <emphasis role="lua" xml:id="box.delete">box.delete(space_no, ...)</emphasis> </term> <listitem><para> Delete a tuple identified by a primary key. @@ -1619,14 +1619,14 @@ and <code>box.fiber.testcancel()</code> is checked whenever such an event occurs <variablelist xml:id="box.fiber"> <varlistentry> <term> - <emphasis role="lua">box.fiber.id(fiber) </emphasis> + <emphasis role="lua" xml:id="box.fiber.id">box.fiber.id(fiber) </emphasis> </term> <listitem><simpara>Return a numeric id of the fiber.</simpara></listitem> </varlistentry> <varlistentry> <term> - <emphasis role="lua">box.fiber.self() </emphasis> + <emphasis role="lua" xml:id="box.fiber.self">box.fiber.self() </emphasis> </term> <listitem><simpara>Return <code>box.fiber</code> userdata object for the currently scheduled fiber.</simpara></listitem> @@ -1634,14 +1634,14 @@ and <code>box.fiber.testcancel()</code> is checked whenever such an event occurs <varlistentry> <term> - <emphasis role="lua">box.fiber.find(id) </emphasis> + <emphasis role="lua" xml:id="box.fiber.find">box.fiber.find(id) </emphasis> </term> <listitem><simpara>Locate a fiber userdata object by id.</simpara></listitem> </varlistentry> <varlistentry> <term> - <emphasis role="lua">box.fiber.create(function) </emphasis> + <emphasis role="lua" xml:id="box.fiber.create">box.fiber.create(function) </emphasis> </term> <listitem><simpara> Create a fiber for <code>function</code>. @@ -1653,7 +1653,7 @@ and <code>box.fiber.testcancel()</code> is checked whenever such an event occurs <varlistentry> <term> - <emphasis role="lua">box.fiber.resume(fiber, ...) </emphasis> + <emphasis role="lua" xml:id="box.fiber.resume">box.fiber.resume(fiber, ...) </emphasis> </term> <listitem><simpara>Resume a created or suspended fiber.</simpara></listitem> @@ -1671,13 +1671,14 @@ and <code>box.fiber.testcancel()</code> is checked whenever such an event occurs If the fiber is attached, whatever arguments are passed to this call, are passed on to the calling fiber. If the fiber is detached, <code>box.fiber.yield()</code> - returns back everything passed into it. + returns back everything passed into it after temporarily + yielding control back to the scheduler. </para></listitem> </varlistentry> <varlistentry> <term> - <emphasis role="lua">box.fiber.detach()</emphasis> + <emphasis role="lua" xml:id="box.fiber.detach">box.fiber.detach()</emphasis> </term> <listitem><simpara> Detach the current fiber. This is a cancellation point. This is a yield point. @@ -1686,7 +1687,19 @@ and <code>box.fiber.testcancel()</code> is checked whenever such an event occurs <varlistentry> <term> - <emphasis role="lua">box.fiber.sleep(time)</emphasis> + <emphasis role="lua" xml:id="box.fiber.wrap">box.fiber.wrap(function, ...)</emphasis> + </term> + <listitem><simpara> + This is a quick way to create and start a detached + fiber. The fiber function is passed in the first + argument, the function arguments follow. The fiber is + created detached and resumed immediately. + </simpara></listitem> + </varlistentry> + + <varlistentry> + <term> + <emphasis role="lua" xml:id="box.fiber.sleep">box.fiber.sleep(time)</emphasis> </term> <listitem><simpara> Yield to the sched fiber and sleep <code>time</code> seconds. @@ -1696,7 +1709,20 @@ and <code>box.fiber.testcancel()</code> is checked whenever such an event occurs <varlistentry> <term> - <emphasis role="lua">box.fiber.cancel(fiber)</emphasis> + <emphasis role="lua" xml:id="box.fiber.status">box.fiber.status(fiber)</emphasis> + </term> + <listitem><simpara> + Returns the status of the fiber. If no argument is + provided, the current fiber's status is returned. The + status can be either <quote>dead</quote>, + <quote>suspended</quote>, <quote>attached</quote> + or <quote>running</quote>. + </simpara></listitem> + </varlistentry> + + <varlistentry> + <term> + <emphasis role="lua" xml:id="box.fiber.cancel">box.fiber.cancel(fiber)</emphasis> </term> <listitem><simpara> Cancel a <code>fiber</code>. @@ -1707,7 +1733,7 @@ and <code>box.fiber.testcancel()</code> is checked whenever such an event occurs <varlistentry> <term> - <emphasis role="lua">box.fiber.testcancel()</emphasis> + <emphasis role="lua" xml:id="box.fiber.testcancel">box.fiber.testcancel()</emphasis> </term> <listitem><simpara> Check if the current fiber has been canceled and @@ -2217,35 +2243,98 @@ end <section xml:id="sp-box-net-box"> <title>Package <code>box.net.box</code> — working with networked Tarantool peers</title> -<variablelist xml:id="box.net.box"> <simpara> Library <code>box.net</code> contains connectors - to remote systems, such as MariaDB or PostgreSQL, etc. - The first supported system is Tarantool itself, a - connector for it is implemented in library <code>box.net.box</code>. + to remote database systems, such as MariaDB or PostgreSQL. + The first supported system is Tarantool itself. + </simpara> +<variablelist xml:id="box.net.box"> + <simpara> + The basic object provided by <code>box.net.box</code> + library is a connection. A connection is created by + calling <code>box.net.box.new()</code>. To + execute remote requests, simply invoke methods of the + connection object, a physical connection is established + upon request and is re-established if necessary. + When done, issue <code>conn:close()</code>. Connection + objects are garbage collected just like any other objects + in Lua, so an explicit destruction is not mandatory. + However, since <code>close()</code> is a system call, it + is a good programming practice to close a connection + explicitly when it is no longer needed, to avoid lengthy + stalls of the garbage collector. + </simpara> + <simpara> + The library also provides a pre-created connection object + to the local server, <code>box.net.self</code>. This + connection is always <quote>established</quote>. The + purpose of this object is to make polymorphic use of + <code>box.net.box</code> API easier. There is an + important difference, however, between the embedded + connection and a remote one. With the embedded connection, + requests which do not modify data do not yield. When using + a remote connection, it is important to keep in mind that + any request can yield, and local database state may + have changed by the time it returns. + </simpara> + <simpara> + All <code>box.net.box</code> methods are fiber-safe. It's + safe to share and use the same connection object across + multiple concurrent fibers. In fact, it's perhaps the + best programming practice with Tarantool: when multiple + fibers use the same connection, all requests are pipelined + through the same network socket, but each fiber gets a + correct response back. Reducing the number of active sockets + lowers the overhead of system calls and increases the + overall server performance. There are, however cases, when + a single connection is not enough: when it's necessary to + prioritize requests, use different authentication ids, + etc. + </simpara> + <simpara> + All remote calls support execution timeouts. A specialized + wrapper, <code>box.net.box.timeout()</code> allows setting + a timeout. Using a wrapper object makes the remote + connection API compatible with the local one, removing + the need for a separate <code>timeout</code> argument, ignored + by the local version. Once sent, a + request can not be revoked from the remote server even if + a timeout expires: the expired timeout only aborts the + wait for the remote server response. + <code>box.net.box.timeout()</code>, + </simpara> + <simpara> + Object-oriented and functional APIs are equivalent: + <code>conn:close()</code> is identical to + <code>box.net.box.close(conn)</code>. </simpara> <varlistentry> <term> - <emphasis role="lua">conn = box.net.box.new(host, port [, connect_timeout])</emphasis> + <emphasis role="lua" xml:id="box.net.box.new"> + conn = box.net.box.new(host, port [, reconnect_interval])</emphasis> </term> <listitem> <para> - Create a new connection to a remote Tarantool. The - connection is established on demand, at the time - of first request. The returned object supports - methods for making remote calls, such as select, - update or delete. All calls to a remote server - support timeouts. + Create a new connection. The connection is + established on demand, at the time of the first + request. It is re-established automatically after + a disconnect. Argument + <code>reconnect_interval</code> (in seconds) is + responsible for the amount of time the server + sleeps between failing attempts to reconnect. The + returned object supports methods for making remote + calls, such as select, update or delete. </para> </listitem> </varlistentry> <varlistentry> - <term><emphasis role="lua">conn:ping()</emphasis></term> + <term><emphasis role="lua" xml:id="box.net.box.ping"> + conn:ping()</emphasis></term> <listitem> <para> - Send PING command to a remote server. + Execute a PING command. Returns <code>true</code> on success, <code>false</code> on error. </para> @@ -2253,7 +2342,8 @@ end </varlistentry> <varlistentry> - <term><emphasis role="lua">conn:close()</emphasis></term> + <term><emphasis role="lua" xml:id="box.net.box.close"> + conn:close()</emphasis></term> <listitem> <para> Close a connection. The connection is also @@ -2266,86 +2356,120 @@ end </varlistentry> <varlistentry> - <term><emphasis role="lua">conn:select()</emphasis></term> + <term><emphasis role="lua" xml:id="box.net.box.select"> + conn:select(space_no, index_no, ...)</emphasis></term> <listitem> - <para>See box.select(...). Please note, that unlike - a local <code>box.select()</code> any call to a remote - server yields, thus local data may change while - remote <code>select()</code> is running.</para> + <para> + See <code + xlink:href="#box.select">box.select(...)</code>. + Please note, that unlike a local + <code>box.select()</code> any call to a remote + server yields, thus local data may change while + remote <code>select()</code> is running. + </para> </listitem> </varlistentry> <varlistentry> - <term><emphasis role="lua">conn:select_limit()</emphasis></term> + <term><emphasis role="lua" xml:id="box.net.box.select_limit"> + conn:select_limit(space_no, index_no, offset, limit, ...)</emphasis></term> <listitem> - <para>See box.select_limit(...)</para> + <para> + See <code + xlink:href="#box.select_limit">box.select_limit(...)</code> + </para> </listitem> </varlistentry> <varlistentry> - <term><emphasis role="lua">conn:select_range()</emphasis></term> + <term><emphasis role="lua" xml:id="box.net.box.select_range"> + conn:select_range(space_no, index_no, limit, key, ...)</emphasis></term> <listitem> - <para>See box.select_range(...)</para> + <para> + See <code + xlink:href="#box.select_range">box.select_range(...)</code>. + </para> </listitem> </varlistentry> <varlistentry> - <term><emphasis role="lua">conn:insert()</emphasis></term> + <term><emphasis role="lua" xml:id="box.net.box.insert">conn:insert(space_no, ...)</emphasis></term> <listitem> - <para>See box.insert(...)</para> + <para> + See <code xlink:href="#box.insert">box.insert(...)</code>. + </para> </listitem> </varlistentry> <varlistentry> - <term><emphasis role="lua">conn:replace()</emphasis></term> + <term><emphasis role="lua" xml:id="box.net.box.replace">conn:replace(space_no, ...)</emphasis></term> <listitem> - <para>See box.replace(...)</para> + <para> + See <code xlink:href="#box.replace">box.replace(...)</code>. + </para> </listitem> </varlistentry> <varlistentry> - <term><emphasis role="lua">conn:update(...)</emphasis></term> + <term><emphasis role="lua" xml:id="box.net.box.update">conn:update(...)</emphasis></term> <listitem> - <para>See box.update(...)</para> + <para> + See <code + xlink:href="#box.update">box.update(...)</code>. + </para> </listitem> </varlistentry> <varlistentry> - <term><emphasis role="lua">conn:delete(...)</emphasis></term> + <term><emphasis role="lua" xml:id="box.net.box.delete">conn:delete(space_no, key)</emphasis></term> <listitem> - <para>See box.delete(...)</para> + <para> + See <code xlink:href="#box.delete">box.delete(...)</code>. + </para> </listitem> </varlistentry> <varlistentry> - <term><emphasis role="lua">conn:call(...)</emphasis></term> + <term><emphasis role="lua" xml:id="box.net.box.call">conn:call(proc_name, ...)</emphasis></term> <listitem> - <para>Call a remote stored procedure, such as <code>box.select_reverse_range()</code> and such.</para> + <para>Call a remote stored procedure, such as + <code>box.select_reverse_range()</code>. + Please keep in mind that the call is using + the binary protocol to pack procedure arguments, + and since the latter is type-agnostic it's recommended + to pass all arguments of remote stored procedure as + strings, for example: +<programlisting> + conn:call("box.select_reverse_range", "1", "4", "10", "Smith") +</programlisting> + </para> </listitem> </varlistentry> <varlistentry> - <term><emphasis role="lua">conn:timeout(timeout)</emphasis></term> + <term><emphasis role="lua" xml:id="box.net.box.timeout">conn:timeout(timeout)</emphasis></term> <listitem> - <para>Returns a closure which is identical to the invoked - function, excepts adds time out functionality to it. + <para> + Returns a closure which is identical to the + invoked function, except the added timeout + functionality. <programlisting> --- wait for 'foo' result until 'foo' is finished -local something = remote:call('foo', 'arg1', ...) +-- wait for 'update' until it is finished +local tuple = conn:update('1', 'key', ...) --- wait up to 0.1 second return nil if foo is still continue -local other = remote:timeout(0.1):call('foo', 'arg1', ...) +-- send update but don't bother to wait for results +local other = conn:timeout(0):update('1', 'arg1', ...) </programlisting> </para> </listitem> </varlistentry> </variablelist> - <bridgehead renderas="sect4">Examples</bridgehead> + <bridgehead renderas="sect4">Example</bridgehead> <programlisting> +-- connect to the local server local self = box.net.box.new('127.0.0.1', box.info.primary_port) -self:ping() -self:insert(1,3,4) +self:insert("1", "Hello", "World") </programlisting> </section> diff --git a/doc/user/target.db b/doc/user/target.db index 8f0bfdff9f..306bb5c8c4 100644 --- a/doc/user/target.db +++ b/doc/user/target.db @@ -1,5 +1,5 @@ -<div element="book" href="#tarantool-user-guide" number="" targetptr="tarantool-user-guide"><ttl>Tarantool User Guide, version 1.4.9-40-g67f3d3c</ttl><xreftext>Tarantool User Guide, version 1.4.9-40-g67f3d3c</xreftext><div element="chapter" href="#preface" number="1" targetptr="preface"><ttl>Preface</ttl><xreftext>Chapter 1, <i>Preface</i></xreftext><div element="section" href="#tarantool-overview" number="" targetptr="tarantool-overview"><ttl>Tarantool: an overview</ttl><xreftext>the section called “Tarantool: an overviewâ€</xreftext></div><div element="section" href="#manual-conventions" number="" targetptr="manual-conventions"><ttl>Conventions</ttl><xreftext>the section called “Conventionsâ€</xreftext></div><div element="section" href="#reporting-bugs" number="" targetptr="reporting-bugs"><ttl>Reporting bugs</ttl><xreftext>the section called “Reporting bugsâ€</xreftext></div></div><div element="chapter" href="#getting-started" number="2" targetptr="getting-started"><ttl>Getting started</ttl><xreftext>Chapter 2, <i>Getting started</i></xreftext></div><div element="chapter" href="#data-and-persistence" number="3" targetptr="data-and-persistence"><ttl>Data model and data persistence</ttl><xreftext>Chapter 3, <i>Data model and data persistence</i></xreftext><div element="section" href="#dynamic-data-model" number="" targetptr="dynamic-data-model"><ttl>Dynamic data model</ttl><xreftext>the section called “Dynamic data modelâ€</xreftext></div><div element="section" href="#data-persistence" number="" targetptr="data-persistence"><ttl>Data persistence</ttl><xreftext>the section called “Data persistenceâ€</xreftext></div></div><div element="chapter" href="#language-reference" number="4" targetptr="language-reference"><ttl>Language reference</ttl><xreftext>Chapter 4, <i>Language reference</i></xreftext><div element="section" href="#data-manipulation" number="" targetptr="data-manipulation"><ttl>Data manipulation</ttl><xreftext>the section called “Data manipulationâ€</xreftext><div element="section" href="#memcached-protocol" number="" targetptr="memcached-protocol"><ttl>Memcached protocol</ttl><xreftext>the section called “Memcached protocolâ€</xreftext></div></div><div element="section" href="#administrative-console" number="" targetptr="administrative-console"><ttl>Administrative console</ttl><xreftext>the section called “Administrative consoleâ€</xreftext><obj element="term" href="#save-snapshot" number="" targetptr="save-snapshot"><ttl>???TITLE???</ttl><xreftext>SAVE SNAPSHOT</xreftext></obj><obj element="term" href="#reload-configuration" number="" targetptr="reload-configuration"><ttl>???TITLE???</ttl><xreftext>RELOAD CONFIGURATION</xreftext></obj><obj element="term" href="#show-configuration" number="" targetptr="show-configuration"><ttl>???TITLE???</ttl><xreftext>SHOW CONFIGURATION</xreftext></obj><obj element="term" href="#show-info" number="" targetptr="show-info"><ttl>???TITLE???</ttl><xreftext>SHOW INFO</xreftext></obj><obj element="term" href="#show-stat" number="" targetptr="show-stat"><ttl>???TITLE???</ttl><xreftext>SHOW STAT</xreftext></obj><obj element="term" href="#show-slab" number="" targetptr="show-slab"><ttl>???TITLE???</ttl><xreftext>SHOW SLAB</xreftext></obj><obj element="term" href="#show-palloc" number="" targetptr="show-palloc"><ttl>???TITLE???</ttl><xreftext>SHOW PALLOC</xreftext></obj><obj element="term" href="#save-coredump" number="" targetptr="save-coredump"><ttl>???TITLE???</ttl><xreftext>SAVE COREDUMP</xreftext></obj><obj element="term" href="#show-fiber" number="" targetptr="show-fiber"><ttl>???TITLE???</ttl><xreftext>SHOW FIBER</xreftext></obj><obj element="term" href="#lua-command" number="" targetptr="lua-command"><ttl>???TITLE???</ttl><xreftext>LUA ...</xreftext></obj></div><div element="section" href="#stored-procedures" number="" targetptr="stored-procedures"><ttl>Writing stored procedures in Lua</ttl><xreftext>the section called “Writing stored procedures in Luaâ€</xreftext><obj element="emphasis" href="#init.lua" number="" targetptr="init.lua"><ttl>???TITLE???</ttl><xreftext>init.lua</xreftext></obj><obj element="term" href="#tonumber64" number="" targetptr="tonumber64"><ttl>???TITLE???</ttl><xreftext>tonumber64</xreftext></obj><div element="section" href="#sp-box" number="" targetptr="sp-box"><ttl>Package <code class="code">box</code></ttl><xreftext>the section called “Package <code class="code">box</code>â€</xreftext><obj element="variablelist" href="#box" number="" targetptr="box"><ttl>???TITLE???</ttl><xreftext>box</xreftext></obj><obj element="emphasis" href="#box.select" number="" targetptr="box.select"><ttl>???TITLE???</ttl><xreftext>box.select</xreftext></obj><obj element="emphasis" href="#box.select_range" number="" targetptr="box.select_range"><ttl>???TITLE???</ttl><xreftext>box.select_range</xreftext></obj><obj element="emphasis" href="#box.select_reverse_range" number="" targetptr="box.select_reverse_range"><ttl>???TITLE???</ttl><xreftext>box.select_reverse_range</xreftext></obj></div><div element="section" href="#sp-box-tuple" number="" targetptr="sp-box-tuple"><ttl>Package <code class="code">box.tuple</code></ttl><xreftext>the section called “Package <code class="code">box.tuple</code>â€</xreftext><obj element="variablelist" href="#box.tuple" number="" targetptr="box.tuple"><ttl>???TITLE???</ttl><xreftext>box.tuple</xreftext></obj></div><div element="section" href="#sp-box-space" number="" targetptr="sp-box-space"><ttl>Package <code class="code">box.space</code></ttl><xreftext>the section called “Package <code class="code">box.space</code>â€</xreftext><obj element="variablelist" href="#box.space" number="" targetptr="box.space"><ttl>???TITLE???</ttl><xreftext>box.space</xreftext></obj><obj element="emphasis" href="#box.space.select_range" number="" targetptr="box.space.select_range"><ttl>???TITLE???</ttl><xreftext>box.space[i].select_range()</xreftext></obj><obj element="emphasis" href="#box.space.select_reverse_range" number="" targetptr="box.space.select_reverse_range"><ttl>???TITLE???</ttl><xreftext>box.space.select_reverse_range</xreftext></obj></div><div element="section" href="#sp-box-index" number="" targetptr="sp-box-index"><ttl>Package <code class="code">box.index</code></ttl><xreftext>the section called “Package <code class="code">box.index</code>â€</xreftext><obj element="variablelist" href="#box.index" number="" targetptr="box.index"><ttl>???TITLE???</ttl><xreftext>box.index</xreftext></obj><obj element="emphasis" href="#box.index.iterator" number="" targetptr="box.index.iterator"><ttl>???TITLE???</ttl><xreftext>box.index.iterator</xreftext></obj><obj element="table" href="#iterator-types" number="4.1" targetptr="iterator-types"><ttl>Iterator types</ttl><xreftext>Table 4.1, “Iterator typesâ€</xreftext></obj></div><div element="section" href="#sp-box-fiber" number="" targetptr="sp-box-fiber"><ttl>Package <code class="code">box.fiber</code></ttl><xreftext>the section called “Package <code class="code">box.fiber</code>â€</xreftext><obj element="variablelist" href="#box.fiber" number="" targetptr="box.fiber"><ttl>???TITLE???</ttl><xreftext>???TITLE???</xreftext></obj></div><div element="section" href="#sp-box-session" number="" targetptr="sp-box-session"><ttl>Package <code class="code">box.session</code></ttl><xreftext>the section called “Package <code class="code">box.session</code>â€</xreftext></div><div element="section" href="#sp-box-ipc" number="" targetptr="sp-box-ipc"><ttl>Package <code class="code">box.ipc</code> — inter procedure communication</ttl><xreftext>the section called “Package <code class="code">box.ipc</code> — inter procedure communicationâ€</xreftext><obj element="variablelist" href="#box.ipc" number="" targetptr="box.ipc"><ttl>???TITLE???</ttl><xreftext>???TITLE???</xreftext></obj></div><div element="section" href="#sp-box-socket" number="" targetptr="sp-box-socket"><ttl>Package <code class="code">box.socket</code> — TCP and UDP sockets</ttl><xreftext>the section called “Package <code class="code">box.socket</code> — TCP and UDP socketsâ€</xreftext><obj element="variablelist" href="#box.socket" number="" targetptr="box.socket"><ttl>???TITLE???</ttl><xreftext>???TITLE???</xreftext></obj><obj element="table" href="#idp398336" number="4.2"><ttl><code class="code">readline()</code> returns</ttl><xreftext>Table 4.2, “<code class="code">readline()</code> returnsâ€</xreftext></obj></div><div element="section" href="#sp-box-cfg" number="" targetptr="sp-box-cfg"><ttl>Packages <code class="code">box.cfg</code>, +<div element="book" href="#tarantool-user-guide" number="" targetptr="tarantool-user-guide"><ttl>Tarantool User Guide, version 1.5.0-103-g387e34f</ttl><xreftext>Tarantool User Guide, version 1.5.0-103-g387e34f</xreftext><div element="chapter" href="#preface" number="1" targetptr="preface"><ttl>Preface</ttl><xreftext>Chapter 1, <i>Preface</i></xreftext><div element="section" href="#tarantool-overview" number="" targetptr="tarantool-overview"><ttl>Tarantool: an overview</ttl><xreftext>the section called “Tarantool: an overviewâ€</xreftext></div><div element="section" href="#manual-conventions" number="" targetptr="manual-conventions"><ttl>Conventions</ttl><xreftext>the section called “Conventionsâ€</xreftext></div><div element="section" href="#reporting-bugs" number="" targetptr="reporting-bugs"><ttl>Reporting bugs</ttl><xreftext>the section called “Reporting bugsâ€</xreftext></div></div><div element="chapter" href="#getting-started" number="2" targetptr="getting-started"><ttl>Getting started</ttl><xreftext>Chapter 2, <i>Getting started</i></xreftext></div><div element="chapter" href="#data-and-persistence" number="3" targetptr="data-and-persistence"><ttl>Data model and data persistence</ttl><xreftext>Chapter 3, <i>Data model and data persistence</i></xreftext><div element="section" href="#dynamic-data-model" number="" targetptr="dynamic-data-model"><ttl>Dynamic data model</ttl><xreftext>the section called “Dynamic data modelâ€</xreftext></div><div element="section" href="#data-persistence" number="" targetptr="data-persistence"><ttl>Data persistence</ttl><xreftext>the section called “Data persistenceâ€</xreftext></div></div><div element="chapter" href="#language-reference" number="4" targetptr="language-reference"><ttl>Language reference</ttl><xreftext>Chapter 4, <i>Language reference</i></xreftext><div element="section" href="#data-manipulation" number="" targetptr="data-manipulation"><ttl>Data manipulation</ttl><xreftext>the section called “Data manipulationâ€</xreftext><div element="section" href="#memcached-protocol" number="" targetptr="memcached-protocol"><ttl>Memcached protocol</ttl><xreftext>the section called “Memcached protocolâ€</xreftext></div></div><div element="section" href="#administrative-console" number="" targetptr="administrative-console"><ttl>Administrative console</ttl><xreftext>the section called “Administrative consoleâ€</xreftext><obj element="term" href="#save-snapshot" number="" targetptr="save-snapshot"><ttl>???TITLE???</ttl><xreftext>SAVE SNAPSHOT</xreftext></obj><obj element="term" href="#reload-configuration" number="" targetptr="reload-configuration"><ttl>???TITLE???</ttl><xreftext>RELOAD CONFIGURATION</xreftext></obj><obj element="term" href="#show-configuration" number="" targetptr="show-configuration"><ttl>???TITLE???</ttl><xreftext>SHOW CONFIGURATION</xreftext></obj><obj element="term" href="#show-info" number="" targetptr="show-info"><ttl>???TITLE???</ttl><xreftext>SHOW INFO</xreftext></obj><obj element="term" href="#show-stat" number="" targetptr="show-stat"><ttl>???TITLE???</ttl><xreftext>SHOW STAT</xreftext></obj><obj element="term" href="#show-slab" number="" targetptr="show-slab"><ttl>???TITLE???</ttl><xreftext>SHOW SLAB</xreftext></obj><obj element="term" href="#show-palloc" number="" targetptr="show-palloc"><ttl>???TITLE???</ttl><xreftext>SHOW PALLOC</xreftext></obj><obj element="term" href="#save-coredump" number="" targetptr="save-coredump"><ttl>???TITLE???</ttl><xreftext>SAVE COREDUMP</xreftext></obj><obj element="term" href="#show-fiber" number="" targetptr="show-fiber"><ttl>???TITLE???</ttl><xreftext>SHOW FIBER</xreftext></obj><obj element="term" href="#lua-command" number="" targetptr="lua-command"><ttl>???TITLE???</ttl><xreftext>LUA ...</xreftext></obj></div><div element="section" href="#stored-procedures" number="" targetptr="stored-procedures"><ttl>Writing stored procedures in Lua</ttl><xreftext>the section called “Writing stored procedures in Luaâ€</xreftext><obj element="emphasis" href="#init.lua" number="" targetptr="init.lua"><ttl>???TITLE???</ttl><xreftext>init.lua</xreftext></obj><obj element="term" href="#tonumber64" number="" targetptr="tonumber64"><ttl>???TITLE???</ttl><xreftext>tonumber64</xreftext></obj><div element="section" href="#sp-box" number="" targetptr="sp-box"><ttl>Package <code class="code">box</code></ttl><xreftext>the section called “Package <code class="code">box</code>â€</xreftext><obj element="variablelist" href="#box" number="" targetptr="box"><ttl>???TITLE???</ttl><xreftext>box</xreftext></obj><obj element="emphasis" href="#box.process" number="" targetptr="box.process"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.select" number="" targetptr="box.select"><ttl>???TITLE???</ttl><xreftext>box.select</xreftext></obj><obj element="emphasis" href="#box.insert" number="" targetptr="box.insert"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.select_limit" number="" targetptr="box.select_limit"><ttl>???TITLE???</ttl><xreftext>box.select_limit</xreftext></obj><obj element="emphasis" href="#box.replace" number="" targetptr="box.replace"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.update" number="" targetptr="box.update"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.delete" number="" targetptr="box.delete"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.select_range" number="" targetptr="box.select_range"><ttl>???TITLE???</ttl><xreftext>box.select_range</xreftext></obj><obj element="emphasis" href="#box.select_reverse_range" number="" targetptr="box.select_reverse_range"><ttl>???TITLE???</ttl><xreftext>box.select_reverse_range</xreftext></obj></div><div element="section" href="#sp-box-tuple" number="" targetptr="sp-box-tuple"><ttl>Package <code class="code">box.tuple</code></ttl><xreftext>the section called “Package <code class="code">box.tuple</code>â€</xreftext><obj element="variablelist" href="#box.tuple" number="" targetptr="box.tuple"><ttl>???TITLE???</ttl><xreftext>box.tuple</xreftext></obj></div><div element="section" href="#sp-box-space" number="" targetptr="sp-box-space"><ttl>Package <code class="code">box.space</code></ttl><xreftext>the section called “Package <code class="code">box.space</code>â€</xreftext><obj element="variablelist" href="#box.space" number="" targetptr="box.space"><ttl>???TITLE???</ttl><xreftext>box.space</xreftext></obj><obj element="emphasis" href="#box.space.select_range" number="" targetptr="box.space.select_range"><ttl>???TITLE???</ttl><xreftext>box.space[i].select_range()</xreftext></obj><obj element="emphasis" href="#box.space.select_reverse_range" number="" targetptr="box.space.select_reverse_range"><ttl>???TITLE???</ttl><xreftext>box.space.select_reverse_range</xreftext></obj></div><div element="section" href="#sp-box-index" number="" targetptr="sp-box-index"><ttl>Package <code class="code">box.index</code></ttl><xreftext>the section called “Package <code class="code">box.index</code>â€</xreftext><obj element="variablelist" href="#box.index" number="" targetptr="box.index"><ttl>???TITLE???</ttl><xreftext>box.index</xreftext></obj><obj element="emphasis" href="#box.index.iterator" number="" targetptr="box.index.iterator"><ttl>???TITLE???</ttl><xreftext>box.index.iterator(type, ...)</xreftext></obj><obj element="para" href="#iterator-consistency" number="" targetptr="iterator-consistency"><ttl>???TITLE???</ttl><xreftext/></obj><obj element="para" href="#iterator-types" number="" targetptr="iterator-types"><ttl>???TITLE???</ttl><xreftext/></obj><obj element="table" href="#idp439728" number="4.1"><ttl>Common iterator types</ttl><xreftext>Table 4.1, “Common iterator typesâ€</xreftext></obj><obj element="table" href="#idp460720" number="4.2"><ttl>TREE iterator types</ttl><xreftext>Table 4.2, “TREE iterator typesâ€</xreftext></obj><obj element="table" href="#idp888096" number="4.3"><ttl>BITSET iterator types</ttl><xreftext>Table 4.3, “BITSET iterator typesâ€</xreftext></obj></div><div element="section" href="#sp-box-fiber" number="" targetptr="sp-box-fiber"><ttl>Package <code class="code">box.fiber</code></ttl><xreftext>the section called “Package <code class="code">box.fiber</code>â€</xreftext><obj element="variablelist" href="#box.fiber" number="" targetptr="box.fiber"><ttl>???TITLE???</ttl><xreftext>???TITLE???</xreftext></obj><obj element="emphasis" href="#box.fiber.yield" number="" targetptr="box.fiber.yield"><ttl>???TITLE???</ttl><xreftext>box.fiber.yield(...)</xreftext></obj></div><div element="section" href="#sp-box-session" number="" targetptr="sp-box-session"><ttl>Package <code class="code">box.session</code></ttl><xreftext>the section called “Package <code class="code">box.session</code>â€</xreftext></div><div element="section" href="#sp-box-ipc" number="" targetptr="sp-box-ipc"><ttl>Package <code class="code">box.ipc</code> — inter procedure communication</ttl><xreftext>the section called “Package <code class="code">box.ipc</code> — inter procedure communicationâ€</xreftext><obj element="variablelist" href="#box.ipc" number="" targetptr="box.ipc"><ttl>???TITLE???</ttl><xreftext>???TITLE???</xreftext></obj></div><div element="section" href="#sp-box-socket" number="" targetptr="sp-box-socket"><ttl>Package <code class="code">box.socket</code> — TCP and UDP sockets</ttl><xreftext>the section called “Package <code class="code">box.socket</code> — TCP and UDP socketsâ€</xreftext><obj element="variablelist" href="#box.socket" number="" targetptr="box.socket"><ttl>???TITLE???</ttl><xreftext>???TITLE???</xreftext></obj><obj element="table" href="#idp712288" number="4.4"><ttl><code class="code">readline()</code> returns</ttl><xreftext>Table 4.4, “<code class="code">readline()</code> returnsâ€</xreftext></obj></div><div element="section" href="#sp-box-net-box" number="" targetptr="sp-box-net-box"><ttl>Package <code class="code">box.net.box</code> — working with networked Tarantool peers</ttl><xreftext>the section called “Package <code class="code">box.net.box</code> — working with networked Tarantool peersâ€</xreftext><obj element="variablelist" href="#box.net.box" number="" targetptr="box.net.box"><ttl>???TITLE???</ttl><xreftext>???TITLE???</xreftext></obj><obj element="emphasis" href="#box.net.box.new" number="" targetptr="box.net.box.new"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.net.box.ping" number="" targetptr="box.net.box.ping"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.net.box.close" number="" targetptr="box.net.box.close"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.net.box.select" number="" targetptr="box.net.box.select"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.net.box.select_limit" number="" targetptr="box.net.box.select_limit"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.net.box.select_range" number="" targetptr="box.net.box.select_range"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.net.box.insert" number="" targetptr="box.net.box.insert"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.net.box.replace" number="" targetptr="box.net.box.replace"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.net.box.update" number="" targetptr="box.net.box.update"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.net.box.delete" number="" targetptr="box.net.box.delete"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.net.box.call" number="" targetptr="box.net.box.call"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.net.box.timeout" number="" targetptr="box.net.box.timeout"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj></div><div element="section" href="#sp-box-cfg" number="" targetptr="sp-box-cfg"><ttl>Packages <code class="code">box.cfg</code>, <code class="code">box.info</code>, <code class="code">box.slab</code> and <code class="code">box.stat</code>: server introspection</ttl><xreftext>the section called “Packages <code class="code">box.cfg</code>, <code class="code">box.info</code>, <code class="code">box.slab</code> and - <code class="code">box.stat</code>: server introspectionâ€</xreftext><obj element="code" href="#box.cfg" number="" targetptr="box.cfg"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="code" href="#box.stat" number="" targetptr="box.stat"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj></div><div element="section" href="#sp-limitations" number="" targetptr="sp-limitations"><ttl>Limitation of stored procedures</ttl><xreftext>the section called “Limitation of stored proceduresâ€</xreftext></div></div><div element="section" href="#triggers" number="" targetptr="triggers"><ttl>Defining triggers in Lua</ttl><xreftext>the section called “Defining triggers in Luaâ€</xreftext><div element="section" href="#sp-box-session-triggers" number="" targetptr="sp-box-session-triggers"><ttl>Triggers on connect and disconnect</ttl><xreftext>session triggers</xreftext></div></div></div><div element="chapter" href="#replication" number="5" targetptr="replication"><ttl>Replication</ttl><xreftext>Chapter 5, <i>Replication</i></xreftext><div element="section" href="#replication-architecture" number="" targetptr="replication-architecture"><ttl>Replication architecture</ttl><xreftext>the section called “Replication architectureâ€</xreftext></div><div element="section" href="#setting-up-the-master" number="" targetptr="setting-up-the-master"><ttl>Setting up the master</ttl><xreftext>the section called “Setting up the masterâ€</xreftext></div><div element="section" href="#settin-up-a-replica" number="" targetptr="settin-up-a-replica"><ttl>Setting up a replica</ttl><xreftext>the section called “Setting up a replicaâ€</xreftext></div><div element="section" href="#recovering-from-a-degraded-state" number="" targetptr="recovering-from-a-degraded-state"><ttl>Recovering from a degraded state</ttl><xreftext>the section called “Recovering from a degraded stateâ€</xreftext></div></div><div element="chapter" href="#configuration-reference" number="6" targetptr="configuration-reference"><ttl>Configuration reference</ttl><xreftext>Chapter 6, <i>Configuration reference</i></xreftext><div element="section" href="#command-line-options" number="" targetptr="command-line-options"><ttl>Command line options</ttl><xreftext>the section called “Command line optionsâ€</xreftext><obj element="listitem" href="#help-option" number="" targetptr="help-option"><ttl>???TITLE???</ttl><xreftext/></obj><obj element="listitem" href="#version-option" number="" targetptr="version-option"><ttl>???TITLE???</ttl><xreftext/></obj><obj element="listitem" href="#config-option" number="" targetptr="config-option"><ttl>???TITLE???</ttl><xreftext/></obj><obj element="option" href="#init-storage-option" number="" targetptr="init-storage-option"><ttl>???TITLE???</ttl><xreftext>--init-storage</xreftext></obj><obj element="option" href="#cat-option" number="" targetptr="cat-option"><ttl>???TITLE???</ttl><xreftext>--cat</xreftext></obj></div><div element="section" href="#option-file" number="" targetptr="option-file"><ttl>The option file</ttl><xreftext>option file</xreftext><obj element="table" href="#idp1180064" number="6.1"><ttl>Basic parameters</ttl><xreftext>Table 6.1, “Basic parametersâ€</xreftext></obj><obj element="entry" href="#work_dir" number="" targetptr="work_dir"><ttl>???TITLE???</ttl><xreftext>work_dir</xreftext></obj><obj element="entry" href="#wal_dir" number="" targetptr="wal_dir"><ttl>???TITLE???</ttl><xreftext>wal_dir</xreftext></obj><obj element="entry" href="#snap_dir" number="" targetptr="snap_dir"><ttl>???TITLE???</ttl><xreftext>snap_dir</xreftext></obj><obj element="entry" href="#bind_ipaddr" number="" targetptr="bind_ipaddr"><ttl>???TITLE???</ttl><xreftext>bind_ipaddr</xreftext></obj><obj element="entry" href="#primary_port" number="" targetptr="primary_port"><ttl>???TITLE???</ttl><xreftext>primary_port</xreftext></obj><obj element="entry" href="#secondary_port" number="" targetptr="secondary_port"><ttl>???TITLE???</ttl><xreftext>secondary_port</xreftext></obj><obj element="entry" href="#admin_port" number="" targetptr="admin_port"><ttl>???TITLE???</ttl><xreftext>admin_port</xreftext></obj><obj element="entry" href="#custom_proc_title" number="" targetptr="custom_proc_title"><ttl>???TITLE???</ttl><xreftext>custom_proc_title</xreftext></obj><obj element="table" href="#idp1233728" number="6.2"><ttl>Configuring the storage</ttl><xreftext>Table 6.2, “Configuring the storageâ€</xreftext></obj><obj element="anchor" href="#slab_alloc_arena" number="" targetptr="slab_alloc_arena"><ttl>???TITLE???</ttl><xreftext>slab_alloc_arena</xreftext></obj><obj element="para" href="#space" number="" targetptr="space"><ttl>???TITLE???</ttl><xreftext>the section called “The option fileâ€</xreftext></obj><obj element="table" href="#idp1269856" number="6.3"><ttl>Binary logging and snapshots</ttl><xreftext>Table 6.3, “Binary logging and snapshotsâ€</xreftext></obj><obj element="entry" href="#rows_per_wal" number="" targetptr="rows_per_wal"><ttl>???TITLE???</ttl><xreftext>rows_per_wal</xreftext></obj><obj element="entry" href="#wal_mode" number="" targetptr="wal_mode"><ttl>???TITLE???</ttl><xreftext>wal_mode</xreftext></obj><obj element="table" href="#idp1305184" number="6.4"><ttl>Replication</ttl><xreftext>Table 6.4, “Replicationâ€</xreftext></obj><obj element="entry" href="#replication_port" number="" targetptr="replication_port"><ttl>???TITLE???</ttl><xreftext>replication_port</xreftext></obj><obj element="entry" href="#replication_source" number="" targetptr="replication_source"><ttl>???TITLE???</ttl><xreftext>replication_source</xreftext></obj><obj element="table" href="#idp1324288" number="6.5"><ttl>Networking</ttl><xreftext>Table 6.5, “Networkingâ€</xreftext></obj><obj element="table" href="#idp1343056" number="6.6"><ttl>Logging</ttl><xreftext>Table 6.6, “Loggingâ€</xreftext></obj><obj element="table" href="#idp1367952" number="6.7"><ttl>Memcached protocol support</ttl><xreftext>Table 6.7, “Memcached protocol supportâ€</xreftext></obj><obj element="anchor" href="#memcached_port" number="" targetptr="memcached_port"><ttl>???TITLE???</ttl><xreftext>memcached_port</xreftext></obj><obj element="anchor" href="#memcached_space" number="" targetptr="memcached_space"><ttl>???TITLE???</ttl><xreftext>memcached_space</xreftext></obj><obj element="anchor" href="#memcached_expire" number="" targetptr="memcached_expire"><ttl>???TITLE???</ttl><xreftext>memcached_expire</xreftext></obj></div></div><div element="chapter" href="#connectors" number="7" targetptr="connectors"><ttl>Connectors</ttl><xreftext>Chapter 7, <i>Connectors</i></xreftext><div element="section" href="#connector-c" number="" targetptr="connector-c"><ttl>C</ttl><xreftext>the section called “Câ€</xreftext></div><div element="section" href="#connector-node.js" number="" targetptr="connector-node.js"><ttl>node.js</ttl><xreftext>the section called “node.jsâ€</xreftext></div><div element="section" href="#connector-perl" number="" targetptr="connector-perl"><ttl>Perl</ttl><xreftext>the section called “Perlâ€</xreftext></div><div element="section" href="#connector-php" number="" targetptr="connector-php"><ttl>PHP</ttl><xreftext>the section called “PHPâ€</xreftext></div><div element="section" href="#connector-python" number="" targetptr="connector-python"><ttl>Python</ttl><xreftext>the section called “Pythonâ€</xreftext></div><div element="section" href="#connector-ruby" number="" targetptr="connector-ruby"><ttl>Ruby</ttl><xreftext>the section called “Rubyâ€</xreftext></div></div><div element="chapter" href="#os-install-notes" number="8" targetptr="os-install-notes"><ttl>System-specific installation notes</ttl><xreftext>Chapter 8, <i>System-specific installation notes</i></xreftext><div element="section" href="#Debian" number="" targetptr="Debian"><ttl>Debian GNU/Linux and Ubuntu</ttl><xreftext>the section called “Debian GNU/Linux and Ubuntuâ€</xreftext></div><div element="section" href="#rpm-based-distros" number="" targetptr="rpm-based-distros"><ttl>Fedora, RHEL, CentOS</ttl><xreftext>the section called “Fedora, RHEL, CentOSâ€</xreftext></div><div element="section" href="#FreeBSD" number="" targetptr="FreeBSD"><ttl>FreeBSD</ttl><xreftext>the section called “FreeBSDâ€</xreftext></div><div element="section" href="#mac-os-x" number="" targetptr="mac-os-x"><ttl>Mac OS X</ttl><xreftext>the section called “Mac OS Xâ€</xreftext></div></div><div element="appendix" href="#proctitle" number="A" targetptr="proctitle"><ttl>Server process titles</ttl><xreftext>Appendix A, <i>Server process titles</i></xreftext></div><div element="appendix" href="#errcode" number="B" targetptr="errcode"><ttl>List of error codes</ttl><xreftext>Appendix B, <i>List of error codes</i></xreftext><obj element="term" href="#ER_NONMASTER" number="" targetptr="ER_NONMASTER"><ttl>???TITLE???</ttl><xreftext>ER_NONMASTER</xreftext></obj><obj element="term" href="#ER_ILLEGAL_PARAMS" number="" targetptr="ER_ILLEGAL_PARAMS"><ttl>???TITLE???</ttl><xreftext>ER_ILLEGAL_PARAMS</xreftext></obj><obj element="term" href="#ER_TUPLE_IS_RO" number="" targetptr="ER_TUPLE_IS_RO"><ttl>???TITLE???</ttl><xreftext>ER_TUPLE_IS_RO</xreftext></obj><obj element="term" href="#ER_MEMORY_ISSUE" number="" targetptr="ER_MEMORY_ISSUE"><ttl>???TITLE???</ttl><xreftext>ER_MEMORY_ISSUE</xreftext></obj><obj element="term" href="#ER_WAL_IO" number="" targetptr="ER_WAL_IO"><ttl>???TITLE???</ttl><xreftext>ER_WAL_IO</xreftext></obj><obj element="term" href="#ER_INDEX_VIOLATION" number="" targetptr="ER_INDEX_VIOLATION"><ttl>???TITLE???</ttl><xreftext>ER_INDEX_VIOLATION</xreftext></obj><obj element="term" href="#ER_KEY_PART_COUNT" number="" targetptr="ER_KEY_PART_COUNT"><ttl>???TITLE???</ttl><xreftext>ER_KEY_PART_COUNT</xreftext></obj><obj element="term" href="#ER_NO_SUCH_SPACE" number="" targetptr="ER_NO_SUCH_SPACE"><ttl>???TITLE???</ttl><xreftext>ER_NO_SUCH_SPACE</xreftext></obj><obj element="term" href="#ER_NO_SUCH_INDEX" number="" targetptr="ER_NO_SUCH_INDEX"><ttl>???TITLE???</ttl><xreftext>ER_NO_SUCH_INDEX</xreftext></obj><obj element="term" href="#ER_PROC_LUA" number="" targetptr="ER_PROC_LUA"><ttl>???TITLE???</ttl><xreftext>ER_PROC_LUA</xreftext></obj></div></div> + <code class="code">box.stat</code>: server introspectionâ€</xreftext><obj element="code" href="#box.cfg" number="" targetptr="box.cfg"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="code" href="#box.stat" number="" targetptr="box.stat"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj></div><div element="section" href="#sp-limitations" number="" targetptr="sp-limitations"><ttl>Limitation of stored procedures</ttl><xreftext>the section called “Limitation of stored proceduresâ€</xreftext></div></div><div element="section" href="#triggers" number="" targetptr="triggers"><ttl>Defining triggers in Lua</ttl><xreftext>the section called “Defining triggers in Luaâ€</xreftext><div element="section" href="#sp-box-session-triggers" number="" targetptr="sp-box-session-triggers"><ttl>Triggers on connect and disconnect</ttl><xreftext>session triggers</xreftext></div></div></div><div element="chapter" href="#replication" number="5" targetptr="replication"><ttl>Replication</ttl><xreftext>Chapter 5, <i>Replication</i></xreftext><div element="section" href="#replication-architecture" number="" targetptr="replication-architecture"><ttl>Replication architecture</ttl><xreftext>the section called “Replication architectureâ€</xreftext></div><div element="section" href="#setting-up-the-master" number="" targetptr="setting-up-the-master"><ttl>Setting up the master</ttl><xreftext>the section called “Setting up the masterâ€</xreftext></div><div element="section" href="#settin-up-a-replica" number="" targetptr="settin-up-a-replica"><ttl>Setting up a replica</ttl><xreftext>the section called “Setting up a replicaâ€</xreftext></div><div element="section" href="#recovering-from-a-degraded-state" number="" targetptr="recovering-from-a-degraded-state"><ttl>Recovering from a degraded state</ttl><xreftext>the section called “Recovering from a degraded stateâ€</xreftext></div></div><div element="chapter" href="#server-administration" number="6" targetptr="server-administration"><ttl>Server administration</ttl><xreftext>Chapter 6, <i>Server administration</i></xreftext><div element="section" href="#signal-handling" number="" targetptr="signal-handling"><ttl>Server signal handling</ttl><xreftext>the section called “Server signal handlingâ€</xreftext></div><div element="section" href="#os-install-notes" number="" targetptr="os-install-notes"><ttl>System-specific administration notes</ttl><xreftext>the section called “System-specific administration notesâ€</xreftext><div element="section" href="#Debian" number="" targetptr="Debian"><ttl>Debian GNU/Linux and Ubuntu</ttl><xreftext>the section called “Debian GNU/Linux and Ubuntuâ€</xreftext></div><div element="section" href="#rpm-based-distros" number="" targetptr="rpm-based-distros"><ttl>Fedora, RHEL, CentOS</ttl><xreftext>the section called “Fedora, RHEL, CentOSâ€</xreftext></div><div element="section" href="#FreeBSD" number="" targetptr="FreeBSD"><ttl>FreeBSD</ttl><xreftext>the section called “FreeBSDâ€</xreftext></div><div element="section" href="#mac-os-x" number="" targetptr="mac-os-x"><ttl>Mac OS X</ttl><xreftext>the section called “Mac OS Xâ€</xreftext></div></div></div><div element="chapter" href="#configuration-reference" number="7" targetptr="configuration-reference"><ttl>Configuration reference</ttl><xreftext>Chapter 7, <i>Configuration reference</i></xreftext><div element="section" href="#command-line-options" number="" targetptr="command-line-options"><ttl>Command line options</ttl><xreftext>the section called “Command line optionsâ€</xreftext><obj element="listitem" href="#help-option" number="" targetptr="help-option"><ttl>???TITLE???</ttl><xreftext/></obj><obj element="listitem" href="#version-option" number="" targetptr="version-option"><ttl>???TITLE???</ttl><xreftext/></obj><obj element="listitem" href="#config-option" number="" targetptr="config-option"><ttl>???TITLE???</ttl><xreftext/></obj><obj element="option" href="#init-storage-option" number="" targetptr="init-storage-option"><ttl>???TITLE???</ttl><xreftext>--init-storage</xreftext></obj></div><div element="section" href="#option-file" number="" targetptr="option-file"><ttl>The option file</ttl><xreftext>option file</xreftext><obj element="table" href="#idp1279216" number="7.1"><ttl>Basic parameters</ttl><xreftext>Table 7.1, “Basic parametersâ€</xreftext></obj><obj element="entry" href="#work_dir" number="" targetptr="work_dir"><ttl>???TITLE???</ttl><xreftext>work_dir</xreftext></obj><obj element="entry" href="#wal_dir" number="" targetptr="wal_dir"><ttl>???TITLE???</ttl><xreftext>wal_dir</xreftext></obj><obj element="entry" href="#snap_dir" number="" targetptr="snap_dir"><ttl>???TITLE???</ttl><xreftext>snap_dir</xreftext></obj><obj element="entry" href="#bind_ipaddr" number="" targetptr="bind_ipaddr"><ttl>???TITLE???</ttl><xreftext>bind_ipaddr</xreftext></obj><obj element="entry" href="#primary_port" number="" targetptr="primary_port"><ttl>???TITLE???</ttl><xreftext>primary_port</xreftext></obj><obj element="entry" href="#secondary_port" number="" targetptr="secondary_port"><ttl>???TITLE???</ttl><xreftext>secondary_port</xreftext></obj><obj element="entry" href="#admin_port" number="" targetptr="admin_port"><ttl>???TITLE???</ttl><xreftext>admin_port</xreftext></obj><obj element="entry" href="#custom_proc_title" number="" targetptr="custom_proc_title"><ttl>???TITLE???</ttl><xreftext>custom_proc_title</xreftext></obj><obj element="table" href="#idp1332880" number="7.2"><ttl>Configuring the storage</ttl><xreftext>Table 7.2, “Configuring the storageâ€</xreftext></obj><obj element="anchor" href="#slab_alloc_arena" number="" targetptr="slab_alloc_arena"><ttl>???TITLE???</ttl><xreftext>slab_alloc_arena</xreftext></obj><obj element="para" href="#space" number="" targetptr="space"><ttl>???TITLE???</ttl><xreftext>the section called “The option fileâ€</xreftext></obj><obj element="table" href="#idp1368816" number="7.3"><ttl>Binary logging and snapshots</ttl><xreftext>Table 7.3, “Binary logging and snapshotsâ€</xreftext></obj><obj element="entry" href="#rows_per_wal" number="" targetptr="rows_per_wal"><ttl>???TITLE???</ttl><xreftext>rows_per_wal</xreftext></obj><obj element="entry" href="#wal_mode" number="" targetptr="wal_mode"><ttl>???TITLE???</ttl><xreftext>wal_mode</xreftext></obj><obj element="table" href="#idp1404208" number="7.4"><ttl>Replication</ttl><xreftext>Table 7.4, “Replicationâ€</xreftext></obj><obj element="entry" href="#replication_port" number="" targetptr="replication_port"><ttl>???TITLE???</ttl><xreftext>replication_port</xreftext></obj><obj element="entry" href="#replication_source" number="" targetptr="replication_source"><ttl>???TITLE???</ttl><xreftext>replication_source</xreftext></obj><obj element="table" href="#idp1423248" number="7.5"><ttl>Networking</ttl><xreftext>Table 7.5, “Networkingâ€</xreftext></obj><obj element="table" href="#idp1442576" number="7.6"><ttl>Logging</ttl><xreftext>Table 7.6, “Loggingâ€</xreftext></obj><obj element="table" href="#idp1467472" number="7.7"><ttl>Memcached protocol support</ttl><xreftext>Table 7.7, “Memcached protocol supportâ€</xreftext></obj><obj element="anchor" href="#memcached_port" number="" targetptr="memcached_port"><ttl>???TITLE???</ttl><xreftext>memcached_port</xreftext></obj><obj element="anchor" href="#memcached_space" number="" targetptr="memcached_space"><ttl>???TITLE???</ttl><xreftext>memcached_space</xreftext></obj><obj element="anchor" href="#memcached_expire" number="" targetptr="memcached_expire"><ttl>???TITLE???</ttl><xreftext>memcached_expire</xreftext></obj></div></div><div element="chapter" href="#connectors" number="8" targetptr="connectors"><ttl>Connectors</ttl><xreftext>Chapter 8, <i>Connectors</i></xreftext><div element="section" href="#connector-c" number="" targetptr="connector-c"><ttl>C</ttl><xreftext>the section called “Câ€</xreftext></div><div element="section" href="#connector-node.js" number="" targetptr="connector-node.js"><ttl>node.js</ttl><xreftext>the section called “node.jsâ€</xreftext></div><div element="section" href="#connector-perl" number="" targetptr="connector-perl"><ttl>Perl</ttl><xreftext>the section called “Perlâ€</xreftext></div><div element="section" href="#connector-php" number="" targetptr="connector-php"><ttl>PHP</ttl><xreftext>the section called “PHPâ€</xreftext></div><div element="section" href="#connector-python" number="" targetptr="connector-python"><ttl>Python</ttl><xreftext>the section called “Pythonâ€</xreftext></div><div element="section" href="#connector-ruby" number="" targetptr="connector-ruby"><ttl>Ruby</ttl><xreftext>the section called “Rubyâ€</xreftext></div></div><div element="appendix" href="#proctitle" number="A" targetptr="proctitle"><ttl>Server process titles</ttl><xreftext>Appendix A, <i>Server process titles</i></xreftext></div><div element="appendix" href="#errcode" number="B" targetptr="errcode"><ttl>List of error codes</ttl><xreftext>Appendix B, <i>List of error codes</i></xreftext><obj element="term" href="#ER_NONMASTER" number="" targetptr="ER_NONMASTER"><ttl>???TITLE???</ttl><xreftext>ER_NONMASTER</xreftext></obj><obj element="term" href="#ER_ILLEGAL_PARAMS" number="" targetptr="ER_ILLEGAL_PARAMS"><ttl>???TITLE???</ttl><xreftext>ER_ILLEGAL_PARAMS</xreftext></obj><obj element="term" href="#ER_MEMORY_ISSUE" number="" targetptr="ER_MEMORY_ISSUE"><ttl>???TITLE???</ttl><xreftext>ER_MEMORY_ISSUE</xreftext></obj><obj element="term" href="#ER_WAL_IO" number="" targetptr="ER_WAL_IO"><ttl>???TITLE???</ttl><xreftext>ER_WAL_IO</xreftext></obj><obj element="term" href="#ER_INDEX_VIOLATION" number="" targetptr="ER_INDEX_VIOLATION"><ttl>???TITLE???</ttl><xreftext>ER_INDEX_VIOLATION</xreftext></obj><obj element="term" href="#ER_KEY_PART_COUNT" number="" targetptr="ER_KEY_PART_COUNT"><ttl>???TITLE???</ttl><xreftext>ER_KEY_PART_COUNT</xreftext></obj><obj element="term" href="#ER_NO_SUCH_SPACE" number="" targetptr="ER_NO_SUCH_SPACE"><ttl>???TITLE???</ttl><xreftext>ER_NO_SUCH_SPACE</xreftext></obj><obj element="term" href="#ER_NO_SUCH_INDEX" number="" targetptr="ER_NO_SUCH_INDEX"><ttl>???TITLE???</ttl><xreftext>ER_NO_SUCH_INDEX</xreftext></obj><obj element="term" href="#ER_PROC_LUA" number="" targetptr="ER_PROC_LUA"><ttl>???TITLE???</ttl><xreftext>ER_PROC_LUA</xreftext></obj></div></div> diff --git a/extra/pack_lua b/extra/pack_lua deleted file mode 100755 index 9d564c935c..0000000000 --- a/extra/pack_lua +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/perl - -use warnings; -use strict; - -use utf8; -use open qw(:std :utf8); - -use File::Basename qw(dirname basename); -use Getopt::Long qw(GetOptions); -use Pod::Usage; - -sub quote($) { - my ($str) = @_; - for ($str) { - s/\\/\\\\/g; - s/"/\\"/g; - s/\n/\\n/gs; - s/\r/\\r/gs; - s/\t/\\t/gs; - s/(.)/(ord($1) < 0x20) ? sprintf('\\x%02X', ord $1) : $1/ges; - } - $str; -} - -GetOptions - 'o|output=s' => \my $output, - 'h|help' => \my $help -; - -pod2usage({ -verbose => 2}) if $help; -pod2usage unless @ARGV; - -if ($output) { - close STDOUT; - open STDOUT, '>', $output or die "Can't write file $output: $!\n"; -} - -printf <<eof, basename($0), join "\n *\t- ", @ARGV; -/* - * Autogenerated file by 'extra/%s' from: - *\t- %s - */ - -const struct { const char *file, *body; } box_lua[] = { -eof - -for (0 .. $#ARGV) { - print qq[\t{\n]; - printf qq{\t\t"%s",\n}, quote basename $ARGV[$_]; - open my $fh, '<', $ARGV[$_] or die "Can't open file $ARGV[$_]: $!\n"; - printf qq{\t\t"%s"\n}, quote $_ for <$fh>; - print "\t},\n"; -} - -print "\t{ 0, 0 }\n};\n\n"; - -=head1 NAME - -extra/pack_lua - packs internal lua files into one C-module - -=head1 SYNOPSIS - - perl extra/pack_lua -o output.file.c file1.lua file2.lua ... - -=cut diff --git a/include/errcode.h b/include/errcode.h index b0dac16fb8..2675b113e6 100644 --- a/include/errcode.h +++ b/include/errcode.h @@ -78,7 +78,7 @@ enum { TNT_ERRMSG_MAX = 512 }; /* end of silverproxy error codes */ \ /* 24 */_(ER_UNUSED24, 2, "Unused24") \ /* 25 */_(ER_TUPLE_IS_EMPTY, 2, "UPDATE error: the new tuple has no fields") \ - /* 26 */_(ER_UNUSED26, 2, "Unused26") \ + /* 26 */_(ER_FIBER_STACK, 2, "Can not create a new fiber: recursion limit reached") \ /* 27 */_(ER_UNUSED27, 2, "Unused27") \ /* 28 */_(ER_UNUSED28, 2, "Unused28") \ /* 29 */_(ER_UNUSED29, 2, "Unused29") \ diff --git a/include/fiber.h b/include/fiber.h index 49dda87f2f..a78a677e5f 100644 --- a/include/fiber.h +++ b/include/fiber.h @@ -106,6 +106,9 @@ fiber_name(struct fiber *f) return palloc_name(f->gc_pool); } +void +fiber_checkstack(); + void fiber_yield(void); void fiber_yield_to(struct fiber *f); diff --git a/src/box/CMakeLists.txt b/src/box/CMakeLists.txt index 63fac40f9c..18d03b8993 100644 --- a/src/box/CMakeLists.txt +++ b/src/box/CMakeLists.txt @@ -2,36 +2,33 @@ if (TARGET_OS_DARWIN) set(module_link_flags "-pagezero_size 10000 -image_base 100000000") endif() - - -aux_source_directory(${CMAKE_SOURCE_DIR}/src/box/lua lua_sources) - - -set(lua_sources - ${lua_sources} - ${CMAKE_SOURCE_DIR}/src/box/lua/box.net.lua - ${CMAKE_SOURCE_DIR}/src/box/lua/box.lua - ${CMAKE_SOURCE_DIR}/src/box/lua/box.autoincrement.lua - ${CMAKE_SOURCE_DIR}/src/box/lua/box.bless_space.lua - ${CMAKE_SOURCE_DIR}/src/box/lua/box.counter.lua - ${CMAKE_SOURCE_DIR}/src/box/lua/box.fiber.lua - -) - -add_custom_command( - OUTPUT ${CMAKE_BINARY_DIR}/src/box/box.lua.c - DEPENDS ${lua_sources} ${CMAKE_SOURCE_DIR}/extra/pack_lua - WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/src/box - COMMAND ${CMAKE_SOURCE_DIR}/extra/pack_lua -o ${CMAKE_BINARY_DIR}/src/box/box.lua.c ${lua_sources} -) - - +function(lua_source filename) + get_filename_component(module ${filename} NAME_WE) + ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_BINARY_DIR}/src/box/${filename}.c + COMMAND ${ECHO} 'const char ${module}_lua[] =' > ${filename}.new.c + COMMAND ${CMAKE_BINARY_DIR}/extra/txt2c + ${CMAKE_SOURCE_DIR}/src/box/${filename} >> ${filename}.new.c + COMMAND ${ECHO} '\;' >> ${filename}.new.c + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${filename}.new.c + ${CMAKE_BINARY_DIR}/src/box/${filename}.c + COMMAND ${CMAKE_COMMAND} -E remove ${filename}.new.c + DEPENDS ${CMAKE_SOURCE_DIR}/src/box/${filename} txt2c) + + set(lua_sources ${lua_sources} ${CMAKE_BINARY_DIR}/src/box/${filename}.c + PARENT_SCOPE) +endfunction() + +lua_source(lua/box.lua) +lua_source(lua/box_net.lua) +lua_source(lua/misc.lua) + +add_custom_target(generate_lua_sources} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/src/box + DEPENDS ${lua_sources}) set_property(DIRECTORY PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${lua_sources}) tarantool_module("box" tuple.m index.m hash_index.m tree_index.m space.m - port.m request.m txn.m box.m box_lua.m box_lua_space.m - bitset_index.m - ${CMAKE_BINARY_DIR}/src/box/box.lua.c -) + port.m request.m txn.m box.m ${lua_sources} box_lua.m box_lua_space.m + bitset_index.m) target_link_libraries(tarantool_box bitset) diff --git a/src/box/box_lua.m b/src/box/box_lua.m index ce0657d0f8..747284bdc9 100644 --- a/src/box/box_lua.m +++ b/src/box/box_lua.m @@ -47,6 +47,9 @@ #include "port.h" #include "tbuf.h" +/* contents of box.lua, misc.lua, box.net.lua respectively */ +extern char box_lua[], box_net_lua[], misc_lua[]; +const char *lua_sources[] = { box_lua, box_net_lua, misc_lua, NULL }; /** * All box connections share the same Lua state. We use @@ -1276,11 +1279,14 @@ box_lua_find(lua_State *L, const char *name, const char *name_end) /** - * A helper to find lua objects by box.find + * A helper to find lua stored procedures for box.call. + * box.call iteslf is pure Lua, to avoid issues + * with infinite call recursion smashing C + * thread stack. */ static int -lbox_find(struct lua_State *L) +lbox_call_loadproc(struct lua_State *L) { const char *name; size_t name_len; @@ -1624,6 +1630,29 @@ lbox_pack(struct lua_State *L) return 1; } +const char * +box_unpack_response(struct lua_State *L, const void *s, const void *end) +{ + u32 tuple_count = pick_u32(&s, end); + + /* Unpack and push tuples. */ + while (tuple_count--) { + u32 bsize = pick_u32(&s, end); + u32 field_count = pick_u32(&s, end); + if (valid_tuple(s, end, field_count) != bsize) + luaL_error(L, "box.unpack(): can't unpack tuple"); + + struct tuple *t = tuple_alloc(bsize); + t->field_count = field_count; + memcpy(t->data, s, bsize); + + s += bsize; + lbox_pushtuple(L, t); + } + return s; +} + + static int lbox_unpack(struct lua_State *L) { @@ -1636,7 +1665,7 @@ lbox_unpack(struct lua_State *L) const void *end = str + str_size; const void *s = str; - int i = 0; + int save_stacksize = lua_gettop(L); char charbuf; u8 u8buf; @@ -1679,7 +1708,7 @@ lbox_unpack(struct lua_State *L) break; case 'a': - case 'A': + case 'A': /* The rest of the data is a Lua string. */ lua_pushlstring(L, s, end - s); s = end; break; @@ -1729,85 +1758,34 @@ lbox_unpack(struct lua_State *L) s += 5; break; - case 'R': { - if (end - s < 4) - goto WRONG_RESPONSE; - u32 count = *(u32 *)s; - s += 4; - - if (s == end) { - lua_pushnumber(L, count); - break; - } - while(count--) { - if (end - s < 4) - goto WRONG_RESPONSE; - u32 size = *(u32 *)s; - s += 4; - - if (end - s < size) - goto WRONG_RESPONSE; - - if (end - s < 4) - goto WRONG_RESPONSE; - u32 c = *(u32 *)s; - s += 4; - - - /* check input tuple */ - typeof(s) tdata = s; - for (u32 j = 0; j < c; j++) { - u32 fsize = pick_varint32(&tdata, end); - if (end - tdata < fsize) - goto WRONG_RESPONSE; - tdata += fsize; - } - if (tdata != s + size) - goto WRONG_RESPONSE; - - - struct tuple * t = tuple_alloc(size); - t->field_count = c; - memcpy(t->data, s, size); - - s += size; - lbox_pushtuple(L, t); - - /* latest increment outside switch */ - if (count) - i++; - - } - + case 'R': /* Unpack server response, IPROTO format. */ + { + s = box_unpack_response(L, s, end); break; - WRONG_RESPONSE: - luaL_error(L, "Can't parse response body"); - } - default: luaL_error(L, "box.unpack: unsupported " "format specifier '%c'", *f); } - i++; f++; } + assert(s <= end); + if (s != end) { luaL_error(L, "box.unpack('%s'): too many bytes: " "unpacked %d, total %d", format, s - str, str_size); } - return i; + return lua_gettop(L) - save_stacksize; #undef CHECK_SIZE } - static const struct luaL_reg boxlib[] = { {"process", lbox_process}, - {"find", lbox_find}, + {"call_loadproc", lbox_call_loadproc}, {"raise", lbox_raise}, {"pack", lbox_pack}, {"unpack", lbox_unpack}, @@ -1830,14 +1808,11 @@ mod_lua_init(struct lua_State *L) lua_pop(L, 1); tarantool_lua_register_type(L, iteratorlib_name, lbox_iterator_meta); - extern const struct { const char *file, *body; } box_lua[]; - for (int i = 0; box_lua[i].file; i++) { - say_debug("Processing internal lua file %s", box_lua[i].file); - /* Load box.lua */ - if (luaL_dostring(L, box_lua[i].body)) { - panic("Error loading '%s': %s", - box_lua[i].file, lua_tostring(L, -1)); - } + /* Load Lua extension */ + for (const char **s = lua_sources; *s; s++) { + if (luaL_dostring(L, *s)) + panic("Error loading Lua source %.160s...: %s", + *s, lua_tostring(L, -1)); } assert(lua_gettop(L) == 0); diff --git a/src/box/lua/box.autoincrement.lua b/src/box/lua/box.autoincrement.lua deleted file mode 100644 index feef39d716..0000000000 --- a/src/box/lua/box.autoincrement.lua +++ /dev/null @@ -1,22 +0,0 @@ --- Assumes that spaceno has a TREE int32 (NUM) or int64 (NUM64) primary key --- inserts a tuple after getting the next value of the --- primary key and returns it back to the user -function box.auto_increment(spaceno, ...) - spaceno = tonumber(spaceno) - local max_tuple = box.space[spaceno].index[0].idx:max() - local max = 0 - if max_tuple ~= nil then - max = max_tuple[0] - local fmt = 'i' - if #max == 8 then fmt = 'l' end - max = box.unpack(fmt, max) - else - -- first time - if box.space[spaceno].index[0].key_field[0].type == "NUM64" then - max = tonumber64(max) - end - end - return box.insert(spaceno, max + 1, ...) -end - - diff --git a/src/box/lua/box.bless_space.lua b/src/box/lua/box.bless_space.lua deleted file mode 100644 index 49e83e6184..0000000000 --- a/src/box/lua/box.bless_space.lua +++ /dev/null @@ -1,111 +0,0 @@ -function box.bless_space(space) - local index_mt = {} - -- __len and __index - index_mt.len = function(index) return #index.idx end - index_mt.__newindex = function(table, index) - return error('Attempt to modify a read-only table') end - index_mt.__index = index_mt - -- min and max - index_mt.min = function(index) return index.idx:min() end - index_mt.max = function(index) return index.idx:max() end - index_mt.random = function(index, rnd) return index.idx:random(rnd) end - -- iteration - index_mt.iterator = function(index, ...) - return index.idx:iterator(...) - end - -- - -- pairs/next/prev methods are provided for backward compatibility purposes only - index_mt.pairs = function(index) - return index.idx.next, index.idx, nil - end - -- - local next_compat = function(idx, iterator_type, ...) - local arg = {...} - if #arg == 1 and type(arg[1]) == "userdata" then - return idx:next(...) - else - return idx:next(iterator_type, ...) - end - end - index_mt.next = function(index, ...) - return next_compat(index.idx, box.index.GE, ...); - end - index_mt.prev = function(index, ...) - return next_compat(index.idx, box.index.LE, ...); - end - index_mt.next_equal = function(index, ...) - return next_compat(index.idx, box.index.EQ, ...); - end - index_mt.prev_equal = function(index, ...) - return next_compat(index.idx, box.index.REQ, ...); - end - -- index subtree size - index_mt.count = function(index, ...) - return index.idx:count(...) - end - -- - index_mt.select_range = function(index, limit, ...) - local range = {} - for v in index:iterator(box.index.GE, ...) do - if #range >= limit then - break - end - table.insert(range, v) - iterator_state, v = index:next(iterator_state) - end - return unpack(range) - end - index_mt.select_reverse_range = function(index, limit, ...) - local range = {} - for v in index:iterator(box.index.LE, ...) do - if #range >= limit then - break - end - table.insert(range, v) - iterator_state, v = index:prev(iterator_state) - end - return unpack(range) - end - -- - local space_mt = {} - space_mt.len = function(space) return space.index[0]:len() end - space_mt.__newindex = index_mt.__newindex - space_mt.select = function(space, ...) return box.select(space.n, ...) end - space_mt.select_range = function(space, ino, limit, ...) - return space.index[ino]:select_range(limit, ...) - end - space_mt.select_reverse_range = function(space, ino, limit, ...) - return space.index[ino]:select_reverse_range(limit, ...) - end - space_mt.select_limit = function(space, ino, offset, limit, ...) - return box.select_limit(space.n, ino, offset, limit, ...) - end - space_mt.insert = function(space, ...) return box.insert(space.n, ...) end - space_mt.update = function(space, ...) return box.update(space.n, ...) end - space_mt.replace = function(space, ...) return box.replace(space.n, ...) end - space_mt.delete = function(space, ...) return box.delete(space.n, ...) end - space_mt.truncate = function(space) - local pk = space.index[0] - while #pk.idx > 0 do - for t in pk:iterator() do - local key = {}; - -- ipairs does not work because pk.key_field is zero-indexed - for _k2, key_field in pairs(pk.key_field) do - table.insert(key, t[key_field.fieldno]) - end - space:delete(unpack(key)) - end - end - end - space_mt.pairs = function(space) return space.index[0]:pairs() end - space_mt.__index = space_mt - - setmetatable(space, space_mt) - if type(space.index) == 'table' and space.enabled then - for j, index in pairs(space.index) do - rawset(index, 'idx', box.index.new(space.n, j)) - setmetatable(index, index_mt) - end - end -end - diff --git a/src/box/lua/box.fiber.lua b/src/box/lua/box.fiber.lua deleted file mode 100644 index 470b3ddb5b..0000000000 --- a/src/box/lua/box.fiber.lua +++ /dev/null @@ -1,21 +0,0 @@ --- --- create and start new detached fiber --- -function box.fiber.wrap(foo, ...) - if type(foo) ~= 'function' then - error "box.fiber.wrap: first argument must be function" - end - - local args = { ... } - - local f = box.fiber.create( - function() - box.fiber.detach() - foo(unpack(args)) - end - ) - - box.fiber.resume(f) - - return f -end diff --git a/src/box/lua/box.lua b/src/box/lua/box.lua index 7e7ae4ef00..a84c8126d0 100644 --- a/src/box/lua/box.lua +++ b/src/box/lua/box.lua @@ -67,6 +67,116 @@ function box.dostring(s, ...) return chunk(...) end +function box.bless_space(space) + local index_mt = {} + -- __len and __index + index_mt.len = function(index) return #index.idx end + index_mt.__newindex = function(table, index) + return error('Attempt to modify a read-only table') end + index_mt.__index = index_mt + -- min and max + index_mt.min = function(index) return index.idx:min() end + index_mt.max = function(index) return index.idx:max() end + index_mt.random = function(index, rnd) return index.idx:random(rnd) end + -- iteration + index_mt.iterator = function(index, ...) + return index.idx:iterator(...) + end + -- + -- pairs/next/prev methods are provided for backward compatibility purposes only + index_mt.pairs = function(index) + return index.idx.next, index.idx, nil + end + -- + local next_compat = function(idx, iterator_type, ...) + local arg = {...} + if #arg == 1 and type(arg[1]) == "userdata" then + return idx:next(...) + else + return idx:next(iterator_type, ...) + end + end + index_mt.next = function(index, ...) + return next_compat(index.idx, box.index.GE, ...); + end + index_mt.prev = function(index, ...) + return next_compat(index.idx, box.index.LE, ...); + end + index_mt.next_equal = function(index, ...) + return next_compat(index.idx, box.index.EQ, ...); + end + index_mt.prev_equal = function(index, ...) + return next_compat(index.idx, box.index.REQ, ...); + end + -- index subtree size + index_mt.count = function(index, ...) + return index.idx:count(...) + end + -- + index_mt.select_range = function(index, limit, ...) + local range = {} + for v in index:iterator(box.index.GE, ...) do + if #range >= limit then + break + end + table.insert(range, v) + iterator_state, v = index:next(iterator_state) + end + return unpack(range) + end + index_mt.select_reverse_range = function(index, limit, ...) + local range = {} + for v in index:iterator(box.index.LE, ...) do + if #range >= limit then + break + end + table.insert(range, v) + iterator_state, v = index:prev(iterator_state) + end + return unpack(range) + end + -- + local space_mt = {} + space_mt.len = function(space) return space.index[0]:len() end + space_mt.__newindex = index_mt.__newindex + space_mt.select = function(space, ...) return box.select(space.n, ...) end + space_mt.select_range = function(space, ino, limit, ...) + return space.index[ino]:select_range(limit, ...) + end + space_mt.select_reverse_range = function(space, ino, limit, ...) + return space.index[ino]:select_reverse_range(limit, ...) + end + space_mt.select_limit = function(space, ino, offset, limit, ...) + return box.select_limit(space.n, ino, offset, limit, ...) + end + space_mt.insert = function(space, ...) return box.insert(space.n, ...) end + space_mt.update = function(space, ...) return box.update(space.n, ...) end + space_mt.replace = function(space, ...) return box.replace(space.n, ...) end + space_mt.delete = function(space, ...) return box.delete(space.n, ...) end + space_mt.truncate = function(space) + local pk = space.index[0] + while #pk.idx > 0 do + for t in pk:iterator() do + local key = {}; + -- ipairs does not work because pk.key_field is zero-indexed + for _k2, key_field in pairs(pk.key_field) do + table.insert(key, t[key_field.fieldno]) + end + space:delete(unpack(key)) + end + end + end + space_mt.pairs = function(space) return space.index[0]:pairs() end + space_mt.__index = space_mt + + setmetatable(space, space_mt) + if type(space.index) == 'table' and space.enabled then + for j, index in pairs(space.index) do + rawset(index, 'idx', box.index.new(space.n, j)) + setmetatable(index, index_mt) + end + end +end -- User can redefine the hook function box.on_reload_configuration() diff --git a/src/box/lua/box.net.lua b/src/box/lua/box_net.lua similarity index 90% rename from src/box/lua/box.net.lua rename to src/box/lua/box_net.lua index dbb5dc3ed4..f7624b182b 100644 --- a/src/box/lua/box.net.lua +++ b/src/box/lua/box_net.lua @@ -1,4 +1,11 @@ box.net = { +-- +-- The idea of box.net.box implementation is that +-- most calls are simply wrappers around 'process' +-- function. The embedded 'process' function sends +-- requests to the local server, the remote 'process' +-- routes requests to a remote. +-- box = { delete = function(self, space, ...) local key_part_count = select('#', ...) @@ -101,6 +108,10 @@ box.net = { ) end, + -- To make use of timeouts safe across multiple + -- concurrent fibers do not store timeouts as + -- part of conection state, but put it inside + -- a helper object. timeout = function(self, timeout) @@ -108,17 +119,17 @@ box.net = { setmetatable(wrapper, { __index = function(wrp, name, ...) - local foo = self[name] - if foo ~= nil then + local func = self[name] + if func ~= nil then return function(wr, ...) - self.timeout_request = timeout - return foo(self, ...) + self.request_timeout = timeout + return func(self, ...) end end - - error(string.format('Can not find "remote:%s" function', - name)) + + error(string.format('Can not find "box.net.box.%s" function', + name)) end }); @@ -132,7 +143,7 @@ box.net = { process = function(self, ...) return box.process(...) end, - + select_range = function(self, sno, ino, limit, ...) return box.space[tonumber(sno)].index[tonumber(ino)] :select_range(tonumber(limit), ...) @@ -143,18 +154,17 @@ box.net = { :select_reverse_range(tonumber(limit), ...) end, + -- for compatibility with the networked version, + -- implement call call = function(self, proc_name, ...) - local fref = box.find(proc_name) - if type(fref) ~= 'function' then - error("object '" .. proc_name .. "' is not a function") - end - return fref(...) + local proc = box.call_loadproc(proc_name) + return proc(...) end, ping = function(self) return true end, - + -- local tarantool doesn't provide timeouts timeout = function(self, timeout) return self @@ -166,6 +176,10 @@ box.net = { } } +-- +-- Make sure box.net.box.select(conn, ...) works +-- just as well as conn:select(...) +-- setmetatable(box.net.self, { __index = box.net.box }) box.net.box.new = function(host, port, reconnect_timeout) @@ -195,7 +209,7 @@ box.net.box.new = function(host, port, reconnect_timeout) end end end, - + -- write channel wch = box.ipc.channel(1), @@ -204,12 +218,13 @@ box.net.box.new = function(host, port, reconnect_timeout) }, - + process = function(self, op, request) local started = box.time() - local timeout = self.timeout_request - self.timeout_request = nil + local timeout = self.request_timeout + self.request_timeout = nil + -- get an auto-incremented request id local sync = self.processing:next_sync() self.processing[sync] = box.ipc.channel(1) request = box.pack('iiia', op, string.len(request), sync, request) @@ -256,6 +271,7 @@ box.net.box.new = function(host, port, reconnect_timeout) box.raise(code, body) end + -- boc.unpack('R') unpacks response body for us (tuple) return box.unpack('R', body) end else @@ -298,9 +314,9 @@ box.net.box.new = function(host, port, reconnect_timeout) self:fatal("Unexpected eof while reading header") return end - + local op, blen, sync = box.unpack('iii', header) - + local body = '' if blen > 0 then res = { self.s:recv(blen) } @@ -335,7 +351,7 @@ box.net.box.new = function(host, port, reconnect_timeout) if sync == nil then break end - + if self.processing[sync] ~= nil then self.processing[sync]:put({true, resp}, 0) else @@ -405,3 +421,4 @@ box.net.box.new = function(host, port, reconnect_timeout) return remote end +-- vim: set et ts=4 sts diff --git a/src/box/lua/box.counter.lua b/src/box/lua/misc.lua similarity index 61% rename from src/box/lua/box.counter.lua rename to src/box/lua/misc.lua index 371cee82c0..b5c6651e3f 100644 --- a/src/box/lua/box.counter.lua +++ b/src/box/lua/misc.lua @@ -46,4 +46,27 @@ function box.counter.dec(space, ...) end +-- vim: set et ts=4 sts +-- Assumes that spaceno has a TREE int32 (NUM) or int64 (NUM64) primary key +-- inserts a tuple after getting the next value of the +-- primary key and returns it back to the user +function box.auto_increment(spaceno, ...) + spaceno = tonumber(spaceno) + local max_tuple = box.space[spaceno].index[0].idx:max() + local max = 0 + if max_tuple ~= nil then + max = max_tuple[0] + local fmt = 'i' + if #max == 8 then fmt = 'l' end + max = box.unpack(fmt, max) + else + -- first time + if box.space[spaceno].index[0].key_field[0].type == "NUM64" then + max = tonumber64(max) + end + end + return box.insert(spaceno, max + 1, ...) +end + + -- vim: set et ts=4 sts diff --git a/src/fiber.m b/src/fiber.m index 3a1db8efd8..4066cd910b 100644 --- a/src/fiber.m +++ b/src/fiber.m @@ -72,7 +72,7 @@ fiber_call(struct fiber *callee, ...) { struct fiber *caller = fiber; - assert(sp - call_stack < FIBER_CALL_STACK); + assert(sp + 1 - call_stack < FIBER_CALL_STACK); assert(caller); fiber = callee; @@ -89,6 +89,12 @@ fiber_call(struct fiber *callee, ...) va_end(fiber->f_data); } +void +fiber_checkstack() +{ + if (sp + 1 - call_stack >= FIBER_CALL_STACK) + tnt_raise(ClientError, :ER_FIBER_STACK); +} /** Interrupt a synchronous wait of a fiber inside the event loop. * We do so by keeping an "async" event in every fiber, solely diff --git a/src/lua/init.m b/src/lua/init.m index c128c554b8..be88775846 100644 --- a/src/lua/init.m +++ b/src/lua/init.m @@ -545,8 +545,9 @@ box_lua_fiber_run(va_list ap __attribute__((unused))) /** @retval true if check failed, false otherwise */ static bool -fiber_checkstack(struct lua_State *L) +lbox_fiber_checkstack(struct lua_State *L) { + fiber_checkstack(); struct fiber *f = fiber; const int MAX_STACK_DEPTH = 16; int depth = 1; @@ -564,7 +565,7 @@ lbox_fiber_create(struct lua_State *L) { if (lua_gettop(L) != 1 || !lua_isfunction(L, 1)) luaL_error(L, "fiber.create(function): bad arguments"); - if (fiber_checkstack(L)) + if (lbox_fiber_checkstack(L)) luaL_error(L, "fiber.create(function): recursion limit" " reached"); @@ -645,6 +646,52 @@ lbox_fiber_resume(struct lua_State *L) return nargs; } +static void +box_lua_fiber_run_detached(va_list ap) +{ + int coro_ref = va_arg(ap, int); + struct lua_State *L = va_arg(ap, struct lua_State *); + @try { + lua_call(L, lua_gettop(L) - 1, LUA_MULTRET); + } @catch (FiberCancelException *e) { + @throw; + } @catch (tnt_Exception *e) { + [e log]; + } @catch (id allOthers) { + lua_settop(L, 1); + if (lua_tostring(L, -1) != NULL) + say_error("%s", lua_tostring(L, -1)); + } @finally { + luaL_unref(L, LUA_REGISTRYINDEX, coro_ref); + } +} + +/** + * Create, resume and detach a fiber + * given the function and its arguments. + */ +static int +lbox_fiber_wrap(struct lua_State *L) +{ + if (lua_gettop(L) < 1 || !lua_isfunction(L, 1)) + luaL_error(L, "fiber.wrap(function, ...): bad arguments"); + fiber_checkstack(); + + struct fiber *f = fiber_new("lua", box_lua_fiber_run_detached); + /* Not a system fiber. */ + f->flags |= FIBER_USER_MODE; + struct lua_State *child_L = lua_newthread(L); + int coro_ref = luaL_ref(L, LUA_REGISTRYINDEX); + /* Move the arguments to the new coro */ + lua_xmove(L, child_L, lua_gettop(L)); + fiber_call(f, coro_ref, child_L); + if (f->fid) + lbox_pushfiber(L, f); + else + lua_pushnil(L); + return 1; +} + /** * Yield the current fiber. * @@ -708,7 +755,7 @@ fiber_is_caller(struct lua_State *L, struct fiber *f) { static int lbox_fiber_status(struct lua_State *L) { - struct fiber *f = lbox_checkfiber(L, 1); + struct fiber *f = lua_gettop(L) ? lbox_checkfiber(L, 1) : fiber; const char *status; if (f->fid == 0) { /* This fiber is dead. */ @@ -834,6 +881,7 @@ static const struct luaL_reg fiberlib[] = { {"testcancel", lbox_fiber_testcancel}, {"create", lbox_fiber_create}, {"resume", lbox_fiber_resume}, + {"wrap", lbox_fiber_wrap}, {"yield", lbox_fiber_yield}, {"status", lbox_fiber_status}, {"name", lbox_fiber_name}, diff --git a/test/box/lua.result b/test/box/lua.result index c967afd142..35ebd97031 100644 --- a/test/box/lua.result +++ b/test/box/lua.result @@ -14,13 +14,13 @@ lua local t = {} for n in pairs(box) do table.insert(t, ' - box.' .. tostring(n --- - box.auto_increment - box.bless_space + - box.call_loadproc - box.cfg - box.counter - box.delete - box.dostring - box.error - box.fiber - - box.find - box.flags - box.index - box.info @@ -803,9 +803,39 @@ lua box.fiber.find(920) --- - nil ... -# A test case for Bug##933487 +lua f = function() box.fiber.wrap(f) end +--- +... +call f() +No match +lua f = function(a, b) box.fiber.wrap(function(arg) result = arg end, a..b) end +--- +... +lua f('hello ', 'world') +--- +... +lua result +--- + - hello world +... +lua f('bye ', 'world') +--- +... +lua result +--- + - bye world +... +lua box.fiber.wrap(function() result = box.fiber.status() end) +--- + - nil +... +lua result +--- + - running +... +# A test case for Bug#933487 # tarantool crashed during shutdown if non running LUA fiber -# was created +# was created # lua f = box.fiber.create(function () return true end) --- diff --git a/test/box/lua.test b/test/box/lua.test index f2cd9021d5..6cfb45f484 100644 --- a/test/box/lua.test +++ b/test/box/lua.test @@ -6,7 +6,7 @@ import sys exec admin "lua" exec admin "lua 1" exec admin "lua print(' lua says: hello')" -# What's in the box? +# What's in the box? exec admin "lua local t = {} for n in pairs(box) do table.insert(t, ' - box.' .. tostring(n)) end table.sort(t) for i = 1, #t do print(t[i]) end t = nil" # Test box.pack() exec admin "lua box.pack()" @@ -210,11 +210,34 @@ exec admin "lua collectgarbage('collect')" exec admin "lua box.fiber.find(900)" exec admin "lua box.fiber.find(910)" exec admin "lua box.fiber.find(920)" + +# +# Test box.fiber.wrap() +# +# This should try to infinitely create fibers, +# but hit the fiber stack size limit and fail +# with an error. +# +exec admin "lua f = function() box.fiber.wrap(f) end" +exec sql "call f()" +# +# Test argument passing +# +exec admin "lua f = function(a, b) box.fiber.wrap(function(arg) result = arg end, a..b) end" +exec admin "lua f('hello ', 'world')" +exec admin "lua result" +exec admin "lua f('bye ', 'world')" +exec admin "lua result" +# +# Test that the created fiber is detached +# +exec admin "lua box.fiber.wrap(function() result = box.fiber.status() end)" +exec admin "lua result" # # -print """# A test case for Bug##933487 +print """# A test case for Bug#933487 # tarantool crashed during shutdown if non running LUA fiber -# was created +# was created #""" exec admin "lua f = box.fiber.create(function () return true end)" exec admin "save snapshot" diff --git a/test/box/lua_misc.result b/test/box/lua_misc.result index e0392a4c4a..31495fe9f8 100644 --- a/test/box/lua_misc.result +++ b/test/box/lua_misc.result @@ -106,11 +106,12 @@ box.error.ER_PROC_RET: 12290 box.error.ER_TUPLE_IS_TOO_LONG: 11010 box.error.ER_EXACT_MATCH: 11522 box.error.ER_SECONDARY: 770 -box.error.ER_OK: 0 box.error.ER_SPACE_DISABLED: 13314 -box.error.ER_TUPLE_NOT_FOUND: 12546 +box.error.ER_OK: 0 box.error.ER_TUPLE_FOUND: 14082 -box.error.ER_UNKNOWN_UPDATE_OP: 11266 +box.error.ER_TUPLE_NOT_FOUND: 12546 +box.error.ER_FIBER_STACK: 6658 +box.error.ER_SPLICE: 10754 box.error.ER_NO_SUCH_FIELD: 13826 box.error.ER_UNSUPPORTED: 2562 box.error.ER_INJECTION: 2306 @@ -121,9 +122,9 @@ box.error.ER_NO_SUCH_SPACE: 14594 box.error.ER_TUPLE_IS_EMPTY: 6402 box.error.ER_PROC_LUA: 13058 box.error.ER_NO_SUCH_PROC: 12802 -box.error.ER_SPLICE: 10754 +box.error.ER_UNKNOWN_UPDATE_OP: 11266 box.error.ER_KEY_PART_COUNT: 12034 -box.error.ER_WAL_IO: 9986 box.error.ER_FIELD_TYPE: 10242 +box.error.ER_WAL_IO: 9986 box.error.ER_MEMORY_ISSUE: 1793 ... diff --git a/test/box/net.box.result b/test/box/net.box.result index ed19b1bb20..ad130a494b 100644 --- a/test/box/net.box.result +++ b/test/box/net.box.result @@ -110,11 +110,10 @@ lua remote:timeout(0.5):select(0, 0, 345) --- - 345: {'test1-replaced', 'test2-replaced'} ... -lua remote:call('box.fiber.sleep', '.1') +lua remote:call('box.fiber.sleep', '.01') --- - - 0 ... -lua remote:timeout(0.1):call('box.fiber.sleep', '10') +lua remote:timeout(0.01):call('box.fiber.sleep', '10') --- - nil ... @@ -174,9 +173,9 @@ lua remote:close() ... lua remote:close() --- -error: '[string "box.net = {..."]:383: box.net.box: already closed' +error: '[string "box.net = {..."]:399: box.net.box: already closed' ... lua remote:ping() --- -error: '[string "box.net = {..."]:388: box.net.box: connection was closed' +error: '[string "box.net = {..."]:404: box.net.box: connection was closed' ... diff --git a/test/box/net.box.test b/test/box/net.box.test index 2f8f9ecdfc..d807969d7a 100644 --- a/test/box/net.box.test +++ b/test/box/net.box.test @@ -44,8 +44,8 @@ exec admin "lua box.select(0, 0, 345)" exec admin "lua remote:select(0, 0, 345)" exec admin "lua remote:timeout(0.5):select(0, 0, 345)" -exec admin "lua remote:call('box.fiber.sleep', '.1')" -exec admin "lua remote:timeout(0.1):call('box.fiber.sleep', '10')" +exec admin "lua remote:call('box.fiber.sleep', '.01')" +exec admin "lua remote:timeout(0.01):call('box.fiber.sleep', '10')" exec admin "lua pstart = box.time()" diff --git a/test/lib/sql_ast.py b/test/lib/sql_ast.py index dedeadd77a..1d828a7320 100644 --- a/test/lib/sql_ast.py +++ b/test/lib/sql_ast.py @@ -51,7 +51,7 @@ ER = { 23: "ER_RESERVED23" , 24: "ER_UNUSED24" , 25: "ER_TUPLE_IS_EMPTY" , - 26: "ER_UNUSED26" , + 26: "ER_FIBER_STACK" , 27: "ER_UNUSED27" , 28: "ER_UNUSED28" , 29: "ER_UNUSED29" , -- GitLab