From 6f3359f840a9ea73db518edb19b0271bb85cd6d8 Mon Sep 17 00:00:00 2001 From: ocelot-inc <pgulutzan@ocelot.ca> Date: Mon, 28 Oct 2013 16:33:08 -0600 Subject: [PATCH] stored-procedures.xml update --- doc/user/stored-procedures.xml | 206 ++++++++++++++++++++------------- 1 file changed, 127 insertions(+), 79 deletions(-) diff --git a/doc/user/stored-procedures.xml b/doc/user/stored-procedures.xml index e326717c03..07a6e2d742 100644 --- a/doc/user/stored-procedures.xml +++ b/doc/user/stored-procedures.xml @@ -22,13 +22,13 @@ </para> <para> - Tarantool uses <link + 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 arithmetics.</link> + operations</link> and <link xlink:href="#tonumber64">64-bit integer arithmetic.</link> </para> </blockquote> <para> @@ -44,7 +44,7 @@ Found 1 tuple: </programlisting> In the language of the administrative console <olink targetptr="lua-command" /> evaluates an arbitrary - Lua chunk. CALL is the SQL standard statement, so its syntax + Lua chunk. CALL is an SQL standard statement, so its syntax was adopted by Tarantool command line client to invoke the CALL command of the binary protocol. </para> @@ -55,7 +55,7 @@ Found 1 tuple: parser plus the binary protocol on the <olink targetptr="primary_port" />. Since it's possible to execute any Lua chunk in the administrative console, the newly created <code - language="Pascal">function f1()</code> + language="Lua">function f1()</code> can be called there too: <programlisting><computeroutput>localhost> lua f1() --- @@ -113,7 +113,7 @@ expirationd.run_task("exprd space 0", 0, is_expired, purge, <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 + the start script fail just the same way they would fail if they were sent from a remote client. </para> <para> @@ -151,8 +151,8 @@ expirationd.run_task("exprd space 0", 0, is_expired, purge, In the binary protocol, it's only possible to <emphasis role="strong">invoke</emphasis> existing procedures, but not <emphasis role="strong">define</emphasis> - or <emphasis role="strong">alter</emphasis> them. - CALL request packet contains CALL command code (22), the name + 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 @@ -210,7 +210,7 @@ error: 1:15 expected '(' certain operations to be used by a system administrator only. </para> <para> - Every value, returned from a stored function by means of + Every value, returned from a stored function by means of a <code>return</code> clause, is converted to a Tarantool tuple. Tuples are returned as such, in binary form; a Lua scalar, such as a string or an integer, is converted to a tuple with only @@ -223,7 +223,7 @@ error: 1:15 expected '(' is sent to the client as <olink targetptr="ER_PROC_LUA" /> return code, with the original error message preserved. Similarly, an error which has occurred inside Tarantool (observed on the - client as an error code), when happens during execution of a + client as an error code), when it happens during execution of a Lua procedure, produces a genuine Lua error: <programlisting><computeroutput>localhost> lua function f1() error("oops") end --- @@ -241,7 +241,7 @@ localhost> lua pcall(box.insert, 99, 1, 'test') </para> <para> It's possible not only to invoke trivial Lua code, but call - into Tarantool storage functionality, using + into Tarantool storage functionality, using the <code>box</code> Lua library. The contents of the library can be inspected at runtime: @@ -262,7 +262,7 @@ replace: function select_range: function pack: function ...</computeroutput></programlisting> - As is shown in the listing, <code>box</code> package ships: + As is shown in the listing, the <code>box</code> package contains: <itemizedlist> <listitem><para> high-level functions, such as @@ -274,7 +274,7 @@ pack: function libraries, such as <code>cfg, space, fiber, index, tuple</code>, to access server configuration, create, resume and interrupt fibers, inspect contents of spaces, indexes - and tuples, send and receive data over network. + and tuples, send and receive data over the network. </para></listitem> </itemizedlist> </para> @@ -287,8 +287,8 @@ pack: function <para>Convert a given string or a Lua number to a 64-bit integer. The returned value supports all arithmetic operations, but uses - 64-bit integer arithmetics, rather than floating-point, - arithmetics as in the built-in number type. + 64-bit integer arithmetic, rather than floating-point + arithmetic as in the built-in number type. <bridgehead renderas="sect4">Example</bridgehead> <programlisting> localhost> lua tonumber64('123456789'), tonumber64(123456789) @@ -362,7 +362,7 @@ localhost> lua type(i), type(i*2), type(i/2), i, i*2, i/2 command. </para> <para> - Please note, that since all requests from Lua + Please note that, since all requests from Lua enter the core through <emphasis role="lua">box.process()</emphasis>, all checks and triggers run by the core automatically apply. @@ -437,7 +437,7 @@ localhost> lua box.select(5, 1, 'firstname', 'lastname') <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 in a + which one can specify offset and limit for a multi-tuple return. The server may return multiple tuples when the index is non-unique or a partial key is used for search. @@ -509,26 +509,65 @@ localhost> lua box.select(5, 1, 'firstname', 'lastname') Returns the updated tuple. <bridgehead renderas="sect4">Example</bridgehead> <programlisting> -localhost> lua box.insert(0, 0, 'hello world') ---- - - 0: {'hello world'} -... -localhost> lua box.update(0, 0, '+p', 1, 1) -- add value 1 to field #1 ---- -error: 'Field type does not match one required by operation: expected a 32-bit or 64-bit int' -... -localhost> lua box.update(0, 0, '+p', 0, 2) -- add value 2 to field 0 ---- - - 2: {'hello world'} -... -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, 1) ---- - - 2: {'Bienvenue tout le monde!'} -... +#Assume that the initial state of the database is ... +# space[0] has one tuple set and one primary key whose type is 32-bit integer. +# There is one row, with field[0] = 999 and field[1] = 'A'. + +#In the following update ... +# The first argument is 0, that is, the affected space is space[0] +# The second argument is 999, that is, the affected tuple is identified by primary key value = 999 +# The third argument is '=p', that is, there is one operation, assignment to a field +# The fourth argument is 1, that is, the affected field is field[1] +# The fifth argument is 'B', that is, field[1] contents change to 'B' +# Therefore, after the following update, field[0] = 999 and field[1] = 'B'. +lua box.update(0, 999, '=p', 1, 'B') + +#In the following update, the arguments are the same, except that ... +# the key is passed as a Lua table (inside braces). This is unnecessary +# when the primary key has only one field, but would be necessary if the +# primary key had more than one field. +# Therefore, after the following update, field[0] = 999 and field[1] = 'B' (no change). +lua box.update(0, {999}, '=p', 1, 'B') + +#In the following update, the arguments are the same, except that ... +# The fourth argument is 2, that is the affected field is field[2]. +# It is okay that, until now, field[2] has not existed. It gets added. +# Therefore, after the following update, field[0] = 999, field[1] = 'B', field[2] = 1. +lua box.update(0, 999, '=p', 2, 1) + +#In the following update, the arguments are the same, except that ... +# The third argument is '+p', that is, the operation is addition rather than assignment. +# Since field[2] previously contained 10, this means we're adding 1 to 1. +# Therefore, after the following update, field[0] = 999, field[1] = 'B', field[2] = 2. +lua box.update(0, 999, '+p', 2, 1) + +#In the following update ... +# The idea is to modify two fields at once. +# The third argument is '|p=p', that is, there are two operations, OR and assignment. +# The fourth and fifth arguments mean that field[2] gets ORed with 1. +# The fifth and sixth arguments mean that field[1] gets assigned 'C'. +# Therefore, after the following update, field[0] = 999, field[1] = 'C', field[2] = 3. +lua box.update(0, 999, '|p=p', 2, 1, 1, 'C') + +#In the following update ... +# The idea is to delete field[1], then subtract 3 from field[2], but ... +# after the delete, there is a renumbering -- so field[2] becomes field[1] +# before we subtract 3 from it, and that's why the sixth argument is 1 not 2. +# Therefore, after the following update, field[0] = 999, field[1] = 0. +lua box.update(0, 999, '#p-p', 1, 0, 1, 3) + +#In the following update ... +# We're making a long string so that the splice will work in the next example. +# Therefore, after the following update, field[0[ = 999, field[1] = 'XYZ'. +lua box.update(0, 999, '=p', 1, 'XYZ') + +#In the following update ... +# The third argument is ':p', that is, this is the example of splice. +# The fifth argument is actually four arguments packed together ... +# a filler, an offset, the number of bytes to cut (1), and the string to add ('!') +# Therefore, after the following update, field[0[ = 999, field[1] = 'X!Z'. +lua box.update(0, 999, ':p', 1, box.pack('ppp', 1, 1, '!')) + </programlisting> </para> </listitem> @@ -561,7 +600,7 @@ Call ERROR, Illegal parameters, key is not u32 (ER_ILLEGAL_PARAMS) </emphasis> </term> <listitem><para> - Select a range of tuples, starting from offset + Select a range of tuples, starting from the offset specified by <code>key</code>. The key can be multipart. Limit selection with at most <code>limit</code> tuples. If no key is specified, @@ -645,7 +684,7 @@ localhost> lua box.select_range(4, 1, 2, '1') </para> <para> For TREE indexes, this returns tuples in sorted order. - Other index types do not support this call. + For other index types this call is not supported. If <code>key</code> is <code>nil</code> or unspecified, the selection starts from the end of the index. <bridgehead renderas="sect4">Example</bridgehead> @@ -756,7 +795,7 @@ localhost> lua box.select_reverse_range(4, 1, 2, '1') </member> <member><code>p</code> — stores the length of the argument as a BER-encoded integer - followed by the argument itself (a 4-bytes for integers (LE order) + followed by the argument itself (a little-endian 4-byte integer for integers, and a binary blob for other types), </member> <member><code>=, +, &, |, ^, : </code>— @@ -939,7 +978,7 @@ lua box.dostring('local f = function(key) t=box.select(0, 0, key); if t ~= nil t </para> <para> Requires <emphasis>libuuid</emphasis> library to be - installed. The library is loaded in runtime, + installed. The library is loaded at runtime, and if the library is not available, this function returns an error. </para> @@ -952,7 +991,7 @@ lua box.dostring('local f = function(key) t=box.select(0, 0, key); if t ~= nil t <listitem> <para> Generate hex-string of 128-bit (16 bytes) unique id. - Return 32-bytes string. + Return 32-byte string. </para> <bridgehead renderas="sect4">Example</bridgehead> <programlisting> @@ -971,11 +1010,11 @@ lua box.dostring('local f = function(key) t=box.select(0, 0, key); if t ~= nil t <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, it's error code + 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 a unique constraint violation, no such space/index, + such as unique constraint violation, no such space/index, etc. A complete list of errors is present in <link xlink:href="https://github.com/tarantool/tarantool/blob/master/include/errcode.h">errcode.h</link> file in the source tree. Lua constants which correspond to Tarantool errors @@ -1022,11 +1061,11 @@ localhost> lua box.auto_increment(0, "I am a duplicate") <listitem> <para> Increments a counter identified by the key. The key can be - multi-part, but there must be an index covering + multipart, but there must be an index covering all fields of the key. If there is no tuple identified by the given key, creates a new one with initial counter value set to 1. Returns the - new counter value back. + new counter value. </para> <bridgehead renderas="sect4">Example</bridgehead> <programlisting>localhost> lua box.counter.inc(0, 'top.mail.ru') @@ -1067,7 +1106,7 @@ localhost> lua box.counter.dec(0, 'top.mail.ru') <title>Package <code>box.tuple</code></title> <variablelist xml:id="box.tuple" xreflabel="box.tuple"> - <para>The package stands for <code>box.tuple</code> userdata + <para>This package handles the <code>box.tuple</code> userdata type. It is possible to access individual tuple fields using an index, select a range of fields, iterate over all fields in a tuple or convert a tuple to a Lua table. Tuples are @@ -1255,7 +1294,7 @@ lua box.cjson.decode('{"hello": "world"}').hello <para>This package is a container for all configured spaces. A space object provides access to space attributes, such as id, whether or not a space is - enabled, space cardinality, estimated number of rows. It also + 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>. @@ -1310,7 +1349,7 @@ lua box.cjson.decode('{"hello": "world"}').hello </term> <listitem> <simpara> - Select a range of tuples, starting from offset specified by + Select a range of tuples, starting from the offset specified by <code>key</code>. The key can be multipart. Limit selection with at most <code>limit</code> tuples. If no key is specified, start from the first key in the index. @@ -1337,13 +1376,12 @@ lua box.cjson.decode('{"hello": "world"}').hello <simpara> Select a reverse range of tuples, limited by <code>limit</code>, starting from <code>key</code>. - The key can be multipart. TREE index returns - tuples in descending order. Other index types - do not support this call. + The key can be multipart. For TREE indexes, this returns + tuples in descending order. For other index types + this call is not supported. </simpara> </listitem> </varlistentry> - <varlistentry> <term> <emphasis role="lua">space:insert(...)</emphasis> @@ -1447,7 +1485,7 @@ localhost> lua for k,v in box.space[0]:pairs() do print(v) end <emphasis role="lua">index.type</emphasis> </term> <listitem><simpara> - A string for index type, either 'TREE', 'HASH', 'BITSET'. + A string for index type, either 'TREE', 'HASH', or 'BITSET'. </simpara></listitem> </varlistentry> @@ -1482,20 +1520,20 @@ localhost> lua for k,v in box.space[0]:pairs() do print(v) end index types support different iterators. The remaining arguments of the function are varying and depend on the iteration type. For example, - TREE index maintains a strict order of keys and + a TREE index maintains a strict order of keys and can return all tuples in ascending or descending order, starting from the specified key. Other index types, however, do not support ordering. </simpara> <para xml:id="iterator-consistency"> - To understand consistency of tuples, + 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": caused a write to + 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 @@ -1624,7 +1662,7 @@ error: 'Iterator type is not supported' <emphasis role="lua">index:count()</emphasis> </term> <listitem><simpara> - Iterate over an index, count the number of tuples which equal the + Iterate over an index, counting the number of tuples which equal the provided search criteria. The argument can either point to a tuple, a key, or one or more key parts. Returns the number of matched tuples. @@ -1681,10 +1719,10 @@ created. </para> <para> A runaway fiber can be stopped with <code>box.fiber.cancel()</code>. -<code>box.fiber.cancel()</code>, however, is advisory — it works -only if the runaway fiber is calling <code>box.fiber.testcancel()</code> +However, <code>box.fiber.cancel()</code> is advisory — 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>, are calling <code>box.fiber.testcancel()</code>. +or <code>box.update()</code>, do call <code>box.fiber.testcancel()</code>. <code>box.select()</code> doesn't. </para> <para> @@ -1738,7 +1776,7 @@ and <code>box.fiber.testcancel()</code> is checked whenever such an event occurs <emphasis role="lua" xml:id="box.fiber.create">box.fiber.create(function) </emphasis> </term> <listitem><simpara> - Create a fiber for <code>function</code>. + Create a fiber for a <code>function</code>. </simpara> <bridgehead renderas="sect4">Errors</bridgehead> <simpara>Can hit a recursion limit.</simpara> @@ -1787,7 +1825,7 @@ and <code>box.fiber.testcancel()</code> is checked whenever such an event occurs This is a quick way to create and start a detached fiber. The fiber function is passed in the first argument, the function arguments follow. The fiber is - created detached and resumed immediately. + created, detached, and resumed immediately. </simpara></listitem> </varlistentry> @@ -1847,7 +1885,7 @@ and <code>box.fiber.testcancel()</code> is checked whenever such an event occurs <para> A session is an object associated with each client connection. Through this module, it's possible to query session state, -as well as set a Lua chunk executed on connect or disconnect +as well as set a Lua chunk executed on a connect or disconnect event. </para> <variablelist> @@ -1878,6 +1916,16 @@ event. <listitem><simpara>Return true if a session is alive, false otherwise.</simpara></listitem> </varlistentry> + + <varlistentry> + <term> + <emphasis role="lua">box.session.peer(id) </emphasis> + </term> + <listitem><simpara>Return the host address and port for the session + peer, for example "127.0.0.1:55457", or "0.0.0.0:0" if the session + is not connected.</simpara></listitem> + </varlistentry> + </variablelist> <para> This module also makes it possible to define triggers on connect @@ -2056,7 +2104,7 @@ end BSD sockets is a mechanism to exchange data with a local or remote host in connection-oriented (TCP) or datagram-oriented (UDP) mode. - Semantics of the calls in <code>box.socket</code> API closely follows + 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>. @@ -2100,7 +2148,7 @@ end a long time. </simpara> <simpara> - As all other <code>box</code> libraries, the API can be used + As with all other <code>box</code> libraries, the API can be used in procedural style (e.g. <code>box.socket.close(socket)</code>) as well as in object-oriented style (<code>socket:close()</code>). </simpara> @@ -2252,7 +2300,7 @@ end <para> Start listening for incoming connections. The listen backlog, on Linux, is taken from <filename>/proc/sys/net/core/somaxconn</filename>, - whereas on BSD is set to <constant>SOMAXCONN</constant>. + whereas on BSD it is set to <constant>SOMAXCONN</constant>. <bridgehead renderas="sect4">Returns</bridgehead> Socket on success, <code>nil, "error", errno, errstr</code> on error. </para> @@ -2324,7 +2372,7 @@ end <term><emphasis role="lua">socket:error()</emphasis></term> <listitem> <para> - Retrieve the last error occurred on a socket. + Retrieve the last error that occurred on a socket. <bridgehead renderas="sect4">Returns</bridgehead> <code>errno, errstr</code>. <code>0, "Success"</code> if there is no error. @@ -2362,7 +2410,7 @@ end The library also provides a pre-created connection object to the local server, <code>box.net.self</code>. This connection is always <quote>established</quote>. The - purpose of this object is to make polymorphic use of + purpose of this object is to make polymorphic use of the <code>box.net.box</code> API easier. There is an important difference, however, between the embedded connection and a remote one. With the embedded connection, @@ -2413,7 +2461,7 @@ end Create a new connection. The connection is established on demand, at the time of the first request. It is re-established automatically after - a disconnect. Argument + a disconnect. The argument <code>reconnect_interval</code> (in seconds) is responsible for the amount of time the server sleeps between failing attempts to reconnect. The @@ -2545,7 +2593,7 @@ end <listitem> <para> Returns a closure which is identical to the - invoked function, except the added timeout + invoked function, except for the added timeout functionality. <programlisting> -- wait for 'update' until it is finished @@ -2598,7 +2646,7 @@ logger = cat - >> tarantool.log <para> This package provides access to information about server variables: pid, uptime, version and such. - Its contents is identical to output of <olink + Its contents are identical to the output from <olink targetptr="show-info"/>. </para> <varlistentry> @@ -2607,8 +2655,8 @@ logger = cat - >> tarantool.log </term> <listitem> <simpara> - Since contents of box.info is dynamic, it's not - possible to iterate over keys with Lua + 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 @@ -2772,7 +2820,7 @@ localhost> </section> <section xml:id="sp-limitations"> -<title>Limitation of stored procedures</title> +<title>Limitations of stored procedures</title> <para> There are two limitations in stored procedures support one should @@ -2780,12 +2828,12 @@ localhost> </para> <bridgehead renderas="sect4">Cooperative multitasking environment</bridgehead> <para> - Tarantool core is built around cooperative multi-tasking + 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 + 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: @@ -2805,14 +2853,14 @@ localhost> 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 responsibility of the stored procedure - author. Most of <code>box</code> calls, such as + 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, + 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 -- GitLab