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> &mdash; 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