diff --git a/.gitignore b/.gitignore index dd46dfdae0074708e49f18cbac3f8e71bdd81f47..d3d77504cc8a66eafe9c94ecf187cd414d0f7dd0 100644 --- a/.gitignore +++ b/.gitignore @@ -62,8 +62,4 @@ third_party/luajit/src/lj_libdef.h third_party/luajit/src/lj_recdef.h third_party/luajit/src/lj_vm.s VERSION -debian/*.debhelper -debian/*.log -debian/*.substvars -*.cdbs-orig src/00000000000000000001.snap diff --git a/CMakeLists.txt b/CMakeLists.txt index 424d296f848ee6302457e797b3c7a36e28d69b6c..dc197d86d0b8a4b2f0041da472d3611d1cd864e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,7 +98,7 @@ add_custom_target(tags COMMAND ctags -R -f tags # set (CPACK_PACKAGE_VERSION_MAJOR "1") set (CPACK_PACKAGE_VERSION_MINOR "6") -set (CPACK_PACKAGE_VERSION_PATCH "2") +set (CPACK_PACKAGE_VERSION_PATCH "3") set (PACKAGE_VERSION "") diff --git a/debian/control b/debian/control index c54bb43cb8fb2355f1167b3300ef5544458bd119..596a94722777c76d0988573bfc2bee0b02be5f4e 100644 --- a/debian/control +++ b/debian/control @@ -14,29 +14,30 @@ Homepage: http://tarantool.org/ VCS-Browser: https://github.com/tarantool/tarantool VCS-Git: git://github.com/tarantool/tarantool.git -Package: tarantool-common -Architecture: all -Priority: optional -Depends: ${misc:Depends}, adduser -Description: Tarantool in-memory database - common files - Tarantool is an in-memory database and Lua application server. - This package provides scripts to work with tarantool configuration - and log files. +# Package: tarantool-common +# Architecture: all +# Priority: optional +# Depends: ${misc:Depends}, adduser +# Description: Tarantool in-memory database - common files +# Tarantool is an in-memory database and Lua application server. +# This package provides scripts to work with tarantool configuration +# and log files. Package: tarantool Architecture: i386 amd64 kfreebsd-i386 kfreebsd-amd64 hurd-i386 Priority: optional Depends: ${shlibs:Depends}, ${misc:Depends} Conflicts: tarantool-dbg (<< 1.5.2), - tarantool-common (<< 1.6~), +# tarantool-common (<< 1.6~), tarantool-client (<< 1.6~), tarantool-client-dbg (<< 1.6~), tarantool-plugins (<< 1.6~), tarantool-mysql-plugin (<< 1.6~), tarantool-postgresql-plugin (<< 1.6~), libtarantool-dev (<< 1.6~) -Recommends: tarantool-common (>= 1.6), - tarantool-modules +# Recommends: tarantool-common (>= 1.6), +# tarantool-modules +Recommends: tarantool-modules Description: In-memory database with Lua application server Tarantool is an in-memory database and Lua application server. Its key properties include: diff --git a/debian/rules b/debian/rules index 5e8c510daea2b8e99a197e1ca1aa3ca1227ce147..4415b71d73686d13b7ec167f2518c9000ec54f19 100755 --- a/debian/rules +++ b/debian/rules @@ -67,14 +67,14 @@ install/tarantool:: # make -C build-area test-force || /bin/true -install/tarantool-common:: - pod2man -c 'tarantool instances control' \ - debian/tarantool_instance.pod > build-area/tarantool_instance.1 - pod2man -c 'tarantool log rotation' \ - debian/scripts/tarantool_logrotate \ - > build-area/tarantool_logrotate.1 - pod2man -c 'snapshot rotate' \ - debian/scripts/tarantool_snapshot_rotate \ - > build-area/tarantool_snapshot_rotate.1 - install -m0755 extra/logger.pl \ - debian/tarantool-common/usr/lib/tarantool/logger +# install/tarantool-common:: +# pod2man -c 'tarantool instances control' \ +# debian/tarantool_instance.pod > build-area/tarantool_instance.1 +# pod2man -c 'tarantool log rotation' \ +# debian/scripts/tarantool_logrotate \ +# > build-area/tarantool_logrotate.1 +# pod2man -c 'snapshot rotate' \ +# debian/scripts/tarantool_snapshot_rotate \ +# > build-area/tarantool_snapshot_rotate.1 +# install -m0755 extra/logger.pl \ +# debian/tarantool-common/usr/lib/tarantool/logger diff --git a/doc/user/configuration-reference.xml b/doc/user/configuration-reference.xml index ca291be9745290de728b7c81c88f3626f8682242..1b8f07d47709f447c64c6cddbb0a1e4f9aebe27e 100644 --- a/doc/user/configuration-reference.xml +++ b/doc/user/configuration-reference.xml @@ -95,8 +95,8 @@ The Lua program almost always begins by invoking <code>box.cfg()</code>, if the database server will be used or if ports need to be opened. For example, suppose <filename>script.lua</filename> contains the lines<programlisting>#!/usr/bin/env tarantool box.cfg{ - primary_port = os.getenv("PRIMARY_PORT"), - admin_port = os.getenv("ADMIN_PORT"), + listen = os.getenv("LISTEN"), + admin = os.getenv("ADMIN"), slab_alloc_arena = 0.1, pid_file = "tarantool.pid", rows_per_wal = 50 @@ -104,15 +104,15 @@ box.cfg{ print('Starting ',arg[1])</programlisting> and suppose the command line is <code>~/tarantool/src/tarantool script.lua ARG</code>. Then the screen might look like this:<programlisting> -<prompt>$</prompt> <userinput>export PRIMARY_PORT=3303</userinput> +<prompt>$</prompt> <userinput>export PRIMARY_PORT=3301</userinput> <prompt>$</prompt> <userinput>~/tarantool/src/tarantool script.lua ARG</userinput> 2014-07-02 10:19:29.078 ... version 1.6.0-1471-g663694c 2014-07-02 10:19:29.078 ... log level 5 2014-07-02 10:19:29.078 ... mapping 107374184 bytes for a shared arena... 2014-07-02 10:19:29.086 ... initialized 2014-07-02 10:19:29.101 ... recovery start -2014-07-02 10:19:29.107 ... bound to primary port tcp://0.0.0.0:3303 -2014-07-02 10:19:29.108 ... I am primary +2014-07-02 10:19:29.107 ... bound to primary port tcp://0.0.0.0:3301 +2014-07-02 10:19:29.108 ... ready to accept requests Starting ARG 2014-07-02 10:19:29.108 ... entering the event loop</programlisting> </para> @@ -138,7 +138,7 @@ Starting ARG </para> <para> To see all the non-null parameters, say <code>box.cfg</code> (no parentheses). - To see a particular parameter, for example the primary port, say <code>box.cfg.primary_port</code>. + To see a particular parameter, for example the listen address, say <code>box.cfg.listen</code>. </para> <para> The following tables describe all parameters for basic operation, @@ -212,7 +212,7 @@ Starting ARG <entry>Deprecated. Do not use.</entry> </row> <row> - <entry xml:id="primary_port" xreflabel="primary_port">primary_port</entry> + <entry xml:id="primary_port" xreflabel="primary_port">listen</entry> <entry>integer or string</entry> <entry>null</entry> <entry>no</entry> @@ -220,15 +220,15 @@ Starting ARG Has no default value, so <emphasis role="strong">must be specified</emphasis> if connections will occur from remote clients - that do not use admin_port. + that do not use "admin address" (the administrative host and port). Note: a replica also binds to this port, and accepts connections, but these connections can only serve reads until the replica becomes a master. - A typical value is 3303.</entry> + A typical value is 3301.</entry> </row> <row> - <entry xml:id="admin_port" xreflabel="admin_port">admin_port</entry> + <entry xml:id="admin_port" xreflabel="admin_port">admin</entry> <entry>integer or string</entry> <entry>null</entry> <entry>no</entry> @@ -266,11 +266,11 @@ Starting ARG ordinarily <command>ps</command> shows the Tarantool server process thus: </para> <programlisting>kostja@shmita:~$ ps -a -o command | grep box -tarantool: primary pri: 3303 adm: 33135</programlisting> +tarantool: primary pri: 3301 adm: 3313</programlisting> <para>But if the configuration file contains custom_proc_title=sessions then the output looks like:</para> <programlisting>kostja@shmita:~$ ps -a -o command | grep box -tarantool: primary@sessions pri: 3303 adm: 3313</programlisting> +tarantool: primary@sessions pri: 3301 adm: 3313</programlisting> </entry> </row> @@ -472,7 +472,7 @@ tarantool: primary@sessions pri: 3303 adm: 3313</programlisting> For example, if replication_source = "1.2.3.4:55555" then the replica server tries to connect to 1.2.3.4 port 55555. A replica server does not accept updates - on <olink targetptr="primary_port"/>. This parameter is + on <olink targetptr="primary_port">listen</olink>. This parameter is dynamic, that is, to enter master mode, simply set replication_source to an empty string and issue "box.cfg{replication_source=new-value}".</entry> @@ -643,8 +643,8 @@ tarantool: primary@sessions pri: 3303 adm: 3313</programlisting> instances of the server using the same configuration file. The first one to start will be the "primary" instance. The second one to start will be the "standby" instance. - The standby instance will initialize and will try to connect on primary_port - and admin_port, but will fail because the + The standby instance will initialize and will try to connect on listen + address and admin address, but will fail because the primary instance has already taken them. So the standby instance goes into a loop, reading the write ahead log which the primary instance is writing (so the diff --git a/doc/user/connectors.xml b/doc/user/connectors.xml index 44e2617814447bcbbe983ac3dbbf7b75caae1186..17031d023e3f6f7a780945da46ec6c6e1086cac6 100644 --- a/doc/user/connectors.xml +++ b/doc/user/connectors.xml @@ -113,10 +113,11 @@ And that is why APIs exist for drivers for C, Perl, Python, PHP, Ruby, and so on the necessary file <filename>tp.h</filename>, and the default library path contains the directory where Tarantool library files were placed at installation time. Before trying to run, check that the server - (tarantool) is running on localhost (127.0.0.1) and its primary port is the default (3303) and + (tarantool) is running on localhost (127.0.0.1) and its listen address is the default + (local host, port 3301) and space[513]'s primary key type is numeric (space[513].index[0].key_field[1].type = "NUM"). To run, say <code>./example</code>. - The program will open a socket connection with the tarantool server at localhost:3303, + The program will open a socket connection with the tarantool server at localhost:3301, then format a buffer for sending an INSERT request, then send the request, then check if the server returned an error, then — if all is well — print "Insert succeeded". If the row already exists, the program will print <quote>Duplicate key exists in unique index 0</quote>. @@ -136,10 +137,10 @@ int main() struct sockaddr_in sock; /* the usual socket address info */ if ((fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) <= 0) /* open the socket. abort if failure */ exit(1); - memset(&sock, 0, sizeof(sock)); /* connect to localhost:3303 */ + memset(&sock, 0, sizeof(sock)); /* connect to localhost:3301 */ sock.sin_family = AF_INET; sock.sin_addr.s_addr = inet_addr("127.0.0.1"); - sock.sin_port = htons(3303); + sock.sin_port = htons(3301); if (connect(fd, (struct sockaddr *)&sock, sizeof(sock)) < 0) /* connect, abort if failure */ exit(1); const int greeting_buffer_size = 128; /* handle the server's greeting */ @@ -219,14 +220,15 @@ sudo cpan install DR::Tarantool <para> Here is a complete Perl program that inserts [99999,'BB'] into space[0] via the Perl API. Before trying to run, check that the server - (tarantool) is running on localhost (127.0.0.1) and its primary port is the default (3303) and + (tarantool) is running on localhost (127.0.0.1) and its listen address is the default + (local host, port 3301) and space[0]'s primary key type is numeric (space[0].index[0].key_field[1].type = "NUM" in configuration file). To run, paste the code into a file named example.pl and say <code>perl example.pl</code>. The program will connect using an application-specific definition of the space. The program will open a socket connection - with the tarantool server at localhost:3303, then send an INSERT request, + with the tarantool server at localhost:3301, then send an INSERT request, then — if all is well — end without displaying any messages. - If tarantool is not running on localhost with primary port = 3303, the program will print + If tarantool is not running on localhost with listen address = port 3301, the program will print <quote>Connection refused</quote>. </para> <para> @@ -237,7 +239,7 @@ use DR::Tarantool ':all'; my $tnt = tarantool host => '127.0.0.1', # look for tarantool on localhost - port => 3303, # assume tarantool primary port = default + port => 3301, # assume tarantool listen address = default spaces => { 0 => { # definition of space[0] ... name => 't0', # space[0] name = 't0' @@ -295,18 +297,19 @@ export PHP_INI_SCAN_DIR=~/tarantool-php/test/share <para> Here is a complete PHP program that inserts [99999,'BB'] into space[0] via the PHP API. Before trying to run, check that the server - (tarantool) is running on localhost (127.0.0.1) and its primary port is the default (3303) and + (tarantool) is running on localhost (127.0.0.1) and its listen address is the default + (local host, port 3301) and space[0]'s primary key type is numeric (space[0].index[0].key_field[1].type = "NUM" in configuration file). To run, paste the code into a file named example.php and say <code>php example.php</code>. The program will open a socket connection - with the tarantool server at localhost:3303, then send an INSERT request, + with the tarantool server at localhost:3301, then send an INSERT request, then — if all is well — print "Insert succeeded". If the tuple already exists, the program will print <quote>Duplicate key exists in unique index 0</quote>. </para> <para> <programlisting> <?php -$tarantool = new Tarantool("localhost", 3303, 33015); +$tarantool = new Tarantool("localhost", 3301, 3313); try { $tarantool->insert(0, array(99999, "BB"), TARANTOOL_FLAGS_ADD); print "Insert succeeded\n"; @@ -333,11 +336,11 @@ catch (Exception $e) { <userinput><code>pip install tarantool</code></userinput> to install in <filename>/usr</filename> (requires root privilege) or <userinput><code>pip install tarantool --user</code></userinput> to install in <filename>~</filename> i.e. user's default directory. - The program is assuming that the server (tarantool) is running on localhost (127.0.0.1) and its primary port is - the default (3303) and space99's primary key type is string (box.space.space99.index['primary'].key_field[1].type = "STR") + The program is assuming that the server (tarantool) is running on localhost (127.0.0.1) and its listen address is + the default (local host, port 3301) and space99's primary key type is string (box.space.space99.index['primary'].key_field[1].type = "STR") and user 'guest' has permission to read and write on space99. An administrator could fulfill all those conditions by starting the tarantool server and executing these requests:<programlisting> -box.cfg{primary_port = 3303} +box.cfg{listen = 3301} box.schema.create_space('space99') box.space.space99:create_index('primary',{parts = {1,'STR'}}) box.schema.user.grant('guest', 'read', 'space', '_space') @@ -350,7 +353,7 @@ box.schema.user.grant('guest', 'read,write', 'space', 'space99')</programlisting #!/usr/bin/python from tarantool import Connection -c = Connection("127.0.0.1", 3303) +c = Connection("127.0.0.1", 3301) result = c.insert("space99",('First Tuple','Value', 'Value')) print result </programlisting> diff --git a/doc/user/databases.xml b/doc/user/databases.xml index 57477de80f947a7de44b30630dc137a8e5fad50d..1911115ac7caa6d2ab7222c9d78cb2fc21860f1f 100644 --- a/doc/user/databases.xml +++ b/doc/user/databases.xml @@ -90,7 +90,7 @@ The contents of the <code>box</code> library can be inspected at runtime with <code>box</code>, with no arguments. The packages inside the box library are: schema, box.tuple, box.space, box.index, - box.net.box, box.cfg, box.info, box.slab, box.stat. + 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 definition (create alter drop), data manipulation (insert delete update select replace), and introspection (inspecting contents of spaces, accessing server configuration). @@ -1188,7 +1188,7 @@ session.delimiter('')! <varlistentry> <term> <emphasis role="lua" xml:id="boxindexiterator" xreflabel="box.index.iterator(type, ...)"> - box.space.<replaceable>space-name</replaceable>.index.<replaceable>index-name</replaceable>]:iterator(<replaceable>iterator-type, bitset-value | field-value...</replaceable>)</emphasis> + box.space.<replaceable>space-name</replaceable>.index[.<replaceable>index-name</replaceable>]:pairs(<replaceable>bitset-value | field-value..., iterator-type</replaceable>)</emphasis> </term> <listitem> <para> @@ -1298,7 +1298,7 @@ session.delimiter('')! <varlistentry> <term> <emphasis role="lua" xml:id="box.index.iterator" xreflabel="box.index.select(type, ...)"> - box.space.<replaceable>space-name</replaceable>.index.<replaceable>index-name</replaceable>]:select(<replaceable>{fields, {parameters}]</replaceable>)</emphasis> + box.space.<replaceable>space-name</replaceable>[.index.<replaceable>index-name</replaceable>]:select(<replaceable>{fields, {parameters}]</replaceable>)</emphasis> </term> <listitem> <para> @@ -1334,9 +1334,15 @@ The result will be a table of tuples and will look like this: ... </programlisting> </para> + <para> + Note: <code>[.index.<replaceable>index-name</replaceable>]</code> is optional. If it is + omitted, then the assumed index is the first (primary-key) index. Therefore, for + the example above, <code>box.space.tester:select(1, {iterator = 'GT'})</code> + would have returned the same two rows, via the 'primary' index. + </para> </listitem> </varlistentry> - + <varlistentry> <term> <emphasis role="lua">box.space.<replaceable>space-name</replaceable>.index.<replaceable>index-name</replaceable>:min([key])</emphasis> @@ -2035,287 +2041,6 @@ session.delimiter('')! <!-- end of lib --> -<section xml:id="sp-box-net-box"> - <title>Package <code>box.net.box</code> — 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 - — 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 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 — 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 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', 3303)</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', 3303)</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>, ...)</emphasis></term> - <listitem> - <para> - <code>conn:select(<replaceable>space-number</replaceable>, ...)</code> is the remote-call equivalent of the local call - <code xlink:href="#box.select">box.space[<replaceable>space-number</replaceable>]:select(...)</code>. - Please note this difference: a local <code>box.space[<replaceable>space-number</replaceable>]:select(...)</code> does not yield, - but a remote <code>conn:select(<replaceable>space-number</replaceable>, ...)</code> call does yield, - so local data may change while a remote <code>conn:select(<replaceable>space-number</replaceable>, ...)</code> is running. - </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(<replaceable>space-number</replaceable>, ...)</code> is the remote-call equivalent of the local call - <code xlink:href="#box.insert">box.space[<replaceable>space-number</replaceable>]: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(<replaceable>space-number</replaceable>, ...)</code> is the remote-call equivalent of the local call - <code xlink:href="#box.replace">box.space[<replaceable>space-number</replaceable>]: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(<replaceable>space-number</replaceable>, ...)</code> is the remote-call equivalent of the local call - <code xlink:href="#box.update">box.space[<replaceable>space-number</replaceable>]:update(...)</code>. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua" xml:id="box.net.box.delete"> - conn:delete(<replaceable>space-number</replaceable>, ...)</emphasis></term> - <listitem> - <para> - <code>conn:delete(<replaceable>space-number</replaceable>, ...)</code> is the remote-call equivalent of the local call - <code xlink:href="#box.delete">box.space[<replaceable>space-number</replaceable>]: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('func', '1', '2', '3')</code> is the remote-call equivalent of <code>func('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.space.tester:insert',{2})</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.5):update({'1'}, {{'=p', 1, 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 named tester with a numeric primary key. - Assume that the database is nearly empty. - Assume that the tarantool server is running on localhost 127.0.0.1:3303. -<programlisting> -<prompt>tarantool></prompt><userinput> ta = {}</userinput> ---- -... -<prompt>tarantool></prompt><userinput> box.schema.user.grant('guest', 'read,write,execute', 'space', 'tester')</userinput> -<prompt>tarantool></prompt><userinput> session = require('session'); session.delimiter('!')</userinput> -<prompt>tarantool></prompt><userinput> function example()</userinput> -<prompt> -></prompt><userinput> if box.net.self:ping() then</userinput> -<prompt> -></prompt><userinput> table.insert(ta, 'self:ping() succeeded')</userinput> -<prompt> -></prompt><userinput> table.insert(ta, ' (no surprise -- self connection is pre-established)')</userinput> -<prompt> -></prompt><userinput> end</userinput> -<prompt> -></prompt><userinput> if box.cfg.primary_port == 3303 then</userinput> -<prompt> -></prompt><userinput> table.insert(ta,'The local server primary port number = 3303')</userinput> -<prompt> -></prompt><userinput> else</userinput> -<prompt> -></prompt><userinput> table.insert(ta, 'The local server primary port number is not 3303')</userinput> -<prompt> -></prompt><userinput> table.insert(ta, '( (maybe box.cfg{...primary_port=3303...} was not stated)')</userinput> -<prompt> -></prompt><userinput> table.insert(ta, '( (so connect will fail)')</userinput> -<prompt> -></prompt><userinput> end</userinput> -<prompt> -></prompt><userinput> conn = box.net.box.new('127.0.0.1', 3303)</userinput> -<prompt> -></prompt><userinput> conn:delete(box.space.tester.id, 800)</userinput> -<prompt> -></prompt><userinput> table.insert(ta, 'conn:delete done on tester.')</userinput> -<prompt> -></prompt><userinput> conn:insert(box.space.tester.id, {800, 'data'})</userinput> -<prompt> -></prompt><userinput> table.insert(ta, 'conn:insert done on tester, index 0')</userinput> -<prompt> -></prompt><userinput> table.insert(ta, ' primary key value = 800.')</userinput> -<prompt> -></prompt><userinput> wtuple = conn:select(box.space.tester.id, 800)</userinput> -<prompt> -></prompt><userinput> table.insert(ta, 'conn:select done on tester, index 0')</userinput> -<prompt> -></prompt><userinput> table.insert(ta, ' number of fields = ' .. #wtuple)</userinput> -<prompt> -></prompt><userinput> conn:delete(box.space.tester.id, 800)</userinput> -<prompt> -></prompt><userinput> table.insert(ta, 'conn:delete done on tester')</userinput> -<prompt> -></prompt><userinput> conn:replace(box.space.tester.id, {800, 'New data', 'Extra data'})</userinput> -<prompt> -></prompt><userinput> table.insert(ta, 'conn:replace done on tester')</userinput> -<prompt> -></prompt><userinput> conn:timeout(1):update(box.space.tester.id, {800}, {{'=p', 1, 'Fld#1'}})</userinput> -<prompt> -></prompt><userinput> table.insert(ta, 'conn:update done on tester')</userinput> -<prompt> -></prompt><userinput> conn:close()</userinput> -<prompt> -></prompt><userinput> table.insert(ta, 'conn:close done')</userinput> -<prompt> -></prompt><userinput> end!</userinput> ---- -... -<prompt>tarantool></prompt><userinput> session.delimiter('')!</userinput> -<prompt>tarantool></prompt><userinput> example()</userinput> ---- -... -<prompt>tarantool></prompt><userinput> ta</userinput> ---- -- - self:ping() succeeded - - ' (no surprise -- self connection is pre-established)' - - The local server primary port number = 3303 = default - - conn:delete done on tester. - - conn:insert done on tester, index 0 - - ' primary key value = 800.' - - conn:select done on tester, index 0 - - ' number of fields = 2' - - conn:delete done on tester - - conn:replace done on tester - - conn:update done on tester - - conn:close done -... -<prompt>tarantool></prompt><userinput> box.space.tester:select(800) -- Prove that the update succeeded.</userinput> ---- -- [800, 'Fld#1', 'Extra data'] -... -</programlisting> -</para> -</section> - <section xml:id="sp-box-cfg"> <title>Packages <code>box.cfg</code>, <code>box.info</code>, <code>box.slab</code> and @@ -2567,6 +2292,288 @@ tarantool> <userinput>box.stat().DELETE -- a selected item of the table</userinp </para> </section> +<section xml:id="sp-net-box"> + <title>Package <code>net.box</code> — working with networked Tarantool peers</title> + <para> + The <code>net.box</code> package contains connectors to remote database systems. + One variant, <code>box.net.sql</code>, is for connecting to MySQL or MariaDB or PostgreSQL + — that variant is the subject of the <olink targetptr="plugins"><quote>SQL DBMS plugins</quote></olink> appendix. + In this section the subject is the built-in variant, <code>box.net</code>. + This is for connecting to tarantool servers via a network. + </para> +<variablelist xml:id="net.box"> + <para> + Call <code>require('net.box')</code> to get a net.box object, which will be called <code>net_box</code> + for examples in this section. + Call <code><replaceable>net_box</replaceable>: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>net.box()</code> routines, passing <code>conn:</code>, + to execute requests on the remote box. + Call <code>conn:close</code> to disconnect. + </para> + + <para> + All <code>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 — for example when it's necessary to + prioritize requests or to use different authentication ids. + </para> + + <varlistentry> + <term> + <emphasis role="lua" xml:id="net.box.new"> + conn = <replaceable>net_box</replaceable>:new(<replaceable>host</replaceable>, <replaceable>port</replaceable> [, {<replaceable>other parameter[s]</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 returned <code>conn</code> object supports methods for making remote + requests, such as select, update or delete. + </para> + <para> + For the local tarantool server there is a pre-created always-established + connection object named <code><replaceable>net_box</replaceable>.self</code>. + Its purpose is to make polymorphic use of the + <code>net.box</code> API easier. Therefore + <code>conn = <replaceable>net_box</replaceable>:new('localhost', 3301)</code> can + be replaced by <code>conn = <replaceable>net.box</replaceable>.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>wait_connect</code>, <code>user</code>, <code>password</code>. + </para> + <para> + Returns: (type = userdata) conn object). + </para> + <para> + Examples: <code>conn = net_box:new('localhost', 3301)</code>, + <code>conn = net_box:new('127.0.0.1', box.cfg.listen, {wait_connect = false, user = 'guest', password = ''})</code>. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><emphasis role="lua" xml:id="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>net_box.self:ping()</code>. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><emphasis role="lua" xml:id="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="net.box.select"> + conn.space.<replaceable>space-name</replaceable>:select(<replaceable>field-value</replaceable>, ...)</emphasis></term> + <listitem> + <para> + <code>conn.space.<replaceable>space-name</replaceable>:select(...)</code> is the remote-call equivalent of the local call + <code xlink:href="#box.select">box.space.<replaceable>space-name</replaceable>:select(...)</code>. + Please note this difference: a local <code>box.space.<replaceable>space-name</replaceable>:select(...)</code> does not yield, + but a remote <code>conn.space.<replaceable>space-name</replaceable>:select(...)</code> call does yield, + so local data may change while a remote <code>conn.space.<replaceable>space-name</replaceable>:select(...)</code> is running. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><emphasis role="lua" xml:id="net.box.insert"> + conn.space.<replaceable>space-name</replaceable>:insert{field-value, ...}</emphasis></term> + <listitem> + <para> + <code>conn.space.<replaceable>space-name</replaceable>:insert(...)</code> is the remote-call equivalent of the local call + <code xlink:href="#box.insert">box.space.<replaceable>space-name</replaceable>:insert(...)</code>. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><emphasis role="lua" xml:id="net.box.replace"> + conn.space.<replaceable>space-name</replaceable>:replace{field-value, ...}</emphasis></term> + <listitem> + <para> + <code>conn.space.<replaceable>space-name</replaceable>:replace(...)</code> is the remote-call equivalent of the local call + <code xlink:href="#box.replace">box.space.<replaceable>space-name</replaceable>:replace(...)</code>. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><emphasis role="lua" xml:id="net.box.update"> + conn.space.<replaceable>space-name</replaceable>:update(<replaceable>key</replaceable>, <replaceable>format</replaceable>, ...)</emphasis></term> + <listitem> + <para> + <code>conn.space.<replaceable>space-name</replaceable>:update(...)</code> is the remote-call equivalent of the local call + <code xlink:href="#box.update">box.space.<replaceable>space-name</replaceable>:update(...)</code>. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><emphasis role="lua" xml:id="net.box.delete"> + conn.space.<replaceable>space-name</replaceable>:delete{key}</emphasis></term> + <listitem> + <para> + <code>conn.space.<replaceable>space-name</replaceable>:delete{...}</code> is the remote-call equivalent of the local call + <code xlink:href="#box.delete">box.space.<replaceable>space-name</replaceable>:delete{...}</code>. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><emphasis role="lua" xml:id="net.box.call"> + conn:call(<replaceable>function-name</replaceable> [, <replaceable>arguments</replaceable>])</emphasis></term> + <listitem> + <para> + <code>conn:call('func', '1', '2', '3')</code> is the remote-call equivalent of <code>func('1', '2', '3')</code>. + That is, conn:call is a remote stored-procedure call. + </para> + <para> + Example: <code>conn:call('box.space.tester:insert',{2})</code>. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><emphasis role="lua" xml:id="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.5).space.tester:update({1}, {{'=', 2, 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 net.box methods</bridgehead> + <para> + This example will work with the sandbox configuration described in the preface. + That is, there is a space named tester with a numeric primary key. + Assume that the database is nearly empty. + Assume that the tarantool server is running on localhost 127.0.0.1:3301. +<programlisting> +<prompt>tarantool></prompt><userinput> box.schema.user.grant('guest', 'read,write,execute', 'universe')</userinput> +--- +... +<prompt>tarantool></prompt><userinput> session = require('session'); session.delimiter('!')</userinput> +--- +... +<prompt>tarantool></prompt><userinput> net_box = require('net.box')!</userinput> +--- +... +<prompt>tarantool></prompt><userinput> function example()</userinput> +<prompt> ></prompt><userinput> if net_box.self:ping() then</userinput> +<prompt> ></prompt><userinput> table.insert(ta, 'self:ping() succeeded')</userinput> +<prompt> ></prompt><userinput> table.insert(ta, ' (no surprise -- self connection is pre-established)')</userinput> +<prompt> ></prompt><userinput> end</userinput> +<prompt> ></prompt><userinput> if box.cfg.listen == '3301' then</userinput> +<prompt> ></prompt><userinput> table.insert(ta,'The local server listen address = 3301')</userinput> +<prompt> ></prompt><userinput> else</userinput> +<prompt> ></prompt><userinput> table.insert(ta, 'The local server listen address is not 3301')</userinput> +<prompt> ></prompt><userinput> table.insert(ta, '( (maybe box.cfg{...listen="3301"...} was not stated)')</userinput> +<prompt> ></prompt><userinput> table.insert(ta, '( (so connect will fail)')</userinput> +<prompt> ></prompt><userinput> end</userinput> +<prompt> ></prompt><userinput> conn = net_box:new('127.0.0.1', 3301)</userinput> +<prompt> ></prompt><userinput> conn.space.tester:delete{800}</userinput> +<prompt> ></prompt><userinput> table.insert(ta, 'conn delete done on tester.')</userinput> +<prompt> ></prompt><userinput> conn.space.tester:insert{800, 'data'}</userinput> +<prompt> ></prompt><userinput> table.insert(ta, 'conn insert done on tester, index 0')</userinput> +<prompt> ></prompt><userinput> table.insert(ta, ' primary key value = 800.')</userinput> +<prompt> ></prompt><userinput> wtuple = conn.space.tester:select(800)</userinput> +<prompt> ></prompt><userinput> table.insert(ta, 'conn select done on tester, index 0')</userinput> +<prompt> ></prompt><userinput> table.insert(ta, ' number of fields = ' .. #wtuple)</userinput> +<prompt> ></prompt><userinput> conn.space.tester:delete{800}</userinput> +<prompt> ></prompt><userinput> table.insert(ta, 'conn delete done on tester')</userinput> +<prompt> ></prompt><userinput> conn.space.tester:replace{800, 'New data', 'Extra data'}</userinput> +<prompt> ></prompt><userinput> table.insert(ta, 'conn:replace done on tester')</userinput> +<prompt> ></prompt><userinput> conn:timeout(0.5).space.tester:update({800}, {{'=', 2, 'Fld#1'}})</userinput> +<prompt> ></prompt><userinput> table.insert(ta, 'conn update done on tester')</userinput> +<prompt> ></prompt><userinput> conn:close()</userinput> +<prompt> ></prompt><userinput> table.insert(ta, 'conn close done')</userinput> +<prompt> ></prompt><userinput> end!</userinput> +--- +... +<prompt>tarantool></prompt><userinput> session.delimiter('')!</userinput> +--- +... +<prompt>tarantool></prompt><userinput> ta = {}</userinput> +--- +... +<prompt>tarantool></prompt><userinput> example()</userinput> +--- +... +<prompt>tarantool></prompt><userinput> ta</userinput> +--- +- - self:ping() succeeded + - ' (no surprise -- self connection is pre-established)' + - The local server listen address = 3301 + - conn delete done on tester. + - conn insert done on tester, index 0 + - ' primary key value = 800.' + - conn select done on tester, index 0 + - ' number of fields = 1' + - conn delete done on tester + - conn:replace done on tester + - conn update done on tester + - conn close done +... +<prompt>tarantool></prompt><userinput> box.space.tester:select(800) -- Prove that the update succeeded.</userinput> +--- +- [800, 'Fld#1', 'Extra data'] +... +</programlisting> +</para> +</section> <section xml:id="sp-shard"> <title>Package <code>shard</code></title> @@ -2653,8 +2660,8 @@ https://github.com/tarantool/shard/blob/master/README.md</link>. Get the space number and the primary-key value from the function's parameters. Pass the space number and the primary-key value to [curr] or [prev] to get a Shard Identification Number. If the number is equal to "me", perform the function directly because this is the responsible node. -Otherwise, use the box.net.box package to pass the function to the host and port of - the node that, according to the Shard List, is responsible for handling this tuple. +Otherwise, use the box.net package to pass the function to the host and port of +the node that, according to the Shard List, is responsible for handling this tuple. </programlisting> </para> </listitem> @@ -3013,12 +3020,13 @@ error: can't save snapshot, errno 17 (File exists) </variablelist> </section> -<section xml:id="sp-limitations"> -<title>A limitation that affects long-running Lua functions</title> +<section xml:id="multitasking"> +<title>Atomic execution</title> <para> - There is a limitation in stored procedures support one should - be aware of: execution atomicity. + In several places it's been noted that Lua processes occur in + fibers on a single thread. That is why there + can be a guarantee of execution atomicity. That requires emphasis. </para> <bridgehead renderas="sect4">Cooperative multitasking environment</bridgehead> <para> @@ -3059,10 +3067,67 @@ error: can't save snapshot, errno 17 (File exists) database state. Effectively, it's only possible to have CAS (compare-and-swap) -like atomic stored procedures: i.e. functions which select and then modify a record. - Multiple data change requests always run through a built-in yield point. </para> +<para> + At this point an objection could arise: "It's good that a single + data-change request will commit and yield, but surely there are + times when multiple data-change requests must happen without + yielding." The standard example is the money-transfer, where + $1 is withdrawn from account #1 and deposited into account #2. + If something interrupted after the withdrawal, then the + institution would be out of balance. For such cases, the + <code>begin ... commit|rollback</code> block was designed. +</para> + <variablelist> + <varlistentry> + <term xml:id="begin" xreflabel="begin()"> + <emphasis role="lua">box.begin()</emphasis> + </term> + <listitem><para> + From this point, implicit yields are suspended. + In effect the fiber which executes <code>box.begin()</code> + is starting an "active multi-request transaction", blocking all + other fibers until the transaction ends. + </para></listitem> + </varlistentry> + + <varlistentry> + <term xml:id="commit" xreflabel="commit()"> + <emphasis role="lua">box.commit()</emphasis> + </term> + <listitem><para> + End the currently active transaction, and make + all its data-change operations permanent. + </para></listitem> + </varlistentry> + + <varlistentry> + <term xml:id="rollback" xreflabel="rollback()"> + <emphasis role="lua">box.rollback()</emphasis> + </term> + <listitem><para> + End the currently active transaction, but cancel + all its data-change operations. An explicit call + to fiber.yield() will have the same effect. + </para></listitem> + </varlistentry> + + </variablelist> + +<para> +Example: +Assuming that in tuple set 'tester' there are tuples +in which the third field represents a positive dollar amount ... +Start a transaction, withdraw from tuple#1, deposit in tuple#2, +and end the transaction, making its effects permanent.<programlisting> +box.begin() +amount_of_money = 1.00 +box.space.tester:update({999}, {{'-', 3, amount_of_money}}) +box.space.tester:update({1000}, {{'+', 3, amount_of_money}}) +box.commit()</programlisting> +</para> </section> <section xml:id="errcode"> @@ -3388,7 +3453,7 @@ session.su(<replaceable>user-name</replaceable>) #allows changing current user <para> If a user types requests directly on the Tarantool server in its interactive mode, or if a user connects via telnet to the administrative port (using -<olink targetptr="admin_port"/> instead of primary_port), then the user by default is 'admin' and has +<olink targetptr="admin_port">admin</olink> instead of listen), then the user by default is 'admin' and has many privileges. If a user connects from an application program via one of the <olink targetptr="connectors">connectors</olink>, then the user by default is 'guest' and has few privileges. Typically an admin user will set up and configure objects, then diff --git a/doc/user/language-reference.xml b/doc/user/language-reference.xml index d1050ca013d65ebdbd63b6b13bb3e2fb5903efe5..c7832dca4806af3ad10299df556acd4fbe81bbfe 100644 --- a/doc/user/language-reference.xml +++ b/doc/user/language-reference.xml @@ -22,7 +22,7 @@ (also called the "binary protocol"), and provides full data access. </para> <para> - The default value of the port is <literal>3303</literal>, + The default value of the port is <literal>3301</literal>, as defined in the <olink targetptr="primary_port"/> configuration option. </para></listitem> diff --git a/doc/user/lua-and-packages.xml b/doc/user/lua-and-packages.xml index 889d6551e2b4c147903dcff058a2770b052bbcad..3cdee6a4ef5e84e95a97f8e84c3ffcaaedeb1e05 100644 --- a/doc/user/lua-and-packages.xml +++ b/doc/user/lua-and-packages.xml @@ -5,7 +5,7 @@ <chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude" - xml:id="language-reference"> + xml:id="lua-and-packages"> <title>Lua and the Tarantool Lua Packages</title> diff --git a/doc/user/plugins.xml b/doc/user/plugins.xml index fa9756cfb76e5b3cf527226caa96acf8752f509a..a8ca7a431176973d62639211ed7736a7f45285b8 100644 --- a/doc/user/plugins.xml +++ b/doc/user/plugins.xml @@ -46,7 +46,7 @@ can work on both SQL and Tarantool inside the same Lua routine. <para> The connection method is <code>box.net.sql.connect('mysql'|'pg', <replaceable>host</replaceable>, <replaceable>port</replaceable>, <replaceable>user</replaceable>, <replaceable>password</replaceable>, <replaceable>database</replaceable>)</code>. -The methods for select/insert/etc. are the same as the ones in <olink targetptr="sp-box-net-box">the box.net library</olink>. +The methods for select/insert/etc. are the same as the ones in <link linkend="sp-net-box">the net.box package</link>. </para> <para xml:id="plugin-mysql-example"> diff --git a/doc/user/proctitle.xml b/doc/user/proctitle.xml index 5476dce8bc6aa0aa518c07ee5ef855b091996db7..fc2c90c1c9c5bc88badf1369b7755126d6561328 100644 --- a/doc/user/proctitle.xml +++ b/doc/user/proctitle.xml @@ -42,18 +42,17 @@ </para></listitem> </itemizedlist> Possible port names are: <quote>pri</quote> for - <olink targetptr="primary_port"/>, <quote>sec</quote> for <olink - targetptr="secondary_port"/> and <quote>adm</quote> for <olink + <olink targetptr="primary_port">listen</olink>, and <quote>adm</quote> for <olink targetptr="admin_port"/>. </para> <para> For example: <itemizedlist> <listitem><para> - <command>tarantool: primary pri: 50000 sec: 50001 adm: 50002</command> + <command>tarantool: primary pri: 50000 adm: 50002</command> </para></listitem> <listitem><para> - <command>tarantool: primary@infobox pri: 15013 sec: 15523 adm: 10012</command> + <command>tarantool: primary@infobox pri: 15013 adm: 10012</command> </para></listitem> </itemizedlist> </para> diff --git a/doc/user/replication.xml b/doc/user/replication.xml index 2c0dd16531d39f4b90abad86dc48a3d5dc53a4ee..fd914269583fb1b181cce9b5d96c5599c5abe7c0 100644 --- a/doc/user/replication.xml +++ b/doc/user/replication.xml @@ -54,7 +54,7 @@ updates from the master having identical LSNs would not be applied. In fact, if replication is ON, Tarantool does not accept updates, even on its <olink - targetptr="primary_port"/>. + targetptr="primary_port">"listen" address</olink>. </para> </section> diff --git a/doc/user/server-administration.xml b/doc/user/server-administration.xml index e65cf2744569b7916137199e04bfe3ac6164078b..64b395764652f279e216e4d6470997d4e9e3ed19 100644 --- a/doc/user/server-administration.xml +++ b/doc/user/server-administration.xml @@ -61,7 +61,7 @@ File-name can be any script containing code for initializing. Effect: The code in the file is executed during startup. Example: <code>init.lua</code>. Notes: If a script is used, there will be no prompt. The script should contain -configuration information including "admin_port=..." or "primary_port=..." so +configuration information including "admin=..." or "listen=..." so that a separate program can connect to the server via one of the ports. </para> <para> @@ -161,7 +161,7 @@ Here is an example of an interactive-mode tarantool client session: <programlisting> <prompt>$ </prompt>tarantool [ tarantool will display an introductory message including version number here ] -tarantool> box.cfg{admin_port=3313, primary_port=3303} +tarantool> box.cfg{admin=3313, listen=3301} [ tarantool will display configuration information here ] tarantool> s = box.schema.create_space('tester') [ tarantool may display an in-progress message here ] @@ -189,10 +189,10 @@ Explanatory notes about what tarantool displayed in the above example: </para> <para> * Many requests return typed objects. - In the case of "box.cfg{admin_port=3313, primary_port=3303}", + In the case of "box.cfg{admin=3313, listen=3301}", this result is displayed on the screen. If the request had assigned the result to a variable, for example - "c = box.cfg{admin_port=3313, primary_port=3303}", then + "c = box.cfg{admin=3313, listen=3301}", then the result would not have been displayed on the screen. </para> <para> diff --git a/doc/user/stored-procedures.xml b/doc/user/stored-procedures.xml index 7ec2ed0fefdf3ad833bf17a2b3da95c87e832821..7df0bb4226160c08f2165a6659a5a568db76c77b 100644 --- a/doc/user/stored-procedures.xml +++ b/doc/user/stored-procedures.xml @@ -451,8 +451,8 @@ tarantool> <userinput>box.space.tester:update({0}, {{'^', 2, 4}})</userinput> (<link xlink:href="https://en.wikipedia.org/wiki/Cyclic_redundancy_check">CRC32</link>). The functions in <code>digest</code> are:<programlisting><code> digest.crc32(<replaceable>string</replaceable>) Returns 32-bit checksum made with CRC32. digest.crc32_update(<replaceable>number</replaceable>,<replaceable>string</replaceable>) Returns update of a checksum calculated with crc32. - digest.sha0(<replaceable>string</replaceable>) Returns 160-bit digest made with SHA-0. Not recommended. - digest.sha0_hex(<replaceable>string</replaceable>) Returns hexadecimal of a digest calculated with sha0. + digest.sha(<replaceable>string</replaceable>) Returns 160-bit digest made with SHA-0. Not recommended. + digest.sha_hex(<replaceable>string</replaceable>) Returns hexadecimal of a digest calculated with sha. digest.sha1(<replaceable>string</replaceable>) Returns 160-bit digest made with SHA-1. digest.sha1_hex(<replaceable>string</replaceable>) Returns hexadecimal of a digest calculated with sha1. digest.sha224(<replaceable>string</replaceable>) Returns 224-bit digest made with SHA-2. diff --git a/doc/user/tutorial.xml b/doc/user/tutorial.xml index 184c5d3fbd40a040a82d63c682deedc1a5dec16b..e900c30508ab9f9d967474f891ed3424b1795ce6 100644 --- a/doc/user/tutorial.xml +++ b/doc/user/tutorial.xml @@ -490,7 +490,7 @@ The server name is <computeroutput><filename>tarantool</filename></computeroutpu <para> The server starts in interactive mode and outputs a command prompt. To turn on the database, configure it: -<programlisting><prompt>tarantool></prompt> <userinput>box.cfg{admin_port=3313}</userinput></programlisting> +<programlisting><prompt>tarantool></prompt> <userinput>box.cfg{admin=3313}</userinput></programlisting> (this minimal example is sufficient). </para> @@ -508,7 +508,7 @@ If all goes well, you will see the server displaying progress as it initializes, 2014-06-10 11:53:41.095 ... 0.0M rows written 2014-06-10 11:53:41.126 ... done 2014-06-10 11:53:41.126 ... bound to admin port tcp://0.0.0.0:3313 -2014-06-10 11:53:41.127 ... I am primary +2014-06-10 11:53:41.127 ... ready to accept requests </programlisting> </para> @@ -637,8 +637,8 @@ inserted and selected tuples. "script_dir" no longer exists, use #! instead (see below re "Tarantool = a shell script processor"). </para> <para>CHANGES IN PORT CONFIGURATION. - "secondary_port" no longer exists; use "primary_port". - "replication_port" no longer exists; use "primary_port". + "secondary_port" no longer exists; use "listen". + "replication_port" no longer exists; use "listen". "memcached" no longer exists (memcached is not supported). The admin port is Lua-only now, and the lua prefix is gone. </para> diff --git a/extra/CMakeLists.txt b/extra/CMakeLists.txt index f0c48389ea71011d9f5ec6f3643bd7051c552305..b6cdf165e3b40f4d5ef2496efa657771c5fed398 100644 --- a/extra/CMakeLists.txt +++ b/extra/CMakeLists.txt @@ -3,23 +3,23 @@ # if (ENABLE_RPM) # chmod +x 655 - install (FILES tarantool DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/init.d - PERMISSIONS - OWNER_READ OWNER_WRITE - GROUP_READ GROUP_EXECUTE - WORLD_READ WORLD_EXECUTE) - # chmod +x 755 - install (FILES tarantool_multi.sh DESTINATION bin - PERMISSIONS - OWNER_READ OWNER_WRITE OWNER_EXECUTE - GROUP_READ GROUP_EXECUTE - WORLD_READ WORLD_EXECUTE) - # chmod +x 755 - install (FILES tarantool_deploy.sh DESTINATION bin - PERMISSIONS - OWNER_READ OWNER_WRITE OWNER_EXECUTE - GROUP_READ GROUP_EXECUTE - WORLD_READ WORLD_EXECUTE) +# install (FILES tarantool DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/init.d +# PERMISSIONS +# OWNER_READ OWNER_WRITE +# GROUP_READ GROUP_EXECUTE +# WORLD_READ WORLD_EXECUTE) +# # chmod +x 755 +# install (FILES tarantool_multi.sh DESTINATION bin +# PERMISSIONS +# OWNER_READ OWNER_WRITE OWNER_EXECUTE +# GROUP_READ GROUP_EXECUTE +# WORLD_READ WORLD_EXECUTE) +# # chmod +x 755 +# install (FILES tarantool_deploy.sh DESTINATION bin +# PERMISSIONS +# OWNER_READ OWNER_WRITE OWNER_EXECUTE +# GROUP_READ GROUP_EXECUTE +# WORLD_READ WORLD_EXECUTE) endif() configure_file(rpm/tarantool.rpm.spec.in rpm/tarantool.rpm.spec @ONLY) diff --git a/extra/rpm/tarantool.rpm.spec.in b/extra/rpm/tarantool.rpm.spec.in index b241071d92c97f844c075078ae061a30778965f3..828cd7bb0d7ea748aff42959e01f01cc1b8e5193 100644 --- a/extra/rpm/tarantool.rpm.spec.in +++ b/extra/rpm/tarantool.rpm.spec.in @@ -8,6 +8,11 @@ %define _source_filedigest_algorithm 0 %define _binary_filedigest_algorithm 0 +%global debug_package %{nil} +%global _enable_debug_package %{nil} +%global __debug_install_post %{nil} +%global __debug_package %{nil} + %bcond_without postgresql %bcond_without mysql @@ -27,7 +32,8 @@ BuildRequires: binutils-devel BuildRequires: perl-podlators %endif -# Strange bug. Fix according to http://www.jethrocarr.com/2012/05/23/bad-packaging-habits/ +# Strange bug. +# Fix according to http://www.jethrocarr.com/2012/05/23/bad-packaging-habits/ BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) Name: %{?scl_prefix}tarantool @@ -37,8 +43,9 @@ Group: Applications/Databases Summary: Tarantool - an efficient in-memory data store Vendor: tarantool.org License: BSD -Requires: %{?scl_prefix}tarantool-debuginfo = @RPM_PACKAGE_VERSION@-@RPM_PACKAGE_RELEASE@ Requires: readline +Provides: %{?scl_prefix}tarantool-debuginfo +Provides: %{?scl_prefix}tarantool-debug URL: http://tarantool.org Source0: @RPM_PACKAGE_SOURCE_FILE_NAME@ %description @@ -153,7 +160,7 @@ tarantool-sql-module. .. cmake_key_value('CMAKE_INSTALL_INFODIR', '%{_infodir}') .. cmake_key_value('CMAKE_INSTALL_MANDIR', '%{_mandir}') .. cmake_key_value('CMAKE_INSTALL_LOCALSTATEDIR', '%{_localstatedir}') - .. ' %{!?scl:-DCMAKE_INSTALL_SYSCONFDIR=%{_sysconfdir}}' + .. ' %{!?scl:-DCMAKE_INSTALL_SYSCONFDIR=%{_sysconfdir}}' .. ' %{!?scl:-DENABLE_RPM=ON}' .. ' %{?scl:-DENABLE_RPM_SCL=ON}' .. dev_with('postgresql', 'WITH_POSTGRESQL') @@ -169,18 +176,13 @@ tarantool-sql-module. make DESTDIR=%{buildroot} install %post -groupadd tarantool > /dev/null 2>&1 -useradd -r -g tarantool tarantool > /dev/null 2>&1 -# Performe a single instance setup -/usr/bin/tarantool_deploy.sh --yes --quiet 1.1 %preun %files %defattr(-,root,root,-) -%dir "%{_datadir}/tarantool" -%{!?scl:"%{_datadir}/tarantool/00000000000000000001.snap"} +"%{_bindir}/tarantool" %dir "%{_datadir}/doc/tarantool" "%{_datadir}/doc/tarantool/README.md" @@ -188,11 +190,6 @@ useradd -r -g tarantool tarantool > /dev/null 2>&1 "%{_datadir}/doc/tarantool/box-protocol.txt" "%{_mandir}/man1/tarantool.1.gz" -"%{_bindir}/tarantool" -%{!?scl:"%{_bindir}/tarantool_multi.sh"} -%{!?scl:"%{_bindir}/tarantool_deploy.sh"} -%{!?scl:"%{_sysconfdir}/init.d/tarantool"} - %files sql-module %defattr(-,root,root,-) %dir "%{_datadir}/tarantool" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 082de681c698f1dad91f0d957051b56a542f93b7..9804d41ffe1c8461ca2b7667df3d92bdd88fb050 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,6 +27,7 @@ lua_source(lua_sources lua/errno.lua) lua_source(lua_sources lua/log.lua) lua_source(lua_sources lua/box_net_box.lua) lua_source(lua_sources lua/help.lua) +lua_source(lua_sources lua/tap.lua) file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/third_party/luafun) lua_source(lua_sources ../third_party/luafun/fun.lua) @@ -85,7 +86,6 @@ set (common_sources lua/init.cc lua/fiber.cc lua/trigger.cc - lua/errinj.cc lua/ipc.cc lua/socket.cc lua/session.cc diff --git a/src/box/CMakeLists.txt b/src/box/CMakeLists.txt index 31067cc95a445324da0755bc3282a113b562664c..12177aceb0bec7c7db4db5c5d89535f63b76f282 100644 --- a/src/box/CMakeLists.txt +++ b/src/box/CMakeLists.txt @@ -50,4 +50,5 @@ add_library(box lua/space.cc lua/info.cc lua/stat.cc + lua/error.cc ${bin_sources}) diff --git a/src/box/lua/call.cc b/src/box/lua/call.cc index 3c6929f8ece83f63c7284a7fbed3242a63a24c5c..7fed303683ba76dee760ce2407def2cc189d7487 100644 --- a/src/box/lua/call.cc +++ b/src/box/lua/call.cc @@ -29,6 +29,7 @@ #include "box/lua/call.h" #include "pickle.h" +#include "box/lua/error.h" #include "box/lua/tuple.h" #include "box/lua/index.h" #include "box/lua/space.h" @@ -304,7 +305,7 @@ boxffi_select(struct port *port, uint32_t space_id, uint32_t index_id, box_process(port, &request); return 0; } catch (Exception *e) { - /* will be hanled by box.raise() in Lua */ + /* will be hanled by box.error() in Lua */ return -1; } } @@ -368,27 +369,6 @@ lbox_delete(lua_State *L) return lua_gettop(L) - 3; } -static int -lbox_raise(lua_State *L) -{ - if (lua_gettop(L) == 0) { - /* re-throw saved exceptions (if any) */ - if (cord()->exception == NULL) - return 0; - cord()->exception->raise(); - return 0; - } - - if (lua_gettop(L) < 2) - luaL_error(L, "box.raise(): bad arguments"); - uint32_t code = lua_tointeger(L, 1); - if (code >= tnt_error_codes_enum_MAX) - luaL_error(L, "box.raise(): unknown error code"); - const char *str = lua_tostring(L, 2); - tnt_raise(ClientError, str, code); - return 0; -} - /** * A helper to find a Lua function by name and put it * on top of the stack. @@ -537,7 +517,6 @@ lbox_snapshot(struct lua_State *L) } static const struct luaL_reg boxlib[] = { - {"raise", lbox_raise}, {"snapshot", lbox_snapshot}, {NULL, NULL} }; @@ -560,6 +539,7 @@ box_lua_init(struct lua_State *L) luaL_register_module(L, "box.internal", boxlib_internal); lua_pop(L, 1); + box_lua_error_init(L); box_lua_tuple_init(L); box_lua_index_init(L); box_lua_space_init(L); diff --git a/src/box/lua/error.cc b/src/box/lua/error.cc new file mode 100644 index 0000000000000000000000000000000000000000..00d3baabef31e9ec42db683a600fc6b1e81eb643 --- /dev/null +++ b/src/box/lua/error.cc @@ -0,0 +1,172 @@ +/* + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include "box/lua/error.h" + +extern "C" { +#include <lua.h> +#include <lauxlib.h> +#include <lualib.h> +} /* extern "C" */ + +#include <fiber.h> +#include <errcode.h> +#include <errinj.h> + +#include "lua/utils.h" + +static int +lbox_raise(lua_State *L) +{ + uint32_t code = 0; + const char *reason = NULL; + const char *file = ""; + unsigned line = 0; + lua_Debug info; + + /* lua_type(L, 1) == LUA_TTABLE - box.error table */ + int top = lua_gettop(L); + if (top <= 1) { + /* re-throw saved exceptions (if any) */ + if (cord()->exception == NULL) + return 0; + cord()->exception->raise(); + return 0; + } else if (top >= 2 && lua_type(L, 2) == LUA_TNUMBER) { + code = lua_tointeger(L, 2); + reason = tnt_errcode_desc(code); + if (top > 2) { + /* Call string.format(reason, ...) to format message */ + lua_getglobal(L, "string"); + if (lua_isnil(L, -1)) + goto raise; + lua_getfield(L, -1, "format"); + if (lua_isnil(L, -1)) + goto raise; + lua_pushstring(L, reason); + for (int i = 3; i <= top; i++) + lua_pushvalue(L, i); + lua_call(L, top - 1, 1); + reason = lua_tostring(L, -1); + } + } else if (top == 2 && lua_istable(L, 2)) { + /* A special case that rethrows raw error (used by net.box) */ + lua_getfield(L, 2, "code"); + code = lua_tointeger(L, -1); + lua_pop(L, 1); + lua_getfield(L, 2, "reason"); + reason = lua_tostring(L, -1); + if (reason == NULL) + reason = ""; + lua_pop(L, 1); + } else { + luaL_error(L, "box.error(): bad arguments"); + } + +raise: + if (lua_getstack(L, 1, &info) && lua_getinfo(L, "Sl", &info)) { + if (*info.short_src) { + file = info.short_src; + } else if (*info.source) { + file = info.source; + } else { + file = "eval"; + } + line = info.currentline; + } + + /* see tnt_raise() */ + say_debug("ClientError at %s:%i", file, line); + throw new ClientError(file, line, reason, code); + return 0; +} + +static int +lbox_errinj_set(struct lua_State *L) +{ + char *name = (char*)luaL_checkstring(L, 1); + bool state = lua_toboolean(L, 2); + if (errinj_set_byname(name, state)) { + lua_pushfstring(L, "error: can't find error injection '%s'", name); + return 1; + } + lua_pushstring(L, "ok"); + return 1; +} + +static inline int +lbox_errinj_cb(struct errinj *e, void *cb_ctx) +{ + struct lua_State *L = (struct lua_State*)cb_ctx; + lua_pushstring(L, e->name); + lua_newtable(L); + lua_pushstring(L, "state"); + lua_pushboolean(L, e->state); + lua_settable(L, -3); + lua_settable(L, -3); + return 0; +} + +static int +lbox_errinj_info(struct lua_State *L) +{ + lua_newtable(L); + errinj_foreach(lbox_errinj_cb, L); + return 1; +} + +void +box_lua_error_init(struct lua_State *L) { + static const struct luaL_reg errorlib[] = { + {NULL, NULL} + }; + luaL_register(L, "box.error", errorlib); + for (int i = 0; i < tnt_error_codes_enum_MAX; i++) { + const char *name = tnt_error_codes[i].errstr; + if (strstr(name, "UNUSED") || strstr(name, "RESERVED")) + continue; + assert(strncmp(name, "ER_", 3) == 0); + lua_pushnumber(L, i); + /* cut ER_ prefix from constant */ + lua_setfield(L, -2, name + 3); + } + lua_newtable(L); + lua_pushcfunction(L, lbox_raise); + lua_setfield(L, -2, "__call"); + lua_setmetatable(L, -2); + lua_pop(L, 1); + + static const struct luaL_reg errinjlib[] = { + {"info", lbox_errinj_info}, + {"set", lbox_errinj_set}, + {NULL, NULL} + }; + /* box.error.injection is not set by register_module */ + luaL_register_module(L, "box.error.injection", errinjlib); + lua_pop(L, 1); +} diff --git a/src/lua/errinj.h b/src/box/lua/error.h similarity index 88% rename from src/lua/errinj.h rename to src/box/lua/error.h index dce6b11fa3c6083235a61c1d397966429f2a1769..f0dc5895f9834700a901211f522b3ec62afbd12c 100644 --- a/src/lua/errinj.h +++ b/src/box/lua/error.h @@ -1,6 +1,5 @@ -#ifndef INCLUDES_TARANTOOL_LUA_ERRINJ_H -#define INCLUDES_TARANTOOL_LUA_ERRINJ_H - +#ifndef INCLUDES_TARANTOOL_LUA_ERROR_H +#define INCLUDES_TARANTOOL_LUA_ERROR_H /* * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following @@ -31,6 +30,8 @@ */ struct lua_State; -void tarantool_lua_errinj_init(struct lua_State *L); -#endif /* INCLUDES_TARANTOOL_LUA_ERRINJ_H */ +void +box_lua_error_init(struct lua_State *L); + +#endif /* INCLUDES_TARANTOOL_LUA_ERROR_H */ diff --git a/src/box/lua/index.cc b/src/box/lua/index.cc index 44341362e890f0b77e4540e009ae7191381febc0..0371fd0990de3d0659b61b0a3292cc32d9e467b9 100644 --- a/src/box/lua/index.cc +++ b/src/box/lua/index.cc @@ -53,7 +53,7 @@ boxffi_index_len(uint32_t space_id, uint32_t index_id) try { return check_index(space_id, index_id)->size(); } catch (Exception *) { - return (size_t) -1; /* handled by box.raise() in Lua */ + return (size_t) -1; /* handled by box.error() in Lua */ } } @@ -63,7 +63,7 @@ boxffi_index_random(uint32_t space_id, uint32_t index_id, uint32_t rnd) try { return check_index(space_id, index_id)->random(rnd); } catch (Exception *) { - return (struct tuple *) -1; /* handled by box.raise() in Lua */ + return (struct tuple *) -1; /* handled by box.error() in Lua */ } } @@ -99,7 +99,7 @@ boxffi_index_iterator(uint32_t space_id, uint32_t index_id, int type, } catch (Exception *) { if (it) it->free(it); - /* will be hanled by box.raise() in Lua */ + /* will be hanled by box.error() in Lua */ return NULL; } } diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua index 6780aea771bf923c8c0c5fe1e69dd477e5a4d267..4d8c73e3a27a8b10b6d5dff00ca00b4f3f557b02 100644 --- a/src/box/lua/load_cfg.lua +++ b/src/box/lua/load_cfg.lua @@ -70,8 +70,7 @@ local function reload_cfg(oldcfg, newcfg) end for key, val in pairs(newcfg) do if dynamic_cfg[key] == nil then - box.raise(box.error.RELOAD_CFG, - "Can't set option '"..key.."' dynamically"); + box.error(box.error.RELOAD_CFG, key); end if val == "" then val = nil diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua index cebfe88ad7f03b2daa3a7ff472dbb2b31545fb0f..ad6f5190f1cdfeab1536d7d1d5736366aea7e7c3 100644 --- a/src/box/lua/schema.lua +++ b/src/box/lua/schema.lua @@ -69,8 +69,8 @@ local function user_resolve(user) return tuple[1] end -box.begin = function() if ffi.C.boxffi_txn_begin() == -1 then box.raise() end end -box.commit = function() if ffi.C.boxffi_txn_commit() == -1 then box.raise() end end +box.begin = function() if ffi.C.boxffi_txn_begin() == -1 then box.error() end end +box.commit = function() if ffi.C.boxffi_txn_commit() == -1 then box.error() end end box.rollback = ffi.C.boxffi_txn_rollback; box.schema.space = {} @@ -89,8 +89,7 @@ box.schema.space.create = function(name, options) if options.if_not_exists then return box.space[name], "not created" else - box.raise(box.error.SPACE_EXISTS, - "Space '"..name.."' already exists") + box.error(box.error.SPACE_EXISTS, name) end end local id @@ -134,8 +133,7 @@ box.schema.space.drop = function(space_id) end end if _space:delete{space_id} == nil then - box.raise(box.error.NO_SUCH_SPACE, - "Space "..space_id.." does not exist") + box.error(box.error.NO_SUCH_SPACE, '#'..tostring(space_id)) end end box.schema.space.rename = function(space_id, space_name) @@ -195,12 +193,10 @@ box.schema.index.rename = function(space_id, index_id, name) end box.schema.index.alter = function(space_id, index_id, options) if box.space[space_id] == nil then - box.raise(box.error.NO_SUCH_SPACE, - "Space "..space_id.." does not exist") + box.error(box.error.NO_SUCH_SPACE, '#'..tostring(space_id)) end if box.space[space_id].index[index_id] == nil then - box.raise(box.error.NO_SUCH_INDEX, - "Index "..index_id.." not found in space"..space_id) + box.error(box.error.NO_SUCH_INDEX, index_id, box.space[space_id].name) end if options == nil then return @@ -217,7 +213,7 @@ box.schema.index.alter = function(space_id, index_id, options) end if options.id ~= nil then if options.parts ~= nil then - box.raise(box.error.PROC_LUA, + box.error(box.error.PROC_LUA, "Don't know how to update both id and parts") end ops = {} @@ -324,7 +320,7 @@ function box.schema.space.bless(space) index_mt.len = function(index) local ret = builtin.boxffi_index_len(index.space.id, index.id) if ret == -1 then - box.raise() + box.error() end return tonumber(ret) end @@ -335,7 +331,7 @@ function box.schema.space.bless(space) -- min and max index_mt.min = function(index, key) if index.type == 'HASH' then - box.raise(box.error.UNSUPPORTED, 'HASH does not support min()') + box.error(box.error.UNSUPPORTED, 'HASH', 'min()') end local lst = index:select(key, { iterator = 'GE', limit = 1 })[1] if lst ~= nil then @@ -346,7 +342,7 @@ function box.schema.space.bless(space) end index_mt.max = function(index, key) if index.type == 'HASH' then - box.raise(box.error.UNSUPPORTED, 'HASH does not support max()') + box.error(box.error.UNSUPPORTED, 'HASH', 'max()') end local lst = index:select(key, { iterator = 'LE', limit = 1 })[1] if lst ~= nil then @@ -359,7 +355,7 @@ function box.schema.space.bless(space) rnd = rnd or math.random() local tuple = builtin.boxffi_index_random(index.space.id, index.id, rnd) if tuple == ffi.cast('void *', -1) then - box.raise() -- error + box.error() -- error elseif tuple ~= nil then return box.tuple.bless(tuple) else @@ -377,9 +373,7 @@ function box.schema.space.bless(space) elseif box.index[opts.iterator] then itype = box.index[opts.iterator] elseif opts.iterator ~= nil then - box.raise(box.error.ITERATOR_TYPE, - "Unknown iterator type '".. - tostring(opts.iterator).."'") + box.error(box.error.ITERATOR_TYPE, tostring(opts.iterator)) end end @@ -387,7 +381,7 @@ function box.schema.space.bless(space) local cdata = builtin.boxffi_index_iterator(index.space.id, index.id, itype, keybuf); if cdata == nil then - box.raise() + box.error() end return fun.wrap(iterator_gen, keybuf, ffi.gc(cdata, iterator_cdata_gc)) @@ -418,9 +412,7 @@ function box.schema.space.bless(space) local function check_index(space, index_id) if space.index[index_id] == nil then - box.raise(box.error.NO_SUCH_INDEX, - string.format("No index #%d is defined in space %d", index_id, - space.id)) + box.error(box.error.NO_SUCH_INDEX, index_id, space.name) end end @@ -429,15 +421,14 @@ function box.schema.space.bless(space) port.size = 0; if builtin.boxffi_select(ffi.cast(port_t, port), index.space.id, index.id, box.index.EQ, 0, 2, key, key_end) ~=0 then - return box.raise() + return box.error() end if port.size == 0 then return elseif port.size == 1 then return box.tuple.bless(port.ret[0]) else - box.raise(box.error.MORE_THAN_ONE_TUPLE, - "More than one tuple found by get()") + box.error(box.error.MORE_THAN_ONE_TUPLE) end end @@ -469,7 +460,7 @@ function box.schema.space.bless(space) port.size = 0; if builtin.boxffi_select(ffi.cast(port_t, port), index.space.id, index.id, iterator, offset, limit, key, key_end) ~=0 then - return box.raise() + return box.error() end local ret = {} @@ -492,7 +483,7 @@ function box.schema.space.bless(space) end index_mt.alter= function(index, options) if index.id == nil or index.space == nil then - box.raise(box.error.PROC_LUA, "Usage: index:alter{opts}") + box.error(box.error.PROC_LUA, "Usage: index:alter{opts}") end return box.schema.index.alter(index.space.id, index.id, options) end @@ -620,7 +611,7 @@ function box.schema.space.bless(space) space_mt.run_triggers = function(space, yesno) local space = ffi.C.space_by_id(space.id) if space == nil then - box.raise(box.error.NO_SUCH_SPACE, "Space not found") + box.error(box.error.NO_SUCH_SPACE, space.name) end ffi.C.space_run_triggers(space, yesno) end @@ -662,8 +653,7 @@ local function object_resolve(object_type, object_name) if object_type == 'space' then local space = box.space[object_name] if space == nil then - box.raise(box.error.NO_SUCH_SPACE, - "Space '"..object_name.."' does not exist") + box.error(box.error.NO_SUCH_SPACE, object_name) end return space.id end @@ -678,8 +668,7 @@ local function object_resolve(object_type, object_name) if func then return func[1] else - box.raise(box.error.NO_SUCH_FUNCTION, - "Function '"..object_name.."' does not exist") + box.error(box.error.NO_SUCH_FUNCTION, object_name) end end if object_type == 'role' then @@ -693,13 +682,11 @@ local function object_resolve(object_type, object_name) if role then return role[1] else - box.raise(box.error.NO_SUCH_USER, - "Role '"..object_name.."' does not exist") + box.error(box.error.NO_SUCH_USER, object_name) end end - box.raise(box.error.UNKNOWN_SCHEMA_OBJECT, - "Unknown object type '"..object_type.."'") + box.error(box.error.UNKNOWN_SCHEMA_OBJECT, object_type) end box.schema.func = {} @@ -707,8 +694,7 @@ box.schema.func.create = function(name) local _func = box.space[box.schema.FUNC_ID] local func = _func.index['name']:get{name} if func then - box.raise(box.error.FUNCTION_EXISTS, - "Function '"..name.."' already exists") + box.error(box.error.FUNCTION_EXISTS, name) end _func:auto_increment{session.uid(), name} end @@ -748,8 +734,7 @@ end box.schema.user.create = function(name, opts) local uid = user_resolve(name) if uid then - box.raise(box.error.USER_EXISTS, - "User '"..name.."' already exists") + box.error(box.error.USER_EXISTS, name) end if opts == nil then opts = {} @@ -765,8 +750,7 @@ end box.schema.user.drop = function(name) local uid = user_resolve(name) if uid == nil then - box.raise(box.error.NO_SUCH_USER, - "User '"..name.."' does not exist") + box.error(box.error.NO_SUCH_USER, name) end -- recursive delete of user data local _priv = box.space[box.schema.PRIV_ID] @@ -789,8 +773,7 @@ box.schema.user.grant = function(user_name, privilege, object_type, object_name, grantor) local uid = user_resolve(user_name) if uid == nil then - box.raise(box.error.NO_SUCH_USER, - "User '"..user_name.."' does not exist") + box.error(box.error.NO_SUCH_USER, user_name) end privilege = privilege_resolve(privilege) local oid = object_resolve(object_type, object_name) @@ -806,8 +789,7 @@ end box.schema.user.revoke = function(user_name, privilege, object_type, object_name) local uid = user_resolve(user_name) if uid == nil then - box.raise(box.error.NO_SUCH_USER, - "User '"..name.."' does not exist") + box.error(box.error.NO_SUCH_USER, name) end privilege = privilege_resolve(privilege) local oid = object_resolve(object_type, object_name) @@ -830,8 +812,7 @@ box.schema.role = {} box.schema.role.create = function(name) local uid = user_resolve(name) if uid then - box.raise(box.error.USER_EXISTS, - "Role '"..name.."' already exists") + box.error(box.error.USER_EXISTS, name) end local _user = box.space[box.schema.USER_ID] _user:auto_increment{session.uid(), name, 'role'} diff --git a/src/box/schema.h b/src/box/schema.h index c8f71c885ce955066317d484852b528ddb309fd7..69b63f66b9464b5f0b245af079b0cc3b4c20137b 100644 --- a/src/box/schema.h +++ b/src/box/schema.h @@ -29,6 +29,7 @@ * SUCH DAMAGE. */ #include "exception.h" +#include <stdio.h> /* snprintf */ enum schema_id { /** Start of the reserved range of system spaces. */ @@ -81,7 +82,9 @@ space_cache_find(uint32_t id) if (space) return space; - tnt_raise(ClientError, ER_NO_SUCH_SPACE, id); + char name[12]; + snprintf(name, sizeof(name), "#%u", id); + tnt_raise(ClientError, ER_NO_SUCH_SPACE, name); } /** diff --git a/src/box/space.h b/src/box/space.h index 73bf6ce8f1e5846e9200a2697385e305df63d8fb..3111b03c33f94eb64fb4f480a96987c7b56696ba 100644 --- a/src/box/space.h +++ b/src/box/space.h @@ -268,7 +268,7 @@ index_find(struct space *space, uint32_t index_id) Index *index = space_index(space, index_id); if (index == NULL) tnt_raise(LoggedError, ER_NO_SUCH_INDEX, index_id, - space_id(space)); + space->def.name); return index; } diff --git a/src/errcode.h b/src/errcode.h index 4da99c65721600502ff5548cc48bd5042dea407f..d6754b9e197ec0997371b43d9d96ef6478b936ae 100644 --- a/src/errcode.h +++ b/src/errcode.h @@ -59,7 +59,7 @@ enum { TNT_ERRMSG_MAX = 512 }; /* 7 */_(ER_SECONDARY, 2, "Can't modify data upon a request on the secondary port.") \ /* 8 */_(ER_INJECTION, 2, "Error injection '%s'") \ /* 9 */_(ER_CREATE_SPACE, 2, "Failed to create space %u: %s") \ - /* 10 */_(ER_SPACE_EXISTS, 2, "Space %u already exists") \ + /* 10 */_(ER_SPACE_EXISTS, 2, "Space '%s' already exists") \ /* 11 */_(ER_DROP_SPACE, 2, "Can't drop space %u: %s") \ /* 12 */_(ER_ALTER_SPACE, 2, "Can't modify space %u: %s") \ /* 13 */_(ER_INDEX_TYPE, 2, "Unsupported index type supplied for index %u in space %u") \ @@ -84,13 +84,13 @@ enum { TNT_ERRMSG_MAX = 512 }; /* 32 */_(ER_PROC_LUA, 2, "%s") \ /* 33 */_(ER_NO_SUCH_PROC, 2, "Procedure '%.*s' is not defined") \ /* 34 */_(ER_NO_SUCH_TRIGGER, 2, "Trigger is not found") \ - /* 35 */_(ER_NO_SUCH_INDEX, 2, "No index #%u is defined in space %u") \ - /* 36 */_(ER_NO_SUCH_SPACE, 2, "Space %u does not exist") \ + /* 35 */_(ER_NO_SUCH_INDEX, 2, "No index #%u is defined in space '%s'") \ + /* 36 */_(ER_NO_SUCH_SPACE, 2, "Space '%s' does not exist") \ /* 37 */_(ER_NO_SUCH_FIELD, 2, "Field %u was not found in the tuple") \ /* 38 */_(ER_SPACE_FIELD_COUNT, 2, "Tuple field count %u does not match space %u field count %u") \ /* 39 */_(ER_INDEX_FIELD_COUNT, 2, "Tuple field count %u is less than required by a defined index (expected %u)") \ /* 40 */_(ER_WAL_IO, 2, "Failed to write to disk") \ - /* 41 */_(ER_MORE_THAN_ONE_TUPLE, 2, "More than one tuple found") \ + /* 41 */_(ER_MORE_THAN_ONE_TUPLE, 2, "More than one tuple found by get()") \ /* 42 */_(ER_ACCESS_DENIED, 2, "%s access denied for user '%s'") \ /* 43 */_(ER_CREATE_USER, 2, "Failed to create user '%s': %s") \ /* 44 */_(ER_DROP_USER, 2, "Failed to drop user '%s': %s") \ @@ -121,7 +121,7 @@ enum { TNT_ERRMSG_MAX = 512 }; /* 69 */_(ER_MISSING_REQUEST_FIELD, 2, "Missing mandatory field '%s' in request") \ /* 70 */_(ER_IDENTIFIER, 2, "Invalid identifier '%s' (expected letters, digits or an underscore)") \ /* 71 */_(ER_DROP_FUNCTION, 2, "Can't drop function %u: %s") \ - /* 72 */_(ER_ITERATOR_TYPE, 2, "Unknown iterator type %s") \ + /* 72 */_(ER_ITERATOR_TYPE, 2, "Unknown iterator type '%s'") \ /* 73 */_(ER_REPLICA_MAX, 2, "Replica count limit reached: %u") \ /* 74 */_(ER_INVALID_XLOG, 2, "Failed to read xlog: %lld") \ /* 75 */_(ER_INVALID_XLOG_NAME, 2, "Invalid xlog name: expected %lld got %lld") \ @@ -146,7 +146,7 @@ extern struct errcode_record tnt_error_codes[]; static inline const char *tnt_errcode_str(uint32_t errcode) { if (errcode >= tnt_error_codes_enum_MAX) { - /* Unknown error code - can be triggered using box.raise() */ + /* Unknown error code - can be triggered using box.error() */ return "ER_UNKNOWN"; } return tnt_error_codes[errcode].errstr; diff --git a/src/lua/box_net_box.lua b/src/lua/box_net_box.lua index 517fe3fb0739c5fe3220c9f466d0719f06dcfec5..149f25552a21970fa64ea86bde932fef469bd8e2 100644 --- a/src/lua/box_net_box.lua +++ b/src/lua/box_net_box.lua @@ -171,15 +171,11 @@ local proto = { opts = {} end if spaceno == nil or type(spaceno) ~= 'number' then - box.raise(box.error.NO_SUCH_SPACE, - string.format("Space %s does not exist", tostring(spaceno))) + box.error(box.error.NO_SUCH_SPACE, '#'..tostring(spaceno)) end if indexno == nil or type(indexno) ~= 'number' then - box.raise(box.error.NO_SUCH_INDEX, - string.format("No index #%s is defined in space %s", - tostring(spaceno), - tostring(indexno))) + box.error(box.error.NO_SUCH_INDEX, indexno, '#'..tostring(spaceno)) end local body = { @@ -203,8 +199,7 @@ local proto = { if type(opts.iterator) == 'string' then local iterator = box.index[ opts.iterator ] if iterator == nil then - box.raise(box.error.INVALID_MSGPACK, - "Wrong iterator " .. opts.iterator) + box.error(box.error.ITERATOR_TYPE, tostring(opts.iterator)) end body[ITERATOR] = iterator else @@ -266,8 +261,7 @@ local function space_metatable(self) if #res == 1 then return res[1] end - box.raise(box.error.MORE_THAN_ONE_TUPLE, - "More than one tuple found by get()") + box.error(box.error.MORE_THAN_ONE_TUPLE) end } } @@ -291,8 +285,7 @@ local function index_metatable(self) if #res == 1 then return res[1] end - box.raise(box.error.MORE_THAN_ONE_TUPLE, - "More than one tuple found by get()") + box.error(box.error.MORE_THAN_ONE_TUPLE) end, min = function(idx, key) @@ -425,7 +418,7 @@ local remote_methods = { if not cn:wait_connected(timeout) then cn:close() - box.raise(box.error.TIMEOUT, 'Timeout exceeded') + box.error(box.error.TIMEOUT) end return cn end @@ -845,15 +838,14 @@ local remote_methods = { if self.state == 'closed' then if raise then - box.raise(box.error.NO_CONNECTION, - "Connection was closed") + box.error(box.error.NO_CONNECTION) end end if self.timeouts[fid] <= 0 then self.timeouts[fid] = nil if raise then - box.raise(box.error.TIMEOUT, 'Timeout exceeded') + box.error(box.error.TIMEOUT) else return { hdr = { [TYPE] = bit.bor(ERROR_TYPE, box.error.TIMEOUT) }, @@ -893,7 +885,7 @@ local remote_methods = { if response == nil then if raise then - box.raise(box.error.TIMEOUT, 'Timeout exceeded') + box.error(box.error.TIMEOUT) else return { hdr = { [TYPE] = bit.bor(ERROR_TYPE, box.error.TIMEOUT) }, @@ -903,8 +895,10 @@ local remote_methods = { end if raise and response.hdr[TYPE] ~= OK then - local errcode = bit.band(response.hdr[TYPE], ERROR - 1) - box.raise(errcode, response.body[ERROR]) + box.error({ + code = response.hdr[TYPE], + reason = response.body[ERROR] + }) end if response.body[DATA] ~= nil then @@ -971,8 +965,16 @@ remote.self = { end } -setmetatable(remote.self, { __index = box }) +setmetatable(remote.self, { + __index = function(self, key) + if key == 'space' then + -- proxy self.space to box.space + return require('box').space + end + return nil + end +}) return remote diff --git a/src/lua/console.lua b/src/lua/console.lua index 3bc0ff68ca172fef163c66f4d4cea0a43ba597ef..3db0a7053fff830ed0fbf0dacb8eab3b00ffc5c1 100644 --- a/src/lua/console.lua +++ b/src/lua/console.lua @@ -26,7 +26,7 @@ local function format(status, ...) return formatter.encode(res) end -local function local_eval(self, line, ...) +local function local_eval(self, line) -- -- Attempt to append 'return ' before the chunk: if the chunk is -- an expression, this pushes results of the expression onto the @@ -40,7 +40,7 @@ local function local_eval(self, line, ...) if not fun then return format(false, errmsg) end - return format(pcall(fun, ...)) + return format(pcall(fun)) end local function eval(line) @@ -55,7 +55,7 @@ local local_mt = { } } -local function remote_eval(self, line, ...) +local function remote_eval(self, line) -- -- call remote 'console.eval' function using 'dostring' and return result -- @@ -66,7 +66,7 @@ local function remote_eval(self, line, ...) return format(status, res) end -- return formatted output from remote - return res[1][0] + return res[1][1] end local function remote_close(self) @@ -136,7 +136,7 @@ local function connect(...) if not session.storage.console then error("console.connect() works only in interactive mode") end - local conn = box.net.box.new(...) + local conn = require('net.box'):new(...) conn:ping() -- test connection table.insert(session.storage.console.handlers, setmetatable( { conn = conn}, remote_mt)) diff --git a/src/lua/errinj.cc b/src/lua/errinj.cc deleted file mode 100644 index 7425035d79728ddf7410d259dff9fbbb4e6d7ec5..0000000000000000000000000000000000000000 --- a/src/lua/errinj.cc +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "lua/errinj.h" - -#include <errinj.h> - -extern "C" { -#include <lua.h> -#include <lauxlib.h> -#include <lualib.h> -} /* extern "C" */ - -static int -lbox_errinj_set(struct lua_State *L) -{ - char *name = (char*)luaL_checkstring(L, 1); - bool state = lua_toboolean(L, 2); - if (errinj_set_byname(name, state)) { - lua_pushfstring(L, "error: can't find error injection '%s'", name); - return 1; - } - lua_pushstring(L, "ok"); - return 1; -} - -static inline int -lbox_errinj_cb(struct errinj *e, void *cb_ctx) -{ - struct lua_State *L = (struct lua_State*)cb_ctx; - lua_pushstring(L, e->name); - lua_newtable(L); - lua_pushstring(L, "state"); - lua_pushboolean(L, e->state); - lua_settable(L, -3); - lua_settable(L, -3); - return 0; -} - -static int -lbox_errinj_info(struct lua_State *L) -{ - lua_newtable(L); - errinj_foreach(lbox_errinj_cb, L); - return 1; -} - -static const struct luaL_reg errinjlib[] = { - {"info", lbox_errinj_info}, - {"set", lbox_errinj_set}, - {NULL, NULL} -}; - -/** Initialize box.errinj package. */ -void -tarantool_lua_errinj_init(struct lua_State *L) -{ - luaL_register(L, "errinj", errinjlib); - lua_pop(L, 1); -} diff --git a/src/lua/init.cc b/src/lua/init.cc index 31e13f3305d0d6026118fe24760eac586ccb80d0..8a3b910372ebaf72337ad5907ed457159f2756b6 100644 --- a/src/lua/init.cc +++ b/src/lua/init.cc @@ -47,7 +47,6 @@ extern "C" { #include <scoped_guard.h> #include "coeio.h" #include "lua/fiber.h" -#include "lua/errinj.h" #include "lua/ipc.h" #include "lua/errno.h" #include "lua/socket.h" @@ -77,7 +76,8 @@ extern char uuid_lua[], log_lua[], console_lua[], box_net_box_lua[], - help_lua[]; + help_lua[], + tap_lua[]; static const char *lua_sources[] = { init_lua, @@ -94,6 +94,7 @@ static const char *lua_modules[] = { "uuid", uuid_lua, "log", log_lua, "net.box", box_net_box_lua, + "tap", tap_lua, NULL }; @@ -173,25 +174,6 @@ lbox_coredump(struct lua_State *L __attribute__((unused))) return 1; } -static const struct luaL_reg errorlib [] = { - {NULL, NULL} -}; - -static void -tarantool_lua_error_init(struct lua_State *L) { - luaL_register(L, "box.error", errorlib); - for (int i = 0; i < tnt_error_codes_enum_MAX; i++) { - const char *name = tnt_error_codes[i].errstr; - if (strstr(name, "UNUSED") || strstr(name, "RESERVED")) - continue; - assert(strncmp(name, "ER_", 3) == 0); - lua_pushnumber(L, i); - /* cut ER_ prefix from constant */ - lua_setfield(L, -2, name + 3); - } - lua_pop(L, 1); -} - /* }}} */ /* @@ -293,7 +275,6 @@ tarantool_lua_init(const char *tarantool_bin, int argc, char **argv) lua_register(L, "tonumber64", lbox_tonumber64); lua_register(L, "coredump", lbox_coredump); - tarantool_lua_errinj_init(L); tarantool_lua_fiber_init(L); tarantool_lua_cjson_init(L); tarantool_lua_yaml_init(L); @@ -302,7 +283,6 @@ tarantool_lua_init(const char *tarantool_bin, int argc, char **argv) tarantool_lua_socket_init(L); tarantool_lua_bsdsocket_init(L); tarantool_lua_session_init(L); - tarantool_lua_error_init(L); tarantool_lua_pickle_init(L); luaopen_msgpack(L); lua_pop(L, 1); diff --git a/src/lua/tap.lua b/src/lua/tap.lua new file mode 100644 index 0000000000000000000000000000000000000000..83356030be80a6053c915e7d6650a71e2ea4a379 --- /dev/null +++ b/src/lua/tap.lua @@ -0,0 +1,215 @@ +--- tap.lua internal file +--- +--- The Test Anything Protocol vesion 13 producer +--- + +local yaml = require('yaml') +local ffi = require('ffi') -- for iscdata + +local function traceback(level) + local trace = {} + level = level or 3 + while true do + local info = debug.getinfo(level, "nSl") + if not info then break end + local frame = { + source = info.source; + src = info.short_src; + line = info.linedefined or 0; + what = info.what; + name = info.name; + namewhat = info.namewhat; + filename = info.source:sub(1, 1) == "@" and info.source:sub(2) or + 'eval' + } + table.insert(trace, frame) + level = level + 1 + end + return trace +end + +local function diag(test, fmt, ...) + io.write(string.rep(' ', 4 * test.level), "# ", string.format(fmt, ...), + "\n") +end + +local function ok(test, cond, message, extra) + test.total = test.total + 1 + io.write(string.rep(' ', 4 * test.level)) + if cond then + io.write(string.format("ok - %s\n", message)) + return true + end + + test.failed = test.failed + 1 + io.write(string.format("not ok - %s\n", message)) + extra = extra or {} + if test.trace then + local frame = debug.getinfo(3, "Sl") + extra.trace = traceback() + extra.filename = extra.trace[#extra.trace].filename + extra.line = extra.trace[#extra.trace].line + end + if next(extra) == nil then + return false -- don't have extra information + end + -- print aligned yaml output + for line in yaml.encode(extra):gmatch("[^\n]+") do + io.write(string.rep(' ', 2 + 4 * test.level), line, "\n") + end + return false +end + +local function fail(test, message, extra) + return ok(test, false, message, extra) +end + +local function skip(test, message, extra) + ok(test, true, message.." # skip", extra) +end + +local function is(test, got, expected, message, extra) + extra = extra or {} + extra.got = got + extra.expected = expected + return ok(test, got == expected, message, extra) +end + +local function isnt(test, got, unexpected, message, extra) + extra = extra or {} + extra.got = got + extra.unexpected = unexpected + return ok(test, got ~= unexpected, message, extra) +end + +local function isnil(test, v, message, extra) + return is(test, not v and 'nil' or v, 'nil', message, extra) +end + +local function isnumber(test, v, message, extra) + return is(test, type(v), 'number', message, extra) +end + +local function isstring(test, v, message, extra) + return is(test, type(v), 'string', message, extra) +end + +local function istable(test, v, message, extra) + return is(test, type(v), 'table', message, extra) +end + +local function isboolean(test, v, message, extra) + return is(test, type(v), 'boolean', message, extra) +end + +local function isudata(test, v, utype, message, extra) + extra = extra or {} + extra.expected = 'userdata<'..utype..'>' + if type(v) == 'userdata' then + extra.got = 'userdata<'..getmetatable(v)..'>' + return ok(test, getmetatable(v) == utype, message, extra) + else + extra.got = type(v) + return fail(test, message, extra) + end +end + +local function iscdata(test, v, ctype, message, extra) + extra = extra or {} + extra.expected = ffi.typeof(ctype) + if type(v) == 'cdata' then + extra.got = ffi.typeof(v) + return ok(test, ffi.istype(ctype, v), message, extra) + else + extra.got = type(v) + return fail(test, message, extra) + end +end + +local test_mt +local function test(parent, name, fun) + local level = parent ~= nil and parent.level + 1 or 0 + local test = setmetatable({ + parent = parent; + name = name; + level = level; + total = 0; + failed = 0; + planned = 0; + trace = parent == nil and true or parent.trace; + }, test_mt) + if fun ~= nil then + test:diag('%s', test.name) + fun(test) + test:diag('%s: end', test.name) + return test:check() + else + return test + end +end + +local function plan(test, planned) + test.planned = planned + io.write(string.rep(' ', 4 * test.level), string.format("1..%d\n", planned)) +end + +local function check(test) + if test.checked then + error('check called twice') + end + test.checked = true + if test.planned ~= test.total then + if test.parent ~= nil then + ok(test.parent, false, "bad plan", { planned = test.planned; + run = test.total}) + else + diag(test, string.format("bad plan: planned %d run %d", + test.planned, test.total)) + end + elseif test.failed > 0 then + if test.parent ~= nil then + ok(test.parent, false, "failed subtests", { + failed = test.failed; + planned = test.planned; + }) + return false + else + diag(test, "failed subtest: %d", test.failed) + end + else + if test.parent ~= nil then + ok(test.parent, true, test.name) + end + end + return true +end + +test_mt = { + __index = { + test = test; + plan = plan; + check = check; + diag = diag; + ok = ok; + fail = fail; + skip = skip; + is = is; + isnt = isnt; + isnil = isnil; + isnumber = isnumber; + isstring = isstring; + istable = istable; + isboolean = isboolean; + isudata = isudata; + iscdata = iscdata; + } +} + +local function root_test(...) + io.write('TAP version 13', '\n') + return test(nil, ...) +end + +return { + test = root_test; +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 017e4998a5fda33e8afe4bc20930193caaa290e6..ad6576d4806507961cd2f2455bd649b6e0446679 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -13,13 +13,3 @@ add_custom_target(test-force add_subdirectory(unit) # Disable connector_c for 1.6 #add_subdirectory(connector_c) - -if (ENABLE_RPM) - install (FILES ${CMAKE_SOURCE_DIR}/src/box/bootstrap.snap - DESTINATION ${CMAKE_INSTALL_DATADIR}/tarantool - RENAME 00000000000000000001.snap) -elseif(NOT ENABLE_RPM_SCL) - install (FILES ${CMAKE_SOURCE_DIR}/src/box/bootstrap.snap - DESTINATION "${CMAKE_INSTALL_LOCALSTATEDIR}/lib/tarantool" - RENAME 00000000000000000001.snap) -endif() diff --git a/test/app/cfg.result b/test/app/cfg.result index 804aeb7327bdb676764a53f975588204543d8dc5..1ce036cf2d52286c3780141fd4461229e6948f2d 100644 --- a/test/app/cfg.result +++ b/test/app/cfg.result @@ -1,3 +1,3 @@ -false [string "-- load_cfg.lua - internal file..."]:100: Please call box.cfg{} first +false [string "-- load_cfg.lua - internal file..."]:99: Please call box.cfg{} first true table -false [string "-- load_cfg.lua - internal file..."]:100: Please call box.cfg{} first +false [string "-- load_cfg.lua - internal file..."]:99: Please call box.cfg{} first diff --git a/test/app/pcall.result b/test/app/pcall.result index e70f316bc71f624ac6e84a1e1646fd9aecb6442d..38429cee4f3dd09d68120c3431823f0cf01a2f86 100644 --- a/test/app/pcall.result +++ b/test/app/pcall.result @@ -4,7 +4,7 @@ pcall inside xpcall: true pcall is ok pcall with Lua error(): false some message -pcall with box.raise(): false some message +pcall with box.error(): false Illegal parameters, some message pcall with no return: 1 pcall with multireturn: true 1 2 3 -------------------------------------------------------------------------------- diff --git a/test/app/pcall.test.lua b/test/app/pcall.test.lua index 248ccbd7b6344cb687f062fa61ebbd10eb63bcfa..91557e3218925e2200b40bb60fbc9bfe052842b5 100755 --- a/test/app/pcall.test.lua +++ b/test/app/pcall.test.lua @@ -26,9 +26,9 @@ local status, msg = pcall(function() error('some message') end) print('pcall with Lua error():', status, msg:match('some message')) local status, msg = pcall(function() - box.raise(box.error.ILLEGAL_PARAMS, 'some message') + box.error(box.error.ILLEGAL_PARAMS, 'some message') end) -print('pcall with box.raise():', status, msg) +print('pcall with box.error():', status, msg) print('pcall with no return:', select('#', pcall(function() end))) print('pcall with multireturn:', pcall(function() return 1, 2, 3 end)) diff --git a/test/app/tap.result b/test/app/tap.result new file mode 100644 index 0000000000000000000000000000000000000000..052e3ad667e5a3812a36a102ce4a7d0051eb16cf --- /dev/null +++ b/test/app/tap.result @@ -0,0 +1,121 @@ +TAP version 13 +1..30 +ok - true +ok - extra information is not printed on success +not ok - extra printed using yaml only on failure + --- + state: some userful information to debug on failure + details: a table argument formatted using yaml.encode() + ... +not ok - failed +ok - test marked as ok and skipped # skip +ok - tonumber(48) is 48 +ok - 0xff is not 64 +not ok - 1 is not 1 + --- + unexpected: 1 + got: 1 + ... +ok - nil is nil +not ok - 48 is nil + --- + expected: nil + got: 48 + ... +ok - 10 is a number +ok - 0 is also a number +ok - "blabla" is string +not ok - 48 is string + --- + expected: string + got: number + ... +not ok - nil is string + --- + expected: string + got: nil + ... +ok - true is boolean +not ok - 1 is boolean + --- + expected: boolean + got: number + ... +ok - {} is a table +not ok - udata + --- + expected: userdata<fiber> + got: nil + ... +not ok - udata + --- + expected: userdata<some utype> + got: userdata<fiber> + ... +ok - udata +not ok - cdata type + --- + expected: ctype<int> + got: string + ... +not ok - cdata type + --- + expected: ctype<int> + got: number + ... +ok - cdata type +not ok - cdata type + --- + expected: ctype<int> + got: ctype<unsigned int> + ... + # subtest 1 + 1..2 + ok - true + ok - true + # subtest 1: end +ok - subtest 1 + 1..1 + ok - true in subtest + # hello from subtest +ok - subtest 2 + # 1 level + 1..1 + # 2 level + 1..1 + # 3 level + 1..1 + # 4 level + 1..1 + # 5 level + 1..1 + ok - ok + # 5 level: end + ok - 5 level + # 4 level: end + ok - 4 level + # 3 level: end + ok - 3 level + # 2 level: end + ok - 2 level + # 1 level: end +ok - 1 level + # bad plan + 1..3 + ok - true + # bad plan: end +not ok - bad plan + --- + planned: 3 + run: 1 + ... + # failed subtest + 1..1 + not ok - failed subtest + # failed subtest: end +not ok - failed subtests + --- + planned: 1 + failed: 1 + ... +# failed subtest: 14 diff --git a/test/app/tap.test.lua b/test/app/tap.test.lua new file mode 100755 index 0000000000000000000000000000000000000000..243d1cbdc90f92e20f4c4a7f1af920f78c60c60e --- /dev/null +++ b/test/app/tap.test.lua @@ -0,0 +1,123 @@ +#!/usr/bin/env tarantool + +-- +-- Test suite for The Test Anything Protocol module implemented +-- using module itself. +-- + +-- Load 'tap' module +local tap = require "tap" + +-- +-- Create a root test +-- +test = tap.test("root test") +-- Disable stack traces for this test because Tarantool test system also +-- checks test output. +test.trace = false + +-- +-- ok, fail and skip predicates +-- + +test:plan(30) -- plan to run 3 test +test:ok(true, 'true') -- basic function +local extra = { state = 'some userful information to debug on failure', + details = 'a table argument formatted using yaml.encode()' } +test:ok(true, "extra information is not printed on success", extra) +test:ok(false, "extra printed using yaml only on failure", extra) + +test:fail('failed') -- always fail the test +test:skip('test marked as ok and skipped') + +-- +-- is and isnt predicates +-- +test:is(tonumber("48"), 48, "tonumber(48) is 48") +test:isnt(0xff, 64, "0xff is not 64") +test:isnt(1, 1, "1 is not 1") + +-- +-- type predicates +-- +test:isnil(nil, 'nil is nil') +test:isnil(48, '48 is nil') +test:isnumber(10, '10 is a number') +test:isnumber(0, '0 is also a number') +test:isstring("blabla", '"blabla" is string') +test:isstring(48, '48 is string') +test:isstring(nil, 'nil is string') +test:isboolean(true, 'true is boolean') +test:isboolean(1, '1 is boolean') +test:istable({}, '{} is a table') +local udata = require('fiber').self() +test:isudata(nil, 'fiber', 'udata') +test:isudata(udata, 'some utype', 'udata') +test:isudata(udata, 'fiber', 'udata') +local ffi = require('ffi') +test:iscdata('xx', 'int', 'cdata type') +test:iscdata(10, 'int', 'cdata type') +test:iscdata(ffi.new('int', 10), 'int', 'cdata type') +test:iscdata(ffi.new('unsigned int', 10), 'int', 'cdata type') + +-- +-- Any test also can create unlimited number of sub tests. +-- Subtest with callbacks (preferred). +-- +test:test("subtest 1", function(t) + t:plan(2) + t:ok(true, 'true') + t:ok(true, 'true') + -- test:check() is called automatically +end) +-- each subtest is counted in parent + +-- +-- Subtest without callbacks. +-- +sub2 = test:test("subtest 2") + sub2:plan(1) + sub2:ok(true, 'true in subtest') + sub2:diag('hello from subtest') + sub2:check() -- please call check() explicitly + +-- +-- Multisubtest +-- +test:test("1 level", function(t) + t:plan(1) + t:test("2 level", function(t) + t:plan(1) + t:test("3 level", function(t) + t:plan(1) + t:test("4 level", function(t) + t:plan(1) + t:test("5 level", function(t) + t:plan(1) + t:ok(true, 'ok') + end) + end) + end) + end) +end) + +--- +--- Subtest with bad plan() +--- +test:test("bad plan", function(t) + t:plan(3) + t:ok(true, 'true') +end) + + +test:test("failed subtest", function(t) + t:plan(1) + t:fail("failed subtest") +end) + +-- +-- Finish root test. Since we used non-callback variant, we have to +-- call check explicitly. +-- +test:check() -- call check() explicitly +os.exit(0) diff --git a/test/box/access.result b/test/box/access.result index 207457a2fab55ee68b3732b7c0b727dab64be8c5..d4fdbc98140a02a4901e96160de4863be7df8d1a 100644 --- a/test/box/access.result +++ b/test/box/access.result @@ -82,7 +82,7 @@ end; ... usermax(); --- -- error: User 'user29' does not exist +- error: User 'user29' is not found ... --# setopt delimiter '' box.schema.user.create('rich') diff --git a/test/box/alter.result b/test/box/alter.result index 1d454079d4b400085b3c122fb1ee105c30f1e6c0..76edd8110395f9d10bcd836728b90823b9c05f24 100644 --- a/test/box/alter.result +++ b/test/box/alter.result @@ -104,23 +104,23 @@ space.index[0] -- space:select{0} --- -- error: 'No index #0 is defined in space 321' +- error: 'No index #0 is defined in space ''hello''' ... space:insert{0, 0} --- -- error: 'No index #0 is defined in space 321' +- error: 'No index #0 is defined in space ''hello''' ... space:replace{0, 0} --- -- error: 'No index #0 is defined in space 321' +- error: 'No index #0 is defined in space ''hello''' ... space:update({0}, {{'+', 1, 1}}) --- -- error: 'No index #0 is defined in space 321' +- error: 'No index #0 is defined in space ''hello''' ... space:delete{0} --- -- error: 'No index #0 is defined in space 321' +- error: 'No index #0 is defined in space ''hello''' ... t = _space:delete{space.id} --- @@ -134,7 +134,7 @@ space_deleted ... space:replace{0} --- -- error: Space 321 does not exist +- error: Space '#321' does not exist ... _index:insert{_space.id, 0, 'primary', 'tree', 1, 1, 0, 'num'} --- diff --git a/test/box/alter_limits.result b/test/box/alter_limits.result index f03a38d38630c715a302a785cab82b37fb0201f8..87d1cc2bbda53d04bea0bfcd3efefa66f9d3d2da 100644 --- a/test/box/alter_limits.result +++ b/test/box/alter_limits.result @@ -66,7 +66,7 @@ s:drop() -- no such space s:drop() --- -- error: Space 512 does not exist +- error: Space '#512' does not exist ... -- no such engine box.schema.create_space('tweedleedee', { engine = 'unknown' }) @@ -135,23 +135,23 @@ s = box.schema.create_space('tweedledum') ... s:insert{0} --- -- error: 'No index #0 is defined in space 512' +- error: 'No index #0 is defined in space ''tweedledum''' ... s:select{} --- -- error: 'No index #0 is defined in space 512' +- error: 'No index #0 is defined in space ''tweedledum''' ... s:delete{0} --- -- error: 'No index #0 is defined in space 512' +- error: 'No index #0 is defined in space ''tweedledum''' ... s:update(0, {{"=", 1, 0}}) --- -- error: 'No index #0 is defined in space 512' +- error: 'No index #0 is defined in space ''tweedledum''' ... s:insert{0} --- -- error: 'No index #0 is defined in space 512' +- error: 'No index #0 is defined in space ''tweedledum''' ... s.index[0] --- @@ -898,7 +898,7 @@ primary.id ... primary:select{} --- -- error: 'No index #0 is defined in space 512' +- error: 'No index #0 is defined in space ''test''' ... s:drop() --- diff --git a/test/box/auth_access.result b/test/box/auth_access.result index 02db9c129ba103ac7419a587fc786dd4de74a421..47f6b8bec95929b8f1a93a0e70d3161217704490 100644 --- a/test/box/auth_access.result +++ b/test/box/auth_access.result @@ -19,7 +19,7 @@ s:drop() ... s:drop() --- -- error: Space 512 does not exist +- error: Space '#512' does not exist ... -- -- Check double create user @@ -131,7 +131,7 @@ box.schema.user.drop('testus') ... box.schema.user.drop('testus') --- -- error: User 'testus' does not exist +- error: User 'testus' is not found ... -- -- Check 'guest' user @@ -288,7 +288,7 @@ box.schema.func.drop('uniuser_func') ... box.schema.user.drop('uniuser_testus') --- -- error: User 'uniuser_testus' does not exist +- error: User 'uniuser_testus' is not found ... session.su('admin') --- @@ -301,7 +301,7 @@ box.schema.user.drop('someuser') ... box.schema.user.drop('uniuser_testus') --- -- error: User 'uniuser_testus' does not exist +- error: User 'uniuser_testus' is not found ... box.schema.user.drop('uniuser') --- diff --git a/test/box/box.net.box.result b/test/box/box.net.box.result index 907414a7e56febfc3b5d488e1f2a8a7bd77e38e8..9f6f528170de25db79b00db6638f29b7d50a8f4b 100644 --- a/test/box/box.net.box.result +++ b/test/box/box.net.box.result @@ -254,7 +254,7 @@ cn:ping() ... cn:call('test_foo') --- -- error: Connection was closed +- error: Connection is not established ... -- -- 2 reconnect cn = remote:new('127.0.0.1', port, { reconnect_after = .1 }) diff --git a/test/box/box.net.box.test.lua b/test/box/box.net.box.test.lua index 4911ce6a9002c41682a08705f0ea53bbdb4967f0..4bae183153b932e5af5aba64167a3a0a0f19783b 100644 --- a/test/box/box.net.box.test.lua +++ b/test/box/box.net.box.test.lua @@ -149,6 +149,9 @@ cn:timeout(.01):call('ret_after', 1) cn = remote:timeout(0.0000000001):new('127.0.0.1', port, { user = 'netbox', password = '123' }) cn = remote:timeout(1):new('127.0.0.1', port, { user = 'netbox', password = '123' }) + + + remote.self:ping() remote.self.space.net_box_test_space:select{234} remote.self:timeout(123).space.net_box_test_space:select{234} diff --git a/test/box/call.result b/test/box/call.result index 9682d126ae08f73d33afabfd9275a7715fcab54f..3e0fa00834b1834c756d40e50428fbcca15c7e94 100644 --- a/test/box/call.result +++ b/test/box/call.result @@ -45,11 +45,11 @@ call f1() errcode: ER_PROC_RET errmsg: msgpack.encode: can not encode Lua type 'function' ... -call dostring('box.raise(33333, "Hey!")') +call dostring('box.error(33333, "Hey!")') --- - error: - errcode: ER_PROC_LUA - errmsg: [string "box.raise(33333, "Hey!")"]:1: box.raise(): unknown error code + errcode: ER_UNKNOWN (565) + errmsg: Unknown error ... # A test case for Bug#103491 diff --git a/test/box/call.test.py b/test/box/call.test.py index 30e9c12d2e6d87f64c0aa47120685540dad931af..cba95b6cf7dde82d65172ab3d44f74723c4b3092 100644 --- a/test/box/call.test.py +++ b/test/box/call.test.py @@ -14,7 +14,7 @@ sql("call f1()") # A test case for https://github.com/tarantool/tarantool/issues/44 # IPROTO required! -sql("call dostring('box.raise(33333, \"Hey!\")')") +sql("call dostring('box.error(33333, \"Hey!\")')") print """ # A test case for Bug#103491 @@ -70,7 +70,7 @@ sql("call f1('jason', 1, 'test', 2, 'stewart')") admin("space = box.schema.create_space('tweedledum', { id = 0 })") admin("space:create_index('primary', { type = 'hash' })") - + admin("function myreplace(...) return space:replace{...} end") admin("function myinsert(...) return space:insert{...} end") sql("insert into t0 values (1, 'test box delete')") diff --git a/test/box/cfg.result b/test/box/cfg.result index 04c0a7f051d4a8d7af2574b17904bb9279c7a069..f063128c00b65ce88c1b9abac8fd29610ab24c6f 100644 --- a/test/box/cfg.result +++ b/test/box/cfg.result @@ -2,7 +2,7 @@ --# push filter 'admin: .*' to 'admin: <uri>' box.cfg.nosuchoption = 1 --- -- error: '[string "-- load_cfg.lua - internal file..."]:127: Attempt to modify a read-only +- error: '[string "-- load_cfg.lua - internal file..."]:126: Attempt to modify a read-only table' ... t = {} for k,v in pairs(box.cfg) do if type(v) ~= 'table' and type(v) ~= 'function' then table.insert(t, k..': '..tostring(v)) end end diff --git a/test/box/errinj.result b/test/box/errinj.result index b12dcf3861ef1132049fb4c0361740b3e3b92460..e525ed83c1d11dab10a269a7d30ab154aca470f6 100644 --- a/test/box/errinj.result +++ b/test/box/errinj.result @@ -1,4 +1,4 @@ -errinj = require('errinj') +errinj = require('box.error.injection') --- ... space = box.schema.create_space('tweedledum') @@ -196,7 +196,7 @@ s_disabled.enabled ... s_disabled:insert{0} --- -- error: 'No index #0 is defined in space 512' +- error: 'No index #0 is defined in space ''disabled''' ... s_withindex:create_index('secondary', { type = 'tree', parts = { 2, 'num'} }) --- @@ -271,7 +271,7 @@ box.space['withdata'] ... s_withdata:create_index('another', { type = 'tree', parts = { 5, 'num' }, unique = false}) --- -- error: Space 514 does not exist +- error: Space '#514' does not exist ... s_withdata.index.another --- diff --git a/test/box/errinj.test.lua b/test/box/errinj.test.lua index 45bebb3f53f9415929048e0466303c325c8ef814..d16edf5c9d85b9de3c613aaef34e611b2fee85c7 100644 --- a/test/box/errinj.test.lua +++ b/test/box/errinj.test.lua @@ -1,4 +1,4 @@ -errinj = require('errinj') +errinj = require('box.error.injection') space = box.schema.create_space('tweedledum') space:create_index('primary', { type = 'hash' }) diff --git a/test/box/errinj_index.result b/test/box/errinj_index.result index a13929773801ed7f204bb5168778b42bcb5c000f..0bce3216dacf3de941595092b597ceb614018a3d 100644 --- a/test/box/errinj_index.result +++ b/test/box/errinj_index.result @@ -1,4 +1,4 @@ -errinj = require('errinj') +errinj = require('box.error.injection') --- ... -- Check a failed realloc in tree index. diff --git a/test/box/errinj_index.test.lua b/test/box/errinj_index.test.lua index cf4baaf4c3af3584082ffae0e21f2e41511edce4..3a339d4aca6007e14c35271211903ab268327824 100644 --- a/test/box/errinj_index.test.lua +++ b/test/box/errinj_index.test.lua @@ -1,4 +1,4 @@ -errinj = require('errinj') +errinj = require('box.error.injection') -- Check a failed realloc in tree index. diff --git a/test/box/misc.result b/test/box/misc.result index 351a4edfc542b17f51772d973662a19466094985..cc87edfc46dc383cfbbe214d84da93021f0b7fbc 100644 --- a/test/box/misc.result +++ b/test/box/misc.result @@ -22,7 +22,6 @@ t - error - index - info - - raise - rollback - schema - slab @@ -35,36 +34,25 @@ t = nil --- ... ---------------- --- # box.raise +-- # box.error ---------------- --# stop server default --# start server default --- during server starting there could be exceptions, --- therefore box.raise() call can throw and can not throw, --- that's why we can't test box.raise() result -1 + 1 ---- -- 2 -... -box.raise(123, 'test') ---- -- error: 'box.raise(): unknown error code' -... -box.raise(0, 'the other test') +box.error({code = 123, reason = 'test'}) --- -- error: the other test +- error: test ... -box.raise(12, 345) +box.error(box.error.ILLEGAL_PARAMS, "bla bla") --- -- error: '345' +- error: Illegal parameters, bla bla ... -box.raise() +box.error() --- -- error: '345' +- error: Illegal parameters, bla bla ... -box.raise() +box.error() --- -- error: '345' +- error: Illegal parameters, bla bla ... space = box.space.tweedledum --- diff --git a/test/box/misc.test.lua b/test/box/misc.test.lua index 94c70cb5b6d830b8290a5bc97c3a348f3ae77090..4a5ea92d6a2b8ceeebbdc13d6ba5a6ab58a0dbd5 100644 --- a/test/box/misc.test.lua +++ b/test/box/misc.test.lua @@ -10,21 +10,15 @@ t t = nil ---------------- --- # box.raise +-- # box.error ---------------- --# stop server default --# start server default --- during server starting there could be exceptions, --- therefore box.raise() call can throw and can not throw, --- that's why we can't test box.raise() result - -1 + 1 -box.raise(123, 'test') -box.raise(0, 'the other test') -box.raise(12, 345) -box.raise() -box.raise() +box.error({code = 123, reason = 'test'}) +box.error(box.error.ILLEGAL_PARAMS, "bla bla") +box.error() +box.error() space = box.space.tweedledum diff --git a/test/box/sql.result b/test/box/sql.result index 764055da360e41705bd97128c0b21b94c28de046..cd40f5349dea5e2321d31a20ee043b4966752c6a 100644 --- a/test/box/sql.result +++ b/test/box/sql.result @@ -168,19 +168,19 @@ select * from t1 where k0 = 0 --- - error: errcode: ER_NO_SUCH_SPACE - errmsg: Space 1 does not exist + errmsg: Space '#1' does not exist ... select * from t65537 where k0 = 0 --- - error: errcode: ER_NO_SUCH_SPACE - errmsg: Space 65537 does not exist + errmsg: Space '#65537' does not exist ... select * from t4294967295 where k0 = 0 --- - error: errcode: ER_NO_SUCH_SPACE - errmsg: Space 4294967295 does not exist + errmsg: Space '#4294967295' does not exist ... box.space[0]:drop() --- diff --git a/test/replication/hot_standby.result b/test/replication/hot_standby.result index 24ed629b95eb11755ad2d986e90664219b916d96..3756f45d96df68b83e651ea6b984313490a71389 100644 --- a/test/replication/hot_standby.result +++ b/test/replication/hot_standby.result @@ -9,7 +9,8 @@ box.schema.user.grant('guest', 'read,write,execute', 'universe') --# set connection default --# setopt delimiter ';' --# set connection default, hot_standby, replica -while box.space['_priv']:len() < 1 do require('fiber').sleep(0.01) end; +fiber = require('fiber') +while box.space['_priv']:len() < 1 do fiber.sleep(0.001) end; --- ... do @@ -47,7 +48,7 @@ do function _wait_lsn(_lsnd) while _get_pri_lsn() < _lsnd + begin_lsn do - require('fiber').sleep(0.001) + fiber.sleep(0.001) end begin_lsn = begin_lsn + _lsnd end @@ -118,9 +119,11 @@ _select(1, 10) - [10, 'the tuple 10'] ... --# stop server default -require('fiber').sleep(0.2) +--# set connection hot_standby +while box.info.status ~= 'running' do fiber.sleep(0.001) end --- ... +--# set connection replica -- hot_standby.listen is garbage, since hot_standby.lua -- uses MASTER environment variable for its listen --# set variable hot_standby_port to 'hot_standby.master' diff --git a/test/replication/hot_standby.test.lua b/test/replication/hot_standby.test.lua index 997dbd1395da4394267c58d64ecfab1a345450c3..911b1dd7719a56a20d3a22fa0dc5e23a45069aaf 100644 --- a/test/replication/hot_standby.test.lua +++ b/test/replication/hot_standby.test.lua @@ -8,7 +8,8 @@ box.schema.user.grant('guest', 'read,write,execute', 'universe') --# setopt delimiter ';' --# set connection default, hot_standby, replica -while box.space['_priv']:len() < 1 do require('fiber').sleep(0.01) end; +fiber = require('fiber') +while box.space['_priv']:len() < 1 do fiber.sleep(0.001) end; do local pri_id = '' local begin_lsn = 0 @@ -44,7 +45,7 @@ do function _wait_lsn(_lsnd) while _get_pri_lsn() < _lsnd + begin_lsn do - require('fiber').sleep(0.001) + fiber.sleep(0.001) end begin_lsn = begin_lsn + _lsnd end @@ -69,7 +70,9 @@ _wait_lsn(10) _select(1, 10) --# stop server default -require('fiber').sleep(0.2) +--# set connection hot_standby +while box.info.status ~= 'running' do fiber.sleep(0.001) end +--# set connection replica -- hot_standby.listen is garbage, since hot_standby.lua -- uses MASTER environment variable for its listen