<!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 defined and invoked interactively, 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 above example, the word <olink targetptr="lua-command"><emphasis>lua</emphasis></olink>
      is a signal to send the request, via the <olink targetptr="admin_port">administrative port</olink>,
      using the text protocol, for evaluation as a chunk of Lua code.
      The word <link linkend="utility-tarantool-call"><emphasis>call</emphasis></link>
      is a signal to send the request, via the <olink targetptr="primary_port">primary port</olink>,
      using the binary protocol, for execution of a previously-defined procedure. 
      (CALL is an SQL standard statement so its syntax
      was adopted by the Tarantool command-line client.)
    </para>
    <para>
      Thus, "<code>lua function f1() return 'hello' end</code>" sends over
      the administrative port as text, and causes definition of the procedure.
      Then "<code>call f1()</code>" uses the client-side SQL parser to convert
      to binary, sends over the primary port as binary, and causes execution of
      the procedure.
    </para>
    <para>
      Since it's possible to execute any Lua chunk via the
      administrative port, one can say <code language="Lua">lua f1()</code>
      to invoke the function, instead of <code>call f1()</code> ...
    <programlisting><computeroutput>localhost> <userinput>lua f1()</userinput>
---
 - hello
...
localhost> <userinput>lua 1 + 2</userinput>
---
 - 3
...
localhost> <userinput>lua 'hello' .. ' world' -- '..' means 'concatenate'</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"><filename>script_dir</filename></olink>.

      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 changes of the interpreter
      state, including global variable values, have immediate
      effect on all client connections.
    </para>
    <para>
      However, each connection uses its own Lua
      <emphasis>coroutine</emphasis> &mdash; a mechanism akin to a
      Tarantool <emphasis>fiber</emphasis>. A coroutine has its
      own execution stack and its own set of local variables and
      definitions, as described in the 
      <link xlink:href="http://www.lua.org/pil/6.1.html">
      <emphasis>closure</emphasis> section</link> of the Lua manual. 
    </para>
    <para>
      The interpreter environment is not restricted when
      <olink targetptr="init.lua"/> is loaded. But before the
      server starts accepting requests, it disables access to
      some of the standard Lua APIs for file I/O, process control,
      and module management. This prevents trivial security attacks.
    </para>
    <para>
      With 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:~<prompt>$</prompt> <userinput>cat arg.lua</userinput>
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:~<prompt>$</prompt> <userinput>tarantool</userinput>
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. Use of object-oriented
      syntax is possible on the administrative port 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>
      When a function in Lua terminates with an error, the error
      is sent to the client as <olink targetptr="ER_PROC_LUA" />
      return code, along with the original error message.
      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 f()error('!') end</userinput>
---
...
localhost> <userinput>call f()</userinput>
Call ERROR, Lua error: [string "function f()error('!') end"]:1: ! (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>

<variablelist>
 <title>Lua function <code>tonumber64</code></title>
    <varlistentry>
        <term xml:id="tonumber64" xreflabel="tonumber64"> <emphasis role="lua">tonumber64(<replaceable>value</replaceable>)</emphasis></term>
        <listitem>
            <para>
              Convert a string or a Lua number to a
              64-bit integer. The result can be used in arithmetic,
              and the arithmetic will be 64-bit integer arithmetic
              rather than floating-point arithmetic. (Operations on
              an unconverted Lua number use floating-point arithmetic.)
              The tonumber64() function is added by Tarantool; the name is global.
              <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>
localhost> <userinput>lua 123456789012345, tonumber64(123456789012345)</userinput>
---
 - 1.2345678901234e+14
 - 123456789012345
...
localhost> <userinput>lua i = tonumber64('1000000000')</userinput>
---
...
localhost> <userinput>lua type(i), i / 2, i - 2, i * 2, i + 2, i % 2, i ^ 2</userinput>
---
 - cdata
 - 500000000
 - 999999998
 - 2000000000
 - 1000000002
 - 0
 - 1000000000000000000
...
</programlisting>
            </para>
        </listitem>
    </varlistentry>
</variablelist>

<section xml:id="sp-box-library">
    <title>The <code>box</code> library</title>

    <para>
      As well as executing Lua chunks or defining their own functions,
      users can exploit the Tarantool server's storage functionality
      with the <code>box</code> Lua library.
    </para>

  <para>
  <bridgehead renderas="sect4">Packages of the box library</bridgehead>
  
    The contents of the <code>box</code> library can be inspected at runtime with
    <code>lua for k, v in pairs(box) do print(k, ': ', type(v)) end</code>.
    The packages inside the box library are: box, box.tuple, box.cjson, box.space, box.index, box.fiber,
    box.session, box.ipc, box.socket, box.net.box, box.cfg, box.info, box.slab, box.stat.
    Every package contains one or more Lua functions. A few packages contain members as well as functions.
    The functions allow data manipulation (insert delete update select replace),
    creating or resuming or interrupting fibers,
    introspection (inspecting contents of spaces, accessing server configuration),
    and sending or receiving data over a network.
    </para>

    <para>
      <table>
      <title xml:id="function-types">Possible types of the values that a function in the box library can return</title>
      <tgroup cols="4" align="left" colsep="1" rowsep="1">
      <thead>
      <row><entry>General type</entry>                   <entry>Specific type</entry><entry>What Lua type() would return</entry>                                         <entry>Example</entry></row>
      </thead>
      <tbody>
      <row><entry xml:id="function-type-number">scalar     </entry><entry>number</entry>      <entry><link xlink:href="http://www.lua.org/pil/2.3.html">"number"</link></entry>   <entry>12345</entry></row>
      <row><entry xml:id="function-type-string">scalar     </entry><entry>string</entry>      <entry><link xlink:href="http://www.lua.org/pil/2.4.html">"string"</link></entry>   <entry>'A B C'</entry></row>
      <row><entry xml:id="function-type-nil">scalar        </entry><entry>nil</entry>         <entry><link xlink:href="http://www.lua.org/pil/2.1.html">"nil"</link></entry>      <entry>nil</entry></row>
      <row><entry xml:id="function-type-lua-table">compound</entry><entry>Lua table</entry>   <entry><link xlink:href="http://www.lua.org/pil/2.5.html">"table"</link></entry>    <entry>table: 0x410f8b10</entry></row>
      <row><entry xml:id="function-type-tuple">compound    </entry><entry>tuple</entry>       <entry><link xlink:href="http://www.lua.org/pil/28.1.html">"Userdata"</link></entry><entry>12345: {'A B C'}</entry></row>
      </tbody>
      </tgroup>                                   
      </table>
      A tuple is returned in binary format (like <code>12345: {'A B C'}</code>) if
      the function is called via the administrative port; a tuple is returned in
      YAML format (like <code>[12345, 'A B C']</code>) if the function is called
      from the primary port; a few functions may return multiple tuples;
      for more tuple examples see <code xlink:href="#box.tuple">box.tuple</code>.
      A scalar may be converted to a tuple with only one field.
      A Lua table may contain all of a tuple's fields except the "key" (the primary-key fields).
    </para>
</section>

<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(<replaceable>request-code, request-string</replaceable>)</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> function is a low-level function, 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.
               </para>
               <para>
               Parameters: <code>request-code</code> &mdash; (type = 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>.
                    <code>request-string</code> &mdash; command
                    arguments packed in binary format.
                </para>
                <para>
                Returns: (type = <link xlink:href="#function-types">tuple</link>) zero or more tuples.
               </para>
               <para>
               Possible Errors: Any server error produced by the executed
                command.
            </para>
            <para>
                Please note that, since all the Lua data-manipulation functions
                enter the server 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 will fail.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua" xml:id="box.select" xreflabel="box.select">
                box.select(<replaceable>space-number, index-number, field-value [, field-value ...]</replaceable>)
            </emphasis>
        </term>
        <listitem>
            <para>
                Search for a tuple or tuples in the given space. A
                wrapper around <code>box.process()</code>.
            </para>
            <para>
                 Parameters: <code>space-number</code> &mdash; = space id,
                 <code>index-number</code> &mdash; = index number in the
                 space, to be used for matching,
                 <code>field-value(s)</code>&mdash;
                 = values to be matched against the index key, which may be multipart.
            </para>
            <para>
               Returns: (type = tuple) zero or more tuples.
            </para>
            <para>
               Possible Errors: 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#1', 'my first tuple')</userinput>
Call OK, 1 rows affected
['test#1', 'my first tuple']
localhost> <userinput>call box.select('0', '0', 'test#1')</userinput>
Call OK, 1 rows affected
['test#1', 'my first tuple']
localhost> <userinput>lua box.insert(5, 'test#2', 'first_name', 'last_name')</userinput>
---
 - 'test#2': {'first_name', 'last_name'}
...
localhost> <userinput>lua box.select(5, 1, 'first_name', 'last_name')</userinput>
---
 - 'test#2': {'first_name', 'last_name'}
...
</programlisting>
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua" xml:id="box.insert">box.insert(<replaceable>space-number, field-value [, field-value ...])</replaceable></emphasis>
        </term>
        <listitem>
	           <para>
	             Insert a tuple into a space. This function is a wrapper around <code>box.process()</code>.
            </para>
            <para>
              Parameters: <code>space-number</code>, <code> field-value(s)</code> = fields of the new tuple.
            </para>
            <para>
              Returns: (type = tuple) the inserted tuple.
            </para>
            <para>
              Possible errors: If a tuple with the same primary key already exists,
              <code>box.insert()</code> returns an error ER_TUPLE_FOUND.
            </para>
	       </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua" xml:id="box.select_limit" xreflabel="box.select_limit">
                box.select_limit(<replaceable>space-number, index-number, offset, limit, field-value [, field-value ...]</replaceable>)
            </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.
            </para>
            <para>
              Parameters: <code>space-number</code>, <code>index-number</code>,
              <code>offset</code> = where to start within a list of tuples, base 0, <code>limit</code> = maximum number to select,
              <code>field-value(s)</code> values to match against keys in the index.
            </para>
            <para>
               Returns: (type = tuple) zero or more tuples.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua" xml:id="box.replace">box.replace(<replaceable>space-number, field-value [, field-value ...]</replaceable>)</emphasis>
        </term>
        <listitem>
            <para>
                Insert a tuple into a space. 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>.
            </para>
            <para>
              Parameters: <code>space-number</code>, <code> field-value(s)</code> = fields of the new tuple.
            </para>
            <para>
            Returns: (type = tuple) the inserted tuple.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
         <emphasis role="lua" xml:id="box.update">box.update(<replaceable>space-number, key, format, {field_no, value}...</replaceable>)</emphasis>
        </term>
        <listitem>
            <para>
                Update a tuple.
               </para>
            <para>
             Parameters: <code>space-number</code>,
              <code>key</code> = primary-key field values, must be passed as a Lua table if key is multi-part,
                <code>format</code> = a sequence of
                pairs of characters, where the first character in each pair
                is the operation specifier, and the second character in
                each pair is the operation argument.
                The <code>{field_no, value}</code> arguments are the
                field numbers of affected fields and applicable values.
                For some operations the field number can be -1, meaning
                the last field in the tuple.
                There must be a pair of {field_no, value} arguments
                for each character pair in the format argument.
                The format and {field_no, value} arguments are passed to
                <code>box.pack()</code> and the result is sent
                to <code>box.process()</code>.
                Possible operation 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, <quote>!</quote> for insertion.
                Possible operation arguments are: <quote>p</quote>.
                Thus in the instruction <code>lua box.update(0,44,'+p=p',1,55,3,'x')</code>
                the space number is 0, the primary-key value is 44,
                the format is '+p=p' meaning "add a value to a field
                and then assign a value to a field", the first affected field
                is field 1 and the value which will be added to it is 55, the second affected field
                is field 3 and the value which will be assigned to it is 'x'.
               </para>
               <para>
               Returns: (type = tuple) the updated tuple.
              </para>
              <para>
                <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 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(<replaceable>space-number, field-value [, field-value ...]</replaceable>)</emphasis>
        </term>
        <listitem>
            <para>
              Delete a tuple identified by a primary key.
            </para>
            <para>
              Parameters: <code>space-number</code>, <code>field-value(s)</code> = values to match against keys in the primary index.
            </para>
            <para>
              Returns: (type = tuple) the deleted tuple.
            <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>
localhost> <userinput>call box.delete('0', 'test#1')</userinput>
Call OK, 1 rows affected
['test', 'my first tuple']
localhost> <userinput>call box.delete('0', 'test#1')</userinput>
Call OK, 0 rows affected
localhost> <userinput>call box.delete('0', 44)</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(<replaceable>space-number, index-number, limit, [, field-value ...]</replaceable>)
            </emphasis>
        </term>
        <listitem>
            <para>
              Select a limited range of tuples, starting with the tuple
              specified by <code>field-value(s)</code>.
              This is a simple wrapper around <code xlink:href="#box.space.select_range">box.space[space-number]:select_range(index-number, ...)</code>.
            </para>
            <para>
              Parameters: <code>space-number</code>,
              <code>index-number</code>,
              <code>limit</code> = maximum number to select,
              <code>field-value(s)</code> values to match against keys in the specified index.
            </para>
            <para>
              Returns: (type = tuple) 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.
            </para>
            <para>
              Possible errors:
              For BITSET indexes, box.select_range() does not work.
            </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(<replaceable>space-number, index-number, limit, field-value [, field-value ...]</replaceable>)
            </emphasis>
        </term>
        <listitem>
            <para>
              Select a reverse (descending-order) limited range of tuples, starting with the tuple
              specified by <code>field-value(s)</code>.
              This is a simple wrapper around <code xlink:href="#box.space.select_range">box.space[space-number]:select_range(index-number, ...)</code>.
            </para>
            <para>Parameters: <code>space-number</code>,
              <code>index-number</code>,
              <code>limit</code> = maximum number to select,
              <code>field-value(s)</code> values to match against keys in the specified index.
            </para>
            <para>
              Returns: For TREE indexes, this returns tuples in descending sorted order.
              If <code>key</code> is <code>nil</code> or unspecified,
              the selection starts from the end of the index.
              For other index types this call is not supported.
            <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(<replaceable>format, argument [, argument ...]</replaceable>)</emphasis></term>
        <listitem><para>
            To use Tarantool binary protocol primitives from Lua,
            it's necessary to convert Lua variables to binary
            format. The box.pack() helper function is prototyped after Perl
            <link xlink:href="http://perldoc.perl.org/functions/pack.html">
             'pack'</link>.
            </para>
            <para>
               Parameters: <code>format</code> = string containing format specifiers, <code>argument(s)</code> = scalar values to be formatted.
            </para>
            <para>
            <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>
            </para>
            <para>
              Returns: a binary string containing all arguments, packed
              according to the format specifiers.
            </para>
            <para>
              Possible Errors: Unknown format specifier.
            </para>
            <para>
        <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(<replaceable>format, binary-string</replaceable>)</emphasis></term>
        <listitem>
            <para>
              Counterpart to <code>box.pack()</code>.
            </para>
            <para>
              Parameters: <code>format</code>, <code>binary-string</code>.
            </para>
            <para>
             Returns: (type = scalar) A list of strings or numbers.
            </para>
            <para>
            <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>localhost> <userinput>setopt delimiter='!' #this means following commands must end with '!'</userinput>
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('bsi', box.pack('bsi', 255, 65535, 4294967295))!</userinput>
---
 - 255
 - 65535
 - 4294967295
...
localhost> <userinput>lua box.unpack('ls', box.pack('ls',</userinput>
         > <userinput>    tonumber64('18446744073709551615'), 65535))!</userinput>
---
 - 18446744073709551615
 - 65535
...
localhost> <userinput>lua num, str, num64 = box.unpack('ppp', box.pack('ppp', 666, </userinput>
         > <userinput>    '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
localhost> <userinput>setopt delimiter=''  #back to normal: commands end with line feed!</userinput>
</programlisting>
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua">box.dostring(<replaceable>lua-chunk-string [, lua-chunk-string-argument ...]</replaceable>)</emphasis>
        </term>
        <listitem>
            <para>
              Parse and execute an arbitrary chunk of Lua code.
              This function is mainly useful to define and run
              Lua code without having to
              introduce changes to the global Lua environment.
            </para>
            <para>
              Parameters: <code>lua-chunk-string</code> = string containing Lua code,
              <code>lua-chunk-string-argument(s)</code> = zero or more scalar values
               which will be appended to, or substitute for, items in the Lua chunk.
             </para>
             <para>
               Returns: whatever is returned by the Lua code chunk.
            </para>
            <para>
               Possible errors: If there is a compilation error,
               it is raised as a Lua error.
            </para>
            <para>
            <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>setopt delimiter='!' #<link linkend="utility-tarantool-setopt">this</link> means ignore line feeds until next '!'</userinput>
localhost&gt; <userinput>lua box.dostring('local f = function(key)</userinput>
        -&gt; <userinput>                  t = box.select(0, 0, key);</userinput>
        -&gt; <userinput>                  if t ~= nil then return t[0] else return nil end</userinput>
        -&gt; <userinput>                  end</userinput>
        -&gt; <userinput>                  return f(...)', 0)!</userinput>
---
 - nil
...
localhost&gt; <userinput>setopt delimiter=''!</userinput>
</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 microseconds since the epoch) 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>
                Possible errors: The server tries to load the <emphasis>libuuid</emphasis> library
                when it starts. If the library is not available, which can happen if it was not
                found when the server was built from source, then box.uuid() 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(<replaceable>errcode-number, errtext-string</replaceable>)</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 the file <link xlink:href="https://github.com/tarantool/tarantool/blob/master/include/errcode.h"><filename>errcode.h</filename></link>
                in the source tree.
                Lua constants which correspond to Tarantool errors
                are defined in the <code>box.error</code> module. The error
                message can be arbitrary.
                Lua procedures can use <code>box.raise()</code> to emulate
                request errors (for example: unique key exception).
            </para>
            <para>
              Parameters: <code>errcode-number</code> = number taken from the complete list of errors,
              <code>errtext-string</code> = the message which will accompany the error.
            </para>
            <para>
              Possible errors: whatever is specified in errcode-number.
            </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(<replaceable>space-number [, field-value ...]</replaceable>)</emphasis>
        </term>
        <listitem>
            <para>
                Insert a new tuple using an auto-increment primary key.
                The space specified by space-number must have a
                NUM or NUM64 primary key index of type TREE.
                The primary-key field will be incremented before the insert.
            </para>
            <para>
               Parameters: <code>space-number</code>, <code>field-value(s)</code> = values for the tuple's fields,
               other than the primary-key field.
            </para>
            <para>
               Returns: (type = tuple) the inserted tuple.
            </para>
            <para>
               Possible errors: index has wrong type or primary-key indexed field is not a number.
            </para>
            <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>localhost> <userinput>lua box.auto_increment(0, 'Fld#1', 'Fld#2')</userinput>
---
 - 1: {'Fld#1', 'Fld#2'}
...
localhost> <userinput>lua box.auto_increment(0, 'Fld#3')</userinput>
---
 - 2: {'Fld#3'}
...
</programlisting>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term>
            <emphasis role="lua">box.counter.inc(<replaceable>space-number, field-value [, field-value ...]</replaceable>)</emphasis>
        </term>
        <listitem>
            <para>
                Increments a counter in a tuple whose primary key matches the field-value(s).
                The field following the primary-key fields will be the counter.
                If there is no tuple matching the field-value(s), a new one is inserted
                with initial counter value set to 1.
            </para>
                <para>Parameters: <code>space-number</code>, <code>field-value(s)</code> = values
                which must match the primary key.
            </para>
            <para>
               Returns: (type = number) 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(<replaceable>space-number, field-value [, field-value ...]</replaceable>)</emphasis>
        </term>
        <listitem>
            <para>
                Decrements a counter in a tuple whose primary key matches the field-value(s).
                The field following the primary-key fields will be the counter.
                If there is no tuple matching the field-value(s), a new one is not inserted.
                If the counter value drops to zero, the tuple is deleted.
            </para>
            <para>
               Parameters: <code>space-number</code>, <code>field-value(s)</code> = values
               which must match the primary key.
            </para>
            <para>
              Returns: (type = number) the new counter value.
            </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>

<bridgehead renderas="sect4">Example showing use of the box functions</bridgehead>
<para>
This example will work with the sandbox configuration described in the preface. That is, there is a space[0] with a numeric primary key.
The example function will: (1) select the tuple whose key value is 1000;
(2) return an error if the tuple already exists and already has 3 fields;
(3) Insert or replace the tuple with: field[0] = 1000, field[1] = a uuid, field[2] = number of seconds since 1970-01-01;
(4) Get field[2] from what was replaced;
(5) Format the value from field[2] as yyyy-mm-dd hh:mm:ss.ffff;
(6) Return the formatted value.
The function uses Tarantool box functions box.replace(), box.time(), box.select_limit(), box_uuid_hex().
The function uses Lua functions
<link xlink:href="http://www.lua.org/pil/22.1.html">os.date()</link>
and <link xlink:href="http://www.lua.org/pil/20.html">string.sub()</link>.
</para>
<programlisting>
setopt delimiter='!'
lua function example()
  local a, b, c, selected_tuple, replaced_tuple, time_field
  selected_tuple = box.select_limit(0, 0, 0, 1, 1000)
  if selected_tuple ~= nil then
    if #selected_tuple == 3 then
      box.raise(1,'This tuple already has 3 fields')
    end
  end
  replaced_tuple = box.replace(0, 1000,  box.uuid_hex(), tostring(box.time()))
  time_field = tonumber(replaced_tuple[2])
  formatted_time_field = os.date("%Y-%m-%d %H:%M:%S", time_field)
  c = time_field % 1
  d = string.sub(c, 3, 6)
  formatted_time_field = formatted_time_field .. '.' .. d
  return formatted_time_field
end!
setopt delimiter=''!
</programlisting>
<para>
... And here is what happens when one invokes the function:
<programlisting>
<prompt>localhost&gt;</prompt> <userinput>lua box.delete(0, 1000)</userinput>
---
 - 1000: {'264ee2da03634f24972be76c43808254', '1391037015.6809'}
...
<prompt>localhost&gt;</prompt> <userinput>lua example(1001)</userinput>
---
 - 2014-01-29 16:11:51.1582
...
<prompt>localhost&gt;</prompt> <userinput>lua example(1001)</userinput>
---
error: 'This tuple already has 3 fields'
...
</programlisting>
</para>

</section>

<section xml:id="sp-box-tuple">
    <title>Package <code>box.tuple</code></title>
<variablelist xml:id="box.tuple" xreflabel="box.tuple">
    <para>The <code>box.tuple</code> 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(<replaceable>scalar-value | Lua-table-value</replaceable>)</emphasis>
        </term>
        <listitem>
            <para>
                Construct a new tuple from either a scalar or a Lua table.
                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.
            </para>
            <para>
               Parameters: <code>scalar-value | Lua-table-value</code> = the value that will become the tuple contents.
            </para>
            <para>
              Returns: (type = tuple) a new tuple.
            </para>
            <para>
              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"># <replaceable>tuple-value</replaceable></emphasis>
        </term>
        <listitem>
            <para>
                The # operator in Lua means "return count of components".
                So, if t is a tuple instance, <code>#t</code>
                will return the number of
                 fields.
            </para>
            <para>
               Returns: (type = number) number of fields.
            </para>
            <para>
                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({'Fld#1','Fld#2','Fld#3','Fld#4'})</userinput>
---
...
localhost&gt; <userinput>lua #t</userinput>
---
 - 4
...</programlisting>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term>
            <emphasis role="lua"> <replaceable>tuple-value</replaceable> : 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.
            </para>
            <para>
              Returns: (type = number) number of bytes.
            </para>
            <para>
              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">[ <replaceable>field-number</replaceable> ]</emphasis>
        </term>
        <listitem>
            <para>
                If t is a tuple instance, <code>t[<replaceable>field-number</replaceable>]</code>
                will return the field numbered <code>field-number</code> in the tuple.
                 The first field is t[0].
            </para>
            <para>
              Returns: (type = scalar) field value.
            </para>                
            <para>
              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({'Fld#1','Fld#2','Fld#3','Fld#4'})</userinput>
---
...
localhost&gt; <userinput>lua t[1]</userinput>
---
 - Fld#2
...</programlisting>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua">find(<replaceable>[field-number,] field-value) or findall([field-number,] field-value</replaceable>)</emphasis>
        </term>
        <listitem>
            <para>
              If t is a tuple instance, <code>t:find(<replaceable>field-value</replaceable>)</code>
              will return the number of the first field in t that matches the field value), and
              <code>t:findall(<replaceable>field-value [, field-value ...]</replaceable>)</code>
              will return numbers of all fields in t that match the field value. Optionally
              one can put a numeric argument field-number before the search-value to indicate
              <quote>start searching at field number <code>field-number</code>.</quote>
            </para>
            <para>
              Returns: (type = number) the number of the field in the tuple.
            </para>
            <para>
              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(<replaceable>start-field-number, fields-to-remove [, field-value ...]</replaceable>)</emphasis>
        </term>
        <listitem>
            <para>
              If t is a tuple instance, <code>t:transform(<replaceable>start-field-number</replaceable>,<replaceable>fields-to-remove</replaceable>)</code>
              will return a tuple where, starting from field start-field-number, a number of fields (fields-to-remove) are removed.
              Optionally one can add more arguments after fields-to-remove to indicate new values that will replace
              what was removed.
            </para>
            <para>
              Parameters: <code>start-field-number</code> = base 0, may be negative, <code>fields-to-remove</code>, <code>field-values(s)</code>.
            </para>
            <para>
              Returns: (type = tuple) a new tuple.
            </para>
            <para>
              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({'Fld#1','Fld#2','Fld#3','Fld#4','Fld#5'})
---
...
localhost&gt; <userinput>lua t:transform(1,2,'x')</userinput>
---
 - 'Fld#1': {'x', 'Fld#4', 'Fld#5'}
...</programlisting>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua">slice(<replaceable>start-field-number [, end-field-number]</replaceable>)</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 all 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>
            <para>
              Parameters: <code>start-field-number</code> = base 0, may be negative, <code>end-field-number</code> = optional, base 0, negative treated as positive.
            </para>
            <para>
              Returns: (type = scalar) one or more field values.
            </para>
            <bridgehead renderas="sect4">Example</bridgehead>
            <programlisting>localhost&gt; <userinput>lua t = box.tuple.new({'Fld#1','Fld#2','Fld#3','Fld#4','Fld#5'})</userinput>
---
...
localhost&gt; <userinput>lua t:slice(1, 3)</userinput>
---
 - Fld#2
 - Fld#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>.
            </para>
            <para>
              Returns: (type = scalar) field(s) from the tuple.
            </para>
            <para>
              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({'Fld#1','Fld#2','Fld#3','Fld#4','Fld#5'})</userinput>
---
...
localhost&gt; <userinput>lua t:unpack()</userinput>
---
 - Fld#1
 - Fld#2
 - Fld#3
 - Fld#4
 - Fld#5
...</programlisting>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term>
            <emphasis role="lua">pairs()</emphasis>
        </term>
        <listitem>
            <para>
              In Lua, lua-table-value:pairs() is a method which returns: function, lua-table-value, nil.
              Tarantool has extended this so that tuple-value:pairs() returns: function, tuple-value, nil.
              It is useful for Lua iterators, because Lua iterators traverse
              a value's components until an end marker is reached.
            </para>
            <para>
              Returns: (type = function) function, (type = tuple) tuple-value, (type = nil) nil.
            </para>
            <para>
              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; <userinput>lua t = box.tuple.new({'Fld#1','Fld#2','Fld#3','Fld#4','Fld#5'})</userinput>
---
...
localhost&gt; <userinput>lua for k, v in t:pairs() do print(v) end</userinput>
---
Fld#1
Fld#2
Fld#3
Fld#4
Fld#5
...</programlisting>
        </listitem>
    </varlistentry>

</variablelist>

<bridgehead renderas="sect4">Example showing use of the box.tuple functions</bridgehead>
<para>
This function will illustrate how to convert tuples to/from
Lua tables and lists of scalars:
<programlisting>
  scalars to tuple:     tuple = box.tuple.new({scalar1, scalar2, ... scalar_n})
  tuple to Lua table:   lua_table = {tuple:unpack()}
  tuple to scalars:     scalar1, scalar2, ... scalar_n = tuple:unpack()
  Lua table to tuple:   tuple = box.tuple.new(lua_table)
</programlisting>
Then it will find the field that contains 'b',
remove that field from the tuple,
and display how many bytes remain in the tuple.
The function uses Tarantool box.tuple functions new(), unpack(), find(), transform(), bsize().
</para>
<programlisting>
setopt delimiter='!'
lua function example()
  local tuple1, tuple2, lua_table_1, scalar1, scalar2, scalar3, field_number
  tuple1 = box.tuple.new({'a', 'b', 'c'})
  luatable1 = {tuple1:unpack()}
  scalar1, scalar2, scalar3 = tuple1:unpack()
  tuple2 = box.tuple.new(luatable1)
  field_number = tuple2:find('b')
  tuple2 = tuple2:transform(field_number, 1)
  print('tuple2 = ',tuple2, ' # of bytes = ', tuple2:bsize())
end!
setopt delimiter=''!
</programlisting>
<para>
... And here is what happens when one invokes the function:
<programlisting>
<prompt>localhost&gt;</prompt> <userinput>lua example()</userinput>
---
tuple2 = 'a': {'c'} # of bytes = 4
...
</programlisting>
</para>

</section>

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

<variablelist xml:id="box.cjson" xreflabel="box.cjson">
    <para>
        The <code>box.cjson</code> package provides JSON manipulation routines.
        It is 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(<replaceable>scalar-value | Lua-table-value</replaceable>)</emphasis></term>
        <listitem>
            <para>
              Convert a Lua object to a JSON string.
            </para>
            <para>
              Parameters: either a scalar value or a Lua table value.
            </para>
            <para>
              Returns: (type = string) the original value reformatted as 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(<replaceable>string-value</replaceable>)</emphasis></term>
        <listitem>
            <para>
              Convert a JSON string to a Lua object.
            </para>
            <para>
              Parameters: <code>string-value</code> = a string formatted as JSON.
            </para>
            <para>
              Returns: (type = Lua table) the original contents formatted as a Lua table.
            </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>
      The <code>box.space</code> package 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">box.space[<replaceable>space-number</replaceable>].n</emphasis></term>
        <listitem>
            <para>
              (type = number) Ordinal space number, <code>box.space[i].n == i</code>.
            </para>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term><emphasis role="lua">box.space[<replaceable>space-number</replaceable>].enabled</emphasis></term>
        <listitem>
            <para>
              (type = boolean) Whether or not this space is enabled in the
              configuration file.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua">box.space[<replaceable>space-number</replaceable>].cardinality</emphasis>
        </term>
        <listitem>
            <para>
             (type = number) The required field count for all tuples in this space.
             The cardinality can be set in <olink targetptr="space">the configuration file</olink>.
             The default value is 0, which means there is no required field count.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua">box.space[<replaceable>space-number</replaceable>].index[]</emphasis>
        </term>
        <listitem>
            <para>
              (type = table) 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].cardinality,box.space[0].index[0].type</userinput>
---
 - 0
 - 0
 - HASH
...
</programlisting>
            </para>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term>
            <emphasis role="lua">box.space[<replaceable>space-number</replaceable>]:select(<replaceable>index-number, field-value [, field-value ...]</replaceable>)</emphasis>
        </term>
        <listitem>
            <para>
              <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>.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua" xml:id="box.space.select_range" xreflabel="box.space[i].select_range()">
            box.space[<replaceable>space-number</replaceable>]:select_range(<replaceable>index-number, limit, field-value [, field-value ...]</replaceable>)
            </emphasis>
        </term>
        <listitem>
            <para>
              <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>.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua"
            xml:id="box.space.select_reverse_range"
            xreflabel="box.space.select_reverse_range">
            box.space[<replaceable>space-number</replaceable>]:select_reverse_range(<replaceable>limit, field-value [, field-value ...]</replaceable>)</emphasis>
        </term>
        <listitem>
            <para>
              <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>.
            </para>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term>
            <emphasis role="lua">box.space[<replaceable>space-number</replaceable>]:insert(<replaceable>field-value [, field-value ...]</replaceable>)</emphasis>
        </term>
        <listitem>
            <para>
              <code>lua box.space[<replaceable>space-number</replaceable>]:insert(<replaceable>field-value ...</replaceable>)</code>
              is the object-oriented equivalent of
              <code xlink:href="#box.insert">box.insert(<replaceable>space-number</replaceable>,<replaceable>field-value ...</replaceable>)</code>.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua">box.space[<replaceable>space-number</replaceable>]:replace(<replaceable>field-value [, field-value ...]</replaceable>)</emphasis>
        </term>
        <listitem>
            <para>
              <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>field-value ...</replaceable>)</code>.
            </para>
        </listitem>
    </varlistentry>

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

    <varlistentry>
        <term>
            <emphasis role="lua">box.space[<replaceable>space-number</replaceable>]:update(<replaceable>field-value [, field-value ...], format, {field_no, value}...</replaceable>)</emphasis>
        </term>
        <listitem>
            <para>
              <code>lua box.space[<replaceable>space-number</replaceable>]:update(<replaceable>field-value ...</replaceable>)</code>
              is the object-oriented equivalent of
              <code xlink:href="#box.update">box.update(<replaceable>space-number</replaceable>,<replaceable>field-value ...</replaceable>)</code>.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua">box.space[<replaceable>space-number</replaceable>]:len()</emphasis>
        </term>
        <listitem>
            <para>
              Returns: (type = number) 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">box.space[<replaceable>space-number</replaceable>]:truncate()</emphasis>
        </term>
        <listitem>
            <para>
              Deletes all tuples.
            </para>
            <para>
               Returns: nil.
            </para>
            <para>
            <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">box.space[<replaceable>space-number</replaceable>]:pairs()</emphasis>
        </term>
        <listitem>
            <para>
              A helper function to prepare for iterating over all tuples in a space.
            </para>
            <para>
              Returns: (type = function) function which can be used in a for/end loop.
              Within the loop, a value (type = tuple) is returned for each iteration.
            </para>
            <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>

<bridgehead renderas="sect4">Example showing use of the box.space functions</bridgehead>
<para>
This function will illustrate how to look at all the spaces,
and for each display: whether the space is enabled, approximately
how many tuples it contains, and the contents of its first two tuples.
Warning: the way to traverse spaces will change in the next
version of Tarantool.
The function uses Tarantool box.space functions len() and pairs().
The iteration through the spaces is coded as an infinite loop,
but no worries -- it will be halted with an error message when
the space number becomes greater than the maximum.
</para>
<programlisting>
setopt delimiter='!'
lua function example()
  local space_number, tuple_number, tuple_count
  space_number = 0
  while 0 == 0 do
    tuple_count = box.space[space_number]:len()
    print('space_number ',space_number)
    print('  enabled = ', box.space[space_number].enabled)
    print('  approximate number of tuples  = ', tuple_count)
    tuple_number = 1
    for k, v in box.space[space_number]:pairs() do
      print('    tuple#',tuple_number,' = ',v)
      tuple_number = tuple_number + 1
      if tuple_number &gt; 2 then break end
    end
    space_number = space_number + 1
  end
end!
setopt delimiter=''!
</programlisting>
<para>
... And here is what happens when one invokes the function:
<programlisting>
<prompt>localhost&gt;</prompt> <userinput>lua example()</userinput>
---
space_number 0
  enabled = true
  approximate number of tuples  = 4
    tuple#1 = 0: {0, 1390945890}
    tuple#2 = 1: {1, 'b'}
space_number 1
  enabled = true
  approximate number of tuples  = 4
    tuple#1 = 0: {0, 1390945890}
    tuple#2 = 1: {1, 'b'}
error: '[string "function example()   local space_number, tupl..."]:1:
       attempt to index a nil value'
...
</programlisting>
</para>

</section>

<section xml:id="sp-box-index">
    <title>Package <code >box.index</code></title>
<variablelist xml:id="box.index" xreflabel="box.index">
            <para>
              The <code>box.index</code> package provides read-only access for index definitions and index keys.
              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 of type <code>box.index</code> in the
              storage engine.
            </para>
    <varlistentry>
        <term><emphasis role="lua">box.space[<replaceable>space-number</replaceable>].index[<replaceable>index-number</replaceable>].unique</emphasis></term>
        <listitem>
            <para>
              (type = boolean) true if the index is unique.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua">box.space[<replaceable>space-number</replaceable>].index[<replaceable>index-number</replaceable>].type</emphasis>
        </term>
        <listitem>
            <para>
              (type = string) index type,  'TREE' or 'HASH' or 'BITSET'.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua">box.space[<replaceable>space-number</replaceable>].index[<replaceable>index-number</replaceable>].key_field[]</emphasis>
        </term>
        <listitem>
            <para>
              An array describing index key fields.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua">box.space[<replaceable>space-number</replaceable>].index[<replaceable>index-number</replaceable>].idx</emphasis>
        </term>
        <listitem>
            <para>
              A group of methods including max(), min(), count(), random(), next(),
              next_equal(), prev(), prev_equal(). For each case there is an alternative syntax,
              and use of the alternative syntax is recommended.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term></term>
        <listitem><bridgehead renderas="sect4">Example</bridgehead>
<programlisting>localhost&gt; <userinput>lua box.space[0].index[0].unique, box.space[0].index[0].type</userinput>
---
 - true
 - HASH
...
localhost&gt; <userinput>lua box.space[0].index[0].key_field[0], box.space[0].index[0].idx</userinput>
---
 - table: 0x41d03518
 - index 0 in space 0
...

localhost&gt; <userinput>lua box.space[0].index[0].idx:max()</userinput>
---
 - 999: {2, 'c'}
...</programlisting></listitem>
    </varlistentry>

    <varlistentry>
        <term>
             <emphasis role="lua" xml:id="box.index.iterator" xreflabel="box.index.iterator(type, ...)">
            box.space[<replaceable>space-number</replaceable>].index[<replaceable>index-number</replaceable>]:iterator(<replaceable>iterator-type, bitset-value | field-value...</replaceable>)</emphasis>
        </term>
        <listitem>
            <para>
                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.
            </para>
            <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>
                Parameters:
                <code>type</code> &mdash; iteration strategy as defined in tables below.
            </para>
            <para>
               Returns: this method returns an iterator closure, i.e.
                    a <code>function</code> which can be used to
                    get the next value on each invocation.
            </para>
            <para>
               Possible Errors:
                    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);</userinput>
---
...
localhost> <userinput>lua 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);</userinput>
---
...
localhost> <userinput>lua print(it(), ' ', it(), ' ', it());</userinput>
---
3: {1, 2} nil nil
...
localhost> <userinput>lua it = box.space[0].index[1]:iterator(box.index.GE, 2, 1);</userinput>
---
...
localhost> <userinput>lua print(it(), ' ', it(), ' ', it());</userinput>
---
5: {2, 1} 6: {2, 2} nil
...
localhost> <userinput>lua v = box.space[0].index[1]:iterator(box.index.ALL)</userinput>
---
...
localhost> <userinput>lua for v in v 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">box.space[<replaceable>space-number</replaceable>].index[<replaceable>index-number</replaceable>]:min()</emphasis>
        </term>
        <listitem>
            <para>
              Find the minimum value in the specified index.
            </para>
            <para>
              Returns: (type = tuple) the tuple for the first key in the index.
            </para>
            <para>
              Possible errors: index is not of type 'TREE'.
            </para>
            <para>
            <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">box.space[<replaceable>space-number</replaceable>].index[<replaceable>index-number</replaceable>]:max()</emphasis>
        </term>
        <listitem>
            <para>
              Find the maximum value in the specified index.
            </para>
            <para>
              Returns: (type = tuple) the tuple for the last key in the index.
            </para>
            <para>
              Possible errors: index is not of type 'TREE'.
            </para>
            <para>
            <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">box.space[<replaceable>space-number</replaceable>].index[<replaceable>index-number</replaceable>]:random(<replaceable>random-value</replaceable>)</emphasis>
        </term>
        <listitem>
            <para>
              Find a random value in the specified index.
              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.
            </para>
            <para>
              Parameters: <code>random-number</code> = an arbitrary non-negative integer.
            </para>
            <para>
              Returns: (type = tuple) the tuple for the random key in the index.
            </para>
            <para>
            <bridgehead renderas="sect4">Example</bridgehead>
<programlisting>localhost&gt; <userinput>lua box.space[0].index[0]:random(1)</userinput>
---
 - 'Beta!': {66, 'This is the second tuple!'}
...
</programlisting>
        </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua">box.space[<replaceable>space-number</replaceable>].index[<replaceable>index-number</replaceable>]:count(<replaceable>key-value</replaceable>)</emphasis>
        </term>
        <listitem>
            <para>
              Iterate over an index, counting the number of tuples which equal the
              provided search criteria.
            </para>
            <para>
              Parameters: <code>key-value</code> = the value which must match the key(s)
              in the specified index. The type may be a list of field-values, or a tuple containg
              only the field-values.
            </para>
            <para>
              Returns: (type = number) the number of matching index keys.
            </para>
            <para>
            <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>
      The <code>box.fiber</code> package allows for creating, running and managing <emphasis>fibers</emphasis>.
    </para>
    <para>
      A fiber is a set of instructions which are executed
      with cooperative multitasking. Fibers managed by the
      box.fiber package are associated with a user-supplied function
      called the <emphasis>fiber function</emphasis>.

      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 yields control with <code>box.fiber.yield()</code>, it is suspended.
      When a fiber ends (because the fiber function ends), 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
      the Tarantool internal <quote>sched</quote> fiber, and gets
      scheduled only if there is a libev event associated
      with it.
      To detach, a running fiber should invoke <code>box.fiber.wrap()</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>
      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> does not.
      In practice, a runaway fiber can only become unresponsive
      if it does many computations and does not 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 (now called a fiber carcass) to the fiber pool.
      The carcass can be reused when another fiber is created.
    </para>
<variablelist xml:id="box.fiber">
    <varlistentry>
        <term>
            <emphasis role="lua" xml:id="box.fiber.id">box.fiber.id(<replaceable>fiber</replaceable>) </emphasis>
        </term>
        <listitem>
            <para>
              Returns: (type = number) id of the fiber.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua" xml:id="box.fiber.self">box.fiber.self() </emphasis>
        </term>
        <listitem>
            <para>
              Returns: (type = userdata) <code>box.fiber</code>
              object for the currently scheduled fiber.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua" xml:id="box.fiber.find">box.fiber.find(<replaceable>id</replaceable>) </emphasis>
        </term>
        <listitem>
            <para>
              Locate a fiber userdata object by id.
            </para>
            <para>
              Returns: (type = userdata) box.fiber object for the specified fiber.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua" xml:id="box.fiber.create">box.fiber.create(<replaceable>function-name</replaceable>) </emphasis>
        </term>
        <listitem>
            <para>
              Create a fiber.
            </para>
            <para>
              Parameters: <code>function-name</code> = the function that the fiber is associated with.
            </para>
            <para>
              Returns: (type = userdata) the box.fiber object of the new fiber.
            </para>
            <para>
              Possible errors: the function does not exist or if a recursion limit is hit.
            </para>
        </listitem>
    </varlistentry>

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

    <varlistentry>
        <term>
         <emphasis role="lua" xml:id="box.fiber.yield" xreflabel="box.fiber.yield">box.fiber.yield(<replaceable>yield-arguments</replaceable>) </emphasis>
        </term>
        <listitem>
            <para>
              If the fiber is attached, yield control to the calling fiber if the fiber
              is attached; otherwise, yield to sched.
            </para>
            <para>
              Parameters: <code>yield-arguments</code>:  
              If the fiber is attached, arguments passed
              to box.fiber.yield are passed on to the calling fiber.
              If the fiber is detached, <code>box.fiber.yield()</code>
              arguments passed to box.fiber.yield are returned 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>
            <para>
              Detach the current fiber. This is a cancellation point. This is a yield point.
              It is usually more convenient to use <code>box.fiber.wrap()</code> for detaching.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua" xml:id="box.fiber.wrap">box.fiber.wrap(<replaceable>function, function-arguments</replaceable>)</emphasis>
        </term>
        <listitem>
            <para>
              This is a quick way to create and start a detached
              fiber. The fiber is
              created, detached, and resumed immediately.
            </para>
            <para>
              Parameters: <code>function</code> = the function to be associated with the fiber,
              <code>function-arguments</code> = what will be passed to the function.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua" xml:id="box.fiber.sleep">box.fiber.sleep(<replaceable>time</replaceable>)</emphasis>
        </term>
        <listitem>
            <para>
              Yield to the sched fiber and sleep for the specified number of seconds.
              Only the current fiber can be made to sleep.
            </para>
            <para>
              Parameters: <code>time</code> = number of seconds to sleep.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua" xml:id="box.fiber.status">box.fiber.status(<replaceable>[fiber]</replaceable>)</emphasis>
        </term>
        <listitem>
            <para>
              Return the status of the specified fiber.
            </para>
            <para>
              Parameters: <code>fiber></code> = the fiber to be checked -- if this is not
              supplied, then the current fiber is to be checked.
            </para>
            <para>
              Returns: (type = string) the status of <code>fiber</code>.
              One of: <quote>dead</quote>,
              <quote>suspended</quote>, <quote>attached</quote>
              or <quote>running</quote>.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua" xml:id="box.fiber.cancel">box.fiber.cancel(<replaceable>fiber</replaceable>)</emphasis>
        </term>
        <listitem>
            <para>
              Cancel a <code>fiber</code>.
              Running and suspended fibers can be canceled.
            </para>
            <para>
              Parameters: <code>fiber</code> = the fiber to be canceled.
            </para>
            <para>
              Possible errors: the specified fiber does not permit cancel.
            </para>
        </listitem>
    </varlistentry>

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

<para>
<bridgehead renderas="sect4">Example</bridgehead>
Make the function which will be associated with the fiber.
This function contains an infinite loop
("while 0 == 0" is always true).
Each iteration of the loop adds 1 to a global variable
named gvar, then goes to sleep for 2 seconds.
The sleep causes an implicit box.fiber.yield().<programlisting>
<prompt>localhost&gt;</prompt><userinput> setopt delimiter = '!'</userinput>
<prompt>localhost&gt;</prompt><userinput> lua function function_x()</userinput>
<prompt>        -&gt;</prompt><userinput>   gvar = 0</userinput>
<prompt>        -&gt;</prompt><userinput>   while 0 == 0 do</userinput>
<prompt>        -&gt;</prompt><userinput>     gvar = gvar + 1</userinput>
<prompt>        -&gt;</prompt><userinput>     box.fiber.sleep(2)</userinput>
<prompt>        -&gt;</prompt><userinput>     end</userinput>
<prompt>        -&gt;</prompt><userinput>   end!</userinput>
---
...
<prompt>localhost&gt;</prompt><userinput> setopt delimiter = ''!</userinput></programlisting>
Make a fiber, associate function_x with the fiber,
and start function_x. It will immediately "detach"
so it will be running independently of the caller.
<programlisting>
<prompt>localhost&gt;</prompt><userinput> lua fiber_of_x = box.fiber.wrap(function_x)</userinput>
---
...</programlisting>

Get the id of the fiber (fid), to be used in later displays.<programlisting>
<prompt>localhost&gt;</prompt><userinput> lua fid = box.fiber.wrap(function_x)</userinput>
---
...
</programlisting>
Pause for a while, while the detached function runs. Then ...
Display the fiber id, the fiber status, and gvar  (gvar will have
gone up a bit depending how long the pause lasted). The status is
suspended because the fiber spends almost all its time sleeping or yielding.<programlisting>
<prompt>localhost&gt;</prompt><userinput> lua print('#',fid,'. ',box.fiber.status(fiber_of_x),'. gvar=',gvar)</userinput>
---
fiber=104. suspended. gvar=9
...</programlisting>
Pause for a while, while the detached function runs. Then ...
Cancel the fiber. Then, once again ...
Display the fiber id, the fiber status, and gvar (gvar will have
gone up a bit more depending how long the pause lasted). This time
the status is dead because the cancel worked.<programlisting>
<prompt>localhost&gt;</prompt><userinput> lua box.fiber.cancel(fiber_of_x)</userinput>
---
...
<prompt>localhost&gt;</prompt><userinput> lua print('#',fid,'. ',box.fiber.status(fiber_of_x),'. gvar=',gvar)</userinput>
---
fiber=104. dead. gvar=22
...</programlisting>
</para>

</section>

<!--   end of lib -->

<section xml:id="sp-box-session">
    <title>Package <code>box.session</code></title>
    <para>
    The <code>box.session</code> package allows querying the session state,
    writing to a session-specific temporary record, or setting up triggers
    which will fire when a session starts or ends.
    A <emphasis>session</emphasis> is an object associated with each client connection.
    </para>
<variablelist>
    <varlistentry>
        <term>
            <emphasis role="lua">box.session.id() </emphasis>
        </term>
        <listitem>
            <para>
              Returns: (type = number) the unique identifier
              (ID) for the current session. The result can be 0 meaning
              there is no session (for example because a function is
              running in a detached fiber).
            </para>
      </listitem>
    </varlistentry>

    <varlistentry>
        <term>
            <emphasis role="lua">box.session.exists(<replaceable>id</replaceable>) </emphasis>
        </term>
        <listitem>
            <para>
              Returns: (type = number) 1 if the session exists,
              0 if the session does not exist.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
        <emphasis role="lua">box.session.peer(<replaceable>id</replaceable>) </emphasis>
        </term>
        <listitem>
            <para>
               Parameters: <code>id</code> = the unique identifier of the session.
            </para>
            <para>
              Returns: (type = string) If the specified session exists, the host
              address and port of the session peer, for example "127.0.0.1:55457".
              If the specified session does not exist, "0.0.0.0:0". The command is executed on the server,
              so the "local name" is the server's host and administrative port,
              and the "peer name" is the client's host and port.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term>
           <emphasis role="lua">box.session.storage</emphasis>
        </term>
        <listitem>
            <para>
              A Lua table that can hold arbitrary
              unordered session-specific names and values, which will last until
              the session ends.
            </para>
        </listitem>
    </varlistentry>
</variablelist>

<para>
<bridgehead renderas="sect4">Example</bridgehead><programlisting>
<prompt>localhost&gt;</prompt><userinput> lua box.session.peer(box.session.id())</userinput>
---
 - 127.0.0.1:45129
...
<prompt>localhost&gt;</prompt><userinput> lua box.session.storage.random_memorandum = "Don't forget the eggs."</userinput>
---
...
<prompt>localhost&gt;</prompt><userinput> lua box.session.storage.radius_of_mars = 3396</userinput>
---
...
<prompt>localhost&gt;</prompt><userinput> lua for k, v in pairs(box.session.storage) do print(k, ' ', v) end</userinput>
---
radius_of_mars 3396
random_memorandum Don't forget the eggs.
...</programlisting>
</para>

    <para>
See <olink targetptr="sp-box-session-triggers">the section "Triggers on connect and disconnect"</olink>
for instructions about defining triggers for connect and disconnect events
 with <code>box.session.on_connect()</code> and <code>box.session.on_disconnect()</code>.
    </para>
</section>

<!--   end of lib -->

<section xml:id="sp-box-ipc">
    <title>Package <code>box.ipc</code> &mdash; inter procedure communication</title>
    <para>
      The <code>box.ipc</code> package allows sending and receiving messages between different procedures of a session.
    </para>
    <para>
      Call <code>box.ipc.channel()</code> to allocate space and get a channel object, which will be
      called <code>channel</code> for examples in this section.
      Call the other box.ipc() routines, passing <code>channel</code>, to send messages, receive messages, or check ipc status.
      Message exchange is synchronous.
      The channel is garbage collected when no one is using it, as with any
      other Lua object.
      Object-oriented and functional APIs are equivalent, so <code>channel:put(message)</code>
      is the same as <code>channel:put(channel, message)</code>. 
    </para>
<variablelist xml:id="box.ipc">
    <para>
    </para>
    <varlistentry>
        <term><emphasis role="lua">box.ipc.channel(<replaceable>capacity-number</replaceable>)</emphasis></term>
        <listitem>
            <para>
              Create a new communication channel.
            </para>
            <para>
              Parameters: <code>capacity-number</code> =
              a positive integer as great as the maximum number of slots
              (spaces for get or put or broadcast messages)
              that might be pending at any given time.
            </para>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term><emphasis role="lua">channel:put(<replaceable>channel, message[, timeout]</replaceable>)</emphasis></term>
        <listitem>
            <para>
                Send a message using a channel. If the channel is full,
                <code>channel:put()</code>
                blocks until there is a free slot in the channel.
            </para>
            <para>
                Parameters: <code>channel</code>, <code>message</code>, <code>timeout</code>.
            </para>
            <para>
                Returns: If <code>timeout</code> is provided,
                and the channel doesn't become empty for the duration
                of the timeout,
                <code>channel:put()</code>
                returns false. Otherwise it returns true.
            </para>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term><emphasis role="lua">channel:close()</emphasis></term>
        <listitem>
            <simpara>
               Close the channel. All waiters in the channel will be
               woken up. All following <code>channel:put()</code>
               or <code>channel:get()</code> operations will return
               an error (nil).
            </simpara>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term><emphasis role="lua">channel:get(<replaceable>channel[, timeout]</replaceable>)</emphasis></term>
        <listitem>
            <para>
                Fetch a message from a channel. If the channel is empty,
                <code>channel:get()</code>
                blocks until there is a message.
            </para>
            <para>
              Parameters: <code>channel</code>, <code>timeout</code>.
            </para>
            <para>
                Possible errors: If <code>timeout</code> is provided,
                and there are no new messages for the duration
                of the timeout,
                <code>channel:get()</code>
                returns error.
            </para>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term><emphasis role="lua">channel:broadcast(<replaceable>channel, message, timeout</replaceable>)</emphasis></term>
        <listitem>
            <para>
             If the channel is empty, <code>channel:broadcast()</code> is equivalent to
             <code>channel:put()</code>.
              Otherwise, <code>channel:broadcast()</code> sends the message to all readers of the
              channel.
            </para>
            <para>
             Parameters: <code>channel</code>, <code>message</code>, <code>timeout</code>.
            </para>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term><emphasis role="lua">channel:is_empty(<replaceable>channel</replaceable>)</emphasis></term>
        <listitem>
            <para>
               Check whether the specified channel is empty (has no messages).
            </para>
            <para>
               Parameters: <code>channel</code>.
            </para>
            <para>
               Returns: (type = boolean) true if the specified channel is empty.
            </para>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term><emphasis role="lua">channel:is_full(<replaceable>channel</replaceable>)</emphasis></term>
        <listitem>
            <para>
                Check whether the specified channel is full.
            </para>
            <para>
                Parameters: <code>channel</code>.
            </para>
            <para>
                Returns: (type = boolean) true if the specified channel is full (has no room for a new message).
            </para>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term><emphasis role="lua">channel:has_readers(<replaceable>channel</replaceable>)</emphasis></term>
        <listitem>
            <para>
               Check whether the specified channel is empty and has readers waiting
               for a message (because they have issued <code>channel:get()</code> and then
               blocked).
            </para>
            <para>
             Parameters: <code>channel</code>.
            </para>
            <para>
               Returns: (type = boolean) true if blocked users are waiting. Otherwise false.
            </para>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term><emphasis role="lua">channel:has_writers(<replaceable>channel</replaceable>)</emphasis></term>
        <listitem>
            <para>
                Check whether the specified channel is full and has writers waiting
                (because they have issued <code>channel:put()</code> and then blocked
                due to lack of room).
            </para>
            <para>
                Parameters: <code>channel</code>.
            </para>
            <para>
                Returns: (type = boolean) true if blocked users are waiting. Otherwise false.
            </para>
        </listitem>
    </varlistentry>
    <varlistentry>
        <term><emphasis role="lua">channel:is_closed()</emphasis></term>
        <listitem>
            <simpara>
                Return true if the specified channel is already
                closed.
                Otherwise return false.
            </simpara>
        </listitem>
    </varlistentry>
</variablelist>
<para>
            <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 are waiting for data
        end
        ...

        if channel:has_writers() then
            # there are some fibers that are waiting for 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>
</para>
</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">
    <para>
      The <code>box.socket</code> package allows exchanging data via BSD sockets
      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>.
    </para>
    <para>
      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.
    </para>
    <para>
      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).
    </para>
    <para>
      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>.
    </para>
    <para>
      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.
    </para>
    <para>
      As with all other <code>box</code> functions, 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>).
    </para>
    <para>
      A closed socket should not be used any more. Alternatively, the
      socket will be closed when its userdata is garbage collected
      by Lua.
    </para>

    <varlistentry>
        <term><emphasis role="lua">box.socket.tcp()</emphasis></term>
        <listitem>
            <para>
                Create a new TCP socket.
            </para>
            <para>
                Returns: (type = userdata) 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.
            </para>
            <para>
                Returns: (type = userdata) a new socket, or <code>nil</code>.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term><emphasis role="lua">socket:connect(<replaceable>host, port, [timeout</replaceable>])</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 connection succeeds.
               </para>
               <para>
                Parameters: <code>host</code>, <code>port</code>, <code>timeout</code>.
               </para>
               <para>
                Returns: (type = userdata) 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(<replaceable>data, [timeout]</replaceable>)</emphasis></term>
        <listitem>
            <para>
             Send data over a connected socket.
            </para>
            <para>
             Parameters: <code>data</code>, <code>timeout</code>.
            </para>
            <para>
             Returns: (type = number) 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(<replaceable>size, [timeout]</replaceable>)</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.
            </para>
            <para>
              Parameters: <code>size</code>, <code>timeout</code>.
            </para>
            <para>
              Returns: (type = string) 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(<replaceable>[limit] [, separator list] [, timeout]</replaceable>)</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' (line feed) or eof (end of transmission).
            </para>
            <para>
              Parameters: <code>limit</code> &mdash; maximum number of bytes to read. The function reads
              until a separator is seen, or until (limit) bytes have been read. The default is "no limit".
              <code>separator list</code> &mdash; a Lua table containing one or more separators.
              The function reads until one of the separators is seen. The default is a Lua table containing '\n'.
              <code>timeout</code> &mdash; number of seconds to wait before returning an error.
            </para>
            <para>
                Returns:
                (type = string) A Lua string with data if success,
                an empty string if error. If multiple separators were passed in <code>separator list</code>,
                the separator which matched is also shown, as the third part of the return.
                <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(<replaceable>host, port[, timeout]</replaceable>)</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, <code>socket:bind</code> never yields and
                the timeout is unused.
            </para>
            <para>
              Parameters: <code>host</code>, <code>port</code>, <code>timeout</code>.
            </para>
            <para>
               Returns: (type = userdata) a 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>.
            </para>
            <para>
               Returns: (type = userdata) a socket object on success, <code>nil, "error", errno, errstr</code> on error.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term><emphasis role="lua">socket:accept(<replaceable>[timeout]</replaceable>)</emphasis></term>
        <listitem>
            <para>
                Wait for a new client connection and create a connected
                socket.
            </para>
            <para>
               Parameters: <code>timeout</code>.
            </para>
            <para>
               Returns: (type = userdata) <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(<replaceable>data, host, port, [timeout]</replaceable>)</emphasis></term>
        <listitem>
            <para>
                Send a message on a UDP socket to a specified host.
            </para>
            <para>
               Parameters: <code>data</code>, <code>host</code>, <code>timeout</code>.
            </para>
            <para>
               Returns: (type = number) 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(<replaceable>limit[, timeout]</replaceable>)</emphasis></term>
        <listitem>
            <para>
                Receive a message on a UDP socket.
            </para>
            <para>
                Parameters: <code>limit</code>, <code>timeout</code>.
            </para>
            <para>
                Returns: (type = string) 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(<replaceable>how</replaceable>)</emphasis></term>
        <listitem>
            <para>
                Shutdown a reading, writing or both ends of a socket.
            </para>
            <para>
               Parameters: <code>how</code> = box.socket.SHUT_RD, box.socket.SHUT_WR,
               or box.socket.SHUT_RDWR.
            </para>
            <para>
               Returns: (type = userdata) 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.
            </para>
            <para>
                Returns:(type = number) <code>errno, errstr</code>. <code>0, "Success"</code>
                if there is no error.
            </para>
        </listitem>
    </varlistentry>

</variablelist>


 <bridgehead renderas="sect4">Example showing use of box.socket over the Internet</bridgehead>
 <para>
 In this example a connection is made over the internet between the Tarantool server
 and <link xlink:href="http://mail.ru">mail.ru</link>,
 then an HTTP "get" message is sent, and a response is received: "HTTP/1.0 200 OK".
 This is not a useful way to communicate with this particular site,
 but shows that the system works.
<programlisting>
<prompt>localhost&gt;</prompt> <userinput>lua sock = box.socket.tcp()</userinput>
---
...
<prompt>localhost&gt;</prompt> <userinput>lua type(s)</userinput>
---
 - userdata
...
<prompt>localhost&gt;</prompt> <userinput>lua sock:connect('mail.ru', 80)</userinput>
---
 - fd 22, aka 192.168.1.72:49488, peer of 94.100.180.199:80
...
<prompt>localhost&gt;</prompt> <userinput>lua sock:error()</userinput>
---
 - 0
 - Success
...
<prompt>localhost&gt;</prompt> <userinput>lua sock:send('GET / HTTP/1.0\n\n')</userinput>
---
 - 16
...
<prompt>localhost&gt;</prompt> <userinput>lua sock:recv(17)</userinput>
---
 - HTTP/1.0 200 OK
...
 <prompt>localhost&gt;</prompt> <userinput>lua sock:close()</userinput>
---
...
</programlisting>
</para>

</section>

<section xml:id="sp-box-net-box">
    <title>Package <code>box.net.box</code> &mdash; working with networked Tarantool peers</title>
    <para>
        The <code>box.net</code> package contains connectors to remote database systems.
        One variant, <code>box.net.sql</code>, is for connecting to MySQL or MariaDB or PostgreSQL
        &mdash; that variant is the subject of the <quote>SQL DBMS plugins</quote> appendix.
        In this section the subject is the built-in variant, <code>box.net.box</code>.
        This is for connecting to tarantool_box servers via a network.
    </para>
<variablelist xml:id="box.net.box">
    <para>
        Call <code>box.net.box.new()</code> to connect and get a connection object,
        which will be called <code>conn</code> for examples in this section.
        Call the other <code>box.net.box()</code> routines, passing <code>conn</code>,
        to execute requests on the remote box.
        Call <code>box.net.box.close(conn)</code> to disconnect.
        Object-oriented and functional APIs are equivalent, so
        <code>conn:close()</code> is the same as <code>box.net.box.close(conn)</code>.
    </para>

    <para>
        All <code>box.net.box</code> methods are fiber-safe, that is, it is
        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 back a
        correct response. 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 &mdash; for example when it's necessary to
        prioritize requests or to use different authentication ids.
    </para>

    <varlistentry>
        <term>
            <emphasis role="lua" xml:id="box.net.box.new">
             conn = box.net.box.new(<replaceable>host</replaceable>, <replaceable>port</replaceable> [, <replaceable>reconnect_interval</replaceable>])</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)
                specifies the amount of time the server
                sleeps between failing attempts to reconnect.
                The returned <code>conn</code> object supports methods for making remote
                requests, such as select, update or delete.
            </para>
            <para>
               For the local tarantool_box server there is a pre-created always-established
               connection object named <code>box.net.self</code>.
               Its purpose is to make polymorphic use of the
               <code>box.net.box</code> API easier. Therefore
               <code>conn = box.net.box.new('localhost', 33013)</code> can
               be replaced by <code>conn = box.net.box.self</code>.
               However, there is an important difference 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, any request can yield, and local database state may
               have changed by the time it returns.
            </para>
            <para>
               Parameters: <code>host</code>, <code>port</code>, <code>reconnect_interval</code>.
            </para>
            <para>
               Returns: (type = userdata) conn object).
            </para>
            <para>
               Example: <code>conn = box.net.box.new('localhost', 33013)</code>.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term><emphasis role="lua" xml:id="box.net.box.ping">
        conn:ping()</emphasis></term>
        <listitem>
            <para>
                Execute a PING command.
            </para>
            <para>
               Returns: (type = boolean) <code>true</code> on success,
                 <code>false</code> on error. Example: <code>self:ping()</code>.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term><emphasis role="lua" xml:id="box.net.box.close">
        conn:close()</emphasis></term>
        <listitem>
            <para>
            Close a connection.
            </para>
            <para>
              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 good programming practice to close a connection
              explicitly when it is no longer needed, to avoid lengthy
              stalls of the garbage collector.
            </para>
            <para>
              Example: <code>conn:close()</code>.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term><emphasis role="lua" xml:id="box.net.box.select">
         conn:select(<replaceable>space-number</replaceable>, <replaceable>index-number</replaceable>, ...)</emphasis></term>
        <listitem>
            <para>
              <code>conn:select(...)</code> is the remote-call equivalent of the local call <code xlink:href="#box.select">box.select(...)</code>.
              Please note this difference: a local <code>box.select()</code> does not yield,
              but a remote <code>conn:select()</code> call does yield,
              so local data may change while a remote <code>conn:select()</code> is running.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term><emphasis role="lua" xml:id="box.net.box.select_limit">
         conn:select_limit(<replaceable>space-number</replaceable>, <replaceable>index-number</replaceable>, <replaceable>offset</replaceable>, <replaceable>limit</replaceable>, ...)</emphasis></term>
        <listitem>
            <para>
              <code>conn:select_limit(...)</code> is the remote-call equivalent of the local call <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(<replaceable>space-number</replaceable>, <replaceable>index-number</replaceable>, <replaceable>limit</replaceable>, <replaceable>key</replaceable>, ...)</emphasis></term>
        <listitem>
            <para>
              <code>conn:select_range(...)</code> is the remote-call equivalent of the local call <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(<replaceable>space-number</replaceable>, ...)</emphasis></term>
        <listitem>
            <para>
              <code>conn:insert(...)</code> is the remote-call equivalent of the local call <code xlink:href="#box.insert">box.insert(...)</code>.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term><emphasis role="lua" xml:id="box.net.box.replace">
         conn:replace(<replaceable>space-number</replaceable>, ...)</emphasis></term>
        <listitem>
            <para>
              <code>conn:replace(...)</code> is the remote-call equivalent of the local call <code xlink:href="#box.replace">box.replace(...)</code>.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term><emphasis role="lua" xml:id="box.net.box.update">
         conn:update(<replaceable>space-number</replaceable>, <replaceable>key</replaceable>, <replaceable>format</replaceable>, ...)</emphasis></term>
        <listitem>
            <para>
              <code>conn:update(...)</code> is the remote-call equivalent of the local call <code xlink:href="#box.update">box.update(...)</code>.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term><emphasis role="lua" xml:id="box.net.box.delete">
         conn:delete(<replaceable>space-number</replaceable>, <replaceable>key</replaceable>)</emphasis></term>
        <listitem>
            <para>
              <code>conn:delete(...)</code> is the remote-call equivalent of the local call <code xlink:href="#box.delete">box.delete(...)</code>.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term><emphasis role="lua" xml:id="box.net.box.call">
         conn:call(<replaceable>function-name</replaceable> [, <replaceable>arguments</replaceable>])</emphasis></term>
        <listitem>
            <para>
              <code>conn:call('proc', '1', '2', '3')</code> is the remote-call equivalent of <code>CALL proc('1', '2', '3')</code>.
              That is, box.net.box.call is a remote stored-procedure call.
              Please keep in mind that the call is using
              the binary protocol to pack procedure arguments,
              and the binary protocol is type agnostic, so it's recommended
              to pass all arguments of remote stored procedure calls as
              strings.
            </para>
            <para>
              Example: <code>conn:call("box.select_reverse_range", "1", "4", "10", "Smith")</code>.
            </para>
        </listitem>
    </varlistentry>

    <varlistentry>
        <term><emphasis role="lua" xml:id="box.net.box.timeout">
         conn:timeout(<replaceable>timeout</replaceable>)</emphasis></term>
        <listitem>
            <para>
              <code>timeout(...)</code> is a wrapper which sets a timeout for the request that follows it.
              Example: <code>conn:timeout(0):update('1', 'arg1', 15)</code>.
            </para>
            <para>
              All remote calls support execution timeouts.
              Using a wrapper object makes the remote
              connection API compatible with the local one, removing
              the need for a separate <code>timeout</code> argument, which
              the local version would ignore. Once a request is sent,
              it cannot be revoked from the remote server even if
              a timeout expires: the timeout expiration only aborts the
              wait for the remote server response, not the request itself.
            </para>
        </listitem>
    </varlistentry>
</variablelist>

 <bridgehead renderas="sect4">Example showing use of most of the box.net.box methods</bridgehead>
 <para>
 This example will work with the sandbox configuration described in the preface.
 That is, there is a space[0] with a numeric primary key.
 Assume that the database is nearly empty.
 Assume that the tarantool_box server is running on localhost 127.0.0.1:33013.
<programlisting><prompt>localhost&gt;</prompt> <userinput> setopt delimiter = '!'</userinput>
<prompt>localhost&gt;</prompt> <userinput> lua function example()</userinput>
<prompt>        -&gt;</prompt> <userinput>   if box.net.self:ping() then</userinput>
<prompt>        -&gt;</prompt> <userinput>     print('self:ping() succeeded')</userinput>
<prompt>        -&gt;</prompt> <userinput>     print('  (no surprise -- self connection is pre-established)')</userinput>
<prompt>        -&gt;</prompt> <userinput>     end</userinput>
<prompt>        -&gt;</prompt> <userinput>   if box.cfg.primary_port == 33013 then</userinput>
<prompt>        -&gt;</prompt> <userinput>     print('The local server primary port number = 33013 = default')</userinput>
<prompt>        -&gt;</prompt> <userinput>   else</userinput>
<prompt>        -&gt;</prompt> <userinput>     print('The local server primary port number is not 33013')</userinput>
<prompt>        -&gt;</prompt> <userinput>     print('  (so connect will fail)')</userinput>
<prompt>        -&gt;</prompt> <userinput>     end</userinput>
<prompt>        -&gt;</prompt> <userinput>   conn = box.net.box.new('127.0.0.1', 33013)</userinput>
<prompt>        -&gt;</prompt> <userinput>   conn:delete(0,800)</userinput>
<prompt>        -&gt;</prompt> <userinput>   print('conn:delete done on space[0].')</userinput>
<prompt>        -&gt;</prompt> <userinput>   conn:insert(0, 800, 'data')</userinput>
<prompt>        -&gt;</prompt> <userinput>   print('conn:insert done on space[0], index 0')</userinput>
<prompt>        -&gt;</prompt> <userinput>   print('  primary key value = 800.')</userinput>
<prompt>        -&gt;</prompt> <userinput>   wtuple = conn:select(0, 0, 800)</userinput>
<prompt>        -&gt;</prompt> <userinput>   print('conn:select done on space[0], index 0.')</userinput>
<prompt>        -&gt;</prompt> <userinput>   print('  number of fields = ', #wtuple)</userinput>
<prompt>        -&gt;</prompt> <userinput>   conn:delete(0, 800)</userinput>
<prompt>        -&gt;</prompt> <userinput>   print('conn:delete done on space[0].')</userinput>
<prompt>        -&gt;</prompt> <userinput>   conn:replace(0, 800, 'New data', 'Extra data')</userinput>
<prompt>        -&gt;</prompt> <userinput>   print('conn:replace done on space[0].')</userinput>
<prompt>        -&gt;</prompt> <userinput>   conn:timeout(0):update(0, 800, '=p=p', 1, 'Fld#1', 2, 'Fld#2')</userinput>
<prompt>        -&gt;</prompt> <userinput>   print('conn:update done on space[0]')</userinput>
<prompt>        -&gt;</prompt> <userinput>   print('  timed out after waiting 0 seconds for a return')</userinput>
<prompt>        -&gt;</prompt> <userinput>   conn:close()</userinput>
<prompt>        -&gt;</prompt> <userinput>   print('conn:close done')</userinput>
<prompt>        -&gt;</prompt> <userinput> end!</userinput>
---
...
<prompt>localhost&gt;</prompt> <userinput> setopt delimiter = ''!</userinput>
<prompt>localhost&gt;</prompt> <userinput> lua example()</userinput>
---
self:ping() succeeded
  (no surprise -- self connection is pre-established)
The local server primary port number = 33013 = default
conn:delete done on space[0].
conn:insert done on space[0], index 0.
  primary key value = 800.
conn:select done on space[0], index 0.
  number of fields = 2
conn:delete done on space[0].
conn:replace done on space[0].
conn:update done on space[0], 
  timed out after waiting 0 seconds for a return
conn:close done
...
<prompt>localhost&gt;</prompt> <userinput> select * from t0 where k0 = 800 # Prove that the update succeeded.</userinput>
Select OK, 1 rows affected
[800, 'Fld#1', 'Fld#2']
</programlisting>
</para>
</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>
      The box.cfg 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>
        The box.info 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>
            <para>
              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.
            </para>
            <para>
              Returns: (type = Lua table) keys and values in the package.
            </para>
            <bridgehead renderas="sect4">Example</bridgehead><programlisting>
localhost> <userinput>lua for k, v in pairs(box.info()) do print(k, ': ', v) end</userinput>
---
version: 1.5.2-17-g99249b5
status: primary
pid: 1747
lsn: 1712
recovery_last_update: 1306964594.980
recovery_lag: 0
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>
      The box.slab 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>
      The box.stat 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</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
-->
