<!DOCTYPE section [
<!ENTITY % tnt SYSTEM "../tnt.ent">
%tnt;
]>
<section xmlns="http://docbook.org/ns/docbook" version="5.0"
      xmlns:xi="http://www.w3.org/2001/XInclude"
      xmlns:xlink="http://www.w3.org/1999/xlink"
      xml:id="stored-procedures">
  <title>Writing stored procedures in Lua</title>
<blockquote>
    <para>
        <link xlink:href="http://www.lua.org">Lua</link>
        is a light-weight, multi-paradigm, embeddable language.
        Stored procedures in Lua can be used to implement
        data manipulation patterns or data structures. A
        server-side procedure written in Lua can select and modify
        data, access configuration and perform administrative
        tasks. It is possible to dynamically define, invoke,
        alter and drop Lua procedures. Lua procedures can run
        in the background and perform administrative tasks,
        such as data expiration or re-sharding.

    </para>
    <para>
        Tarantool uses the <link
        xlink:href="http://www.luajit.org">LuaJIT</link>
        just-in-time Lua compiler and virtual machine.
        Apart from increased performance, this provides such
        features as <link
        xlink:href="http://bitop.luajit.org/">bitwise
        operations</link> and <link xlink:href="#tonumber64">64-bit integer arithmetic.</link>
    </para>
</blockquote>
<para>
    Procedures can be invoked from the administrative
    console and using the binary protocol, for example:
    <programlisting><computeroutput>localhost> <userinput>lua function f1() return 'hello' end</userinput>
---
...
localhost> <userinput>call f1()</userinput>
Call OK, 1 rows affected
['hello']
</computeroutput>
</programlisting>
    In the language of the administrative console
    <olink targetptr="lua-command" /> evaluates an arbitrary
    Lua chunk. CALL is an SQL standard statement, so its syntax
    was adopted by Tarantool command line client
    to invoke the CALL command of the binary protocol.
</para>
<para>
    In the example above, "<code>lua function f1() return 'hello' end</code>" defines a Lua procedure
    using the text protocol of the administrative port,
    and "<code>call f1()</code>" invokes the procedure using the Tarantool client-side SQL
    parser plus the binary protocol on the <olink targetptr="primary_port" />.
    Since it's possible to execute any Lua chunk in the
    administrative console, the newly created <code
    language="Lua">function f1()</code>
    can be invoked there too:
    <programlisting><computeroutput>localhost> <userinput>lua f1()</userinput>
---
 - hello
...
localhost> <userinput>lua 1+2</userinput>
---
 - 3
...
localhost> <userinput>lua "hello".." world"</userinput>
---
 - hello world
...
</computeroutput></programlisting>
  </para>
  <para>
    Lua procedures could also be called at the time of initialization
    using a dedicated <filename xml:id="init.lua" xreflabel="init.lua">init.lua</filename> script,
    located in <olink targetptr="script_dir" />.

    An example of such a script is given below:
    <programlisting>
    <![CDATA[
-- Importing expirationd module
dofile("expirationd.lua")

function is_expired(args, tuple)
   if tuple == nil then
       return true
   end

   if #tuple <= args.field_no then
       return true
   end

   field = tuple[args.field_no]
   if field == nil or #field ~= 4 then
       return true
   end

   local current_time = os.time()
   local tuple_ts = box.unpack("i", field)
   return current_time >= tuple_ts + args.ttl
end
function purge(args, tuple)
    box.space[0]:delete(tuple[0])
end

-- Run task
expirationd.run_task("exprd space 0", 0, is_expired, purge,
                    { field_no = 1, ttl = 30 * 60 })
]]>
    </programlisting>
 </para>
 <para>
    The initialization script can select and modify data. However,
    if the server is a running replica, data change requests from
    the start script fail just the same way they would fail if they
    were sent from a remote client.
  </para>
 <para>
   Another common task to perform in the initialization script
   is to start background fibers for data expiration, re-sharding,
   or communication with networked peers.
 </para>
 <para>
   Finally, the script can be used to define Lua <olink
   targetptr="triggers">triggers</olink> invoked on various events
   within the system.
 </para>
  <para>
    There is a single global instance of the Lua interpreter, which is
    shared across all connections. Anything prefixed with
    <code>lua </code> on the administrative console is sent
    directly to this interpreter. Any change of the interpreter
    state is immediately available to all client connections.
  </para>
  <para>
    Each connection, however, is using its own Lua
    <emphasis>coroutine</emphasis> &mdash; a mechanism akin to
    Tarantool <emphasis>fibers</emphasis>. A coroutine has an
    own execution stack and a Lua <emphasis>closure</emphasis>
    &mdash; set of local variables and definitions.
  </para>
  <para>
     The interpreter environment is not restricted when
     <olink targetptr="init.lua"/> is loaded. But before the
     server starts accepting requests, the standard Lua APIs, such
     as for file I/O, process control and module management are
     unset, to avoid possible trivial security attacks.
  </para>
  <para>
    In the binary protocol, it's only possible to <emphasis
    role="strong">call</emphasis> existing
    procedures, but not <emphasis role="strong">define</emphasis>
    or <emphasis role="strong">alter</emphasis> them. The
    CALL request packet contains the command code for CALL (22), the name
    of a procedure to be called, and a tuple for procedure
    arguments. Currently, Tarantool tuples are type-agnostic,
    thus each field of the tuple is passed into the procedure
    as an argument of type <quote>string</quote>. For example:
<programlisting><computeroutput>kostja@atlas:~$ cat arg.lua
function f1(a)
    local s = a
    if type(a) == 'string' then
        s = ''
        for i=1, #a, 1 do
            s = s..string.format('0x%x ', string.byte(a, i))
        end
    end
    return type(a), s
end
kostja@atlas:~$ tarantool
localhost> <userinput>lua dofile('arg.lua')</userinput>
---
...
localhost> <userinput>lua f1('1234')</userinput>
---
 - string
 - 0x31 0x32 0x33 0x34
...
localhost> <userinput>call f1('1234')</userinput>
Call OK, 2 rows affected
['string']
['0x31 0x32 0x33 0x34 ']
localhost> <userinput>lua f1(1234)</userinput>
---
 - number
 - 1234
...
localhost> <userinput>call f1(1234)</userinput>
Call OK, 2 rows affected
['string']
['0xd2 0x4 0x0 0x0 ']</computeroutput></programlisting>
    In the above example, the way the procedure receives its
    argument is identical in the two protocols, when the argument is a
    string. A numeric field, however, when submitted via the
    binary protocol, is seen by the procedure as
    a 4-byte blob, not as a Lua <quote>number</quote> type.
    </para>
    <para>In addition to conventional method invocation,
    Lua provides object-oriented syntax. Access to the latter is
    available on the administrative console only:
    <programlisting><computeroutput>localhost> <userinput>lua box.space[0]:truncate()</userinput>
---
...
localhost> <userinput>call box.space[0]:truncate()</userinput>
error: 1:15 expected '('
</computeroutput></programlisting>
    Since it's impossible to invoke object methods from the binary
    protocol, the object-oriented syntax is often used to restrict
    certain operations to be used by a system administrator only.
  </para>
  <para>
    Every value, returned from a stored function by means of a
    <code>return</code> clause, is converted to a Tarantool tuple.
    Tuples are returned as such, in binary form; a Lua scalar, such as
    a string or an integer, is converted to a tuple with only
    one field. When the returned value is a <emphasis>Lua
    table</emphasis>, the resulting tuple contains only table
    values, but not keys.
  </para>
  <para>
    When a function in Lua terminates with an error, the error
    is sent to the client as <olink targetptr="ER_PROC_LUA" />
    return code, with the original error message preserved.
    Similarly, an error which has occurred inside Tarantool (observed on the
    client as an error code), when it happens during execution of a
    Lua procedure, produces a genuine Lua error:
<programlisting><computeroutput>localhost> <userinput>lua function f1() error("oops") end</userinput>
---
...
localhost> <userinput>call f1()</userinput>
Call ERROR, Lua error: [string "function f1() error("oops") end"]:1: oops (ER_PROC_LUA)
localhost> <userinput>call box.insert('99', 1, 'test')</userinput>
Call ERROR, Space 99 is disabled (ER_SPACE_DISABLED)
localhost> <userinput>lua pcall(box.insert, 99, 1, 'test')</userinput>
---
 - false
 - Space 99 is disabled
...
</computeroutput></programlisting>
  </para>
  <para>
    It's possible not only to invoke trivial Lua code, but call
    into Tarantool storage functionality, using the
    <code>box</code>
    Lua library. The contents of the library can be
    inspected at runtime:
<programlisting><computeroutput>localhost> <userinput>lua for k, v in pairs(box) do print(k, ": ", type(v)) end</userinput>
---
fiber: table
space: table
cfg: table
on_reload_configuration: function
update: function
process: function
delete: function
insert: function
select: function
index: table
unpack: function
replace: function
select_range: function
pack: function
...</computeroutput></programlisting>
    As is shown in the listing, the <code>box</code> package contains:
    <itemizedlist>
        <listitem><para>
            high-level functions, such as
            <code>process(), update(), select(), select_range(), insert(),
                replace(), delete()</code>, to manipulate
                tuples and access spaces from Lua.
        </para></listitem>
        <listitem><para>
            libraries, such as <code>cfg, space, fiber, index, tuple</code>,
            to access server configuration, create, resume and
            interrupt fibers, inspect contents of spaces, indexes
            and tuples, send and receive data over the network.
        </para></listitem>
    </itemizedlist>
  </para>

<variablelist>
    <title>Global Lua names added by Tarantool</title>
    <varlistentry>
        <term xml:id="tonumber64" xreflabel="tonumber64"> <emphasis role="lua">tonumber64(value)</emphasis></term>
        <listitem>
            <para>Convert a given string or a Lua number to a
            64-bit integer. The returned value supports all
            arithmetic operations, but uses
            64-bit integer arithmetic, rather than floating-point
            arithmetic as in the built-in number type.
                <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>
localhost> <userinput>lua tonumber64('123456789'), tonumber64(123456789)</userinput>
---
 - 123456789
 - 123456789
...
localhost> <userinput>lua i=tonumber64(1)</userinput>
---
...
localhost> <userinput>lua type(i), type(i*2),  type(i/2), i, i*2, i/2</userinput>
---
 - cdata
 - cdata
 - cdata
 - 1
 - 2
 - 0
...
</programlisting>
            </para>
        </listitem>
    </varlistentry>
</variablelist>

<section xml:id="sp-box">
    <title>Package <code>box</code></title>
<variablelist xml:id="box" xreflabel="box">
    <varlistentry>
        <term>
            <emphasis role="lua" xml:id="box.process">box.process(op, request)</emphasis>
        </term>
        <listitem>
            <para>
                Process a request passed in as a binary string.
                This is an entry point into the server request
                processor. It can be used to insert, update,
                select and delete tuples from within a Lua procedure.
            </para>
            <para>
                The <code>box.process</code> API is a low-level API, and it expects
                all arguments to be packed in accordance
                with the binary protocol (excluding the iproto
                header). Normally, there is no need
                to use <code>box.process()</code> directly:
                <code>box.select(), box.update()</code>
                and other convenience wrappers
                invoke <code>box.process()</code> with
                correctly packed arguments.
                <bridgehead renderas="sect4">Parameters</bridgehead>
                <simplelist>
                    <member><code>op</code> &mdash; number, any
                    Tarantool command code, except 22 (CALL). See
                    <link xlink:href="https://github.com/tarantool/tarantool/blob/master/doc/box-protocol.txt">
                    <filename>doc/box-protocol.txt</filename></link>.
                    </member>
                    <member><code>request</code> &mdash; command
                    arguments packed in binary format.</member>
                </simplelist>
                <bridgehead renderas="sect4">Returns</bridgehead>
                This function returns zero or more tuples. In Lua, a
                tuple is represented by a
                <emphasis>userdata</emphasis> object of type
                <code xlink:href="#box.tuple">box.tuple</code>. If
                a Lua procedure is called from the administrative
                console, returned tuples are printed out in YAML
                format.  When called from the binary
                protocol, the binary format is used.
                <bridgehead renderas="sect4">Errors</bridgehead>
                Any server error produced by the executed
                command.
            </para>
            <para>
                Please note that, since all requests from Lua
                enter the core through <emphasis
                role="lua">box.process()</emphasis>, all checks
                and triggers run by the core automatically apply.
                For example, if the server is in read-only mode,
                an update or delete fails. Analogously, if a
                system-wide "instead of" trigger is defined, it
                is run.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua" xml:id="box.select" xreflabel="box.select">
                box.select(space_no, index_no, ...)
            </emphasis>
        </term>
        <listitem>
            <para>
                Search for a tuple or tuples in the given space. A
                wrapper around <code>box.process()</code>.
                <bridgehead renderas="sect4">Parameters</bridgehead>
                <simplelist>
                    <member><code>space_no</code> &mdash; space id,
                    </member>
                    <member><code>index_no</code> &mdash; index number in the
                        space, to be used for match</member>
                    <member><code>...</code>&mdash; index key,
                    possibly multipart.
                    </member>
                </simplelist>
                <bridgehead renderas="sect4">Returns</bridgehead>
                Returns zero or more tuples.
                <bridgehead renderas="sect4">Errors</bridgehead>
                Same as in <code>box.process()</code>. Any error
                results in a Lua exception.
                <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>
localhost> <userinput>call box.insert(0, 'test', 'my first tuple')</userinput>
Call OK, 1 rows affected
['test', 'my first tuple']
localhost> <userinput>call box.select(0, 0, 'test')</userinput>
Call OK, 1 rows affected
['test', 'my first tuple']
localhost> <userinput>lua box.insert(5, 'testtest', 'firstname', 'lastname')</userinput>
---
 - 'testtest': {'firstname', 'lastname'}
...
localhost> <userinput>lua box.select(5, 1, 'firstname', 'lastname')</userinput>
---
 - 'testtest': {'firstname', 'lastname'}
...
</programlisting>
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua" xml:id="box.insert">box.insert(space_no, ...)</emphasis>
        </term>
        <listitem>
	    <para>
	        Insert a tuple into a space. Tuple fields
                follow <code>space_no</code>. If a tuple with
                the same primary key already exists,
                <code>box.insert()</code> returns an error.
                This function is a
                wrapper around <code>box.process()</code>.
                <bridgehead renderas="sect4">Returns</bridgehead>
                Returns the inserted tuple.
	    </para>
	</listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua" xml:id="box.select_limit" xreflabel="box.select_limit">
                box.select_limit(space_no, index_no, offset, limit, ...)
            </emphasis>
        </term>
        <listitem>
            <para>
                Search for tuples in the given space. This is a
                full version of the built-in SELECT command, in
                which one can specify offset and limit for a
                multi-tuple return.  The server may return
                multiple tuples when the index is non-unique or a
                partial key is used for search.
            </para>
        </listitem>
    </varlistentry>


    <varlistentry>
        <term>
            <emphasis role="lua" xml:id="box.replace">box.replace(space_no, ...)</emphasis>
        </term>
        <listitem>
            <para>
                Insert a tuple into a space. Tuple fields
                follow <code>space_no</code>. If a tuple with
                the same primary key already exists,
                <code>box.replace()</code> replaces the existing
                tuple with a new one. This function is a
                wrapper around <code>box.process()</code>.
                <bridgehead renderas="sect4">Returns</bridgehead>
                Returns the inserted tuple.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua" xml:id="box.update">box.update(space_no, key, format, ...)</emphasis>
        </term>
        <listitem>
            <para>
                Update a tuple identified by a primary
                <code>key</code>. If a key is multipart,
                it is passed in as a Lua table. Update arguments follow,
                described by <code>format</code>.
                The format and arguments are passed to
                <code>box.pack()</code> and the result is sent
                to <code>box.process()</code>.
                A correct <code>format</code> is a sequence of
                pairs: update operation, operation arguments. A
                single character of format describes either an
                operation which needs to take place or operation
                argument. A format specifier also works as a
                placeholder for the number of a field, which needs
                to be updated, or for an argument value.
                For example:
                <simplelist>
                    <member><code>+p=p</code> &mdash; add a value
                    to one field and assign another,
                    </member>
                    <member><code>:p</code> &mdash; splice a
                    field: start at offset, cut length bytes, and add a
                    string.</member>
                    <member><code>#p</code> &mdash; delete a
                    field.</member>
                    <member><code>!p</code> &mdash; insert a field
                    (before the one specified).</member>
                </simplelist>
                Possible format specifiers are: <quote>+</quote>
                for addition, <quote>-</quote> for subtraction,
                <quote>&amp;</quote> for bitwise AND,
                <quote>|</quote> for bitwise OR, <quote>^</quote>
                for bitwise exclusive OR (XOR), <quote>:</quote>
                for string splice and <quote>p</quote> for
                operation argument.
                <bridgehead renderas="sect4">Returns</bridgehead>
                Returns the updated tuple.
                <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>
#Assume that the initial state of the database is ...
#  space[0] has one tuple set and one primary key whose type is 32-bit integer.
#  There is one row, with field[0] = 999 and field[1] = 'A'.

#In the following update ...
#  The first argument is 0, that is, the affected space is space[0]
#  The second argument is 999, that is, the affected tuple is identified by primary key value = 999
#  The third argument is '=p', that is, there is one operation, assignment to a field
#  The fourth argument is 1, that is, the affected field is field[1]
#  The fifth argument is 'B', that is, field[1] contents change to 'B'
#  Therefore, after the following update, field[0] = 999 and field[1] = 'B'.
lua box.update(0, 999, '=p', 1, 'B')

#In the following update, the arguments are the same, except that ...
#  the key is passed as a Lua table (inside braces). This is unnecessary
#  when the primary key has only one field, but would be necessary if the
#  primary key had more than one field.
#  Therefore, after the following update, field[0] = 999 and field[1] = 'B' (no change).
lua box.update(0, {999}, '=p', 1, 'B')

#In the following update, the arguments are the same, except that ...
#   The fourth argument is 2, that is the affected field is field[2].
#   It is okay that, until now, field[2] has not existed. It gets added.
#   Therefore, after the following update, field[0] = 999, field[1] = 'B', field[2] = 1.
lua box.update(0, 999, '=p', 2, 1)

#In the following update, the arguments are the same, except that ...
#   The third argument is '+p', that is, the operation is addition rather than assignment.
#   Since field[2] previously contained 10, this means we're adding 1 to 1.
#   Therefore, after the following update, field[0] = 999, field[1] = 'B', field[2] = 2.
lua box.update(0, 999, '+p', 2, 1)

#In the following update ...
#   The idea is to modify two fields at once.
#   The third argument is '|p=p', that is, there are two operations, OR and assignment.
#   The fourth and fifth arguments mean that field[2] gets ORed with 1.
#   The fifth and sixth arguments mean that field[1] gets assigned 'C'.
#   Therefore, after the following update, field[0] = 999, field[1] = 'C', field[2] = 3.
lua box.update(0, 999, '|p=p', 2, 1, 1, 'C')

#In the following update ...
#   The idea is to delete field[1], then subtract 3 from field[2], but ...
#   after the delete, there is a renumbering -- so field[2] becomes field[1]
#   before we subtract 3 from it, and that's why the sixth argument is 1 not 2.
#   Therefore, after the following update, field[0] = 999, field[1] = 0.
lua box.update(0, 999, '#p-p', 1, 0, 1, 3)

#In the following update ...
#   We're making a long string so that the splice will work in the next example.
#   Therefore, after the following update, field[0[ = 999, field[1] = 'XYZ'.
lua box.update(0, 999, '=p', 1, 'XYZ')

#In the following update ...
#   The third argument is ':p', that is, this is the example of splice.
#   The fifth argument is actually four arguments packed together ...
#      a filler, an offset, the number of bytes to cut (1), and the string to add ('!')
#   Therefore, after the following update, field[0[ = 999, field[1] = 'X!Z'.
lua box.update(0, 999, ':p', 1, box.pack('ppp', 1, 1, '!'))

</programlisting>
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua" xml:id="box.delete">box.delete(space_no, ...)</emphasis>
        </term>
        <listitem><para>
            Delete a tuple identified by a primary key.
            <bridgehead renderas="sect4">Returns</bridgehead>
            Returns the deleted tuple.
                <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>
localhost> <userinput>call box.delete(0, 'test')</userinput>
Call OK, 1 rows affected
['test', 'my first tuple']
localhost> <userinput>call box.delete(0, 'test')</userinput>
Call OK, 0 rows affected
localhost> <userinput>call box.delete(0, 'tes')</userinput>
Call ERROR, Illegal parameters, key is not u32 (ER_ILLEGAL_PARAMS)
</programlisting>
        </para></listitem>
    </varlistentry>
    <varlistentry>
        <term>
            <emphasis role="lua" xml:id="box.select_range" xreflabel="box.select_range">
                box.select_range(space_no, index_no, limit, key, ...)
            </emphasis>
        </term>
        <listitem><para>
            Select a range of tuples, starting from the offset
            specified by <code>key</code>. The key can be
            multipart.  Limit selection with at most
            <code>limit</code> tuples.  If no key is specified,
            start from the first key in the index.
        </para>
        <para>
            For TREE indexes, this returns tuples in sorted order.
            For HASH indexes, the order of tuples is unspecified, and
            can change significantly if data is inserted or deleted
            between two calls to <code>box.select_range()</code>.
            If <code>key</code> is <code>nil</code> or unspecified,
            the selection starts from the start of the index.
            This is a simple wrapper around <code xlink:href="#box.space.select_range">box.space[space_no]:select_range(index_no, ...)</code>.
            BITSET index does not support this call.
        </para>
        <para>
            <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>localhost> <userinput>show configuration</userinput>
---
...
  space[4].cardinality: "-1"
  space[4].estimated_rows: "0"
  space[4].index[0].type: "HASH"
  space[4].index[0].unique: "true"
  space[4].index[0].key_field[0].fieldno: "0"
  space[4].index[0].key_field[0].type: "STR"
  space[4].index[1].type: "TREE"
  space[4].index[1].unique: "false"
  space[4].index[1].key_field[0].fieldno: "1"
  space[4].index[1].key_field[0].type: "STR"
...
localhost> <userinput>insert into t4 values ('0', '0')</userinput>
Insert OK, 1 rows affected
localhost> <userinput>insert into t4 values ('1', '1')</userinput>
Insert OK, 1 rows affected
localhost> <userinput>insert into t4 values ('2', '2')</userinput>
Insert OK, 1 rows affected
localhost> <userinput>insert into t4 values ('3', '3')</userinput>
Insert OK, 1 rows affected
localhost> <userinput>lua box.select_range(4, 0, 10)</userinput>
---
 - '3': {'3'}
 - '0': {'0'}
 - '1': {'1'}
 - '2': {'2'}
...
localhost> <userinput>lua box.select_range(4, 1, 10)</userinput>
---
 - '0': {'0'}
 - '1': {'1'}
 - '2': {'2'}
 - '3': {'3'}
...
localhost> <userinput>lua box.select_range(4, 1, 2)</userinput>
---
 - '0': {'0'}
 - '1': {'1'}
...
localhost> <userinput>lua box.select_range(4, 1, 2, '1')</userinput>
---
 - '1': {'1'}
 - '2': {'2'}
...
</programlisting>
        </para></listitem>
    </varlistentry>
    <varlistentry>
        <term>
            <emphasis role="lua" xml:id="box.select_reverse_range" xreflabel="box.select_reverse_range">
                box.select_reverse_range(space_no, index_no, limit, key, ...)
            </emphasis>
        </term>
        <listitem><para>
            Select a reverse range of tuples, starting from the offset
            specified by <code>key</code>. The key can be
            multipart.
            Limit selection with at most <code>limit</code>
            tuples.
            If no key is specified, start from the last key in
            the index.
            </para>
            <para>
            For TREE indexes, this returns tuples in sorted order.
            For other index types this call is not supported.
            If <code>key</code> is <code>nil</code> or unspecified,
            the selection starts from the end of the index.
            <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>localhost> <userinput>show configuration</userinput>
---
...
  space[4].cardinality: "-1"
  space[4].estimated_rows: "0"
  space[4].index[0].type: "HASH"
  space[4].index[0].unique: "true"
  space[4].index[0].key_field[0].fieldno: "0"
  space[4].index[0].key_field[0].type: "STR"
  space[4].index[1].type: "TREE"
  space[4].index[1].unique: "false"
  space[4].index[1].key_field[0].fieldno: "1"
  space[4].index[1].key_field[0].type: "STR"
...
localhost> <userinput>insert into t4 values ('0', '0')</userinput>
Insert OK, 1 rows affected
localhost> <userinput>insert into t4 values ('1', '1')</userinput>
Insert OK, 1 rows affected
localhost> <userinput>insert into t4 values ('2', '2')</userinput>
Insert OK, 1 rows affected
localhost> <userinput>insert into t4 values ('3', '3')</userinput>
Insert OK, 1 rows affected
localhost> <userinput>lua box.select_reverse_range(4, 0, 10)</userinput>
---
 error: 'Illegal parameters, hash iterator is forward only
...
localhost> <userinput>lua box.select_reverse_range(4, 1, 10)</userinput>
---
 - '3': {'3'}
 - '2': {'2'}
 - '1': {'1'}
 - '0': {'0'}
...
localhost> <userinput>lua box.select_reverse_range(4, 1, 2)</userinput>
---
 - '3': {'3'}
 - '2': {'2'}
...
localhost> <userinput>lua box.select_reverse_range(4, 1, 2, '1')</userinput>
---
 - '1': {'1'}
 - '0': {'0'}
...
</programlisting>
        </para></listitem>
    </varlistentry>
    <varlistentry>
        <term><emphasis role="lua">box.pack(format, ...)</emphasis></term>
        <listitem><para>
            To use Tarantool binary protocol primitives from Lua,
            it's necessary to convert Lua variables to binary
            format. This helper function is prototyped after Perl
            'pack'. It takes a format and a list of arguments, and
            returns a binary string with all arguments packed
            according to the format.
            <bridgehead renderas="sect4">Format specifiers</bridgehead>
            <simplelist>
                <member><code>b</code> &mdash; converts Lua
                variable to a 1-byte
                integer, and stores the integer in the resulting
                string
                </member>
                <member><code>s</code> &mdash; converts Lua
                variable to a 2-byte
                integer, and stores the integer in the resulting
                string, low byte first,
                </member>
                <member><code>i</code> &mdash; converts Lua
                variable to a 4-byte
                integer, and stores the integer in the resulting
                string, low byte first,
                </member>
                <member><code>l</code> &mdash; converts Lua
                variable to a 8-byte
                integer, and stores the integer in the resulting
                string, low byte first,
                </member>
                <member><code>n</code> &mdash; converts Lua
                variable to a 2-byte
                integer, and stores the integer in the resulting
                string, big endian,
                </member>
                <member><code>N</code> &mdash; converts Lua
                variable to a 4-byte
                integer, and stores the integer in the resulting
                string, big endian,
                </member>
                <member><code>Q</code> &mdash; converts Lua
                variable to a 8-byte
                integer, and stores the integer in the resulting
                string, big endian,
                </member>
                <member><code>f</code> &mdash; converts Lua
                variable to a 4-byte
                float, and stores the float in the resulting
                string,
                </member>
                <member><code>d</code> &mdash; converts Lua
                variable to a 8-byte
                double, and stores the double in the resulting
                string,
                </member>
                <member><code>w</code> &mdash; converts Lua
                integer to a BER-encoded integer,
                </member>
                <member><code>p</code> &mdash; stores the length
                of the argument as a BER-encoded integer
                followed by the argument itself (a little-endian 4-byte integer for integers,
                and a binary blob for other types),
                </member>
                <member><code>=, +, &amp;, |, ^, : </code>&mdash;
                stores the corresponding Tarantool UPDATE
                operation code: field assignment, addition,
                conjunction, disjunction, exclusive disjunction,
                splice (from Perl SPLICE function). Expects
                field number to update as an argument. These format
                specifiers only store the corresponding operation
                code and field number to update, but do not
                describe operation arguments.
                </member>
            </simplelist>
        <bridgehead renderas="sect4">Errors</bridgehead>
        Unknown format specifier.
        <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>
localhost> <userinput>lua box.insert(0, 0, 'hello world')</userinput>
---
 - 0: {'hello world'}
...
localhost> <userinput>lua box.update(0, 0, "=p", 1, 'bye world')</userinput>
---
 - 0: {'bye world'}
...
localhost> <userinput>lua box.update(0, 0, ":p", 1, box.pack('ppp', 0, 3, 'hello'))</userinput>
---
 - 0: {'hello world'}
...
localhost> <userinput>lua box.update(0, 0, "=p", 1, 4)</userinput>
---
 - 0: {4}
...
localhost> <userinput>lua box.update(0, 0, "+p", 1, 4)</userinput>
---
 - 0: {8}
...
localhost> <userinput>lua box.update(0, 0, "^p", 1, 4)</userinput>
---
 - 0: {12}
...
</programlisting>
        </para></listitem>
    </varlistentry>

    <varlistentry>
        <term><emphasis role="lua">box.unpack(format, binary)</emphasis></term>
        <listitem><para>
            Counterpart to <code>box.pack()</code>.
            <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>localhost> <userinput>lua tuple=box.replace(2, 0)</userinput>
---
...
localhost> <userinput>lua string.len(tuple[0])</userinput>
---
 - 4
...
localhost> <userinput>lua box.unpack('i', tuple[0])</userinput>
---
 - 0
...
localhost> <userinput>lua box.unpack('bsil', box.pack('bsil', 255, 65535, 4294967295, tonumber64('18446744073709551615')))</userinput>
---
 - 255
 - 65535
 - 4294967295
 - 18446744073709551615
...
localhost> <userinput>lua num, str, num64 = box.unpack('ppp', box.pack('ppp', 666, 'string', tonumber64('666666666666666')))</userinput>
---
...
localhost> <userinput>lua print(box.unpack('i', num));</userinput>
---
666
...
localhost> <userinput>lua print(str);</userinput>
---
string
...
localhost> <userinput>lua print(box.unpack('l', num64))</userinput>
---
666666666666666
...
localhost> <userinput>lua box.unpack('=p', box.pack('=p', 1, '666'))</userinput>
---
 - 1
 - 666
</programlisting>
        </para></listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua">box.print(...)</emphasis>
        </term>
        <listitem><para>
Redefines Lua <code>print()</code> built-in to print either to the log file
(when Lua is used from the binary port) or back to the user (for the
administrative console).
</para><para>
When printing to the log file, INFO log level is used. When printing to
the administrative console, all output is sent directly
to the socket.
</para><para>
Note: the administrative console output must be YAML-compatible.
        </para></listitem>
    </varlistentry>
    <varlistentry>
        <term>
            <emphasis role="lua">box.dostring(s, ...)</emphasis>
        </term>
        <listitem>
            <para>
                Evaluates an arbitrary chunk of Lua code passed in
                <code>s</code>. If there is a compilation error,
                it is raised as a Lua error. If there is no compilation
                error, all arguments which follow <code>s</code>
                are passed to the compiled chunk and the chunk is
                invoked.
            </para>
            <para>
                This function is mainly useful to define and run
                an arbitrary piece of Lua code, without having to
                introduce changes to the global Lua environment.
            <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>
localhost&gt; <userinput>lua box.dostring('abc')</userinput>
---
error: '[string "abc"]:1: ''='' expected near ''&lt;eof&gt;'''
...
localhost&gt; <userinput>lua box.dostring('return 1')</userinput>
---
 - 1
...
localhost&gt; <userinput>lua box.dostring('return ...', 'hello', 'world')</userinput>
---
 - hello
 - world
...
localhost&gt; <userinput>lua box.dostring('local f = function(key) t=box.select(0, 0, key); if t ~= nil then return t[0] else return nil end end return f(...)', 0)</userinput>
---
 - nil
...
</programlisting>
            </para>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term>
            <emphasis role="lua">box.time()</emphasis>
        </term>
        <listitem>
            <para>
                Returns current system time (in seconds since the epoch) as a Lua
                number.  The time is taken from the event loop
                clock, which makes this call very cheap,
                but still useful for constructing artificial
                tuple keys.
                <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>localhost&gt; <userinput>lua box.time(),box.time()</userinput>
---
 - 1385758759.2591
 - 1385758759.2591
...
</programlisting>
            </para>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term>
            <emphasis role="lua">box.time64()</emphasis>
        </term>
        <listitem>
            <para>
                Returns current system time (in seconds) as a 64-bit
                integer. The time is taken from the event loop clock.
                <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>localhost&gt; <userinput>lua box.time(),box.time64()</userinput>
---
 - 1385758828.9825
 - 1385758828982485
...
</programlisting>
            </para>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term>
            <emphasis role="lua">box.uuid()</emphasis>
        </term>
        <listitem>
            <para>
                Returns a 128-bit (16-byte) unique id in binary form.
            </para>
            <para>
                Requires <emphasis>libuuid</emphasis> library to be
                installed. The library is loaded at runtime,
                and if the library is not available, this
                function returns an error.
                <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>localhost&gt; <userinput>lua box.uuid() == box.uuid() -- Comment: == means "are they equal?"</userinput>
---
 - false
...
</programlisting>
            </para>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term>
            <emphasis role="lua">box.uuid_hex()</emphasis>
        </term>
        <listitem>
            <para>
                Returns a 32-byte hexadecimal conversion of a 128-bit
                unique id, as a string.
            </para>
            <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>localhost&gt; <userinput>lua box.uuid_hex()</userinput>
---
 - b8eadcb078b54bed8fa8425d129b10e8
...
</programlisting>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term>
            <emphasis role="lua">box.raise(errcode, errtext)</emphasis>
        </term>
        <listitem>
            <para>
                Raises a client error. The difference between this function
                and the built-in <code>error()</code> function in Lua
                is that when the error reaches the client, its error code
                is preserved, whereas every Lua error is presented to the
                client as <constant>ER_PROC_LUA</constant>. This function
                makes it possible to emulate any kind of native exception,
                such as unique constraint violation, no such space/index,
                etc. A complete list of errors is present in <link xlink:href="https://github.com/tarantool/tarantool/blob/master/include/errcode.h">errcode.h</link>
                file in the source tree.
                Lua constants which correspond to Tarantool errors
                are defined in <code>box.error</code> module. The error
                message can be arbitrary.
                Throws client error. Lua procedure can emulate any
                request errors (for example: unique key exception).
            </para>
            <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>localhost&gt; <userinput>lua box.raise(box.error.ER_WAL_IO, 'Wal I/O error')</userinput>
---
error: 'Wal I/O error'
...
</programlisting>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term>
            <emphasis role="lua">box.auto_increment(space_no, ...)</emphasis>
        </term>
        <listitem>
            <para>
                Insert values into space designated by space_no, using
                an auto-increment primary key. The space must have a
                NUM or NUM64 primary key index of type TREE.
            </para>
            <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>localhost> <userinput>lua box.auto_increment(0, "I am a duplicate")</userinput>
---
 - 1: {'I am a duplicate'}
...
localhost> <userinput>lua box.auto_increment(0, "I am a duplicate")</userinput>
---
 - 2: {'I am a duplicate'}
...
</programlisting>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term>
            <emphasis role="lua">box.counter.inc(space_no, key)</emphasis>
        </term>
        <listitem>
            <para>
                Increments a counter identified by the key. The key can be
                multipart, but there must be an index covering
                all fields of the key. If there is no tuple
                identified by the given key, creates a new one
                with initial counter value set to 1.  Returns the
                new counter value.
            </para>
            <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>localhost> <userinput>lua box.counter.inc(0, 'top.mail.ru')</userinput>
---
 - 1
...
localhost> <userinput>lua box.counter.inc(0, 'top.mail.ru')</userinput>
---
 - 2
...</programlisting>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term>
            <emphasis role="lua">box.counter.dec(space_no, key)</emphasis>
        </term>
        <listitem>
            <para>
                Decrements a counter identified by the given key. If
                the key is not found, is a no-op. When counter value
                drops to 0, the tuple is deleted.
            </para>
            <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>localhost> <userinput>lua box.counter.dec(0, 'top.mail.ru')</userinput>
---
 - 1
...
localhost> <userinput>lua box.counter.dec(0, 'top.mail.ru')</userinput>
---
 - 0
...</programlisting>
        </listitem>
    </varlistentry>
</variablelist>
</section>

<section xml:id="sp-box-tuple">
    <title>Package <code>box.tuple</code></title>
<variablelist xml:id="box.tuple" xreflabel="box.tuple">
    <para>This package provides read-only access for the <code>box.tuple</code> userdata
    type. It allows, for a single tuple: selective retrieval of the
    field contents, retrieval of information about size,
    iteration over all the fields, and conversion to a Lua table.
    </para>
    <varlistentry>
        <term>
            <emphasis role="lua">box.tuple.new(...)</emphasis>
        </term>
        <listitem>
            <para>
                Construct a new tuple from a Lua table or a scalar.
                Alternatively, one can get new tuples from tarantool's
                SQL-like statements: SELECT, INSERT, UPDATE, REPLACE,
                which can be regarded as statements that do new()
                implicitly.
                In the following example, x and t will be new tuple objects.
                Saying <code>lua t</code> returns the entire tuple t.
            </para>
            <bridgehead renderas="sect4">Example</bridgehead>
            <programlisting>localhost&gt; <userinput>lua x=box.insert(0,'a',tonumber('1'),tonumber64('2')):totable()</userinput>
---
...
localhost> <userinput>lua t=box.tuple.new({'abc','def','ghi','abc'})</userinput>
---
...
localhost> <userinput>lua t</userinput>
---
 - 'abc': {'def', 'ghi', 'abc'}
...</programlisting>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term>
            <emphasis role="lua">#</emphasis>
        </term>
        <listitem>
            <para>
                The # operand in Lua means "return count of components".
                So, if t is a tuple instance, <code>#t</code>
                will return the number of
                fields.
                In the following example, a tuple named t is created
                and then the number of fields in t is returned.
            </para>
            <bridgehead renderas="sect4">Example</bridgehead>
            <programlisting>localhost&gt; <userinput>lua t=box.tuple.new({'Field#1','Field#2','Field#3','Field#4'})</userinput>
---
...
localhost&gt; <userinput>lua #t</userinput>
---
 - 4
...</programlisting>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term>
            <emphasis role="lua">bsize()</emphasis>
        </term>
        <listitem>
            <para>
             If t is a tuple instance, <code>t:bsize()</code>
             will return the number of bytes in the tuple.
             It is useful to check this number when making changes to data,
             because there is a fixed maximum: one megabyte.
             Every field has one or more "length" bytes preceding the
             actual contents, so bsize() returns a value which is
             slightly greater than the sum of the lengths of the contents.
             In the following example, a tuple named t is created
             which has three fields, and for each field it takes one byte
             to store the length and three bytes to store the contents,
             so bsize() returns  3*(1+3).
            </para>
            <bridgehead renderas="sect4">Example</bridgehead>
            <programlisting>localhost&gt; <userinput>lua t=box.tuple.new({'aaa','bbb','ccc'})</userinput>
---
...
localhost&gt; <userinput>lua t:bsize()</userinput>
---
 - 12
...</programlisting>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term>
            <emphasis role="lua">[ ]</emphasis>
        </term>
        <listitem>
            <para>
                If t is a tuple instance, <code>t[<replaceable>n</replaceable>]</code>
                will return the
                 <code>n</code>th field in the tuple. The first field is t[0].
                In the following example, a tuple named t is created
                and then the second field in t is returned.
            </para>
            <bridgehead renderas="sect4">Example</bridgehead>
            <programlisting>localhost&gt; <userinput>lua t=box.tuple.new({'Field#1','Field#2','Field#3','Field#4'})</userinput>
---
...
localhost&gt; <userinput>lua t[1]</userinput>
---
 - Field#2
...</programlisting>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term>
            <emphasis role="lua">find() or findall()</emphasis>
        </term>
        <listitem>
            <para>
             If t is a tuple instance, <code>t:find(<replaceable>search-value</replaceable>)</code>
             will return the number of the first field in t that matches search-value, and
              <code>t:findall(<replaceable>search-value</replaceable>)</code>
             will return numbers of all fields in t that match search-value. Optionally
             one can put a numeric argument n before the search-value to indicate
              <quote>start searching at field number n.</quote>
              In the following example, a tuple named t is created
              and then: the number of the first field in t which matches 'a' is returned,
              then the numbers of all the fields in t which match 'a' are returned,
              then the numbers of all the fields in t which match 'a' and are at or after the second field
              are returned.
            </para>
            <bridgehead renderas="sect4">Example</bridgehead>
            <programlisting>localhost&gt; <userinput>lua t=box.tuple.new({'a','b','c','a'})</userinput>
---
...
localhost&gt; <userinput>lua t:find('a')</userinput>
---
 - 0
...
localhost&gt; <userinput>lua t:findall('a')</userinput>
---
 - 0
 - 3
...
localhost&gt; <userinput>lua t:findall(1,'a')</userinput>
---
 - 3
...</programlisting>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term>
            <emphasis role="lua">transform()</emphasis>
        </term>
        <listitem>
            <para>
             If t is a tuple instance, <code>t:transform(<replaceable>n1</replaceable>,<replaceable>n2</replaceable>)</code>
             will return a tuple where, starting from field n1, a number of fields (n2) are removed.
             Optionally one can add more arguments after n2 to indicate new values that will replace
             what was removed.
             In the following example, a tuple named t is created
             and then, starting from the second field, two fields are removed
             but one new one is added, then the result is returned.
            </para>
            <bridgehead renderas="sect4">Example</bridgehead>
            <programlisting>localhost&gt; lua t=box.tuple.new({'Field#1','Field#2','Field#3','Field#4','Field#5'})
---
...
localhost&gt; <userinput>lua t:transform(1,2,'x')</userinput>
---
 - 'Field#1': {'x', 'Field#4', 'Field#5'}
...</programlisting>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term>
            <emphasis role="lua">slice()</emphasis>
        </term>
        <listitem>
            <para>
             If t is a tuple instance, <code>t:slice(<replaceable>n</replaceable>)</code>
             will return all fields starting with field number n, and
             <code>t:slice(<replaceable>n1</replaceable>,<replaceable>n2</replaceable>)</code>
             will return a tuple containing fields starting with field number n1, but
             stopping <emphasis>before</emphasis> field number n2.
             In the following example, a tuple named t is created
             and then, starting from the second field, fields before the fourth field are selected,
             then the result is returned.
            </para>
            <bridgehead renderas="sect4">Example</bridgehead>
            <programlisting>localhost&gt; lua t=box.tuple.new({'Field#1','Field#2','Field#3','Field#4','Field#5'})
---
...
localhost&gt; <userinput>lua t:slice(1,3)</userinput>
---
 - Field#2
 - Field#3
...</programlisting>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term>
            <emphasis role="lua">unpack()</emphasis>
        </term>
        <listitem>
            <para>
             If t is a tuple instance, <code>t:unpack(<replaceable>n</replaceable>)</code>
             will return all fields. In effect, <code>unpack()</code> is the same as <code>slice(0,-1)</code>.
             In the following example, a tuple named t is created
             and then all its fields are selected,
             then the result is returned.
            </para>
            <bridgehead renderas="sect4">Example</bridgehead>
            <programlisting>localhost&gt; <userinput>lua t=box.tuple.new({'Field#1','Field#2','Field#3','Field#4','Field#5'})</userinput>
---
...
localhost&gt; <userinput>lua t:unpack()</userinput>
---
 - Field#1
 - Field#2
 - Field#3
 - Field#4
 - Field#5
...</programlisting>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term>
            <emphasis role="lua">pairs()</emphasis>
        </term>
        <listitem>
            <para>
            In Lua, pairs() is a method which returns: function, value, nil.
            It is useful for Lua iterators, because Lua iterators traverse
            a value's components until an end marker is reached.
            In the following example, a tuple named t is created
            and then all its fields are selected using a Lua for-end loop.
            </para>
            <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>localhost&gt; lua t=box.tuple.new({'Field#1','Field#2','Field#3','Field#4','Field#5'})
---
...
localhost&gt; <userinput>lua for k,v in t:pairs() do print(v) end</userinput>
---
Field#1
Field#2
Field#3
Field#4
Field#5
...</programlisting>
        </listitem>
    </varlistentry>

</variablelist>
</section>

<section xml:id="sp-box-cjson">
    <title>Package <code>box.cjson</code></title>

<variablelist xml:id="box.cjson" xreflabel="box.cjson">
    <para>
        This package provides JSON manipulation routines.
        It's based on the <link xlink:href="http://www.kyne.com.au/~mark/software/lua-cjson.php">
        Lua-CJSON package by Mark Pulford</link>.

        For a complete manual on Lua-CJSON please read <link xlink:href="http://www.kyne.com.au/~mark/software/lua-cjson-manual.html">the official documentation</link>.
    </para>
    <varlistentry>
        <term><emphasis role="lua">box.cjson.encode(object)</emphasis></term>
        <listitem>
            <para>Convert a Lua object to a JSON string.</para>
            <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>localhost&gt; <userinput>lua box.cjson.encode(123)</userinput>
---
 - 123
...
localhost&gt; <userinput>lua box.cjson.encode({123})</userinput>
---
 - [123]
...
localhost&gt; <userinput>lua box.cjson.encode({123, 234, 345})</userinput>
---
 - [123,234,345]
...
localhost&gt; <userinput>lua box.cjson.encode({abc = 234, cde = 345})</userinput>
---
 - {"cde":345,"abc":234}
...
localhost&gt; <userinput>lua box.cjson.encode({hello = { 'world' } })</userinput>
---
 - {"hello":["world"]}
...
</programlisting>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term><emphasis role="lua">box.cjson.decode(string)</emphasis></term>
        <listitem>
            <para>Convert a JSON string to a Lua object.</para>
            <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>localhost&gt; <userinput>lua box.cjson.decode('123')</userinput>
---
 - 123
...
localhost&gt; <userinput>lua box.cjson.decode('[123, "hello"]')[2]</userinput>
---
 - hello
...
localhost&gt; <userinput>lua box.cjson.decode('{"hello": "world"}').hello</userinput>
---
 - world
...
</programlisting>
        </listitem>
    </varlistentry>
</variablelist>
</section>

<section xml:id="sp-box-space">
    <title>Package <code>box.space</code></title>
<variablelist xml:id="box.space" xreflabel="box.space">
    <para>This package is a container for all
    configured spaces. A space object provides access to space
    attributes, such as id, whether or not a space is
    enabled, space cardinality, and estimated number of rows. It also
    contains object-oriented versions of <code>box</code>
    functions. For example, instead of <code>box.insert(0, ...)</code>
    one can write <code>box.space[0]:insert(...)</code>.
    Package source code is available in file <filename
    xlink:href="https://github.com/tarantool/tarantool/blob/master/src/box/lua/box.lua">src/box/lua/box.lua</filename></para>
    <para>A list of all <code>space</code> members follows.</para>
    <varlistentry>
        <term><emphasis role="lua">space.n</emphasis></term>
        <listitem><simpara>Ordinal space number, <code>box.space[i].n == i</code></simpara></listitem>
    </varlistentry>
    <varlistentry>
        <term><emphasis role="lua">space.enabled</emphasis></term>
        <listitem><simpara>
            Whether or not this space is enabled in the
            configuration file.
        </simpara></listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua">space.cardinality</emphasis>
        </term>
        <listitem><simpara>
            A limit on tuple field count for tuples in this space.
            This limit can be set in the configuration file. Value 0
            stands for <quote>unlimited</quote>.
        </simpara></listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua">space.index[]</emphasis>
        </term>
        <listitem><para>
            A container for all defined indexes. An index is a Lua object
            of type <code xlink:href="#box.index">box.index</code> with
            methods to search tuples and iterate over them in predefined order.
        <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>localhost&gt; <userinput>lua box.space[0].n, box.space[0].enabled, box.space[0].cardinality, box.space[0].index[0].type</userinput>
---
 - 0
 - true
 - 0
 - HASH
...
</programlisting>
        </para></listitem>
    </varlistentry>
    <varlistentry>
        <term>
            <emphasis role="lua">space:select(index_no, ...)</emphasis>
        </term>
        <listitem>
        <simpara>
        <code>lua box.space[<replaceable>space_number</replaceable>]:select(<replaceable>index_number...</replaceable>)</code>
        is the object-oriented equivalent of
        <code xlink:href="#box.select">box.select(<replaceable>space_number</replaceable>,<replaceable>index_number...</replaceable>)</code>.
        </simpara></listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua" xml:id="box.space.select_range" xreflabel="box.space[i].select_range()">
                space:select_range(index_no, limit, key)
            </emphasis>
        </term>
        <listitem>
        <simpara>
        <code>lua box.space[<replaceable>space_number</replaceable>]:select_range(<replaceable>index_number...</replaceable>)</code>
        is the object-oriented equivalent of
        <code xlink:href="#box.select_range">box.select_range(<replaceable>space_number</replaceable>,<replaceable>index_number...</replaceable>)</code>.
        </simpara>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua"
            xml:id="box.space.select_reverse_range"
            xreflabel="box.space.select_reverse_range">
            space:select_reverse_range(limit, key)</emphasis>
        </term>
        <listitem>
        <simpara>
        <code>lua box.space[<replaceable>space_number</replaceable>]:select_reverse_range(<replaceable>index_number...</replaceable>)</code>
        is the object-oriented equivalent of
        <code xlink:href="#box.select_range">box.select_reverse_range(<replaceable>space_number</replaceable>,<replaceable>index_number...</replaceable>)</code>.
        </simpara>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term>
            <emphasis role="lua">space:insert(...)</emphasis>
        </term>
        <listitem>
        <simpara>
        <code>lua box.space[<replaceable>space_number</replaceable>]:insert(<replaceable>key</replaceable>)</code>
        is the object-oriented equivalent of
        <code xlink:href="#box.insert">box.insert(<replaceable>space_number</replaceable>,<replaceable>key</replaceable>)</code>.
        </simpara></listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua">space:replace(...)</emphasis>
        </term>
        <listitem>
        <simpara>
        <code>lua box.space[<replaceable>space_number</replaceable>]:replace(<replaceable>key</replaceable>)</code>
        is the object-oriented equivalent of
        <code xlink:href="#box.replace">box.replace(<replaceable>space_number</replaceable>,<replaceable>key</replaceable>)</code>.
        </simpara></listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua">space:delete(key)</emphasis>
        </term>
        <listitem>
        <simpara>
        <code>lua box.space[<replaceable>space_number</replaceable>]:delete(<replaceable>key</replaceable>)</code>
        is the object-oriented equivalent of
        <code xlink:href="#box.delete">box.delete(<replaceable>space_number</replaceable>,<replaceable>key</replaceable>)</code>.
        </simpara></listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua">space:update(key, format, ...)</emphasis>
        </term>
        <listitem>
        <simpara>
        <code>lua box.space[<replaceable>space_number</replaceable>]:update(<replaceable>key</replaceable>)</code>
        is the object-oriented equivalent of
        <code xlink:href="#box.update">box.update(<replaceable>space_number</replaceable>,<replaceable>key</replaceable>)</code>.
        </simpara></listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua">space:len()</emphasis>
        </term>
        <listitem>
        <para>
            Returns number of tuples in the space.
        <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>localhost&gt; <userinput>lua box.space[0]:len()</userinput>
---
 - 2
...
</programlisting>
        </para></listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua">space:truncate()</emphasis>
        </term>
        <listitem>
        <para>
            Deletes all tuples.
        <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>localhost&gt; <userinput>lua box.space[0]:truncate()</userinput>
---
...
localhost&gt; <userinput>lua box.space[0]:len()</userinput>
---
 - 0
...
</programlisting>
        </para></listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua">space:pairs()</emphasis>
        </term>
        <listitem>
        <simpara>
            A helper function to iterate over all space tuples,
            Lua style.
        </simpara>
                <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>
localhost> <userinput>lua for k,v in box.space[0]:pairs() do print(v) end</userinput>
---
1: {'hello'}
2: {'my     '}
3: {'Lua    '}
4: {'world'}
...
</programlisting>
        </listitem>
    </varlistentry>
</variablelist>
</section>

<section xml:id="sp-box-index">
    <title>Package <code >box.index</code></title>
<variablelist xml:id="box.index" xreflabel="box.index">
    <para>
        This package implements methods of type <code>box.index</code>.
        Indexes are contained in <code
        xlink:href="#box.space">box.space[i].index[]</code> array
        within each space object. They provide an API for
        ordered iteration over tuples. This API is a direct
        binding to corresponding methods of index objects in the
        storage engine.
    </para>
    <varlistentry>
        <term><emphasis role="lua">index.unique</emphasis></term>
        <listitem><simpara>
            Boolean, true if the index is unique.
        </simpara></listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua">index.type</emphasis>
        </term>
        <listitem><simpara>
            A string for index type, either 'TREE', 'HASH', or 'BITSET'.
        </simpara></listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua">index.key_field[]</emphasis>
        </term>
        <listitem><simpara>
            An array describing index key fields.
        </simpara></listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua">index.idx</emphasis>
        </term>
        <listitem><para>
            The underlying userdata which does all the magic.
        <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>localhost&gt; <userinput>lua box.space[0].index[0].unique,box.space[0].index[0].type,box.space[0].index[0].key_field[0],box.space[0].index[0].idx</userinput>
---
 - true
 - HASH
 - table: 0x41d03518
 - index 0 in space 0
...
</programlisting>
        </para></listitem>
    </varlistentry>

    <varlistentry>
        <term>
             <emphasis role="lua" xml:id="box.index.iterator" xreflabel="box.index.iterator(type, ...)">
            index:iterator(type, ...)</emphasis>
        </term>
        <listitem>
            <simpara>
                This method provides iteration support within an
                index. Parameter <code>type</code> is used to
                identify the semantics of iteration. Different
                index types support different iterators. The
                remaining arguments of the function are varying
                and depend on the iteration type. For example,
                a TREE index maintains a strict order of keys and
                can return all tuples in ascending or descending
                order, starting from the specified key. Other
                index types, however, do not support ordering.
            </simpara>
            <para xml:id="iterator-consistency">
                To understand consistency of tuples
                returned by an iterator, it's essential to know
                the principles of the Tarantool transaction processing
                subsystem.
                An iterator in Tarantool does not own a consistent
                read view. Instead, each procedure is granted exclusive
                access to all tuples and spaces until it
                encounters a "context switch": by causing a write to
                disk, network, or by an explicit call to <emphasis
                role="lua" xlink:href="#box.fiber.yield">box.fiber.yield()</emphasis>.
                When the execution flow returns to the yielded
                procedure, the data set could have changed significantly.
                Iteration, resumed after a yield point, does not
                preserve the read view, but continues with the new
                content of the database.
            </para>
            <para>
                <bridgehead renderas="sect4">Parameters</bridgehead>
                <simplelist>
                        <member><code>type</code> &mdash; iteration strategy as defined in tables below.</member>
                </simplelist>

                <bridgehead renderas="sect4">Returns</bridgehead>
                    This method returns an iterator closure, i.e.
                    a <code>function</code> which can be used to
                    get the next value on each invocation.
                <bridgehead renderas="sect4">Errors</bridgehead>
                    Selected iteration type is not supported in
                    the subject index type or supplied parameters
                    do not match iteration type.
            </para>

            <xi:include href="iterator-types.xml"/>

            <para>
                <bridgehead renderas="sect4">Examples</bridgehead>
<programlisting>
localhost> <userinput>show configuration</userinput>
---
...
  space[0].enabled: "true"
  space[0].index[0].type: "HASH"
  space[0].index[0].unique: "true"
  space[0].index[0].key_field[0].fieldno: "0"
  space[0].index[0].key_field[0].type: "NUM"
  space[0].index[1].type: "TREE"
  space[0].index[1].unique: "false"
  space[0].index[1].key_field[0].fieldno: "1"
  space[0].index[1].key_field[0].type: "NUM"
  space[0].index[1].key_field[1].fieldno: "2"
  space[0].index[1].key_field[1].type: "NUM"
...
localhost> <userinput>INSERT INTO t0 VALUES (1, 1, 0)</userinput>
Insert OK, 1 rows affected
localhost> <userinput>INSERT INTO t0 VALUES (2, 1, 1)</userinput>
Insert OK, 1 rows affected
localhost> <userinput>INSERT INTO t0 VALUES (3, 1, 2)</userinput>
Insert OK, 1 rows affected
localhost> <userinput>INSERT INTO t0 VALUES (4, 2, 0)</userinput>
Insert OK, 1 rows affected
localhost> <userinput>INSERT INTO t0 VALUES (5, 2, 1)</userinput>
Insert OK, 1 rows affected
localhost> <userinput>INSERT INTO t0 VALUES (6, 2, 2)</userinput>
Insert OK, 1 rows affected
localhost> <userinput>lua it = box.space[0].index[1]:iterator(box.index.EQ, 1); print(it(), " ", it(), " ", it());</userinput>
---
1: {1, 0} 2: {1, 1} 3: {1, 2}
...
localhost> <userinput>lua it = box.space[0].index[1]:iterator(box.index.EQ, 1, 2); print(it(), " ", it(), " ", it());</userinput>
---
3: {1, 2} nil nil
...
localhost> <userinput>lua i = box.space[0].index[1]:iterator(box.index.GE, 2, 1);  print(it(), " ", it(), " ", it());</userinput>
---
5: {2, 1} 6: {2, 2} nil
...
localhost> <userinput>lua for v in box.space[0].index[1]:iterator(box.index.ALL) do print(v) end</userinput>
---
1: {1, 0}
2: {1, 1}
3: {1, 2}
4: {2, 0}
5: {2, 1}
6: {2, 2}
...
localhost> <userinput>lua i = box.space[0].index[0]:iterator(box.index.LT, 1);</userinput>
---
error: 'Iterator type is not supported'
</programlisting>
            </para>
        </listitem>
    </varlistentry>


    <varlistentry>
        <term>
            <emphasis role="lua">index:min()</emphasis>
        </term>
        <listitem>
        <para>
            The smallest value in the index. Available only for
            indexes of type 'TREE'.
        <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>localhost&gt; <userinput>lua box.space[0].index[0]:min()</userinput>
---
 - 'Alpha': {55, 'This is the first tuple!'}
...
</programlisting>
        </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua">index:max()</emphasis>
        </term>
        <listitem>
        <para>
            The biggest value in the index. Available only for
            indexes of type 'TREE'.
        <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>localhost&gt; <userinput>lua box.space[0].index[0]:max()</userinput>
---
 - 'Gamma': {55, 'This is the third tuple!'}
...
</programlisting>
        </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua">index:random(randint)</emphasis>
        </term>
        <listitem>
        <para>
           Return a random value from an index. A random
           non-negative integer must be supplied as input, and
           a value is selected accordingly in index-specific fashion.
           This method is useful when it's important to get insight
           into data distribution in an index without having to
           iterate over the entire data set.
        <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>localhost&gt; <userinput>lua box.space[0].index[0]:random(1)</userinput>
---
 - 1635018050: {66, 'This is the second tuple!'}
...
</programlisting>
        </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua">index:count()</emphasis>
        </term>
        <listitem>
        <para>
           Iterate over an index, counting the number of tuples which equal the
           provided search criteria. The argument can either point to a
           tuple, a key, or one or more key parts. Returns the number of matched
           tuples.
        <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>localhost&gt; <userinput>lua box.space[0].index[0]:count("Alpha")</userinput>
---
 - 1
...
</programlisting>
        </para>
        </listitem>
    </varlistentry>

</variablelist>
</section>

<section xml:id="sp-box-fiber">
    <title>Package <code>box.fiber</code></title>
    <para>Functions in this package allow you to create, run and
    manage existing <emphasis>fibers</emphasis>.
    </para>
    <para>
A fiber is an independent execution thread implemented
using a mechanism of cooperative multitasking.

A fiber has three possible states: running, suspended or dead.
When a fiber is created with <code>box.fiber.create()</code>,
it is suspended.
When a fiber is started with <code>box.fiber.resume()</code>, it is running.
When a fiber's control is yielded back to the caller with
<code>box.fiber.yield()</code>, it is suspended.
When a fiber ends (due to <code>return</code> or by reaching the
end of the fiber function), it is dead.
    </para>
    <para>
A fiber can also be attached or detached.
An attached fiber is a child of the creator,
and is running only if the creator has called
<code>box.fiber.resume()</code>. A detached fiber is a child of
Tarantool internal <quote>sched</quote> fiber, and gets
scheduled only if there is a libev event associated
with it.
    </para>
    <para>
To detach, a running fiber must invoke <code>box.fiber.detach()</code>.
A detached fiber loses connection with its parent forever.
    </para>
    <para>
All fibers are part of the fiber registry, <code>box.fiber</code>.
This registry can be searched (<code>box.fiber.find()</code>)
either by fiber id (fid), which is numeric, or by fiber name,
which is a string. If there is more than one fiber with the given
name, the first fiber that matches is returned.
    </para>
    <para>
Once fiber function is done or calls <code>return</code>,
the fiber is considered dead. Its carcass is put into
a fiber pool, and can be reused when another fiber is
created.
    </para>
    <para>
A runaway fiber can be stopped with <code>box.fiber.cancel()</code>.
However, <code>box.fiber.cancel()</code> is advisory &mdash; it works
only if the runaway fiber calls <code>box.fiber.testcancel()</code>
once in a while. Most <code>box.*</code> hooks, such as <code>box.delete()</code>
or <code>box.update()</code>, do call <code>box.fiber.testcancel()</code>.
<code>box.select()</code> doesn't.
    </para>
    <para>
In practice, a runaway fiber can only become unresponsive
if it does a lot of computations and doesn't check
whether it's been canceled.
<!--
In addition to the advisory cancellation, configuration parameter
<code>lua_timeout</code> can be used to cancel runaway Lua
procedures.
-->
    </para>
    <para>
The other potential problem comes from detached
fibers which never get scheduled, because they are not subscribed
to any events, or because no relevant events occur. Such morphing fibers
can be killed with <code>box.fiber.cancel()</code> at any time,
since <code>box.fiber.cancel()</code>
sends an asynchronous wakeup event to the fiber,
and <code>box.fiber.testcancel()</code> is checked whenever such an event occurs.
    </para>
    <para>Like all Lua objects, dead fibers are
    garbage collected: the garbage collector frees pool allocator
    memory owned by the fiber, resets all fiber data, and returns
    the fiber to the fiber pool.</para>
<variablelist xml:id="box.fiber">
    <varlistentry>
        <term>
            <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" 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>
    </varlistentry>

    <varlistentry>
        <term>
            <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" xml:id="box.fiber.create">box.fiber.create(function) </emphasis>
        </term>
        <listitem><simpara>
            Create a fiber for a <code>function</code>.
        </simpara>
        <bridgehead renderas="sect4">Errors</bridgehead>
        <simpara>Can hit a recursion limit.</simpara>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua" xml:id="box.fiber.resume">box.fiber.resume(fiber, ...) </emphasis>
        </term>
        <listitem><simpara>Resume a created
        or suspended fiber.</simpara></listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua" xml:id="box.fiber.yield" xreflabel="box.fiber.yield(...)">box.fiber.yield(...) </emphasis>
        </term>
        <listitem><para>
        Yield control to the calling fiber, if the fiber
        is attached, or to sched otherwise.
        </para>
        <para>
        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 after temporarily
        yielding control back to the scheduler.
        </para></listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <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.
        </simpara></listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <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.
    Only the current fiber can be made to sleep.
        </simpara></listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <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>.
        Running and suspended fibers can be canceled.
        Returns an error if the subject fiber does not permit cancel.
        </simpara></listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua" xml:id="box.fiber.testcancel">box.fiber.testcancel()</emphasis>
        </term>
        <listitem><simpara>
            Check if the current fiber has been canceled and
            throw an exception if this is the case.
        </simpara></listitem>
    </varlistentry>
</variablelist>
</section>

<!--   end of lib -->

<section xml:id="sp-box-session">
    <title>Package <code>box.session</code></title>
    <para>Learn session state, set on-connect and
    on-disconnect triggers.
    </para>
    <para>
A session is an object associated with each client connection.
Through this module, it's possible to query session state,
as well as set a Lua chunk executed on a connect or disconnect
event.
    </para>
<variablelist>
    <varlistentry>
        <term>
            <emphasis role="lua">box.session.id() </emphasis>
        </term>
        <listitem><simpara>Return a unique monotonic identifier of
        the current session. The identifier can be used to check
        whether or not a session is alive. 0 means there is no
        session (e.g. a procedure is running in a detached
        fiber).
        </simpara></listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua">box.session.fd(id) </emphasis>
        </term>
        <listitem><simpara>Return an integer file descriptor
        associated with the connected client.</simpara></listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua">box.session.exists(id) </emphasis>
        </term>
        <listitem><simpara>Return true if a session is alive,
        false otherwise.</simpara></listitem>
    </varlistentry>

    <varlistentry>
        <term>
           <emphasis role="lua">box.session.peer(id) </emphasis>
        </term>
        <listitem><simpara>Return the host address and port for the session
        peer, for example "127.0.0.1:55457", or "0.0.0.0:0" if the session
        is not connected.</simpara></listitem>
    </varlistentry>

    <varlistentry>
        <term>
           <emphasis role="lua">box.session.storage</emphasis>
        </term>
        <listitem><simpara>A virtual table that is local for each session.
        It can be used to store session-specific values. The lifetime is the
        same as the session's (until disconnect).
        </simpara></listitem>
    </varlistentry>

</variablelist>
    <para>
This module also makes it possible to define triggers on connect
and disconnect events. Please see <olink targetptr="sp-box-session-triggers">
the triggers chapter</olink> for details.
    </para>
</section>

<!--   end of lib -->

<section xml:id="sp-box-ipc">
    <title>Package <code>box.ipc</code> &mdash; inter procedure communication</title>
<variablelist xml:id="box.ipc">
    <simpara>
    </simpara>
    <varlistentry>
        <term><emphasis role="lua">box.ipc.channel(capacity)</emphasis></term>
        <listitem>
            <simpara>
                Create a new communication channel with
                predefined capacity. The channel can be used
                to synchronously exchange messages between
                stored procedures. The channel is garbage
                collected when no one is using it, just like any
                other Lua object. Channels can be worked with
                using functional or object-oriented syntax. For
                example, the following two lines are equivalent:
            </simpara>
<programlisting>
    channel:put(message)
    box.ipc.channel.put(channel, message)
</programlisting>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term><emphasis role="lua">box.ipc.channel.put(channel, message, timeout)</emphasis></term>
        <listitem>
            <simpara>
                Send a message using a channel. If the channel is full,
                <emphasis role="lua">box.ipc.channel.put()</emphasis>
                blocks until there is a free slot in the channel.
                If <emphasis role="lua">timeout</emphasis> is provided,
                and the channel doesn't become empty for the duration
                of the timeout,
                <emphasis role="lua">box.ipc.channel.put()</emphasis>
                returns false. Otherwise it returns true.
            </simpara>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term><emphasis role="lua">box.ipc.channel.get(channel, timeout)</emphasis></term>
        <listitem>
            <simpara>
                Fetch a message from a channel. If the channel is empty,
                <emphasis role="lua">box.ipc.channel.get()</emphasis>
                blocks until there is a message.
                If <emphasis role="lua">timeout</emphasis> is provided,
                and there are no new messages for the duration
                of the timeout,
                <emphasis role="lua">box.ipc.channel.get()</emphasis>
                returns error.
            </simpara>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term><emphasis role="lua">box.ipc.channel.broadcast(channel, message, timeout)</emphasis></term>
        <listitem>
            <simpara>
                If the channel is empty, is equivalent to
                <emphasis role="lua">box.ipc.channel.put()</emphasis>.
                Otherwise sends the message to all readers of the
                channel.
            </simpara>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term><emphasis role="lua">box.ipc.channel.is_empty(channel)</emphasis></term>
        <listitem>
            <simpara>
                Check if the channel is empty (has no messages).
            </simpara>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term><emphasis role="lua">box.ipc.channel.is_full(channel)</emphasis></term>
        <listitem>
            <simpara>
                Check if the channel is full (has no room for a new message).
            </simpara>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term><emphasis role="lua">box.ipc.channel.has_readers(channel)</emphasis></term>
        <listitem>
            <simpara>
                Check if the channel is empty and has readers waiting
                for a message.
            </simpara>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term><emphasis role="lua">box.ipc.channel.has_writers(channel)</emphasis></term>
        <listitem>
            <simpara>
                Check if the channel is full and has writers waiting
                for empty room.
            </simpara>
            <bridgehead renderas="sect4">Example</bridgehead><programlisting>
local channel = box.ipc.channel(10)
function consumer_fiber()
    while true do
        local task = channel:get()
        ...
    end
end

function consumer2_fiber()
    while true do
        local task = channel:get(10)        -- 10 seconds
        if task ~= nil then
            ...
        else
            print("timeout!")
        end
    end
end

function producer_fiber()
    while true do
        task = box.select(...)
        ...
        if channel:is_empty() then
            # channel is empty
        end

        if channel:is_full() then
            # channel is full
        end

        ...
        if channel:has_readers() then
            # there are some fibers that wait data
        end
        ...

        if channel:has_writers() then
            # there are some fibers that wait readers
        end
        channel:put(task)
    end
end

function producer2_fiber()
    while true do
        task = box.select(...)

        if channel:put(task, 10) then       -- 10 seconds
            ...
        else
            print("timeout!")
        end
    end
end
</programlisting>
        </listitem>
    </varlistentry>
</variablelist>
</section>

<!--   end of lib -->

<section xml:id="sp-box-socket">
    <title>Package <code>box.socket</code> &mdash; TCP and UDP sockets</title>
<variablelist xml:id="box.socket">
    <simpara>
      BSD sockets is a mechanism to exchange data with a local or
      remote host in connection-oriented (TCP) or datagram-oriented
      (UDP) mode.
      Semantics of the calls in the <code>box.socket</code> API closely follow
      semantics of the corresponding POSIX calls. Function names
      and signatures are mostly compatible with
      <link xlink:href="http://w3.impa.br/~diego/software/luasocket/">luasocket</link>.
    </simpara>
    <simpara>
      Similarly to luasocket, <code>box.socket</code> doesn't throw exceptions
      on errors. On success, most calls return a socket object.
      On error, a multiple return of <code>nil, status, errno, errstr</code>
      is produced.
      <code>Status</code> can be one of <code>"error"</code>, <code>"timeout"</code>,
      <code>"eof"</code> or <code>"limit"</code>. On
      success, status is always <code>nil</code>.
      A call which returns data (<code>recv()</code>, <code>recvfrom()</code>,
      <code>readline()</code>) on success returns a Lua string of
      the requested size and <code>nil</code> status. On error or timeout,
      an empty string is followed by the corresponding status, error number and message.
      A call which sends data (<code>send()</code>, <code>sendto()</code>) on
      success returns the number of bytes sent, and the <code>status</code> is, again,
      <code>nil</code>. On error or timeout <code>0</code> is returned,
      followed by status, error number and message.
    </simpara>
    <simpara>
      The last error can be retrieved from the socket using
      <code>socket:error()</code>. Any call except <code>error()</code> clears
      the last error first (but may set a new one).
    </simpara>
    <simpara>
      Calls which require a socket address and in POSIX expect
      <code>struct sockaddr_in</code>, in <code>box.socket</code>
      simply accept host name and port as additional arguments.
      Name resolution is done automatically. If it fails,
      status is set to <code>"error"</code>, errno is set to <code>-1</code>
      and error string is set to <code>"Host name resolution failed"</code>.
    </simpara>
    <simpara>
      All calls that can take time block the calling fiber
      and can get it preempted. The implementation, however, uses
      non-blocking cooperative I/O, so Tarantool continues processing
      queries while a call is blocked.
      A timeout can be provided for any socket call which can take
      a long time.
    </simpara>
    <simpara>
      As with all other <code>box</code> libraries, the API can be used
      in procedural style (e.g. <code>box.socket.close(socket)</code>) as well
      as in object-oriented style (<code>socket:close()</code>).
    </simpara>
    <simpara>
      A closed socket should not be used any more. Alternatively, the
      socket will be closed when its userdata is garbage collected
      by Lua.
    </simpara>

    <varlistentry>
        <term><emphasis role="lua">box.socket.tcp()</emphasis></term>
        <listitem>
            <para>
                Create a new TCP socket.
                <bridgehead renderas="sect4">Returns</bridgehead>
                A new socket or <code>nil</code>.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term><emphasis role="lua">box.socket.udp()</emphasis></term>
        <listitem>
            <para>
                Create a new UDP socket.
                <bridgehead renderas="sect4">Returns</bridgehead>
                A new socket or <code>nil</code>.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term><emphasis role="lua">socket:connect(host, port, [timeout])</emphasis></term>
        <listitem>
            <para>
                Connect a socket to a remote host. Can be used with IPv6 and IPv4
                addresses, as well as domain names. If multiple addresses
                correspond to a domain, tries them all until successfully
                connected.
                <bridgehead renderas="sect4">Returns</bridgehead>
                Returns a connected socket on success,
                <code>nil, status, errno, errstr</code> on error or timeout.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term><emphasis role="lua">socket:send(data, [timeout])</emphasis></term>
        <listitem>
            <para>
             Send data over a connected socket.
             <bridgehead renderas="sect4">Returns</bridgehead>
             The number of bytes sent. On success, this is exactly
             the length of <code>data</code>. In case of error or timeout,
             returns the number of bytes sent before error,
             followed by <code>status, errno, errstr</code>.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term><emphasis role="lua">socket:recv(size, [timeout])</emphasis></term>
        <listitem>
            <para>
              Read <code>size</code> bytes from a connected socket.
              An internal read-ahead buffer is used to reduce the cost
              of this call.
             <bridgehead renderas="sect4">Returns</bridgehead>
              A string of the requested length on success.
              On error or timeout, returns an empty string, followed
              by <code>status, errno, errstr</code>.
              If there was some data read before a timeout occurred, it
              will be available on the next call.
              In case the writing side has closed its end, returns the remainder
              read from the socket (possibly an empty string),
              followed by <code>"eof"</code> status.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term><emphasis role="lua">socket:readline([limit], [separator list], [timeout])</emphasis></term>
        <listitem>
            <para>
                Read a line from a connected socket.
            </para>
            <para>
                <code>socket:readline()</code> with no arguments reads data from a socket
                until '\n' or eof.
                If a limit is set, the call reads data until a separator is found,
                or the limit is reached. By default, there is no limit.
                Instead of the default separator, a Lua table can be used
                with one or multiple separators. Then the data is read
                until the first matching separator is found.
            </para>
            <para>
                <bridgehead renderas="sect4">Returns</bridgehead>
                A Lua string with data in case of success
                or an empty string in case of error. When
                multiple separators were provided in a separator
                table, the matched separator is returned as the third argument.
                <table>
                    <title><code>readline()</code> returns</title>
                    <tgroup cols="2" align="left" colsep="1" rowsep="1">
                      <tbody>
                        <row>
                          <entry><code>data, nil, separator</code></entry><entry>success</entry>
                        </row>
                        <row>
                          <entry><code>"", "timeout", ETIMEDOUT, errstr</code></entry><entry>timeout</entry>
                        </row>
                        <row>
                          <entry><code>"", "error", errno, errstr</code></entry><entry>error</entry>
                        </row>
                        <row>
                          <entry><code>data, "limit"</code></entry><entry>limit</entry>
                        </row>
                        <row>
                          <entry><code>data, "eof"</code></entry><entry>eof</entry>
                        </row>
                      </tbody>
                    </tgroup>
                </table>
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term><emphasis role="lua">socket:bind(host, port[, timeout])</emphasis></term>
        <listitem>
            <para>
                Bind a socket to the given host/port.
                A UDP socket after binding can be used
                to receive data (see <code>recvfrom()</code>). A TCP socket
                can be used to accept new connections, after it's
                been put in listen mode.
                The timeout is used for name resolution only. If host
                name is an IP address, the call never yields and
                the timeout is unused.
                <bridgehead renderas="sect4">Returns</bridgehead>
                Socket object on success, <code>nil, status, errno, errstr</code> on error.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term><emphasis role="lua">socket:listen()</emphasis></term>
        <listitem>
            <para>
                Start listening for incoming connections. The listen
                backlog, on Linux, is taken from <filename>/proc/sys/net/core/somaxconn</filename>,
                whereas on BSD it is set to <constant>SOMAXCONN</constant>.
                <bridgehead renderas="sect4">Returns</bridgehead>
                Socket on success, <code>nil, "error", errno, errstr</code> on error.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term><emphasis role="lua">socket:accept([timeout])</emphasis></term>
        <listitem>
            <para>
                Wait for a new client connection and create a connected
                socket.
                <bridgehead renderas="sect4">Returns</bridgehead>
                <code>peer_socket, nil, peer_host, peer_port</code> on success.
                <code>nil, status, errno, errstr</code> on error.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term><emphasis role="lua">socket:sendto(data, host, port, [timeout])</emphasis></term>
        <listitem>
            <para>
                Send a message on a UDP socket to a specified host.
                <bridgehead renderas="sect4">Returns</bridgehead>
                The number of bytes sent on success, <code>0, status, errno, errstr</code>
                on error or timeout.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term><emphasis role="lua">socket:recvfrom(limit[, timeout])</emphasis></term>
        <listitem>
            <para>
                Receive a message on a UDP socket.
                <bridgehead renderas="sect4">Returns</bridgehead>
                Message, <code>nil</code>, client address, client port on success,
                <code>"", status, errno, errstr</code> on error or timeout.
            </para>
        </listitem>
    </varlistentry>


    <varlistentry>
        <term><emphasis role="lua">socket:shutdown(how)</emphasis></term>
        <listitem>
            <para>
                Shutdown a reading, writing or both ends of a socket.
                Accepts box.socket.SHUT_RD, box.socket.SHUT_WR
                and box.socket.SHUT_RDWR.
                <bridgehead renderas="sect4">Returns</bridgehead>
                Socket on success, <code>nil, "error", errno, errstr</code> on error.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term><emphasis role="lua">socket:close()</emphasis></term>
        <listitem>
            <para>
                Close (destroy) a socket. A closed socket should not
                be used any more.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term><emphasis role="lua">socket:error()</emphasis></term>
        <listitem>
            <para>
                Retrieve the last error that occurred on a socket.
                <bridgehead renderas="sect4">Returns</bridgehead>
                <code>errno, errstr</code>. <code>0, "Success"</code>
                if there is no error.
            </para>
        </listitem>
    </varlistentry>

</variablelist>
</section>

<section xml:id="sp-box-net-box">
    <title>Package <code>box.net.box</code> &mdash; working with networked Tarantool peers</title>
    <simpara>
        Library <code>box.net</code> contains connectors
        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 the
        <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" xml:id="box.net.box.new">
            conn = box.net.box.new(host, port [, reconnect_interval])</emphasis>
        </term>
        <listitem>
            <para>
                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. The 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" xml:id="box.net.box.ping">
            conn:ping()</emphasis></term>
        <listitem>
            <para>
                Execute a PING command.
                Returns <code>true</code> on success,
                <code>false</code> on error.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term><emphasis role="lua" xml:id="box.net.box.close">
            conn:close()</emphasis></term>
        <listitem>
            <para>
                Close a connection. The connection is also
                closed when it's garbage collected. It's still
                recommended to close connections explicitly,
                to spare the garbage collector from heavy work
                such as closing the socket.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term><emphasis role="lua" xml:id="box.net.box.select">
            conn:select(space_no, index_no, ...)</emphasis></term>
        <listitem>
            <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" xml:id="box.net.box.select_limit">
            conn:select_limit(space_no, index_no, offset, limit, ...)</emphasis></term>
        <listitem>
            <para>
                See <code
                xlink:href="#box.select_limit">box.select_limit(...)</code>
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <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 <code
                xlink:href="#box.select_range">box.select_range(...)</code>.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term><emphasis role="lua" xml:id="box.net.box.insert">conn:insert(space_no, ...)</emphasis></term>
        <listitem>
            <para>
                See <code xlink:href="#box.insert">box.insert(...)</code>.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term><emphasis role="lua" xml:id="box.net.box.replace">conn:replace(space_no, ...)</emphasis></term>
        <listitem>
            <para>
                See <code xlink:href="#box.replace">box.replace(...)</code>.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term><emphasis role="lua" xml:id="box.net.box.update">conn:update(...)</emphasis></term>
        <listitem>
            <para>
                See <code
                xlink:href="#box.update">box.update(...)</code>.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term><emphasis role="lua" xml:id="box.net.box.delete">conn:delete(space_no, key)</emphasis></term>
        <listitem>
            <para>
                See <code xlink:href="#box.delete">box.delete(...)</code>.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <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>.
            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" xml:id="box.net.box.timeout">conn:timeout(timeout)</emphasis></term>
        <listitem>
            <para>
                Returns a closure which is identical to the
                invoked function, except for the added timeout
                functionality.
<programlisting>
-- wait for 'update' until it is finished
local tuple = conn:update('1', 'key', ...)

-- 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">Example</bridgehead>
 <programlisting>
-- connect to the local server
local self = box.net.box.new('127.0.0.1', box.info.primary_port)
self:insert("1", "Hello", "World")
</programlisting>
</section>

<section xml:id="sp-box-cfg">
    <title>Packages <code>box.cfg</code>,
    <code>box.info</code>, <code>box.slab</code> and
    <code>box.stat</code>: server introspection</title>

<variablelist>
    <title>Package <code xml:id="box.cfg">box.cfg</code></title>
    <para>This package provides read-only access to
    all server configuration parameters.</para>
    <varlistentry>
        <term><emphasis role="lua">box.cfg</emphasis></term>
        <listitem><bridgehead renderas="sect4">Example</bridgehead><programlisting>
localhost> <userinput>lua for k, v in pairs(box.cfg) do print(k, " = ", v) end</userinput>
---
io_collect_interval = 0
pid_file = box.pid
panic_on_wal_error = false
slab_alloc_factor = 2
slab_alloc_minimal = 64
admin_port = 33015
logger = cat - >> tarantool.log
...
</programlisting></listitem>
    </varlistentry>
</variablelist>

<variablelist>
    <title>Package <code>box.info</code></title>
    <para>
        This package provides access to information about
        server variables: pid, uptime, version and such.
        Its contents are identical to the output from <olink
        targetptr="show-info"/>.
    </para>
    <varlistentry>
        <term>
            <emphasis role="lua">box.info()</emphasis>
        </term>
        <listitem>
            <simpara>
            Since box.info contents are dynamic, it's not
            possible to iterate over keys with the Lua
            <emphasis>pairs()</emphasis> function. For this
            purpose, <emphasis>box.info()</emphasis> builds and
            returns a Lua table with all keys and values provided
            in the package.
            </simpara>

       <bridgehead renderas="sect4">Example</bridgehead><programlisting>
localhost> <userinput>lua for k,v in pairs(box.info()) do print(k, ": ", v) end</userinput>
---
version: 1.4.7-92-g4ba95ca
status: primary
pid: 1747
lsn: 1712
recovery_last_update: 1306964594.980
recovery_lag: 0.000
uptime: 39
build: table: 0x419cb880
logger_pid: 1748
config: /home/unera/work/tarantool/test/box/tarantool_good.cfg
...
</programlisting>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term>
            <emphasis role="lua">box.info.status, box.info.pid, box.info.lsn, ...</emphasis>
        </term>
        <listitem>
       <bridgehead renderas="sect4">Example</bridgehead><programlisting>
localhost> <userinput>lua box.info.pid</userinput>
---
 - 1747
...
localhost> <userinput>lua box.info.logger_pid</userinput>
---
 - 1748
...
localhost> <userinput>lua box.info.version</userinput>
---
 - 1.4.7-92-g4ba95ca
...
localhost> <userinput>lua box.info.config</userinput>
---
 - /home/unera/work/tarantool/test/box/tarantool_good.cfg
...
localhost> <userinput>lua box.info.uptime</userinput>
---
 - 3672
...
localhost> <userinput>lua box.info.lsn</userinput>
---
 - 1712
...
localhost> <userinput>lua box.info.status</userinput>
---
 - primary
...
localhost> <userinput>lua box.info.recovery_lag</userinput>
---
 - 0.000
...
localhost> <userinput>lua box.info.recovery_last_update</userinput>
---
 - 1306964594.980
...
localhost> <userinput>lua box.info.snapshot_pid</userinput>
---
 - 0
...
localhost> <userinput>lua for k, v in pairs(box.info.build) do print(k .. ': ', v) end</userinput>
---
flags:  -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -DCORO_ASM -fno-omit-frame-pointer -fno-stack-protector -fexceptions -funwind-tables -fgnu89-inline -pthread  -Wno-sign-compare -Wno-strict-aliasing -std=gnu99 -Wall -Wextra -Werror
target: Linux-x86_64-Debug
compiler: /usr/bin/gcc
options: cmake . -DCMAKE_INSTALL_PREFIX=/usr/local -DENABLE_STATIC=OFF -DENABLE_GCOV=OFF -DENABLE_TRACE=ON -DENABLE_BACKTRACE=ON -DENABLE_CLIENT=OFF
...
</programlisting>
        </listitem>
    </varlistentry>
</variablelist>
<variablelist>
    <title>Package <code>box.slab</code></title>
    <para>This package provides access to slab allocator statistics.</para>
    <varlistentry>
        <term><emphasis role="lua">box.slab</emphasis></term>
        <listitem><bridgehead renderas="sect4">Example</bridgehead><programlisting>
localhost> <userinput>lua box.slab.arena_used</userinput>
---
 - 4194304
...
localhost> <userinput>lua box.slab.arena_size</userinput>
---
 - 104857600
...
localhost> <userinput>lua for k, v in pairs(box.slab.slabs) do print(k) end</userinput>
---
64
128
...
localhost> <userinput>lua for k, v in pairs(box.slab.slabs[64]) do print(k, ':', v) end</userinput>
---
items:1
bytes_used:160
item_size:64
slabs:1
bytes_free:4194144
...
</programlisting></listitem>
    </varlistentry>
</variablelist>

<variablelist>
    <title>Package <code xml:id="box.stat">box.stat</code></title>
    <para>This package provides access to request
    statistics.</para>
    <varlistentry>
        <term><emphasis role="lua">box.stat</emphasis></term>
        <listitem><bridgehead renderas="sect4">Example</bridgehead><programlisting>
localhost> <userinput>lua box.stat -- a virtual table</userinput>
---
 - table: 0x41a07a08
...
localhost> <userinput>lua box.stat() -- a full table (the same)</userinput>
---
 - table: 0x41a0ebb0
...
localhost> <userinput>lua for k, v in pairs(box.stat()) do print(k) end</userinput>
---
DELETE
SELECT
REPLACE
CALL
UPDATE
DELETE_1_3
...
localhost> <userinput>lua for k, v in pairs(box.stat().DELETE) do print(k, ': ', v) end</userinput>
---
total: 23210
rps: 22
...
localhost> <userinput>lua for k, v in pairs(box.stat.DELETE) do print(k, ': ', v) end -- the same</userinput>
---
total: 23210
rps: 22
...
localhost> <userinput>lua for k, v in pairs(box.stat.SELECT) do print(k, ': ', v) end</userinput>
---
total: 34553330
rps: 23
...
localhost>
</programlisting></listitem>
    </varlistentry>
</variablelist>

<para>
    Additional examples can be found in the open source <link
    xlink:href="https://github.com/mailru/tntlua">Lua stored
    procedures repository</link> and in the server test suite.
</para>
</section>

<section xml:id="sp-limitations">
<title>Limitations of stored procedures</title>

<para>
    There are two limitations in stored procedures support one should
    be aware of: execution atomicity and lack of typing.
</para>
<bridgehead renderas="sect4">Cooperative multitasking environment</bridgehead>
<para>
    Tarantool core is built around a cooperative multi-tasking
    paradigm: unless a running fiber deliberately yields control
    to some other fiber, it is not preempted.
    <quote>Yield points</quote> are built into all
    calls from Tarantool core to the operating system.
    Any system call which can block is performed in a
    asynchronous manner and the fiber waiting
    on the system call is preempted with a fiber ready to
    run. This model makes all programmatic locks unnecessary:
    cooperative multitasking ensures that there is no concurrency
    around a resource, no race conditions and no memory
    consistency issues.
</para>
<para>
    When requests are small, e.g. simple UPDATE, INSERT, DELETE,
    SELECT, fiber scheduling is fair: it takes only a little time
    to process the request, schedule a disk write, and yield to
    a fiber serving the next client.
</para>
<para>
    A stored procedure, however, can perform complex computations,
    or be written in such a way that control is not given away for a
    long time. This can lead to unfair scheduling, when a single
    client throttles the rest of the system, or to apparent stalls
    in request processing.
    Avoiding this situation is the responsibility of the stored procedure
    author. Most of the <code>box</code> calls, such as
    <code>box.insert()</code>, <code>box.update()</code>,
    <code>box.delete()</code> are yield points; <code>box.select()</code>
    and <code>box.select_range()</code>, however, are not.
</para>
<para>
    It should also be noted that, in absence of transactions,
    any yield in a stored procedure is a potential change in the
    database state. Effectively, it's only possible
    to have CAS (compare-and-swap) -like atomic stored
    procedures: i.e. procedures which select and then modify a record.

    Multiple data change requests always run through a built-in
    yield point.
</para>
<bridgehead renderas="sect4">Lack of field types</bridgehead>
<para>
   When invoking a stored procedure from the binary protocol,
   it's not possible to convey types of arguments. Tuples are
   type-agnostic. The conventional workaround is to use
   strings to pass all (textual and numeric) data.
</para>

</section>
</section>

<!--
vim: tw=66 syntax=docbk
vim: spell spelllang=en_us
-->
