diff --git a/.gitignore b/.gitignore
index 8db9e4cd903694db40a08a551fdc35266c5337b7..1f82f83581b598817abafda890c312928027bb98 100644
--- a/.gitignore
+++ b/.gitignore
@@ -49,3 +49,9 @@ doc/www-data/*.ru.html
 doc/www-data.in/download
 doc/man/tarantool.1
 doc/man/tarantool_box.1
+connector/c/tnt/libtarantool.so.1
+connector/c/tnt/libtarantool.so.1.1
+connector/c/tntnet/libtarantoolnet.so.1
+connector/c/tntnet/libtarantoolnet.so.1.1
+connector/c/tntsql/libtarantoolsql.so.1
+connector/c/tntsql/libtarantoolsql.so.1.1
diff --git a/doc/sql.txt b/doc/sql.txt
index ccf121755c3c5f9a74fb2ef4de5e119dca0b6317..c277f1f8b78c420f8481912326485257400013a7 100644
--- a/doc/sql.txt
+++ b/doc/sql.txt
@@ -1,19 +1,19 @@
 ;  
 ; Tarantool SQL parser is implemented entirely on the client side.
 ; This BNF provides a reference of the supported subset of 
-; the standard SQL, to which all clients are strongly encouraged 
+; SQL, to which all clients are strongly encouraged
 ; to stick.
 ; 
 ; Convention: UPPERCASE letters are used for terminals and literals.
 ; Lowercase letters are used for <non-terminals>. SQL is
-; case-insensitive, so this convention is present only to imporve
+; case-insensitive, so this convention is present only to improve
 ; legibility of the BNF.
 
 <sql> ::= <insert> | <replace> | <update> | <delete> | <select>
 
 <insert> ::= INSERT [INTO] <ident> VALUES <value_list>
 
-<insert> ::= REPLACE [INTO] <ident> VALUES <value_list>
+<replace> ::= REPLACE [INTO] <ident> VALUES <value_list>
 
 <update> ::= UPDATE <ident> SET <update_list> <simple_where>
 
diff --git a/doc/user/CMakeLists.txt b/doc/user/CMakeLists.txt
index ee097af2a65b08f850400db74b4ba327a2d10560..34d1a421ad6c8a36578529705a85f3a875351084 100644
--- a/doc/user/CMakeLists.txt
+++ b/doc/user/CMakeLists.txt
@@ -63,11 +63,10 @@ add_custom_target(pdf
     COMMAND fop tarantool_user_guide.fo tarantool_user_guide.pdf)
 
 add_custom_target(relink
+    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
     COMMAND ${XSLTPROC} --nonet
         --stringparam collect.xref.targets "only"
-        --xinclude -o ${PATH_USERGUIDE_HTML}
-        ${CMAKE_SOURCE_DIR}/doc/user/tnt-html.xsl
-        ${CMAKE_SOURCE_DIR}/doc/user/user.xml)
+        --xinclude tnt-html.xsl user.xml)
 
 #
 # Java saxon-based documentation generation (misc)
diff --git a/doc/user/data-model.xml b/doc/user/data-model.xml
index d8d193e5e95bde5677451fb343d0624a45903398..63560fd000b0387bcc8b19f3bee68feaacb36254 100644
--- a/doc/user/data-model.xml
+++ b/doc/user/data-model.xml
@@ -90,7 +90,7 @@
     <listitem><para>
        REPLACE replaces data when a
        tuple with given primary key already exists. Such replace
-       can insert a tuple of different cardinality.
+       can insert a tuple with a different number of fields.
     </para></listitem>
   </itemizedlist>
 </para>
diff --git a/doc/user/errcode.xml b/doc/user/errcode.xml
index affe269ee40413b5213e88a0ecdf4741068b3986..ef2b92d5d9cc582aa0b26ca709b089fa6a18fa64 100644
--- a/doc/user/errcode.xml
+++ b/doc/user/errcode.xml
@@ -56,8 +56,8 @@ of existing codes.</para>
   </varlistentry>
 
   <varlistentry>
-    <term xml:id="ER_KEY_CARDINALITY" xreflabel="ER_KEY_CARDINALITY">ER_KEY_CARDINALITY</term>
-    <listitem><para>Key cardinality is greater than index cardinality
+    <term xml:id="ER_KEY_PART_COUNT" xreflabel="ER_KEY_PART_COUNT">ER_KEY_PART_COUNT</term>
+    <listitem><para>Key part count is greater than index part count
     </para></listitem>
   </varlistentry>
 
diff --git a/doc/user/language-reference.xml b/doc/user/language-reference.xml
index 15f719f0384ea9301ce5b807934161dc521675aa..a0c4e1502bba3f19694e68870bc8b82f286657b8 100644
--- a/doc/user/language-reference.xml
+++ b/doc/user/language-reference.xml
@@ -74,7 +74,7 @@
     header, allows simplifying client or proxy I/O.
     The server response to a request always carries in its header
     the same request type and id.
-    The id makes it possible to always match request to a
+    The id makes it possible to always match a request to a
     response, even if the latter arrived out of order.
   </para>
   <para>Request type defines the format of the payload.
@@ -85,11 +85,11 @@
     exception, all commands operate on whole tuple(s).
   </para>
   <para>Unless implementing a client driver, one needn't
-    concern him or her self with the complications of the binary
+    concern oneself with the complications of the binary
     protocol. <olink targetptr="connectors">Language-specific
     drivers</olink> provide a friendly way to store domain
     language data structures in Tarantool, and the command line
-    client supports a subset of the standard SQL.
+    client supports a subset of standard SQL.
     A complete description of both, the binary protocol and
     the supported SQL, is maintained in annotated Backus-Naur
     form in the source tree: please see
@@ -132,7 +132,7 @@
     understands all administrative statements
     and automatically directs them to the administrative port.
     The server response to an administrative command, even though
-    is always in plain text, can be quite complex.
+    it is always in plain text, can be quite complex.
     It is encoded using YAML markup to simplify automated parsing.
   </para>
   <para>To learn about all supported administrative commands, you
@@ -151,8 +151,8 @@
         <filename><olink
         targetptr="snap_dir"/>/&lt;latest-lsn&gt;.snap</filename>.
         To take a snapshot, Tarantool forks and quickly
-        <function>munmap(2)</function>s all memory except one that
-        stores tuples. Since all modern operating systems support
+        <function>munmap(2)</function>s all memory except memory
+        where tuples are stored. Since all modern operating systems support
         virtual memory copy-on-write, this effectively creates a
         consistent snapshot of all tuples in the child process,
         which is then written to disk tuple by tuple. Since a
@@ -170,7 +170,7 @@
 <programlisting>localhost> show info
 ---
 info:
-  version: "1.4.4"
+  version: "1.4.6"
   lsn: 843301
 ...
 localhost> save snapshot
@@ -258,6 +258,8 @@ info:
         <emphasis role="tntadmin">show stat</emphasis>
       </term>
       <listitem><para>
+      Show the average number of requests per second, and the total number of requests since startup,
+      broken down by request type: INSERT or SELECT or UPDATE or DELETE."
 <programlisting>
 localhost> show stat
 ---
@@ -301,7 +303,7 @@ statistics:
       </term>
       <listitem><para>
         A pool allocator is used for temporary memory, when
-        serving client requests. Every fiber has an own
+        serving client requests. Every fiber has its own
         pool. Shows the current state of pools of all fibers.
       </para></listitem>
     </varlistentry>
@@ -334,7 +336,7 @@ statistics:
       <listitem><para>
         Execute a chunk of Lua code. This can be used to define,
         invoke, debug and drop <olink
-        targetptr="stored-programs">stored programs</olink>,
+        targetptr="stored-procedures">stored procedures</olink>,
         inspect server environment, perform automated
         administrative tasks.
       </para></listitem>
@@ -344,7 +346,7 @@ statistics:
 
 </section>
 
-<xi:include href="stored-programs.xml" />
+<xi:include href="stored-procedures.xml" />
 
 </chapter>
 
diff --git a/doc/user/persistence-architecture.xml b/doc/user/persistence-architecture.xml
index e1c3aa7377f6344f878e2442c301636ee8445e72..d1e7e46158a7d73bb7cb0fe9078a98f128f2aae4 100644
--- a/doc/user/persistence-architecture.xml
+++ b/doc/user/persistence-architecture.xml
@@ -7,7 +7,7 @@
 <title>Data persistence</title>
 <para>
 To maintain data persistence, Tarantool writes each data change
-request (INSERT, UPDATE, DELETE) into a write ahead log. WAL
+request (INSERT, UPDATE, DELETE) into a write-ahead log. WAL
 files have extension <filename>.xlog</filename> and are stored in <olink
 targetptr="wal_dir"/>. A new WAL file is created for every <olink
 targetptr="rows_per_wal"/> records.  Each INSERT, UPDATE or DELETE
@@ -23,36 +23,35 @@ each WAL record contains a checksum and a UNIX time stamp.
 </para>
 
 <para>
-Tarantool proceeds requests atomically: a change is either
-accepted and recorded in the WAL, or is rejected wholesale.
+Tarantool processes requests atomically: a change is either
+accepted and recorded in the WAL, or discarded completely.
 Let's clarify how this happens, using REPLACE command as an
 example:
 <orderedlist>
     <listitem><para>
-    The server tries to locate an old tuple identified by
-    the same primary key. If found, the tuple is remembered for
-    later.
+    The server attempts to locate the original tuple by
+    primary key. If found, a reference to the tuple is retained
+    for later use.
     </para></listitem>
     <listitem><para>
-    The new tuple is <emphasis>validated</emphasis>. If it
-    violates any of the unique key constraints, misses
-    any of indexed fields, or an indexed field type does not
-    match index type, the change is aborted.
+    The new tuple is then <emphasis>validated</emphasis>. If it
+    violates a unique-key constraint, misses
+    an indexed field, or an index-field type does not
+    match the type of the index, the change is aborted.
     </para></listitem>
     <listitem><para>
-    The new tuple is marked 'invisible' and is added to 
+    The new tuple is marked 'invisible' and is added to
     the primary and secondary indexes.
     </para></listitem>
     <listitem><para>
-    A message is sent to a separate <quote>wal_writer</quote>
-    thread requesting that the change is recorded in the WAL.
-    The fiber associate with the current connection is scheduled
-    off CPU until an acknowledgment is received from the WAL
-    writer.
+    A message is sent to <quote>wal_writer</quote>, running in a
+    separate thread, requesting that the change be recorded in the WAL.
+    The fiber associated with the current connection is suspended
+    until an acknowledgment from the WAL writer.
     </para></listitem>
     <listitem><para>
-    Upon success, 'invisible' flag is cleared
-    and the old tuple is deleted. A response is sent to the
+    Upon success, the 'invisible' flag is cleared
+    and the original tuple is deleted. A response is sent to the
     client. Upon failure, the new tuple is removed and <olink
     targetptr="ER_WAL_IO"/> error is sent to the client.
     </para></listitem>
@@ -60,13 +59,12 @@ example:
 </para>
 
 <para>
-Communication between master and WAL writer threads is asynchronous.
-It is implemented using an asynchronous FIFO queue.
-Asynchronous but reliable message passing between the master
-and WAL writer threads allows Tarantool to continue handling
-requests regardless of disk throughput. SELECT performance,
-provided SELECTs are run in their own connections, is unaffected
-by disk load.
+The master and the WAL writer threads communicate using asynchronous (yet reliable)
+messaging; the master theread, not being blocked on
+WAL tasks, continues to handle requests quickly
+even at hight volumes of disk I/O. For instance, SELECT performance,
+provided SELECTs are run in their own connections, remains
+unaffected by disk load.
 </para>
 
 <para>
diff --git a/doc/user/space.xml b/doc/user/space.xml
index 8f8816c97fa198181ed080aee999c804b889d75d..3bc9b92076877ba6b408d13e62a2efae547e61e5 100644
--- a/doc/user/space.xml
+++ b/doc/user/space.xml
@@ -41,8 +41,8 @@ struct space_t
   /* A space can be quickly disabled and re-enabled at run time. */
   bool enabled;
   /*
-   * A limit on tuple cardinality can be set, to prevent too large tuples
-   * from coming in.
+   * If given, each tuple in the space must have exactly
+   * this many fields.
    */
   unsigned int cardinality;
   /* Only used for HASH indexes, to preallocate memory. */
diff --git a/doc/user/stored-programs.xml b/doc/user/stored-procedures.xml
similarity index 95%
rename from doc/user/stored-programs.xml
rename to doc/user/stored-procedures.xml
index fd580c25c1c14255240cc97d3f679a1d33af410f..8d86e362d6f83f546385f0cb03b3df6c1ec6afd1 100644
--- a/doc/user/stored-programs.xml
+++ b/doc/user/stored-procedures.xml
@@ -5,7 +5,7 @@
 <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-programs">
+      xml:id="stored-procedures">
   <title>Writing stored procedures in Lua</title>
 <blockquote>
     <para>
@@ -33,7 +33,7 @@ Found 1 tuple:
     In the language of the administrative console
     <olink targetptr="lua-command" /> evaluates an arbitrary
     Lua chunk. CALL is the SQL standard statement used
-    to represent CALL command of the binary
+    to invoke the CALL command of the binary
     protocol.
     In the example above, a Lua procedure is first defined
     using the text protocol of the administrative port,
@@ -95,7 +95,7 @@ expirationd.run_task("exprd space 0", 0, is_expired, nil,
   </para>
 
   <para>
-    There is a single global instance of Lua interpreter, which is
+    There is a single global instance of the Lua interpreter, which is
     shared across all connections. Anything prefixed with
     <code>lua </code> on the administrative console is sent
     directly to this interpreter. Any change of the interpreter
@@ -103,7 +103,7 @@ expirationd.run_task("exprd space 0", 0, is_expired, nil,
   </para>
   <para>
     Each connection, however, is using its own Lua
-    <emphasis>coroutine</emphasis> &mdash; a mechanism, akin to
+    <emphasis>coroutine</emphasis> &mdash; a mechanism akin to
     Tarantool <emphasis>fibers</emphasis>. A coroutine has an
     own execution stack and a Lua <emphasis>closure</emphasis>
     &mdash; set of local variables and definitions.
@@ -180,7 +180,7 @@ error: 1:15 expected '('
     When a function in Lua terminates with an error, the error
     is sent to the client as <olink targetptr="ER_PROC_LUA" />
     return code, with the original error message preserved.
-    Similarly, an error occurred inside Tarantool (observed on the
+    Similarly, an error which has occurred inside Tarantool (observed on the
     client as an error code), when happens during execution of a
     Lua procedure, produces a genuine Lua error:
 <programlisting><computeroutput>localhost> lua function f1() error("oops") end
@@ -247,7 +247,7 @@ pack: function
             <para>
                 Process a request passed in as a binary string.
                 This is an entry point into the server request
-                processor. It allows to insert, update,
+                processor. It can be used to insert, update,
                 select and delete tuples from within a Lua procedure.
             </para>
             <para>
@@ -373,8 +373,8 @@ localhost> lua box.select(5, 1, 'firstname', 'lastname')
                 single character of format describes either an
                 operation which needs to take place or operation
                 argument. A format specifier also works as a
-                placeholder for the number of field, which needs
-                to be updated, or argument value.
+                placeholder for the number of a field, which needs
+                to be updated, or for an argument value.
                 For example: 
                 <simplelist>
                     <member><code>+p=p</code> &mdash; add a value
@@ -419,7 +419,7 @@ localhost> lua box.update(0, 2, '!p', 1, 'Bienvenue tout le monde!')
 ---
  - 2: {'Bienvenue tout le monde!', 'Hello world!'}
 ...
-localhost> lua box.update(0, 2, '#p', 2, 'Biennvenue tout le monde!')
+localhost> lua box.update(0, 2, '#p', 2, 'Bienvenue tout le monde!')
 ---
  - 2: {'Bienvenue tout le monde!'}
 ...
@@ -467,7 +467,7 @@ Call ERROR, Illegal parameters, key is not u32 (ER_ILLEGAL_PARAMS)
             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 start of the index.
+            the selection starts from the start of the index.
             <bridgehead renderas="sect4">Example</bridgehead>
 <programlisting>localhost> show configuration
 ---
@@ -535,8 +535,8 @@ localhost> lua box.select_range(4, 1, 2, '1')
                 string, low byte first,
                 </member>
                 <member><code>p</code> &mdash; stores the length
-                of the argument as a 4-byte int, low byte first,
-                followed by the argument itself: a 4-byte int, low
+                of the argument as a 4-byte integer, low byte first,
+                followed by the argument itself: a 4-byte integer, low
                 byte first, for integers, or a binary blob for
                 anything else,
                 </member>
@@ -720,7 +720,7 @@ localhost> lua t:slice(1, -1)
             <emphasis role="lua">space.cardinality</emphasis>
         </term>
         <listitem><simpara>
-            A limit on tuple cardinality for tuples in this space.
+            A limit on tuple field count for tuples in this space.
             This limit can be set in the configuration file. Value 0
             stands for <quote>unlimited</quote>.
         </simpara></listitem>
@@ -732,8 +732,8 @@ localhost> lua t:slice(1, -1)
         </term>
         <listitem><simpara>
             A container for all defined indexes. An index is a Lua object
-            of type <code xlink:href="#box.index">box.index</code> which
-            allows to search tuples and iterate over them in predefined order.
+            of type <code xlink:href="#box.index">box.index</code> with
+            methods to search tuples and iterate over them in predefined order.
         </simpara></listitem>
     </varlistentry>
     <varlistentry>
@@ -992,18 +992,21 @@ localhost> lua for k,v in i.next, i, nil do print(v) end
 
 <variablelist>
     <title>Package <code>box.fiber</code></title>
-    <para>Functions in this package allow to create, run and
+    <para>Functions in this package allow you to create, run and
     manage existing <emphasis>fibers</emphasis>.
     </para>
     <para>
 A fiber is an independent execution thread implemented
 using a mechanism of cooperative multitasking.
-Each fiber can be running, suspended or dead.
-A fiber is created (<code>box.fiber.create()</code>) suspended.
-It can be started with <code>box.fiber.resume()</code>, yield
-control back to the caller with <code>box.fiber.yield()</code>
-end with <code>return</code> or just by reaching the end of
-fiber function.
+
+A fiber has three possible states: running, suspended or dead.
+When a fiber is created with <code>box.fiber.create()</code>,
+it is suspended.
+When a fiber is started with <code>box.fiber.resume()</code>, it is running.
+When a fiber's control is yielded back to the caller with
+<code>box.fiber.yield()</code>, it is suspended.
+When a fiber ends (due to <code>return</code> or by reaching the
+end of the fiber function), it is dead.
     </para>
     <para>
 A fiber can also be attached or detached.
@@ -1048,15 +1051,17 @@ can be used to cancel runaway Lua procedures.
     </para>
     <para>
 The other potential problem comes from detached
-fibers which never get scheduled, because are not subscribed
-to any events, or no relevant events occur. Such morphing fibers
+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.</para>
+    garbage collected: the garbage collector frees pool allocator
+    memory owned by the fiber, resets all fiber data, and returns
+    the fiber to the fiber pool.</para>
     <varlistentry>
         <term>
             <emphasis role="lua">box.fiber.id(fiber) </emphasis>
@@ -1185,10 +1190,10 @@ logger = cat - >> tarantool.log
 </para>
 
 <section>
-<title>Limitation of stored programs</title>
+<title>Limitation of stored procedures</title>
 
 <para>
-    There are two limitations in stored program support one should
+    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>
diff --git a/doc/user/target.db b/doc/user/target.db
index 7991ed8da6bae718d50079a06ea2a2aec3155f62..dd34c3308be2ee10d639461b65e7fade20b0144e 100644
--- a/doc/user/target.db
+++ b/doc/user/target.db
@@ -1 +1 @@
-<div element="book" href="#tarantool-user-guide" number="" targetptr="tarantool-user-guide"><ttl>Tarantool/Box User Guide, version 1.4.5-186-ga1d666f</ttl><xreftext>Tarantool/Box User Guide, version 1.4.5-186-ga1d666f</xreftext><div element="chapter" href="#idp97824" number="1"><ttl>Preface</ttl><xreftext>Chapter 1, <i>Preface</i></xreftext><div element="section" href="#preface" number="" targetptr="preface"><ttl>Tarantool/Box: an overview</ttl><xreftext>the section called “Tarantool/Box: an overview”</xreftext></div><div element="section" href="#idp200192" number=""><ttl>Conventions</ttl><xreftext>the section called “Conventions”</xreftext></div><div element="section" href="#idp209088" number=""><ttl>Reporting bugs</ttl><xreftext>the section called “Reporting bugs”</xreftext></div></div><div element="chapter" href="#idp230464" number="2"><ttl>Getting started</ttl><xreftext>Chapter 2, <i>Getting started</i></xreftext></div><div element="chapter" href="#data-and-persistence" number="3" targetptr="data-and-persistence"><ttl>Data model and data persitence</ttl><xreftext>Chapter 3, <i>Data model and data persitence</i></xreftext><div element="section" href="#idp296336" number=""><ttl>Dynamic data model</ttl><xreftext>the section called “Dynamic data model”</xreftext></div><div element="section" href="#idp402880" number=""><ttl>Data persistence</ttl><xreftext>the section called “Data persistence”</xreftext></div></div><div element="chapter" href="#language-reference" number="4" targetptr="language-reference"><ttl>Language reference</ttl><xreftext>Chapter 4, <i>Language reference</i></xreftext><div element="section" href="#idp671408" number=""><ttl>Data manipulation</ttl><xreftext>the section called “Data manipulation”</xreftext><div element="section" href="#idp666656" number=""><ttl>Memcached protocol</ttl><xreftext>the section called “Memcached protocol”</xreftext></div></div><div element="section" href="#idp663760" number=""><ttl>Administrative console</ttl><xreftext>the section called “Administrative console”</xreftext><obj element="term" href="#save-snapshot" number="" targetptr="save-snapshot"><ttl>???TITLE???</ttl><xreftext>SAVE SNAPSHOT</xreftext></obj><obj element="term" href="#reload-configuration" number="" targetptr="reload-configuration"><ttl>???TITLE???</ttl><xreftext>RELOAD CONFIGURATION</xreftext></obj><obj element="term" href="#show-configuration" number="" targetptr="show-configuration"><ttl>???TITLE???</ttl><xreftext>SHOW CONFIGURATION</xreftext></obj><obj element="term" href="#show-info" number="" targetptr="show-info"><ttl>???TITLE???</ttl><xreftext>SHOW INFO</xreftext></obj><obj element="term" href="#show-stat" number="" targetptr="show-stat"><ttl>???TITLE???</ttl><xreftext>SHOW STAT</xreftext></obj><obj element="term" href="#show-slab" number="" targetptr="show-slab"><ttl>???TITLE???</ttl><xreftext>SHOW SLAB</xreftext></obj><obj element="term" href="#show-palloc" number="" targetptr="show-palloc"><ttl>???TITLE???</ttl><xreftext>SHOW PALLOC</xreftext></obj><obj element="term" href="#save-coredump" number="" targetptr="save-coredump"><ttl>???TITLE???</ttl><xreftext>SAVE COREDUMP</xreftext></obj><obj element="term" href="#show-fiber" number="" targetptr="show-fiber"><ttl>???TITLE???</ttl><xreftext>SHOW FIBER</xreftext></obj><obj element="term" href="#lua-command" number="" targetptr="lua-command"><ttl>???TITLE???</ttl><xreftext>LUA ...</xreftext></obj></div><div element="section" href="#stored-programs" number="" targetptr="stored-programs"><ttl>Writing stored procedures in Lua</ttl><xreftext>the section called “Writing stored procedures in Lua”</xreftext><obj element="code" href="#box" number="" targetptr="box"><ttl>???TITLE???</ttl><xreftext>box</xreftext></obj><obj element="code" href="#box.tuple" number="" targetptr="box.tuple"><ttl>???TITLE???</ttl><xreftext>box.tuple</xreftext></obj><obj element="code" href="#box.space" number="" targetptr="box.space"><ttl>???TITLE???</ttl><xreftext>box.space</xreftext></obj><obj element="code" href="#box.index" number="" targetptr="box.index"><ttl>???TITLE???</ttl><xreftext>box.index</xreftext></obj><div element="section" href="#idp880288" number=""><ttl>Limitation of stored programs</ttl><xreftext>the section called “Limitation of stored programs”</xreftext></div></div></div><div element="chapter" href="#replication" number="5" targetptr="replication"><ttl>Replication</ttl><xreftext>Chapter 5, <i>Replication</i></xreftext><div element="section" href="#idp263808" number=""><ttl>Replication architecture</ttl><xreftext>the section called “Replication architecture”</xreftext></div><div element="section" href="#idm18496" number=""><ttl>Setting up the master</ttl><xreftext>the section called “Setting up the master”</xreftext></div><div element="section" href="#idp395232" number=""><ttl>Setting up a replica</ttl><xreftext>the section called “Setting up a replica”</xreftext></div><div element="section" href="#idp29680" number=""><ttl>Recovering from a degraded state</ttl><xreftext>the section called “Recovering from a degraded state”</xreftext></div></div><div element="chapter" href="#configuration-reference" number="6" targetptr="configuration-reference"><ttl>Configuration reference</ttl><xreftext>Chapter 6, <i>Configuration reference</i></xreftext><div element="section" href="#idp912560" number=""><ttl>Command line options</ttl><xreftext>the section called “Command line options”</xreftext><obj element="listitem" href="#help-option" number="" targetptr="help-option"><ttl>???TITLE???</ttl><xreftext/></obj><obj element="listitem" href="#version-option" number="" targetptr="version-option"><ttl>???TITLE???</ttl><xreftext/></obj><obj element="listitem" href="#config-option" number="" targetptr="config-option"><ttl>???TITLE???</ttl><xreftext/></obj><obj element="option" href="#init-storage-option" number="" targetptr="init-storage-option"><ttl>???TITLE???</ttl><xreftext>--init-storage</xreftext></obj><obj element="option" href="#cat-option" number="" targetptr="cat-option"><ttl>???TITLE???</ttl><xreftext>--cat</xreftext></obj></div><div element="section" href="#option-file" number="" targetptr="option-file"><ttl>The option file</ttl><xreftext>option file</xreftext><obj element="table" href="#idp925232" number="6.1"><ttl>Basic parameters</ttl><xreftext>Table 6.1, “Basic parameters”</xreftext></obj><obj element="entry" href="#work_dir" number="" targetptr="work_dir"><ttl>???TITLE???</ttl><xreftext>work_dir</xreftext></obj><obj element="entry" href="#wal_dir" number="" targetptr="wal_dir"><ttl>???TITLE???</ttl><xreftext>wal_dir</xreftext></obj><obj element="entry" href="#snap_dir" number="" targetptr="snap_dir"><ttl>???TITLE???</ttl><xreftext>snap_dir</xreftext></obj><obj element="entry" href="#primary_port" number="" targetptr="primary_port"><ttl>???TITLE???</ttl><xreftext>primary_port</xreftext></obj><obj element="entry" href="#secondary_port" number="" targetptr="secondary_port"><ttl>???TITLE???</ttl><xreftext>secondary_port</xreftext></obj><obj element="entry" href="#admin_port" number="" targetptr="admin_port"><ttl>???TITLE???</ttl><xreftext>admin_port</xreftext></obj><obj element="entry" href="#custom_proc_title" number="" targetptr="custom_proc_title"><ttl>???TITLE???</ttl><xreftext>custom_proc_title</xreftext></obj><obj element="table" href="#idp974448" number="6.2"><ttl>Configuring the storage</ttl><xreftext>Table 6.2, “Configuring the storage”</xreftext></obj><obj element="anchor" href="#slab_alloc_arena" number="" targetptr="slab_alloc_arena"><ttl>???TITLE???</ttl><xreftext>slab_alloc_arena</xreftext></obj><obj element="para" href="#space" number="" targetptr="space"><ttl>???TITLE???</ttl><xreftext>the section called “The option file”</xreftext></obj><obj element="table" href="#idp1010528" number="6.3"><ttl>Binary logging and snapshots</ttl><xreftext>Table 6.3, “Binary logging and snapshots”</xreftext></obj><obj element="entry" href="#rows_per_wal" number="" targetptr="rows_per_wal"><ttl>???TITLE???</ttl><xreftext>rows_per_wal</xreftext></obj><obj element="entry" href="#wal_mode" number="" targetptr="wal_mode"><ttl>???TITLE???</ttl><xreftext>wal_mode</xreftext></obj><obj element="table" href="#idp1045376" number="6.4"><ttl>Replication</ttl><xreftext>Table 6.4, “Replication”</xreftext></obj><obj element="entry" href="#replication_port" number="" targetptr="replication_port"><ttl>???TITLE???</ttl><xreftext>replication_port</xreftext></obj><obj element="entry" href="#replication_source" number="" targetptr="replication_source"><ttl>???TITLE???</ttl><xreftext>replication_source</xreftext></obj><obj element="table" href="#idp1064352" number="6.5"><ttl>Networking</ttl><xreftext>Table 6.5, “Networking”</xreftext></obj><obj element="table" href="#idp1083120" number="6.6"><ttl>Logging</ttl><xreftext>Table 6.6, “Logging”</xreftext></obj><obj element="table" href="#idp1108016" number="6.7"><ttl>Memcached protocol support</ttl><xreftext>Table 6.7, “Memcached protocol support”</xreftext></obj><obj element="anchor" href="#memcached_port" number="" targetptr="memcached_port"><ttl>???TITLE???</ttl><xreftext>memcached_port</xreftext></obj><obj element="anchor" href="#memcached_space" number="" targetptr="memcached_space"><ttl>???TITLE???</ttl><xreftext>memcached_space</xreftext></obj><obj element="anchor" href="#memcached_expire" number="" targetptr="memcached_expire"><ttl>???TITLE???</ttl><xreftext>memcached_expire</xreftext></obj></div></div><div element="chapter" href="#connectors" number="7" targetptr="connectors"><ttl>Connectors</ttl><xreftext>Chapter 7, <i>Connectors</i></xreftext><div element="section" href="#idp104160" number=""><ttl>C</ttl><xreftext>the section called “C”</xreftext></div><div element="section" href="#idp91968" number=""><ttl>Perl</ttl><xreftext>the section called “Perl”</xreftext></div><div element="section" href="#idp192864" number=""><ttl>PHP</ttl><xreftext>the section called “PHP”</xreftext></div><div element="section" href="#idp891456" number=""><ttl>Python</ttl><xreftext>the section called “Python”</xreftext></div><div element="section" href="#idp188704" number=""><ttl>Ruby</ttl><xreftext>the section called “Ruby”</xreftext></div></div><div element="appendix" href="#proctitle" number="A" targetptr="proctitle"><ttl>Server process titles</ttl><xreftext>Appendix A, <i>Server process titles</i></xreftext></div><div element="appendix" href="#errcode" number="B" targetptr="errcode"><ttl>List of error codes</ttl><xreftext>Appendix B, <i>List of error codes</i></xreftext><obj element="term" href="#ER_NONMASTER" number="" targetptr="ER_NONMASTER"><ttl>???TITLE???</ttl><xreftext>ER_NONMASTER</xreftext></obj><obj element="term" href="#ER_ILLEGAL_PARAMS" number="" targetptr="ER_ILLEGAL_PARAMS"><ttl>???TITLE???</ttl><xreftext>ER_ILLEGAL_PARAMS</xreftext></obj><obj element="term" href="#ER_TUPLE_IS_RO" number="" targetptr="ER_TUPLE_IS_RO"><ttl>???TITLE???</ttl><xreftext>ER_TUPLE_IS_RO</xreftext></obj><obj element="term" href="#ER_MEMORY_ISSUE" number="" targetptr="ER_MEMORY_ISSUE"><ttl>???TITLE???</ttl><xreftext>ER_MEMORY_ISSUE</xreftext></obj><obj element="term" href="#ER_WAL_IO" number="" targetptr="ER_WAL_IO"><ttl>???TITLE???</ttl><xreftext>ER_WAL_IO</xreftext></obj><obj element="term" href="#ER_INDEX_VIOLATION" number="" targetptr="ER_INDEX_VIOLATION"><ttl>???TITLE???</ttl><xreftext>ER_INDEX_VIOLATION</xreftext></obj><obj element="term" href="#ER_KEY_CARDINALITY" number="" targetptr="ER_KEY_CARDINALITY"><ttl>???TITLE???</ttl><xreftext>ER_KEY_CARDINALITY</xreftext></obj><obj element="term" href="#ER_NO_SUCH_SPACE" number="" targetptr="ER_NO_SUCH_SPACE"><ttl>???TITLE???</ttl><xreftext>ER_NO_SUCH_SPACE</xreftext></obj><obj element="term" href="#ER_NO_SUCH_INDEX" number="" targetptr="ER_NO_SUCH_INDEX"><ttl>???TITLE???</ttl><xreftext>ER_NO_SUCH_INDEX</xreftext></obj><obj element="term" href="#ER_PROC_LUA" number="" targetptr="ER_PROC_LUA"><ttl>???TITLE???</ttl><xreftext>ER_PROC_LUA</xreftext></obj></div></div>
+<div element="book" href="#tarantool-user-guide" number="" targetptr="tarantool-user-guide"><ttl>Tarantool/Box User Guide, version 1.4.5-219-g8cd1466</ttl><xreftext>Tarantool/Box User Guide, version 1.4.5-219-g8cd1466</xreftext><div element="chapter" href="#idp42304" number="1"><ttl>Preface</ttl><xreftext>Chapter 1, <i>Preface</i></xreftext><div element="section" href="#preface" number="" targetptr="preface"><ttl>Tarantool/Box: an overview</ttl><xreftext>the section called “Tarantool/Box: an overview”</xreftext></div><div element="section" href="#idp199536" number=""><ttl>Conventions</ttl><xreftext>the section called “Conventions”</xreftext></div><div element="section" href="#idp208432" number=""><ttl>Reporting bugs</ttl><xreftext>the section called “Reporting bugs”</xreftext></div></div><div element="chapter" href="#idm37968" number="2"><ttl>Getting started</ttl><xreftext>Chapter 2, <i>Getting started</i></xreftext></div><div element="chapter" href="#data-and-persistence" number="3" targetptr="data-and-persistence"><ttl>Data model and data persitence</ttl><xreftext>Chapter 3, <i>Data model and data persitence</i></xreftext><div element="section" href="#idp26544" number=""><ttl>Dynamic data model</ttl><xreftext>the section called “Dynamic data model”</xreftext></div><div element="section" href="#idp394448" number=""><ttl>Data persistence</ttl><xreftext>the section called “Data persistence”</xreftext></div></div><div element="chapter" href="#language-reference" number="4" targetptr="language-reference"><ttl>Language reference</ttl><xreftext>Chapter 4, <i>Language reference</i></xreftext><div element="section" href="#idp671792" number=""><ttl>Data manipulation</ttl><xreftext>the section called “Data manipulation”</xreftext><div element="section" href="#idp667040" number=""><ttl>Memcached protocol</ttl><xreftext>the section called “Memcached protocol”</xreftext></div></div><div element="section" href="#idp664144" number=""><ttl>Administrative console</ttl><xreftext>the section called “Administrative console”</xreftext><obj element="term" href="#save-snapshot" number="" targetptr="save-snapshot"><ttl>???TITLE???</ttl><xreftext>SAVE SNAPSHOT</xreftext></obj><obj element="term" href="#reload-configuration" number="" targetptr="reload-configuration"><ttl>???TITLE???</ttl><xreftext>RELOAD CONFIGURATION</xreftext></obj><obj element="term" href="#show-configuration" number="" targetptr="show-configuration"><ttl>???TITLE???</ttl><xreftext>SHOW CONFIGURATION</xreftext></obj><obj element="term" href="#show-info" number="" targetptr="show-info"><ttl>???TITLE???</ttl><xreftext>SHOW INFO</xreftext></obj><obj element="term" href="#show-stat" number="" targetptr="show-stat"><ttl>???TITLE???</ttl><xreftext>SHOW STAT</xreftext></obj><obj element="term" href="#show-slab" number="" targetptr="show-slab"><ttl>???TITLE???</ttl><xreftext>SHOW SLAB</xreftext></obj><obj element="term" href="#show-palloc" number="" targetptr="show-palloc"><ttl>???TITLE???</ttl><xreftext>SHOW PALLOC</xreftext></obj><obj element="term" href="#save-coredump" number="" targetptr="save-coredump"><ttl>???TITLE???</ttl><xreftext>SAVE COREDUMP</xreftext></obj><obj element="term" href="#show-fiber" number="" targetptr="show-fiber"><ttl>???TITLE???</ttl><xreftext>SHOW FIBER</xreftext></obj><obj element="term" href="#lua-command" number="" targetptr="lua-command"><ttl>???TITLE???</ttl><xreftext>LUA ...</xreftext></obj></div><div element="section" href="#stored-procedures" number="" targetptr="stored-procedures"><ttl>Writing stored procedures in Lua</ttl><xreftext>the section called “Writing stored procedures in Lua”</xreftext><obj element="code" href="#box" number="" targetptr="box"><ttl>???TITLE???</ttl><xreftext>box</xreftext></obj><obj element="code" href="#box.tuple" number="" targetptr="box.tuple"><ttl>???TITLE???</ttl><xreftext>box.tuple</xreftext></obj><obj element="code" href="#box.space" number="" targetptr="box.space"><ttl>???TITLE???</ttl><xreftext>box.space</xreftext></obj><obj element="code" href="#box.index" number="" targetptr="box.index"><ttl>???TITLE???</ttl><xreftext>box.index</xreftext></obj><div element="section" href="#idp880464" number=""><ttl>Limitation of stored procedures</ttl><xreftext>the section called “Limitation of stored procedures”</xreftext></div></div></div><div element="chapter" href="#replication" number="5" targetptr="replication"><ttl>Replication</ttl><xreftext>Chapter 5, <i>Replication</i></xreftext><div element="section" href="#idp275200" number=""><ttl>Replication architecture</ttl><xreftext>the section called “Replication architecture”</xreftext></div><div element="section" href="#idp41184" number=""><ttl>Setting up the master</ttl><xreftext>the section called “Setting up the master”</xreftext></div><div element="section" href="#idm31856" number=""><ttl>Setting up a replica</ttl><xreftext>the section called “Setting up a replica”</xreftext></div><div element="section" href="#idp288992" number=""><ttl>Recovering from a degraded state</ttl><xreftext>the section called “Recovering from a degraded state”</xreftext></div></div><div element="chapter" href="#configuration-reference" number="6" targetptr="configuration-reference"><ttl>Configuration reference</ttl><xreftext>Chapter 6, <i>Configuration reference</i></xreftext><div element="section" href="#idp912960" number=""><ttl>Command line options</ttl><xreftext>the section called “Command line options”</xreftext><obj element="listitem" href="#help-option" number="" targetptr="help-option"><ttl>???TITLE???</ttl><xreftext/></obj><obj element="listitem" href="#version-option" number="" targetptr="version-option"><ttl>???TITLE???</ttl><xreftext/></obj><obj element="listitem" href="#config-option" number="" targetptr="config-option"><ttl>???TITLE???</ttl><xreftext/></obj><obj element="option" href="#init-storage-option" number="" targetptr="init-storage-option"><ttl>???TITLE???</ttl><xreftext>--init-storage</xreftext></obj><obj element="option" href="#cat-option" number="" targetptr="cat-option"><ttl>???TITLE???</ttl><xreftext>--cat</xreftext></obj></div><div element="section" href="#option-file" number="" targetptr="option-file"><ttl>The option file</ttl><xreftext>option file</xreftext><obj element="table" href="#idp925584" number="6.1"><ttl>Basic parameters</ttl><xreftext>Table 6.1, “Basic parameters”</xreftext></obj><obj element="entry" href="#work_dir" number="" targetptr="work_dir"><ttl>???TITLE???</ttl><xreftext>work_dir</xreftext></obj><obj element="entry" href="#wal_dir" number="" targetptr="wal_dir"><ttl>???TITLE???</ttl><xreftext>wal_dir</xreftext></obj><obj element="entry" href="#snap_dir" number="" targetptr="snap_dir"><ttl>???TITLE???</ttl><xreftext>snap_dir</xreftext></obj><obj element="entry" href="#primary_port" number="" targetptr="primary_port"><ttl>???TITLE???</ttl><xreftext>primary_port</xreftext></obj><obj element="entry" href="#secondary_port" number="" targetptr="secondary_port"><ttl>???TITLE???</ttl><xreftext>secondary_port</xreftext></obj><obj element="entry" href="#admin_port" number="" targetptr="admin_port"><ttl>???TITLE???</ttl><xreftext>admin_port</xreftext></obj><obj element="entry" href="#custom_proc_title" number="" targetptr="custom_proc_title"><ttl>???TITLE???</ttl><xreftext>custom_proc_title</xreftext></obj><obj element="table" href="#idp974864" number="6.2"><ttl>Configuring the storage</ttl><xreftext>Table 6.2, “Configuring the storage”</xreftext></obj><obj element="anchor" href="#slab_alloc_arena" number="" targetptr="slab_alloc_arena"><ttl>???TITLE???</ttl><xreftext>slab_alloc_arena</xreftext></obj><obj element="para" href="#space" number="" targetptr="space"><ttl>???TITLE???</ttl><xreftext>the section called “The option file”</xreftext></obj><obj element="table" href="#idp1010880" number="6.3"><ttl>Binary logging and snapshots</ttl><xreftext>Table 6.3, “Binary logging and snapshots”</xreftext></obj><obj element="entry" href="#rows_per_wal" number="" targetptr="rows_per_wal"><ttl>???TITLE???</ttl><xreftext>rows_per_wal</xreftext></obj><obj element="entry" href="#wal_mode" number="" targetptr="wal_mode"><ttl>???TITLE???</ttl><xreftext>wal_mode</xreftext></obj><obj element="table" href="#idp1045856" number="6.4"><ttl>Replication</ttl><xreftext>Table 6.4, “Replication”</xreftext></obj><obj element="entry" href="#replication_port" number="" targetptr="replication_port"><ttl>???TITLE???</ttl><xreftext>replication_port</xreftext></obj><obj element="entry" href="#replication_source" number="" targetptr="replication_source"><ttl>???TITLE???</ttl><xreftext>replication_source</xreftext></obj><obj element="table" href="#idp1064832" number="6.5"><ttl>Networking</ttl><xreftext>Table 6.5, “Networking”</xreftext></obj><obj element="table" href="#idp1083600" number="6.6"><ttl>Logging</ttl><xreftext>Table 6.6, “Logging”</xreftext></obj><obj element="table" href="#idp1108496" number="6.7"><ttl>Memcached protocol support</ttl><xreftext>Table 6.7, “Memcached protocol support”</xreftext></obj><obj element="anchor" href="#memcached_port" number="" targetptr="memcached_port"><ttl>???TITLE???</ttl><xreftext>memcached_port</xreftext></obj><obj element="anchor" href="#memcached_space" number="" targetptr="memcached_space"><ttl>???TITLE???</ttl><xreftext>memcached_space</xreftext></obj><obj element="anchor" href="#memcached_expire" number="" targetptr="memcached_expire"><ttl>???TITLE???</ttl><xreftext>memcached_expire</xreftext></obj></div></div><div element="chapter" href="#connectors" number="7" targetptr="connectors"><ttl>Connectors</ttl><xreftext>Chapter 7, <i>Connectors</i></xreftext><div element="section" href="#idm11744" number=""><ttl>C</ttl><xreftext>the section called “C”</xreftext></div><div element="section" href="#idp187680" number=""><ttl>Perl</ttl><xreftext>the section called “Perl”</xreftext></div><div element="section" href="#idp223696" number=""><ttl>PHP</ttl><xreftext>the section called “PHP”</xreftext></div><div element="section" href="#idp697056" number=""><ttl>Python</ttl><xreftext>the section called “Python”</xreftext></div><div element="section" href="#idp861616" number=""><ttl>Ruby</ttl><xreftext>the section called “Ruby”</xreftext></div></div><div element="appendix" href="#proctitle" number="A" targetptr="proctitle"><ttl>Server process titles</ttl><xreftext>Appendix A, <i>Server process titles</i></xreftext></div><div element="appendix" href="#errcode" number="B" targetptr="errcode"><ttl>List of error codes</ttl><xreftext>Appendix B, <i>List of error codes</i></xreftext><obj element="term" href="#ER_NONMASTER" number="" targetptr="ER_NONMASTER"><ttl>???TITLE???</ttl><xreftext>ER_NONMASTER</xreftext></obj><obj element="term" href="#ER_ILLEGAL_PARAMS" number="" targetptr="ER_ILLEGAL_PARAMS"><ttl>???TITLE???</ttl><xreftext>ER_ILLEGAL_PARAMS</xreftext></obj><obj element="term" href="#ER_TUPLE_IS_RO" number="" targetptr="ER_TUPLE_IS_RO"><ttl>???TITLE???</ttl><xreftext>ER_TUPLE_IS_RO</xreftext></obj><obj element="term" href="#ER_MEMORY_ISSUE" number="" targetptr="ER_MEMORY_ISSUE"><ttl>???TITLE???</ttl><xreftext>ER_MEMORY_ISSUE</xreftext></obj><obj element="term" href="#ER_WAL_IO" number="" targetptr="ER_WAL_IO"><ttl>???TITLE???</ttl><xreftext>ER_WAL_IO</xreftext></obj><obj element="term" href="#ER_INDEX_VIOLATION" number="" targetptr="ER_INDEX_VIOLATION"><ttl>???TITLE???</ttl><xreftext>ER_INDEX_VIOLATION</xreftext></obj><obj element="term" href="#ER_KEY_CARDINALITY" number="" targetptr="ER_KEY_CARDINALITY"><ttl>???TITLE???</ttl><xreftext>ER_KEY_CARDINALITY</xreftext></obj><obj element="term" href="#ER_NO_SUCH_SPACE" number="" targetptr="ER_NO_SUCH_SPACE"><ttl>???TITLE???</ttl><xreftext>ER_NO_SUCH_SPACE</xreftext></obj><obj element="term" href="#ER_NO_SUCH_INDEX" number="" targetptr="ER_NO_SUCH_INDEX"><ttl>???TITLE???</ttl><xreftext>ER_NO_SUCH_INDEX</xreftext></obj><obj element="term" href="#ER_PROC_LUA" number="" targetptr="ER_PROC_LUA"><ttl>???TITLE???</ttl><xreftext>ER_PROC_LUA</xreftext></obj></div></div>
diff --git a/include/errcode.h b/include/errcode.h
index 99e0531496484fa678c8be2a11642b263c1bcc5e..2875d6e625f7bdfff7426ae2295fd7c78759cd47 100644
--- a/include/errcode.h
+++ b/include/errcode.h
@@ -99,7 +99,7 @@ enum { TNT_ERRMSG_MAX = 512 };
 	/* 44 */_(ER_UNKNOWN_UPDATE_OP,		2, "Unknown UPDATE operation") \
 	/* 45 */_(ER_EXACT_MATCH,		2, "Partial key in an exact match (key field count: %d, expected: %d)") \
 	/* 46 */_(ER_UNUSED46,			2, "Unused46") \
-	/* 47 */_(ER_KEY_CARDINALITY,		2, "Key cardinality %d is greater than index cardinality %d") \
+	/* 47 */_(ER_KEY_PART_COUNT,		2, "Key part count %d is greater than index part count %d") \
 	/* 48 */_(ER_PROC_RET,			2, "Return type '%s' is not supported in the binary protocol") \
 	/* 49 */_(ER_TUPLE_NOT_FOUND,		2, "Tuple doesn't exist") \
 	/* 50 */_(ER_NO_SUCH_PROC,		2, "Procedure '%.*s' is not defined") \
diff --git a/include/log_io.h b/include/log_io.h
index e611b199b85b1e7574d86e3bd1249e176a51715a..b3f27b2b4329b4a9625b5d7d05348e272a27f7f7 100644
--- a/include/log_io.h
+++ b/include/log_io.h
@@ -133,9 +133,6 @@ struct recovery_state {
 	struct wait_lsn wait_lsn;
 
 	bool finalize;
-
-	/* Points to module-specific state */
-	void *data;
 };
 
 struct recovery_state *recovery_state;
@@ -175,19 +172,17 @@ static inline struct row_v11 *row_v11(const struct tbuf *t)
 	return (struct row_v11 *)t->data;
 }
 
-struct tbuf *convert_to_v11(struct tbuf *orig, u16 tag, u64 cookie, i64 lsn);
-
 void recovery_init(const char *snap_dirname, const char *xlog_dirname,
 		   row_handler row_handler,
 		   int rows_per_wal, const char *wal_mode,
 		   double wal_fsync_delay,
-		   int flags, void *data);
+		   int flags);
 void recovery_update_mode(const char *wal_mode, double fsync_delay);
 void recovery_update_io_rate_limit(double new_limit);
 void recovery_free();
 int recover(struct recovery_state *, i64 lsn);
-void recover_follow(struct recovery_state *r, ev_tstamp wal_dir_rescan_delay);
-void recover_finalize(struct recovery_state *r);
+void recovery_follow_local(struct recovery_state *r, ev_tstamp wal_dir_rescan_delay);
+void recovery_finalize(struct recovery_state *r);
 int wal_write(struct recovery_state *r, u16 tag, u16 op,
 	      u64 cookie, i64 lsn, struct tbuf *data);
 
diff --git a/mod/box/box.m b/mod/box/box.m
index b61f53117b5b8095e53dc605c149398a35a49de4..e7abf9b68eb00b5fd6f1809d3190798e7a856a53 100644
--- a/mod/box/box.m
+++ b/mod/box/box.m
@@ -1844,7 +1844,7 @@ box_enter_master_or_replica_mode(struct tarantool_cfg *conf)
 static void
 box_leave_local_standby_mode(void *data __attribute__((unused)))
 {
-	recover_finalize(recovery_state);
+	recovery_finalize(recovery_state);
 
 	box_enter_master_or_replica_mode(&cfg);
 }
@@ -2139,7 +2139,7 @@ mod_init(void)
 	recovery_init(cfg.snap_dir, cfg.wal_dir,
 		      recover_row, cfg.rows_per_wal, cfg.wal_mode,
 		      cfg.wal_fsync_delay,
-		      init_storage ? RECOVER_READONLY : 0, NULL);
+		      init_storage ? RECOVER_READONLY : 0);
 
 	recovery_update_io_rate_limit(cfg.snap_io_rate_limit);
 	recovery_setup_panic(recovery_state, cfg.panic_on_snap_error, cfg.panic_on_wal_error);
@@ -2168,7 +2168,7 @@ mod_init(void)
 
 	if (cfg.local_hot_standby) {
 		say_info("starting local hot standby");
-		recover_follow(recovery_state, cfg.wal_dir_rescan_delay);
+		recovery_follow_local(recovery_state, cfg.wal_dir_rescan_delay);
 		snprintf(status, sizeof(status), "hot_standby");
 		title("hot_standby");
 	}
diff --git a/mod/box/index.m b/mod/box/index.m
index 5d6bdb97a554245f1641b1d0f566c21f1ca10dd2..d9a896d6ca70c11d2030565a7408d21d878be1b1 100644
--- a/mod/box/index.m
+++ b/mod/box/index.m
@@ -199,7 +199,7 @@ iterator_first_equal(struct iterator *it)
 - (void) checkKeyParts: (int) part_count :(bool) partial_key_allowed
 {
 	if (part_count > key_def->part_count)
-		tnt_raise(ClientError, :ER_KEY_CARDINALITY,
+		tnt_raise(ClientError, :ER_KEY_PART_COUNT,
 			  part_count, key_def->part_count);
 	if (!partial_key_allowed && part_count < key_def->part_count)
 		tnt_raise(ClientError, :ER_EXACT_MATCH,
diff --git a/src/log_io.m b/src/log_io.m
index 31d201472dad7ed26509fa37d92a287415280b38..e7bd3a8c9725778c8417097d7332b8e1b5710bfc 100644
--- a/src/log_io.m
+++ b/src/log_io.m
@@ -45,6 +45,67 @@
 #include <crc32.h>
 #include <tarantool_pthread.h>
 #include "errinj.h"
+/*
+ * Recovery subsystem
+ * ------------------
+ *
+ * A facade of the recovery subsystem is struct recovery_state,
+ * which is a singleton.
+ *
+ * Depending on the configuration, start-up parameters, the
+ * actual task being performed, the recovery can be
+ * in a different state.
+ *
+ * The main factors influencing recovery state are:
+ * - temporal: whether or not the instance is just booting
+ *   from a snapshot, is in 'local hot standby mode', or
+ *   is already accepting requests
+ * - topological: whether or not it is a master instance
+ *   or a replica
+ * - task based: whether it's a master process,
+ *   snapshot saving process or a replication relay.
+ *
+ * Depending on the above factors, recovery can be in two main
+ * operation modes: "read mode", recovering in-memory state
+ * from existing data, and "write mode", i.e. recording on
+ * disk changes of the in-memory state.
+ *
+ * Let's enumerate all possible distinct states of recovery:
+ *
+ * Read mode
+ * ---------
+ * IR - initial recovery, initiated right after server start:
+ * reading data from the snapshot and existing WALs
+ * and restoring the in-memory state
+ * IRR - initial replication relay mode, reading data from
+ * existing WALs (xlogs) and sending it to the client.
+ *
+ * HS - standby mode, entered once all existing WALs are read:
+ * following the WAL directory for all changes done by the master
+ * and updating the in-memory state
+ * RR - replication relay, following the WAL directory for all
+ * changes done by the master and sending them to the
+ * replica
+ *
+ * Write mode
+ * ----------
+ * M - master mode, recording in-memory state changes in the WAL
+ * R - replica mode, receiving changes from the master and
+ * recording them in the WAL
+ * S - snapshot mode, writing entire in-memory state to a compact
+ * snapshot file.
+ *
+ * The following state transitions are possible/supported:
+ *
+ * recovery_init() -> IR | IRR # recover()
+ * IR -> HS         # recovery_follow_local()
+ * IRR -> RR        # recovery_follow_local()
+ * HS -> M          # recovery_finalize()
+ * M -> R           # recovery_follow_remote()
+ * R -> M           # recovery_stop_remote()
+ * M -> S           # snapshot()
+ * R -> S           # snapshot()
+ */
 
 const u16 snap_tag = -1;
 const u16 wal_tag = -2;
@@ -698,7 +759,9 @@ error:
 
 
 static struct log_io *
-log_io_open_for_read(struct recovery_state *recover, struct log_io_class *class, i64 lsn, int suffix,
+log_io_open_for_read(struct recovery_state *recover,
+		     struct log_io_class *class,
+		     i64 lsn, int suffix,
 		     const char *filename)
 {
 	const char *errmsg;
@@ -721,7 +784,7 @@ log_io_open_for_read(struct recovery_state *recover, struct log_io_class *class,
 		strncpy(l->filename, filename, PATH_MAX);
 	}
 
-	say_debug("%s: opening %s'", __func__, l->filename);
+	say_debug("%s: opening %s", __func__, l->filename);
 
 	l->f = fopen(l->filename, "r");
 	if (l->f == NULL) {
@@ -743,19 +806,22 @@ error:
 	return NULL;
 }
 
+/**
+ * In case of error, writes a message to the server log
+ * and sets errno.
+ */
 struct log_io *
-log_io_open_for_write(struct recovery_state *recover, struct log_io_class *class, i64 lsn,
-		      int suffix, int *save_errno)
+log_io_open_for_write(struct recovery_state *recover,
+		      struct log_io_class *class, i64 lsn, int suffix)
 {
 	struct log_io *l = NULL;
 	int fd;
 	char *dot;
 	bool exists;
-	const char *errmsg;
+	int save_errno;
 
 	l = calloc(1, sizeof(*l));
 	if (l == NULL) {
-		*save_errno = errno;
 		say_syserror("calloc");
 		return NULL;
 	}
@@ -778,8 +844,7 @@ log_io_open_for_write(struct recovery_state *recover, struct log_io_class *class
 		exists = access(l->filename, F_OK) == 0;
 		*dot = '.';
 		if (exists) {
-			*save_errno = EEXIST;
-			errmsg = "exists";
+			errno = EEXIST;
 			goto error;
 		}
 	}
@@ -790,29 +855,24 @@ log_io_open_for_write(struct recovery_state *recover, struct log_io_class *class
 	 */
 	fd = open(l->filename,
 		  O_WRONLY | O_CREAT | O_EXCL | l->class->open_wflags, 0664);
-	if (fd < 0) {
-		*save_errno = errno;
-		errmsg = strerror(errno);
+	if (fd < 0)
 		goto error;
-	}
 
 	l->f = fdopen(fd, "w");
-	if (l->f == NULL) {
-		*save_errno = errno;
-		errmsg = strerror(errno);
+	if (l->f == NULL)
 		goto error;
-	}
 
 	say_info("creating `%s'", l->filename);
 	write_header(l);
 	return l;
 
 error:
-	say_error("%s: failed to open `%s': %s", __func__, l->filename,
-		  errmsg);
+	save_errno = errno; /* Preserve over fclose()/free() */
+	say_syserror("%s: failed to open `%s'", __func__, l->filename);
 	if (l->f != NULL)
 		fclose(l->f);
 	free(l);
+	errno = save_errno;
 	return NULL;
 }
 
@@ -979,8 +1039,11 @@ recover_wal(struct recovery_state *r, struct log_io *l)
 	}
 }
 
-/*
- * this function will not close r->current_wal if recovery was successful
+/** Find out if there are new .xlog files since the current
+ * LSN, and read them all up.
+ *
+ * This function will not close r->current_wal if
+ * recovery was successful.
  */
 static int
 recover_remaining_wals(struct recovery_state *r)
@@ -998,7 +1061,10 @@ recover_remaining_wals(struct recovery_state *r)
 		goto recover_current_wal;
 
 	while (r->confirmed_lsn < wal_greatest_lsn) {
-		/* if newer WAL appeared in directory before current_wal was fully read try reread last */
+		/*
+		 * If a newer WAL appeared in the directory before
+		 * current_wal was fully read, try re-reading
+		 * one last time. */
 		if (r->current_wal != NULL) {
 			if (r->current_wal->retry++ < 3) {
 				say_warn("try reread `%s' despite newer WAL exists",
@@ -1011,9 +1077,10 @@ recover_remaining_wals(struct recovery_state *r)
 			}
 		}
 
-		current_lsn = r->confirmed_lsn + 1;	/* TODO: find better way looking for next xlog */
-		next_wal = log_io_open_for_read(r, r->wal_class, current_lsn, 0, NULL);
-
+		/* TODO: find a better way of finding the next xlog */
+		current_lsn = r->confirmed_lsn + 1;
+		next_wal = log_io_open_for_read(r, r->wal_class, current_lsn,
+						0, NULL);
 		/*
 		 * When doing final recovery, and dealing with the
 		 * last file, try opening .<suffix>.inprogress.
@@ -1035,30 +1102,33 @@ recover_remaining_wals(struct recovery_state *r)
 			break;
 		}
 
-
 		assert(r->current_wal == NULL);
 		r->current_wal = next_wal;
 		say_info("recover from `%s'", r->current_wal->filename);
 
-	      recover_current_wal:
+recover_current_wal:
 		rows_before = r->current_wal->rows;
 		result = recover_wal(r, r->current_wal);
 		if (result < 0) {
-			say_error("failure reading from %s", r->current_wal->filename);
+			say_error("failure reading from %s",
+				  r->current_wal->filename);
 			break;
 		}
 
-		if (r->current_wal->rows > 0 && r->current_wal->rows != rows_before)
+		if (r->current_wal->rows > 0 &&
+		    r->current_wal->rows != rows_before) {
 			r->current_wal->retry = 0;
-
-		/* rows == 0 could possible indicate to an empty WAL */
+		}
+		/* rows == 0 could indicate an empty WAL */
 		if (r->current_wal->rows == 0) {
-			say_error("read zero records from %s", r->current_wal->filename);
+			say_error("read zero records from %s",
+				  r->current_wal->filename);
 			break;
 		}
 
 		if (result == LOG_EOF) {
-			say_info("done `%s' confirmed_lsn:%" PRIi64, r->current_wal->filename,
+			say_info("done `%s' confirmed_lsn:%" PRIi64,
+				 r->current_wal->filename,
 				 r->confirmed_lsn);
 			log_io_close(&r->current_wal);
 		}
@@ -1133,10 +1203,10 @@ recover(struct recovery_state *r, i64 lsn)
 	return result;
 }
 
-static void recover_follow_file(ev_stat *w, int revents __attribute__((unused)));
+static void recovery_follow_file(ev_stat *w, int revents __attribute__((unused)));
 
 static void
-recover_follow_dir(ev_timer *w, int revents __attribute__((unused)))
+recovery_follow_dir(ev_timer *w, int revents __attribute__((unused)))
 {
 	struct recovery_state *r = w->data;
 	struct log_io *wal = r->current_wal;
@@ -1147,13 +1217,13 @@ recover_follow_dir(ev_timer *w, int revents __attribute__((unused)))
 	/* recover_remaining_wals found new wal */
 	if (r->current_wal != NULL && wal != r->current_wal) {
 		ev_stat *stat = &r->current_wal->stat;
-		ev_stat_init(stat, recover_follow_file, r->current_wal->filename, 0.);
+		ev_stat_init(stat, recovery_follow_file, r->current_wal->filename, 0.);
 		ev_stat_start(stat);
 	}
 }
 
 static void
-recover_follow_file(ev_stat *w, int revents __attribute__((unused)))
+recovery_follow_file(ev_stat *w, int revents __attribute__((unused)))
 {
 	struct recovery_state *r = w->data;
 	int result;
@@ -1161,28 +1231,29 @@ recover_follow_file(ev_stat *w, int revents __attribute__((unused)))
 	if (result < 0)
 		panic("recover failed");
 	if (result == LOG_EOF) {
-		say_info("done `%s' confirmed_lsn:%" PRIi64, r->current_wal->filename,
+		say_info("done `%s' confirmed_lsn:%" PRIi64,
+			 r->current_wal->filename,
 			 r->confirmed_lsn);
 		log_io_close(&r->current_wal);
-		recover_follow_dir((ev_timer *)w, 0);
+		recovery_follow_dir((ev_timer *)w, 0);
 	}
 }
 
 void
-recover_follow(struct recovery_state *r, ev_tstamp wal_dir_rescan_delay)
+recovery_follow_local(struct recovery_state *r, ev_tstamp wal_dir_rescan_delay)
 {
-	ev_timer_init(&r->wal_timer, recover_follow_dir,
+	ev_timer_init(&r->wal_timer, recovery_follow_dir,
 		      wal_dir_rescan_delay, wal_dir_rescan_delay);
 	ev_timer_start(&r->wal_timer);
 	if (r->current_wal != NULL) {
 		ev_stat *stat = &r->current_wal->stat;
-		ev_stat_init(stat, recover_follow_file, r->current_wal->filename, 0.);
+		ev_stat_init(stat, recovery_follow_file, r->current_wal->filename, 0.);
 		ev_stat_start(stat);
 	}
 }
 
 void
-recover_finalize(struct recovery_state *r)
+recovery_finalize(struct recovery_state *r)
 {
 	int result;
 
@@ -1430,11 +1501,9 @@ write_to_disk(struct recovery_state *r, struct wal_write_request *req)
 	bool is_bulk_end = STAILQ_NEXT(req, wal_fifo_entry) == NULL;
 
 	if (r->current_wal == NULL) {
-		int unused;
 		/* Open WAL with '.inprogress' suffix. */
 		r->current_wal =
-			log_io_open_for_write(r, r->wal_class, req->lsn, -1,
-					      &unused);
+			log_io_open_for_write(r, r->wal_class, req->lsn, -1);
 	}
 	else if (r->current_wal->rows == 1) {
 		/* rename WAL after first successful write to name
@@ -1599,8 +1668,7 @@ wal_write(struct recovery_state *r, u16 tag, u16 op, u64 cookie,
 void
 recovery_init(const char *snap_dirname, const char *wal_dirname,
 	      row_handler row_handler, int rows_per_wal,
-	      const char *wal_mode, double wal_fsync_delay,
-	      int flags, void *data)
+	      const char *wal_mode, double wal_fsync_delay, int flags)
 {
 	assert(recovery_state == NULL);
 	recovery_state = p0alloc(eter_pool, sizeof(struct recovery_state));
@@ -1611,7 +1679,6 @@ recovery_init(const char *snap_dirname, const char *wal_dirname,
 
 	r->wal_timer.data = r;
 	r->row_handler = row_handler;
-	r->data = data;
 	r->remote_recovery = NULL;
 
 	r->snap_class = snapshot_class_create(snap_dirname);
@@ -1760,13 +1827,12 @@ snapshot_save(struct recovery_state *r, void (*f) (struct log_io_iter *))
 	struct log_io *snap;
 	char final_filename[PATH_MAX + 1];
 	char *dot;
-	int save_errno;
 
 	memset(&i, 0, sizeof(i));
 
-	snap = log_io_open_for_write(r, r->snap_class, r->confirmed_lsn, -1, &save_errno);
+	snap = log_io_open_for_write(r, r->snap_class, r->confirmed_lsn, -1);
 	if (snap == NULL)
-		panic_status(save_errno, "can't open snap for writing");
+		panic_status(errno, "Failed to save snapshot: failed to open file in write mode.");
 
 	iter_open(snap, &i, write_rows);
 
diff --git a/src/replication.m b/src/replication.m
index efc782d9a40aa35893faf7e7a6526e98caa796e6..e6388b6c5c40122992b710e237ce9bfd6821ed21 100644
--- a/src/replication.m
+++ b/src/replication.m
@@ -560,7 +560,6 @@ replication_relay_loop(int client_sock)
 {
 	char name[FIBER_NAME_MAXLEN];
 	struct sigaction sa;
-	struct recovery_state *log_io;
 	struct tbuf *ver;
 	i64 lsn;
 	ssize_t r;
@@ -617,12 +616,10 @@ replication_relay_loop(int client_sock)
 	/* Initialize the recovery process */
 	recovery_init(NULL, cfg.wal_dir, replication_relay_send_row,
 		      INT32_MAX, "fsync_delay", 0,
-		      RECOVER_READONLY, false);
+		      RECOVER_READONLY);
 
-	log_io = recovery_state;
-
-	recover(log_io, lsn);
-	recover_follow(log_io, 0.1);
+	recover(recovery_state, lsn);
+	recovery_follow_local(recovery_state, 0.1);
 
 	ev_loop(0);
 
diff --git a/src/salloc.m b/src/salloc.m
index efe340ab113ba6c2b3104d206bc45fcd237f411f..9559146f1974757ac655d25d73105ea87bfc912b 100644
--- a/src/salloc.m
+++ b/src/salloc.m
@@ -351,8 +351,8 @@ slab_stat(struct tbuf *t)
 			    (int)slab_classes[i].item_size, slabs, items, used, free);
 
 	}
-	tbuf_printf(t, "  items_used: %.2f" CRLF, (double)total_used / arena.size * 100);
-	tbuf_printf(t, "  arena_used: %.2f" CRLF, (double)arena.used / arena.size * 100);
+	tbuf_printf(t, "  items_used: %.2f%%" CRLF, (double)total_used / arena.size * 100);
+	tbuf_printf(t, "  arena_used: %.2f%%" CRLF, (double)arena.used / arena.size * 100);
 }
 
 void
diff --git a/test/box_big/hash.result b/test/box_big/hash.result
index 1726ff069a7a6444624f061bc6b19f88c70c2673..1083930a5ad75f84254e78906a589c066ea23fe4 100644
--- a/test/box_big/hash.result
+++ b/test/box_big/hash.result
@@ -100,7 +100,7 @@ error: 'Supplied key field type does not match index type: expected u32'
 ...
 lua box.space[10]:select(0, 1, 2)
 ---
-error: 'Key cardinality 2 is greater than index cardinality 1'
+error: 'Key part count 2 is greater than index part count 1'
 ...
 
 #-----------------------------------------------------------------------------#
@@ -141,7 +141,7 @@ error: 'Supplied key field type does not match index type: expected u32'
 ...
 lua box.space[10]:delete(1, 2)
 ---
-error: 'Key cardinality 2 is greater than index cardinality 1'
+error: 'Key part count 2 is greater than index part count 1'
 ...
 
 #=============================================================================#
@@ -245,7 +245,7 @@ error: 'Supplied key field type does not match index type: expected u64'
 ...
 lua box.space[11]:select(0, '00000001', '00000002')
 ---
-error: 'Key cardinality 2 is greater than index cardinality 1'
+error: 'Key part count 2 is greater than index part count 1'
 ...
 
 #-----------------------------------------------------------------------------#
@@ -286,7 +286,7 @@ error: 'Supplied key field type does not match index type: expected u64'
 ...
 lua box.space[11]:delete('00000001', '00000002')
 ---
-error: 'Key cardinality 2 is greater than index cardinality 1'
+error: 'Key part count 2 is greater than index part count 1'
 ...
 
 #=============================================================================#
@@ -372,7 +372,7 @@ lua box.space[12]:select(0, 'key 5')
 
 lua box.space[12]:select(0, 'key 1', 'key 2')
 ---
-error: 'Key cardinality 2 is greater than index cardinality 1'
+error: 'Key part count 2 is greater than index part count 1'
 ...
 
 #-----------------------------------------------------------------------------#
@@ -409,7 +409,7 @@ lua box.space[12]:delete('key 5')
 
 lua box.space[12]:delete('key 1', 'key 2')
 ---
-error: 'Key cardinality 2 is greater than index cardinality 1'
+error: 'Key part count 2 is greater than index part count 1'
 ...
 lua box.space[10]:truncate()
 ---
diff --git a/test/box_big/lua.result b/test/box_big/lua.result
index 8024e87608230a18f495cbb1dd42742f4762e4d3..583ca0679d584dc0b00a833369a3f12429dfa36f 100644
--- a/test/box_big/lua.result
+++ b/test/box_big/lua.result
@@ -17,7 +17,7 @@ Found 1 tuple:
 # https://bugs.launchpad.net/tarantool/+bug/904208
 #
 call box.select(1, 1, 'new', 'world', 'order')
-An error occurred: ER_KEY_CARDINALITY, 'Key cardinality 3 is greater than index cardinality 2'
+An error occurred: ER_KEY_PART_COUNT, 'Key part count 3 is greater than index part count 2'
 call box.delete(1, 'brave')
 Found 1 tuple:
 ['brave', 'new', 'world']
diff --git a/test/box_big/tree_pk_multipart.result b/test/box_big/tree_pk_multipart.result
index bfcaaca1b8f6fb7b589c08f39c83b21ea40e02c8..c3c4667fa64dd764e12b973fa4ed779203874b6e 100644
--- a/test/box_big/tree_pk_multipart.result
+++ b/test/box_big/tree_pk_multipart.result
@@ -194,7 +194,7 @@ error: 'Partial key in an exact match (key field count: 2, expected: 3)'
 ...
 lua box.delete(9, 'The Wolf!', 'Vincent', 1, 'Come again?')
 ---
-error: 'Key cardinality 4 is greater than index cardinality 3'
+error: 'Key part count 4 is greater than index part count 3'
 ...
 lua box.update_ol(9, { box.upd.assign(3, '<ooops>') }, 'The Wolf!', 'Vincent', 1)
 ---
@@ -223,7 +223,7 @@ error: 'Partial key in an exact match (key field count: 2, expected: 3)'
 ...
 lua box.update_ol(9, { box.upd.assign(3, '<ooops>') }, 'The Wolf!', 'Vincent', 1, 'Come again?')
 ---
-error: 'Key cardinality 4 is greater than index cardinality 3'
+error: 'Key part count 4 is greater than index part count 3'
 ...
 lua box.space[9]:len()
 ---
diff --git a/test/lib/sql_ast.py b/test/lib/sql_ast.py
index 0f353dfb17088f39f8a9a86a517f8ac917d75a1d..fed763dc886fc734f5472b00844dac33456a3eda 100644
--- a/test/lib/sql_ast.py
+++ b/test/lib/sql_ast.py
@@ -72,7 +72,7 @@ ER = {
    44: "ER_UNKNOWN_UPDATE_OP"   ,
    45: "ER_EXACT_MATCH"         ,
    46: "ER_UNUSED46"            ,
-   47: "ER_KEY_CARDINALITY"     ,
+   47: "ER_KEY_PART_COUNT"      ,
    48: "ER_PROC_RET"            ,
    49: "ER_TUPLE_NOT_FOUND"     ,
    50: "ER_NO_SUCH_PROC"        ,