diff --git a/README.MacOSX b/README.MacOSX index cf24c08f1f4e88e6cdc31b4e7b33482b824daba9..aefe599a8382c23c30d1bee5d8233ccef2d56265 100644 --- a/README.MacOSX +++ b/README.MacOSX @@ -8,7 +8,7 @@ homebrew as MacPorts. If you want to build at the Homebrew environment execute just: - brew install http://tarantool.org/dist/tarantool.rb + brew install http://tarantool.org/dist/master/tarantool.rb Target OS: MacOS X "Lion" diff --git a/doc/user/configuration-reference.xml b/doc/user/configuration-reference.xml index d7db9b0cde11f4cdde63d6294059c07baf11862f..9c519fa541c65d117eb56a746b38e598c10976f9 100644 --- a/doc/user/configuration-reference.xml +++ b/doc/user/configuration-reference.xml @@ -10,37 +10,36 @@ <title>Configuration reference</title> <blockquote><para> This chapter provides a reference of options which - can be set in the command line or - <filename>tarantool.cfg</filename> configuration file. + can be set on the command line or in a configuration file. </para></blockquote> <para> -Tarantool splits its configuration parameters between command -line options and a configuration file. Command line options -are provided only for the most basic properties; the rest -must be set in the configuration file. -At runtime, this allows to disambiguate the source of -a configuration setting: it unequivocally comes either from -the command line, or from the configuration file, but never from -both. +Tarantool is started by entering the command: + +<programlisting><prompt>$ </prompt><userinput>tarantool</userinput></programlisting> +or +<programlisting><prompt>$ </prompt><userinput>tarantool <replaceable>Lua-initialization-file</replaceable></userinput></programlisting> +or +<programlisting><prompt>$ </prompt><userinput>tarantool <replaceable>options</replaceable></userinput></programlisting> + </para> <section xml:id="command-line-options"> -<title>Command line options</title> +<title>Command line parameter and options</title> <para> - Tarantool follows the <citetitle - xlink:href="http://www.gnu.org/prep/standards/standards.html#Command_002dLine-Interfaces">GNU - standard</citetitle> for its command line interface: long - options start with a double dash (<option>--option</option>), - their short counterparts use a single one (<option>-o</option>). - For phrases, both dashes and - underscores can be used as word separators - (<option>--cfg-get</option> and <option>--cfg_get</option> both work). - If an option requires an argument, you can either separate it - with a space or equals sign (<option>--cfg-get=pid_file</option> and - <option>--cfg-get pid_file</option> both work). + </para> <itemizedlist> + <listitem xml:id="lua-file-option"> + <para><option><replaceable>lua-initialization-file</replaceable></option></para> + <para>Invoke the Lua program in this file, + which by convention may have the name "script.lua", + when starting tarantool. + If the program invokes <code>box.cfg{}</code>, + see the reference for a + <olink targetptr="configuration-file">configuration file</olink>.</para> + </listitem> + <listitem xml:id="help-option"> <para><option>--help</option>, <option>-h</option></para> <para>Print an annotated list of all available options and exit.</para> @@ -50,18 +49,16 @@ both. <para><option>--version</option>, <option>-V</option></para> <para>Print product name and version, for example: <programlisting><prompt>$ </prompt> ./tarantool --version -Tarantool 1.4.0-69-g45551dd +Tarantool 1.6.0-1084-ge067689 +Target: Linux-x86_64-Debug +... </programlisting> In this example: <simplelist> <member> <quote>Tarantool</quote> is the name of the reusable asynchronous networking programming framework. - </member> - <member> - <quote>Box</quote> is the name - of the storage back-end. - </member> + </member> <member> The 3-number version follows the standard <literal><major>-<minor>-<patch></literal> @@ -76,6 +73,10 @@ Tarantool 1.4.0-69-g45551dd only, and indicate how much this particular build has diverged from the last release. </member> + <member> + <quote>Target</quote> is the platform tarantool was built on. + Some platform-specific details may follow this line. + </member> </simplelist> </para> <note><para> @@ -87,142 +88,60 @@ Tarantool 1.4.0-69-g45551dd </para></note> </listitem> - <listitem xml:id="config-option"> - <para><option>--config=</option><userinput><filename>/path/to/config.file</filename></userinput>, <option>-c</option></para> - <para> - Tarantool does not start without a configuration file. By - default, the server looks for file named - <filename>tarantool.cfg</filename> in the current working - directory. An alternative location can be provided using - this option. - </para> - </listitem> - - <listitem> - <para><option>--check-config</option></para> - <para>Check the configuration file for errors. This option is - normally used on the command line - before <quote>box.cfg.reload()</quote> - is issued on the administrative port, to ensure that the new - configuration is valid. When configuration is - indeed correct, the program produces no output and returns <literal>0</literal>. - Otherwise, information about discovered error is printed out - and the program terminates with a non-zero value. - </para> - </listitem> - - <listitem> - <para><option>--cfg-get=</option><userinput>option_name</userinput></para> - <para>Given option name, print option value. If the - option does not exist, or the configuration file is - incorrect, an error is returned. If the option - is not explicitly specified, its default value is used - instead. Example: - <programlisting><prompt>$ </prompt>./tarantool --cfg-get=admin_port -33015 </programlisting> - </para> - </listitem> - <listitem> - <para> - <option xml:id="init-storage-option" - xreflabel="--init-storage"> - --init-storage - </option></para> - <para>Initialize the directory, specified in <emphasis>vardir</emphasis> - configuration option by creating an empty snapshot file in - it. Prior to Tarantool 1.6, if <filename>vardir</filename> - didn't contain at least one snapshot, the server did not - start. Starting from 1.6, the initial storage file is - created automatically when starting in a clean data - directory. - </para> - </listitem> </itemizedlist> - <para> - The only two options which could affect a running server are: - </para> - <itemizedlist> - <listitem> - <para><option>--verbose</option>, <option>-v</option></para> - <para>Increase verbosity level in log messages. This option - currently has no effect.</para> - </listitem> - <listitem> - <para><option>--background</option>, <option>-b</option></para> - <para>Detach from the controlling terminal and run in the - background. - <caution><para>Tarantool uses - <filename>stdout</filename> and - <filename>stderr</filename> for - debug and error log output. When starting the server with - option <option>--background</option>, make sure to - either redirect its standard out and standard error - streams, or provide <emphasis>logger</emphasis> option - in the configuration file, since otherwise all logging - information will be lost.</para></caution> - </para> - </listitem> - </itemizedlist> </section> <section xml:id="configuration-file" xreflabel="configuration file"> <title>The configuration file</title> <para> - All advanced configuration parameters must be specified in a - configuration file, which is required for server start. If no path to - the configuration file is specified on the command line (see - <option xlink:href="#config-option" - xlink:title="--config=...">--config</option>), - the server looks for a file named <filename>tarantool.cfg</filename> - in the current working directory. + Configuration parameters are usually specified inside a + Lua file with a call to <olink targetptr="sp-box-cfg">box.cfg</olink>. + Typically this Lua file is the initialization file + which is specified on the tarantool command line. + A simple example of such a file is <filename>test/box/box.lua</filename>: +<programlisting> +#!/usr/bin/env tarantool +os = require('os') + +box.cfg{ + primary_port = os.getenv("PRIMARY_PORT"), + admin_port = os.getenv("ADMIN_PORT"), + slab_alloc_arena = 0.1, + pid_file = "tarantool.pid", + rows_per_wal = 50 +} +</programlisting> </para> <para> - To facilitate centralized and automated configuration - management, runtime configuration modifications are supported - solely through <olink targetptr="box.cfg.reload"/> - administrative statement. Thus, the - procedure to change Tarantool configuration at runtime is to - edit the configuration file. This ensures that, should the - server get killed or restart, no unexpected changes to - configuration can occur. + Most configuration parameters are for allocating resources, + opening ports, and specifying database behavior. + All parameters are optional. + A few parameters are dynamic, that is, they can be changed + at runtime by calling box.cfg{} a second time. </para> <para> - Not all configuration file settings are changeable at runtime: - such settings will be highlighted in this reference. - If the same setting is given more than once, the latest occurrence - takes effect. - You can always invoke <olink targetptr="box.cfg.show"/> - from the administrative console to show the current - configuration. + 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 reload the parameters, use <olink targetptr="box.cfg.reload"/>. </para> <para> - Tarantool maintains a set of all allowed configuration - parameters in two template files, which are easy to maintain - and extend: - <filename xlink:href="https://github.com/tarantool/tarantool/blob/master/cfg/core_cfg.cfg_tmpl">cfg/core_cfg.cfg_tmpl</filename>, - <filename xlink:href="https://github.com/tarantool/tarantool/blob/master/src/box/box_cfg.cfg_tmpl">src/box/box_cfg.cfg_tmpl</filename>. - These files can always be used as a reference for any - parameter in this manual. - </para> - - <para>In addition, two working examples can be found in the source tree: - <filename xlink:href="https://github.com/tarantool/tarantool/blob/master/test/box/tarantool.cfg">test/box/tarantool.cfg</filename>, - <filename xlink:href="https://github.com/tarantool/tarantool/blob/master/test/big/tarantool.cfg">test/big/tarantool.cfg</filename>. + The following tables describe all parameters for basic operation, + for storage, for binary logging and snapshots, for replication, + for networking, for logging, and for hot standby. </para> <table frame='all' pgwide='1'> <title>Basic parameters</title> - <tgroup cols='6' colsep='1' rowsep='1'> + <tgroup cols='5' colsep='1' rowsep='1'> <colspec colnum="1" colname="col1" colwidth="2*"/> - <colspec colnum="6" colname="col4" colwidth="6*"/> + <colspec colnum="5" colname="col4" colwidth="6*"/> <thead> <row> <entry>Name</entry> <entry>Type</entry> <entry>Default</entry> - <entry>Required?</entry> <entry>Dynamic?</entry> <entry>Description</entry> </row> @@ -233,8 +152,7 @@ Tarantool 1.4.0-69-g45551dd <row> <entry>username</entry> <entry>string</entry> - <entry>""</entry> - <entry>no</entry> + <entry>null</entry> <entry>no</entry> <entry>UNIX user name to switch to after start.</entry> </row> @@ -242,8 +160,7 @@ Tarantool 1.4.0-69-g45551dd <row> <entry xml:id="work_dir" xreflabel="work_dir">work_dir</entry> <entry>string</entry> - <entry>""</entry> - <entry>no</entry> + <entry>null</entry> <entry>no</entry> <entry>A directory where database working files will be stored. The server switches to work_dir with chdir(2) after @@ -251,25 +168,10 @@ Tarantool 1.4.0-69-g45551dd If not specified, defaults to the current directory.</entry> </row> - <row> - <entry xml:id="script_dir" xreflabel="script_dir">script_dir</entry> - <entry>string</entry> - <entry>""</entry> - <entry>no</entry> - <entry>no</entry> - <entry>If this path is set, it is added to the Lua package - search path, so that instance-specific Lua scripts can - be loaded and executed. If the directory specified in - the path contains <filename>init.lua</filename> file, it - is loaded and executed at server start. - </entry> - </row> - <row> <entry xml:id="wal_dir" xreflabel="wal_dir">wal_dir</entry> <entry>string</entry> - <entry>""</entry> - <entry>no</entry> + <entry>"."</entry> <entry>no</entry> <entry>A directory where write-ahead log (.xlog) files are stored. Can be relative to work_dir. Most commonly used so @@ -281,25 +183,23 @@ Tarantool 1.4.0-69-g45551dd <row> <entry xml:id="snap_dir" xreflabel="snap_dir">snap_dir</entry> <entry>string</entry> - <entry>""</entry> - <entry>no</entry> + <entry>"."</entry> <entry>no</entry> <entry>A directory where snapshot (.snap) files will be stored. Can be relative to work_dir. If not specified, defaults to work_dir. See also <olink targetptr="wal_dir"/>.</entry> </row> -<!-- <row> - <entry>coredump</entry><entry>0 or 1</entry><entry>0</entry> - <entry>Deprecated. Save core on abort/assert? You may - turn off the coredump off when using ulimit</entry> + <entry xml:id="coredump" xreflabel="coredump">coredump</entry> + <entry>0 or 1</entry> + <entry>0</entry> + <entry>no</entry> + <entry>Deprecated. Do not use.</entry> </row> ---> <row> <entry xml:id="bind_ipaddr" xreflabel="bind_ipaddr">bind_ipaddr</entry> <entry>string</entry> - <entry><emphasis role="strong">"INADDR_ANY"</emphasis></entry> - <entry>no</entry> + <entry>"INADDR_ANY"</entry> <entry>no</entry> <entry>The network interface to bind to. By default, the server binds to all available addresses. @@ -309,37 +209,38 @@ Tarantool 1.4.0-69-g45551dd <row> <entry xml:id="primary_port" xreflabel="primary_port">primary_port</entry> <entry>integer</entry> - <entry><emphasis role="strong">none</emphasis></entry> - <entry><emphasis role="strong">yes</emphasis></entry> + <entry>null</entry> <entry>no</entry> <entry>The read/write data port. Has no default value, so <emphasis role="strong">must be specified</emphasis> - in the configuration file. Normally set to 3301. + if connections will occur from remote clients + that do not use admin_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.</entry> + reads until the replica becomes a master. + A typical value is 3301.</entry> </row> <row> <entry xml:id="admin_port" xreflabel="admin_port">admin_port</entry> <entry>integer</entry> - <entry>none</entry> - <entry>no</entry> + <entry>null</entry> <entry>no</entry> <entry>The TCP port to listen on for administrative - connections. Has no default value. Not used unless - assigned a value. Normally set to 33015.</entry> + connections. Has no default value, so must be specified + if connections will occur via telnet. Not used unless + assigned a value. + A typical value is 3313.</entry> </row> <row> <entry>pid_file</entry> <entry>string</entry> - <entry>tarantool.pid</entry> - <entry>no</entry> + <entry>null</entry> <entry>no</entry> <entry>Store the process id in this file. Can be - relative to work_dir.</entry> + relative to work_dir. A typical value is "tarantool.pid".</entry> </row> <row> @@ -348,8 +249,7 @@ Tarantool 1.4.0-69-g45551dd custom_proc_title </entry> <entry>string</entry> - <entry>""</entry> - <entry>no</entry> + <entry>null</entry> <entry>no</entry> <entry> <para>Inject the given string into <olink @@ -367,22 +267,30 @@ tarantool: primary@sessions pri: 3301 adm: 33015</programlisting> </entry> </row> + <row> + <entry>background</entry> + <entry>boolean</entry> + <entry>false</entry> + <entry>no</entry> + <entry>Run the server as a background task. + The logger and pid_file parameters must be non-null for this to work.</entry> + </row> + </tbody> </tgroup> </table> <table frame='all' pgwide='1'> <title>Configuring the storage</title> - <tgroup cols='6' colsep='1' rowsep='1'> + <tgroup cols='5' colsep='1' rowsep='1'> <colspec colnum="1" colname="col1" colwidth="2*"/> - <colspec colnum="6" colname="col4" colwidth="6*"/> + <colspec colnum="5" colname="col4" colwidth="6*"/> <thead> <row> <entry>Name</entry> <entry>Type</entry> <entry>Default</entry> - <entry>Required?</entry> <entry>Dynamic?</entry> <entry>Description</entry> </row> @@ -395,7 +303,6 @@ tarantool: primary@sessions pri: 3301 adm: 33015</programlisting> <entry>float</entry> <entry>1.0</entry> <entry>no</entry> - <entry>no</entry> <entry> <anchor xml:id="slab_alloc_arena" xreflabel="slab_alloc_arena"/> How much memory Tarantool @@ -417,7 +324,6 @@ tarantool: primary@sessions pri: 3301 adm: 33015</programlisting> <entry>integer</entry> <entry>64</entry> <entry>no</entry> - <entry>no</entry> <entry>Size of the smallest allocation unit. It can be tuned down if most of the tuples are very small.</entry> </row> @@ -427,7 +333,6 @@ tarantool: primary@sessions pri: 3301 adm: 33015</programlisting> <entry>float</entry> <entry>2.0</entry> <entry>no</entry> - <entry>no</entry> <entry>Use slab_alloc_factor as the multiplier for computing the sizes of memory chunks that tuples are stored in. A lower value may result in less wasted @@ -441,16 +346,15 @@ tarantool: primary@sessions pri: 3301 adm: 33015</programlisting> <table frame='all' pgwide='1'> <title>Binary logging and snapshots</title> - <tgroup cols='6' colsep='1' rowsep='1'> + <tgroup cols='5' colsep='1' rowsep='1'> <colspec colnum="1" colname="col1" colwidth="2*"/> - <colspec colnum="6" colname="col4" colwidth="6*"/> + <colspec colnum="5" colname="col4" colwidth="6*"/> <thead> <row> <entry>Name</entry> <entry>Type</entry> <entry>Default</entry> - <entry>Required?</entry> <entry>Dynamic?</entry> <entry>Description</entry> </row> @@ -463,7 +367,6 @@ tarantool: primary@sessions pri: 3301 adm: 33015</programlisting> <entry>boolean</entry> <entry>true</entry> <entry>no</entry> - <entry>no</entry> <entry>If there is an error reading the snapshot file (at server start), abort.</entry> </row> @@ -473,7 +376,6 @@ tarantool: primary@sessions pri: 3301 adm: 33015</programlisting> <entry>boolean</entry> <entry>false</entry> <entry>no</entry> - <entry>no</entry> <entry>If there is an error reading a write-ahead log file (at server start), abort.</entry> </row> @@ -483,7 +385,6 @@ tarantool: primary@sessions pri: 3301 adm: 33015</programlisting> <entry>integer</entry> <entry>500000</entry> <entry>no</entry> - <entry>no</entry> <entry>How many log records to store in a single write-ahead log file. When this limit is reached, Tarantool creates another WAL file named @@ -495,9 +396,8 @@ tarantool: primary@sessions pri: 3301 adm: 33015</programlisting> <row> <entry>snap_io_rate_limit</entry> <entry>float</entry> - <entry>0.0</entry> - <entry>no</entry> - <entry>yes</entry> + <entry>null</entry> + <entry><emphasis role="strong">yes</emphasis></entry> <entry>Reduce the throttling effect of <olink targetptr="box.snapshot"/> on INSERT/UPDATE/DELETE performance by setting a limit on @@ -508,12 +408,11 @@ tarantool: primary@sessions pri: 3301 adm: 33015</programlisting> </row> <row> - <entry xml:id="wal_fsync_delay" xreflabel="wal_fsync_delay">wal_fsync_delay</entry> - <entry>float</entry> - <entry>0</entry> - <entry>no</entry> - <entry>yes</entry> - <entry>Do not flush the write-ahead log to disk more often + <entry xml:id="wal_fsync_delay" xreflabel="wal_fsync_delay">wal_fsync_delay</entry> + <entry>float</entry> + <entry>0</entry> + <entry><emphasis role="strong">yes</emphasis></entry> + <entry>Do not flush the write-ahead log to disk more often than once in wal_fsync_delay seconds. By default the delay is zero, which means there is no flushing after writes (the meaning of wal_fsync_delay=0 may change in later versions). @@ -526,19 +425,29 @@ tarantool: primary@sessions pri: 3301 adm: 33015</programlisting> </row> <row> - <entry xml:id="wal_mode" xreflabel="wal_mode">wal_mode</entry> - <entry>string</entry> - <entry>"fsync_delay"</entry> - <entry>no</entry> - <entry>yes</entry> - <entry>Specify fiber-WAL-disk synchronization mode as: - <emphasis>none:</emphasis> write-ahead log is not maintained; <emphasis>write:</emphasis> fibers wait for their data to - be written to the write-ahead log (no fsync(2)); <emphasis>fsync</emphasis>: - fibers wait for their data, fsync(2) follows each write(2); - <emphasis>fsync_delay</emphasis>: fibers wait for their - data, fsync(2) is called every N=<emphasis>wal_fsync_delay</emphasis> - seconds (N=0.0 means no fsync(2) - equivalent to - <emphasis>wal_mode = "write"</emphasis>);</entry> + <entry xml:id="wal_mode" xreflabel="wal_mode">wal_mode</entry> + <entry>string</entry> + <entry>"write"</entry> + <entry><emphasis role="strong">yes</emphasis></entry> + <entry>Specify fiber-WAL-disk synchronization mode as: + <emphasis>none:</emphasis> write-ahead log is not maintained; <emphasis>write:</emphasis> fibers wait for their data to + be written to the write-ahead log (no fsync(2)); <emphasis>fsync</emphasis>: + fibers wait for their data, fsync(2) follows each write(2); + <emphasis>fsync_delay</emphasis>: fibers wait for their + data, fsync(2) is called every N=<emphasis>wal_fsync_delay</emphasis> + seconds (N=0.0 means no fsync(2) - equivalent to + <emphasis>wal_mode = "write"</emphasis>);</entry> + </row> + + <row> + <entry xml:id="wal_dir_rescan_delay" xreflabel="wal_dir_rescan_delay">wal_mode</entry> + <entry>float</entry> + <entry>0.1</entry> + <entry>no</entry> + <entry>Number of seconds between periodic scans of the + write-ahead-log file directory, when checking for + changes to write-ahead-log files for the sake of + replication or local hot standby.</entry> </row> </tbody> @@ -547,44 +456,27 @@ tarantool: primary@sessions pri: 3301 adm: 33015</programlisting> <table frame='all' pgwide='1'> <title>Replication</title> - <tgroup cols='6' colsep='1' rowsep='1'> + <tgroup cols='5' colsep='1' rowsep='1'> <colspec colnum="1" colname="col1" colwidth="2*"/> - <colspec colnum="6" colname="col4" colwidth="6*"/> + <colspec colnum="5" colname="col4" colwidth="6*"/> <thead> <row> <entry>Name</entry> <entry>Type</entry> <entry>Default</entry> - <entry>Required?</entry> <entry>Dynamic?</entry> <entry>Description</entry> </row> </thead> <tbody> - <row> - <entry xml:id="replication_port" - xreflabel="replication_port">replication_port</entry> - <entry>integer</entry> - <entry>0</entry> - <entry>no</entry> - <entry>no</entry> - <entry>If replication_port is greater than zero, the - server is considered to be a Tarantool master. - The master server listens on the specified port - for incoming connections from - replicas. See also <olink - targetptr="replication_source"/>, which complements - this setting on the replica side.</entry> - </row> <row> <entry xml:id="replication_source" xreflabel="replication_source">replication_source</entry> <entry>string</entry> - <entry>NULL</entry> - <entry>no</entry> + <entry>null</entry> <entry><emphasis role="strong">yes</emphasis></entry> <entry>If replication_source is not an empty string, the server is considered to be a Tarantool replica. @@ -605,16 +497,15 @@ tarantool: primary@sessions pri: 3301 adm: 33015</programlisting> <table frame='all' pgwide='1'> <title>Networking</title> - <tgroup cols='6' colsep='1' rowsep='1'> + <tgroup cols='5' colsep='1' rowsep='1'> <colspec colnum="1" colname="col1" colwidth="2*"/> - <colspec colnum="6" colname="col4" colwidth="6*"/> + <colspec colnum="5" colname="col4" colwidth="6*"/> <thead> <row> <entry>Name</entry> <entry>Type</entry> <entry>Default</entry> - <entry>Required?</entry> <entry>Dynamic?</entry> <entry>Description</entry> </row> @@ -625,9 +516,8 @@ tarantool: primary@sessions pri: 3301 adm: 33015</programlisting> <row> <entry>io_collect_interval</entry> <entry>float</entry> - <entry>0.0</entry> - <entry>no</entry> - <entry>yes</entry> + <entry>null</entry> + <entry><emphasis role="strong">yes</emphasis></entry> <entry>The server will sleep for io_collect_interval seconds between iterations of the event loop. Can be used to reduce CPU load in deployments in which the @@ -639,8 +529,7 @@ tarantool: primary@sessions pri: 3301 adm: 33015</programlisting> <row> <entry>readahead</entry> <entry>integer</entry> - <entry>16384</entry> - <entry>no</entry> + <entry>16320</entry> <entry>no</entry> <entry>The size of the read-ahead buffer associated with a client connection. The larger the buffer, the more @@ -661,16 +550,15 @@ tarantool: primary@sessions pri: 3301 adm: 33015</programlisting> <table frame='all' pgwide='1'> <title>Logging</title> - <tgroup cols='6' colsep='1' rowsep='1'> + <tgroup cols='5' colsep='1' rowsep='1'> <colspec colnum="1" colname="col1" colwidth="2*"/> - <colspec colnum="6" colname="col4" colwidth="6*"/> + <colspec colnum="5" colname="col4" colwidth="6*"/> <thead> <row> <entry>Name</entry> <entry>Type</entry> <entry>Default</entry> - <entry>Required?</entry> <entry>Dynamic?</entry> <entry>Description</entry> </row> @@ -681,8 +569,7 @@ tarantool: primary@sessions pri: 3301 adm: 33015</programlisting> <row> <entry>log_level</entry> <entry>integer</entry> - <entry>4</entry> - <entry>no</entry> + <entry>5</entry> <entry><emphasis role="strong">yes</emphasis></entry> <entry>How verbose the logging is. There are 5 log verbosity classes: 1 -- ERROR, 2 -- CRITICAL, 3 -- @@ -697,8 +584,7 @@ tarantool: primary@sessions pri: 3301 adm: 33015</programlisting> <row> <entry>logger</entry> <entry>string</entry> - <entry>""</entry> - <entry>no</entry> + <entry>null</entry> <entry>no</entry> <entry>By default, the log is sent to the standard error stream (<filename>stderr</filename>). If logger @@ -713,15 +599,14 @@ tarantool: primary@sessions pri: 3301 adm: 33015</programlisting> <row> <entry>logger_nonblock</entry> - <entry>integer</entry> - <entry>0</entry> - <entry>no</entry> + <entry>boolean</entry> + <entry>true</entry> <entry>no</entry> - <entry>If logger_nonblock equals 1, Tarantool does not + <entry>If logger_nonblock equals true, Tarantool does not block on the log file descriptor when it's not ready for write, and drops the message instead. If log_level is high, and a lot of messages go to the log - file, setting logger_nonblock to 1 may improve logging + file, setting logger_nonblock to true may improve logging performance at the cost of some log messages getting lost.</entry> </row> @@ -730,7 +615,6 @@ tarantool: primary@sessions pri: 3301 adm: 33015</programlisting> <entry>too_long_threshold</entry> <entry>float</entry> <entry>0.5</entry> - <entry>no</entry> <entry><emphasis role="strong">yes</emphasis></entry> <entry>If processing a request takes longer than the given value (in seconds), warn about it in the log. @@ -744,16 +628,15 @@ tarantool: primary@sessions pri: 3301 adm: 33015</programlisting> <table frame='all' pgwide='1'> <title>Hot Standby</title> - <tgroup cols='6' colsep='1' rowsep='1'> + <tgroup cols='5' colsep='1' rowsep='1'> <colspec colnum="1" colname="col1" colwidth="2*"/> - <colspec colnum="6" colname="col4" colwidth="6*"/> + <colspec colnum="5" colname="col4" colwidth="6*"/> <thead> <row> <entry>Name</entry> <entry>Type</entry> <entry>Default</entry> - <entry>Required?</entry> <entry>Dynamic?</entry> <entry>Description</entry> </row> @@ -766,7 +649,6 @@ tarantool: primary@sessions pri: 3301 adm: 33015</programlisting> <entry>boolean</entry> <entry>false</entry> <entry>no</entry> - <entry>no</entry> <entry> <anchor xml:id="local_hot_standby" xreflabel="local_hot_standby"/> If local_hot_standby=true, the expectation is that there will be two diff --git a/doc/user/lua-tutorial.xml b/doc/user/lua-tutorial.xml index ddf297c4823bc7f3cf9f98108d8738f3f4a91b85..20c0142a7766023fa1bbb87bf95efb1f1b3b44a8 100644 --- a/doc/user/lua-tutorial.xml +++ b/doc/user/lua-tutorial.xml @@ -33,7 +33,7 @@ in with the tarantool client while reading along. We are going to use the "tarantool_sandbox" that was created in section <olink targetptr="getting-started-start-stop">Starting Tarantool and making your first database</olink>. So there is a single space, and a numeric primary key, -a running tarantool server, and a running tarantool client. +and a running tarantool server which also serves as a client. </para> <para> @@ -85,14 +85,16 @@ For more about functions see Lua manual chapter 5 "Functions" <para> The screen now looks like this: <programlisting> -localhost> <userinput>function string_function()</userinput> +tarantool> <userinput>function string_function()</userinput> -> <userinput>return "hello world"</userinput> -> <userinput>end!</userinput> --- ... -localhost> <userinput>string_function()!</userinput> +tarantool> <userinput>string_function()!</userinput> +--- - hello world -localhost> +... +tarantool> </programlisting> </para> @@ -127,18 +129,18 @@ For more about Lua variables see Lua manual chapter 4.2 "Local Variables and Blo <para> The screen now looks like this: <programlisting> -localhost> <userinput>function main_function()</userinput> +tarantool> <userinput>function main_function()</userinput> -> <userinput>local string_value</userinput> -> <userinput>string_value = string_function()</userinput> -> <userinput>return string_value</userinput> -> <userinput>end!</userinput> --- ... -localhost> <userinput>main_function()!</userinput> +tarantool> <userinput>main_function()!</userinput> --- - hello world ... -localhost> +tarantool> </programlisting> </para> @@ -179,7 +181,7 @@ main_function()! <para> The screen now looks like this: <programlisting> -localhost> <userinput>function string_function()</userinput> +tarantool> <userinput>function string_function()</userinput> -> <userinput>local random_number</userinput> -> <userinput>local random_string</userinput> -> <userinput>random_number = math.random(65, 90)</userinput> @@ -188,11 +190,11 @@ localhost> <userinput>function string_function()</userinput> -> <userinput>end!</userinput> --- ... -localhost> <userinput>main_function()!</userinput> +tarantool> <userinput>main_function()!</userinput> --- - C ... -localhost> +tarantool> </programlisting> ... Well, actually it won't always look like this because math.random() produces random numbers. But for the illustration purposes it won't matter what the random string values are. @@ -232,7 +234,7 @@ For more about Lua loops see Lua manual chapter 4.3.4 "Numeric for" <para> The screen now looks like this: <programlisting> -localhost> <userinput>function string_function()</userinput> +tarantool> <userinput>function string_function()</userinput> -> <userinput>local random_number</userinput> -> <userinput>local random_string</userinput> -> <userinput>random_string = ""</userinput> @@ -244,11 +246,11 @@ localhost> <userinput>function string_function()</userinput> -> <userinput>end!</userinput> --- ... -localhost> <userinput>main_function()!</userinput> +tarantool> <userinput>main_function()!</userinput> --- - 'ZUDJBHKEFM' ... -localhost> +tarantool> </programlisting> </para> @@ -283,7 +285,7 @@ For more about Tarantool tuples see Tarantool manual section <para> The screen now looks like this: <programlisting> -localhost> <userinput>function main_function()</userinput> +tarantool> <userinput>function main_function()</userinput> -> <userinput>local string_value</userinput> -> <userinput>string_value = string_function()</userinput> -> <userinput>t = box.tuple.new({1, string_value})</userinput> @@ -291,11 +293,11 @@ localhost> <userinput>function main_function()</userinput> -> <userinput>end!</userinput> --- ... -localhost> <userinput>main_function()!</userinput> +tarantool> <userinput>main_function()!</userinput> --- - [1, 'PNPZPCOOKA'] ... -localhost> +tarantool> </programlisting> </para> @@ -313,14 +315,14 @@ function main_function() box.space.space0:replace(t) end! </programlisting> -The new line here is box.space.space0:replace(0,t). The name contains 'space0' because the +The new line here is box.space.space0:replace(t). The name contains 'space0' because the insertion is going to be to space0. The second parameter is the tuple value. To be perfectly correct we could have said box.space.space0:insert(t) here, rather than box.space.space0:replace(t), but "replace" means <quote>insert even if there is already a tuple whose primary-key value is a duplicate</quote>, and that makes it easier to re-run the exercise even if the sandbox database isn't empty. -Once this is done, space[0] will contain a tuple with two fields. The first +Once this is done, space0 will contain a tuple with two fields. The first field will be 1. The second field will be a random 10-letter string. Once again the string_function() can be invoked from main_function() which can be invoked with @@ -342,7 +344,7 @@ For more about Tarantool insert and replace calls, see Tarantool manual section <para> The screen now looks like this: <programlisting> -localhost> <userinput>function main_function()</userinput> +tarantool> <userinput>function main_function()</userinput> -> <userinput>local string_value</userinput> -> <userinput>string_value = string_function()</userinput> -> <userinput>t = box.tuple.new({1,string_value})</userinput> @@ -350,14 +352,14 @@ localhost> <userinput>function main_function()</userinput> -> <userinput>end!</userinput> --- ... -localhost> <userinput>main_function()!</userinput> +tarantool> <userinput>main_function()!</userinput> --- ... -localhost> <userinput>box.space.space0:select(1)!</userinput> +tarantool> <userinput>box.space.space0:select(1)!</userinput> --- -- [1, 'EUJYVEECIL'] +- - [1, 'EUJYVEECIL'] ... -localhost> +tarantool> </programlisting> </para> @@ -391,7 +393,7 @@ and then getting end_time = number of seconds just after the inserting, we can calculate (end_time - start_time) = elapsed time in seconds. We will display that value by putting it in a request without any assignments, which causes Tarantool to send the value to the client, which prints it. -(Lua's answer to the C printf() function, which is print(), will not work.) +(Lua's answer to the C printf() function, which is print(), will also work.) </para> <para> @@ -439,8 +441,8 @@ main_function()! The screen now looks like this: <programlisting> -localhost> <userinput>setopt delimiter = '!'!</userinput> -localhost> <userinput>function string_function()</userinput> +tarantool> <userinput>setopt delimiter = '!'!</userinput> +tarantool> <userinput>function string_function()</userinput> -> <userinput>local random_number</userinput> -> <userinput>local random_string</userinput> -> <userinput>random_string = ""</userinput> @@ -452,7 +454,7 @@ localhost> <userinput>function string_function()</userinput> -> <userinput>end!</userinput> --- ... -localhost> <userinput>function main_function()</userinput> +tarantool> <userinput>function main_function()</userinput> -> <userinput>local string_value</userinput> -> <userinput>start_time = os.clock()</userinput> -> <userinput>for i = 1,1000000,1 do</userinput> @@ -464,14 +466,14 @@ localhost> <userinput>function main_function()</userinput> -> <userinput>end!</userinput> --- ... -localhost> <userinput>main_function()!</userinput> +tarantool> <userinput>main_function()!</userinput> --- ... -localhost> <userinput>'insert done in ' .. end_time - start_time .. ' seconds'!</userinput> +tarantool> <userinput>'insert done in ' .. end_time - start_time .. ' seconds'!</userinput> --- -insert done in 60.62 seconds +- insert done in 60.62 seconds ... -localhost> +tarantool> </programlisting> </para> @@ -508,15 +510,14 @@ SETOPT DELIMITER='!' function sum_json_field(field_name) local v, t, sum, field_value, is_valid_json, lua_table --[[1]] sum = 0 --[[2]] - v = box.space.space0.index.primary:iterator(box.index.ALL) --[[3]] - for t in v do --[[4]] - is_valid_json, lua_table = pcall(box.cjson.decode, t[1]) --[[5]] - if is_valid_json then --[[6]] - field_value = lua_table[field_name] --[[7]] - if type(field_value) == "number" then sum = sum + field_value end --[[8]] - end --[[9]] - end --[[10]] - return sum --[[11]] + for v, t in box.space.space0:pairs() do --[[3]] + is_valid_json, lua_table = pcall(box.cjson.decode, t[1]) --[[4]] + if is_valid_json then --[[5]] + field_value = lua_table[field_name] --[[6]] + if type(field_value) == "number" then sum = sum + field_value end --[[7]] + end --[[8]] + end --[[9]] + return sum --[[10]] end! SETOPT DELIMITER=''! </programlisting> @@ -532,21 +533,20 @@ function. </para> <para> -LINE 3: WHY INDEX ITERATOR". Our job is to go through all the rows and there are two ways +LINE 3: WHY PAIRS()". Our job is to go through all the rows and there are two ways to do it: with box.space.<replaceable>space-name</replaceable>:pairs() or with <olink targetptr="box.index.iterator">index.iterator</olink>. We preferred -index.iterator because it delivers in index order regardless of the index type, that is, -it works with HASH, TREE, and BITSET indexes. +pairs() because it is simpler. </para> <para> -LINE 4: START THE MAIN LOOP. Everything inside this "<code>for</code>" loop will be repeated +LINE 3: START THE MAIN LOOP. Everything inside this "<code>for</code>" loop will be repeated as long as there is another index key. A tuple is fetched and can be referenced with variable <code>t</code>. </para> <para> -LINE 5: WHY "PCALL". If we simply said "<code>lua_table = box.cjson.decode(t[1]))</code>", +LINE 4: WHY "PCALL". If we simply said "<code>lua_table = box.cjson.decode(t[1]))</code>", then the function would abort with an error if it encountered something wrong with the JSON string -- a missing colon, for example. By putting the function inside "<code>pcall</code>" (<link xlink:href="http://www.lua.org/pil/8.4.html">protected call</link>), we're saying: we want to intercept that sort @@ -555,7 +555,7 @@ will know what to do about it later. </para> <para> -LINE 5: MEANING. The function is <olink targetptr="box.cjson">box.cjson.decode</olink> which means decode a JSON +LINE 4: MEANING. The function is <olink targetptr="box.cjson">box.cjson.decode</olink> which means decode a JSON string, and the parameter is <code>t[1]</code> which is a reference to a JSON string. There's a bit of hard coding here, we're assuming that the second field in the tuple is where the JSON string was inserted. For example, we're assuming a tuple looks like <programlisting>field[0]: 444 @@ -569,7 +569,7 @@ decoded string". </para> <para> -LINE 7. At last we are ready to get the JSON field value from the Lua +LINE 6. At last we are ready to get the JSON field value from the Lua table that came from the JSON string. The value in <code>field_name</code>, which is the parameter for the whole function, must be a name of a JSON field. For example, inside the JSON string @@ -582,7 +582,7 @@ in the Lua table, get the value and put it in variable <code>field_value</code>. </para> <para> -LINE 8: WHY "IF". Suppose that the JSON string is well formed but the +LINE 7: WHY "IF". Suppose that the JSON string is well formed but the JSON field is not a number, or is missing. In that case, the function would be aborted when there was an attempt to add it to the sum. By first checking <code>type(field_value) == "number"</code>, we avoid that abortion. @@ -613,7 +613,7 @@ Therefore the real sum of the Quantity field in the JSON strings should be: <para> Invoke the function with <code>sum_json_field("Quantity")</code>. <programlisting language="lua"> -<prompt>localhost></prompt> <userinput>sum_json_field("Quantity")</userinput> +<prompt>tarantool></prompt> <userinput>sum_json_field("Quantity")</userinput> --- - 22 ... diff --git a/doc/user/plugins.xml b/doc/user/plugins.xml index 8c27b79452d77b31a4047be26ae22275bba4a305..9700b7152a5d983b17b3e915164966a383e12551 100644 --- a/doc/user/plugins.xml +++ b/doc/user/plugins.xml @@ -45,7 +45,7 @@ can work on both SQL and Tarantool inside the same Lua routine. <para> The connection method is -<code>box.net.sql.connect('mysql'|'postgresql', <replaceable>host</replaceable>, <replaceable>port</replaceable>, <replaceable>user</replaceable>, <replaceable>password</replaceable>, <replaceable>database</replaceable>)</code>. +<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>. </para> @@ -72,10 +72,10 @@ OK OK # Check that the mysql client can connect using some factory defaults: -# port = 3306, user = 'root', user password = 'root', database = 'test'. -# (Do not use a blank password.) -# These can be changed, provided one changes them in all places. -<prompt>$ </prompt><userinput>~/mysql-5.5/bin/mysql --port=3306 -h 127.0.0.1 --user=root --password=root--database=test</userinput> +# port = 3306, user = 'root', user password = '', database = 'test'. +# These can be changed, provided one uses the changed values in +# all places. +<prompt>$ </prompt><userinput>~/mysql-5.5/bin/mysql --port=3306 -h 127.0.0.1 --user=root --password= --database=test</userinput> Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 25 Server version: 5.5.35 MySQL Community Server (GPL) @@ -99,25 +99,21 @@ Bye <prompt>$ </prompt><userinput>make clean</userinput> <prompt>$ </prompt><userinput>rm CMakeCache.txt</userinput> <prompt>$ </prompt><userinput>cmake . -DWITH_MYSQL=on -DMYSQL_INCLUDE_DIR=~/mysql-5.5/include\</userinput> -<prompt>> </prompt><userinput> -DMYSQL_LIBRARIES=~/mysql-5.5/lib/libmysqlclient.so -DENABLE_CLIENT=true</userinput> +<prompt>> </prompt><userinput> -DMYSQL_LIBRARIES=~/mysql-5.5/lib/libmysqlclient.so</userinput> ... -- Found MySQL includes: ~/mysql-5.5/include/mysql.h -- Found MySQL library: ~/mysql-5.5/lib/libmysqlclient.so --- box.net.sql(mysql) INC=~/mysql-5.5/include --- box.net.sql(mysql) LIBS=~/mysql-5.5/lib/libmysqlclient.so ... -- Configuring done -- Generating done -- Build files have been written to: ~/tarantool <prompt>$ </prompt><userinput>make</userinput> ... -[ 49%] Built target core Scanning dependencies of target mysql -[ 50%] Building CXX object src/plugin/mysql/CMakeFiles/mysql.dir/mysql.cc.o +[ 79%] Building CXX object src/module/mysql/CMakeFiles/mysql.dir/mysql.cc.o Linking CXX shared library libmysql.so -[ 50%] Built target mysql +[ 79%] Built target mysql ... -[100%] Built target xlog [100%] Built target man <prompt>$ </prompt> @@ -128,66 +124,56 @@ Linking CXX shared library libmysql.so # -DCMAKE_INSTALL_LIBDIR and -DCMAKE_INSTALL_PREFIX. # For this example we assume that "make install" is not done. -# Change directory to a directory which contains the tarantool.cfg file. +# Change directory to a directory which can be used for temporary tests. # For this example we assume that the name of this directory is -# /home/pgulutzan/tarantool_test. (Change "/home/pgulutzan" to whatever +# /home/pgulutzan/tarantool_sandbox. (Change "/home/pgulutzan" to whatever # is the actual base directory for the machine that's used for this test.) -# Edit the tarantool.cfg file and add this line: -# script_dir = "/home/pgulutzan/tarantool_test" -# The script_dir is the directory where the init.lua file must be. -# Now create a file named /home/pgulutzan/tarantool_test/init.lua -# and put the following lines in it (again, change "/home/pgulutzan" -# to whatever the real directory is that contains tarantool): -package.path = "/home/pgulutzan/tarantool/src/module/sql/?.lua;"..package.path -require("sql") -if type(box.net.sql) ~= "table" then -error("net.sql load failed") -end -require("box.net.mysql") - # Now, to help tarantool find the essential mysql.so file, execute these lines: -<userinput>cd /home/pgulutzan/tarantool_test</userinput> +<userinput>cd /home/pgulutzan/tarantool_sandbox</userinput> <userinput>mkdir box</userinput> <userinput>mkdir box/net</userinput> <userinput>cp ~/tarantool/src/module/mysql/mysql.so ./box/net/mysql.so</userinput> -# Start the Tarantool server. -# Run it in the background but let the initial display be in the foreground. -# So it's possible to see the message that the plugin was loaded. -<prompt>$ </prompt><userinput>~/tarantool/src/box/tarantool&</userinput> -2013-12-03 17:46:16.239 [12957] 1/sched C> version 1.5.1-271-g610930e -... loading /home/pgulutzan/tarantool_test/init.lua ... -... -2013-12-03 17:46:16.244 [12957] 1/sched C> entering event loop +# Start the Tarantool server. Do not use a Lua initialization file. + +<prompt>$ </prompt><userinput>~/tarantool/src/tarantool</userinput> +~/tarantool/src/tarantool: version 1.6.0-1085-gf6d30a5 +<prompt>tarantool> </prompt> -# Type 'Enter' and then start the Tarantool client. -<prompt>$ </prompt><userinput>~/tarantool/client/tarantool/tarantool</userinput> -<prompt>localhost> </prompt> +# Enter the following lines on the prompt (again, change "/home/pgulutzan" +# to whatever the real directory is that contains tarantool): +package.path = "/home/pgulutzan/tarantool/src/module/sql/?.lua;"..package.path +require("sql") +if type(box.net.sql) ~= "table" then error("net.sql load failed") end +require("box.net.mysql") +# ... Make sure that tarantool replies "true" for the calls to "require()". # Create a Lua function that will connect to the MySQL server, +# (using some factory default values for the port and user and password), # retrieve one row, and display the row. # For explanations of the statement types used here, read the -# Lua tutorial in the Tarantool user manual. -<prompt>localhost> </prompt><userinput>SETOPT delimiter = '!'</userinput> -<prompt>localhost> </prompt><userinput>function mysql_select ()</userinput> +# Lua tutorial earlier in the Tarantool user manual. +<prompt>tarantool> </prompt><userinput>SETOPT delimiter = '!'</userinput> +<prompt>tarantool> </prompt><userinput>function mysql_select ()</userinput> <prompt>-> </prompt><userinput> local dbh = box.net.sql.connect(</userinput> - <prompt>-> </prompt><userinput> 'mysql', '127.0.0.1', 3306, 'root', 'root', 'test')</userinput> + <prompt>-> </prompt><userinput> 'mysql', '127.0.0.1', 3306, 'root', '', 'test')</userinput> <prompt>-> </prompt><userinput> local test = dbh:select('SELECT * FROM test WHERE s1 = 1')</userinput> - <prompt>> </prompt><userinput> local row = ''</userinput> + <prompt>-> </prompt><userinput> local row = ''</userinput> <prompt>-> </prompt><userinput> for i, card in pairs(test) do</userinput> <prompt>-> </prompt><userinput> row = row .. card.s2 .. ' '</userinput> <prompt>-> </prompt><userinput> end</userinput> - <prompt> > </prompt><userinput> return row</userinput> + <prompt>-> </prompt><userinput> return row</userinput> <prompt>-> </prompt><userinput> end!</userinput> --- ... -<prompt>localhost> </prompt><userinput>SETOPT delimiter = ''!</userinput> -<prompt>localhost> </prompt> +<prompt>tarantool> </prompt><userinput>SETOPT delimiter = ''!</userinput> +<prompt>tarantool> </prompt> # Execute the Lua function. -<prompt>localhost> </prompt><userinput>mysql_select()</userinput> -- 2013-12-03 17:57:24.688 [12957] 102/iproto I> MySQL row - +<prompt>tarantool> </prompt><userinput>mysql_select()</userinput> +--- +- 'MySQL row ' +... # Observe the result. It contains "MySQL row". # So this is the row that was inserted into the MySQL database. # And now it's been selected with the Tarantool client. @@ -195,7 +181,6 @@ require("box.net.mysql") <para xml:id="plugin-postgresql-example"> <bridgehead renderas="sect4">PostgreSQL Example</bridgehead> -Warning: This example is obsolete; a new example is being prepared to replace it. This example assumes that a recent version of PostgreSQL has been installed. The PostgreSQL library and include files are also necessary. On Ubuntu they can be installed with <programlisting><prompt>$ </prompt><userinput>sudo apt-get install libpq-dev</userinput></programlisting> @@ -226,7 +211,7 @@ OK # port = 5432, user = 'postgres', user password = 'postgres', database = 'postgres'. # These can be changed, provided one changes them in all places. # Insert a row in database postgres, and quit. -<prompt>$ </prompt><userinput>~psql -h 127.0.0.1 -p 5432 -U postgres -d postgres</userinput> +<prompt>$ </prompt><userinput>psql -h 127.0.0.1 -p 5432 -U postgres -d postgres</userinput> Password for user postgres: psql (9.3.0, server 9.3.2) SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256) @@ -246,54 +231,56 @@ INSERT 0 1 <prompt>$ </prompt><userinput>make clean</userinput> <prompt>$ </prompt><userinput>rm CMakeCache.txt</userinput> <prompt>$ </prompt><userinput>cmake . -DWITH_POSTGRESQL=on -DPostgreSQL_LIBRARY=/usr/lib/libpq.so\</userinput> -<prompt>> </prompt><userinput> -DPostgreSQL_INCLUDE_DIR=/usr/include/postgresql -DENABLE_CLIENT=true</userinput> +<prompt>> </prompt><userinput> -DPostgreSQL_INCLUDE_DIR=/usr/include/postgresql</userinput> ... --- Found PostgreSQL: /usr/lib/libpq.so --- box.net.sql(pg): INC=/usr/include/postgresql;/usr/include/postgresql --- box.net.sql(pg): LIBS=pq +-- Found PostgreSQL: /usr/lib/libpq.so (found version "9.3.2") ... -- Configuring done -- Generating done -- Build files have been written to: ~/tarantool <prompt>$ </prompt><userinput>make</userinput> ... -[ 49%] Built target core -[ 50%] Building CXX object src/plugin/pg/CMakeFiles/pg.dir/pg.cc.o +[ 79%] Building CXX object src/plugin/pg/CMakeFiles/pg.dir/pg.cc.o Linking CXX shared library libpg.so -[ 50%] Built target pg +[ 79%] Built target pg ... -[100%] Built target xlog [100%] Built target man <prompt>$ </prompt> -# Before starting Tarantool server, tell it where the PostgreSQL plugin is. -<prompt>$ </prompt><userinput>export TARANTOOL_PLUGIN_DIR=~/tarantool/src/plugin/pg</userinput> -<prompt>$ </prompt> +# Change directory to a directory which can be used for temporary tests. +# For this example we assume that the name of this directory is +# /home/pgulutzan/tarantool_sandbox. (Change "/home/pgulutzan" to whatever +# is the actual base directory for the machine that's used for this test.) +# Now, to help tarantool find the essential mysql.so file, execute these lines: +<userinput>cd /home/pgulutzan/tarantool_sandbox</userinput> +<userinput>mkdir box</userinput> +<userinput>mkdir box/net</userinput> +<userinput>cp ~/tarantool/src/module/pg/pg.so ./box/net/pg.so</userinput> -# Start the Tarantool server. -# Run it in the background but let the initial display be in the foreground. -# So it's possible to see the message that the plugin was loaded. -<prompt>$ </prompt><userinput>~/tarantool/src/box/tarantool&</userinput> -2013-12-06 13:01:51.518 [23978] 1/sched C> version 1.5.1-290-g45b93e7 -... Loading plugin: ~/tarantool/src/plugin/pg/libpg.so ... -... Plugin 'postgresql' was loaded, version: 1 -... -2013-12-06 13:01:51.531 [23978] 1/sched C> entering event loop +# Start the Tarantool server. Do not use a Lua initialization file. -# Type 'Enter' and then start the Tarantool client. -<prompt>$ </prompt><userinput>~/tarantool/client/tarantool/tarantool</userinput> -<prompt>localhost> </prompt> +<prompt>$ </prompt><userinput>~/tarantool/src/tarantool</userinput> +~/tarantool/src/tarantool: version 1.6.0-1085-gf6d30a5 +<prompt>tarantool> </prompt> + +# Enter the following lines on the prompt (again, change "/home/pgulutzan" +# to whatever the real directory is that contains tarantool): +package.path = "/home/pgulutzan/tarantool/src/module/sql/?.lua;"..package.path +require("sql") +if type(box.net.sql) ~= "table" then error("net.sql load failed") end +require("box.net.pg") +# ... Make sure that tarantool replies "true" for the calls to "require()". # Create a Lua function that will connect to the PostgreSQL server, # retrieve one row, and display the row. # For explanations of the statement types used here, read the # Lua tutorial in the Tarantool user manual. -<prompt>localhost> </prompt><userinput>SETOPT delimiter = '!'</userinput> -<prompt>localhost> </prompt><userinput>function postgresql_select ()</userinput> +<prompt>tarantool> </prompt><userinput>SETOPT delimiter = '!'</userinput> +<prompt>tarantool> </prompt><userinput>function postgresql_select ()</userinput> <prompt>-> </prompt><userinput> local dbh = box.net.sql.connect(</userinput> <prompt>-> </prompt><userinput> 'pg', '127.0.0.1', 5432, 'postgres', 'postgres', 'postgres')</userinput> <prompt>-> </prompt><userinput> local test = dbh:select('SELECT * FROM test WHERE s1 = 1')</userinput> - <prompt>> </prompt><userinput> local row = ''</userinput> + <prompt>-> </prompt><userinput> local row = ''</userinput> <prompt>-> </prompt><userinput> for i, card in pairs(test) do</userinput> <prompt>-> </prompt><userinput> row = row .. card.s2 .. ' '</userinput> <prompt>-> </prompt><userinput> end</userinput> @@ -301,14 +288,14 @@ Linking CXX shared library libpg.so <prompt>-> </prompt><userinput> end!</userinput> --- ... -<prompt>localhost> </prompt><userinput>SETOPT delimiter = ''!</userinput> -<prompt>localhost> </prompt> +<prompt>tarantool> </prompt><userinput>SETOPT delimiter = ''!</userinput> +<prompt>tarantool> </prompt> # Execute the Lua function. -<prompt>localhost> </prompt><userinput>postgresql_select()</userinput> -- 2013-12-06 13:07:45.893 [23978] 102/iproto I> PostgreSQL row - - +<prompt>tarantool> </prompt><userinput>postgresql_select()</userinput> +--- +- 'PostgreSQL row ' +... # Observe the result. It contains "PostgreSQL row". # So this is the row that was inserted into the PostgreSQL database. diff --git a/doc/user/server-administration.xml b/doc/user/server-administration.xml index 56d872ad18978df6ce0d4b8abbc98223a8c07793..c6a08d9013c1e8aa033789a1d3ed205bf0272f0c 100644 --- a/doc/user/server-administration.xml +++ b/doc/user/server-administration.xml @@ -13,24 +13,31 @@ <section xml:id="signal-handling"> <title>Server signal handling</title> <para> - The server is configured to gracefully shutdown on SIGTERM and + The server is configured to shut down gracefully on SIGTERM and SIGINT (keyboard interrupt) or SIGHUP. SIGUSR1 can be used to save a snapshot. All other signals are blocked or ignored. The signals are processed in the main event loop. Thus, if the control flow never reaches the event loop (thanks to a runaway stored procedure), the server stops responding to any signal, and - can be only killed with SIGKILL (this signal can not be ignored). + can only be killed with SIGKILL (this signal can not be ignored). </para> </section> <section xml:id="utility-tarantool"> -<title>Utility <code>tarantool</code> — the main client</title> +<title>Utility <code>tarantool</code> — using the server as a client</title> <para> -This section shows all legal syntax for the tarantool command-line client, with short notes and examples. +If <code>tarantool</code> is started without an initialization file, then +there will be a prompt ("<code>tarantool></code>") and it will be possible +to enter requests. When used this way, <code>tarantool</code> is a client +program as well as a server program. +</para> +<para> +This section shows all legal syntax for the tarantool program, with short notes and examples. Other client programs may have similar options and request syntaxes. +Some of the information in this section is duplicated in the Configuration Reference chapter. </para> <para> @@ -46,104 +53,33 @@ A vertical bar <code>|</code> means the preceding and following tokens are mutua <para> <bridgehead renderas="sect4">Options when starting client from the command line</bridgehead> -General form: <code>tarantool [<replaceable>option</replaceable>...] [<replaceable>request</replaceable>]</code>. - -Request will be described in a later part of this section. +General form: <code>tarantool</code> or <code>tarantool <replaceable>file-name</replaceable></code> +or <code>tarantool <replaceable>option</replaceable>... </code>. +</para> +<para> +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 +that a separate program can connect to the server via one of the ports. +</para> +<para> Option is one of the following (in alphabetical order by the long form of the option): </para> <variablelist> - <varlistentry> - <term xml:id="utility-tarantool-admin-port" xreflabel="utility-tarantool-admin-port">--admin-port</term> - <listitem><para> - Syntax: short form: <code>-a <replaceable>port-number</replaceable></code> - long form: <code>--a[dmin-port] [=] <replaceable>port-number</replaceable></code>. - Effect: Client will look for the server on the port designated by port-number. - Notes: This is the <quote>administrative</quote> port. The default value is 33015. - If --port is specified then there is no need to specify --admin-port, the client will discover it. - </para></listitem> - </varlistentry> - <varlistentry> - <term xml:id="utility-tarantool-cat" xreflabel="utility-tarantool-cat">--cat</term> - <listitem><para> - Syntax: short form: <code>-C <replaceable>file-name</replaceable></code> - long form: <code>--c[at] <replaceable>file-name</replaceable></code>. - Effect: Client will print the contents of the write-ahead log or snapshot designated by file-name. - Example: <code>--cat /tarantool_user/work_dir/00000000000000000018.xlog</code> - Notes: The client stops after displaying the contents. There is also a way to use --cat for Lua requests. - </para></listitem> - </varlistentry> - <varlistentry> - <term xml:id="utility-tarantool-delim" xreflabel="utility-tarantool-delim">--delim</term> - <listitem><para> - Syntax: short form: <code>-D <replaceable>delimiter</replaceable></code> - long form: <code>--d[elim] <replaceable>delimiter</replaceable></code>. - Effect: If --cat is used, then put delimiter at end of each line - of a Lua file. If --cat is not used, then require that - all requests end with delimiter. - Example: <code>--delim = '!'</code> - Notes: See also the SETOPT DELIMITER request. - </para></listitem> - </varlistentry> - <varlistentry> - <term xml:id="utility-tarantool-format" xreflabel="utility-tarantool-format">--format</term> - <listitem><para> - Syntax: short form: <code>-M tarantool|raw</code> - long form: <code>--fo[rmat] tarantool|raw</code>. - Effect: set format for output from --cat - Example: <code>--format tarantool</code> - Notes: The default format is tarantool. - </para></listitem> - </varlistentry> - <varlistentry> - <term xml:id="utility-tarantool-from" xreflabel="utility-tarantool-from">--from</term> - <listitem><para> - Syntax: short form: <code>-F <replaceable>log-sequence-number</replaceable></code> - long form: <code>--fr[om] <replaceable>log-sequence-number</replaceable></code>. - Effect: Play only what has a a log sequence number greater than or equal to log-sequence-number. - Example: <code>--from 55</code> - Notes: See also --play and --to. - </para></listitem> - </varlistentry> <varlistentry> <term xml:id="utility-tarantool-help" xreflabel="utility-tarantool-help">--help</term> <listitem><para> Syntax: short form: <code>-?</code> - long form: <code>--hel[p]</code>. + long form: <code>--h[elp]</code>. Effect: Client displays a help message including a list of options. Example: <code>--help</code> - Notes: The client stops after displaying the help. - </para></listitem> - </varlistentry> - <varlistentry> - <term xml:id="utility-tarantool-host" xreflabel="utility-tarantool-host">--host</term> - <listitem><para> - Syntax: short form: <code>-h <replaceable>host-name</replaceable></code> - long form: <code>--ho[st] [=] <replaceable>host-name</replaceable></code>. - Effect: Client will look for the server on the computer designated by host-name. - Example: <code>--host = 127.0.0.1</code> - Notes: The default value is localhost. - </para></listitem> - </varlistentry> - <varlistentry> - <term xml:id="utility-tarantool-space" xreflabel="utility-tarantool-space">--space</term> - <listitem><para> - Syntax: short form: <code>-S <replaceable>space-number</replaceable></code> - Long form: <code>--s[pace] <replaceable>space-number</replaceable></code>. - Effect: Play only what is applicable to the space designated by space-number. - Example: <code>--space 0</code> - </para></listitem> - </varlistentry> - <varlistentry> - <term xml:id="utility-tarantool-to" xreflabel="utility-tarantool-to">--to</term> - <listitem><para> - Syntax: short form: <code>-T <replaceable>log-sequence-number</replaceable></code> - long form: <code>--t[o] <replaceable>log-sequence-number</replaceable></code>. - Effect: Play only what has a log sequence number less than or equal to log-sequence-number. - Example: <code>--to 66</code> - Notes: See also --play and --from. + Notes: The program stops after displaying the help. </para></listitem> </varlistentry> + <varlistentry> <term xml:id="utility-tarantool-version" xreflabel="utility-tarantool-version">--version</term> <listitem><para> @@ -151,7 +87,7 @@ Option is one of the following (in alphabetical order by the long form of the op long form: <code>--v[ersion]</code>. Effect: Client displays version information. Example: <code>--version</code> - Notes: The client stops after displaying the version. + Notes: The program stops after displaying the version. </para></listitem> </varlistentry> </variablelist> @@ -161,8 +97,8 @@ Option is one of the following (in alphabetical order by the long form of the op </para> <para> Keywords are: Character sequences containing only letters of the English alphabet. - Examples: SETOPT, PAGER. - Notes: Keywords are case insensitive so PAGER and Pager are the same thing. + Examples: SETOPT. + Notes: Keywords are case insensitive so SETOPT and Setopt are the same thing. </para> <para> Procedure identifiers are: Any sequence of letters, digits, or underscores which is @@ -186,12 +122,11 @@ Tokens must be separated from each other by one or more spaces, except that spaces are not necessary around single-byte tokens or string literals. </para> -<para> +<para xml:id="utility-tarantool-delim"> <bridgehead renderas="sect4">Requests in alphabetical order</bridgehead> -Although an initial request may be entered on the tarantool command line, -generally they are entered following the prompt in interactive mode while -tarantool is running. (A prompt will be the name of the host and a greater-than -sign, for example <code>localhost></code>). The end-of-request marker is +Generally requests are entered following the prompt in interactive mode while +tarantool is running. (A prompt will be the word tarantool and a greater-than +sign, for example <code>tarantool></code>). The end-of-request marker is a newline (line feed). </para> @@ -199,46 +134,13 @@ a newline (line feed). <varlistentry> <term xml:id="utility-tarantool-exit" xreflabel="utility-tarantool-exit">EXIT</term> <listitem><para> - Syntax: <code>EXIT</code>. - Effect: The tarantool program stops. - Example: <code>EXIT</code>. - Notes: The QUIT request does the same thing. The client sends nothing to the server. - </para></listitem> - </varlistentry> - <varlistentry> - <term xml:id="utility-tarantool-help2" xreflabel="utility-tarantool-help2">HELP</term> - <listitem><para> - Syntax: <code>HELP</code>. - Effect: Client displays a message including a list of possible requests. - Example: <code>HELP</code>. - Notes: The client sends nothing to the server. - </para></listitem> - </varlistentry> - <varlistentry> - <term xml:id="utility-tarantool-loadfile" xreflabel="utility-tarantool-loadfile">LOADFILE</term> - <listitem><para> - Syntax: <code>LOADFILE <replaceable>string-literal</replaceable></code>. - Effect: The client loads instructions from the file identified by string-literal. - Example: <code>LOADFILE '/home/tarantool_user/file5.txt'</code>. - </para></listitem> - </varlistentry> - <varlistentry> - <term xml:id="utility-tarantool-quit" xreflabel="utility-tarantool-quit">QUIT</term> - <listitem><para> - Syntax: <code>QUIT</code>. - Effect: The client stops. This request is handled entirely by the client. - Example: <code>QUIT</code>. - Notes: The EXIT request does the same thing. The client sends nothing to the server. - </para></listitem> - </varlistentry> - <varlistentry> - <term xml:id="utility-tarantool-set" xreflabel="utility-tarantool-set">SET</term> - <listitem><para> - Syntax: <code>SET INJECTION <replaceable>name-token</replaceable> <replaceable>state-token</replaceable></code>. - Effect: In normal mode: error. - Notes: This request is only available in debug mode. + Syntax: <code>control-C</code>. + Effect: The tarantool program receives a SIGINT signal and stops. + Example: <code>^C</code>. + Notes: The preferable way to stop the program is to send an "os.exit()" request. </para></listitem> </varlistentry> + <varlistentry> <term xml:id="utility-tarantool-setopt" xreflabel="utility-tarantool-setopt">SETOPT</term> <listitem><para> @@ -246,18 +148,8 @@ a newline (line feed). The string must be a value in single quotes. Effect: string becomes end-of-request delimiter, so newline alone is not treated as end of request. Example: <code>SETOPT DELIMITER = '!'</code>. - Notes: The client sends nothing to the server. - </para> - <para> - Syntax: <code>SETOPT PAGER = <replaceable>string-literal</replaceable></code>. - The string must be a value in single quotes. - Effect: string becomes the pager that will be invoked for subsequent commands; - usually the values are '/usr/bin/less' or '/bin/more' for the common - Linux pagers. - Example: <code>SETOPT PAGER = '/usr/bin/less'</code>. - Notes: The client sends nothing to the server. - </para> - </listitem> + Notes: This has been temporarily disabled. + </para></listitem> </varlistentry> <varlistentry> @@ -272,222 +164,64 @@ a newline (line feed). </variablelist> <para> -For a condensed Backus-Naur Form [BNF] description of some of the requests, see +For a condensed Backus-Naur Form [BNF] description of the suggested form of client requests, see <link xlink:href="https://github.com/tarantool/tarantool/blob/master/doc/box-protocol.txt"><filename>doc/box-protocol.txt</filename></link> and <link xlink:href="https://github.com/tarantool/tarantool/blob/master/doc/sql.txt"><filename>doc/sql.txt</filename></link>. </para> -<para> -<bridgehead renderas="sect4">Modes</bridgehead> -Depending how one combines the tarantool client's options, there are in effect three modes of operation: -<quote>interactive</quote>, <quote>print and play</quote>, or <quote>replication</quote> mode. -</para> + <para> In <emphasis>interactive</emphasis> mode, one types requests and gets results. -One can specify a request file when starting -(<code>tarantool < file_name</code>) -or one can specify a request file with the LOADFILE request: -(<code>LOADFILE file_name</code>), but typically the requests +Typically the requests are typed in by the user following prompts. Here is an example of an interactive-mode tarantool client session: <programlisting> <prompt>$ </prompt>tarantool -localhost> <userinput>box.space.space0:insert{12345}</userinput> -- [12345] -localhost> <userinput>EXIT</userinput> -<prompt>$ </prompt> -</programlisting> - -</para> -<para> -In <emphasis>print and play</emphasis> mode, -one uses --cat and --play and --from and --to and --space options -to print write-ahead-log contents, or to send write-ahead-log -contents to the server. -Here is an example of a print-and-play-mode tarantool client session: -<programlisting> -<prompt>$ </prompt>tarantool --cat 00000000000000000005.xlog --from 22 --to 26 -Insert, lsn: 22, time: 1385327353.345869, len: 33, space: 0, - cookie: 127.0.0.1:44787 ['X-1', 100] -Insert, lsn: 23, time: 1385327353.346745, len: 42, space: 0, - cookie: 127.0.0.1:44787 ['X-2', 200, 8243105135088135759] -Insert, lsn: 24, time: 1385327353.347352, len: 34, space: 0, - cookie: 127.0.0.1:44787 ['X-3', 300, ''] -Update, lsn: 25, time: 1385327353.348209, len: 42, space: 0, - cookie: 127.0.0.1:44787 ['X-1'] -Delete, lsn: 26, time: 1385327353.348879, len: 28, space: 0, - cookie: 127.0.0.1:44787 ['X-2'] -<prompt>$ </prompt> -</programlisting> -</para> -<para> -In <emphasis>replication</emphasis> mode, -one connects as a replica, and then writes -a binary log to a file. -</para> - -</section> - -<section xml:id="tarantar"> -<title>Utility <code>tarantar</code></title> -<para> -The tarantar utility program will create new snapshots by reading existing -snapshots and write-ahead-log (xlog) files. Thus it differs from <olink targetptr="box.snapshot"/>, -which creates new snapshots from the database. Since tarantar uses less -memory than box.snapshot(), it is especially appropriate for taking periodic -snapshots as a background task. -</para> -<para> -To prepare: ensure that the configuration file is available. -</para> -<para> -To run:<programlisting> <command>tarantar</command> [options] <replaceable>configuration-file</replaceable></programlisting> -where possible options are:<simplelist> - <member><code>-c </code> or <code>--create </code> — create snapshot file. example: <code>--create</code></member> - <member><code>-i <replaceable>seconds-count</replaceable></code> or <code>--interval <replaceable>seconds-count</replaceable></code> — repeat every seconds-count seconds. example: <code>-i 3600</code></member> - <member><code>-n <replaceable>lsn-number</replaceable></code> or <code>--lsn <replaceable>lsn-number</replaceable></code> — start from lsn = lsn-number. if not specified, lsn = latest. example: <code>-n 5</code></member> - <member><code>-l <replaceable>bytes-count</replaceable></code> or <code>--limit <replaceable>bytes-count</replaceable></code> — do not use more than bytes-count bytes of memory. example: <code>-l 5000000</code></member> - <member><code>-? </code> or <code>--help </code> — display a help message and exit. example: <code>--help</code></member> - <member><code>-V </code> or <code>--version</code> — display version and exit. example: <code>-V</code></member></simplelist></para> -<para> -Example: -<programlisting> -<prompt>$ </prompt>~/tarantool/client/tarantar/tarantar -c -i 30 ./tarantool.cfg -snap_dir: /home/user/tarantool_test/work_dir -wal_dir: /home/user/tarantool_test/work_dir -spaces: 1 -interval: 30 -memory_limit: 0M - -START SNAPSHOTTING Fri Oct 25 09:35:25 2013 - -last snapshot lsn: 7 -(snapshot) 00000000000000000007.snap 0.000M processed - -( >> ) 00000000000000000006.snap 0.000M processed - -START SNAPSHOTTING Fri Oct 25 09:35:55 2013 - -last snapshot lsn: 7 -(snapshot) 00000000000000000007.snap 0.000M processed - -( >> ) 00000000000000000006.snap 0.000M processed - -snapshot exists, skip. - + [ tarantool will display an introductory message including version number here ] +tarantool> box.cfg{admin_port=3313, primary_port=3301} + [ tarantool will display configuration information here ] +tarantool> s = box.schema.create_space('space0') + [ tarantool may display an in-progress message here ] +--- ... - +tarantool> i = s:create_index('primary', {type = 'hash', parts = {0, 'NUM'}}) +--- +... +tarantool> box.space.space0:insert{1,'My first tuple'} +--- +- [1, 'My first tuple'] +... +tarantool> box.space.space0:select(1) +--- +- - [1, 'My first tuple'] +... +tarantool> box.space.space0:drop() +--- +... +tarantool> os.exit() +2014-04-30 10:28:00.886 [20436] main/101/spawner I> Exiting: master shutdown +<prompt>$ </prompt> </programlisting> +Explanatory notes about what tarantool displayed in the above example: </para> - -<para> -<bridgehead renderas="sect4">Why tarantar?</bridgehead> -To recapitulate the idea of a snapshot and a write-ahead log: -Tarantool's database is entirely in memory; however, it has a -complete and up-to-date on-disk backup. This consists of snapshot -files (extension .snap) which are copies of the database as of the -time the snapshot was taken, and write-ahead-log files (extension -.xlog) which contain records of insert/update/delete operations that -are written when the operations occur. If the tarantool server -goes down and later restarts, it will recover the database by -reading the snapshot and then re-applying the write-ahead-log records. -</para> - -<para> -The approach is reliable. But if the snapshot gets old and the -number of write-ahead-log records get huge, then recovery would -take too long and .xlog files would take too much space. -So periodically one should make new snapshots -- if a .snap file -is up to date, then the .xlog files are unnecessary and can be -archived. -</para> - -<para> -To take a snapshot with the tarantool client, one can say -box.snapshot(). box.snapshot() will copy every tuple from -the in-memory database to the .snap file. However, this -is not always the ideal method. -</para> - -<para> -Taking snapshots with tarantar, instead of with box.snapshot(), -can be better because: -<itemizedlist> - <listitem><para>tarantar can work even if the tarantool server is down - because it works from the existing .snap and .xlog files, - rather than from an in-memory database.</para></listitem> - <listitem><para>tarantar saves memory when constructing its own in-memory - index to the rows by making SHA-1 hashes for primary keys - that contain strings or that are multi-column and longer - than 20 bytes</para></listitem> - <listitem><para>tarantar can be made to limit its memory usage so that - it does not interfere with resource use by other processes - including other Tarantool-related processes.</para></listitem> - <listitem><para> - tarantar can be made to run periodically as a daemon</para></listitem> -</itemizedlist> -</para> - -<para> -For more explanation of tarantar's design see <link xlink:href="https://github.com/tarantool/tarantool/wiki/Tarantar">the Tarantool wiki</link>. -</para> - -</section> - -<section xml:id="tarancheck"> -<title>Utility <code>tarancheck</code></title> <para> -The tarancheck utility program will generate and verify <quote>signature files</quote>. -A signature file contains, along with basic information that identifies the database, -checksums calculated for each index in each space of the database, -based on the latest snapshot and all subsequent entries in the write-ahead log. -Signature files are useful for ensuring that databases have been saved without error, -and for quick comparisons to see whether a database's components have been modified. +* Many requests return typed objects. + In the case of "box.cfg{admin_port=3313, primary_port=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=3301}", then + the result would not have been displayed on the screen. </para> <para> -The main reason that tarancheck was created was -so that users would be able to compare the -consistency of two running servers, the master and the replica. -By creating a signature file on the master using the master -directory, and then copying the signature file to the replica, -one will be able to confirm that the replica is not corrupt. +* A display of an object always begins with "---" and ends with "...". </para> <para> -There is one necessary warning. Since either the master or the -replica is likely to be active when tarancheck runs, the check -can only be applicable for the database as of the -last transaction that was run on both the master and the replica. -That is why tarancheck displays last_xlog_lsn, which is the log -sequence number of the write-ahead log, when it finishes. -</para> - -<para> -To prepare: ensure that the configuration file contains -<olink targetptr="wal_dir"/> and <olink targetptr="snap_dir"/> -clauses. Tarancheck does not assume that wal_dir and snap_dir have default values. -</para> -<para> -To run:<programlisting> <command>tarancheck</command> [options] <replaceable>configuration-file</replaceable></programlisting> -where possible options are:<simplelist> - <member><code>-G <replaceable>signature file</replaceable></code> or <code>--generate <replaceable>signature-file</replaceable></code> — generate signature file. example: <code>-G x.crc</code></member> - <member><code>-W <replaceable>signature file</replaceable></code> or <code>--verify <replaceable>signature-file</replaceable></code> — verify signature file. example: <code>--verify x.crc</code></member> - <member><code>-? </code> or <code>--help </code> — display a help message and exit. example: <code>--help</code></member> - <member><code>-V </code> or <code>--version</code> — display version and exit. example: <code>-V</code></member></simplelist></para> -<para> -Example: -<programlisting> -<prompt>$ </prompt>~/tarantool/client/tarantar/tarancheck --generate=x.crc tarantool.cfg ->>> Signature file generation -configured spaces: 1 -snap_dir: ./work_dir -wal_dir: ./work_dir -last snapshot lsn: 1 -last xlog lsn: 0 -(snapshot) 00000000000000000001.snap -(signature) saving x.crc -</programlisting> +* The insert request returns an object of type = tuple, so the object display line + begins with a single dash ('- '). However, the select request returns + an object of type = <emphasis>table of tuples</emphasis>, so the object display line + begins with two dashes ('- - '). </para> </section> @@ -543,12 +277,13 @@ tarantool_deploy.sh: done <section xml:id="os-install-notes"> <title>System-specific administration notes</title> <blockquote><para> - This chapter provides a cheatsheet for most common server management - routines on every supported operating system. + This section will contain information about issue or features which exist + on some platforms but not others -- for example, on certain versions of a + particular Linux distribution. </para></blockquote> <section xml:id="Debian"> - <title>Debian GNU/Linux and Ubuntu</title> + <title>Administrating with Debian GNU/Linux and Ubuntu</title> <para> Setting up an instance: ln -s /etc/tarantool/instances.available/instance-name.cfg /etc/tarantool/instances.enabled/ </para> @@ -565,26 +300,241 @@ tarantool_deploy.sh: done <section xml:id="rpm-based-distros"> <title>Fedora, RHEL, CentOS</title> <para> - TBA + There are no known permanent issues. + For transient issues, go to <link xlink:href="https://github.com/tarantool/tarantool/issues">http://github.com/tarantool/tarantool/issues</link> and enter "RHEL" or "CentOS" or "Fedora" or "Red Hat" in the search box. </para> </section> <section xml:id="FreeBSD"> <title>FreeBSD</title> <para> - TBA + There are no known permanent issues. + For transient issues, go to <link xlink:href="https://github.com/tarantool/tarantool/issues">http://github.com/tarantool/tarantool/issues</link> and enter "FreeBSD" in the search box. </para> </section> <section xml:id="mac-os-x"> <title>Mac OS X</title> <para> - TBA + There are no known permanent issues. + For transient issues, go to <link xlink:href="https://github.com/tarantool/tarantool/issues">http://github.com/tarantool/tarantool/issues</link> and enter "OS X" in the search box. </para> </section> </section> +<section xml:id="authentication"> + +<title>Authentication and access control</title> + +<para> +Understanding the details of security is primarily an issue for administrators, +but ordinary users should at least skim this section so that they will have an +idea of how Tarantool makes it possible for administrators to prevent +unauthorized access to the database and to certain functions. +</para> + +<para> +Briefly: there is a method to guarantee with password checks that users really +are who they say they are ("authentication"). There is a _user space where +user names and password-hashes are stored. There are functions for saying +that certain users are allowed to do certain things ("privileges"). There +is a _priv space where privileges are stored. Whenever a user tries to do +an operation, there is a check whether the user has the privilege to do +the operation ("access control"). +</para> + +<para> +<bridgehead renderas="sect4">Passwords</bridgehead> +Each user may have a password. +The password is any alphanumeric string. +Administrators should advise users to choose long unobvious passwords, +but it is ultimately up to the users to choose or change +their own passwords. +</para> + +<para> +Tarantool passwords are stored in the _user space with a +<link xlink:href="https://en.wikipedia.org/wiki/Cryptographic_hash">Cryptographic hash function</link> +so that, if the password is 'x', the stored hashed-password is a long string like +'lL3OvhkIPOKh+Vn9Avlkx69M/Ck='. +When a client connects to a Tarantool server, the server sends a random +<link xlink:href="https://en.wikipedia.org/wiki/Salt_%28cryptography%29">Salt Value</link> +which the client must mix with the hashed-password before sending +to the server. +Thus the original value 'x' is never stored anywhere except in the +user's head, and the hashed value is never passed passed down a +network wire except when mixed with a random salt. +This system prevents malicious onlookers from finding passwords +by snooping in the log files or snooping on the wire. +It is the same system that <link xlink:href="http://dev.mysql.com/doc/refman/4.1/en/password-hashing.html">MySQL introduced several years ago</link> +which has proved adequate for medium-security installations. +Nevertheless administrators should warn users that no system +is foolproof against determined long-term attacks, so passwords +should be guarded and changed occasionally. +</para> + +<para> +Notes: To get the hash-password of a string 'X', say <code>box.schema.user.password('X')</code>. +To see more about the details of the algorithm for the purpose of writing a new client application, read +<link xlink:href="https://github.com/tarantool/tarantool/blob/master/src/scramble.h">the scramble.h header file</link>. +</para> + +<para> +<bridgehead renderas="sect4">Users and the _user space</bridgehead> +The fields in the _user space are: +a numeric id, a string, the user name, and the optional password. +</para> + +<para> +There are two special users: 'guest' (user id = 0) and 'admin' (user id = 1). +They are defined in advance. +They cannot be dropped. +(The 'guest' user is a default which usually has minimum privileges; +the 'admin' user is an administrator which always has maximum privileges.) +</para> + +<para> +To select a row from the _user space, use <code>box.select</code>. +For example, here is what happens with a select for user id = 0, +which is the 'guest' user, without a password: +<programlisting><prompt>tarantool></prompt> box.space._user:select{0} +--- +- - [0, '', 'guest'] +...</programlisting></para> + +<para> +To change tuples in the user space, do not use ordinary <code>box.space</code> functions +for insert or update or delete -- the _user space is special so +there are special functions which have appropriate error checking. +</para> + +<para> +To create a new user, say +<code>box.schema.user.create(<replaceable>user-name</replaceable>)</code> +or +<code>box.schema.user.create(<replaceable>user-name</replaceable>', {password=<replaceable>password</replaceable>})</code>. +</para> + +<para> +To drop a user, say +<code>box.schema.user.drop(<replaceable>user-name</replaceable>)</code>. +</para> + +<para> +For example, here is a session which creates a new user with +a strong password, selects from the tuple in +the _user space, and then drops the user. +<programlisting><prompt>tarantool></prompt> box.schema.user.create('Elizabeth Browning', {password = 'Iwtso65$SDS?'}) +--- +... +<prompt>tarantool></prompt> box.space._user:select{4} +--- +- - [4, '', 'Elizabeth Browning', {'chap-sha1': 'zyy3yArGOQ4T40PnsL6yPGlgYrU='}] +... +<prompt>tarantool></prompt> box.schema.user.drop('Elizabeth Browning') +--- +...</programlisting></para> + +<para> +Notes: The maximum number of users is 32. +</para> + +<para> +<bridgehead renderas="sect4">Privileges and the _priv space</bridgehead> +The fields in the _priv space are: +the numeric id of the user who gave the privilege ("grantor_id"), +the numeric id of the user who received the privilege ("grantee_id"), +the id of the object, +the type of object -- "space" or "function" or "universe", +the type of operation -- "read" or "write" or "execute" or a combination such as "read,write,execute". +</para> + +<para> +The function for granting a privilege is: +<code>box.schema.user.grant(<replaceable>user-name-of-grantee</replaceable>, <replaceable>operation-type</replaceable>, <replaceable>object-type</replaceable>, '<replaceable>>object-name</replaceable>)</code> +or +<code>box.schema.user.grant(<replaceable>user-name-of-grantee</replaceable>, <replaceable>operation-type</replaceable>, 'universe')</code>. +</para> + +<para> +The function for revoking a privilege is: +<code>box.schema.user.revoke(<replaceable>user-name-of-grantee</replaceable>, <replaceable>operation-type</replaceable>, <replaceable>object-type</replaceable>, '<replaceable>>object-name</replaceable>)</code>. +</para> + +<para> +For example, here is a session where the admin user gave +the guest user the privilege to read from a +space named space55, and then took the privilege away: +<programlisting><prompt>tarantool></prompt> box.schema.user.grant('guest', 'read', 'space', 'space55') +--- +... +<prompt>tarantool></prompt> box.schema.user.revoke('guest', 'read', 'space', 'space55') +--- +...</programlisting></para> + +<para> +Notes: Generally privileges are granted or revoked by the owner of the object +(the user who created it), or by the 'admin' user. +Before dropping any objects or users, steps should be taken to ensure +that all their associated privileges have been revoked. +Only the 'admin' user can grant privileges for the 'universe'. +</para> + +<para> +<bridgehead renderas="sect4">Functions and the _func space</bridgehead> +The fields in the _func space are: +the numeric function id, a number, and the function name. +</para> + +<para> +The _func space does not include the function's body. +One continues to create Lua functions in the usual way, +by saying "<code>function <replaceable>function_name</replaceable> () ... end</code>", without +adding anything in the _func space. The _func space only +exists for storing function tuples so that their names +can be used within grant/revoke functions. +</para> + +<para> +The function for creating a _func tuple is: +<code>box.schema.func.create(<replaceable>function-name</replaceable>)</code>. +</para> + +<para> +The function for dropping a _func tuple is: +<code>box.schema.func.drop(<replaceable>function-name</replaceable>)</code>. +</para> + +<para> +In the following example, a function named 'f7' is created, +then it is put in the _func space, then it is used in a +box.schema.user.grant function, then it is dropped: +<programlisting><prompt>tarantool></prompt> function f7() box.session.uid() end +--- +... +<prompt>tarantool></prompt> box.schema.func.create('f7') +--- +... +<prompt>tarantool></prompt> box.schema.user.grant('guest', 'execute', 'function', 'f7') +--- +... +<prompt>tarantool></prompt> box.schema.func.drop('f7') +--- +...</programlisting></para> + +<para> +<bridgehead renderas="sect4">box.session and security</bridgehead> + +After a connection has taken place, the user has access to a "session" object +which has several functions. The ones which are of interest for security +purposes are: +<programlisting>box.session.uid() #returns the id of the current user +box.session.user() #returns the name of the current user +box.session.su(<replaceable>user-name</replaceable>) #allows changing current user to 'user-name'</programlisting></para> + +</section> + </chapter> <!-- diff --git a/doc/user/stored-procedures.xml b/doc/user/stored-procedures.xml index ad2f06419a76975a13cc456d26b7d23a8448935c..5811521da1a49cae1155d7e63fc3d222768e6413 100644 --- a/doc/user/stored-procedures.xml +++ b/doc/user/stored-procedures.xml @@ -33,10 +33,10 @@ </blockquote> <para> Procedures can be defined and invoked interactively, for example:: - <programlisting><computeroutput>localhost> <userinput>function f1() return 'hello' end</userinput> + <programlisting><computeroutput>tarantool> <userinput>function f1() return 'hello' end</userinput> --- ... -localhost> <userinput>f1()</userinput> +tarantool> <userinput>f1()</userinput> --- - hello ... @@ -47,18 +47,18 @@ localhost> <userinput>f1()</userinput> using the text or binary protocol, for evaluation as a chunk of Lua code. </para> <para> - Thus, the request "<code>function f1() return 'hello' end</code>" sends over + Thus, the request "<code>function f1() return 'hello' end</code>" causes definition of the Lua function which will be identified as f1(). Then the request "<code>f1()</code>" causes execution of the function. The function returns a string 'hello', which gets displayed. </para> <para> It's possible to execute any chunk of Lua code, not just invoke functions ... - <programlisting><computeroutput>localhost> <userinput>1 + 2</userinput> + <programlisting><computeroutput>tarantool> <userinput>1 + 2</userinput> --- - 3 ... -localhost> <userinput>'hello' .. ' world' -- '..' means 'concatenate'</userinput> +tarantool> <userinput>'hello' .. ' world' -- '..' means 'concatenate'</userinput> --- - hello world ... @@ -163,15 +163,15 @@ function f1(a) return type(a), s end kostja@atlas:~<prompt>$</prompt> <userinput>tarantool</userinput> -localhost> <userinput>dofile('arg.lua')</userinput> +tarantool> <userinput>dofile('arg.lua')</userinput> --- ... -localhost> <userinput>f1('1234')</userinput> +tarantool> <userinput>f1('1234')</userinput> --- - string - 0x31 0x32 0x33 0x34 ... -localhost> <userinput>f1(1234)</userinput> +tarantool> <userinput>f1(1234)</userinput> --- - number - 1234 @@ -190,27 +190,24 @@ localhost> <userinput>f1(1234)</userinput> or is the full <replaceable>library-name.package-name[object-numeric-id]</replaceable>. The following example shows all four forms of object-specifier: <programlisting> -localhost> <userinput>s = box.schema.create_space('name_of_space', {id = 33})</userinput> +tarantool> <userinput>s = box.schema.create_space('name_of_space', {id = 33})</userinput> --- ... -localhost> <userinput>i = s:create_index('name_of_index', {type = 'tree', parts = {1, 'STR'}})</userinput> +tarantool> <userinput>i = s:create_index('name_of_index', {type = 'tree', parts = {0, 'STR'}})</userinput> --- ... -localhost> <userinput>s:insert{'a', 'b', 'c'}</userinput> +tarantool> <userinput>s:insert{'a', 'b', 'c'}</userinput> --- - ['a', 'b', 'c'] ... -localhost> <userinput>box.space.name_of_space:insert{'c', 'd', 'e'}</userinput> +tarantool> <userinput>box.space.name_of_space:insert{'c', 'd', 'e'}</userinput> --- - ['c', 'd', 'e'] ... -localhost> <userinput>box.space['name_of_space']:insert{'x', 'y', 'z'}</userinput> +tarantool> <userinput>box.space['name_of_space']:insert{'x', 'y', 'z'}</userinput> --- - ['x', 'y', 'z'] ... -localhost> <userinput>box.space[33]:drop()</userinput> ---- -... </programlisting> </para> <para> @@ -220,23 +217,26 @@ localhost> <userinput>box.space[33]:drop()</userinput> Similarly, an error which has occurred inside Tarantool (observed on the client as an error code), when it happens during execution of a Lua procedure, produces a genuine Lua error: -<programlisting><computeroutput>localhost> <userinput>function f()error('!') end</userinput> +<programlisting><computeroutput>tarantool> <userinput>function f()error('!') end</userinput> --- ... -localhost> <userinput>f()</userinput> +tarantool> <userinput>f()</userinput> - error: '[string "function f()error(''!'') end"]:1: !' -localhost> <userinput>s:insert{'a'}</userinput> +tarantool> <userinput>s:insert{5}</userinput> --- - error: 'Tuple field 0 type does not match one required by operation: - expected NUM' + expected STR' ... -localhost> <userinput>function insert_without_colon(tuple) s:insert(tuple) end</userinput> +tarantool> <userinput>function insert_without_colon(tuple) s:insert(tuple) end</userinput> --- ... -localhost> <userinput>pcall(insert_without_colon,{'a', 'b', 'c'})</userinput> +tarantool> <userinput>pcall(insert_without_colon,{0, 'b', 'c'})</userinput> --- - false -- 'Tuple field 0 type does not match one required by operation: expected NUM' +- 'Tuple field 0 type does not match one required by operation: expected STR' +tarantool> <userinput>box.space[33]:drop()</userinput> +--- +... </computeroutput></programlisting> </para> @@ -254,15 +254,15 @@ localhost> <userinput>pcall(insert_without_colon,{'a', 'b', 'c'})</userinput> The tonumber64() function is added by Tarantool; the name is global. <bridgehead renderas="sect4">Example</bridgehead> <programlisting> -localhost> <userinput>type(123456789012345), type(tonumber64(123456789012345))</userinput> +tarantool> <userinput>type(123456789012345), type(tonumber64(123456789012345))</userinput> --- - number - cdata ... -localhost> <userinput>i = tonumber64('1000000000')</userinput> +tarantool> <userinput>i = tonumber64('1000000000')</userinput> --- ... -localhost> <userinput>type(i), i / 2, i - 2, i * 2, i + 2, i % 2, i ^ 2</userinput> +tarantool> <userinput>type(i), i / 2, i - 2, i * 2, i + 2, i % 2, i ^ 2</userinput> --- - cdata - 500000000 @@ -323,7 +323,7 @@ localhost> <userinput>type(i), i / 2, i - 2, i * 2, i + 2, i % 2, i ^ 2</userinp </para> <para> A tuple is returned in YAML format like <code>- [120, 'a', 'b', 'c']</code>. - A few functions may return multiple tuples; + A few functions may return multiple tuples. A scalar may be converted to a tuple with only one field. A Lua table may contain all of a tuple's fields except the "key" (the primary-key fields). For more tuple examples see <code xlink:href="#box.tuple">box.tuple</code>. @@ -349,7 +349,7 @@ localhost> <userinput>type(i), i / 2, i - 2, i * 2, i + 2, i % 2, i ^ 2</userinp <row><entry>Number of indexes accessed</entry><entry>Ordinarily only one index is accessed to retrieve one tuple. But to update the tuple, there must be N accesses if the tuple set has N different indexes.</entry></row> - <row><entry>Number of tuples accessed</entry><entry>A few requests, for example select_range, can retrieve + <row><entry>Number of tuples accessed</entry><entry>A few requests, for example select, can retrieve multiple tuples. This factor is usually less important than the others.</entry></row> <row><entry>WAL settings</entry> <entry>The important settings for the write-ahead log are @@ -396,7 +396,7 @@ localhost> <userinput>type(i), i / 2, i - 2, i * 2, i + 2, i % 2, i ^ 2</userinp <tgroup cols="4" align="left" colsep="1" rowsep="1"> <tbody> <row> - <entry>name</entry><entry>effect</entry><entry>type</entry><entry>default</entry> + <entry>NAME</entry><entry>EFFECT</entry><entry>TYPE</entry><entry>DEFAULT</entry> </row> <row> <entry>temporary</entry><entry>space is temporary</entry><entry>true|false</entry><entry>false</entry> @@ -405,13 +405,16 @@ localhost> <userinput>type(i), i / 2, i - 2, i * 2, i + 2, i % 2, i ^ 2</userinp <entry>id</entry><entry>unique identifier</entry><entry>number</entry><entry>last space's id, +1</entry> </row> <row> - <entry>enabled</entry><entry>space is enable</entry><entry>true|false</entry><entry>true</entry> + <entry>enabled</entry><entry>space is enabled</entry><entry>true|false</entry><entry>true</entry> </row> <row> <entry>arity</entry><entry>fixed field count</entry><entry>number</entry><entry>0 i.e. not fixed</entry> </row> <row> - <entry>if_not_exists</entry><entry>error if duplicate</entry><entry>true|false</entry><entry>false</entry> + <entry>if_not_exists</entry><entry>no error if duplicate name</entry><entry>true|false</entry><entry>false</entry> + </row> + <row> + <entry>engine</entry><entry>storage package</entry><entry>string</entry><entry>'memtx'</entry> </row> </tbody> </tgroup> @@ -424,10 +427,10 @@ localhost> <userinput>type(i), i / 2, i - 2, i * 2, i + 2, i % 2, i ^ 2</userinp Possible errors: If a space with the same name already exists. <bridgehead renderas="sect4">Example</bridgehead> <programlisting> -localhost> <userinput>s = box.schema.create_space('space55')</userinput> +tarantool> <userinput>s = box.schema.create_space('space55')</userinput> --- ... -localhost> <userinput>s = box.schema.create_space('space55', {id = 555, temporary = false})</userinput> +tarantool> <userinput>s = box.schema.create_space('space55', {id = 555, temporary = false})</userinput> --- - error: Space 'space55' already exists ... @@ -479,7 +482,7 @@ localhost> <userinput>s = box.schema.create_space('space55', {id = 555, temporar <tgroup cols="4" align="left" colsep="1" rowsep="1"> <tbody> <row> - <entry>name</entry><entry>effect</entry><entry>type</entry><entry>default</entry> + <entry>NAME</entry><entry>EFFECT</entry><entry>TYPE</entry><entry>DEFAULT</entry> </row> <row> <entry>type</entry><entry>type of index</entry><entry>hash|tree|bitset</entry><entry>tree</entry> @@ -504,10 +507,10 @@ localhost> <userinput>s = box.schema.create_space('space55', {id = 555, temporar Possible errors: too many parts. <bridgehead renderas="sect4">Example</bridgehead> <programlisting> -localhost> <userinput>s = box.space.space55</userinput> +tarantool> <userinput>s = box.space.space55</userinput> --- ... -localhost> <userinput>s:create_index('primary', {unique = true, parts = {0, 'NUM', 1, 'STR'}})</userinput> +tarantool> <userinput>s:create_index('primary', {unique = true, parts = {0, 'NUM', 1, 'STR'}})</userinput> --- ... @@ -553,7 +556,7 @@ localhost> <userinput>s:create_index('primary', {unique = true, parts = {0, 'NUM = values to be matched against the index key, which may be multipart. </para> <para> - Returns: (type = tuple) the selected tuple. + Returns: (type = table of tuples) the selected tuple. </para> <para> Complexity Factors: Index size, Index type. @@ -562,23 +565,28 @@ localhost> <userinput>s:create_index('primary', {unique = true, parts = {0, 'NUM Possible Errors: No such space; wrong type. <bridgehead renderas="sect4">Example</bridgehead> <programlisting> -localhost> <userinput>box.space.space0:insert{101, 'test#1', 'my first tuple'}</userinput> +tarantool> <userinput>box.space.space0:insert{101, 'test#1', 'my first tuple'}</userinput> --- - [101, 'test#1', 'my first tuple'] ... -localhost> <userinput>box.space.space0:select{101}</userinput> +tarantool> <userinput>box.space.space0:select{101}</userinput> --- -- [101, 'test#1', 'my first tuple'] +- - [101, 'test#1', 'my first tuple'] ... -localhost> <userinput>box.space.space0:insert{105, 'test#2', 'first_name', 'last_name'}</userinput> +tarantool> <userinput>box.space.space0:insert{105, 'test#2', 'first_name', 'last_name'}</userinput> --- - [105, 'test#2', 'first_name', 'last_name'] ... -localhost> <userinput>box.space.space0:select{105}</userinput> +tarantool> <userinput>table_of_tuples = box.space.space0:select{105}</userinput> +--- +... +tarantool> <userinput>table_of_tuples[1]</userinput> --- - [105, 'test#2', 'first_name', 'last_name'] ... </programlisting> + For examples of complex select()s, which can return multiple tuples + via secondary indexes, see the later section <olink targetptr="box.index.iterator">box.space.space-name.index.index-name]:select</olink>. </para> </listitem> </varlistentry> @@ -606,8 +614,7 @@ localhost> <userinput>box.space.space0:select{105}</userinput> Possible errors: If space-name does not exist. <bridgehead renderas="sect4">Example</bridgehead> <programlisting> ---- -... +tarantool> <userinput>box.space.space_that_does_not_exist_drop()</userinput> </programlisting> </para> </listitem> @@ -633,7 +640,7 @@ localhost> <userinput>box.space.space0:select{105}</userinput> Possible errors: If space-name does not exist. <bridgehead renderas="sect4">Example</bridgehead> <programlisting> -localhost> <userinput>box.space.space55:rename('space56')</userinput> +tarantool> <userinput>box.space.space55:rename('space56')</userinput> --- ... </programlisting> @@ -661,7 +668,7 @@ localhost> <userinput>box.space.space55:rename('space56')</userinput> Possible errors: The first index cannot be changed to {unique = false}. <bridgehead renderas="sect4">Example</bridgehead> <programlisting> -localhost> <userinput>box.space.space55.index.primary:alter({type = 'hash'})</userinput> +tarantool> <userinput>box.space.space55.index.primary:alter({type = 'hash'})</userinput> --- ... </programlisting> @@ -689,7 +696,7 @@ localhost> <userinput>box.space.space55.index.primary:alter({type = 'hash'})</us Possible errors: If index-name doesn't exist. <bridgehead renderas="sect4">Example</bridgehead> <programlisting> -localhost> <userinput>box.space.space55.index.primary:drop()</userinput> +tarantool> <userinput>box.space.space55.index.primary:drop()</userinput> --- ... </programlisting> @@ -717,7 +724,7 @@ localhost> <userinput>box.space.space55.index.primary:drop()</userinput> Possible errors: If index-name doesn't exist. <bridgehead renderas="sect4">Example</bridgehead> <programlisting> -localhost> <userinput>box.space.space55.index.primary:rename('secondary')</userinput> +tarantool> <userinput>box.space.space55.index.primary:rename('secondary')</userinput> --- ... </programlisting> @@ -895,14 +902,14 @@ box.space.space0:update({999}, {{':p', 1, box.pack('ppp', 1, 1, '!')}}) Complexity Factors: Index size, Index type <bridgehead renderas="sect4">Example</bridgehead> <programlisting> -localhost> <userinput>box.space.space0:delete(0)</userinput> +tarantool> <userinput>box.space.space0:delete(0)</userinput> --- - [0, 'My first tuple'] ... -localhost> <userinput>box.space.space0:delete(0)</userinput> +tarantool> <userinput>box.space.space0:delete(0)</userinput> --- ... -localhost> <userinput>box.space.space0:delete('a')</userinput> +tarantool> <userinput>box.space.space0:delete('a')</userinput> - error: 'Supplied key type of part 0 does not match index part type: expected NUM' </programlisting> @@ -951,7 +958,7 @@ localhost> <userinput>box.space.space0:delete('a')</userinput> of type <code xlink:href="#box.index">box.index</code> with methods to search tuples and iterate over them in predefined order. <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>localhost> <userinput>box.space.space0.n,box.space.space0.arity,box.space.space0.index.primary.type</userinput> +<programlisting>tarantool> <userinput>box.space.space0.n,box.space.space0.arity,box.space.space0.index.primary.type</userinput> --- - 1029 - 0 @@ -970,7 +977,7 @@ localhost> <userinput>box.space.space0:delete('a')</userinput> <para> Returns: (type = number) number of tuples in the space. <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>localhost> <userinput>box.space.space0:len()</userinput> +<programlisting>tarantool> <userinput>box.space.space0:len()</userinput> --- - 2 ... @@ -995,10 +1002,10 @@ localhost> <userinput>box.space.space0:delete('a')</userinput> </para> <para> <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>localhost> <userinput>box.space.space0:truncate()</userinput> +<programlisting>tarantool> <userinput>box.space.space0:truncate()</userinput> --- ... -localhost> <userinput>box.space.space0:len()</userinput> +tarantool> <userinput>box.space.space0:len()</userinput> --- - 0 ... @@ -1021,10 +1028,10 @@ localhost> <userinput>box.space.space0:len()</userinput> </para> <bridgehead renderas="sect4">Example</bridgehead> <programlisting> -localhost> <userinput>tmp = ''; for k, v in box.space.space0:pairs() do tmp = tmp .. v[1] end</userinput> +tarantool> <userinput>tmp = ''; for k, v in box.space.space0:pairs() do tmp = tmp .. v[1] end</userinput> --- ... -localhost> <userinput>tmp</userinput> +tarantool> <userinput>tmp</userinput> --- - Hello My Lua world ... @@ -1088,7 +1095,7 @@ end! setopt delimiter=''!</programlisting> Here is what example() returns in a typical installation: <programlisting> -<prompt>localhost></prompt> <userinput>example()</userinput> +<prompt>tarantool></prompt> <userinput>example()</userinput> --- - - 'version 1 6 ' ... @@ -1123,14 +1130,15 @@ end! setopt delimiter=''!</programlisting> Here is what example() returns in a typical installation: <programlisting> -<prompt>localhost></prompt> <userinput>example()</userinput> +<prompt>tarantool></prompt> <userinput>example()</userinput> --- -- - '272 0 _schema ' - - '280 0 _space ' - - '288 0 _index ' - - '512 0 a ' - - '513 3 c ' - - '514 0 d ' +- - '33 0 space0 sophia 0 ' + - '272 1 _schema memtx 0 ' + - '280 1 _space memtx 0 ' + - '288 1 _index memtx 0 ' + - '296 1 _func memtx 0 ' + - '304 1 _user memtx 0 ' + - '312 1 _priv memtx 0 ' ... </programlisting> </para> @@ -1164,19 +1172,49 @@ end! setopt delimiter=''!</programlisting> Here is what example() returns in a typical installation: <programlisting> -<prompt>localhost></prompt> <userinput>example()</userinput> +<prompt>tarantool></prompt> <userinput>example()</userinput> --- - - '272 0 primary tree 1 1 0 str ' - '280 0 primary tree 1 1 0 num ' + - '280 1 owner tree 0 1 1 num ' + - '280 2 name tree 1 1 2 str ' - '288 0 primary tree 1 2 0 num 1 num ' - - '512 0 womba tree 1 1 0 NUM ' - - '512 1 #hash HASH 1 1 0 num ' - - '512 2 #tree TREE 1 1 0 num ' + - '288 2 name tree 1 2 0 num 2 str ' + - '296 0 primary tree 1 1 0 num ' + - '296 1 owner tree 0 1 1 num ' + - '296 2 name tree 1 1 2 str ' + - '304 0 primary tree 1 1 0 num ' + - '304 2 name tree 1 1 2 str ' + - '312 0 primary tree 1 3 1 num 2 str 3 num ' + - '312 1 owner tree 0 1 1 num ' +... </programlisting> </para> </listitem> </varlistentry> + <varlistentry> + <term> + <emphasis role="lua">box.space._user</emphasis> + </term> + <listitem> + <para> + _user is a new system tuple set for support of the authorization feature. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term> + <emphasis role="lua">box.space._priv</emphasis> + </term> + <listitem> + <para> + _priv is a new system tuple set for support of the authorization feature. + </para> + </listitem> + </varlistentry> + </variablelist> <bridgehead renderas="sect4">Example showing use of the box.space functions</bridgehead> @@ -1219,14 +1257,16 @@ setopt delimiter=''! <para> ... And here is what happens when one invokes the function: <programlisting> -<prompt>localhost></prompt> <userinput>example()</userinput> +<prompt>tarantool></prompt> <userinput>example()</userinput> --- -- - _schema tuple_count =0 - - _space tuple_count =6. first field in first tuple = 272 - - _index tuple_count =5. first field in first tuple = 272 - - space2 tuple_count =0 - - space1 tuple_count =0 +- - space1 tuple_count =0 - space0 tuple_count =3. first field in first tuple = 1 + - _schema tuple_count =1. first field in first tuple = version + - _space tuple_count =7. first field in first tuple = 33 + - _index tuple_count =13. first field in first tuple = 272 + - _func tuple_count =0 + - _user tuple_count =2. first field in first tuple = 0 + - _priv tuple_count =0 ... </programlisting> </para> @@ -1329,27 +1369,27 @@ setopt delimiter=''! <para> <bridgehead renderas="sect4">Example</bridgehead> <programlisting> -localhost> <userinput>box.space.space0:insert{0, 'hello world'}</userinput> +tarantool> <userinput>box.space.space0:insert{0, 'hello world'}</userinput> --- - [0, 'hello world'] ... -localhost> <userinput>box.space.space0:update({0}, {{'=p', 1, 'bye world'}})</userinput> +tarantool> <userinput>box.space.space0:update({0}, {{'=p', 1, 'bye world'}})</userinput> --- - [0, 'bye world'] ... -localhost> <userinput>box.space.space0:update({0}, {{'=p', 1, box.pack('ppp', 0, 3, 'hello')}})</userinput> +tarantool> <userinput>box.space.space0:update({0}, {{'=p', 1, box.pack('ppp', 0, 3, 'hello')}})</userinput> --- - [0, !!binary AAOlaGVsbG8=] ... -localhost> <userinput>box.space.space0:update({0}, {{'=p', 1, 4}})</userinput> +tarantool> <userinput>box.space.space0:update({0}, {{'=p', 1, 4}})</userinput> --- - [0, 4] ... -localhost> <userinput>box.space.space0:update({0}, {{'+p', 1, 4}})</userinput> +tarantool> <userinput>box.space.space0:update({0}, {{'+p', 1, 4}})</userinput> --- - [0, 8] ... -localhost> <userinput>box.space.space0:update({0}, {{'^p', 1, 4}})</userinput> +tarantool> <userinput>box.space.space0:update({0}, {{'^p', 1, 4}})</userinput> --- - [0, 12] ... @@ -1372,40 +1412,40 @@ localhost> <userinput>box.space.space0:update({0}, {{'^p', 1, 4}})</userinput> </para> <para> <bridgehead renderas="sect4">Example</bridgehead> -<programlisting><prompt>localhost></prompt> <userinput>setopt delimiter='!' #this means following commands must end with '!'</userinput> -<prompt>localhost></prompt> <userinput>tuple = box.space.space0:replace{0}!</userinput> +<programlisting><prompt>tarantool></prompt> <userinput>setopt delimiter='!' #this means following commands must end with '!'</userinput> +<prompt>tarantool></prompt> <userinput>tuple = box.space.space0:replace{0}!</userinput> --- ... -<prompt>localhost></prompt> <userinput>string.len(tuple[0])!</userinput> +<prompt>tarantool></prompt> <userinput>string.len(tuple[0])!</userinput> --- - 1 ... -<prompt>localhost></prompt> <userinput>box.unpack('b', tuple[0])!</userinput> +<prompt>tarantool></prompt> <userinput>box.unpack('b', tuple[0])!</userinput> --- - 48 ... -<prompt>localhost></prompt> <userinput>box.unpack('bsi', box.pack('bsi', 255, 65535, 4294967295))!</userinput> +<prompt>tarantool></prompt> <userinput>box.unpack('bsi', box.pack('bsi', 255, 65535, 4294967295))!</userinput> --- - 255 - 65535 - 4294967295 ... -<prompt>localhost></prompt> <userinput>box.unpack('ls', box.pack('ls', tonumber64('18446744073709551615'), 65535))!</userinput> +<prompt>tarantool></prompt> <userinput>box.unpack('ls', box.pack('ls', tonumber64('18446744073709551615'), 65535))!</userinput> --- - 18446744073709551615 - 65535 ... -<prompt>localhost></prompt> <userinput>num, str, num64 = box.unpack('spl', box.pack('spl', 666, 'string',</userinput> +<prompt>tarantool></prompt> <userinput>num, str, num64 = box.unpack('spl', box.pack('spl', 666, 'string',</userinput> <prompt> -></prompt> <userinput> tonumber64('666666666666666')))!</userinput> --- ... -<prompt>localhost></prompt> <userinput>num, str, num64!</userinput> +<prompt>tarantool></prompt> <userinput>num, str, num64!</userinput> --- - 666 - string - 666666666666666 ... -<prompt>localhost></prompt> <userinput>setopt delimiter='' #back to normal: commands end with line feed!</userinput> +<prompt>tarantool></prompt> <userinput>setopt delimiter='' #back to normal: commands end with line feed!</userinput> </programlisting> </para> </listitem> @@ -1437,21 +1477,21 @@ localhost> <userinput>box.space.space0:update({0}, {{'^p', 1, 4}})</userinput> <para> <bridgehead renderas="sect4">Example</bridgehead> <programlisting> -localhost> <userinput>box.dostring('abc')</userinput> +tarantool> <userinput>box.dostring('abc')</userinput> --- error: '[string "abc"]:1: ''='' expected near ''<eof>''' ... -localhost> <userinput>box.dostring('return 1')</userinput> +tarantool> <userinput>box.dostring('return 1')</userinput> --- - 1 ... -localhost> <userinput>box.dostring('return ...', 'hello', 'world')</userinput> +tarantool> <userinput>box.dostring('return ...', 'hello', 'world')</userinput> --- - hello - world ... -localhost> <userinput>setopt delimiter='!' #<link linkend="utility-tarantool-setopt">this</link> means ignore line feeds until next '!'</userinput> -localhost> <userinput>box.dostring('local f = function(key)</userinput> +tarantool> <userinput>setopt delimiter='!' #<link linkend="utility-tarantool-setopt">this</link> means ignore line feeds until next '!'</userinput> +tarantool> <userinput>box.dostring('local f = function(key)</userinput> -> <userinput> t = box.space.space0:select(key);</userinput> -> <userinput> if t ~= nil then return t[0] else return nil end</userinput> -> <userinput> end</userinput> @@ -1459,7 +1499,7 @@ localhost> <userinput>box.dostring('local f = function(key)</userinput> --- - nil ... -localhost> <userinput>setopt delimiter=''!</userinput> +tarantool> <userinput>setopt delimiter=''!</userinput> </programlisting> </para> </listitem> @@ -1476,7 +1516,7 @@ localhost> <userinput>setopt delimiter=''!</userinput> but still useful for constructing artificial tuple keys. <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>localhost> <userinput>box.time(), box.time()</userinput> +<programlisting>tarantool> <userinput>box.time(), box.time()</userinput> --- - 1385758759.2591 - 1385758759.2591 @@ -1494,7 +1534,7 @@ localhost> <userinput>setopt delimiter=''!</userinput> Returns: current system time (in microseconds since the epoch) as a 64-bit integer. The time is taken from the event loop clock. <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>localhost> <userinput>box.time(), box.time64()</userinput> +<programlisting>tarantool> <userinput>box.time(), box.time64()</userinput> --- - 1385758828.9825 - 1385758828982485 @@ -1516,7 +1556,7 @@ localhost> <userinput>setopt delimiter=''!</userinput> when it starts. If the library is not available, which can happen if it was not found when the server was built from source, then box.uuid() returns an error. <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>localhost> <userinput>box.uuid() == box.uuid() -- Comment: == means "are they equal?"</userinput> +<programlisting>tarantool> <userinput>box.uuid() == box.uuid() -- Comment: == means "are they equal?"</userinput> --- - false ... @@ -1534,7 +1574,7 @@ localhost> <userinput>setopt delimiter=''!</userinput> unique id, as a string. </para> <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>localhost> <userinput>box.uuid_hex()</userinput> +<programlisting>tarantool> <userinput>box.uuid_hex()</userinput> --- - b8eadcb078b54bed8fa8425d129b10e8 ... @@ -1572,7 +1612,7 @@ localhost> <userinput>setopt delimiter=''!</userinput> Possible errors: whatever is specified in errcode-number. </para> <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>localhost> <userinput>box.raise(box.error.ER_WAL_IO, 'WAL I/O error')</userinput> +<programlisting>tarantool> <userinput>box.raise(box.error.ER_WAL_IO, 'WAL I/O error')</userinput> --- - error: 'WAL I/O error' ... @@ -1605,11 +1645,11 @@ localhost> <userinput>setopt delimiter=''!</userinput> Possible errors: index has wrong type or primary-key indexed field is not a number. </para> <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>localhost> <userinput>box.space.space0:auto_increment{'Fld#1', 'Fld#2'}</userinput> +<programlisting>tarantool> <userinput>box.space.space0:auto_increment{'Fld#1', 'Fld#2'}</userinput> --- - [1, 'Fld#1', 'Fld#2'] ... -localhost> <userinput>box.space.space0:auto_increment{'Fld#3'}</userinput> +tarantool> <userinput>box.space.space0:auto_increment{'Fld#3'}</userinput> --- - [2, 'Fld#3'] ... @@ -1637,11 +1677,11 @@ localhost> <userinput>box.space.space0:auto_increment{'Fld#3'}</userinput> Complexity Factors: Index size, Index type, WAL settings. </para> <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>localhost> <userinput>box.counter.inc(box.space.space0.n, {'top.mail.ru'})</userinput> +<programlisting>tarantool> <userinput>box.counter.inc(box.space.space0.n, {'top.mail.ru'})</userinput> --- - 1 ... -localhost> <userinput>box.counter.inc(box.space.space0.n, {'top.mail.ru'})</userinput> +tarantool> <userinput>box.counter.inc(box.space.space0.n, {'top.mail.ru'})</userinput> --- - 2 ...</programlisting> @@ -1669,11 +1709,11 @@ localhost> <userinput>box.counter.inc(box.space.space0.n, {'top.mail.ru'})</user Complexity Factors: Index size, Index type, WAL settings. </para> <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>localhost> <userinput>box.counter.dec(box.space.space0.n, {'top.mail.ru'})</userinput> +<programlisting>tarantool> <userinput>box.counter.dec(box.space.space0.n, {'top.mail.ru'})</userinput> --- - 1 ... -localhost> <userinput>box.counter.dec(box.space.space0.n, {'top.mail.ru'})</userinput> +tarantool> <userinput>box.counter.dec(box.space.space0.n, {'top.mail.ru'})</userinput> --- - 0 ...</programlisting> @@ -1685,7 +1725,7 @@ localhost> <userinput>box.counter.dec(box.space.space0.n, {'top.mail.ru'})</user <para xml:id="box-function-example" xreflabel="box-function-example"> This example will work with the sandbox configuration described in the preface. That is, there is a space named space0 with a numeric primary key. -The example function will: (1) select the tuple whose key value is 1000; +The example function will: (1) select a tuple the tuple whose key value is 1000; (2) return an error if the tuple already exists and already has 3 fields; (3) Insert or replace the tuple with: field[0] = 1000, field[1] = a uuid, field[2] = number of seconds since 1970-01-01; (4) Get field[2] from what was replaced; @@ -1699,11 +1739,13 @@ and <link xlink:href="http://www.lua.org/pil/20.html">string.sub()</link>. <programlisting> setopt delimiter='!' function example() - local a, b, c, selected_tuple, replaced_tuple, time_field - selected_tuple = box.space.space0:select(1000) - if selected_tuple ~= nil then - if #selected_tuple == 3 then - box.raise(1, 'This tuple already has 3 fields') + local a, b, c, table_of_selected_tuples, replaced_tuple, time_field + table_of_selected_tuples = box.space.space0:select(1000) + if table_of_selected_tuples ~= nil then + if table_of_selected_tuples[1] ~= nil then + if #table_of_selected_tuples[1] == 3 then + box.raise(1, 'This tuple already has 3 fields') + end end end replaced_tuple = box.space.space0:replace @@ -1720,15 +1762,15 @@ setopt delimiter=''! <para> ... And here is what happens when one invokes the function: <programlisting> -<prompt>localhost></prompt> <userinput>box.space.space0:delete(1000)</userinput> +<prompt>tarantool></prompt> <userinput>box.space.space0:delete(1000)</userinput> --- - 1000: {'264ee2da03634f24972be76c43808254', '1391037015.6809'} ... -<prompt>localhost></prompt> <userinput>example(1000)</userinput> +<prompt>tarantool></prompt> <userinput>example(1000)</userinput> --- - 2014-01-29 16:11:51.1582 ... -<prompt>localhost></prompt> <userinput>example(1000)</userinput> +<prompt>tarantool></prompt> <userinput>example(1000)</userinput> --- - error: 'This tuple already has 3 fields' ... @@ -1764,17 +1806,17 @@ setopt delimiter=''! Returns: (type = tuple) a new tuple. </para> <para> - In the following example, x and t will be new tuple objects. + In the following example, x will be a new table object containing one tuple and t will be a new tuple object. Saying <code>t</code> returns the entire tuple t. </para> <bridgehead renderas="sect4">Example</bridgehead> - <programlisting>localhost> <userinput>x = box.space.space0:insert{33,tonumber('1'),tonumber64('2')}:totable()</userinput> + <programlisting>tarantool> <userinput>x = box.space.space0:insert{33,tonumber('1'),tonumber64('2')}:totable()</userinput> --- ... -localhost> <userinput>t = box.tuple.new({'abc', 'def', 'ghi', 'abc'})</userinput> +tarantool> <userinput>t = box.tuple.new({'abc', 'def', 'ghi', 'abc'})</userinput> --- ... -localhost> <userinput>t</userinput> +tarantool> <userinput>t</userinput> --- - ['abc', 'def', 'ghi', 'abc'] ...</programlisting> @@ -1799,10 +1841,10 @@ localhost> <userinput>t</userinput> and then the number of fields in t is returned. </para> <bridgehead renderas="sect4">Example</bridgehead> - <programlisting>localhost> <userinput>t = box.tuple.new({'Fld#1','Fld#2','Fld#3','Fld#4'})</userinput> + <programlisting>tarantool> <userinput>t = box.tuple.new({'Fld#1','Fld#2','Fld#3','Fld#4'})</userinput> --- ... -localhost> <userinput>#t</userinput> +tarantool> <userinput>#t</userinput> --- - 4 ...</programlisting> @@ -1832,10 +1874,10 @@ localhost> <userinput>#t</userinput> and a bit for overhead, so bsize() returns 3*(1+3)+1. </para> <bridgehead renderas="sect4">Example</bridgehead> - <programlisting>localhost> <userinput>t = box.tuple.new({'aaa','bbb','ccc'})</userinput> + <programlisting>tarantool> <userinput>t = box.tuple.new({'aaa','bbb','ccc'})</userinput> --- ... -localhost> <userinput>t:bsize()</userinput> +tarantool> <userinput>t:bsize()</userinput> --- - 13 ...</programlisting> @@ -1859,10 +1901,10 @@ localhost> <userinput>t:bsize()</userinput> and then the second field in t is returned. </para> <bridgehead renderas="sect4">Example</bridgehead> - <programlisting>localhost> <userinput>t = box.tuple.new({'Fld#1','Fld#2','Fld#3','Fld#4'})</userinput> + <programlisting>tarantool> <userinput>t = box.tuple.new({'Fld#1','Fld#2','Fld#3','Fld#4'})</userinput> --- ... -localhost> <userinput>t[1]</userinput> +tarantool> <userinput>t[1]</userinput> --- - Fld#2 ...</programlisting> @@ -1893,19 +1935,19 @@ localhost> <userinput>t[1]</userinput> are returned. </para> <bridgehead renderas="sect4">Example</bridgehead> - <programlisting>localhost> <userinput>t = box.tuple.new({'a','b','c','a'})</userinput> + <programlisting>tarantool> <userinput>t = box.tuple.new({'a','b','c','a'})</userinput> --- ... -localhost> <userinput>t:find('a')</userinput> +tarantool> <userinput>t:find('a')</userinput> --- - 0 ... -localhost> <userinput>t:findall('a')</userinput> +tarantool> <userinput>t:findall('a')</userinput> --- - 0 - 3 ... -localhost> <userinput>t:findall(1, 'a')</userinput> +tarantool> <userinput>t:findall(1, 'a')</userinput> --- - 3 ...</programlisting> @@ -1934,10 +1976,10 @@ localhost> <userinput>t:findall(1, 'a')</userinput> but one new one is added, then the result is returned. </para> <bridgehead renderas="sect4">Example</bridgehead> - <programlisting>localhost> <userinput>t = box.tuple.new({'Fld#1','Fld#2','Fld#3','Fld#4','Fld#5'})</userinput> + <programlisting>tarantool> <userinput>t = box.tuple.new({'Fld#1','Fld#2','Fld#3','Fld#4','Fld#5'})</userinput> --- ... -localhost> <userinput>t:transform(1,2,'x')</userinput> +tarantool> <userinput>t:transform(1,2,'x')</userinput> --- - ['Fld#1', 'x', 'Fld#4', 'Fld#5'] ...</programlisting> @@ -1966,10 +2008,10 @@ localhost> <userinput>t:transform(1,2,'x')</userinput> Returns: (type = scalar) one or more field values. </para> <bridgehead renderas="sect4">Example</bridgehead> - <programlisting>localhost> <userinput>t = box.tuple.new({'Fld#1','Fld#2','Fld#3','Fld#4','Fld#5'})</userinput> + <programlisting>tarantool> <userinput>t = box.tuple.new({'Fld#1','Fld#2','Fld#3','Fld#4','Fld#5'})</userinput> --- ... -localhost> <userinput>t:slice(1, 3)</userinput> +tarantool> <userinput>t:slice(1, 3)</userinput> --- - Fld#2 - Fld#3 @@ -1994,10 +2036,10 @@ localhost> <userinput>t:slice(1, 3)</userinput> then the result is returned. </para> <bridgehead renderas="sect4">Example</bridgehead> - <programlisting>localhost> <userinput>t = box.tuple.new({'Fld#1','Fld#2','Fld#3','Fld#4','Fld#5'})</userinput> + <programlisting>tarantool> <userinput>t = box.tuple.new({'Fld#1','Fld#2','Fld#3','Fld#4','Fld#5'})</userinput> --- ... -localhost> <userinput>t:unpack()</userinput> +tarantool> <userinput>t:unpack()</userinput> --- - Fld#1 - Fld#2 @@ -2026,13 +2068,13 @@ localhost> <userinput>t:unpack()</userinput> and then all its fields are selected using a Lua for-end loop. </para> <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>localhost> <userinput>t = box.tuple.new({'Fld#1','Fld#2','Fld#3','Fld#4','Fld#5'})</userinput> +<programlisting>tarantool> <userinput>t = box.tuple.new({'Fld#1','Fld#2','Fld#3','Fld#4','Fld#5'})</userinput> --- ... -localhost> <userinput>tmp = ''; for k, v in t:pairs() do tmp = tmp .. v end</userinput> +tarantool> <userinput>tmp = ''; for k, v in t:pairs() do tmp = tmp .. v end</userinput> --- ... -localhost> <userinput>tmp</userinput> +tarantool> <userinput>tmp</userinput> --- - Fld#1Fld#2Fld#3Fld#4Fld#5 ...</programlisting> @@ -2073,7 +2115,7 @@ setopt delimiter=''! <para> ... And here is what happens when one invokes the function: <programlisting> -<prompt>localhost></prompt> <userinput>example()</userinput> +<prompt>tarantool></prompt> <userinput>example()</userinput> --- - 'tuple2 = ' - ['a', 'c'] @@ -2109,23 +2151,23 @@ setopt delimiter=''! Returns: (type = string) the original value reformatted as a JSON string. </para> <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>localhost> <userinput>box.cjson.encode(123)</userinput> +<programlisting>tarantool> <userinput>box.cjson.encode(123)</userinput> --- - '123' ... -localhost> <userinput>box.cjson.encode({123})</userinput> +tarantool> <userinput>box.cjson.encode({123})</userinput> --- - '[123]' ... -localhost> <userinput>box.cjson.encode({123, 234, 345})</userinput> +tarantool> <userinput>box.cjson.encode({123, 234, 345})</userinput> --- - '[123,234,345]' ... -localhost> <userinput>box.cjson.encode({abc = 234, cde = 345})</userinput> +tarantool> <userinput>box.cjson.encode({abc = 234, cde = 345})</userinput> --- - '{"cde":345,"abc":234}' ... -localhost> <userinput>box.cjson.encode({hello = {'world'}})</userinput> +tarantool> <userinput>box.cjson.encode({hello = {'world'}})</userinput> --- - '{"hello":["world"]}' ... @@ -2145,15 +2187,15 @@ localhost> <userinput>box.cjson.encode({hello = {'world'}})</userinput> Returns: (type = Lua table) the original contents formatted as a Lua table. </para> <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>localhost> <userinput>box.cjson.decode('123')</userinput> +<programlisting>tarantool> <userinput>box.cjson.decode('123')</userinput> --- - 123 ... -localhost> <userinput>box.cjson.decode('[123, "hello"]')[2]</userinput> +tarantool> <userinput>box.cjson.decode('[123, "hello"]')[2]</userinput> --- - hello ... -localhost> <userinput>box.cjson.decode('{"hello": "world"}').hello</userinput> +tarantool> <userinput>box.cjson.decode('{"hello": "world"}').hello</userinput> --- - world ... @@ -2222,7 +2264,7 @@ localhost> <userinput>box.cjson.decode('{"hello": "world"}').hello</userinput <varlistentry> <term></term> <listitem><bridgehead renderas="sect4">Example</bridgehead> -<programlisting>localhost> <userinput>box.space.space0.index.primary</userinput> +<programlisting>tarantool> <userinput>box.space.space0.index.primary</userinput> --- - unique: true idx: ' index 0' @@ -2236,7 +2278,7 @@ localhost> <userinput>box.cjson.decode('{"hello": "world"}').hello</userinput id: 0 ... -localhost> <userinput>box.space.space0.index.primary.idx:max()</userinput> +tarantool> <userinput>box.space.space0.index.primary.idx:max()</userinput> --- - [ 999, 2, 'c'] ...</programlisting></listitem> @@ -2244,7 +2286,7 @@ localhost> <userinput>box.space.space0.index.primary.idx:max()</userinput> <varlistentry> <term> - <emphasis role="lua" xml:id="box.index.iterator" xreflabel="box.index.iterator(type, ...)"> + <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> </term> <listitem> @@ -2301,52 +2343,53 @@ localhost> <userinput>box.space.space0.index.primary.idx:max()</userinput> <para> <bridgehead renderas="sect4">Examples</bridgehead> <programlisting> -localhost> <userinput>s = box.schema.create_space('space17')</userinput> +# This example is not currently working. Use index select function instead. +tarantool> <userinput>s = box.schema.create_space('space17')</userinput> --- ... -localhost> <userinput>s:create_index('primary', {unique = true, parts = {0, 'STR', 1, 'STR'}})</userinput> +tarantool> <userinput>s:create_index('primary', {unique = true, parts = {0, 'STR', 1, 'STR'}})</userinput> --- ... -localhost> <userinput>s:insert{'C', 'C'}</userinput> +tarantool> <userinput>s:insert{'C', 'C'}</userinput> --- - ['C', 'C'] ... -localhost> <userinput>s:insert{'B', 'A'}</userinput> +tarantool> <userinput>s:insert{'B', 'A'}</userinput> --- - ['B', 'A'] ... -localhost> <userinput>s:insert{'C', '!'}</userinput> +tarantool> <userinput>s:insert{'C', '!'}</userinput> --- - ['C', '!'] ... -localhost> <userinput>s:insert{'A', 'C'}</userinput> +tarantool> <userinput>s:insert{'A', 'C'}</userinput> --- - ['A', 'C'] ... -localhost> <userinput>iterator_function = s.index.primary:iterator(box.index.GE, 'A')</userinput> +tarantool> <userinput>iterator_function = s.index.primary:iterator(box.index.GE, 'A')</userinput> --- ... -localhost> <userinput>iterator_function()</userinput> +tarantool> <userinput>iterator_function()</userinput> --- - ['A', 'C'] ... -localhost> <userinput>iterator_function()</userinput> +tarantool> <userinput>iterator_function()</userinput> --- - ['B', 'A'] ... -localhost> <userinput>iterator_function()</userinput> +tarantool> <userinput>iterator_function()</userinput> --- - ['C', '!'] ... -localhost> <userinput>iterator_function()</userinput> +tarantool> <userinput>iterator_function()</userinput> --- - ['C', 'C'] ... -localhost> <userinput>iterator_function()</userinput> +tarantool> <userinput>iterator_function()</userinput> --- - null ... -localhost> <userinput>box.space.space17:drop()</userinput> +tarantool> <userinput>box.space.space17:drop()</userinput> --- ... </programlisting> @@ -2354,7 +2397,48 @@ localhost> <userinput>box.space.space17:drop()</userinput> </listitem> </varlistentry> - + <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> + </term> + <listitem> + <para> + This is is an alternative to <olink targetptr="box.select">box.select()</olink> + which goes via a particular index and can make use of additional parameters that + specify the iterator type, and the limit (that is, the maximum number of tuples to + return). + </para> + <para> + Returns: (type = table of tuples) the tuple or tuples that match the field values. + </para> + <para> + <bridgehead renderas="sect4">Example</bridgehead> +<programlisting> +# Create a space named space0. +# Create a unique index 'primary', which won't be needed for this example. +# Create a non-unique index 'secondary' with an index on the second field. +# Insert three tuples, values in field[1] equal to 'X', 'Y', and 'Z'. +# Select all tuples where the secondary index keys are greater than 'X'. +box.schema.create_space('space0') +box.space.space0:create_index('primary', {parts = {0, 'NUM' }}) +box.space.space0:create_index('secondary', {type = 'tree', unique = false, parts = {1, 'STR'}}) +box.space.space0:insert{1,'X','Row with field[1]=X'} +box.space.space0:insert{2,'Y','Row with field[1]=Y'} +box.space.space0:insert{3,'Z','Row with field[1]=Z'} +box.space.space0.index.secondary:select({'X'}, {iterator = 'GT'}) +</programlisting> +The result will be a table of tuples and will look like this: +<programlisting> +--- +- - [2, 'Y', 'Row with field[1]=Y'] + - [3, 'Z', 'Row with field[1]=Z'] +... +</programlisting> + </para> + </listitem> + </varlistentry> + <varlistentry> <term> <emphasis role="lua">box.space.<replaceable>space-name</replaceable>.index.<replaceable>index-name</replaceable>:min([key])</emphasis> @@ -2374,7 +2458,7 @@ localhost> <userinput>box.space.space17:drop()</userinput> </para> <para> <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>localhost> <userinput>box.space0.index.primary:min()</userinput> +<programlisting>tarantool> <userinput>box.space.space0.index.primary:min()</userinput> --- - ['Alpha!', 55, 'This is the first tuple!'] ... @@ -2402,7 +2486,7 @@ localhost> <userinput>box.space.space17:drop()</userinput> </para> <para> <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>localhost> <userinput>box.space.space0.index.primary:max()</userinput> +<programlisting>tarantool> <userinput>box.space.space0.index.primary:max()</userinput> --- - ['Gamma!', 55, 'This is the third tuple!'] ... @@ -2433,7 +2517,7 @@ localhost> <userinput>box.space.space17:drop()</userinput> </para> <para> <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>localhost> <userinput>box.space.space0.index.secondary:random(1)</userinput> +<programlisting>tarantool> <userinput>box.space.space0.index.secondary:random(1)</userinput> --- - ['Beta!', 66, 'This is the second tuple!'] ... @@ -2461,12 +2545,12 @@ localhost> <userinput>box.space.space17:drop()</userinput> </para> <para> <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>localhost> <userinput>box.space.space0.index.primary:count(999)</userinput> +<programlisting>tarantool> <userinput>box.space.space0.index.primary:count(999)</userinput> --- - 0 ... </programlisting> -<programlisting>localhost> <userinput>box.space.space0.index.primary:count('Alpha!', { iterator = 'LE' })</userinput> +<programlisting>tarantool> <userinput>box.space.space0.index.primary:count('Alpha!', { iterator = 'LE' })</userinput> --- - 1 ... @@ -2740,8 +2824,8 @@ This function contains an infinite loop Each iteration of the loop adds 1 to a global variable named gvar, then goes to sleep for 2 seconds. The sleep causes an implicit box.fiber.yield().<programlisting> -<prompt>localhost></prompt><userinput> setopt delimiter = '!'</userinput> -<prompt>localhost></prompt><userinput> function function_x()</userinput> +<prompt>tarantool></prompt><userinput> setopt delimiter = '!'</userinput> +<prompt>tarantool></prompt><userinput> function function_x()</userinput> <prompt> -></prompt><userinput> gvar = 0</userinput> <prompt> -></prompt><userinput> while 0 == 0 do</userinput> <prompt> -></prompt><userinput> gvar = gvar + 1</userinput> @@ -2750,17 +2834,17 @@ The sleep causes an implicit box.fiber.yield().<programlisting> <prompt> -></prompt><userinput> end!</userinput> --- ... -<prompt>localhost></prompt><userinput> setopt delimiter = ''!</userinput></programlisting> +<prompt>tarantool></prompt><userinput> setopt delimiter = ''!</userinput></programlisting> Make a fiber, associate function_x with the fiber, and start function_x. It will immediately "detach" so it will be running independently of the caller. <programlisting> -<prompt>localhost></prompt><userinput> fiber_of_x = box.fiber.wrap(function_x)</userinput> +<prompt>tarantool></prompt><userinput> fiber_of_x = box.fiber.wrap(function_x)</userinput> --- ...</programlisting> Get the id of the fiber (fid), to be used in later displays.<programlisting> -<prompt>localhost></prompt><userinput> fid = box.fiber.wrap(function_x)</userinput> +<prompt>tarantool></prompt><userinput> fid = box.fiber.wrap(function_x)</userinput> --- ... </programlisting> @@ -2768,7 +2852,7 @@ Pause for a while, while the detached function runs. Then ... Display the fiber id, the fiber status, and gvar (gvar will have gone up a bit depending how long the pause lasted). The status is suspended because the fiber spends almost all its time sleeping or yielding.<programlisting> -<prompt>localhost></prompt><userinput> '#',fid,'. ',box.fiber.status(fiber_of_x),'. gvar=',gvar</userinput> +<prompt>tarantool></prompt><userinput> '#',fid,'. ',box.fiber.status(fiber_of_x),'. gvar=',gvar</userinput> --- - '#' - 'userdata: 0x4133d340' @@ -2783,10 +2867,10 @@ Cancel the fiber. Then, once again ... Display the fiber id, the fiber status, and gvar (gvar will have gone up a bit more depending how long the pause lasted). This time the status is dead because the cancel worked.<programlisting> -<prompt>localhost></prompt><userinput> box.fiber.cancel(fiber_of_x)</userinput> +<prompt>tarantool></prompt><userinput> box.fiber.cancel(fiber_of_x)</userinput> --- ... -<prompt>localhost></prompt><userinput> '#',fid,'. ',box.fiber.status(fiber_of_x),'. gvar=',gvar</userinput> +<prompt>tarantool></prompt><userinput> '#',fid,'. ',box.fiber.status(fiber_of_x),'. gvar=',gvar</userinput> --- - '#' - 'userdata: 0x4133d340' @@ -2870,24 +2954,24 @@ the status is dead because the cancel worked.<programlisting> <para> <bridgehead renderas="sect4">Example</bridgehead><programlisting> -<prompt>localhost></prompt><userinput> box.session.peer(box.session.id())</userinput> +<prompt>tarantool></prompt><userinput> box.session.peer(box.session.id())</userinput> --- - 127.0.0.1:45129 ... -<prompt>localhost></prompt><userinput> box.session.storage.random_memorandum = "Don't forget the eggs."</userinput> +<prompt>tarantool></prompt><userinput> box.session.storage.random_memorandum = "Don't forget the eggs."</userinput> --- ... -<prompt>localhost></prompt><userinput> box.session.storage.radius_of_mars = 3396</userinput> +<prompt>tarantool></prompt><userinput> box.session.storage.radius_of_mars = 3396</userinput> --- ... -<prompt>localhost></prompt><userinput> m = ''</userinput> +<prompt>tarantool></prompt><userinput> m = ''</userinput> --- ... -<prompt>localhost></prompt><userinput> for k, v in pairs(box.session.storage) do m = m .. k .. '=' .. v .. ' ' end</userinput> +<prompt>tarantool></prompt><userinput> for k, v in pairs(box.session.storage) do m = m .. k .. '=' .. v .. ' ' end</userinput> --- ... -<prompt>localhost></prompt><userinput> m</userinput> +<prompt>tarantool></prompt><userinput> m</userinput> --- - 'radius_of_mars=3396 random_memorandum=Don''t forget the eggs. ' ...</programlisting> @@ -3463,31 +3547,31 @@ end This is not a useful way to communicate with this particular site, but shows that the system works. <programlisting> -<prompt>localhost></prompt> <userinput>sock = box.socket.tcp()</userinput> +<prompt>tarantool></prompt> <userinput>sock = box.socket.tcp()</userinput> --- ... -<prompt>localhost></prompt> <userinput>type(sock)</userinput> +<prompt>tarantool></prompt> <userinput>type(sock)</userinput> --- - userdata ... -<prompt>localhost></prompt> <userinput>sock:connect('mail.ru', 80)</userinput> +<prompt>tarantool></prompt> <userinput>sock:connect('mail.ru', 80)</userinput> --- - fd 22, aka 192.168.1.72:49488, peer of 94.100.180.199:80 ... -<prompt>localhost></prompt> <userinput>sock:error()</userinput> +<prompt>tarantool></prompt> <userinput>sock:error()</userinput> --- - 0 - Success ... -<prompt>localhost></prompt> <userinput>sock:send('GET / HTTP/1.0\n\n')</userinput> +<prompt>tarantool></prompt> <userinput>sock:send('GET / HTTP/1.0\n\n')</userinput> --- - 16 ... -<prompt>localhost></prompt> <userinput>sock:recv(17)</userinput> +<prompt>tarantool></prompt> <userinput>sock:recv(17)</userinput> --- - "HTTP/1.0 200 OK\r\n" ... - <prompt>localhost></prompt> <userinput>sock:close()</userinput> + <prompt>tarantool></prompt> <userinput>sock:close()</userinput> --- ... </programlisting> @@ -3712,11 +3796,11 @@ end Assume that the database is nearly empty. Assume that the tarantool server is running on localhost 127.0.0.1:3301. <programlisting> -<prompt>localhost></prompt><userinput> ta = {}</userinput> +<prompt>tarantool></prompt><userinput> ta = {}</userinput> --- ... -<prompt>localhost></prompt><userinput> setopt delimiter = '!'</userinput> -<prompt>localhost></prompt><userinput> function example()</userinput> +<prompt>tarantool></prompt><userinput> setopt 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> @@ -3747,11 +3831,11 @@ end <prompt> -></prompt><userinput> end!</userinput> --- ... -<prompt>localhost></prompt><userinput> setopt delimiter = ''!</userinput> -<prompt>localhost></prompt><userinput> example()</userinput> +<prompt>tarantool></prompt><userinput> setopt delimiter = ''!</userinput> +<prompt>tarantool></prompt><userinput> example()</userinput> --- ... -<prompt>localhost></prompt><userinput> ta</userinput> +<prompt>tarantool></prompt><userinput> ta</userinput> --- - - self:ping() succeeded - ' (no surprise -- self connection is pre-established)' @@ -3766,7 +3850,7 @@ end - conn:update done on space0 - conn:close done ... -<prompt>localhost></prompt><userinput> box.space.space0:select(800) -- Prove that the update succeeded.</userinput> +<prompt>tarantool></prompt><userinput> box.space.space0:select(800) -- Prove that the update succeeded.</userinput> --- - [800, 'Fld#1', 'Extra data'] ... @@ -3788,7 +3872,7 @@ end <varlistentry> <term><emphasis role="lua">box.cfg</emphasis></term> <listitem><bridgehead renderas="sect4">Example</bridgehead><programlisting> -localhost> <userinput>box.cfg</userinput> +tarantool> <userinput>box.cfg</userinput> --- - io_collect_interval = 0 pid_file = box.pid @@ -3828,7 +3912,7 @@ localhost> <userinput>box.cfg</userinput> Returns: (type = Lua table) keys and values in the package. </para> <bridgehead renderas="sect4">Example</bridgehead><programlisting> -localhost> <userinput>box.info()</userinput> +tarantool> <userinput>box.info()</userinput> --- - version: 1.6.0-819-geefb2d0 status: primary @@ -3849,47 +3933,47 @@ localhost> <userinput>box.info()</userinput> </term> <listitem> <bridgehead renderas="sect4">Example</bridgehead><programlisting> -localhost> <userinput>box.info.pid</userinput> +tarantool> <userinput>box.info.pid</userinput> --- - 1747 ... -localhost> <userinput>box.info.logger_pid</userinput> +tarantool> <userinput>box.info.logger_pid</userinput> --- - 1748 ... -localhost> <userinput>box.info.version</userinput> +tarantool> <userinput>box.info.version</userinput> --- - 1.6.0-819-geefb2d0 ... -localhost> <userinput>box.info.config</userinput> +tarantool> <userinput>box.info.config</userinput> --- - /home/unera/work/tarantool/test/box/tarantool_good.cfg ... -localhost> <userinput>box.info.uptime</userinput> +tarantool> <userinput>box.info.uptime</userinput> --- - 3672 ... -localhost> <userinput>box.info.lsn</userinput> +tarantool> <userinput>box.info.lsn</userinput> --- - 1712 ... -localhost> <userinput>box.info.status</userinput> +tarantool> <userinput>box.info.status</userinput> --- - primary ... -localhost> <userinput>box.info.recovery_lag</userinput> +tarantool> <userinput>box.info.recovery_lag</userinput> --- - 0.000 ... -localhost> <userinput>box.info.recovery_last_update</userinput> +tarantool> <userinput>box.info.recovery_last_update</userinput> --- - 1306964594.980 ... -localhost> <userinput>box.info.snapshot_pid</userinput> +tarantool> <userinput>box.info.snapshot_pid</userinput> --- - 0 ... -localhost> <userinput>box.info.build</userinput> +tarantool> <userinput>box.info.build</userinput> --- - flags: ' -fno-omit-frame-pointer -fno-stack-protector -fexceptions -funwind-tables -msse2 -std=gnu99 -Wall -Wextra -Wno-sign-compare @@ -3911,20 +3995,20 @@ localhost> <userinput>box.info.build</userinput> <varlistentry> <term><emphasis role="lua">box.slab</emphasis></term> <listitem><bridgehead renderas="sect4">Example</bridgehead><programlisting> -localhost> <userinput>box.slab.info().arena_used</userinput> +tarantool> <userinput>box.slab.info().arena_used</userinput> --- - 4194304 ... -localhost> <userinput>box.slab.info().arena_size</userinput> +tarantool> <userinput>box.slab.info().arena_size</userinput> --- - 104857600 ... -localhost> <userinput>box.slab.info().slabs</userinput> +tarantool> <userinput>box.slab.info().slabs</userinput> --- 64 128 ... -localhost> <userinput>box.slab.info().slabs[64]</userinput> +tarantool> <userinput>box.slab.info().slabs[64]</userinput> --- items: 1 bytes_used: 160 @@ -3945,12 +4029,12 @@ localhost> <userinput>box.slab.info().slabs[64]</userinput> <varlistentry> <term><emphasis role="lua">box.stat</emphasis></term> <listitem><bridgehead renderas="sect4">Example</bridgehead><programlisting> -localhost> <userinput>box.stat, type(box.stat) -- a virtual table</userinput> +tarantool> <userinput>box.stat, type(box.stat) -- a virtual table</userinput> --- - [] - table ... -localhost> <userinput>box.stat() -- the full contents of the table</userinput> +tarantool> <userinput>box.stat() -- the full contents of the table</userinput> --- - DELETE: total: 33 @@ -3971,7 +4055,7 @@ localhost> <userinput>box.stat() -- the full contents of the table</userinput> total: 8 rps: 0 ... -localhost> <userinput>box.stat().DELETE -- a selected item of the table</userinput> +tarantool> <userinput>box.stat().DELETE -- a selected item of the table</userinput> --- - total: 33 rps: 0